From f209f069626f294a0f3ffc2bf19b31e903eb8b88 Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Tue, 7 Sep 2021 10:33:06 +0000 Subject: [PATCH 1/4] chore: cleanup after publish --- dist/browser/jwe/compact/decrypt.js | 25 - dist/browser/jwe/compact/encrypt.js | 28 - dist/browser/jwe/flattened/decrypt.js | 138 ---- dist/browser/jwe/flattened/encrypt.js | 166 ----- dist/browser/jwe/general/decrypt.js | 30 - dist/browser/jwk/embedded.js | 19 - dist/browser/jwk/from_key_like.js | 6 - dist/browser/jwk/parse.js | 35 - dist/browser/jwk/thumbprint.js | 44 -- dist/browser/jwks/remote.js | 130 ---- dist/browser/jws/compact/sign.js | 19 - dist/browser/jws/compact/verify.js | 23 - dist/browser/jws/flattened/sign.js | 81 -- dist/browser/jws/flattened/verify.js | 103 --- dist/browser/jws/general/sign.js | 73 -- dist/browser/jws/general/verify.js | 26 - dist/browser/jwt/decrypt.js | 21 - dist/browser/jwt/encrypt.js | 70 -- dist/browser/jwt/sign.js | 23 - dist/browser/jwt/unsecured.js | 34 - dist/browser/jwt/verify.js | 14 - dist/browser/lib/buffer_utils.js | 56 -- dist/browser/lib/cek.js | 18 - dist/browser/lib/check_iv_length.js | 8 - dist/browser/lib/check_key_type.js | 28 - dist/browser/lib/check_p2s.js | 6 - dist/browser/lib/decrypt_key_management.js | 95 --- dist/browser/lib/encrypt_key_management.js | 87 --- dist/browser/lib/epoch.js | 1 - dist/browser/lib/is_disjoint.js | 22 - dist/browser/lib/is_object.js | 16 - dist/browser/lib/iv.js | 21 - dist/browser/lib/jwt_claims_set.js | 96 --- dist/browser/lib/jwt_producer.js | 54 -- dist/browser/lib/secs.js | 44 -- dist/browser/lib/validate_algorithms.js | 11 - dist/browser/lib/validate_crit.js | 34 - dist/browser/package.json | 1 - dist/browser/runtime/aesgcmkw.js | 16 - dist/browser/runtime/aeskw.js | 29 - dist/browser/runtime/base64url.js | 31 - dist/browser/runtime/bogus.js | 6 - dist/browser/runtime/check_cek_length.js | 37 - dist/browser/runtime/check_key_length.js | 15 - dist/browser/runtime/decrypt.js | 72 -- dist/browser/runtime/digest.js | 6 - dist/browser/runtime/ecdhes.js | 34 - dist/browser/runtime/encrypt.js | 55 -- dist/browser/runtime/fetch_jwks.js | 31 - dist/browser/runtime/generate.js | 114 --- dist/browser/runtime/get_sign_verify_key.js | 14 - dist/browser/runtime/global.js | 10 - dist/browser/runtime/invalid_key_input.js | 25 - dist/browser/runtime/jwk_to_key.js | 115 --- dist/browser/runtime/key_to_jwk.js | 20 - dist/browser/runtime/pbes2kw.js | 71 -- dist/browser/runtime/random.js | 3 - dist/browser/runtime/rsaes.js | 33 - dist/browser/runtime/sign.js | 11 - dist/browser/runtime/subtle_dsa.js | 43 -- dist/browser/runtime/subtle_rsaes.js | 12 - dist/browser/runtime/timing_safe_equal.js | 19 - dist/browser/runtime/verify.js | 16 - dist/browser/runtime/webcrypto.js | 8 - dist/browser/runtime/zlib.js | 7 - dist/browser/util/base64url.js | 3 - dist/browser/util/decode_protected_header.js | 36 - dist/browser/util/errors.js | 108 --- dist/browser/util/generate_key_pair.js | 6 - dist/browser/util/generate_secret.js | 6 - dist/browser/util/random.js | 4 - dist/deno/README.md | 38 - dist/deno/jwe/compact/decrypt.ts | 94 --- dist/deno/jwe/compact/encrypt.ts | 111 --- dist/deno/jwe/flattened/decrypt.ts | 249 ------- dist/deno/jwe/flattened/encrypt.ts | 321 -------- dist/deno/jwe/general/decrypt.ts | 107 --- dist/deno/jwk/embedded.ts | 62 -- dist/deno/jwk/from_key_like.ts | 39 - dist/deno/jwk/parse.ts | 90 --- dist/deno/jwk/thumbprint.ts | 89 --- dist/deno/jwks/remote.ts | 264 ------- dist/deno/jws/compact/sign.ts | 72 -- dist/deno/jws/compact/verify.ts | 89 --- dist/deno/jws/flattened/sign.ts | 164 ----- dist/deno/jws/flattened/verify.ts | 201 ----- dist/deno/jws/general/sign.ts | 163 ----- dist/deno/jws/general/verify.ts | 99 --- dist/deno/jwt/decrypt.ts | 103 --- dist/deno/jwt/encrypt.ts | 181 ----- dist/deno/jwt/sign.ts | 73 -- dist/deno/jwt/unsecured.ts | 96 --- dist/deno/jwt/verify.ts | 86 --- dist/deno/lib/buffer_utils.ts | 71 -- dist/deno/lib/cek.ts | 24 - dist/deno/lib/check_iv_length.ts | 10 - dist/deno/lib/check_key_type.ts | 51 -- dist/deno/lib/check_p2s.ts | 7 - dist/deno/lib/decrypt_key_management.ts | 128 ---- dist/deno/lib/encrypt_key_management.ts | 121 --- dist/deno/lib/epoch.ts | 1 - dist/deno/lib/is_disjoint.ts | 26 - dist/deno/lib/is_object.ts | 17 - dist/deno/lib/iv.ts | 27 - dist/deno/lib/jwt_claims_set.ts | 148 ---- dist/deno/lib/jwt_producer.ts | 108 --- dist/deno/lib/secs.ts | 51 -- dist/deno/lib/validate_algorithms.ts | 16 - dist/deno/lib/validate_crit.ts | 56 -- dist/deno/runtime/aesgcmkw.ts | 39 - dist/deno/runtime/aeskw.ts | 56 -- dist/deno/runtime/base64url.ts | 35 - dist/deno/runtime/bogus.ts | 7 - dist/deno/runtime/check_cek_length.ts | 46 -- dist/deno/runtime/check_key_length.ts | 18 - dist/deno/runtime/decrypt.ts | 129 ---- dist/deno/runtime/digest.ts | 11 - dist/deno/runtime/ecdhes.ts | 73 -- dist/deno/runtime/encrypt.ts | 114 --- dist/deno/runtime/fetch_jwks.ts | 38 - dist/deno/runtime/generate.ts | 126 ---- dist/deno/runtime/get_sign_verify_key.ts | 23 - dist/deno/runtime/global.ts | 8 - dist/deno/runtime/interfaces.d.ts | 100 --- dist/deno/runtime/invalid_key_input.ts | 24 - dist/deno/runtime/jwk_to_key.ts | 133 ---- dist/deno/runtime/key_to_jwk.ts | 26 - dist/deno/runtime/pbes2kw.ts | 98 --- dist/deno/runtime/random.ts | 5 - dist/deno/runtime/rsaes.ts | 64 -- dist/deno/runtime/sign.ts | 14 - dist/deno/runtime/subtle_dsa.ts | 46 -- dist/deno/runtime/subtle_rsaes.ts | 15 - dist/deno/runtime/timing_safe_equal.ts | 23 - dist/deno/runtime/verify.ts | 18 - dist/deno/runtime/webcrypto.ts | 10 - dist/deno/runtime/zlib.ts | 13 - dist/deno/types.d.ts | 691 ------------------ dist/deno/types.i.d.ts | 13 - dist/deno/util/base64url.ts | 21 - dist/deno/util/decode_protected_header.ts | 65 -- dist/deno/util/errors.ts | 165 ----- dist/deno/util/generate_key_pair.ts | 79 -- dist/deno/util/generate_secret.ts | 48 -- dist/deno/util/random.ts | 9 - dist/node/cjs/jwe/compact/decrypt.js | 28 - dist/node/cjs/jwe/compact/encrypt.js | 31 - dist/node/cjs/jwe/flattened/decrypt.js | 141 ---- dist/node/cjs/jwe/flattened/encrypt.js | 169 ----- dist/node/cjs/jwe/general/decrypt.js | 33 - dist/node/cjs/jwk/embedded.js | 22 - dist/node/cjs/jwk/from_key_like.js | 9 - dist/node/cjs/jwk/parse.js | 38 - dist/node/cjs/jwk/thumbprint.js | 47 -- dist/node/cjs/jwks/remote.js | 133 ---- dist/node/cjs/jws/compact/sign.js | 22 - dist/node/cjs/jws/compact/verify.js | 26 - dist/node/cjs/jws/flattened/sign.js | 84 --- dist/node/cjs/jws/flattened/verify.js | 106 --- dist/node/cjs/jws/general/sign.js | 76 -- dist/node/cjs/jws/general/verify.js | 29 - dist/node/cjs/jwt/decrypt.js | 24 - dist/node/cjs/jwt/encrypt.js | 73 -- dist/node/cjs/jwt/sign.js | 26 - dist/node/cjs/jwt/unsecured.js | 37 - dist/node/cjs/jwt/verify.js | 17 - dist/node/cjs/lib/buffer_utils.js | 65 -- dist/node/cjs/lib/cek.js | 21 - dist/node/cjs/lib/check_iv_length.js | 10 - dist/node/cjs/lib/check_key_type.js | 30 - dist/node/cjs/lib/check_p2s.js | 9 - dist/node/cjs/lib/decrypt_key_management.js | 97 --- dist/node/cjs/lib/encrypt_key_management.js | 89 --- dist/node/cjs/lib/epoch.js | 3 - dist/node/cjs/lib/is_disjoint.js | 24 - dist/node/cjs/lib/is_object.js | 19 - dist/node/cjs/lib/iv.js | 24 - dist/node/cjs/lib/jwt_claims_set.js | 98 --- dist/node/cjs/lib/jwt_producer.js | 57 -- dist/node/cjs/lib/secs.js | 46 -- dist/node/cjs/lib/validate_algorithms.js | 13 - dist/node/cjs/lib/validate_crit.js | 36 - dist/node/cjs/runtime/aesgcmkw.js | 21 - dist/node/cjs/runtime/aeskw.js | 52 -- .../node/cjs/runtime/asn1_sequence_decoder.js | 47 -- .../node/cjs/runtime/asn1_sequence_encoder.js | 90 --- dist/node/cjs/runtime/base64url.js | 21 - dist/node/cjs/runtime/cbc_tag.js | 11 - dist/node/cjs/runtime/check_cek_length.js | 35 - dist/node/cjs/runtime/check_modulus_length.js | 52 -- dist/node/cjs/runtime/ciphers.js | 8 - dist/node/cjs/runtime/decrypt.js | 92 --- dist/node/cjs/runtime/digest.js | 5 - dist/node/cjs/runtime/dsa_digest.js | 25 - dist/node/cjs/runtime/ecdhes.js | 55 -- dist/node/cjs/runtime/encrypt.js | 70 -- dist/node/cjs/runtime/fetch_jwks.js | 36 - dist/node/cjs/runtime/generate.js | 104 --- dist/node/cjs/runtime/get_named_curve.js | 89 --- dist/node/cjs/runtime/get_sign_verify_key.js | 22 - dist/node/cjs/runtime/hmac_digest.js | 16 - dist/node/cjs/runtime/invalid_key_input.js | 38 - dist/node/cjs/runtime/is_key_object.js | 16 - dist/node/cjs/runtime/jwk_to_key.js | 121 --- dist/node/cjs/runtime/key_to_jwk.js | 159 ---- dist/node/cjs/runtime/node_key.js | 86 --- dist/node/cjs/runtime/pbes2kw.js | 45 -- dist/node/cjs/runtime/random.js | 4 - dist/node/cjs/runtime/rsaes.js | 66 -- dist/node/cjs/runtime/secret_key.js | 14 - dist/node/cjs/runtime/sign.js | 29 - dist/node/cjs/runtime/timing_safe_equal.js | 5 - dist/node/cjs/runtime/verify.js | 42 -- dist/node/cjs/runtime/webcrypto.js | 165 ----- dist/node/cjs/runtime/zlib.js | 11 - dist/node/cjs/util/base64url.js | 6 - dist/node/cjs/util/decode_protected_header.js | 39 - dist/node/cjs/util/errors.js | 125 ---- dist/node/cjs/util/generate_key_pair.js | 9 - dist/node/cjs/util/generate_secret.js | 9 - dist/node/cjs/util/random.js | 7 - dist/node/esm/jwe/compact/decrypt.js | 25 - dist/node/esm/jwe/compact/encrypt.js | 28 - dist/node/esm/jwe/flattened/decrypt.js | 138 ---- dist/node/esm/jwe/flattened/encrypt.js | 166 ----- dist/node/esm/jwe/general/decrypt.js | 30 - dist/node/esm/jwk/embedded.js | 19 - dist/node/esm/jwk/from_key_like.js | 6 - dist/node/esm/jwk/parse.js | 35 - dist/node/esm/jwk/thumbprint.js | 44 -- dist/node/esm/jwks/remote.js | 130 ---- dist/node/esm/jws/compact/sign.js | 19 - dist/node/esm/jws/compact/verify.js | 23 - dist/node/esm/jws/flattened/sign.js | 81 -- dist/node/esm/jws/flattened/verify.js | 103 --- dist/node/esm/jws/general/sign.js | 73 -- dist/node/esm/jws/general/verify.js | 26 - dist/node/esm/jwt/decrypt.js | 21 - dist/node/esm/jwt/encrypt.js | 70 -- dist/node/esm/jwt/sign.js | 23 - dist/node/esm/jwt/unsecured.js | 34 - dist/node/esm/jwt/verify.js | 14 - dist/node/esm/lib/buffer_utils.js | 56 -- dist/node/esm/lib/cek.js | 18 - dist/node/esm/lib/check_iv_length.js | 8 - dist/node/esm/lib/check_key_type.js | 28 - dist/node/esm/lib/check_p2s.js | 6 - dist/node/esm/lib/decrypt_key_management.js | 95 --- dist/node/esm/lib/encrypt_key_management.js | 87 --- dist/node/esm/lib/epoch.js | 1 - dist/node/esm/lib/is_disjoint.js | 22 - dist/node/esm/lib/is_object.js | 16 - dist/node/esm/lib/iv.js | 21 - dist/node/esm/lib/jwt_claims_set.js | 96 --- dist/node/esm/lib/jwt_producer.js | 54 -- dist/node/esm/lib/secs.js | 44 -- dist/node/esm/lib/validate_algorithms.js | 11 - dist/node/esm/lib/validate_crit.js | 34 - dist/node/esm/package.json | 1 - dist/node/esm/runtime/aesgcmkw.js | 16 - dist/node/esm/runtime/aeskw.js | 47 -- .../node/esm/runtime/asn1_sequence_decoder.js | 44 -- .../node/esm/runtime/asn1_sequence_encoder.js | 87 --- dist/node/esm/runtime/base64url.js | 17 - dist/node/esm/runtime/cbc_tag.js | 8 - dist/node/esm/runtime/check_cek_length.js | 33 - dist/node/esm/runtime/check_modulus_length.js | 48 -- dist/node/esm/runtime/ciphers.js | 6 - dist/node/esm/runtime/decrypt.js | 90 --- dist/node/esm/runtime/digest.js | 3 - dist/node/esm/runtime/dsa_digest.js | 22 - dist/node/esm/runtime/ecdhes.js | 49 -- dist/node/esm/runtime/encrypt.js | 68 -- dist/node/esm/runtime/fetch_jwks.js | 34 - dist/node/esm/runtime/generate.js | 99 --- dist/node/esm/runtime/get_named_curve.js | 85 --- dist/node/esm/runtime/get_sign_verify_key.js | 19 - dist/node/esm/runtime/hmac_digest.js | 13 - dist/node/esm/runtime/invalid_key_input.js | 36 - dist/node/esm/runtime/is_key_object.js | 14 - dist/node/esm/runtime/jwk_to_key.js | 119 --- dist/node/esm/runtime/key_to_jwk.js | 157 ---- dist/node/esm/runtime/node_key.js | 83 --- dist/node/esm/runtime/pbes2kw.js | 40 - dist/node/esm/runtime/random.js | 2 - dist/node/esm/runtime/rsaes.js | 61 -- dist/node/esm/runtime/secret_key.js | 11 - dist/node/esm/runtime/sign.js | 27 - dist/node/esm/runtime/timing_safe_equal.js | 3 - dist/node/esm/runtime/verify.js | 40 - dist/node/esm/runtime/webcrypto.js | 161 ---- dist/node/esm/runtime/zlib.js | 6 - dist/node/esm/util/base64url.js | 3 - dist/node/esm/util/decode_protected_header.js | 36 - dist/node/esm/util/errors.js | 108 --- dist/node/esm/util/generate_key_pair.js | 6 - dist/node/esm/util/generate_secret.js | 6 - dist/node/esm/util/random.js | 4 - dist/types/jwe/compact/decrypt.d.ts | 7 - dist/types/jwe/compact/encrypt.d.ts | 13 - dist/types/jwe/flattened/decrypt.d.ts | 7 - dist/types/jwe/flattened/encrypt.d.ts | 23 - dist/types/jwe/general/decrypt.d.ts | 7 - dist/types/jwk/embedded.d.ts | 5 - dist/types/jwk/from_key_like.d.ts | 5 - dist/types/jwk/parse.d.ts | 5 - dist/types/jwk/thumbprint.d.ts | 5 - dist/types/jwks/remote.d.ts | 9 - dist/types/jws/compact/sign.d.ts | 10 - dist/types/jws/compact/verify.d.ts | 7 - dist/types/jws/flattened/sign.d.ts | 13 - dist/types/jws/flattened/verify.d.ts | 7 - dist/types/jws/general/sign.d.ts | 15 - dist/types/jws/general/verify.d.ts | 7 - dist/types/jwt/decrypt.d.ts | 9 - dist/types/jwt/encrypt.d.ts | 22 - dist/types/jwt/sign.d.ts | 10 - dist/types/jwt/unsecured.d.ts | 13 - dist/types/jwt/verify.d.ts | 9 - dist/types/lib/jwt_producer.d.ts | 12 - dist/types/types.d.ts | 171 ----- dist/types/util/base64url.d.ts | 9 - dist/types/util/decode_protected_header.d.ts | 5 - dist/types/util/errors.d.ts | 64 -- dist/types/util/generate_key_pair.d.ts | 13 - dist/types/util/generate_secret.d.ts | 7 - dist/types/util/random.d.ts | 6 - 327 files changed, 16349 deletions(-) delete mode 100644 dist/browser/jwe/compact/decrypt.js delete mode 100644 dist/browser/jwe/compact/encrypt.js delete mode 100644 dist/browser/jwe/flattened/decrypt.js delete mode 100644 dist/browser/jwe/flattened/encrypt.js delete mode 100644 dist/browser/jwe/general/decrypt.js delete mode 100644 dist/browser/jwk/embedded.js delete mode 100644 dist/browser/jwk/from_key_like.js delete mode 100644 dist/browser/jwk/parse.js delete mode 100644 dist/browser/jwk/thumbprint.js delete mode 100644 dist/browser/jwks/remote.js delete mode 100644 dist/browser/jws/compact/sign.js delete mode 100644 dist/browser/jws/compact/verify.js delete mode 100644 dist/browser/jws/flattened/sign.js delete mode 100644 dist/browser/jws/flattened/verify.js delete mode 100644 dist/browser/jws/general/sign.js delete mode 100644 dist/browser/jws/general/verify.js delete mode 100644 dist/browser/jwt/decrypt.js delete mode 100644 dist/browser/jwt/encrypt.js delete mode 100644 dist/browser/jwt/sign.js delete mode 100644 dist/browser/jwt/unsecured.js delete mode 100644 dist/browser/jwt/verify.js delete mode 100644 dist/browser/lib/buffer_utils.js delete mode 100644 dist/browser/lib/cek.js delete mode 100644 dist/browser/lib/check_iv_length.js delete mode 100644 dist/browser/lib/check_key_type.js delete mode 100644 dist/browser/lib/check_p2s.js delete mode 100644 dist/browser/lib/decrypt_key_management.js delete mode 100644 dist/browser/lib/encrypt_key_management.js delete mode 100644 dist/browser/lib/epoch.js delete mode 100644 dist/browser/lib/is_disjoint.js delete mode 100644 dist/browser/lib/is_object.js delete mode 100644 dist/browser/lib/iv.js delete mode 100644 dist/browser/lib/jwt_claims_set.js delete mode 100644 dist/browser/lib/jwt_producer.js delete mode 100644 dist/browser/lib/secs.js delete mode 100644 dist/browser/lib/validate_algorithms.js delete mode 100644 dist/browser/lib/validate_crit.js delete mode 100644 dist/browser/package.json delete mode 100644 dist/browser/runtime/aesgcmkw.js delete mode 100644 dist/browser/runtime/aeskw.js delete mode 100644 dist/browser/runtime/base64url.js delete mode 100644 dist/browser/runtime/bogus.js delete mode 100644 dist/browser/runtime/check_cek_length.js delete mode 100644 dist/browser/runtime/check_key_length.js delete mode 100644 dist/browser/runtime/decrypt.js delete mode 100644 dist/browser/runtime/digest.js delete mode 100644 dist/browser/runtime/ecdhes.js delete mode 100644 dist/browser/runtime/encrypt.js delete mode 100644 dist/browser/runtime/fetch_jwks.js delete mode 100644 dist/browser/runtime/generate.js delete mode 100644 dist/browser/runtime/get_sign_verify_key.js delete mode 100644 dist/browser/runtime/global.js delete mode 100644 dist/browser/runtime/invalid_key_input.js delete mode 100644 dist/browser/runtime/jwk_to_key.js delete mode 100644 dist/browser/runtime/key_to_jwk.js delete mode 100644 dist/browser/runtime/pbes2kw.js delete mode 100644 dist/browser/runtime/random.js delete mode 100644 dist/browser/runtime/rsaes.js delete mode 100644 dist/browser/runtime/sign.js delete mode 100644 dist/browser/runtime/subtle_dsa.js delete mode 100644 dist/browser/runtime/subtle_rsaes.js delete mode 100644 dist/browser/runtime/timing_safe_equal.js delete mode 100644 dist/browser/runtime/verify.js delete mode 100644 dist/browser/runtime/webcrypto.js delete mode 100644 dist/browser/runtime/zlib.js delete mode 100644 dist/browser/util/base64url.js delete mode 100644 dist/browser/util/decode_protected_header.js delete mode 100644 dist/browser/util/errors.js delete mode 100644 dist/browser/util/generate_key_pair.js delete mode 100644 dist/browser/util/generate_secret.js delete mode 100644 dist/browser/util/random.js delete mode 100644 dist/deno/README.md delete mode 100644 dist/deno/jwe/compact/decrypt.ts delete mode 100644 dist/deno/jwe/compact/encrypt.ts delete mode 100644 dist/deno/jwe/flattened/decrypt.ts delete mode 100644 dist/deno/jwe/flattened/encrypt.ts delete mode 100644 dist/deno/jwe/general/decrypt.ts delete mode 100644 dist/deno/jwk/embedded.ts delete mode 100644 dist/deno/jwk/from_key_like.ts delete mode 100644 dist/deno/jwk/parse.ts delete mode 100644 dist/deno/jwk/thumbprint.ts delete mode 100644 dist/deno/jwks/remote.ts delete mode 100644 dist/deno/jws/compact/sign.ts delete mode 100644 dist/deno/jws/compact/verify.ts delete mode 100644 dist/deno/jws/flattened/sign.ts delete mode 100644 dist/deno/jws/flattened/verify.ts delete mode 100644 dist/deno/jws/general/sign.ts delete mode 100644 dist/deno/jws/general/verify.ts delete mode 100644 dist/deno/jwt/decrypt.ts delete mode 100644 dist/deno/jwt/encrypt.ts delete mode 100644 dist/deno/jwt/sign.ts delete mode 100644 dist/deno/jwt/unsecured.ts delete mode 100644 dist/deno/jwt/verify.ts delete mode 100644 dist/deno/lib/buffer_utils.ts delete mode 100644 dist/deno/lib/cek.ts delete mode 100644 dist/deno/lib/check_iv_length.ts delete mode 100644 dist/deno/lib/check_key_type.ts delete mode 100644 dist/deno/lib/check_p2s.ts delete mode 100644 dist/deno/lib/decrypt_key_management.ts delete mode 100644 dist/deno/lib/encrypt_key_management.ts delete mode 100644 dist/deno/lib/epoch.ts delete mode 100644 dist/deno/lib/is_disjoint.ts delete mode 100644 dist/deno/lib/is_object.ts delete mode 100644 dist/deno/lib/iv.ts delete mode 100644 dist/deno/lib/jwt_claims_set.ts delete mode 100644 dist/deno/lib/jwt_producer.ts delete mode 100644 dist/deno/lib/secs.ts delete mode 100644 dist/deno/lib/validate_algorithms.ts delete mode 100644 dist/deno/lib/validate_crit.ts delete mode 100644 dist/deno/runtime/aesgcmkw.ts delete mode 100644 dist/deno/runtime/aeskw.ts delete mode 100644 dist/deno/runtime/base64url.ts delete mode 100644 dist/deno/runtime/bogus.ts delete mode 100644 dist/deno/runtime/check_cek_length.ts delete mode 100644 dist/deno/runtime/check_key_length.ts delete mode 100644 dist/deno/runtime/decrypt.ts delete mode 100644 dist/deno/runtime/digest.ts delete mode 100644 dist/deno/runtime/ecdhes.ts delete mode 100644 dist/deno/runtime/encrypt.ts delete mode 100644 dist/deno/runtime/fetch_jwks.ts delete mode 100644 dist/deno/runtime/generate.ts delete mode 100644 dist/deno/runtime/get_sign_verify_key.ts delete mode 100644 dist/deno/runtime/global.ts delete mode 100644 dist/deno/runtime/interfaces.d.ts delete mode 100644 dist/deno/runtime/invalid_key_input.ts delete mode 100644 dist/deno/runtime/jwk_to_key.ts delete mode 100644 dist/deno/runtime/key_to_jwk.ts delete mode 100644 dist/deno/runtime/pbes2kw.ts delete mode 100644 dist/deno/runtime/random.ts delete mode 100644 dist/deno/runtime/rsaes.ts delete mode 100644 dist/deno/runtime/sign.ts delete mode 100644 dist/deno/runtime/subtle_dsa.ts delete mode 100644 dist/deno/runtime/subtle_rsaes.ts delete mode 100644 dist/deno/runtime/timing_safe_equal.ts delete mode 100644 dist/deno/runtime/verify.ts delete mode 100644 dist/deno/runtime/webcrypto.ts delete mode 100644 dist/deno/runtime/zlib.ts delete mode 100644 dist/deno/types.d.ts delete mode 100644 dist/deno/types.i.d.ts delete mode 100644 dist/deno/util/base64url.ts delete mode 100644 dist/deno/util/decode_protected_header.ts delete mode 100644 dist/deno/util/errors.ts delete mode 100644 dist/deno/util/generate_key_pair.ts delete mode 100644 dist/deno/util/generate_secret.ts delete mode 100644 dist/deno/util/random.ts delete mode 100644 dist/node/cjs/jwe/compact/decrypt.js delete mode 100644 dist/node/cjs/jwe/compact/encrypt.js delete mode 100644 dist/node/cjs/jwe/flattened/decrypt.js delete mode 100644 dist/node/cjs/jwe/flattened/encrypt.js delete mode 100644 dist/node/cjs/jwe/general/decrypt.js delete mode 100644 dist/node/cjs/jwk/embedded.js delete mode 100644 dist/node/cjs/jwk/from_key_like.js delete mode 100644 dist/node/cjs/jwk/parse.js delete mode 100644 dist/node/cjs/jwk/thumbprint.js delete mode 100644 dist/node/cjs/jwks/remote.js delete mode 100644 dist/node/cjs/jws/compact/sign.js delete mode 100644 dist/node/cjs/jws/compact/verify.js delete mode 100644 dist/node/cjs/jws/flattened/sign.js delete mode 100644 dist/node/cjs/jws/flattened/verify.js delete mode 100644 dist/node/cjs/jws/general/sign.js delete mode 100644 dist/node/cjs/jws/general/verify.js delete mode 100644 dist/node/cjs/jwt/decrypt.js delete mode 100644 dist/node/cjs/jwt/encrypt.js delete mode 100644 dist/node/cjs/jwt/sign.js delete mode 100644 dist/node/cjs/jwt/unsecured.js delete mode 100644 dist/node/cjs/jwt/verify.js delete mode 100644 dist/node/cjs/lib/buffer_utils.js delete mode 100644 dist/node/cjs/lib/cek.js delete mode 100644 dist/node/cjs/lib/check_iv_length.js delete mode 100644 dist/node/cjs/lib/check_key_type.js delete mode 100644 dist/node/cjs/lib/check_p2s.js delete mode 100644 dist/node/cjs/lib/decrypt_key_management.js delete mode 100644 dist/node/cjs/lib/encrypt_key_management.js delete mode 100644 dist/node/cjs/lib/epoch.js delete mode 100644 dist/node/cjs/lib/is_disjoint.js delete mode 100644 dist/node/cjs/lib/is_object.js delete mode 100644 dist/node/cjs/lib/iv.js delete mode 100644 dist/node/cjs/lib/jwt_claims_set.js delete mode 100644 dist/node/cjs/lib/jwt_producer.js delete mode 100644 dist/node/cjs/lib/secs.js delete mode 100644 dist/node/cjs/lib/validate_algorithms.js delete mode 100644 dist/node/cjs/lib/validate_crit.js delete mode 100644 dist/node/cjs/runtime/aesgcmkw.js delete mode 100644 dist/node/cjs/runtime/aeskw.js delete mode 100644 dist/node/cjs/runtime/asn1_sequence_decoder.js delete mode 100644 dist/node/cjs/runtime/asn1_sequence_encoder.js delete mode 100644 dist/node/cjs/runtime/base64url.js delete mode 100644 dist/node/cjs/runtime/cbc_tag.js delete mode 100644 dist/node/cjs/runtime/check_cek_length.js delete mode 100644 dist/node/cjs/runtime/check_modulus_length.js delete mode 100644 dist/node/cjs/runtime/ciphers.js delete mode 100644 dist/node/cjs/runtime/decrypt.js delete mode 100644 dist/node/cjs/runtime/digest.js delete mode 100644 dist/node/cjs/runtime/dsa_digest.js delete mode 100644 dist/node/cjs/runtime/ecdhes.js delete mode 100644 dist/node/cjs/runtime/encrypt.js delete mode 100644 dist/node/cjs/runtime/fetch_jwks.js delete mode 100644 dist/node/cjs/runtime/generate.js delete mode 100644 dist/node/cjs/runtime/get_named_curve.js delete mode 100644 dist/node/cjs/runtime/get_sign_verify_key.js delete mode 100644 dist/node/cjs/runtime/hmac_digest.js delete mode 100644 dist/node/cjs/runtime/invalid_key_input.js delete mode 100644 dist/node/cjs/runtime/is_key_object.js delete mode 100644 dist/node/cjs/runtime/jwk_to_key.js delete mode 100644 dist/node/cjs/runtime/key_to_jwk.js delete mode 100644 dist/node/cjs/runtime/node_key.js delete mode 100644 dist/node/cjs/runtime/pbes2kw.js delete mode 100644 dist/node/cjs/runtime/random.js delete mode 100644 dist/node/cjs/runtime/rsaes.js delete mode 100644 dist/node/cjs/runtime/secret_key.js delete mode 100644 dist/node/cjs/runtime/sign.js delete mode 100644 dist/node/cjs/runtime/timing_safe_equal.js delete mode 100644 dist/node/cjs/runtime/verify.js delete mode 100644 dist/node/cjs/runtime/webcrypto.js delete mode 100644 dist/node/cjs/runtime/zlib.js delete mode 100644 dist/node/cjs/util/base64url.js delete mode 100644 dist/node/cjs/util/decode_protected_header.js delete mode 100644 dist/node/cjs/util/errors.js delete mode 100644 dist/node/cjs/util/generate_key_pair.js delete mode 100644 dist/node/cjs/util/generate_secret.js delete mode 100644 dist/node/cjs/util/random.js delete mode 100644 dist/node/esm/jwe/compact/decrypt.js delete mode 100644 dist/node/esm/jwe/compact/encrypt.js delete mode 100644 dist/node/esm/jwe/flattened/decrypt.js delete mode 100644 dist/node/esm/jwe/flattened/encrypt.js delete mode 100644 dist/node/esm/jwe/general/decrypt.js delete mode 100644 dist/node/esm/jwk/embedded.js delete mode 100644 dist/node/esm/jwk/from_key_like.js delete mode 100644 dist/node/esm/jwk/parse.js delete mode 100644 dist/node/esm/jwk/thumbprint.js delete mode 100644 dist/node/esm/jwks/remote.js delete mode 100644 dist/node/esm/jws/compact/sign.js delete mode 100644 dist/node/esm/jws/compact/verify.js delete mode 100644 dist/node/esm/jws/flattened/sign.js delete mode 100644 dist/node/esm/jws/flattened/verify.js delete mode 100644 dist/node/esm/jws/general/sign.js delete mode 100644 dist/node/esm/jws/general/verify.js delete mode 100644 dist/node/esm/jwt/decrypt.js delete mode 100644 dist/node/esm/jwt/encrypt.js delete mode 100644 dist/node/esm/jwt/sign.js delete mode 100644 dist/node/esm/jwt/unsecured.js delete mode 100644 dist/node/esm/jwt/verify.js delete mode 100644 dist/node/esm/lib/buffer_utils.js delete mode 100644 dist/node/esm/lib/cek.js delete mode 100644 dist/node/esm/lib/check_iv_length.js delete mode 100644 dist/node/esm/lib/check_key_type.js delete mode 100644 dist/node/esm/lib/check_p2s.js delete mode 100644 dist/node/esm/lib/decrypt_key_management.js delete mode 100644 dist/node/esm/lib/encrypt_key_management.js delete mode 100644 dist/node/esm/lib/epoch.js delete mode 100644 dist/node/esm/lib/is_disjoint.js delete mode 100644 dist/node/esm/lib/is_object.js delete mode 100644 dist/node/esm/lib/iv.js delete mode 100644 dist/node/esm/lib/jwt_claims_set.js delete mode 100644 dist/node/esm/lib/jwt_producer.js delete mode 100644 dist/node/esm/lib/secs.js delete mode 100644 dist/node/esm/lib/validate_algorithms.js delete mode 100644 dist/node/esm/lib/validate_crit.js delete mode 100644 dist/node/esm/package.json delete mode 100644 dist/node/esm/runtime/aesgcmkw.js delete mode 100644 dist/node/esm/runtime/aeskw.js delete mode 100644 dist/node/esm/runtime/asn1_sequence_decoder.js delete mode 100644 dist/node/esm/runtime/asn1_sequence_encoder.js delete mode 100644 dist/node/esm/runtime/base64url.js delete mode 100644 dist/node/esm/runtime/cbc_tag.js delete mode 100644 dist/node/esm/runtime/check_cek_length.js delete mode 100644 dist/node/esm/runtime/check_modulus_length.js delete mode 100644 dist/node/esm/runtime/ciphers.js delete mode 100644 dist/node/esm/runtime/decrypt.js delete mode 100644 dist/node/esm/runtime/digest.js delete mode 100644 dist/node/esm/runtime/dsa_digest.js delete mode 100644 dist/node/esm/runtime/ecdhes.js delete mode 100644 dist/node/esm/runtime/encrypt.js delete mode 100644 dist/node/esm/runtime/fetch_jwks.js delete mode 100644 dist/node/esm/runtime/generate.js delete mode 100644 dist/node/esm/runtime/get_named_curve.js delete mode 100644 dist/node/esm/runtime/get_sign_verify_key.js delete mode 100644 dist/node/esm/runtime/hmac_digest.js delete mode 100644 dist/node/esm/runtime/invalid_key_input.js delete mode 100644 dist/node/esm/runtime/is_key_object.js delete mode 100644 dist/node/esm/runtime/jwk_to_key.js delete mode 100644 dist/node/esm/runtime/key_to_jwk.js delete mode 100644 dist/node/esm/runtime/node_key.js delete mode 100644 dist/node/esm/runtime/pbes2kw.js delete mode 100644 dist/node/esm/runtime/random.js delete mode 100644 dist/node/esm/runtime/rsaes.js delete mode 100644 dist/node/esm/runtime/secret_key.js delete mode 100644 dist/node/esm/runtime/sign.js delete mode 100644 dist/node/esm/runtime/timing_safe_equal.js delete mode 100644 dist/node/esm/runtime/verify.js delete mode 100644 dist/node/esm/runtime/webcrypto.js delete mode 100644 dist/node/esm/runtime/zlib.js delete mode 100644 dist/node/esm/util/base64url.js delete mode 100644 dist/node/esm/util/decode_protected_header.js delete mode 100644 dist/node/esm/util/errors.js delete mode 100644 dist/node/esm/util/generate_key_pair.js delete mode 100644 dist/node/esm/util/generate_secret.js delete mode 100644 dist/node/esm/util/random.js delete mode 100644 dist/types/jwe/compact/decrypt.d.ts delete mode 100644 dist/types/jwe/compact/encrypt.d.ts delete mode 100644 dist/types/jwe/flattened/decrypt.d.ts delete mode 100644 dist/types/jwe/flattened/encrypt.d.ts delete mode 100644 dist/types/jwe/general/decrypt.d.ts delete mode 100644 dist/types/jwk/embedded.d.ts delete mode 100644 dist/types/jwk/from_key_like.d.ts delete mode 100644 dist/types/jwk/parse.d.ts delete mode 100644 dist/types/jwk/thumbprint.d.ts delete mode 100644 dist/types/jwks/remote.d.ts delete mode 100644 dist/types/jws/compact/sign.d.ts delete mode 100644 dist/types/jws/compact/verify.d.ts delete mode 100644 dist/types/jws/flattened/sign.d.ts delete mode 100644 dist/types/jws/flattened/verify.d.ts delete mode 100644 dist/types/jws/general/sign.d.ts delete mode 100644 dist/types/jws/general/verify.d.ts delete mode 100644 dist/types/jwt/decrypt.d.ts delete mode 100644 dist/types/jwt/encrypt.d.ts delete mode 100644 dist/types/jwt/sign.d.ts delete mode 100644 dist/types/jwt/unsecured.d.ts delete mode 100644 dist/types/jwt/verify.d.ts delete mode 100644 dist/types/lib/jwt_producer.d.ts delete mode 100644 dist/types/types.d.ts delete mode 100644 dist/types/util/base64url.d.ts delete mode 100644 dist/types/util/decode_protected_header.d.ts delete mode 100644 dist/types/util/errors.d.ts delete mode 100644 dist/types/util/generate_key_pair.d.ts delete mode 100644 dist/types/util/generate_secret.d.ts delete mode 100644 dist/types/util/random.d.ts diff --git a/dist/browser/jwe/compact/decrypt.js b/dist/browser/jwe/compact/decrypt.js deleted file mode 100644 index e4e87c1c17..0000000000 --- a/dist/browser/jwe/compact/decrypt.js +++ /dev/null @@ -1,25 +0,0 @@ -import decrypt from '../flattened/decrypt.js'; -import { JWEInvalid } from '../../util/errors.js'; -import { decoder } from '../../lib/buffer_utils.js'; -async function compactDecrypt(jwe, key, options) { - if (jwe instanceof Uint8Array) { - jwe = decoder.decode(jwe); - } - if (typeof jwe !== 'string') { - throw new JWEInvalid('Compact JWE must be a string or Uint8Array'); - } - 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: (ciphertext || undefined), - iv: (iv || undefined), - protected: protectedHeader || undefined, - tag: (tag || undefined), - encrypted_key: encryptedKey || undefined, - }, key, options); - return { plaintext: decrypted.plaintext, protectedHeader: decrypted.protectedHeader }; -} -export { compactDecrypt }; -export default compactDecrypt; diff --git a/dist/browser/jwe/compact/encrypt.js b/dist/browser/jwe/compact/encrypt.js deleted file mode 100644 index 132a092398..0000000000 --- a/dist/browser/jwe/compact/encrypt.js +++ /dev/null @@ -1,28 +0,0 @@ -import FlattenedEncrypt from '../flattened/encrypt.js'; -class CompactEncrypt { - constructor(plaintext) { - this._flattened = new FlattenedEncrypt(plaintext); - } - setContentEncryptionKey(cek) { - this._flattened.setContentEncryptionKey(cek); - return this; - } - setInitializationVector(iv) { - this._flattened.setInitializationVector(iv); - return this; - } - setProtectedHeader(protectedHeader) { - this._flattened.setProtectedHeader(protectedHeader); - return this; - } - setKeyManagementParameters(parameters) { - this._flattened.setKeyManagementParameters(parameters); - return this; - } - async encrypt(key, options) { - const jwe = await this._flattened.encrypt(key, options); - return [jwe.protected, jwe.encrypted_key, jwe.iv, jwe.ciphertext, jwe.tag].join('.'); - } -} -export { CompactEncrypt }; -export default CompactEncrypt; diff --git a/dist/browser/jwe/flattened/decrypt.js b/dist/browser/jwe/flattened/decrypt.js deleted file mode 100644 index 39e329284a..0000000000 --- a/dist/browser/jwe/flattened/decrypt.js +++ /dev/null @@ -1,138 +0,0 @@ -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 { 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 checkExtensions = validateCrit.bind(undefined, JWEInvalid, new Map()); -const checkAlgOption = validateAlgorithms.bind(undefined, 'keyManagementAlgorithms'); -const checkEncOption = validateAlgorithms.bind(undefined, 'contentEncryptionAlgorithms'); -async function flattenedDecrypt(jwe, key, options) { - var _a; - if (!isObject(jwe)) { - throw new JWEInvalid('Flattened JWE must be an object'); - } - if (jwe.protected === undefined && jwe.header === undefined && jwe.unprotected === undefined) { - throw new JWEInvalid('JOSE Header missing'); - } - if (typeof jwe.iv !== 'string') { - throw new JWEInvalid('JWE Initialization Vector missing or incorrect type'); - } - if (typeof jwe.ciphertext !== 'string') { - throw new JWEInvalid('JWE Ciphertext missing or incorrect type'); - } - if (typeof jwe.tag !== 'string') { - throw new JWEInvalid('JWE Authentication Tag missing or incorrect type'); - } - if (jwe.protected !== undefined && typeof jwe.protected !== 'string') { - throw new JWEInvalid('JWE Protected Header incorrect type'); - } - if (jwe.encrypted_key !== undefined && typeof jwe.encrypted_key !== 'string') { - throw new JWEInvalid('JWE Encrypted Key incorrect type'); - } - if (jwe.aad !== undefined && typeof jwe.aad !== 'string') { - throw new JWEInvalid('JWE AAD incorrect type'); - } - if (jwe.header !== undefined && !isObject(jwe.header)) { - throw new JWEInvalid('JWE Shared Unprotected Header incorrect type'); - } - if (jwe.unprotected !== undefined && !isObject(jwe.unprotected)) { - throw new JWEInvalid('JWE Per-Recipient Unprotected Header incorrect type'); - } - let parsedProt; - if (jwe.protected) { - const protectedHeader = base64url(jwe.protected); - try { - parsedProt = JSON.parse(decoder.decode(protectedHeader)); - } - catch (_b) { - throw new JWEInvalid('JWE Protected Header is invalid'); - } - } - 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 = { - ...parsedProt, - ...jwe.header, - ...jwe.unprotected, - }; - checkExtensions(options === null || options === void 0 ? void 0 : options.crit, parsedProt, joseHeader); - if (joseHeader.zip !== undefined) { - 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 (typeof alg !== 'string' || !alg) { - throw new JWEInvalid('missing JWE Algorithm (alg) in JWE Header'); - } - if (typeof enc !== 'string' || !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; - if (jwe.encrypted_key !== undefined) { - encryptedKey = base64url(jwe.encrypted_key); - } - if (typeof key === 'function') { - key = await key(parsedProt, jwe); - } - let cek; - try { - cek = await decryptKeyManagement(alg, key, encryptedKey, joseHeader); - } - catch (err) { - if (err instanceof TypeError) { - throw err; - } - cek = generateCek(enc); - } - const iv = base64url(jwe.iv); - const tag = base64url(jwe.tag); - const protectedHeader = encoder.encode((_a = jwe.protected) !== null && _a !== void 0 ? _a : ''); - let additionalData; - if (jwe.aad !== undefined) { - 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 === null || options === void 0 ? void 0 : options.inflateRaw) || inflate)(plaintext); - } - const result = { plaintext }; - if (jwe.protected !== undefined) { - result.protectedHeader = parsedProt; - } - if (jwe.aad !== undefined) { - result.additionalAuthenticatedData = base64url(jwe.aad); - } - if (jwe.unprotected !== undefined) { - result.sharedUnprotectedHeader = jwe.unprotected; - } - if (jwe.header !== undefined) { - result.unprotectedHeader = jwe.header; - } - return result; -} -export { flattenedDecrypt }; -export default flattenedDecrypt; diff --git a/dist/browser/jwe/flattened/encrypt.js b/dist/browser/jwe/flattened/encrypt.js deleted file mode 100644 index 371001bca7..0000000000 --- a/dist/browser/jwe/flattened/encrypt.js +++ /dev/null @@ -1,166 +0,0 @@ -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 checkExtensions = validateCrit.bind(undefined, JWEInvalid, new Map()); -class FlattenedEncrypt { - constructor(plaintext) { - this._plaintext = plaintext; - } - setKeyManagementParameters(parameters) { - if (this._keyManagementParameters) { - throw new TypeError('setKeyManagementParameters can only be called once'); - } - this._keyManagementParameters = parameters; - return this; - } - setProtectedHeader(protectedHeader) { - if (this._protectedHeader) { - throw new TypeError('setProtectedHeader can only be called once'); - } - this._protectedHeader = protectedHeader; - return this; - } - setSharedUnprotectedHeader(sharedUnprotectedHeader) { - if (this._sharedUnprotectedHeader) { - throw new TypeError('setSharedUnprotectedHeader can only be called once'); - } - this._sharedUnprotectedHeader = sharedUnprotectedHeader; - return this; - } - setUnprotectedHeader(unprotectedHeader) { - if (this._unprotectedHeader) { - throw new TypeError('setUnprotectedHeader can only be called once'); - } - this._unprotectedHeader = unprotectedHeader; - return this; - } - setAdditionalAuthenticatedData(aad) { - this._aad = aad; - return this; - } - setContentEncryptionKey(cek) { - if (this._cek) { - throw new TypeError('setContentEncryptionKey can only be called once'); - } - this._cek = cek; - return this; - } - setInitializationVector(iv) { - if (this._iv) { - throw new TypeError('setInitializationVector can only be called once'); - } - this._iv = iv; - return this; - } - async encrypt(key, options) { - 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 = { - ...this._protectedHeader, - ...this._unprotectedHeader, - ...this._sharedUnprotectedHeader, - }; - checkExtensions(options === null || options === void 0 ? void 0 : options.crit, this._protectedHeader, joseHeader); - if (joseHeader.zip !== undefined) { - 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 (typeof alg !== 'string' || !alg) { - throw new JWEInvalid('JWE "alg" (Algorithm) Header Parameter missing or invalid'); - } - if (typeof enc !== 'string' || !enc) { - throw new JWEInvalid('JWE "enc" (Encryption Algorithm) Header Parameter missing or invalid'); - } - let encryptedKey; - 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; - { - let parameters; - ({ 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 || (this._iv = generateIv(enc)); - let additionalData; - let protectedHeader; - let aadMember; - 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; - let tag; - if (joseHeader.zip === 'DEF') { - const deflated = await ((options === null || options === void 0 ? void 0 : 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 = { - 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 { FlattenedEncrypt }; -export default FlattenedEncrypt; diff --git a/dist/browser/jwe/general/decrypt.js b/dist/browser/jwe/general/decrypt.js deleted file mode 100644 index 41ec149d81..0000000000 --- a/dist/browser/jwe/general/decrypt.js +++ /dev/null @@ -1,30 +0,0 @@ -import decrypt from '../flattened/decrypt.js'; -import { JWEDecryptionFailed, JWEInvalid } from '../../util/errors.js'; -import isObject from '../../lib/is_object.js'; -async function generalDecrypt(jwe, key, options) { - if (!isObject(jwe)) { - throw new JWEInvalid('General JWE must be an object'); - } - if (!Array.isArray(jwe.recipients) || !jwe.recipients.every(isObject)) { - throw new JWEInvalid('JWE Recipients missing or incorrect type'); - } - for (const recipient of jwe.recipients) { - try { - return await decrypt({ - aad: jwe.aad, - ciphertext: jwe.ciphertext, - encrypted_key: recipient.encrypted_key, - header: recipient.header, - iv: jwe.iv, - protected: jwe.protected, - tag: jwe.tag, - unprotected: jwe.unprotected, - }, key, options); - } - catch (_a) { - } - } - throw new JWEDecryptionFailed(); -} -export { generalDecrypt }; -export default generalDecrypt; diff --git a/dist/browser/jwk/embedded.js b/dist/browser/jwk/embedded.js deleted file mode 100644 index 60759f22e0..0000000000 --- a/dist/browser/jwk/embedded.js +++ /dev/null @@ -1,19 +0,0 @@ -import parseJwk from './parse.js'; -import isObject from '../lib/is_object.js'; -import { JWSInvalid } from '../util/errors.js'; -async function EmbeddedJWK(protectedHeader, token) { - const joseHeader = { - ...protectedHeader, - ...token.header, - }; - if (!isObject(joseHeader.jwk)) { - throw new JWSInvalid('"jwk" (JSON Web Key) Header Parameter must be a JSON object'); - } - const key = await parseJwk(joseHeader.jwk, joseHeader.alg, true); - if (key.type !== 'public') { - throw new JWSInvalid('"jwk" (JSON Web Key) Header Parameter must be a public key'); - } - return key; -} -export { EmbeddedJWK }; -export default EmbeddedJWK; diff --git a/dist/browser/jwk/from_key_like.js b/dist/browser/jwk/from_key_like.js deleted file mode 100644 index 5ea9173e1c..0000000000 --- a/dist/browser/jwk/from_key_like.js +++ /dev/null @@ -1,6 +0,0 @@ -import asJWK from '../runtime/key_to_jwk.js'; -async function fromKeyLike(key) { - return asJWK(key); -} -export { fromKeyLike }; -export default fromKeyLike; diff --git a/dist/browser/jwk/parse.js b/dist/browser/jwk/parse.js deleted file mode 100644 index cfa6f9492c..0000000000 --- a/dist/browser/jwk/parse.js +++ /dev/null @@ -1,35 +0,0 @@ -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'; -async function parseJwk(jwk, alg, octAsKeyObject) { - if (!isObject(jwk)) { - throw new TypeError('JWK must be an object'); - } - alg || (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'); - } - octAsKeyObject !== null && octAsKeyObject !== void 0 ? octAsKeyObject : (octAsKeyObject = jwk.ext !== true); - if (octAsKeyObject) { - return asKeyObject({ ...jwk, alg, ext: false }); - } - return base64url(jwk.k); - case 'RSA': - if (jwk.oth !== undefined) { - throw new JOSENotSupported('RSA JWK "oth" (Other Primes Info) Parameter value is not supported'); - } - case 'EC': - case 'OKP': - return asKeyObject({ ...jwk, alg }); - default: - throw new JOSENotSupported('unsupported "kty" (Key Type) Parameter value'); - } -} -export { parseJwk }; -export default parseJwk; diff --git a/dist/browser/jwk/thumbprint.js b/dist/browser/jwk/thumbprint.js deleted file mode 100644 index ffb569b31f..0000000000 --- a/dist/browser/jwk/thumbprint.js +++ /dev/null @@ -1,44 +0,0 @@ -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 isObject from '../lib/is_object.js'; -const check = (value, description) => { - if (typeof value !== 'string' || !value) { - throw new JWKInvalid(`${description} missing or invalid`); - } -}; -async function calculateThumbprint(jwk, digestAlgorithm = 'sha256') { - if (!isObject(jwk)) { - throw new TypeError('JWK must be an object'); - } - let components; - 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 { calculateThumbprint }; -export default calculateThumbprint; diff --git a/dist/browser/jwks/remote.js b/dist/browser/jwks/remote.js deleted file mode 100644 index 7665477163..0000000000 --- a/dist/browser/jwks/remote.js +++ /dev/null @@ -1,130 +0,0 @@ -import parseJWK from '../jwk/parse.js'; -import { JWKSInvalid, JOSENotSupported, JWKSNoMatchingKey, JWKSMultipleMatchingKeys, } from '../util/errors.js'; -import fetchJwks from '../runtime/fetch_jwks.js'; -import isObject from '../lib/is_object.js'; -function getKtyFromAlg(alg) { - 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'); - } -} -function isJWKLike(key) { - return isObject(key); -} -class RemoteJWKSet { - constructor(url, options) { - this._cached = new WeakMap(); - if (!(url instanceof URL)) { - throw new TypeError('url must be an instance of URL'); - } - this._url = new URL(url.href); - this._options = { agent: options === null || options === void 0 ? void 0 : options.agent }; - this._timeoutDuration = - typeof (options === null || options === void 0 ? void 0 : options.timeoutDuration) === 'number' ? options === null || options === void 0 ? void 0 : options.timeoutDuration : 5000; - this._cooldownDuration = - typeof (options === null || options === void 0 ? void 0 : options.cooldownDuration) === 'number' ? options === null || options === void 0 ? void 0 : options.cooldownDuration : 30000; - } - coolingDown() { - if (typeof this._cooldownStarted === 'undefined') { - return false; - } - return Date.now() < this._cooldownStarted + this._cooldownDuration; - } - async getKey(protectedHeader) { - if (!this._jwks) { - await this.reload(); - } - const candidates = this._jwks.keys.filter((jwk) => { - let candidate = jwk.kty === getKtyFromAlg(protectedHeader.alg); - if (candidate && typeof protectedHeader.kid === 'string') { - candidate = protectedHeader.kid === jwk.kid; - } - if (candidate && typeof jwk.alg === 'string') { - candidate = protectedHeader.alg === jwk.alg; - } - if (candidate && typeof jwk.use === 'string') { - candidate = jwk.use === 'sig'; - } - if (candidate && Array.isArray(jwk.key_ops)) { - candidate = jwk.key_ops.includes('verify'); - } - if (candidate && protectedHeader.alg === 'EdDSA') { - candidate = ['Ed25519', 'Ed448'].includes(jwk.crv); - } - 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 (cached[protectedHeader.alg] === undefined) { - const keyObject = await parseJWK({ ...jwk, alg: protectedHeader.alg }); - 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 = fetchJwks(this._url, this._timeoutDuration, this._options) - .then((json) => { - if (typeof json !== 'object' || - !json || - !Array.isArray(json.keys) || - !json.keys.every(isJWKLike)) { - throw new JWKSInvalid('JSON Web Key Set malformed'); - } - this._jwks = { keys: json.keys }; - this._cooldownStarted = Date.now(); - this._pendingFetch = undefined; - }) - .catch((err) => { - this._pendingFetch = undefined; - throw err; - }); - } - await this._pendingFetch; - } -} -function createRemoteJWKSet(url, options) { - return RemoteJWKSet.prototype.getKey.bind(new RemoteJWKSet(url, options)); -} -export { createRemoteJWKSet }; -export default createRemoteJWKSet; diff --git a/dist/browser/jws/compact/sign.js b/dist/browser/jws/compact/sign.js deleted file mode 100644 index 5bacca34d9..0000000000 --- a/dist/browser/jws/compact/sign.js +++ /dev/null @@ -1,19 +0,0 @@ -import FlattenedSign from '../flattened/sign.js'; -class CompactSign { - constructor(payload) { - this._flattened = new FlattenedSign(payload); - } - setProtectedHeader(protectedHeader) { - this._flattened.setProtectedHeader(protectedHeader); - return this; - } - async sign(key, options) { - const jws = await this._flattened.sign(key, options); - 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 { CompactSign }; -export default CompactSign; diff --git a/dist/browser/jws/compact/verify.js b/dist/browser/jws/compact/verify.js deleted file mode 100644 index aad640718b..0000000000 --- a/dist/browser/jws/compact/verify.js +++ /dev/null @@ -1,23 +0,0 @@ -import verify from '../flattened/verify.js'; -import { JWSInvalid } from '../../util/errors.js'; -import { decoder } from '../../lib/buffer_utils.js'; -async function compactVerify(jws, key, options) { - if (jws instanceof Uint8Array) { - jws = decoder.decode(jws); - } - if (typeof jws !== 'string') { - throw new JWSInvalid('Compact JWS must be a string or Uint8Array'); - } - const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split('.'); - if (length !== 3) { - throw new JWSInvalid('Invalid Compact JWS'); - } - const verified = await verify({ - payload: (payload || undefined), - protected: protectedHeader || undefined, - signature: (signature || undefined), - }, key, options); - return { payload: verified.payload, protectedHeader: verified.protectedHeader }; -} -export { compactVerify }; -export default compactVerify; diff --git a/dist/browser/jws/flattened/sign.js b/dist/browser/jws/flattened/sign.js deleted file mode 100644 index 35d9cb5e45..0000000000 --- a/dist/browser/jws/flattened/sign.js +++ /dev/null @@ -1,81 +0,0 @@ -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 checkKeyType from '../../lib/check_key_type.js'; -import validateCrit from '../../lib/validate_crit.js'; -const checkExtensions = validateCrit.bind(undefined, JWSInvalid, new Map([['b64', true]])); -class FlattenedSign { - constructor(payload) { - this._payload = payload; - } - setProtectedHeader(protectedHeader) { - if (this._protectedHeader) { - throw new TypeError('setProtectedHeader can only be called once'); - } - this._protectedHeader = protectedHeader; - return this; - } - setUnprotectedHeader(unprotectedHeader) { - if (this._unprotectedHeader) { - throw new TypeError('setUnprotectedHeader can only be called once'); - } - this._unprotectedHeader = unprotectedHeader; - return this; - } - async sign(key, options) { - 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 = { - ...this._protectedHeader, - ...this._unprotectedHeader, - }; - const extensions = checkExtensions(options === null || options === void 0 ? void 0 : options.crit, this._protectedHeader, joseHeader); - let b64 = 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 (typeof alg !== 'string' || !alg) { - throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid'); - } - checkKeyType(alg, key, 'sign'); - let payload = this._payload; - if (b64) { - payload = encoder.encode(base64url(payload)); - } - let protectedHeader; - 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 = { - signature: base64url(signature), - payload: '', - }; - 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 { FlattenedSign }; -export default FlattenedSign; diff --git a/dist/browser/jws/flattened/verify.js b/dist/browser/jws/flattened/verify.js deleted file mode 100644 index 61652d26b6..0000000000 --- a/dist/browser/jws/flattened/verify.js +++ /dev/null @@ -1,103 +0,0 @@ -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'; -const checkExtensions = validateCrit.bind(undefined, JWSInvalid, new Map([['b64', true]])); -const checkAlgOption = validateAlgorithms.bind(undefined, 'algorithms'); -async function flattenedVerify(jws, key, options) { - var _a; - if (!isObject(jws)) { - throw new JWSInvalid('Flattened JWS must be an object'); - } - if (jws.protected === undefined && jws.header === undefined) { - throw new JWSInvalid('Flattened JWS must have either of the "protected" or "header" members'); - } - if (jws.protected !== undefined && typeof jws.protected !== 'string') { - throw new JWSInvalid('JWS Protected Header incorrect type'); - } - if (jws.payload === undefined) { - throw new JWSInvalid('JWS Payload missing'); - } - if (typeof jws.signature !== 'string') { - throw new JWSInvalid('JWS Signature missing or incorrect type'); - } - if (jws.header !== undefined && !isObject(jws.header)) { - throw new JWSInvalid('JWS Unprotected Header incorrect type'); - } - let parsedProt = {}; - if (jws.protected) { - const protectedHeader = base64url(jws.protected); - try { - parsedProt = JSON.parse(decoder.decode(protectedHeader)); - } - catch (_b) { - throw new JWSInvalid('JWS Protected Header is invalid'); - } - } - if (!isDisjoint(parsedProt, jws.header)) { - throw new JWSInvalid('JWS Protected and JWS Unprotected Header Parameter names must be disjoint'); - } - const joseHeader = { - ...parsedProt, - ...jws.header, - }; - const extensions = checkExtensions(options === null || options === void 0 ? void 0 : options.crit, parsedProt, joseHeader); - let b64 = 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 (typeof alg !== 'string' || !alg) { - throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid'); - } - 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') { - key = await key(parsedProt, jws); - } - checkKeyType(alg, key, 'verify'); - const data = concat(encoder.encode((_a = jws.protected) !== null && _a !== void 0 ? _a : ''), 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; - if (b64) { - payload = base64url(jws.payload); - } - else if (typeof jws.payload === 'string') { - payload = encoder.encode(jws.payload); - } - else { - payload = jws.payload; - } - const result = { payload }; - if (jws.protected !== undefined) { - result.protectedHeader = parsedProt; - } - if (jws.header !== undefined) { - result.unprotectedHeader = jws.header; - } - return result; -} -export { flattenedVerify }; -export default flattenedVerify; diff --git a/dist/browser/jws/general/sign.js b/dist/browser/jws/general/sign.js deleted file mode 100644 index 7127accfa1..0000000000 --- a/dist/browser/jws/general/sign.js +++ /dev/null @@ -1,73 +0,0 @@ -import FlattenedSign from '../flattened/sign.js'; -import { JWSInvalid } from '../../util/errors.js'; -const signatureRef = new WeakMap(); -class IndividualSignature { - setProtectedHeader(protectedHeader) { - if (this._protectedHeader) { - throw new TypeError('setProtectedHeader can only be called once'); - } - this._protectedHeader = protectedHeader; - return this; - } - setUnprotectedHeader(unprotectedHeader) { - if (this._unprotectedHeader) { - throw new TypeError('setUnprotectedHeader can only be called once'); - } - this._unprotectedHeader = unprotectedHeader; - return this; - } - set _protectedHeader(value) { - signatureRef.get(this).protectedHeader = value; - } - get _protectedHeader() { - return signatureRef.get(this).protectedHeader; - } - set _unprotectedHeader(value) { - signatureRef.get(this).unprotectedHeader = value; - } - get _unprotectedHeader() { - return signatureRef.get(this).unprotectedHeader; - } -} -class GeneralSign { - constructor(payload) { - this._signatures = []; - this._payload = payload; - } - addSignature(key, options) { - const signature = new IndividualSignature(); - signatureRef.set(signature, { key, options }); - this._signatures.push(signature); - return signature; - } - async sign() { - if (!this._signatures.length) { - throw new JWSInvalid('at least one signature must be added'); - } - const jws = { - signatures: [], - payload: '', - }; - let payloads = new Set(); - await Promise.all(this._signatures.map(async (sig) => { - const { protectedHeader, unprotectedHeader, options, key } = signatureRef.get(sig); - const flattened = new FlattenedSign(this._payload); - if (protectedHeader) { - flattened.setProtectedHeader(protectedHeader); - } - if (unprotectedHeader) { - flattened.setUnprotectedHeader(unprotectedHeader); - } - const { payload, ...rest } = await flattened.sign(key, options); - payloads.add(payload); - jws.payload = payload; - jws.signatures.push(rest); - })); - if (payloads.size !== 1) { - throw new JWSInvalid('inconsistent use of JWS Unencoded Payload Option (RFC7797)'); - } - return jws; - } -} -export { GeneralSign }; -export default GeneralSign; diff --git a/dist/browser/jws/general/verify.js b/dist/browser/jws/general/verify.js deleted file mode 100644 index e44ae2e50b..0000000000 --- a/dist/browser/jws/general/verify.js +++ /dev/null @@ -1,26 +0,0 @@ -import verify from '../flattened/verify.js'; -import { JWSInvalid, JWSSignatureVerificationFailed } from '../../util/errors.js'; -import isObject from '../../lib/is_object.js'; -async function generalVerify(jws, key, options) { - if (!isObject(jws)) { - throw new JWSInvalid('General JWS must be an object'); - } - if (!Array.isArray(jws.signatures) || !jws.signatures.every(isObject)) { - throw new JWSInvalid('JWS Signatures missing or incorrect type'); - } - for (const signature of jws.signatures) { - try { - return await verify({ - header: signature.header, - payload: jws.payload, - protected: signature.protected, - signature: signature.signature, - }, key, options); - } - catch (_a) { - } - } - throw new JWSSignatureVerificationFailed(); -} -export { generalVerify }; -export default generalVerify; diff --git a/dist/browser/jwt/decrypt.js b/dist/browser/jwt/decrypt.js deleted file mode 100644 index ed1b4286c5..0000000000 --- a/dist/browser/jwt/decrypt.js +++ /dev/null @@ -1,21 +0,0 @@ -import decrypt from '../jwe/compact/decrypt.js'; -import jwtPayload from '../lib/jwt_claims_set.js'; -import { JWTClaimValidationFailed } from '../util/errors.js'; -async function jwtDecrypt(jwt, key, options) { - const decrypted = await decrypt(jwt, key, options); - const payload = jwtPayload(decrypted.protectedHeader, decrypted.plaintext, options); - const { protectedHeader } = decrypted; - if (protectedHeader.iss !== undefined && protectedHeader.iss !== payload.iss) { - throw new JWTClaimValidationFailed('replicated "iss" claim header parameter mismatch', 'iss', 'mismatch'); - } - if (protectedHeader.sub !== undefined && protectedHeader.sub !== payload.sub) { - throw new JWTClaimValidationFailed('replicated "sub" claim header parameter mismatch', 'sub', 'mismatch'); - } - if (protectedHeader.aud !== undefined && - JSON.stringify(protectedHeader.aud) !== JSON.stringify(payload.aud)) { - throw new JWTClaimValidationFailed('replicated "aud" claim header parameter mismatch', 'aud', 'mismatch'); - } - return { payload, protectedHeader }; -} -export { jwtDecrypt }; -export default jwtDecrypt; diff --git a/dist/browser/jwt/encrypt.js b/dist/browser/jwt/encrypt.js deleted file mode 100644 index ef8ac9156f..0000000000 --- a/dist/browser/jwt/encrypt.js +++ /dev/null @@ -1,70 +0,0 @@ -import CompactEncrypt from '../jwe/compact/encrypt.js'; -import { encoder } from '../lib/buffer_utils.js'; -import ProduceJWT from '../lib/jwt_producer.js'; -class EncryptJWT extends ProduceJWT { - setProtectedHeader(protectedHeader) { - if (this._protectedHeader) { - throw new TypeError('setProtectedHeader can only be called once'); - } - this._protectedHeader = protectedHeader; - return this; - } - setKeyManagementParameters(parameters) { - if (this._keyManagementParameters) { - throw new TypeError('setKeyManagementParameters can only be called once'); - } - this._keyManagementParameters = parameters; - return this; - } - setContentEncryptionKey(cek) { - if (this._cek) { - throw new TypeError('setContentEncryptionKey can only be called once'); - } - this._cek = cek; - return this; - } - setInitializationVector(iv) { - if (this._iv) { - throw new TypeError('setInitializationVector can only be called once'); - } - this._iv = iv; - return this; - } - replicateIssuerAsHeader() { - this._replicateIssuerAsHeader = true; - return this; - } - replicateSubjectAsHeader() { - this._replicateSubjectAsHeader = true; - return this; - } - replicateAudienceAsHeader() { - this._replicateAudienceAsHeader = true; - return this; - } - async encrypt(key, options) { - 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 { EncryptJWT }; -export default EncryptJWT; diff --git a/dist/browser/jwt/sign.js b/dist/browser/jwt/sign.js deleted file mode 100644 index 0707f7ebf7..0000000000 --- a/dist/browser/jwt/sign.js +++ /dev/null @@ -1,23 +0,0 @@ -import CompactSign from '../jws/compact/sign.js'; -import { JWTInvalid } from '../util/errors.js'; -import { encoder } from '../lib/buffer_utils.js'; -import ProduceJWT from '../lib/jwt_producer.js'; -class SignJWT extends ProduceJWT { - setProtectedHeader(protectedHeader) { - this._protectedHeader = protectedHeader; - return this; - } - async sign(key, options) { - var _a; - const sig = new CompactSign(encoder.encode(JSON.stringify(this._payload))); - sig.setProtectedHeader(this._protectedHeader); - if (Array.isArray((_a = this._protectedHeader) === null || _a === void 0 ? void 0 : _a.crit) && - this._protectedHeader.crit.includes('b64') && - this._protectedHeader.b64 === false) { - throw new JWTInvalid('JWTs MUST NOT use unencoded payload'); - } - return sig.sign(key, options); - } -} -export { SignJWT }; -export default SignJWT; diff --git a/dist/browser/jwt/unsecured.js b/dist/browser/jwt/unsecured.js deleted file mode 100644 index e7fa0535e5..0000000000 --- a/dist/browser/jwt/unsecured.js +++ /dev/null @@ -1,34 +0,0 @@ -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'; -class UnsecuredJWT extends ProduceJWT { - encode() { - const header = base64url.encode(JSON.stringify({ alg: 'none' })); - const payload = base64url.encode(JSON.stringify(this._payload)); - return `${header}.${payload}.`; - } - static decode(jwt, options) { - 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; - try { - header = JSON.parse(decoder.decode(base64url.decode(encodedHeader))); - if (header.alg !== 'none') - throw new Error(); - } - catch (_a) { - throw new JWTInvalid('Invalid Unsecured JWT'); - } - const payload = jwtPayload(header, base64url.decode(encodedPayload), options); - return { payload, header }; - } -} -export { UnsecuredJWT }; -export default UnsecuredJWT; diff --git a/dist/browser/jwt/verify.js b/dist/browser/jwt/verify.js deleted file mode 100644 index 2295d81306..0000000000 --- a/dist/browser/jwt/verify.js +++ /dev/null @@ -1,14 +0,0 @@ -import verify from '../jws/compact/verify.js'; -import jwtPayload from '../lib/jwt_claims_set.js'; -import { JWTInvalid } from '../util/errors.js'; -async function jwtVerify(jwt, key, options) { - var _a; - const verified = await verify(jwt, key, options); - if (((_a = verified.protectedHeader.crit) === null || _a === void 0 ? void 0 : _a.includes('b64')) && verified.protectedHeader.b64 === false) { - throw new JWTInvalid('JWTs MUST NOT use unencoded payload'); - } - const payload = jwtPayload(verified.protectedHeader, verified.payload, options); - return { payload, protectedHeader: verified.protectedHeader }; -} -export { jwtVerify }; -export default jwtVerify; diff --git a/dist/browser/lib/buffer_utils.js b/dist/browser/lib/buffer_utils.js deleted file mode 100644 index d9392a633d..0000000000 --- a/dist/browser/lib/buffer_utils.js +++ /dev/null @@ -1,56 +0,0 @@ -export const encoder = new TextEncoder(); -export const decoder = new TextDecoder(); -const MAX_INT32 = 2 ** 32; -export function concat(...buffers) { - 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, p2sInput) { - return concat(encoder.encode(alg), new Uint8Array([0]), p2sInput); -} -function writeUInt32BE(buf, value, offset) { - 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) { - 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) { - const buf = new Uint8Array(4); - writeUInt32BE(buf, value); - return buf; -} -export function lengthAndInput(input) { - return concat(uint32be(input.length), input); -} -export async function concatKdf(digest, secret, bits, value) { - const iterations = Math.ceil((bits >> 3) / 32); - let res; - 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('sha256', buf); - } - else { - res = concat(res, await digest('sha256', buf)); - } - } - res = res.slice(0, bits >> 3); - return res; -} diff --git a/dist/browser/lib/cek.js b/dist/browser/lib/cek.js deleted file mode 100644 index 702d8a0533..0000000000 --- a/dist/browser/lib/cek.js +++ /dev/null @@ -1,18 +0,0 @@ -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) => (alg) => { - 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/dist/browser/lib/check_iv_length.js b/dist/browser/lib/check_iv_length.js deleted file mode 100644 index 3bb1ecb38a..0000000000 --- a/dist/browser/lib/check_iv_length.js +++ /dev/null @@ -1,8 +0,0 @@ -import { JWEInvalid } from '../util/errors.js'; -import { bitLengths } from './iv.js'; -const checkIvLength = (enc, iv) => { - if (iv.length << 3 !== bitLengths.get(enc)) { - throw new JWEInvalid('Invalid Initialization Vector length'); - } -}; -export default checkIvLength; diff --git a/dist/browser/lib/check_key_type.js b/dist/browser/lib/check_key_type.js deleted file mode 100644 index 4702e55436..0000000000 --- a/dist/browser/lib/check_key_type.js +++ /dev/null @@ -1,28 +0,0 @@ -import invalidKeyInput from '../runtime/invalid_key_input.js'; -const checkKeyType = (alg, key, usage) => { - if (!(key instanceof Uint8Array) && !(key === null || key === void 0 ? void 0 : key.type)) { - throw new TypeError(invalidKeyInput(key, 'KeyObject', 'CryptoKey', 'Uint8Array')); - } - 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(invalidKeyInput(key, 'KeyObject', 'CryptoKey')); - } - if (key.type === 'secret') { - throw new TypeError('CryptoKey or KeyObject instances for asymmetric algorithms must not be of type "secret"'); - } - if (usage === 'sign' && key.type === 'public') { - throw new TypeError('CryptoKey or KeyObject instances for asymmetric algorithm signing must be of type "private"'); - } - if (usage === 'decrypt' && key.type === 'public') { - throw new TypeError('CryptoKey or KeyObject instances for asymmetric algorithm decryption must be of type "private"'); - } -}; -export default checkKeyType; diff --git a/dist/browser/lib/check_p2s.js b/dist/browser/lib/check_p2s.js deleted file mode 100644 index a65289fa7a..0000000000 --- a/dist/browser/lib/check_p2s.js +++ /dev/null @@ -1,6 +0,0 @@ -import { JWEInvalid } from '../util/errors.js'; -export default function checkP2s(p2s) { - if (!(p2s instanceof Uint8Array) || p2s.length < 8) { - throw new JWEInvalid('PBES2 Salt Input must be 8 or more octets'); - } -} diff --git a/dist/browser/lib/decrypt_key_management.js b/dist/browser/lib/decrypt_key_management.js deleted file mode 100644 index d82f5c100f..0000000000 --- a/dist/browser/lib/decrypt_key_management.js +++ /dev/null @@ -1,95 +0,0 @@ -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'; -import { parseJwk } from '../jwk/parse.js'; -import checkKeyType from './check_key_type.js'; -function assertEnryptedKey(encryptedKey) { - if (!encryptedKey) { - throw new JWEInvalid('JWE Encrypted Key missing'); - } -} -function assertHeaderParameter(joseHeader, parameter, name) { - if (joseHeader[parameter] === undefined) { - throw new JWEInvalid(`JOSE Header ${name} (${parameter}) missing`); - } -} -async function decryptKeyManagement(alg, key, encryptedKey, joseHeader) { - checkKeyType(alg, key, 'decrypt'); - switch (alg) { - case 'dir': { - if (encryptedKey !== undefined) { - throw new JWEInvalid('Encountered unexpected JWE Encrypted Key'); - } - return key; - } - case 'ECDH-ES': - if (encryptedKey !== undefined) { - throw new JWEInvalid('Encountered unexpected JWE Encrypted Key'); - } - case 'ECDH-ES+A128KW': - case 'ECDH-ES+A192KW': - case 'ECDH-ES+A256KW': { - assertHeaderParameter(joseHeader, 'epk', 'Ephemeral Public Key'); - if (!ECDH.ecdhAllowed(key)) { - throw new JOSENotSupported('ECDH-ES with the provided key is not allowed or not supported by your javascript runtime'); - } - const epk = await parseJwk(joseHeader.epk, alg); - let partyUInfo; - let partyVInfo; - if (joseHeader.apu !== undefined) - partyUInfo = base64url(joseHeader.apu); - if (joseHeader.apv !== undefined) - partyVInfo = base64url(joseHeader.apv); - const sharedSecret = await ECDH.deriveKey(epk, key, alg === 'ECDH-ES' ? joseHeader.enc : alg, parseInt(alg.substr(-5, 3), 10) || cekLengths.get(joseHeader.enc), partyUInfo, partyVInfo); - if (alg === 'ECDH-ES') { - return sharedSecret; - } - 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': { - assertEnryptedKey(encryptedKey); - return rsaEs(alg, key, encryptedKey); - } - case 'PBES2-HS256+A128KW': - case 'PBES2-HS384+A192KW': - case 'PBES2-HS512+A256KW': { - 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': { - assertEnryptedKey(encryptedKey); - return aesKw(alg, key, encryptedKey); - } - case 'A128GCMKW': - case 'A192GCMKW': - case 'A256GCMKW': { - 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('unsupported or invalid "alg" (JWE Algorithm) header value'); - } - } -} -export default decryptKeyManagement; diff --git a/dist/browser/lib/encrypt_key_management.js b/dist/browser/lib/encrypt_key_management.js deleted file mode 100644 index 97199e204e..0000000000 --- a/dist/browser/lib/encrypt_key_management.js +++ /dev/null @@ -1,87 +0,0 @@ -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'; -import { fromKeyLike } from '../jwk/from_key_like.js'; -import checkKeyType from './check_key_type.js'; -const generateCek = cekFactory(random); -async function encryptKeyManagement(alg, enc, key, providedCek, providedParameters = {}) { - let encryptedKey; - let parameters; - let cek; - checkKeyType(alg, key, 'encrypt'); - switch (alg) { - case 'dir': { - cek = key; - break; - } - case 'ECDH-ES': - case 'ECDH-ES+A128KW': - case 'ECDH-ES+A192KW': - case 'ECDH-ES+A256KW': { - if (!ECDH.ecdhAllowed(key)) { - throw new JOSENotSupported('ECDH-ES with the provided key is not allowed or not supported by your javascript runtime'); - } - const { apu, apv } = providedParameters; - let { epk: ephemeralKey } = providedParameters; - ephemeralKey || (ephemeralKey = await ECDH.generateEpk(key)); - const { x, y, crv, kty } = await fromKeyLike(ephemeralKey); - const sharedSecret = await ECDH.deriveKey(key, ephemeralKey, alg === 'ECDH-ES' ? enc : alg, parseInt(alg.substr(-5, 3), 10) || cekLengths.get(enc), apu, apv); - parameters = { epk: { x, y, crv, kty } }; - if (apu) - parameters.apu = base64url(apu); - if (apv) - parameters.apv = base64url(apv); - if (alg === 'ECDH-ES') { - cek = sharedSecret; - break; - } - cek = providedCek || 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': { - cek = providedCek || generateCek(enc); - encryptedKey = await rsaEs(alg, key, cek); - break; - } - case 'PBES2-HS256+A128KW': - case 'PBES2-HS384+A192KW': - case 'PBES2-HS512+A256KW': { - cek = providedCek || generateCek(enc); - const { p2c, p2s } = providedParameters; - ({ encryptedKey, ...parameters } = await pbes2Kw(alg, key, cek, p2c, p2s)); - break; - } - case 'A128KW': - case 'A192KW': - case 'A256KW': { - cek = providedCek || generateCek(enc); - encryptedKey = await aesKw(alg, key, cek); - break; - } - case 'A128GCMKW': - case 'A192GCMKW': - case 'A256GCMKW': { - cek = providedCek || generateCek(enc); - const { iv } = providedParameters; - ({ encryptedKey, ...parameters } = await aesGcmKw(alg, key, cek, iv)); - break; - } - default: { - throw new JOSENotSupported('unsupported or invalid "alg" (JWE Algorithm) header value'); - } - } - return { cek, encryptedKey, parameters }; -} -export default encryptKeyManagement; diff --git a/dist/browser/lib/epoch.js b/dist/browser/lib/epoch.js deleted file mode 100644 index e405e4b2df..0000000000 --- a/dist/browser/lib/epoch.js +++ /dev/null @@ -1 +0,0 @@ -export default (date) => Math.floor(date.getTime() / 1000); diff --git a/dist/browser/lib/is_disjoint.js b/dist/browser/lib/is_disjoint.js deleted file mode 100644 index 6f643502dc..0000000000 --- a/dist/browser/lib/is_disjoint.js +++ /dev/null @@ -1,22 +0,0 @@ -const isDisjoint = (...headers) => { - const sources = headers.filter(Boolean); - if (sources.length === 0 || sources.length === 1) { - return true; - } - let acc; - 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/dist/browser/lib/is_object.js b/dist/browser/lib/is_object.js deleted file mode 100644 index 4955e93225..0000000000 --- a/dist/browser/lib/is_object.js +++ /dev/null @@ -1,16 +0,0 @@ -function isObjectLike(value) { - return typeof value === 'object' && value !== null; -} -export default function isObject(input) { - if (!isObjectLike(input) || Object.prototype.toString.call(input) !== '[object Object]') { - return false; - } - if (Object.getPrototypeOf(input) === null) { - return true; - } - let proto = input; - while (Object.getPrototypeOf(proto) !== null) { - proto = Object.getPrototypeOf(proto); - } - return Object.getPrototypeOf(input) === proto; -} diff --git a/dist/browser/lib/iv.js b/dist/browser/lib/iv.js deleted file mode 100644 index d254aa16dc..0000000000 --- a/dist/browser/lib/iv.js +++ /dev/null @@ -1,21 +0,0 @@ -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) => (alg) => { - 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/dist/browser/lib/jwt_claims_set.js b/dist/browser/lib/jwt_claims_set.js deleted file mode 100644 index 90b30a4e98..0000000000 --- a/dist/browser/lib/jwt_claims_set.js +++ /dev/null @@ -1,96 +0,0 @@ -import { JWTClaimValidationFailed, JWTExpired, JWTInvalid } from '../util/errors.js'; -import { decoder } from './buffer_utils.js'; -import epoch from './epoch.js'; -import secs from './secs.js'; -import isObject from './is_object.js'; -const normalizeTyp = (value) => value.toLowerCase().replace(/^application\//, ''); -const checkAudiencePresence = (audPayload, audOption) => { - if (typeof audPayload === 'string') { - return audOption.includes(audPayload); - } - if (Array.isArray(audPayload)) { - return audOption.some(Set.prototype.has.bind(new Set(audPayload))); - } - return false; -}; -export default (protectedHeader, encodedPayload, options = {}) => { - 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; - try { - payload = JSON.parse(decoder.decode(encodedPayload)); - } - catch (_a) { - } - if (!isObject(payload)) { - throw new JWTInvalid('JWT Claims Set must be a top-level JSON object'); - } - const { issuer } = options; - if (issuer && !(Array.isArray(issuer) ? 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; - 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 (payload.iat !== undefined || options.maxTokenAge) { - if (typeof payload.iat !== 'number') { - throw new JWTClaimValidationFailed('"iat" claim must be a number', 'iat', 'invalid'); - } - if (payload.exp === undefined && payload.iat > now + tolerance) { - throw new JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', 'iat', 'check_failed'); - } - } - if (payload.nbf !== undefined) { - 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 (payload.exp !== undefined) { - 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/dist/browser/lib/jwt_producer.js b/dist/browser/lib/jwt_producer.js deleted file mode 100644 index e6b047337c..0000000000 --- a/dist/browser/lib/jwt_producer.js +++ /dev/null @@ -1,54 +0,0 @@ -import epoch from './epoch.js'; -import isObject from './is_object.js'; -import secs from './secs.js'; -export default class ProduceJWT { - constructor(payload) { - if (!isObject(payload)) { - throw new TypeError('JWT Claims Set MUST be an object'); - } - this._payload = payload; - } - setIssuer(issuer) { - this._payload = { ...this._payload, iss: issuer }; - return this; - } - setSubject(subject) { - this._payload = { ...this._payload, sub: subject }; - return this; - } - setAudience(audience) { - this._payload = { ...this._payload, aud: audience }; - return this; - } - setJti(jwtId) { - this._payload = { ...this._payload, jti: jwtId }; - return this; - } - setNotBefore(input) { - if (typeof input === 'number') { - this._payload = { ...this._payload, nbf: input }; - } - else { - this._payload = { ...this._payload, nbf: epoch(new Date()) + secs(input) }; - } - return this; - } - setExpirationTime(input) { - if (typeof input === 'number') { - this._payload = { ...this._payload, exp: input }; - } - else { - this._payload = { ...this._payload, exp: epoch(new Date()) + secs(input) }; - } - return this; - } - setIssuedAt(input) { - if (typeof input === 'undefined') { - this._payload = { ...this._payload, iat: epoch(new Date()) }; - } - else { - this._payload = { ...this._payload, iat: input }; - } - return this; - } -} diff --git a/dist/browser/lib/secs.js b/dist/browser/lib/secs.js deleted file mode 100644 index cf470ed8ad..0000000000 --- a/dist/browser/lib/secs.js +++ /dev/null @@ -1,44 +0,0 @@ -const minute = 60; -const hour = minute * 60; -const day = hour * 24; -const week = day * 7; -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; -export default (str) => { - const matched = REGEX.exec(str); - if (!matched) { - throw new TypeError('Invalid time period format'); - } - const value = parseFloat(matched[1]); - const unit = matched[2].toLowerCase(); - switch (unit) { - case 'sec': - case 'secs': - case 'second': - case 'seconds': - case 's': - return Math.round(value); - case 'minute': - case 'minutes': - case 'min': - case 'mins': - case 'm': - return Math.round(value * minute); - case 'hour': - case 'hours': - case 'hr': - case 'hrs': - case 'h': - return Math.round(value * hour); - case 'day': - case 'days': - case 'd': - return Math.round(value * day); - case 'week': - case 'weeks': - case 'w': - return Math.round(value * week); - default: - return Math.round(value * year); - } -}; diff --git a/dist/browser/lib/validate_algorithms.js b/dist/browser/lib/validate_algorithms.js deleted file mode 100644 index a6a7918571..0000000000 --- a/dist/browser/lib/validate_algorithms.js +++ /dev/null @@ -1,11 +0,0 @@ -const validateAlgorithms = (option, algorithms) => { - 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/dist/browser/lib/validate_crit.js b/dist/browser/lib/validate_crit.js deleted file mode 100644 index 68c69f18f5..0000000000 --- a/dist/browser/lib/validate_crit.js +++ /dev/null @@ -1,34 +0,0 @@ -import { JOSENotSupported } from '../util/errors.js'; -function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) { - if (joseHeader.crit !== undefined && protectedHeader.crit === undefined) { - throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected'); - } - if (!protectedHeader || protectedHeader.crit === undefined) { - return new Set(); - } - if (!Array.isArray(protectedHeader.crit) || - protectedHeader.crit.length === 0 || - protectedHeader.crit.some((input) => typeof input !== 'string' || input.length === 0)) { - throw new Err('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present'); - } - let recognized; - if (recognizedOption !== undefined) { - recognized = new Map([...Object.entries(recognizedOption), ...recognizedDefault.entries()]); - } - else { - recognized = recognizedDefault; - } - for (const parameter of protectedHeader.crit) { - if (!recognized.has(parameter)) { - throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`); - } - if (joseHeader[parameter] === undefined) { - throw new Err(`Extension Header Parameter "${parameter}" is missing`); - } - else if (recognized.get(parameter) && protectedHeader[parameter] === undefined) { - throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`); - } - } - return new Set(protectedHeader.crit); -} -export default validateCrit; diff --git a/dist/browser/package.json b/dist/browser/package.json deleted file mode 100644 index 6990891ff3..0000000000 --- a/dist/browser/package.json +++ /dev/null @@ -1 +0,0 @@ -{"type": "module"} diff --git a/dist/browser/runtime/aesgcmkw.js b/dist/browser/runtime/aesgcmkw.js deleted file mode 100644 index 5fd5acc5b2..0000000000 --- a/dist/browser/runtime/aesgcmkw.js +++ /dev/null @@ -1,16 +0,0 @@ -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 = async (alg, key, cek, iv) => { - const jweAlgorithm = alg.substr(0, 7); - iv || (iv = generateIv(jweAlgorithm)); - const { ciphertext: encryptedKey, tag } = await encrypt(jweAlgorithm, cek, key, iv, new Uint8Array(0)); - return { encryptedKey, iv: base64url(iv), tag: base64url(tag) }; -}; -export const unwrap = async (alg, key, encryptedKey, iv, tag) => { - const jweAlgorithm = alg.substr(0, 7); - return decrypt(jweAlgorithm, key, encryptedKey, iv, tag, new Uint8Array(0)); -}; diff --git a/dist/browser/runtime/aeskw.js b/dist/browser/runtime/aeskw.js deleted file mode 100644 index 30a88f1999..0000000000 --- a/dist/browser/runtime/aeskw.js +++ /dev/null @@ -1,29 +0,0 @@ -import bogusWebCrypto from './bogus.js'; -import crypto, { isCryptoKey } from './webcrypto.js'; -import invalidKeyInput from './invalid_key_input.js'; -function checkKeySize(key, alg) { - if (key.algorithm.length !== parseInt(alg.substr(1, 3), 10)) { - throw new TypeError(`invalid key size for alg: ${alg}`); - } -} -function getCryptoKey(key, usage) { - if (isCryptoKey(key)) { - return key; - } - if (key instanceof Uint8Array) { - return crypto.subtle.importKey('raw', key, 'AES-KW', true, [usage]); - } - throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'Uint8Array')); -} -export const wrap = async (alg, key, cek) => { - const cryptoKey = await getCryptoKey(key, 'wrapKey'); - checkKeySize(cryptoKey, alg); - const cryptoKeyCek = await crypto.subtle.importKey('raw', cek, ...bogusWebCrypto); - return new Uint8Array(await crypto.subtle.wrapKey('raw', cryptoKeyCek, cryptoKey, 'AES-KW')); -}; -export const unwrap = async (alg, key, encryptedKey) => { - const cryptoKey = await getCryptoKey(key, 'unwrapKey'); - 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/dist/browser/runtime/base64url.js b/dist/browser/runtime/base64url.js deleted file mode 100644 index 7b93f5cf31..0000000000 --- a/dist/browser/runtime/base64url.js +++ /dev/null @@ -1,31 +0,0 @@ -import { encoder, decoder } from '../lib/buffer_utils.js'; -import globalThis from './global.js'; -export const encode = (input) => { - let unencoded = input; - if (typeof unencoded === 'string') { - unencoded = encoder.encode(unencoded); - } - const CHUNK_SIZE = 0x8000; - const arr = []; - for (let i = 0; i < unencoded.length; i += CHUNK_SIZE) { - arr.push(String.fromCharCode.apply(null, unencoded.subarray(i, i + CHUNK_SIZE))); - } - const base64string = globalThis.btoa(arr.join('')); - return base64string.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_'); -}; -export const decode = (input) => { - let encoded = input; - if (encoded instanceof Uint8Array) { - encoded = decoder.decode(encoded); - } - encoded = encoded.replace(/-/g, '+').replace(/_/g, '/').replace(/\s/g, ''); - try { - return new Uint8Array(globalThis - .atob(encoded) - .split('') - .map((c) => c.charCodeAt(0))); - } - catch (_a) { - throw new TypeError('The input to be decoded is not correctly encoded.'); - } -}; diff --git a/dist/browser/runtime/bogus.js b/dist/browser/runtime/bogus.js deleted file mode 100644 index 79aa20214d..0000000000 --- a/dist/browser/runtime/bogus.js +++ /dev/null @@ -1,6 +0,0 @@ -const bogusWebCrypto = [ - { hash: { name: 'SHA-256' }, name: 'HMAC' }, - true, - ['sign'], -]; -export default bogusWebCrypto; diff --git a/dist/browser/runtime/check_cek_length.js b/dist/browser/runtime/check_cek_length.js deleted file mode 100644 index 854c0e2f0b..0000000000 --- a/dist/browser/runtime/check_cek_length.js +++ /dev/null @@ -1,37 +0,0 @@ -import { JWEInvalid, JOSENotSupported } from '../util/errors.js'; -import { isCryptoKey } from './webcrypto.js'; -const checkCekLength = (enc, cek) => { - let expected; - 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 not supported 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 (isCryptoKey(cek)) { - const { length } = cek.algorithm; - if (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/dist/browser/runtime/check_key_length.js b/dist/browser/runtime/check_key_length.js deleted file mode 100644 index 23146bfe2f..0000000000 --- a/dist/browser/runtime/check_key_length.js +++ /dev/null @@ -1,15 +0,0 @@ -export default (alg, key) => { - if (alg.startsWith('HS')) { - const bitlen = parseInt(alg.substr(-3), 10); - const { length } = key.algorithm; - if (typeof length !== 'number' || length < bitlen) { - throw new TypeError(`${alg} requires symmetric keys to be ${bitlen} bits or larger`); - } - } - if (alg.startsWith('RS') || alg.startsWith('PS')) { - const { modulusLength } = key.algorithm; - if (typeof modulusLength !== 'number' || modulusLength < 2048) { - throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`); - } - } -}; diff --git a/dist/browser/runtime/decrypt.js b/dist/browser/runtime/decrypt.js deleted file mode 100644 index 941bfe7f1e..0000000000 --- a/dist/browser/runtime/decrypt.js +++ /dev/null @@ -1,72 +0,0 @@ -import { concat, uint64be } from '../lib/buffer_utils.js'; -import checkIvLength from '../lib/check_iv_length.js'; -import checkCekLength from './check_cek_length.js'; -import timingSafeEqual from './timing_safe_equal.js'; -import { JOSENotSupported, JWEDecryptionFailed } from '../util/errors.js'; -import crypto, { isCryptoKey } from './webcrypto.js'; -import invalidKeyInput from './invalid_key_input.js'; -async function cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) { - const keySize = parseInt(enc.substr(1, 3), 10); - const encKey = await crypto.subtle.importKey('raw', cek.subarray(keySize >> 3), 'AES-CBC', false, ['decrypt']); - const macKey = await crypto.subtle.importKey('raw', cek.subarray(0, keySize >> 3), { - hash: { name: `SHA-${keySize << 1}` }, - name: 'HMAC', - }, false, ['sign']); - 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; - try { - macCheckPassed = timingSafeEqual(tag, expectedTag); - } - catch (_a) { - } - if (!macCheckPassed) { - throw new JWEDecryptionFailed(); - } - let plaintext; - try { - plaintext = new Uint8Array(await crypto.subtle.decrypt({ iv, name: 'AES-CBC' }, encKey, ciphertext)); - } - catch (_b) { - } - if (!plaintext) { - throw new JWEDecryptionFailed(); - } - return plaintext; -} -async function gcmDecrypt(cek, ciphertext, iv, tag, aad) { - 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, concat(ciphertext, tag))); - } - catch (_a) { - throw new JWEDecryptionFailed(); - } -} -const decrypt = async (enc, cek, ciphertext, iv, tag, aad) => { - if (!isCryptoKey(cek) && !(cek instanceof Uint8Array)) { - throw new TypeError(invalidKeyInput(cek, 'CryptoKey', 'Uint8Array')); - } - checkCekLength(enc, cek); - checkIvLength(enc, iv); - switch (enc) { - case 'A128CBC-HS256': - case 'A192CBC-HS384': - case 'A256CBC-HS512': - return cbcDecrypt(enc, cek, ciphertext, iv, tag, aad); - case 'A128GCM': - case 'A192GCM': - case 'A256GCM': - return gcmDecrypt(cek, ciphertext, iv, tag, aad); - default: - throw new JOSENotSupported('unsupported JWE Content Encryption Algorithm'); - } -}; -export default decrypt; diff --git a/dist/browser/runtime/digest.js b/dist/browser/runtime/digest.js deleted file mode 100644 index 31e03c53f1..0000000000 --- a/dist/browser/runtime/digest.js +++ /dev/null @@ -1,6 +0,0 @@ -import crypto from './webcrypto.js'; -const digest = async (algorithm, data) => { - const subtleDigest = `SHA-${algorithm.substr(-3)}`; - return new Uint8Array(await crypto.subtle.digest(subtleDigest, data)); -}; -export default digest; diff --git a/dist/browser/runtime/ecdhes.js b/dist/browser/runtime/ecdhes.js deleted file mode 100644 index 1b80f23060..0000000000 --- a/dist/browser/runtime/ecdhes.js +++ /dev/null @@ -1,34 +0,0 @@ -import { encoder, concat, uint32be, lengthAndInput, concatKdf } from '../lib/buffer_utils.js'; -import crypto, { isCryptoKey } from './webcrypto.js'; -import digest from './digest.js'; -import invalidKeyInput from './invalid_key_input.js'; -export const deriveKey = async (publicKey, privateKey, algorithm, keyLength, apu = new Uint8Array(0), apv = new Uint8Array(0)) => { - if (!isCryptoKey(publicKey)) { - throw new TypeError(invalidKeyInput(publicKey, 'CryptoKey')); - } - if (!isCryptoKey(privateKey)) { - throw new TypeError(invalidKeyInput(privateKey, 'CryptoKey')); - } - 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.namedCurve.substr(-3), 10) / 8) << - 3)); - return concatKdf(digest, sharedSecret, keyLength, value); -}; -export const generateEpk = async (key) => { - if (!isCryptoKey(key)) { - throw new TypeError(invalidKeyInput(key, 'CryptoKey')); - } - return (await crypto.subtle.generateKey({ name: 'ECDH', namedCurve: key.algorithm.namedCurve }, true, ['deriveBits'])).privateKey; -}; -export const ecdhAllowed = (key) => { - if (!isCryptoKey(key)) { - throw new TypeError(invalidKeyInput(key, 'CryptoKey')); - } - return ['P-256', 'P-384', 'P-521'].includes(key.algorithm.namedCurve); -}; diff --git a/dist/browser/runtime/encrypt.js b/dist/browser/runtime/encrypt.js deleted file mode 100644 index 0c3af6679e..0000000000 --- a/dist/browser/runtime/encrypt.js +++ /dev/null @@ -1,55 +0,0 @@ -import { concat, uint64be } from '../lib/buffer_utils.js'; -import checkIvLength from '../lib/check_iv_length.js'; -import checkCekLength from './check_cek_length.js'; -import crypto, { isCryptoKey } from './webcrypto.js'; -import invalidKeyInput from './invalid_key_input.js'; -import { JOSENotSupported } from '../util/errors.js'; -async function cbcEncrypt(enc, plaintext, cek, iv, aad) { - const keySize = parseInt(enc.substr(1, 3), 10); - const encKey = await crypto.subtle.importKey('raw', cek.subarray(keySize >> 3), 'AES-CBC', false, ['encrypt']); - const macKey = await crypto.subtle.importKey('raw', cek.subarray(0, keySize >> 3), { - hash: { name: `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, cek, iv, aad) { - 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 = async (enc, plaintext, cek, iv, aad) => { - if (!isCryptoKey(cek) && !(cek instanceof Uint8Array)) { - throw new TypeError(invalidKeyInput(cek, 'CryptoKey', 'Uint8Array')); - } - checkCekLength(enc, cek); - checkIvLength(enc, iv); - switch (enc) { - case 'A128CBC-HS256': - case 'A192CBC-HS384': - case 'A256CBC-HS512': - return cbcEncrypt(enc, plaintext, cek, iv, aad); - case 'A128GCM': - case 'A192GCM': - case 'A256GCM': - return gcmEncrypt(plaintext, cek, iv, aad); - default: - throw new JOSENotSupported('unsupported JWE Content Encryption Algorithm'); - } -}; -export default encrypt; diff --git a/dist/browser/runtime/fetch_jwks.js b/dist/browser/runtime/fetch_jwks.js deleted file mode 100644 index d4a49b2684..0000000000 --- a/dist/browser/runtime/fetch_jwks.js +++ /dev/null @@ -1,31 +0,0 @@ -import { JOSEError } from '../util/errors.js'; -import globalThis from './global.js'; -const fetchJwks = async (url, timeout) => { - let controller; - if (typeof AbortController === 'function') { - controller = new AbortController(); - setTimeout(() => controller.abort(), timeout); - } - const response = await globalThis.fetch(url.href, { - signal: controller ? controller.signal : undefined, - redirect: 'manual', - method: 'GET', - ...(typeof globalThis.WebSocketPair === 'undefined' - ? { - referrerPolicy: 'no-referrer', - credentials: 'omit', - mode: 'cors', - } - : undefined), - }); - if (response.status !== 200) { - throw new JOSEError('Expected 200 OK from the JSON Web Key Set HTTP response'); - } - try { - return await response.json(); - } - catch (_a) { - throw new JOSEError('Failed to parse the JSON Web Key Set HTTP response as JSON'); - } -}; -export default fetchJwks; diff --git a/dist/browser/runtime/generate.js b/dist/browser/runtime/generate.js deleted file mode 100644 index 196cf7f8aa..0000000000 --- a/dist/browser/runtime/generate.js +++ /dev/null @@ -1,114 +0,0 @@ -import crypto from './webcrypto.js'; -import { JOSENotSupported } from '../util/errors.js'; -import random from './random.js'; -export async function generateSecret(alg, options) { - var _a; - let length; - let algorithm; - let keyUsages; - switch (alg) { - case 'HS256': - case 'HS384': - case 'HS512': - length = parseInt(alg.substr(-3), 10); - algorithm = { name: 'HMAC', hash: { name: `SHA-${length}` }, 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, (_a = options === null || options === void 0 ? void 0 : options.extractable) !== null && _a !== void 0 ? _a : false, keyUsages); -} -function getModulusLengthOption(options) { - var _a; - const modulusLength = (_a = options === null || options === void 0 ? void 0 : options.modulusLength) !== null && _a !== void 0 ? _a : 2048; - if (typeof modulusLength !== 'number' || modulusLength < 2048) { - throw new JOSENotSupported('Invalid or unsupported modulusLength option provided, 2048 bits or larger keys must be used'); - } - return modulusLength; -} -export async function generateKeyPair(alg, options) { - var _a, _b; - let algorithm; - let keyUsages; - switch (alg) { - case 'PS256': - case 'PS384': - case 'PS512': - algorithm = { - name: 'RSA-PSS', - hash: { name: `SHA-${alg.substr(-3)}` }, - publicExponent: new Uint8Array([0x01, 0x00, 0x01]), - modulusLength: getModulusLengthOption(options), - }; - keyUsages = ['sign', 'verify']; - break; - case 'RS256': - case 'RS384': - case 'RS512': - algorithm = { - name: 'RSASSA-PKCS1-v1_5', - hash: { name: `SHA-${alg.substr(-3)}` }, - publicExponent: new Uint8Array([0x01, 0x00, 0x01]), - modulusLength: getModulusLengthOption(options), - }; - keyUsages = ['sign', 'verify']; - break; - case 'RSA-OAEP': - case 'RSA-OAEP-256': - case 'RSA-OAEP-384': - case 'RSA-OAEP-512': - algorithm = { - name: 'RSA-OAEP', - hash: { name: `SHA-${parseInt(alg.substr(-3), 10) || 1}` }, - publicExponent: new Uint8Array([0x01, 0x00, 0x01]), - modulusLength: getModulusLengthOption(options), - }; - 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: (_a = options === null || options === void 0 ? void 0 : options.crv) !== null && _a !== void 0 ? _a : 'P-256' }; - keyUsages = ['deriveKey', 'deriveBits']; - break; - default: - throw new JOSENotSupported('unsupported or invalid JWK "alg" (Algorithm) Parameter value'); - } - return (crypto.subtle.generateKey(algorithm, (_b = options === null || options === void 0 ? void 0 : options.extractable) !== null && _b !== void 0 ? _b : false, keyUsages)); -} diff --git a/dist/browser/runtime/get_sign_verify_key.js b/dist/browser/runtime/get_sign_verify_key.js deleted file mode 100644 index 10013b1625..0000000000 --- a/dist/browser/runtime/get_sign_verify_key.js +++ /dev/null @@ -1,14 +0,0 @@ -import crypto, { isCryptoKey } from './webcrypto.js'; -import invalidKeyInput from './invalid_key_input.js'; -export default function getCryptoKey(alg, key, usage) { - if (isCryptoKey(key)) { - return key; - } - if (key instanceof Uint8Array) { - if (!alg.startsWith('HS')) { - throw new TypeError(invalidKeyInput(key, 'CryptoKey')); - } - return crypto.subtle.importKey('raw', key, { hash: { name: `SHA-${alg.substr(-3)}` }, name: 'HMAC' }, false, [usage]); - } - throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'Uint8Array')); -} diff --git a/dist/browser/runtime/global.js b/dist/browser/runtime/global.js deleted file mode 100644 index 14d19748a7..0000000000 --- a/dist/browser/runtime/global.js +++ /dev/null @@ -1,10 +0,0 @@ -function getGlobal() { - if (typeof globalThis !== 'undefined') - return globalThis; - if (typeof self !== 'undefined') - return self; - if (typeof window !== 'undefined') - return window; - throw new Error('unable to locate global object'); -} -export default getGlobal(); diff --git a/dist/browser/runtime/invalid_key_input.js b/dist/browser/runtime/invalid_key_input.js deleted file mode 100644 index 468ad288b4..0000000000 --- a/dist/browser/runtime/invalid_key_input.js +++ /dev/null @@ -1,25 +0,0 @@ -export default (actual, ...types) => { - let msg = 'Key must be '; - if (types.length > 2) { - const last = types.pop(); - msg += `one of type ${types.join(', ')}, or ${last}.`; - } - else if (types.length === 2) { - msg += `one of type ${types[0]} or ${types[1]}.`; - } - else { - msg += `of type ${types[0]}.`; - } - if (actual == null) { - msg += ` Received ${actual}`; - } - else if (typeof actual === 'function' && actual.name) { - msg += ` Received function ${actual.name}`; - } - else if (typeof actual === 'object' && actual != null) { - if (actual.constructor && actual.constructor.name) { - msg += ` Received an instance of ${actual.constructor.name}`; - } - } - return msg; -}; diff --git a/dist/browser/runtime/jwk_to_key.js b/dist/browser/runtime/jwk_to_key.js deleted file mode 100644 index bf0d9a7afd..0000000000 --- a/dist/browser/runtime/jwk_to_key.js +++ /dev/null @@ -1,115 +0,0 @@ -import crypto from './webcrypto.js'; -import { JOSENotSupported } from '../util/errors.js'; -import { decode as base64url } from './base64url.js'; -function subtleMapping(jwk) { - let algorithm; - let keyUsages; - switch (jwk.kty) { - case 'oct': { - switch (jwk.alg) { - case 'HS256': - case 'HS384': - case 'HS512': - algorithm = { name: 'HMAC', hash: { name: `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: { name: `SHA-${jwk.alg.substr(-3)}` } }; - keyUsages = jwk.d ? ['sign'] : ['verify']; - break; - case 'RS256': - case 'RS384': - case 'RS512': - algorithm = { name: 'RSASSA-PKCS1-v1_5', hash: { name: `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: { name: `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 }; -} -const parse = async (jwk) => { - var _a, _b; - const { algorithm, keyUsages } = subtleMapping(jwk); - const rest = [ - algorithm, - (_a = jwk.ext) !== null && _a !== void 0 ? _a : false, - (_b = jwk.key_ops) !== null && _b !== void 0 ? _b : keyUsages, - ]; - if (algorithm.name === 'PBKDF2') { - return crypto.subtle.importKey('raw', base64url(jwk.k), ...rest); - } - const keyData = { ...jwk }; - delete keyData.alg; - return crypto.subtle.importKey('jwk', keyData, ...rest); -}; -export default parse; diff --git a/dist/browser/runtime/key_to_jwk.js b/dist/browser/runtime/key_to_jwk.js deleted file mode 100644 index b7ee46e95b..0000000000 --- a/dist/browser/runtime/key_to_jwk.js +++ /dev/null @@ -1,20 +0,0 @@ -import crypto, { isCryptoKey } from './webcrypto.js'; -import invalidKeyInput from './invalid_key_input.js'; -import { encode as base64url } from './base64url.js'; -const keyToJWK = async (key) => { - if (key instanceof Uint8Array) { - return { - kty: 'oct', - k: base64url(key), - }; - } - if (!isCryptoKey(key)) { - throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'Uint8Array')); - } - if (!key.extractable) { - throw new TypeError('non-extractable CryptoKey cannot be exported as a JWK'); - } - const { ext, key_ops, alg, use, ...jwk } = await crypto.subtle.exportKey('jwk', key); - return jwk; -}; -export default keyToJWK; diff --git a/dist/browser/runtime/pbes2kw.js b/dist/browser/runtime/pbes2kw.js deleted file mode 100644 index 481c16814b..0000000000 --- a/dist/browser/runtime/pbes2kw.js +++ /dev/null @@ -1,71 +0,0 @@ -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, { isCryptoKey } from './webcrypto.js'; -import invalidKeyInput from './invalid_key_input.js'; -function getCryptoKey(key) { - if (key instanceof Uint8Array) { - return crypto.subtle.importKey('raw', key, 'PBKDF2', false, ['deriveBits']); - } - if (isCryptoKey(key)) { - return key; - } - throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'Uint8Array')); -} -export const encrypt = async (alg, key, cek, p2c = Math.floor(Math.random() * 2049) + 2048, p2s = random(new Uint8Array(16))) => { - checkP2s(p2s); - const salt = concatSalt(alg, p2s); - const keylen = parseInt(alg.substr(13, 3), 10); - const subtleAlg = { - hash: { name: `SHA-${alg.substr(8, 3)}` }, - iterations: p2c, - name: 'PBKDF2', - salt, - }; - const wrapAlg = { - length: keylen, - name: 'AES-KW', - }; - const cryptoKey = await getCryptoKey(key); - let derived; - 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 = async (alg, key, encryptedKey, p2c, p2s) => { - checkP2s(p2s); - const salt = concatSalt(alg, p2s); - const keylen = parseInt(alg.substr(13, 3), 10); - const subtleAlg = { - hash: { name: `SHA-${alg.substr(8, 3)}` }, - iterations: p2c, - name: 'PBKDF2', - salt, - }; - const wrapAlg = { - length: keylen, - name: 'AES-KW', - }; - const cryptoKey = await getCryptoKey(key); - let derived; - 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/dist/browser/runtime/random.js b/dist/browser/runtime/random.js deleted file mode 100644 index 2728ffaa1c..0000000000 --- a/dist/browser/runtime/random.js +++ /dev/null @@ -1,3 +0,0 @@ -import crypto from './webcrypto.js'; -const random = crypto.getRandomValues.bind(crypto); -export default random; diff --git a/dist/browser/runtime/rsaes.js b/dist/browser/runtime/rsaes.js deleted file mode 100644 index 796a56cad0..0000000000 --- a/dist/browser/runtime/rsaes.js +++ /dev/null @@ -1,33 +0,0 @@ -import subtleAlgorithm from './subtle_rsaes.js'; -import bogusWebCrypto from './bogus.js'; -import crypto, { isCryptoKey } from './webcrypto.js'; -import checkKeyLength from './check_key_length.js'; -import invalidKeyInput from './invalid_key_input.js'; -export const encrypt = async (alg, key, cek) => { - if (!isCryptoKey(key)) { - throw new TypeError(invalidKeyInput(key, 'CryptoKey')); - } - checkKeyLength(alg, key); - if (key.usages.includes('encrypt')) { - return new Uint8Array(await crypto.subtle.encrypt(subtleAlgorithm(alg), key, cek)); - } - if (key.usages.includes('wrapKey')) { - 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 = async (alg, key, encryptedKey) => { - if (!isCryptoKey(key)) { - throw new TypeError(invalidKeyInput(key, 'CryptoKey')); - } - 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/dist/browser/runtime/sign.js b/dist/browser/runtime/sign.js deleted file mode 100644 index 908773dee4..0000000000 --- a/dist/browser/runtime/sign.js +++ /dev/null @@ -1,11 +0,0 @@ -import subtleAlgorithm from './subtle_dsa.js'; -import crypto from './webcrypto.js'; -import checkKeyLength from './check_key_length.js'; -import getSignKey from './get_sign_verify_key.js'; -const sign = async (alg, key, data) => { - const cryptoKey = await getSignKey(alg, key, 'sign'); - checkKeyLength(alg, cryptoKey); - const signature = await crypto.subtle.sign(subtleAlgorithm(alg), cryptoKey, data); - return new Uint8Array(signature); -}; -export default sign; diff --git a/dist/browser/runtime/subtle_dsa.js b/dist/browser/runtime/subtle_dsa.js deleted file mode 100644 index f4cb7427dc..0000000000 --- a/dist/browser/runtime/subtle_dsa.js +++ /dev/null @@ -1,43 +0,0 @@ -import { JOSENotSupported } from '../util/errors.js'; -export default function subtleDsa(alg) { - switch (alg) { - case 'HS256': - return { hash: { name: 'SHA-256' }, name: 'HMAC' }; - case 'HS384': - return { hash: { name: 'SHA-384' }, name: 'HMAC' }; - case 'HS512': - return { hash: { name: 'SHA-512' }, name: 'HMAC' }; - case 'PS256': - return { - hash: { name: 'SHA-256' }, - name: 'RSA-PSS', - saltLength: 256 >> 3, - }; - case 'PS384': - return { - hash: { name: 'SHA-384' }, - name: 'RSA-PSS', - saltLength: 384 >> 3, - }; - case 'PS512': - return { - hash: { name: 'SHA-512' }, - name: 'RSA-PSS', - saltLength: 512 >> 3, - }; - case 'RS256': - return { hash: { name: 'SHA-256' }, name: 'RSASSA-PKCS1-v1_5' }; - case 'RS384': - return { hash: { name: 'SHA-384' }, name: 'RSASSA-PKCS1-v1_5' }; - case 'RS512': - return { hash: { name: 'SHA-512' }, name: 'RSASSA-PKCS1-v1_5' }; - case 'ES256': - return { hash: { name: 'SHA-256' }, name: 'ECDSA', namedCurve: 'P-256' }; - case 'ES384': - return { hash: { name: 'SHA-384' }, name: 'ECDSA', namedCurve: 'P-384' }; - case 'ES512': - return { hash: { name: 'SHA-512' }, name: 'ECDSA', namedCurve: 'P-521' }; - default: - throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`); - } -} diff --git a/dist/browser/runtime/subtle_rsaes.js b/dist/browser/runtime/subtle_rsaes.js deleted file mode 100644 index 3a399bcfa7..0000000000 --- a/dist/browser/runtime/subtle_rsaes.js +++ /dev/null @@ -1,12 +0,0 @@ -import { JOSENotSupported } from '../util/errors.js'; -export default function subtleRsaEs(alg) { - 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 not supported either by JOSE or your javascript runtime`); - } -} diff --git a/dist/browser/runtime/timing_safe_equal.js b/dist/browser/runtime/timing_safe_equal.js deleted file mode 100644 index 442cdccd20..0000000000 --- a/dist/browser/runtime/timing_safe_equal.js +++ /dev/null @@ -1,19 +0,0 @@ -const 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/dist/browser/runtime/verify.js b/dist/browser/runtime/verify.js deleted file mode 100644 index 64f788f416..0000000000 --- a/dist/browser/runtime/verify.js +++ /dev/null @@ -1,16 +0,0 @@ -import subtleAlgorithm from './subtle_dsa.js'; -import crypto from './webcrypto.js'; -import checkKeyLength from './check_key_length.js'; -import getVerifyKey from './get_sign_verify_key.js'; -const verify = async (alg, key, signature, data) => { - const cryptoKey = await getVerifyKey(alg, key, 'verify'); - checkKeyLength(alg, cryptoKey); - const algorithm = subtleAlgorithm(alg); - try { - return await crypto.subtle.verify(algorithm, cryptoKey, signature, data); - } - catch (_a) { - return false; - } -}; -export default verify; diff --git a/dist/browser/runtime/webcrypto.js b/dist/browser/runtime/webcrypto.js deleted file mode 100644 index fcd333fdfd..0000000000 --- a/dist/browser/runtime/webcrypto.js +++ /dev/null @@ -1,8 +0,0 @@ -import globalThis from './global.js'; -export default globalThis.crypto; -export function isCryptoKey(key) { - if (typeof globalThis.CryptoKey === 'undefined') { - return false; - } - return key != null && key instanceof globalThis.CryptoKey; -} diff --git a/dist/browser/runtime/zlib.js b/dist/browser/runtime/zlib.js deleted file mode 100644 index e47cb532dc..0000000000 --- a/dist/browser/runtime/zlib.js +++ /dev/null @@ -1,7 +0,0 @@ -import { JOSENotSupported } from '../util/errors.js'; -export const inflate = 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.'); -}; -export const deflate = async () => { - throw new JOSENotSupported('JWE "zip" (Compression Algorithm) Header Parameter is not supported by your javascript runtime. You need to use the `deflateRaw` encrypt option to provide Deflate Raw implementation.'); -}; diff --git a/dist/browser/util/base64url.js b/dist/browser/util/base64url.js deleted file mode 100644 index 88ce7556d6..0000000000 --- a/dist/browser/util/base64url.js +++ /dev/null @@ -1,3 +0,0 @@ -import * as base64url from '../runtime/base64url.js'; -export const encode = base64url.encode; -export const decode = base64url.decode; diff --git a/dist/browser/util/decode_protected_header.js b/dist/browser/util/decode_protected_header.js deleted file mode 100644 index 261c132033..0000000000 --- a/dist/browser/util/decode_protected_header.js +++ /dev/null @@ -1,36 +0,0 @@ -import { decode as base64url } from './base64url.js'; -import { decoder } from '../lib/buffer_utils.js'; -import isObject from '../lib/is_object.js'; -function decodeProtectedHeader(token) { - let protectedB64u; - if (typeof token === 'string') { - const parts = token.split('.'); - if (parts.length === 3 || parts.length === 5) { - ; - [protectedB64u] = parts; - } - } - else if (typeof token === 'object' && token) { - if ('protected' in token) { - protectedB64u = token.protected; - } - else { - throw new TypeError('Token does not contain a Protected Header'); - } - } - try { - if (typeof protectedB64u !== 'string' || !protectedB64u) { - throw new Error(); - } - const result = JSON.parse(decoder.decode(base64url(protectedB64u))); - if (!isObject(result)) { - throw new Error(); - } - return result; - } - catch (_a) { - throw new TypeError('Invalid Token or Protected Header formatting'); - } -} -export { decodeProtectedHeader }; -export default decodeProtectedHeader; diff --git a/dist/browser/util/errors.js b/dist/browser/util/errors.js deleted file mode 100644 index 52506cbd9d..0000000000 --- a/dist/browser/util/errors.js +++ /dev/null @@ -1,108 +0,0 @@ -export class JOSEError extends Error { - constructor(message) { - super(message); - this.code = JOSEError.code; - this.name = this.constructor.name; - if (Error.captureStackTrace) { - Error.captureStackTrace(this, this.constructor); - } - } -} -JOSEError.code = 'ERR_JOSE_GENERIC'; -export class JWTClaimValidationFailed extends JOSEError { - constructor(message, claim = 'unspecified', reason = 'unspecified') { - super(message); - this.code = JWTClaimValidationFailed.code; - this.claim = claim; - this.reason = reason; - } -} -JWTClaimValidationFailed.code = 'ERR_JWT_CLAIM_VALIDATION_FAILED'; -export class JOSEAlgNotAllowed extends JOSEError { - constructor() { - super(...arguments); - this.code = JOSEAlgNotAllowed.code; - } -} -JOSEAlgNotAllowed.code = 'ERR_JOSE_ALG_NOT_ALLOWED'; -export class JOSENotSupported extends JOSEError { - constructor() { - super(...arguments); - this.code = JOSENotSupported.code; - } -} -JOSENotSupported.code = 'ERR_JOSE_NOT_SUPPORTED'; -export class JWEDecryptionFailed extends JOSEError { - constructor() { - super(...arguments); - this.code = JWEDecryptionFailed.code; - this.message = 'decryption operation failed'; - } -} -JWEDecryptionFailed.code = 'ERR_JWE_DECRYPTION_FAILED'; -export class JWEInvalid extends JOSEError { - constructor() { - super(...arguments); - this.code = JWEInvalid.code; - } -} -JWEInvalid.code = 'ERR_JWE_INVALID'; -export class JWSInvalid extends JOSEError { - constructor() { - super(...arguments); - this.code = JWSInvalid.code; - } -} -JWSInvalid.code = 'ERR_JWS_INVALID'; -export class JWTInvalid extends JOSEError { - constructor() { - super(...arguments); - this.code = JWTInvalid.code; - } -} -JWTInvalid.code = 'ERR_JWT_INVALID'; -export class JWKInvalid extends JOSEError { - constructor() { - super(...arguments); - this.code = JWKInvalid.code; - } -} -JWKInvalid.code = 'ERR_JWK_INVALID'; -export class JWKSInvalid extends JOSEError { - constructor() { - super(...arguments); - this.code = JWKSInvalid.code; - } -} -JWKSInvalid.code = 'ERR_JWKS_INVALID'; -export class JWKSNoMatchingKey extends JOSEError { - constructor() { - super(...arguments); - this.code = JWKSNoMatchingKey.code; - this.message = 'no applicable key found in the JSON Web Key Set'; - } -} -JWKSNoMatchingKey.code = 'ERR_JWKS_NO_MATCHING_KEY'; -export class JWKSMultipleMatchingKeys extends JOSEError { - constructor() { - super(...arguments); - this.code = JWKSMultipleMatchingKeys.code; - this.message = 'multiple matching keys found in the JSON Web Key Set'; - } -} -JWKSMultipleMatchingKeys.code = 'ERR_JWKS_MULTIPLE_MATCHING_KEYS'; -export class JWSSignatureVerificationFailed extends JOSEError { - constructor() { - super(...arguments); - this.code = JWSSignatureVerificationFailed.code; - this.message = 'signature verification failed'; - } -} -JWSSignatureVerificationFailed.code = 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED'; -export class JWTExpired extends JWTClaimValidationFailed { - constructor() { - super(...arguments); - this.code = JWTExpired.code; - } -} -JWTExpired.code = 'ERR_JWT_EXPIRED'; diff --git a/dist/browser/util/generate_key_pair.js b/dist/browser/util/generate_key_pair.js deleted file mode 100644 index 733800cc06..0000000000 --- a/dist/browser/util/generate_key_pair.js +++ /dev/null @@ -1,6 +0,0 @@ -import { generateKeyPair as generate } from '../runtime/generate.js'; -async function generateKeyPair(alg, options) { - return generate(alg, options); -} -export { generateKeyPair }; -export default generateKeyPair; diff --git a/dist/browser/util/generate_secret.js b/dist/browser/util/generate_secret.js deleted file mode 100644 index 2d387754ee..0000000000 --- a/dist/browser/util/generate_secret.js +++ /dev/null @@ -1,6 +0,0 @@ -import { generateSecret as generate } from '../runtime/generate.js'; -async function generateSecret(alg, options) { - return generate(alg, options); -} -export { generateSecret }; -export default generateSecret; diff --git a/dist/browser/util/random.js b/dist/browser/util/random.js deleted file mode 100644 index d7dc7ab182..0000000000 --- a/dist/browser/util/random.js +++ /dev/null @@ -1,4 +0,0 @@ -import runtimeRandom from '../runtime/random.js'; -const random = runtimeRandom; -export { random }; -export default random; diff --git a/dist/deno/README.md b/dist/deno/README.md deleted file mode 100644 index 09b759278a..0000000000 --- a/dist/deno/README.md +++ /dev/null @@ -1,38 +0,0 @@ -# `jose` Modules API Documentation - -> "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. - -## Available modules - -- JSON Web Tokens (JWT) - - [Signing](https://github.com/panva/jose/blob/v3.16.0/docs/classes/jwt_sign.SignJWT.md#readme) - - [Verification & Claims Set Validation](https://github.com/panva/jose/blob/v3.16.0/docs/functions/jwt_verify.jwtVerify.md#readme) - - Encrypted JSON Web Tokens - - [Encryption](https://github.com/panva/jose/blob/v3.16.0/docs/classes/jwt_encrypt.EncryptJWT.md#readme) - - [Decryption & Claims Set Validation](https://github.com/panva/jose/blob/v3.16.0/docs/functions/jwt_decrypt.jwtDecrypt.md#readme) -- JSON Web Encryption (JWE) - - Encryption - [Compact](https://github.com/panva/jose/blob/v3.16.0/docs/classes/jwe_compact_encrypt.CompactEncrypt.md#readme), [Flattened](https://github.com/panva/jose/blob/v3.16.0/docs/classes/jwe_flattened_encrypt.FlattenedEncrypt.md#readme) - - Decryption - [Compact](https://github.com/panva/jose/blob/v3.16.0/docs/functions/jwe_compact_decrypt.compactDecrypt.md#readme), [Flattened](https://github.com/panva/jose/blob/v3.16.0/docs/functions/jwe_flattened_decrypt.flattenedDecrypt.md#readme), [General](https://github.com/panva/jose/blob/v3.16.0/docs/functions/jwe_general_decrypt.generalDecrypt.md#readme) -- JSON Web Signature (JWS) - - Signing - [Compact](https://github.com/panva/jose/blob/v3.16.0/docs/classes/jws_compact_sign.CompactSign.md#readme), [Flattened](https://github.com/panva/jose/blob/v3.16.0/docs/classes/jws_flattened_sign.FlattenedSign.md#readme), [General](https://github.com/panva/jose/blob/v3.16.0/docs/classes/jws_general_sign.GeneralSign.md#readme) - - Verification - [Compact](https://github.com/panva/jose/blob/v3.16.0/docs/functions/jws_compact_verify.compactVerify.md#readme), [Flattened](https://github.com/panva/jose/blob/v3.16.0/docs/functions/jws_flattened_verify.flattenedVerify.md#readme), [General](https://github.com/panva/jose/blob/v3.16.0/docs/functions/jws_general_verify.generalVerify.md#readme) -- JSON Web Key (JWK) - - [Parsing (JWK to KeyLike)](https://github.com/panva/jose/blob/v3.16.0/docs/functions/jwk_parse.parseJwk.md#readme) - - [Conversion (KeyLike to JWK)](https://github.com/panva/jose/blob/v3.16.0/docs/functions/jwk_from_key_like.fromKeyLike.md#readme) - - [Thumbprints](https://github.com/panva/jose/blob/v3.16.0/docs/functions/jwk_thumbprint.calculateThumbprint.md#readme) - - [EmbeddedJWK](https://github.com/panva/jose/blob/v3.16.0/docs/functions/jwk_embedded.EmbeddedJWK.md#readme) -- JSON Web Key Set (JWKS) - - [Verify using a remote JWKSet](https://github.com/panva/jose/blob/v3.16.0/docs/functions/jwks_remote.createRemoteJWKSet.md#readme) -- Key Pair or Secret Generation (Generate KeyLike) - - [Asymmetric Key Pair Generation](https://github.com/panva/jose/blob/v3.16.0/docs/functions/util_generate_key_pair.generateKeyPair.md#readme) - - [Symmetric Secret Generation](https://github.com/panva/jose/blob/v3.16.0/docs/functions/util_generate_secret.generateSecret.md#readme) -- Utilities - - [Decoding Token's Protected Header](https://github.com/panva/jose/blob/v3.16.0/docs/functions/util_decode_protected_header.decodeProtectedHeader.md#readme) -- [Unsecured JWT](https://github.com/panva/jose/blob/v3.16.0/docs/classes/jwt_unsecured.UnsecuredJWT.md#readme) -- [JOSE Errors](https://github.com/panva/jose/blob/v3.16.0/docs/modules/util_errors.md#readme) - -[support-sponsor]: https://github.com/sponsors/panva diff --git a/dist/deno/jwe/compact/decrypt.ts b/dist/deno/jwe/compact/decrypt.ts deleted file mode 100644 index f2da278577..0000000000 --- a/dist/deno/jwe/compact/decrypt.ts +++ /dev/null @@ -1,94 +0,0 @@ -import decrypt from '../flattened/decrypt.ts' -import { JWEInvalid } from '../../util/errors.ts' -import { decoder } from '../../lib/buffer_utils.ts' -import type { - KeyLike, - DecryptOptions, - JWEHeaderParameters, - GetKeyFunction, - FlattenedJWE, - CompactDecryptResult, -} from '../../types.d.ts' - -/** - * 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 - * ```js - * import { compactDecrypt } from 'jose/jwe/compact/decrypt' - * ``` - * - * @example CJS import - * ```js - * const { compactDecrypt } = require('jose/jwe/compact/decrypt') - * ``` - * - * @example Deno import - * ```js - * import { compactDecrypt } from 'https://deno.land/x/jose@VERSION/jwe/compact/decrypt.ts' - * ``` - * - * @example Usage - * ```js - * 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 { plaintext, protectedHeader } = await compactDecrypt(jwe, privateKey) - * - * console.log(protectedHeader) - * console.log(decoder.decode(plaintext)) - * ``` - */ -async function compactDecrypt( - jwe: string | Uint8Array, - key: KeyLike | CompactDecryptGetKey, - options?: DecryptOptions, -): Promise { - if (jwe instanceof Uint8Array) { - jwe = decoder.decode(jwe) - } - - if (typeof jwe !== 'string') { - throw new JWEInvalid('Compact JWE must be a string or Uint8Array') - } - 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: (ciphertext || undefined), - iv: (iv || undefined), - protected: protectedHeader || undefined, - tag: (tag || undefined), - encrypted_key: encryptedKey || undefined, - }, - [1]>key, - options, - ) - - return { plaintext: decrypted.plaintext, protectedHeader: decrypted.protectedHeader! } -} - -export { compactDecrypt } -export default compactDecrypt -export type { KeyLike, DecryptOptions, CompactDecryptResult } diff --git a/dist/deno/jwe/compact/encrypt.ts b/dist/deno/jwe/compact/encrypt.ts deleted file mode 100644 index bdb143ed31..0000000000 --- a/dist/deno/jwe/compact/encrypt.ts +++ /dev/null @@ -1,111 +0,0 @@ -import FlattenedEncrypt from '../flattened/encrypt.ts' -import type { - KeyLike, - JWEKeyManagementHeaderParameters, - JWEHeaderParameters, - EncryptOptions, -} from '../../types.d.ts' - -/** - * The CompactEncrypt class is a utility for creating Compact JWE strings. - * - * @example ESM import - * ```js - * import { CompactEncrypt } from 'jose/jwe/compact/encrypt' - * ``` - * - * @example CJS import - * ```js - * const { CompactEncrypt } = require('jose/jwe/compact/encrypt') - * ``` - * - * @example Deno import - * ```js - * import { CompactEncrypt } from 'https://deno.land/x/jose@VERSION/jwe/compact/encrypt.ts' - * ``` - * - * @example Usage - * ```js - * const encoder = new TextEncoder() - * - * 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) - * ``` - */ -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 { CompactEncrypt } -export default CompactEncrypt -export type { KeyLike, JWEKeyManagementHeaderParameters, JWEHeaderParameters } diff --git a/dist/deno/jwe/flattened/decrypt.ts b/dist/deno/jwe/flattened/decrypt.ts deleted file mode 100644 index 878dafcb18..0000000000 --- a/dist/deno/jwe/flattened/decrypt.ts +++ /dev/null @@ -1,249 +0,0 @@ -import { JOSEAlgNotAllowed, JOSENotSupported, JWEInvalid } from '../../util/errors.ts' -import isDisjoint from '../../lib/is_disjoint.ts' -import isObject from '../../lib/is_object.ts' - -import { decode as base64url } from '../../runtime/base64url.ts' -import decrypt from '../../runtime/decrypt.ts' -import { inflate } from '../../runtime/zlib.ts' -import decryptKeyManagement from '../../lib/decrypt_key_management.ts' - -import type { - FlattenedDecryptResult, - KeyLike, - FlattenedJWE, - JWEHeaderParameters, - DecryptOptions, - GetKeyFunction, -} from '../../types.d.ts' -import { encoder, decoder, concat } from '../../lib/buffer_utils.ts' -import cekFactory from '../../lib/cek.ts' -import random from '../../runtime/random.ts' -import validateCrit from '../../lib/validate_crit.ts' -import validateAlgorithms from '../../lib/validate_algorithms.ts' - -const generateCek = cekFactory(random) -const checkExtensions = 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 - * ```js - * import { flattenedDecrypt } from 'jose/jwe/flattened/decrypt' - * ``` - * - * @example CJS import - * ```js - * const { flattenedDecrypt } = require('jose/jwe/flattened/decrypt') - * ``` - * - * @example Deno import - * ```js - * import { flattenedDecrypt } from 'https://deno.land/x/jose@VERSION/jwe/flattened/decrypt.ts' - * ``` - * - * @example Usage - * ```js - * 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 { - * plaintext, - * protectedHeader, - * additionalAuthenticatedData - * } = await flattenedDecrypt(jwe, privateKey) - * - * console.log(protectedHeader) - * console.log(decoder.decode(plaintext)) - * console.log(decoder.decode(additionalAuthenticatedData)) - * ``` - */ -async function flattenedDecrypt( - jwe: FlattenedJWE, - key: KeyLike | FlattenedDecryptGetKey, - options?: DecryptOptions, -): Promise { - if (!isObject(jwe)) { - throw new JWEInvalid('Flattened JWE must be an object') - } - - if (jwe.protected === undefined && jwe.header === undefined && jwe.unprotected === undefined) { - throw new JWEInvalid('JOSE Header missing') - } - - if (typeof jwe.iv !== 'string') { - throw new JWEInvalid('JWE Initialization Vector missing or incorrect type') - } - - if (typeof jwe.ciphertext !== 'string') { - throw new JWEInvalid('JWE Ciphertext missing or incorrect type') - } - - if (typeof jwe.tag !== 'string') { - throw new JWEInvalid('JWE Authentication Tag missing or incorrect type') - } - - if (jwe.protected !== undefined && typeof jwe.protected !== 'string') { - throw new JWEInvalid('JWE Protected Header incorrect type') - } - - if (jwe.encrypted_key !== undefined && typeof jwe.encrypted_key !== 'string') { - throw new JWEInvalid('JWE Encrypted Key incorrect type') - } - - if (jwe.aad !== undefined && typeof jwe.aad !== 'string') { - throw new JWEInvalid('JWE AAD incorrect type') - } - - if (jwe.header !== undefined && !isObject(jwe.header)) { - throw new JWEInvalid('JWE Shared Unprotected Header incorrect type') - } - - if (jwe.unprotected !== undefined && !isObject(jwe.unprotected)) { - throw new JWEInvalid('JWE Per-Recipient Unprotected Header incorrect type') - } - - let parsedProt!: JWEHeaderParameters - if (jwe.protected) { - const protectedHeader = base64url(jwe.protected) - try { - parsedProt = JSON.parse(decoder.decode(protectedHeader)) - } catch { - throw new JWEInvalid('JWE Protected Header is invalid') - } - } - 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, - } - - checkExtensions(options?.crit, parsedProt, joseHeader) - - if (joseHeader.zip !== undefined) { - 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 (typeof alg !== 'string' || !alg) { - throw new JWEInvalid('missing JWE Algorithm (alg) in JWE Header') - } - - if (typeof enc !== 'string' || !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 (jwe.encrypted_key !== undefined) { - encryptedKey = base64url(jwe.encrypted_key!) - } - - if (typeof key === 'function') { - 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 = generateCek(enc) - } - - const iv = base64url(jwe.iv) - const tag = base64url(jwe.tag) - - const protectedHeader: Uint8Array = encoder.encode(jwe.protected ?? '') - let additionalData: Uint8Array - - if (jwe.aad !== undefined) { - 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 (jwe.protected !== undefined) { - result.protectedHeader = parsedProt - } - - if (jwe.aad !== undefined) { - result.additionalAuthenticatedData = base64url(jwe.aad!) - } - - if (jwe.unprotected !== undefined) { - result.sharedUnprotectedHeader = jwe.unprotected - } - - if (jwe.header !== undefined) { - result.unprotectedHeader = jwe.header - } - - return result -} - -export { flattenedDecrypt } -export default flattenedDecrypt -export type { KeyLike, FlattenedJWE, JWEHeaderParameters, DecryptOptions, FlattenedDecryptResult } diff --git a/dist/deno/jwe/flattened/encrypt.ts b/dist/deno/jwe/flattened/encrypt.ts deleted file mode 100644 index 11d86270c2..0000000000 --- a/dist/deno/jwe/flattened/encrypt.ts +++ /dev/null @@ -1,321 +0,0 @@ -import type { - KeyLike, - FlattenedJWE, - JWEHeaderParameters, - JWEKeyManagementHeaderParameters, - EncryptOptions, -} from '../../types.d.ts' -import type { JWEKeyManagementHeaderResults } from '../../types.i.d.ts' -import ivFactory from '../../lib/iv.ts' -import { encode as base64url } from '../../runtime/base64url.ts' -import random from '../../runtime/random.ts' -import encrypt from '../../runtime/encrypt.ts' -import { deflate } from '../../runtime/zlib.ts' -import encryptKeyManagement from '../../lib/encrypt_key_management.ts' - -import { JOSENotSupported, JWEInvalid } from '../../util/errors.ts' -import isDisjoint from '../../lib/is_disjoint.ts' -import { encoder, decoder, concat } from '../../lib/buffer_utils.ts' -import validateCrit from '../../lib/validate_crit.ts' - -const generateIv = ivFactory(random) -const checkExtensions = validateCrit.bind(undefined, JWEInvalid, new Map()) - -/** - * The FlattenedEncrypt class is a utility for creating Flattened JWE - * objects. - * - * @example ESM import - * ```js - * import { FlattenedEncrypt } from 'jose/jwe/flattened/encrypt' - * ``` - * - * @example CJS import - * ```js - * const { FlattenedEncrypt } = require('jose/jwe/flattened/encrypt') - * ``` - * - * @example Deno import - * ```js - * import { FlattenedEncrypt } from 'https://deno.land/x/jose@VERSION/jwe/flattened/encrypt.ts' - * ``` - * - * @example Usage - * ```js - * const encoder = new TextEncoder() - * - * 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) - * ``` - */ -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, - } - - checkExtensions(options?.crit, this._protectedHeader, joseHeader) - - if (joseHeader.zip !== undefined) { - 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 (typeof alg !== 'string' || !alg) { - throw new JWEInvalid('JWE "alg" (Algorithm) Header Parameter missing or invalid') - } - - if (typeof enc !== 'string' || !enc) { - throw new JWEInvalid('JWE "enc" (Encryption Algorithm) Header Parameter missing or invalid') - } - - 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 ||= 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 { FlattenedEncrypt } -export default FlattenedEncrypt -export type { KeyLike, FlattenedJWE, JWEHeaderParameters, JWEKeyManagementHeaderParameters } diff --git a/dist/deno/jwe/general/decrypt.ts b/dist/deno/jwe/general/decrypt.ts deleted file mode 100644 index 68b1c3bc1c..0000000000 --- a/dist/deno/jwe/general/decrypt.ts +++ /dev/null @@ -1,107 +0,0 @@ -import decrypt from '../flattened/decrypt.ts' -import { JWEDecryptionFailed, JWEInvalid } from '../../util/errors.ts' -import type { - KeyLike, - DecryptOptions, - JWEHeaderParameters, - GetKeyFunction, - FlattenedJWE, - GeneralJWE, - GeneralDecryptResult, -} from '../../types.d.ts' -import isObject from '../../lib/is_object.ts' - -/** - * Interface for General JWE Decryption dynamic key resolution. - * No token components have been verified at the time of this function call. - */ -export interface GeneralDecryptGetKey extends GetKeyFunction {} - -/** - * Decrypts a General JWE. - * - * @param jwe General 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 - * ```js - * import { generalDecrypt } from 'jose/jwe/general/decrypt' - * ``` - * - * @example CJS import - * ```js - * const { generalDecrypt } = require('jose/jwe/general/decrypt') - * ``` - * - * @example Deno import - * ```js - * import { generalDecrypt } from 'https://deno.land/x/jose@VERSION/jwe/general/decrypt.ts' - * ``` - * - * @example Usage - * ```js - * const decoder = new TextDecoder() - * const jwe = { - * ciphertext: '9EzjFISUyoG-ifC2mSihfP0DPC80yeyrxhTzKt1C_VJBkxeBG0MI4Te61Pk45RAGubUvBpU9jm4', - * iv: '8Fy7A_IuoX5VXG9s', - * tag: 'W76IYV6arGRuDSaSyWrQNg', - * aad: 'VGhlIEZlbGxvd3NoaXAgb2YgdGhlIFJpbmc', - * protected: 'eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMjU2R0NNIn0', - * recipients: [ - * { - * encrypted_key: 'Z6eD4UK_yFb5ZoKvKkGAdqywEG_m0e4IYo0x8Vf30LAMJcsc-_zSgIeiF82teZyYi2YYduHKoqImk7MRnoPZOlEs0Q5BNK1OgBmSOhCE8DFyqh9Zh48TCTP6lmBQ52naqoUJFMtHzu-0LwZH26hxos0GP3Dt19O379MJB837TdKKa87skq0zHaVLAquRHOBF77GI54Bc7O49d8aOrSu1VEFGMThlW2caspPRiTSePDMDPq7_WGk50izRhB3Asl9wmP9wEeaTrkJKRnQj5ips1SAZ1hDBsqEQKKukxP1HtdcopHV5_qgwU8Hjm5EwSLMluMQuiE6hwlkXGOujZLVizA' - * } - * ] - * } - * - * const { - * plaintext, - * protectedHeader, - * additionalAuthenticatedData - * } = await generalDecrypt(jwe, privateKey) - * - * console.log(protectedHeader) - * console.log(decoder.decode(plaintext)) - * console.log(decoder.decode(additionalAuthenticatedData)) - * ``` - */ -async function generalDecrypt( - jwe: GeneralJWE, - key: KeyLike | GeneralDecryptGetKey, - options?: DecryptOptions, -): Promise { - if (!isObject(jwe)) { - throw new JWEInvalid('General JWE must be an object') - } - - if (!Array.isArray(jwe.recipients) || !jwe.recipients.every(isObject)) { - throw new JWEInvalid('JWE Recipients missing or incorrect type') - } - - for (const recipient of jwe.recipients) { - try { - return await decrypt( - { - aad: jwe.aad, - ciphertext: jwe.ciphertext, - encrypted_key: recipient.encrypted_key, - header: recipient.header, - iv: jwe.iv, - protected: jwe.protected, - tag: jwe.tag, - unprotected: jwe.unprotected, - }, - [1]>key, - options, - ) - } catch { - // - } - } - throw new JWEDecryptionFailed() -} - -export { generalDecrypt } -export default generalDecrypt -export type { KeyLike, GeneralJWE, DecryptOptions, GeneralDecryptResult } diff --git a/dist/deno/jwk/embedded.ts b/dist/deno/jwk/embedded.ts deleted file mode 100644 index 05fbcc050d..0000000000 --- a/dist/deno/jwk/embedded.ts +++ /dev/null @@ -1,62 +0,0 @@ -import type { KeyObject, FlattenedJWSInput, JWSHeaderParameters } from '../types.d.ts' -import parseJwk from './parse.ts' -import isObject from '../lib/is_object.ts' -import { JWSInvalid } from '../util/errors.ts' - -/** - * 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 - * ```js - * import { EmbeddedJWK } from 'jose/jwk/embedded' - * ``` - * - * @example CJS import - * ```js - * const { EmbeddedJWK } = require('jose/jwk/embedded') - * ``` - * - * @example Deno import - * ```js - * import { EmbeddedJWK } from 'https://deno.land/x/jose@VERSION/jwk/embedded.ts' - * ``` - * - * @example Usage - * ```js - * 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) - * ``` - */ -async function EmbeddedJWK(protectedHeader: JWSHeaderParameters, token: FlattenedJWSInput) { - const joseHeader = { - ...protectedHeader, - ...token.header, - } - if (!isObject(joseHeader.jwk)) { - throw new JWSInvalid('"jwk" (JSON Web Key) Header Parameter must be a JSON object') - } - - const key = await parseJwk(joseHeader.jwk!, joseHeader.alg!, true) - - if (key.type !== 'public') { - throw new JWSInvalid('"jwk" (JSON Web Key) Header Parameter must be a public key') - } - - return key -} - -export { EmbeddedJWK } -export default EmbeddedJWK diff --git a/dist/deno/jwk/from_key_like.ts b/dist/deno/jwk/from_key_like.ts deleted file mode 100644 index b71492ee68..0000000000 --- a/dist/deno/jwk/from_key_like.ts +++ /dev/null @@ -1,39 +0,0 @@ -import type { JWK, KeyLike } from '../types.d.ts' -import asJWK from '../runtime/key_to_jwk.ts' - -/** - * Converts a runtime-specific key representation (KeyLike) to a JWK. - * - * @param key Key representation to transform to a JWK. - * - * @example ESM import - * ```js - * import { fromKeyLike } from 'jose/jwk/from_key_like' - * ``` - * - * @example CJS import - * ```js - * const { fromKeyLike } = require('jose/jwk/from_key_like') - * ``` - * - * @example Deno import - * ```js - * import { fromKeyLike } from 'https://deno.land/x/jose@VERSION/jwk/from_key_like.ts' - * ``` - * - * @example Usage - * ```js - * const privateJwk = await fromKeyLike(privateKey) - * const publicJwk = await fromKeyLike(publicKey) - * - * console.log(privateJwk) - * console.log(publicJwk) - * ``` - */ -async function fromKeyLike(key: KeyLike): Promise { - return asJWK(key) -} - -export { fromKeyLike } -export default fromKeyLike -export type { KeyLike, JWK } diff --git a/dist/deno/jwk/parse.ts b/dist/deno/jwk/parse.ts deleted file mode 100644 index ffd92ab1c9..0000000000 --- a/dist/deno/jwk/parse.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { decode as base64url } from '../runtime/base64url.ts' -import asKeyObject from '../runtime/jwk_to_key.ts' -import { JOSENotSupported } from '../util/errors.ts' -import isObject from '../lib/is_object.ts' -import type { JWK, KeyLike } from '../types.d.ts' - -/** - * Converts a JWK to a runtime-specific key representation (KeyLike). 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 - * ```js - * import { parseJwk } from 'jose/jwk/parse' - * ``` - * - * @example CJS import - * ```js - * const { parseJwk } = require('jose/jwk/parse') - * ``` - * - * @example Deno import - * ```js - * import { parseJwk } from 'https://deno.land/x/jose@VERSION/jwk/parse.ts' - * ``` - * - * @example Usage - * ```js - * const ecPublicKey = await parseJwk({ - * crv: 'P-256', - * kty: 'EC', - * x: 'ySK38C1jBdLwDsNWKzzBHqKYEE5Cgv-qjWvorUXk9fw', - * y: '_LeQBw07cf5t57Iavn4j-BqJsAD1dpoz8gokd3sBsOo' - * }, 'ES256') - * - * const rsaPublicKey = await parseJwk({ - * kty: 'RSA', - * e: 'AQAB', - * n: '12oBZRhCiZFJLcPg59LkZZ9mdhSMTKAQZYq32k_ti5SBB6jerkh-WzOMAO664r_qyLkqHUSp3u5SbXtseZEpN3XPWGKSxjsy-1JyEFTdLSYe6f9gfrmxkUF_7DTpq0gn6rntP05g2-wFW50YO7mosfdslfrTJYWHFhJALabAeYirYD7-9kqq9ebfFMF4sRRELbv9oi36As6Q9B3Qb5_C1rAzqfao_PCsf9EPsTZsVVVkA5qoIAr47lo1ipfiBPxUCCNSdvkmDTYgvvRm6ZoMjFbvOtgyts55fXKdMWv7I9HMD5HwE9uW839PWA514qhbcIsXEYSFMPMV6fnlsiZvQQ' - * }, 'PS256') - * ``` - */ -async function parseJwk(jwk: JWK, alg?: string, octAsKeyObject?: boolean): Promise { - if (!isObject(jwk)) { - throw new TypeError('JWK must be an object') - } - - 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') - } - - octAsKeyObject ??= jwk.ext !== true - - if (octAsKeyObject) { - return asKeyObject({ ...jwk, alg, ext: false }) - } - - return base64url(jwk.k) - case 'RSA': - if (jwk.oth !== undefined) { - throw new JOSENotSupported( - 'RSA JWK "oth" (Other Primes Info) Parameter value is not supported', - ) - } - case 'EC': - case 'OKP': - return asKeyObject({ ...jwk, alg }) - default: - throw new JOSENotSupported('unsupported "kty" (Key Type) Parameter value') - } -} - -export { parseJwk } -export default parseJwk -export type { KeyLike, JWK } diff --git a/dist/deno/jwk/thumbprint.ts b/dist/deno/jwk/thumbprint.ts deleted file mode 100644 index ae0db83f0c..0000000000 --- a/dist/deno/jwk/thumbprint.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { JOSENotSupported, JWKInvalid } from '../util/errors.ts' - -import digest from '../runtime/digest.ts' -import { encode as base64url } from '../runtime/base64url.ts' -import { encoder } from '../lib/buffer_utils.ts' -import type { JWK } from '../types.d.ts' -import isObject from '../lib/is_object.ts' - -const check = (value: unknown, 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 - * ```js - * import { calculateThumbprint } from 'jose/jwk/thumbprint' - * ``` - * - * @example CJS import - * ```js - * const { calculateThumbprint } = require('jose/jwk/thumbprint') - * ``` - * - * @example Deno import - * ```js - * import { calculateThumbprint } from 'https://deno.land/x/jose@VERSION/jwk/thumbprint.ts' - * ``` - * - * @example Usage - * ```js - * const thumbprint = await calculateThumbprint({ - * kty: 'RSA', - * e: 'AQAB', - * n: '12oBZRhCiZFJLcPg59LkZZ9mdhSMTKAQZYq32k_ti5SBB6jerkh-WzOMAO664r_qyLkqHUSp3u5SbXtseZEpN3XPWGKSxjsy-1JyEFTdLSYe6f9gfrmxkUF_7DTpq0gn6rntP05g2-wFW50YO7mosfdslfrTJYWHFhJALabAeYirYD7-9kqq9ebfFMF4sRRELbv9oi36As6Q9B3Qb5_C1rAzqfao_PCsf9EPsTZsVVVkA5qoIAr47lo1ipfiBPxUCCNSdvkmDTYgvvRm6ZoMjFbvOtgyts55fXKdMWv7I9HMD5HwE9uW839PWA514qhbcIsXEYSFMPMV6fnlsiZvQQ' - * }) - * - * console.log(thumbprint) - * ``` - */ -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 { calculateThumbprint } -export default calculateThumbprint -export type { JWK } diff --git a/dist/deno/jwks/remote.ts b/dist/deno/jwks/remote.ts deleted file mode 100644 index 3e1bc662f6..0000000000 --- a/dist/deno/jwks/remote.ts +++ /dev/null @@ -1,264 +0,0 @@ -import type { - KeyObject, - JWSHeaderParameters, - JWK, - FlattenedJWSInput, - GetKeyFunction, -} from '../types.d.ts' -import parseJWK from '../jwk/parse.ts' -import { - JWKSInvalid, - JOSENotSupported, - JWKSNoMatchingKey, - JWKSMultipleMatchingKeys, -} from '../util/errors.ts' -import fetchJwks from '../runtime/fetch_jwks.ts' -import isObject from '../lib/is_object.ts' - -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 - - /** - * An instance of [http.Agent](https://nodejs.org/api/http.html#http_class_http_agent) - * or [https.Agent](https://nodejs.org/api/https.html#https_class_https_agent) to pass - * to the [http.get](https://nodejs.org/api/http.html#http_http_get_options_callback) - * or [https.get](https://nodejs.org/api/https.html#https_https_get_options_callback) - * method's options. Use when behind an http(s) proxy. - * This is a Node.js runtime specific option, it is ignored - * when used outside of Node.js runtime. - */ - agent?: any -} - -function isJWKLike(key: unknown): key is JWK { - return isObject(key) -} - -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?: Promise - - private _options: Pick - - 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._options = { agent: options?.agent } - 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 (cached[protectedHeader.alg!] === undefined) { - const keyObject = await parseJWK({ ...jwk, alg: protectedHeader.alg! }) - - 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 = fetchJwks(this._url, this._timeoutDuration, this._options) - .then((json) => { - if ( - typeof json !== 'object' || - !json || - !Array.isArray(json.keys) || - !json.keys.every(isJWKLike) - ) { - throw new JWKSInvalid('JSON Web Key Set malformed') - } - - this._jwks = { keys: json.keys } - this._cooldownStarted = Date.now() - this._pendingFetch = undefined - }) - .catch((err: Error) => { - 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 - * ```js - * import { createRemoteJWKSet } from 'jose/jwks/remote' - * ``` - * - * @example CJS import - * ```js - * const { createRemoteJWKSet } = require('jose/jwks/remote') - * ``` - * - * @example Deno import - * ```js - * import { createRemoteJWKSet } from 'https://deno.land/x/jose@VERSION/jwks/remote.ts' - * ``` - * - * @example Usage - * ```js - * 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. - */ -function createRemoteJWKSet( - url: URL, - options?: RemoteJWKSetOptions, -): GetKeyFunction { - return RemoteJWKSet.prototype.getKey.bind(new RemoteJWKSet(url, options)) -} - -export { createRemoteJWKSet } -export default createRemoteJWKSet diff --git a/dist/deno/jws/compact/sign.ts b/dist/deno/jws/compact/sign.ts deleted file mode 100644 index 17274b9b21..0000000000 --- a/dist/deno/jws/compact/sign.ts +++ /dev/null @@ -1,72 +0,0 @@ -import FlattenedSign from '../flattened/sign.ts' -import type { JWSHeaderParameters, KeyLike, SignOptions } from '../../types.d.ts' - -/** - * The CompactSign class is a utility for creating Compact JWS strings. - * - * @example ESM import - * ```js - * import { CompactSign } from 'jose/jws/compact/sign' - * ``` - * - * @example CJS import - * ```js - * const { CompactSign } = require('jose/jws/compact/sign') - * ``` - * - * @example Deno import - * ```js - * import { CompactSign } from 'https://deno.land/x/jose@VERSION/jws/compact/sign.ts' - * ``` - * - * @example Usage - * ```js - * const encoder = new TextEncoder() - * - * 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) - * ``` - */ -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. - * @param options JWS Sign options. - */ - async sign(key: KeyLike, options?: SignOptions): Promise { - const jws = await this._flattened.sign(key, options) - - 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 { CompactSign } -export default CompactSign -export type { JWSHeaderParameters, KeyLike } diff --git a/dist/deno/jws/compact/verify.ts b/dist/deno/jws/compact/verify.ts deleted file mode 100644 index 31da725f91..0000000000 --- a/dist/deno/jws/compact/verify.ts +++ /dev/null @@ -1,89 +0,0 @@ -import verify from '../flattened/verify.ts' -import { JWSInvalid } from '../../util/errors.ts' -import { decoder } from '../../lib/buffer_utils.ts' -import type { - CompactVerifyResult, - FlattenedJWSInput, - GetKeyFunction, - JWSHeaderParameters, - KeyLike, - VerifyOptions, -} from '../../types.d.ts' - -/** - * Interface for Compact JWS Verification dynamic key resolution. - * No token components have been verified at the time of this function call. - * - * See [createRemoteJWKSet](../functions/jwks_remote.createRemoteJWKSet.md#function-createremotejwkset) - * to verify using a remote JSON Web Key Set. - */ -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 - * ```js - * import { compactVerify } from 'jose/jws/compact/verify' - * ``` - * - * @example CJS import - * ```js - * const { compactVerify } = require('jose/jws/compact/verify') - * ``` - * - * @example Deno import - * ```js - * import { compactVerify } from 'https://deno.land/x/jose@VERSION/jws/compact/verify.ts' - * ``` - * - * @example Usage - * ```js - * const decoder = new TextDecoder() - * const jws = 'eyJhbGciOiJFUzI1NiJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4.kkAs_gPPxWMI3rHuVlxHaTPfDWDoqdI8jSvuSmqV-8IHIWXg9mcAeC9ggV-45ZHRbiRJ3obUIFo1rHphPA5URg' - * - * const { payload, protectedHeader } = await compactVerify(jws, publicKey) - * - * console.log(protectedHeader) - * console.log(decoder.decode(payload)) - * ``` - */ -async function compactVerify( - jws: string | Uint8Array, - key: KeyLike | CompactVerifyGetKey, - options?: VerifyOptions, -): Promise { - if (jws instanceof Uint8Array) { - jws = decoder.decode(jws) - } - - if (typeof jws !== 'string') { - throw new JWSInvalid('Compact JWS must be a string or Uint8Array') - } - const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split('.') - - if (length !== 3) { - throw new JWSInvalid('Invalid Compact JWS') - } - - const verified = await verify( - { - payload: (payload || undefined), - protected: protectedHeader || undefined, - signature: (signature || undefined), - }, - [1]>key, - options, - ) - - return { payload: verified.payload, protectedHeader: verified.protectedHeader! } -} - -export { compactVerify } -export default compactVerify -export type { KeyLike, VerifyOptions, CompactVerifyResult } diff --git a/dist/deno/jws/flattened/sign.ts b/dist/deno/jws/flattened/sign.ts deleted file mode 100644 index c26b862144..0000000000 --- a/dist/deno/jws/flattened/sign.ts +++ /dev/null @@ -1,164 +0,0 @@ -import isDisjoint from '../../lib/is_disjoint.ts' -import { JWSInvalid } from '../../util/errors.ts' -import { encoder, decoder, concat } from '../../lib/buffer_utils.ts' - -import { encode as base64url } from '../../runtime/base64url.ts' -import sign from '../../runtime/sign.ts' -import type { KeyLike, FlattenedJWS, JWSHeaderParameters, SignOptions } from '../../types.d.ts' -import checkKeyType from '../../lib/check_key_type.ts' -import validateCrit from '../../lib/validate_crit.ts' - -const checkExtensions = validateCrit.bind(undefined, JWSInvalid, new Map([['b64', true]])) - -/** - * The FlattenedSign class is a utility for creating Flattened JWS objects. - * - * @example ESM import - * ```js - * import { FlattenedSign } from 'jose/jws/flattened/sign' - * ``` - * - * @example CJS import - * ```js - * const { FlattenedSign } = require('jose/jws/flattened/sign') - * ``` - * - * @example Deno import - * ```js - * import { FlattenedSign } from 'https://deno.land/x/jose@VERSION/jws/flattened/sign.ts' - * ``` - * - * @example Usage - * ```js - * const encoder = new TextEncoder() - * - * 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) - * ``` - */ -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. - * @param options JWS Sign options. - */ - async sign(key: KeyLike, options?: SignOptions): 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(options?.crit, 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 (typeof alg !== 'string' || !alg) { - throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid') - } - - checkKeyType(alg, key, 'sign') - - 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), - payload: '', - } - - 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 { FlattenedSign } -export default FlattenedSign -export type { KeyLike, FlattenedJWS, JWSHeaderParameters } diff --git a/dist/deno/jws/flattened/verify.ts b/dist/deno/jws/flattened/verify.ts deleted file mode 100644 index 1f34f68fa5..0000000000 --- a/dist/deno/jws/flattened/verify.ts +++ /dev/null @@ -1,201 +0,0 @@ -import { JOSEAlgNotAllowed, JWSInvalid, JWSSignatureVerificationFailed } from '../../util/errors.ts' -import { concat, encoder, decoder } from '../../lib/buffer_utils.ts' -import isDisjoint from '../../lib/is_disjoint.ts' -import isObject from '../../lib/is_object.ts' -import checkKeyType from '../../lib/check_key_type.ts' - -import { decode as base64url } from '../../runtime/base64url.ts' -import verify from '../../runtime/verify.ts' -import validateCrit from '../../lib/validate_crit.ts' -import validateAlgorithms from '../../lib/validate_algorithms.ts' - -import type { - FlattenedVerifyResult, - KeyLike, - FlattenedJWSInput, - JWSHeaderParameters, - VerifyOptions, - GetKeyFunction, -} from '../../types.d.ts' - -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. - * - * See [createRemoteJWKSet](../functions/jwks_remote.createRemoteJWKSet.md#function-createremotejwkset) - * to verify using a remote JSON Web Key Set. - */ -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 - * ```js - * import { flattenedVerify } from 'jose/jws/flattened/verify' - * ``` - * - * @example CJS import - * ```js - * const { flattenedVerify } = require('jose/jws/flattened/verify') - * ``` - * - * @example Deno import - * ```js - * import { flattenedVerify } from 'https://deno.land/x/jose@VERSION/jws/flattened/verify.ts' - * ``` - * - * @example Usage - * ```js - * const decoder = new TextDecoder() - * const jws = { - * signature: 'FVVOXwj6kD3DqdfD9yYqfT2W9jv-Nop4kOehp_DeDGNB5dQNSPRvntBY6xH3uxlCxE8na9d_kyhYOcanpDJ0EA', - * payload: 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4', - * protected: 'eyJhbGciOiJFUzI1NiJ9' - * } - * - * const { payload, protectedHeader } = await flattenedVerify(jws, publicKey) - * - * console.log(protectedHeader) - * console.log(decoder.decode(payload)) - * ``` - */ -async function flattenedVerify( - jws: FlattenedJWSInput, - key: KeyLike | FlattenedVerifyGetKey, - options?: VerifyOptions, -): Promise { - if (!isObject(jws)) { - throw new JWSInvalid('Flattened JWS must be an object') - } - - if (jws.protected === undefined && jws.header === undefined) { - throw new JWSInvalid('Flattened JWS must have either of the "protected" or "header" members') - } - - if (jws.protected !== undefined && typeof jws.protected !== 'string') { - throw new JWSInvalid('JWS Protected Header incorrect type') - } - - if (jws.payload === undefined) { - throw new JWSInvalid('JWS Payload missing') - } - - if (typeof jws.signature !== 'string') { - throw new JWSInvalid('JWS Signature missing or incorrect type') - } - - if (jws.header !== undefined && !isObject(jws.header)) { - throw new JWSInvalid('JWS Unprotected Header incorrect type') - } - - let parsedProt: JWSHeaderParameters = {} - if (jws.protected) { - const protectedHeader = base64url(jws.protected) - try { - parsedProt = JSON.parse(decoder.decode(protectedHeader)) - } catch { - throw new JWSInvalid('JWS Protected Header is invalid') - } - } - 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(options?.crit, 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 (typeof alg !== 'string' || !alg) { - throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid') - } - - 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') { - key = await key(parsedProt, jws) - } - - checkKeyType(alg, key, 'verify') - - 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 (jws.protected !== undefined) { - result.protectedHeader = parsedProt - } - - if (jws.header !== undefined) { - result.unprotectedHeader = jws.header - } - - return result -} - -export { flattenedVerify } -export default flattenedVerify -export type { - KeyLike, - FlattenedJWSInput, - GetKeyFunction, - JWSHeaderParameters, - VerifyOptions, - FlattenedVerifyResult, -} diff --git a/dist/deno/jws/general/sign.ts b/dist/deno/jws/general/sign.ts deleted file mode 100644 index ca0b280df2..0000000000 --- a/dist/deno/jws/general/sign.ts +++ /dev/null @@ -1,163 +0,0 @@ -import FlattenedSign from '../flattened/sign.ts' -import { JWSInvalid } from '../../util/errors.ts' - -import type { KeyLike, GeneralJWS, JWSHeaderParameters, SignOptions } from '../../types.d.ts' - -export interface Signature { - /** - * Sets the JWS Protected Header on the Signature object. - * - * @param protectedHeader JWS Protected Header. - */ - setProtectedHeader(protectedHeader: JWSHeaderParameters): Signature - - /** - * Sets the JWS Unprotected Header on the Signature object. - * - * @param unprotectedHeader JWS Unprotected Header. - */ - setUnprotectedHeader(unprotectedHeader: JWSHeaderParameters): Signature -} - -interface SignatureReference { - protectedHeader?: JWSHeaderParameters - unprotectedHeader?: JWSHeaderParameters - options?: SignOptions - key: KeyLike -} - -const signatureRef: WeakMap = new WeakMap() - -class IndividualSignature implements Signature { - setProtectedHeader(protectedHeader: JWSHeaderParameters) { - if (this._protectedHeader) { - throw new TypeError('setProtectedHeader can only be called once') - } - this._protectedHeader = protectedHeader - return this - } - - setUnprotectedHeader(unprotectedHeader: JWSHeaderParameters) { - if (this._unprotectedHeader) { - throw new TypeError('setUnprotectedHeader can only be called once') - } - this._unprotectedHeader = unprotectedHeader - return this - } - - private set _protectedHeader(value: JWSHeaderParameters) { - signatureRef.get(this)!.protectedHeader = value - } - - private get _protectedHeader(): JWSHeaderParameters { - return signatureRef.get(this)!.protectedHeader! - } - - private set _unprotectedHeader(value: JWSHeaderParameters) { - signatureRef.get(this)!.unprotectedHeader = value - } - - private get _unprotectedHeader(): JWSHeaderParameters { - return signatureRef.get(this)!.unprotectedHeader! - } -} - -/** - * The GeneralSign class is a utility for creating General JWS objects. - * - * @example ESM import - * ```js - * import { GeneralSign } from 'jose/jws/general/sign' - * ``` - * - * @example CJS import - * ```js - * const { GeneralSign } = require('jose/jws/general/sign') - * ``` - * - * @example Deno import - * ```js - * import { GeneralSign } from 'https://deno.land/x/jose@VERSION/jws/general/sign.ts' - * ``` - * - * @example Usage - * ```js - * const encoder = new TextEncoder() - * - * const sign = new GeneralSign(encoder.encode('It’s a dangerous business, Frodo, going out your door.')) - * - * sign - * .addSignature(ecPrivateKey) - * .setProtectedHeader({ alg: 'ES256' }) - * - * sign - * .addSignature(rsaPrivateKey) - * .setProtectedHeader({ alg: 'PS256' }) - * - * const jws = await sign.sign() - * ``` - */ -class GeneralSign { - private _payload: Uint8Array - - private _signatures: IndividualSignature[] = [] - - /** - * @param payload Binary representation of the payload to sign. - */ - constructor(payload: Uint8Array) { - this._payload = payload - } - - addSignature(key: KeyLike, options?: SignOptions): Signature { - const signature = new IndividualSignature() - signatureRef.set(signature, { key, options }) - this._signatures.push(signature) - return signature - } - - /** - * Signs and resolves the value of the General JWS object. - */ - async sign(): Promise { - if (!this._signatures.length) { - throw new JWSInvalid('at least one signature must be added') - } - - const jws: GeneralJWS = { - signatures: [], - payload: '', - } - - let payloads = new Set() - await Promise.all( - this._signatures.map(async (sig) => { - const { protectedHeader, unprotectedHeader, options, key } = signatureRef.get(sig)! - const flattened = new FlattenedSign(this._payload) - - if (protectedHeader) { - flattened.setProtectedHeader(protectedHeader) - } - - if (unprotectedHeader) { - flattened.setUnprotectedHeader(unprotectedHeader) - } - - const { payload, ...rest } = await flattened.sign(key, options) - payloads.add(payload) - jws.payload = payload - jws.signatures.push(rest) - }), - ) - - if (payloads.size !== 1) { - throw new JWSInvalid('inconsistent use of JWS Unencoded Payload Option (RFC7797)') - } - - return jws - } -} - -export { GeneralSign } -export default GeneralSign -export type { KeyLike, GeneralJWS, JWSHeaderParameters } diff --git a/dist/deno/jws/general/verify.ts b/dist/deno/jws/general/verify.ts deleted file mode 100644 index 2b1254961c..0000000000 --- a/dist/deno/jws/general/verify.ts +++ /dev/null @@ -1,99 +0,0 @@ -import verify from '../flattened/verify.ts' -import type { - GeneralJWSInput, - GeneralVerifyResult, - FlattenedJWSInput, - GetKeyFunction, - JWSHeaderParameters, - KeyLike, - VerifyOptions, -} from '../../types.d.ts' -import { JWSInvalid, JWSSignatureVerificationFailed } from '../../util/errors.ts' -import isObject from '../../lib/is_object.ts' - -/** - * Interface for General JWS Verification dynamic key resolution. - * No token components have been verified at the time of this function call. - * - * See [createRemoteJWKSet](../functions/jwks_remote.createRemoteJWKSet.md#function-createremotejwkset) - * to verify using a remote JSON Web Key Set. - */ -export interface GeneralVerifyGetKey - extends GetKeyFunction {} - -/** - * Verifies the signature and format of and afterwards decodes the General JWS. - * - * @param jws General JWS. - * @param key Key, or a function resolving a key, to verify the JWS with. - * @param options JWS Verify options. - * - * @example ESM import - * ```js - * import { generalVerify } from 'jose/jws/general/verify' - * ``` - * - * @example CJS import - * ```js - * const { generalVerify } = require('jose/jws/general/verify') - * ``` - * - * @example Deno import - * ```js - * import { generalVerify } from 'https://deno.land/x/jose@VERSION/jws/general/verify.ts' - * ``` - * - * @example Usage - * ```js - * const decoder = new TextDecoder() - * const jws = { - * payload: 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4', - * signatures: [ - * { - * signature: 'FVVOXwj6kD3DqdfD9yYqfT2W9jv-Nop4kOehp_DeDGNB5dQNSPRvntBY6xH3uxlCxE8na9d_kyhYOcanpDJ0EA', - * protected: 'eyJhbGciOiJFUzI1NiJ9' - * } - * ] - * } - * - * const { payload, protectedHeader } = await generalVerify(jws, publicKey) - * - * console.log(protectedHeader) - * console.log(decoder.decode(payload)) - * ``` - */ -async function generalVerify( - jws: GeneralJWSInput, - key: KeyLike | GeneralVerifyGetKey, - options?: VerifyOptions, -): Promise { - if (!isObject(jws)) { - throw new JWSInvalid('General JWS must be an object') - } - - if (!Array.isArray(jws.signatures) || !jws.signatures.every(isObject)) { - throw new JWSInvalid('JWS Signatures missing or incorrect type') - } - - for (const signature of jws.signatures) { - try { - return await verify( - { - header: signature.header, - payload: jws.payload, - protected: signature.protected, - signature: signature.signature, - }, - [1]>key, - options, - ) - } catch { - // - } - } - throw new JWSSignatureVerificationFailed() -} - -export { generalVerify } -export default generalVerify -export type { KeyLike, GeneralJWSInput, VerifyOptions, GeneralVerifyResult } diff --git a/dist/deno/jwt/decrypt.ts b/dist/deno/jwt/decrypt.ts deleted file mode 100644 index f663816c67..0000000000 --- a/dist/deno/jwt/decrypt.ts +++ /dev/null @@ -1,103 +0,0 @@ -import decrypt from '../jwe/compact/decrypt.ts' -import type { - KeyLike, - DecryptOptions, - JWTPayload, - JWTClaimVerificationOptions, - GetKeyFunction, - JWEHeaderParameters, - FlattenedJWE, - JWTDecryptResult, -} from '../types.d.ts' -import jwtPayload from '../lib/jwt_claims_set.ts' -import { JWTClaimValidationFailed } from '../util/errors.ts' - -/** - * 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 - * ```js - * import { jwtDecrypt } from 'jose/jwt/decrypt' - * ``` - * - * @example CJS import - * ```js - * const { jwtDecrypt } = require('jose/jwt/decrypt') - * ``` - * - * @example Deno import - * ```js - * import { jwtDecrypt } from 'https://deno.land/x/jose@VERSION/jwt/decrypt.ts' - * ``` - * - * @example Usage - * ```js - * const jwt = 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..KVcNLqK-3-8ZkYIC.xSwF4VxO0kUMUD2W-cifsNUxnr-swyBq-nADBptyt6y9n79-iNc5b0AALJpRwc0wwDkJw8hNOMjApNUTMsK9b-asToZ3DXFMvwfJ6n1aWefvd7RsoZ2LInWFfVAuttJDzoGB.uuexQoWHwrLMEYRElT8pBQ' - * - * const { payload, protectedHeader } = await jwtDecrypt(jwt, secretKey, { - * issuer: 'urn:example:issuer', - * audience: 'urn:example:audience' - * }) - * - * console.log(protectedHeader) - * console.log(payload) - * ``` - */ -async function jwtDecrypt( - jwt: string | Uint8Array, - 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 (protectedHeader.iss !== undefined && protectedHeader.iss !== payload.iss) { - throw new JWTClaimValidationFailed( - 'replicated "iss" claim header parameter mismatch', - 'iss', - 'mismatch', - ) - } - - if (protectedHeader.sub !== undefined && protectedHeader.sub !== payload.sub) { - throw new JWTClaimValidationFailed( - 'replicated "sub" claim header parameter mismatch', - 'sub', - 'mismatch', - ) - } - - if ( - protectedHeader.aud !== undefined && - JSON.stringify(protectedHeader.aud) !== JSON.stringify(payload.aud) - ) { - throw new JWTClaimValidationFailed( - 'replicated "aud" claim header parameter mismatch', - 'aud', - 'mismatch', - ) - } - - return { payload, protectedHeader } -} - -export { jwtDecrypt } -export default jwtDecrypt -export type { KeyLike, DecryptOptions, JWTPayload, JWTDecryptOptions, JWTDecryptResult } diff --git a/dist/deno/jwt/encrypt.ts b/dist/deno/jwt/encrypt.ts deleted file mode 100644 index 0291e982c9..0000000000 --- a/dist/deno/jwt/encrypt.ts +++ /dev/null @@ -1,181 +0,0 @@ -import CompactEncrypt from '../jwe/compact/encrypt.ts' -import type { - EncryptOptions, - JWEHeaderParameters, - JWEKeyManagementHeaderParameters, - JWTPayload, - KeyLike, -} from '../types.d.ts' -import { encoder } from '../lib/buffer_utils.ts' -import ProduceJWT from '../lib/jwt_producer.ts' - -/** - * The EncryptJWT class is a utility for creating Compact JWE formatted JWT strings. - * - * @example ESM import - * ```js - * import { EncryptJWT } from 'jose/jwt/encrypt' - * ``` - * - * @example CJS import - * ```js - * const { EncryptJWT } = require('jose/jwt/encrypt') - * ``` - * - * @example Deno import - * ```js - * import { EncryptJWT } from 'https://deno.land/x/jose@VERSION/jwt/encrypt.ts' - * ``` - * - * @example Usage - * ```js - * 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) - * ``` - */ -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 { EncryptJWT } -export default EncryptJWT -export type { JWEHeaderParameters, JWTPayload, KeyLike } diff --git a/dist/deno/jwt/sign.ts b/dist/deno/jwt/sign.ts deleted file mode 100644 index a86bb5f3c8..0000000000 --- a/dist/deno/jwt/sign.ts +++ /dev/null @@ -1,73 +0,0 @@ -import CompactSign from '../jws/compact/sign.ts' -import { JWTInvalid } from '../util/errors.ts' -import type { JWSHeaderParameters, JWTPayload, KeyLike, SignOptions } from '../types.d.ts' -import { encoder } from '../lib/buffer_utils.ts' -import ProduceJWT from '../lib/jwt_producer.ts' - -/** - * The SignJWT class is a utility for creating Compact JWS formatted JWT strings. - * - * @example ESM import - * ```js - * import { SignJWT } from 'jose/jwt/sign' - * ``` - * - * @example CJS import - * ```js - * const { SignJWT } = require('jose/jwt/sign') - * ``` - * - * @example Deno import - * ```js - * import { SignJWT } from 'https://deno.land/x/jose@VERSION/jwt/sign.ts' - * ``` - * - * @example Usage - * ```js - * 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) - * ``` - */ -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. - * @param options JWT Sign options. - */ - async sign(key: KeyLike, options?: SignOptions): Promise { - const sig = new CompactSign(encoder.encode(JSON.stringify(this._payload))) - sig.setProtectedHeader(this._protectedHeader) - if ( - Array.isArray(this._protectedHeader?.crit) && - this._protectedHeader.crit.includes('b64') && - this._protectedHeader.b64 === false - ) { - throw new JWTInvalid('JWTs MUST NOT use unencoded payload') - } - return sig.sign(key, options) - } -} - -export { SignJWT } -export default SignJWT -export type { JWSHeaderParameters, JWTPayload, KeyLike } diff --git a/dist/deno/jwt/unsecured.ts b/dist/deno/jwt/unsecured.ts deleted file mode 100644 index c4f330bd0a..0000000000 --- a/dist/deno/jwt/unsecured.ts +++ /dev/null @@ -1,96 +0,0 @@ -import type { JWSHeaderParameters, JWTClaimVerificationOptions, JWTPayload } from '../types.d.ts' -import { decoder } from '../lib/buffer_utils.ts' -import * as base64url from '../runtime/base64url.ts' -import { JWTInvalid } from '../util/errors.ts' -import jwtPayload from '../lib/jwt_claims_set.ts' -import ProduceJWT from '../lib/jwt_producer.ts' - -interface UnsecuredResult { - payload: JWTPayload - header: JWSHeaderParameters -} - -/** - * The UnsecuredJWT class is a utility for dealing with `{ "alg": "none" }` Unsecured JWTs. - * - * @example ESM import - * ```js - * import { UnsecuredJWT } from 'jose/jwt/unsecured' - * ``` - * - * @example CJS import - * ```js - * const { UnsecuredJWT } = require('jose/jwt/unsecured') - * ``` - * - * @example Deno import - * ```js - * import { UnsecuredJWT } from 'https://deno.land/x/jose@VERSION/jwt/unsecured.ts' - * ``` - * - * @example Encoding - * ```js * - * 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 - * ```js * - * const payload = new UnsecuredJWT.decode(jwt, { - * issuer: 'urn:example:issuer', - * audience: 'urn:example:audience' - * }) - * - * console.log(payload) - * ``` - */ -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. - */ - static decode(jwt: string, options?: JWTClaimVerificationOptions): UnsecuredResult { - 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 { UnsecuredJWT } -export default UnsecuredJWT -export type { JWSHeaderParameters, JWTPayload, UnsecuredResult } diff --git a/dist/deno/jwt/verify.ts b/dist/deno/jwt/verify.ts deleted file mode 100644 index 28e5573768..0000000000 --- a/dist/deno/jwt/verify.ts +++ /dev/null @@ -1,86 +0,0 @@ -import verify from '../jws/compact/verify.ts' -import type { - KeyLike, - VerifyOptions, - JWTPayload, - JWTClaimVerificationOptions, - JWSHeaderParameters, - GetKeyFunction, - FlattenedJWSInput, - JWTVerifyResult, -} from '../types.d.ts' -import jwtPayload from '../lib/jwt_claims_set.ts' -import { JWTInvalid } from '../util/errors.ts' - -/** - * 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. - * - * See [createRemoteJWKSet](../functions/jwks_remote.createRemoteJWKSet.md#function-createremotejwkset) - * to verify using a remote JSON Web Key Set. - */ -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 - * ```js - * import { jwtVerify } from 'jose/jwt/verify' - * ``` - * - * @example CJS import - * ```js - * const { jwtVerify } = require('jose/jwt/verify') - * ``` - * - * @example Deno import - * ```js - * import { jwtVerify } from 'https://deno.land/x/jose@VERSION/jwt/verify.ts' - * ``` - * - * @example Usage - * ```js - * const jwt = 'eyJhbGciOiJFUzI1NiJ9.eyJ1cm46ZXhhbXBsZTpjbGFpbSI6dHJ1ZSwiaWF0IjoxNjA0MzE1MDc0LCJpc3MiOiJ1cm46ZXhhbXBsZTppc3N1ZXIiLCJhdWQiOiJ1cm46ZXhhbXBsZTphdWRpZW5jZSJ9.hx1nOfAT5LlXuzu8O-bhjXBGpklWDt2EsHw7-MDn49NrnwvVsstNhEnkW2ddauB7eSikFtUNeumLpFI9CWDBsg' - * - * const { payload, protectedHeader } = await jwtVerify(jwt, publicKey, { - * issuer: 'urn:example:issuer', - * audience: 'urn:example:audience' - * }) - * - * console.log(protectedHeader) - * console.log(payload) - * ``` - */ -async function jwtVerify( - jwt: string | Uint8Array, - key: KeyLike | JWTVerifyGetKey, - options?: JWTVerifyOptions, -): Promise { - const verified = await verify(jwt, key, options) - if (verified.protectedHeader.crit?.includes('b64') && verified.protectedHeader.b64 === false) { - throw new JWTInvalid('JWTs MUST NOT use unencoded payload') - } - const payload = jwtPayload(verified.protectedHeader, verified.payload, options) - return { payload, protectedHeader: verified.protectedHeader } -} - -export { jwtVerify } -export default jwtVerify -export type { - KeyLike, - JWTPayload, - JWTVerifyOptions, - JWSHeaderParameters, - GetKeyFunction, - JWTVerifyResult, -} diff --git a/dist/deno/lib/buffer_utils.ts b/dist/deno/lib/buffer_utils.ts deleted file mode 100644 index 8a766438fe..0000000000 --- a/dist/deno/lib/buffer_utils.ts +++ /dev/null @@ -1,71 +0,0 @@ -import type { DigestFunction } from '../runtime/interfaces.d.ts' - -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: DigestFunction, - 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('sha256', buf) - } else { - res = concat(res, await digest('sha256', buf)) - } - } - res = res.slice(0, bits >> 3) - return res -} diff --git a/dist/deno/lib/cek.ts b/dist/deno/lib/cek.ts deleted file mode 100644 index 1851ede8e0..0000000000 --- a/dist/deno/lib/cek.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { JOSENotSupported } from '../util/errors.ts' - -const bitLengths = new Map([ - ['A128CBC-HS256', 256], - ['A128GCM', 128], - ['A192CBC-HS384', 384], - ['A192GCM', 192], - ['A256CBC-HS512', 512], - ['A256GCM', 256], -]) - -const factory = - (random: (array: Uint8Array) => Uint8Array) => - (alg: string): Uint8Array => { - 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/dist/deno/lib/check_iv_length.ts b/dist/deno/lib/check_iv_length.ts deleted file mode 100644 index c6ba9d5739..0000000000 --- a/dist/deno/lib/check_iv_length.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { JWEInvalid } from '../util/errors.ts' -import { bitLengths } from './iv.ts' - -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/dist/deno/lib/check_key_type.ts b/dist/deno/lib/check_key_type.ts deleted file mode 100644 index eb3057e8d1..0000000000 --- a/dist/deno/lib/check_key_type.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { KeyLike } from '../types.d.ts' -import invalidKeyInput from '../runtime/invalid_key_input.ts' - -const checkKeyType = ( - alg: string, - key: KeyLike, - usage: 'sign' | 'verify' | 'encrypt' | 'decrypt', -): void => { - if (!(key instanceof Uint8Array) && !key?.type) { - throw new TypeError(invalidKeyInput(key, 'KeyObject', 'CryptoKey', 'Uint8Array')) - } - - 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(invalidKeyInput(key, 'KeyObject', 'CryptoKey')) - } - - if (key.type === 'secret') { - throw new TypeError( - 'CryptoKey or KeyObject instances for asymmetric algorithms must not be of type "secret"', - ) - } - - if (usage === 'sign' && key.type === 'public') { - throw new TypeError( - 'CryptoKey or KeyObject instances for asymmetric algorithm signing must be of type "private"', - ) - } - - if (usage === 'decrypt' && key.type === 'public') { - throw new TypeError( - 'CryptoKey or KeyObject instances for asymmetric algorithm decryption must be of type "private"', - ) - } -} - -export default checkKeyType diff --git a/dist/deno/lib/check_p2s.ts b/dist/deno/lib/check_p2s.ts deleted file mode 100644 index 53c6d9c85f..0000000000 --- a/dist/deno/lib/check_p2s.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { JWEInvalid } from '../util/errors.ts' - -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/dist/deno/lib/decrypt_key_management.ts b/dist/deno/lib/decrypt_key_management.ts deleted file mode 100644 index 72628cad96..0000000000 --- a/dist/deno/lib/decrypt_key_management.ts +++ /dev/null @@ -1,128 +0,0 @@ -import type { JWEHeaderParameters, KeyLike } from '../types.d.ts' -import type { JWEKeyManagementHeaderResults } from '../types.i.d.ts' -import { JOSENotSupported, JWEInvalid } from '../util/errors.ts' -import { unwrap as aesKw } from '../runtime/aeskw.ts' -import * as ECDH from '../runtime/ecdhes.ts' -import { decrypt as pbes2Kw } from '../runtime/pbes2kw.ts' -import { decrypt as rsaEs } from '../runtime/rsaes.ts' -import { unwrap as aesGcmKw } from '../runtime/aesgcmkw.ts' -import { decode as base64url } from '../runtime/base64url.ts' -import { bitLengths as cekLengths } from '../lib/cek.ts' -import { parseJwk } from '../jwk/parse.ts' -import checkKeyType from './check_key_type.ts' - -function assertEnryptedKey(encryptedKey: unknown) { - if (!encryptedKey) { - throw new JWEInvalid('JWE Encrypted Key missing') - } -} - -function assertHeaderParameter( - joseHeader: { [propName: string]: unknown }, - parameter: string, - name: string, -) { - if (joseHeader[parameter] === undefined) { - throw new JWEInvalid(`JOSE Header ${name} (${parameter}) missing`) - } -} - -async function decryptKeyManagement( - alg: string, - key: KeyLike, - encryptedKey: Uint8Array | undefined, - joseHeader: JWEKeyManagementHeaderResults & JWEHeaderParameters, -): Promise { - checkKeyType(alg, key, 'decrypt') - - 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') - } - 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-ES with the provided key is not allowed or not supported by your javascript runtime', - ) - } - const epk = await parseJwk(joseHeader.epk!, alg) - let partyUInfo!: Uint8Array - let partyVInfo!: Uint8Array - if (joseHeader.apu !== undefined) partyUInfo = base64url(joseHeader.apu) - if (joseHeader.apv !== undefined) partyVInfo = base64url(joseHeader.apv) - const sharedSecret = await ECDH.deriveKey( - epk, - key, - alg === 'ECDH-ES' ? joseHeader.enc! : alg, - parseInt(alg.substr(-5, 3), 10) || cekLengths.get(joseHeader.enc!), - 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('unsupported or invalid "alg" (JWE Algorithm) header value') - } - } -} - -export default decryptKeyManagement diff --git a/dist/deno/lib/encrypt_key_management.ts b/dist/deno/lib/encrypt_key_management.ts deleted file mode 100644 index 572c9c2efb..0000000000 --- a/dist/deno/lib/encrypt_key_management.ts +++ /dev/null @@ -1,121 +0,0 @@ -import type { KeyLike, JWEKeyManagementHeaderParameters } from '../types.d.ts' -import type { JWEKeyManagementHeaderResults } from '../types.i.d.ts' -import cekFactory, { bitLengths as cekLengths } from '../lib/cek.ts' -import { JOSENotSupported } from '../util/errors.ts' -import random from '../runtime/random.ts' -import { wrap as aesKw } from '../runtime/aeskw.ts' -import * as ECDH from '../runtime/ecdhes.ts' -import { encrypt as pbes2Kw } from '../runtime/pbes2kw.ts' -import { encrypt as rsaEs } from '../runtime/rsaes.ts' -import { wrap as aesGcmKw } from '../runtime/aesgcmkw.ts' -import { encode as base64url } from '../runtime/base64url.ts' -import { fromKeyLike } from '../jwk/from_key_like.ts' -import checkKeyType from './check_key_type.ts' - -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 - - checkKeyType(alg, key, 'encrypt') - - 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-ES with the provided key is not allowed or not supported by your javascript runtime', - ) - } - const { apu, apv } = providedParameters - let { epk: ephemeralKey } = providedParameters - ephemeralKey ||= await ECDH.generateEpk(key) - const { x, y, crv, kty } = await fromKeyLike(ephemeralKey) - const sharedSecret = await ECDH.deriveKey( - key, - ephemeralKey, - alg === 'ECDH-ES' ? enc : alg, - parseInt(alg.substr(-5, 3), 10) || cekLengths.get(enc), - apu, - apv, - ) - parameters = { epk: { x, y, crv, kty } } - 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 || 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 || 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 || 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 || generateCek(enc) - encryptedKey = await aesKw(alg, key, cek) - break - } - case 'A128GCMKW': - case 'A192GCMKW': - case 'A256GCMKW': { - // Key Wrapping (AES GCM KW) - cek = providedCek || generateCek(enc) - const { iv } = providedParameters - ;({ encryptedKey, ...parameters } = await aesGcmKw(alg, key, cek, iv)) - break - } - default: { - throw new JOSENotSupported('unsupported or invalid "alg" (JWE Algorithm) header value') - } - } - - return { cek, encryptedKey, parameters } -} - -export default encryptKeyManagement diff --git a/dist/deno/lib/epoch.ts b/dist/deno/lib/epoch.ts deleted file mode 100644 index 616795a52e..0000000000 --- a/dist/deno/lib/epoch.ts +++ /dev/null @@ -1 +0,0 @@ -export default (date: Date) => Math.floor(date.getTime() / 1000) diff --git a/dist/deno/lib/is_disjoint.ts b/dist/deno/lib/is_disjoint.ts deleted file mode 100644 index c260352e76..0000000000 --- a/dist/deno/lib/is_disjoint.ts +++ /dev/null @@ -1,26 +0,0 @@ -const isDisjoint = (...headers: Array) => { - const sources = headers.filter(Boolean) - - 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/dist/deno/lib/is_object.ts b/dist/deno/lib/is_object.ts deleted file mode 100644 index f5afee9b47..0000000000 --- a/dist/deno/lib/is_object.ts +++ /dev/null @@ -1,17 +0,0 @@ -function isObjectLike(value: unknown) { - return typeof value === 'object' && value !== null -} - -export default function isObject(input: unknown): boolean { - if (!isObjectLike(input) || Object.prototype.toString.call(input) !== '[object Object]') { - return false - } - if (Object.getPrototypeOf(input) === null) { - return true - } - let proto = input - while (Object.getPrototypeOf(proto) !== null) { - proto = Object.getPrototypeOf(proto) - } - return Object.getPrototypeOf(input) === proto -} diff --git a/dist/deno/lib/iv.ts b/dist/deno/lib/iv.ts deleted file mode 100644 index 11dc881fb0..0000000000 --- a/dist/deno/lib/iv.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { JOSENotSupported } from '../util/errors.ts' - -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) => Uint8Array) => - (alg: string): Uint8Array => { - 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/dist/deno/lib/jwt_claims_set.ts b/dist/deno/lib/jwt_claims_set.ts deleted file mode 100644 index 68b2164078..0000000000 --- a/dist/deno/lib/jwt_claims_set.ts +++ /dev/null @@ -1,148 +0,0 @@ -import type { - JWTPayload, - JWTClaimVerificationOptions, - JWEHeaderParameters, - JWSHeaderParameters, -} from '../types.d.ts' -import { JWTClaimValidationFailed, JWTExpired, JWTInvalid } from '../util/errors.ts' -import { decoder } from './buffer_utils.ts' -import epoch from './epoch.ts' -import secs from './secs.ts' -import isObject from './is_object.ts' - -const normalizeTyp = (value: string) => value.toLowerCase().replace(/^application\//, '') - -const checkAudiencePresence = (audPayload: unknown, audOption: unknown[]) => { - if (typeof audPayload === 'string') { - return audOption.includes(audPayload) - } - - if (Array.isArray(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))) - } - - return false -} - -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!: { [propName: string]: unknown } - try { - payload = JSON.parse(decoder.decode(encodedPayload)) - } catch { - // - } - - if (!isObject(payload)) { - throw new JWTInvalid('JWT Claims Set must be a top-level JSON object') - } - - const { issuer } = options - if (issuer && !((Array.isArray(issuer) ? 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 (payload.iat !== undefined || options.maxTokenAge) { - if (typeof payload.iat !== 'number') { - throw new JWTClaimValidationFailed('"iat" claim must be a number', 'iat', 'invalid') - } - if (payload.exp === undefined && payload.iat > now + tolerance) { - throw new JWTClaimValidationFailed( - '"iat" claim timestamp check failed (it should be in the past)', - 'iat', - 'check_failed', - ) - } - } - - if (payload.nbf !== undefined) { - 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 (payload.exp !== undefined) { - 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/dist/deno/lib/jwt_producer.ts b/dist/deno/lib/jwt_producer.ts deleted file mode 100644 index 44f12657be..0000000000 --- a/dist/deno/lib/jwt_producer.ts +++ /dev/null @@ -1,108 +0,0 @@ -import type { JWTPayload } from '../types.d.ts' -import epoch from './epoch.ts' -import isObject from './is_object.ts' -import secs from './secs.ts' - -/** - * 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/dist/deno/lib/secs.ts b/dist/deno/lib/secs.ts deleted file mode 100644 index 8d9f07f7de..0000000000 --- a/dist/deno/lib/secs.ts +++ /dev/null @@ -1,51 +0,0 @@ -const minute = 60 -const hour = minute * 60 -const day = hour * 24 -const week = day * 7 -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 - -export default (str: string): number => { - const matched = REGEX.exec(str) - - if (!matched) { - throw new TypeError('Invalid time period format') - } - - const value = parseFloat(matched[1]) - const unit = matched[2].toLowerCase() - - switch (unit) { - case 'sec': - case 'secs': - case 'second': - case 'seconds': - case 's': - return Math.round(value) - case 'minute': - case 'minutes': - case 'min': - case 'mins': - case 'm': - return Math.round(value * minute) - case 'hour': - case 'hours': - case 'hr': - case 'hrs': - case 'h': - return Math.round(value * hour) - case 'day': - case 'days': - case 'd': - return Math.round(value * day) - case 'week': - case 'weeks': - case 'w': - return Math.round(value * week) - // years matched - default: - return Math.round(value * year) - } -} diff --git a/dist/deno/lib/validate_algorithms.ts b/dist/deno/lib/validate_algorithms.ts deleted file mode 100644 index 870efaa6ef..0000000000 --- a/dist/deno/lib/validate_algorithms.ts +++ /dev/null @@ -1,16 +0,0 @@ -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/dist/deno/lib/validate_crit.ts b/dist/deno/lib/validate_crit.ts deleted file mode 100644 index d5ea76dc55..0000000000 --- a/dist/deno/lib/validate_crit.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { JOSENotSupported, JWEInvalid, JWSInvalid } from '../util/errors.ts' - -interface CritCheckHeader { - b64?: boolean - crit?: string[] - [propName: string]: unknown -} - -function validateCrit( - Err: typeof JWEInvalid | typeof JWSInvalid, - recognizedDefault: Map, - recognizedOption: { [propName: string]: boolean } | undefined, - protectedHeader: CritCheckHeader, - joseHeader: CritCheckHeader, -) { - if (joseHeader.crit !== undefined && protectedHeader.crit === undefined) { - throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected') - } - - if (!protectedHeader || protectedHeader.crit === undefined) { - return new Set() - } - - if ( - !Array.isArray(protectedHeader.crit) || - protectedHeader.crit.length === 0 || - protectedHeader.crit.some((input: string) => typeof input !== 'string' || input.length === 0) - ) { - throw new Err( - '"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present', - ) - } - - let recognized: Map - if (recognizedOption !== undefined) { - recognized = new Map([...Object.entries(recognizedOption), ...recognizedDefault.entries()]) - } else { - recognized = recognizedDefault - } - - for (const parameter of protectedHeader.crit) { - if (!recognized.has(parameter)) { - throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`) - } - - if (joseHeader[parameter] === undefined) { - throw new Err(`Extension Header Parameter "${parameter}" is missing`) - } else if (recognized.get(parameter) && protectedHeader[parameter] === undefined) { - throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`) - } - } - - return new Set(protectedHeader.crit) -} - -export default validateCrit diff --git a/dist/deno/runtime/aesgcmkw.ts b/dist/deno/runtime/aesgcmkw.ts deleted file mode 100644 index 159c94e3a2..0000000000 --- a/dist/deno/runtime/aesgcmkw.ts +++ /dev/null @@ -1,39 +0,0 @@ -import type { AesGcmKwUnwrapFunction, AesGcmKwWrapFunction } from './interfaces.d.ts' -import encrypt from './encrypt.ts' -import decrypt from './decrypt.ts' -import ivFactory from '../lib/iv.ts' -import random from './random.ts' -import { encode as base64url } from './base64url.ts' - -const generateIv = ivFactory(random) - -export const wrap: AesGcmKwWrapFunction = async ( - alg: string, - key: unknown, - cek: Uint8Array, - iv?: Uint8Array, -) => { - const jweAlgorithm = alg.substr(0, 7) - iv ||= generateIv(jweAlgorithm) - - const { ciphertext: encryptedKey, tag } = await encrypt( - jweAlgorithm, - cek, - key, - iv, - new Uint8Array(0), - ) - - return { encryptedKey, iv: base64url(iv), tag: base64url(tag) } -} - -export const unwrap: AesGcmKwUnwrapFunction = async ( - alg: string, - key: unknown, - encryptedKey: Uint8Array, - iv: Uint8Array, - tag: Uint8Array, -) => { - const jweAlgorithm = alg.substr(0, 7) - return decrypt(jweAlgorithm, key, encryptedKey, iv, tag, new Uint8Array(0)) -} diff --git a/dist/deno/runtime/aeskw.ts b/dist/deno/runtime/aeskw.ts deleted file mode 100644 index dad57810c0..0000000000 --- a/dist/deno/runtime/aeskw.ts +++ /dev/null @@ -1,56 +0,0 @@ -import type { AesKwUnwrapFunction, AesKwWrapFunction } from './interfaces.d.ts' -import bogusWebCrypto from './bogus.ts' -import crypto, { isCryptoKey } from './webcrypto.ts' -import invalidKeyInput from './invalid_key_input.ts' - -function checkKeySize(key: CryptoKey, alg: string) { - // @ts-ignore - if ((key.algorithm).length !== parseInt(alg.substr(1, 3), 10)) { - throw new TypeError(`invalid key size for alg: ${alg}`) - } -} - -function getCryptoKey(key: unknown, usage: KeyUsage) { - if (isCryptoKey(key)) { - return key - } - - if (key instanceof Uint8Array) { - return crypto.subtle.importKey('raw', key, 'AES-KW', true, [usage]) - } - - throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'Uint8Array')) -} - -export const wrap: AesKwWrapFunction = async (alg: string, key: unknown, cek: Uint8Array) => { - const cryptoKey = await getCryptoKey(key, 'wrapKey') - - 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) - - // @ts-ignore - return new Uint8Array(await crypto.subtle.wrapKey('raw', cryptoKeyCek, cryptoKey, 'AES-KW')) -} - -export const unwrap: AesKwUnwrapFunction = async ( - alg: string, - key: unknown, - encryptedKey: Uint8Array, -) => { - const cryptoKey = await getCryptoKey(key, 'unwrapKey') - - checkKeySize(cryptoKey, alg) - - // @ts-ignore - const cryptoKeyCek = await crypto.subtle.unwrapKey( - 'raw', - encryptedKey, - cryptoKey, - 'AES-KW', - ...bogusWebCrypto, - ) - - return new Uint8Array(await crypto.subtle.exportKey('raw', cryptoKeyCek)) -} diff --git a/dist/deno/runtime/base64url.ts b/dist/deno/runtime/base64url.ts deleted file mode 100644 index 9bc611a646..0000000000 --- a/dist/deno/runtime/base64url.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { encoder, decoder } from '../lib/buffer_utils.ts' -import globalThis from './global.ts' - -export const encode = (input: Uint8Array | string) => { - let unencoded = input - if (typeof unencoded === 'string') { - unencoded = encoder.encode(unencoded) - } - const CHUNK_SIZE = 0x8000 - const arr = [] - for (let i = 0; i < unencoded.length; i += CHUNK_SIZE) { - // @ts-expect-error - arr.push(String.fromCharCode.apply(null, unencoded.subarray(i, i + CHUNK_SIZE))) - } - const base64string = globalThis.btoa(arr.join('')) - return base64string.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_') -} - -export const decode = (input: Uint8Array | string) => { - let encoded = input - if (encoded instanceof Uint8Array) { - encoded = decoder.decode(encoded) - } - encoded = encoded.replace(/-/g, '+').replace(/_/g, '/').replace(/\s/g, '') - try { - return new Uint8Array( - globalThis - .atob(encoded) - .split('') - .map((c) => c.charCodeAt(0)), - ) - } catch { - throw new TypeError('The input to be decoded is not correctly encoded.') - } -} diff --git a/dist/deno/runtime/bogus.ts b/dist/deno/runtime/bogus.ts deleted file mode 100644 index cbae5153ff..0000000000 --- a/dist/deno/runtime/bogus.ts +++ /dev/null @@ -1,7 +0,0 @@ -const bogusWebCrypto: [HmacImportParams, boolean, KeyUsage[]] = [ - { hash: { name: 'SHA-256' }, name: 'HMAC' }, - true, - ['sign'], -] - -export default bogusWebCrypto diff --git a/dist/deno/runtime/check_cek_length.ts b/dist/deno/runtime/check_cek_length.ts deleted file mode 100644 index 6311065323..0000000000 --- a/dist/deno/runtime/check_cek_length.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { JWEInvalid, JOSENotSupported } from '../util/errors.ts' -import { isCryptoKey } from './webcrypto.ts' - -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 not supported 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 (isCryptoKey(cek)) { - // @ts-ignore - const { length } = cek.algorithm - if (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/dist/deno/runtime/check_key_length.ts b/dist/deno/runtime/check_key_length.ts deleted file mode 100644 index c174fe2717..0000000000 --- a/dist/deno/runtime/check_key_length.ts +++ /dev/null @@ -1,18 +0,0 @@ -export default (alg: string, key: CryptoKey) => { - if (alg.startsWith('HS')) { - const bitlen = parseInt(alg.substr(-3), 10) - // @ts-ignore - const { length } = key.algorithm - if (typeof length !== 'number' || length < bitlen) { - throw new TypeError(`${alg} requires symmetric keys to be ${bitlen} bits or larger`) - } - } - - if (alg.startsWith('RS') || alg.startsWith('PS')) { - // @ts-ignore - const { modulusLength } = key.algorithm - if (typeof modulusLength !== 'number' || modulusLength < 2048) { - throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`) - } - } -} diff --git a/dist/deno/runtime/decrypt.ts b/dist/deno/runtime/decrypt.ts deleted file mode 100644 index 2976830f0b..0000000000 --- a/dist/deno/runtime/decrypt.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { concat, uint64be } from '../lib/buffer_utils.ts' - -import type { DecryptFunction } from './interfaces.d.ts' -import checkIvLength from '../lib/check_iv_length.ts' -import checkCekLength from './check_cek_length.ts' -import timingSafeEqual from './timing_safe_equal.ts' -import { JOSENotSupported, JWEDecryptionFailed } from '../util/errors.ts' -import crypto, { isCryptoKey } from './webcrypto.ts' -import invalidKeyInput from './invalid_key_input.ts' - -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.subarray(keySize >> 3), - 'AES-CBC', - false, - ['decrypt'], - ) - const macKey = await crypto.subtle.importKey( - 'raw', - cek.subarray(0, keySize >> 3), - { - hash: { name: `SHA-${keySize << 1}` }, - name: 'HMAC', - }, - false, - ['sign'], - ) - - 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 (!macCheckPassed) { - throw new JWEDecryptionFailed() - } - - let plaintext!: Uint8Array - try { - plaintext = new Uint8Array( - // @ts-ignore - await crypto.subtle.decrypt({ iv, name: 'AES-CBC' }, encKey, ciphertext), - ) - } catch { - // - } - if (!plaintext) { - 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( - // @ts-ignore - await crypto.subtle.decrypt( - { - additionalData: aad, - iv, - name: 'AES-GCM', - tagLength: 128, - }, - encKey, - concat(ciphertext, tag), - ), - ) - } catch { - throw new JWEDecryptionFailed() - } -} - -const decrypt: DecryptFunction = async ( - enc: string, - cek: unknown, - ciphertext: Uint8Array, - iv: Uint8Array, - tag: Uint8Array, - aad: Uint8Array, -) => { - if (!isCryptoKey(cek) && !(cek instanceof Uint8Array)) { - throw new TypeError(invalidKeyInput(cek, 'CryptoKey', 'Uint8Array')) - } - - checkCekLength(enc, cek) - checkIvLength(enc, iv) - - switch (enc) { - case 'A128CBC-HS256': - case 'A192CBC-HS384': - case 'A256CBC-HS512': - return cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) - case 'A128GCM': - case 'A192GCM': - case 'A256GCM': - return gcmDecrypt(cek, ciphertext, iv, tag, aad) - default: - throw new JOSENotSupported('unsupported JWE Content Encryption Algorithm') - } -} - -export default decrypt diff --git a/dist/deno/runtime/digest.ts b/dist/deno/runtime/digest.ts deleted file mode 100644 index 46a3438375..0000000000 --- a/dist/deno/runtime/digest.ts +++ /dev/null @@ -1,11 +0,0 @@ -import crypto from './webcrypto.ts' -import type { DigestFunction } from './interfaces.d.ts' - -const digest: DigestFunction = async ( - algorithm: 'sha256' | 'sha384' | 'sha512', - data: Uint8Array, -): Promise => { - const subtleDigest = `SHA-${algorithm.substr(-3)}` - return new Uint8Array(await crypto.subtle.digest(subtleDigest, data)) -} -export default digest diff --git a/dist/deno/runtime/ecdhes.ts b/dist/deno/runtime/ecdhes.ts deleted file mode 100644 index 6a5896ced5..0000000000 --- a/dist/deno/runtime/ecdhes.ts +++ /dev/null @@ -1,73 +0,0 @@ -import type { - EcdhAllowedFunction, - EcdhESDeriveKeyFunction, - GenerateEpkFunction, -} from './interfaces.d.ts' -import { encoder, concat, uint32be, lengthAndInput, concatKdf } from '../lib/buffer_utils.ts' -import crypto, { isCryptoKey } from './webcrypto.ts' -import digest from './digest.ts' -import invalidKeyInput from './invalid_key_input.ts' - -export const deriveKey: EcdhESDeriveKeyFunction = async ( - publicKey: unknown, - privateKey: unknown, - algorithm: string, - keyLength: number, - apu: Uint8Array = new Uint8Array(0), - apv: Uint8Array = new Uint8Array(0), -) => { - if (!isCryptoKey(publicKey)) { - throw new TypeError(invalidKeyInput(publicKey, 'CryptoKey')) - } - if (!isCryptoKey(privateKey)) { - throw new TypeError(invalidKeyInput(privateKey, 'CryptoKey')) - } - - 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( - // @ts-ignore - await crypto.subtle.deriveBits( - { - name: 'ECDH', - public: publicKey, - }, - privateKey, - // @ts-ignore - Math.ceil(parseInt((privateKey.algorithm).namedCurve.substr(-3), 10) / 8) << - 3, - ), - ) - - return concatKdf(digest, sharedSecret, keyLength, value) -} - -export const generateEpk: GenerateEpkFunction = async (key: unknown) => { - if (!isCryptoKey(key)) { - throw new TypeError(invalidKeyInput(key, 'CryptoKey')) - } - - return (<{ publicKey: CryptoKey; privateKey: CryptoKey }>await crypto.subtle.generateKey( - // @ts-ignore - { name: 'ECDH', namedCurve: (key.algorithm).namedCurve }, - true, - ['deriveBits'], - )).privateKey -} - -export const ecdhAllowed: EcdhAllowedFunction = (key: unknown) => { - if (!isCryptoKey(key)) { - throw new TypeError(invalidKeyInput(key, 'CryptoKey')) - } - // @ts-ignore - return ['P-256', 'P-384', 'P-521'].includes((key.algorithm).namedCurve) -} diff --git a/dist/deno/runtime/encrypt.ts b/dist/deno/runtime/encrypt.ts deleted file mode 100644 index ba890406e2..0000000000 --- a/dist/deno/runtime/encrypt.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { concat, uint64be } from '../lib/buffer_utils.ts' -import type { EncryptFunction } from './interfaces.d.ts' -import checkIvLength from '../lib/check_iv_length.ts' -import checkCekLength from './check_cek_length.ts' -import crypto, { isCryptoKey } from './webcrypto.ts' -import invalidKeyInput from './invalid_key_input.ts' -import { JOSENotSupported } from '../util/errors.ts' - -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.subarray(keySize >> 3), - 'AES-CBC', - false, - ['encrypt'], - ) - const macKey = await crypto.subtle.importKey( - 'raw', - cek.subarray(0, keySize >> 3), - { - hash: { name: `SHA-${keySize << 1}` }, - name: 'HMAC', - }, - false, - ['sign'], - ) - - const ciphertext = new Uint8Array( - // @ts-ignore - 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( - // @ts-ignore - 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: unknown, - iv: Uint8Array, - aad: Uint8Array, -) => { - if (!isCryptoKey(cek) && !(cek instanceof Uint8Array)) { - throw new TypeError(invalidKeyInput(cek, 'CryptoKey', 'Uint8Array')) - } - - checkCekLength(enc, cek) - checkIvLength(enc, iv) - - switch (enc) { - case 'A128CBC-HS256': - case 'A192CBC-HS384': - case 'A256CBC-HS512': - return cbcEncrypt(enc, plaintext, cek, iv, aad) - case 'A128GCM': - case 'A192GCM': - case 'A256GCM': - return gcmEncrypt(plaintext, cek, iv, aad) - default: - throw new JOSENotSupported('unsupported JWE Content Encryption Algorithm') - } -} - -export default encrypt diff --git a/dist/deno/runtime/fetch_jwks.ts b/dist/deno/runtime/fetch_jwks.ts deleted file mode 100644 index 88c8fabf20..0000000000 --- a/dist/deno/runtime/fetch_jwks.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { FetchFunction } from './interfaces.d.ts' -import { JOSEError } from '../util/errors.ts' -import globalThis from './global.ts' - -const fetchJwks: FetchFunction = async (url: URL, timeout: number) => { - let controller!: AbortController - if (typeof AbortController === 'function') { - controller = new AbortController() - setTimeout(() => controller.abort(), timeout) - } - - const response = await globalThis.fetch(url.href, { - signal: controller ? controller.signal : undefined, - redirect: 'manual', - method: 'GET', - // do not pass referrerPolicy, credentials, and mode when running - // in Cloudflare Workers environment - // @ts-expect-error - ...(typeof globalThis.WebSocketPair === 'undefined' - ? { - referrerPolicy: 'no-referrer', - credentials: 'omit', - mode: 'cors', - } - : undefined), - }) - - if (response.status !== 200) { - throw new JOSEError('Expected 200 OK from the JSON Web Key Set HTTP response') - } - - try { - return await response.json() - } catch { - throw new JOSEError('Failed to parse the JSON Web Key Set HTTP response as JSON') - } -} -export default fetchJwks diff --git a/dist/deno/runtime/generate.ts b/dist/deno/runtime/generate.ts deleted file mode 100644 index 90893ae7ae..0000000000 --- a/dist/deno/runtime/generate.ts +++ /dev/null @@ -1,126 +0,0 @@ -import crypto from './webcrypto.ts' -import { JOSENotSupported } from '../util/errors.ts' -import random from './random.ts' -import type { GenerateKeyPairOptions } from '../util/generate_key_pair.ts' -import type { GenerateSecretOptions } from '../util/generate_secret.ts' - -export async function generateSecret(alg: string, options?: GenerateSecretOptions) { - let length: number - // @ts-ignore - 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: { name: `SHA-${length}` }, 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, options?.extractable ?? false, keyUsages)) - ) -} - -function getModulusLengthOption(options?: GenerateKeyPairOptions) { - const modulusLength = options?.modulusLength ?? 2048 - if (typeof modulusLength !== 'number' || modulusLength < 2048) { - throw new JOSENotSupported( - 'Invalid or unsupported modulusLength option provided, 2048 bits or larger keys must be used', - ) - } - return modulusLength -} - -export async function generateKeyPair(alg: string, options?: GenerateKeyPairOptions) { - let algorithm: RsaHashedKeyGenParams | EcKeyGenParams - let keyUsages: KeyUsage[] - - switch (alg) { - case 'PS256': - case 'PS384': - case 'PS512': - algorithm = { - name: 'RSA-PSS', - hash: { name: `SHA-${alg.substr(-3)}` }, - publicExponent: new Uint8Array([0x01, 0x00, 0x01]), - modulusLength: getModulusLengthOption(options), - } - keyUsages = ['sign', 'verify'] - break - case 'RS256': - case 'RS384': - case 'RS512': - algorithm = { - name: 'RSASSA-PKCS1-v1_5', - hash: { name: `SHA-${alg.substr(-3)}` }, - publicExponent: new Uint8Array([0x01, 0x00, 0x01]), - modulusLength: getModulusLengthOption(options), - } - keyUsages = ['sign', 'verify'] - break - case 'RSA-OAEP': - case 'RSA-OAEP-256': - case 'RSA-OAEP-384': - case 'RSA-OAEP-512': - algorithm = { - name: 'RSA-OAEP', - hash: { name: `SHA-${parseInt(alg.substr(-3), 10) || 1}` }, - publicExponent: new Uint8Array([0x01, 0x00, 0x01]), - modulusLength: getModulusLengthOption(options), - } - 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') - } - - return >( - crypto.subtle.generateKey(algorithm, options?.extractable ?? false, keyUsages) - ) -} diff --git a/dist/deno/runtime/get_sign_verify_key.ts b/dist/deno/runtime/get_sign_verify_key.ts deleted file mode 100644 index 74cfeb74a4..0000000000 --- a/dist/deno/runtime/get_sign_verify_key.ts +++ /dev/null @@ -1,23 +0,0 @@ -import crypto, { isCryptoKey } from './webcrypto.ts' -import invalidKeyInput from './invalid_key_input.ts' - -export default function getCryptoKey(alg: string, key: unknown, usage: KeyUsage) { - if (isCryptoKey(key)) { - return key - } - - if (key instanceof Uint8Array) { - if (!alg.startsWith('HS')) { - throw new TypeError(invalidKeyInput(key, 'CryptoKey')) - } - return crypto.subtle.importKey( - 'raw', - key, - { hash: { name: `SHA-${alg.substr(-3)}` }, name: 'HMAC' }, - false, - [usage], - ) - } - - throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'Uint8Array')) -} diff --git a/dist/deno/runtime/global.ts b/dist/deno/runtime/global.ts deleted file mode 100644 index ba85627857..0000000000 --- a/dist/deno/runtime/global.ts +++ /dev/null @@ -1,8 +0,0 @@ -function getGlobal() { - if (typeof globalThis !== 'undefined') return globalThis - if (typeof self !== 'undefined') return self - if (typeof window !== 'undefined') return window - throw new Error('unable to locate global object') -} - -export default getGlobal() diff --git a/dist/deno/runtime/interfaces.d.ts b/dist/deno/runtime/interfaces.d.ts deleted file mode 100644 index 3be3b22825..0000000000 --- a/dist/deno/runtime/interfaces.d.ts +++ /dev/null @@ -1,100 +0,0 @@ -import type { JWK, KeyLike } from '../types.d.ts' -import type { AsyncOrSync } from '../types.i.d.ts' - -export interface TimingSafeEqual { - (a: Uint8Array, b: Uint8Array): boolean -} -export interface SignFunction { - (alg: string, key: unknown, data: Uint8Array): Promise -} -export interface VerifyFunction { - (alg: string, key: unknown, signature: Uint8Array, data: Uint8Array): Promise -} -export interface AesKwWrapFunction { - (alg: string, key: unknown, cek: Uint8Array): Promise -} -export interface AesKwUnwrapFunction { - (alg: string, key: unknown, encryptedKey: Uint8Array): Promise -} -export interface RsaEsEncryptFunction { - (alg: string, key: unknown, cek: Uint8Array): Promise -} -export interface RsaEsDecryptFunction { - (alg: string, key: unknown, encryptedKey: Uint8Array): Promise -} -export interface AesGcmKwWrapFunction { - (alg: string, key: unknown, cek: Uint8Array, iv?: Uint8Array): Promise<{ - encryptedKey: Uint8Array - iv: string - tag: string - }> -} -export interface AesGcmKwUnwrapFunction { - ( - alg: string, - key: unknown, - encryptedKey: Uint8Array, - iv: Uint8Array, - tag: Uint8Array, - ): Promise -} -export interface Pbes2KWEncryptFunction { - (alg: string, key: unknown, cek: Uint8Array, p2c?: number, p2s?: Uint8Array): Promise<{ - encryptedKey: Uint8Array - p2c: number - p2s: string - }> -} -export interface Pbes2KWDecryptFunction { - ( - alg: string, - key: unknown, - encryptedKey: Uint8Array, - p2c: number, - p2s: Uint8Array, - ): Promise -} -export interface EcdhESDeriveKeyFunction { - ( - publicKey: unknown, - privateKey: unknown, - enc: string, - keyLength: number, - apu?: Uint8Array, - apv?: Uint8Array, - ): Promise -} -export interface EcdhAllowedFunction { - (key: unknown): boolean -} -export interface GenerateEpkFunction { - (key: unknown): Promise -} -export interface EncryptFunction { - (enc: string, plaintext: Uint8Array, cek: unknown, iv: Uint8Array, aad: Uint8Array): Promise<{ - ciphertext: Uint8Array - tag: Uint8Array - }> -} -export interface DecryptFunction { - ( - enc: string, - cek: unknown, - ciphertext: Uint8Array, - iv: Uint8Array, - tag: Uint8Array, - additionalData: Uint8Array, - ): Promise -} -export interface FetchFunction { - (url: URL, timeout: number, options?: any): Promise<{ [propName: string]: unknown }> -} -export interface DigestFunction { - (digest: 'sha256' | 'sha384' | 'sha512', data: Uint8Array): AsyncOrSync -} -export interface JWKParseFunction { - (jwk: JWK): AsyncOrSync -} -export interface JWKConvertFunction { - (key: unknown): AsyncOrSync -} diff --git a/dist/deno/runtime/invalid_key_input.ts b/dist/deno/runtime/invalid_key_input.ts deleted file mode 100644 index dfcb74c9b8..0000000000 --- a/dist/deno/runtime/invalid_key_input.ts +++ /dev/null @@ -1,24 +0,0 @@ -export default (actual: unknown, ...types: string[]) => { - let msg = 'Key must be ' - - if (types.length > 2) { - const last = types.pop() - msg += `one of type ${types.join(', ')}, or ${last}.` - } else if (types.length === 2) { - msg += `one of type ${types[0]} or ${types[1]}.` - } else { - msg += `of type ${types[0]}.` - } - - if (actual == null) { - msg += ` Received ${actual}` - } else if (typeof actual === 'function' && actual.name) { - msg += ` Received function ${actual.name}` - } else if (typeof actual === 'object' && actual != null) { - if (actual.constructor && actual.constructor.name) { - msg += ` Received an instance of ${actual.constructor.name}` - } - } - - return msg -} diff --git a/dist/deno/runtime/jwk_to_key.ts b/dist/deno/runtime/jwk_to_key.ts deleted file mode 100644 index 8c9db9a9cd..0000000000 --- a/dist/deno/runtime/jwk_to_key.ts +++ /dev/null @@ -1,133 +0,0 @@ -import crypto from './webcrypto.ts' -import type { JWKParseFunction } from './interfaces.d.ts' -import { JOSENotSupported } from '../util/errors.ts' -import type { JWK } from '../types.d.ts' -import { decode as base64url } from './base64url.ts' - -function subtleMapping(jwk: JWK): { - // @ts-ignore - algorithm: RsaHashedImportParams | EcKeyAlgorithm | Algorithm - keyUsages: KeyUsage[] -} { - // @ts-ignore - 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: { name: `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: { name: `SHA-${jwk.alg.substr(-3)}` } } - keyUsages = jwk.d ? ['sign'] : ['verify'] - break - case 'RS256': - case 'RS384': - case 'RS512': - algorithm = { name: 'RSASSA-PKCS1-v1_5', hash: { name: `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: { name: `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 } -} - -const parse: JWKParseFunction = async (jwk: JWK): Promise => { - const { algorithm, keyUsages } = subtleMapping(jwk) - // @ts-ignore - const rest: [RsaHashedImportParams | EcKeyAlgorithm | Algorithm, boolean, KeyUsage[]] = [ - algorithm, - jwk.ext ?? false, - jwk.key_ops ?? keyUsages, - ] - - if (algorithm.name === 'PBKDF2') { - return crypto.subtle.importKey('raw', base64url(jwk.k!), ...rest) - } - - const keyData: JWK = { ...jwk } - delete keyData.alg - return crypto.subtle.importKey( - // @ts-ignore - 'jwk', - keyData, - ...rest, - ) -} -export default parse diff --git a/dist/deno/runtime/key_to_jwk.ts b/dist/deno/runtime/key_to_jwk.ts deleted file mode 100644 index 314f9b8a89..0000000000 --- a/dist/deno/runtime/key_to_jwk.ts +++ /dev/null @@ -1,26 +0,0 @@ -import crypto, { isCryptoKey } from './webcrypto.ts' -import type { JWKConvertFunction } from './interfaces.d.ts' -import type { JWK } from '../types.d.ts' -import invalidKeyInput from './invalid_key_input.ts' -import { encode as base64url } from './base64url.ts' - -const keyToJWK: JWKConvertFunction = async (key: unknown): Promise => { - if (key instanceof Uint8Array) { - return { - kty: 'oct', - k: base64url(key), - } - } - if (!isCryptoKey(key)) { - throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'Uint8Array')) - } - if (!key.extractable) { - throw new TypeError('non-extractable CryptoKey cannot be exported as a JWK') - } - // @ts-ignore - const { ext, key_ops, alg, use, ...jwk } = await crypto.subtle.exportKey('jwk', key) - - // @ts-ignore - return jwk -} -export default keyToJWK diff --git a/dist/deno/runtime/pbes2kw.ts b/dist/deno/runtime/pbes2kw.ts deleted file mode 100644 index 6288b2a8b9..0000000000 --- a/dist/deno/runtime/pbes2kw.ts +++ /dev/null @@ -1,98 +0,0 @@ -import type { Pbes2KWDecryptFunction, Pbes2KWEncryptFunction } from './interfaces.d.ts' -import random from './random.ts' -import { p2s as concatSalt } from '../lib/buffer_utils.ts' -import { encode as base64url } from './base64url.ts' -import { wrap, unwrap } from './aeskw.ts' -import checkP2s from '../lib/check_p2s.ts' -import crypto, { isCryptoKey } from './webcrypto.ts' -import invalidKeyInput from './invalid_key_input.ts' - -function getCryptoKey(key: unknown) { - if (key instanceof Uint8Array) { - return crypto.subtle.importKey('raw', key, 'PBKDF2', false, ['deriveBits']) - } - - if (isCryptoKey(key)) { - return key - } - - throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'Uint8Array')) -} - -export const encrypt: Pbes2KWEncryptFunction = async ( - alg: string, - key: unknown, - 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) - const subtleAlg = { - hash: { name: `SHA-${alg.substr(8, 3)}` }, - iterations: p2c, - name: 'PBKDF2', - salt, - } - const wrapAlg = { - length: keylen, - name: 'AES-KW', - } - - const cryptoKey = await getCryptoKey(key) - - let derived: CryptoKey | Uint8Array - if (cryptoKey.usages.includes('deriveBits')) { - // @ts-ignore - derived = new Uint8Array(await crypto.subtle.deriveBits(subtleAlg, cryptoKey, keylen)) - } else if (cryptoKey.usages.includes('deriveKey')) { - // @ts-ignore - 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: unknown, - encryptedKey: Uint8Array, - p2c: number, - p2s: Uint8Array, -) => { - checkP2s(p2s) - - const salt = concatSalt(alg, p2s) - const keylen = parseInt(alg.substr(13, 3), 10) - const subtleAlg = { - hash: { name: `SHA-${alg.substr(8, 3)}` }, - iterations: p2c, - name: 'PBKDF2', - salt, - } - const wrapAlg = { - length: keylen, - name: 'AES-KW', - } - - const cryptoKey = await getCryptoKey(key) - - let derived: CryptoKey | Uint8Array - if (cryptoKey.usages.includes('deriveBits')) { - // @ts-ignore - derived = new Uint8Array(await crypto.subtle.deriveBits(subtleAlg, cryptoKey, keylen)) - } else if (cryptoKey.usages.includes('deriveKey')) { - // @ts-ignore - 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/dist/deno/runtime/random.ts b/dist/deno/runtime/random.ts deleted file mode 100644 index 11a0fc450d..0000000000 --- a/dist/deno/runtime/random.ts +++ /dev/null @@ -1,5 +0,0 @@ -import crypto from './webcrypto.ts' - -const random = crypto.getRandomValues.bind(crypto) - -export default random diff --git a/dist/deno/runtime/rsaes.ts b/dist/deno/runtime/rsaes.ts deleted file mode 100644 index 95d11c1888..0000000000 --- a/dist/deno/runtime/rsaes.ts +++ /dev/null @@ -1,64 +0,0 @@ -import type { RsaEsDecryptFunction, RsaEsEncryptFunction } from './interfaces.d.ts' -import subtleAlgorithm from './subtle_rsaes.ts' -import bogusWebCrypto from './bogus.ts' -import crypto, { isCryptoKey } from './webcrypto.ts' -import checkKeyLength from './check_key_length.ts' -import invalidKeyInput from './invalid_key_input.ts' - -export const encrypt: RsaEsEncryptFunction = async (alg: string, key: unknown, cek: Uint8Array) => { - if (!isCryptoKey(key)) { - throw new TypeError(invalidKeyInput(key, 'CryptoKey')) - } - checkKeyLength(alg, key) - - if (key.usages.includes('encrypt')) { - // @ts-ignore - 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( - // @ts-ignore - 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: unknown, - encryptedKey: Uint8Array, -) => { - if (!isCryptoKey(key)) { - throw new TypeError(invalidKeyInput(key, 'CryptoKey')) - } - checkKeyLength(alg, key) - - if (key.usages.includes('decrypt')) { - // @ts-ignore - return new Uint8Array(await crypto.subtle.decrypt(subtleAlgorithm(alg), key, encryptedKey)) - } - - if (key.usages.includes('unwrapKey')) { - // @ts-ignore - 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/dist/deno/runtime/sign.ts b/dist/deno/runtime/sign.ts deleted file mode 100644 index 3302b070a3..0000000000 --- a/dist/deno/runtime/sign.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { SignFunction } from './interfaces.d.ts' -import subtleAlgorithm from './subtle_dsa.ts' -import crypto from './webcrypto.ts' -import checkKeyLength from './check_key_length.ts' -import getSignKey from './get_sign_verify_key.ts' - -const sign: SignFunction = async (alg, key: unknown, data) => { - const cryptoKey = await getSignKey(alg, key, 'sign') - checkKeyLength(alg, cryptoKey) - const signature = await crypto.subtle.sign(subtleAlgorithm(alg), cryptoKey, data) - return new Uint8Array(signature) -} - -export default sign diff --git a/dist/deno/runtime/subtle_dsa.ts b/dist/deno/runtime/subtle_dsa.ts deleted file mode 100644 index 920c2b81c4..0000000000 --- a/dist/deno/runtime/subtle_dsa.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { JOSENotSupported } from '../util/errors.ts' - -export default function subtleDsa(alg: string) { - switch (alg) { - case 'HS256': - return { hash: { name: 'SHA-256' }, name: 'HMAC' } - case 'HS384': - return { hash: { name: 'SHA-384' }, name: 'HMAC' } - case 'HS512': - return { hash: { name: 'SHA-512' }, name: 'HMAC' } - case 'PS256': - return { - hash: { name: 'SHA-256' }, - name: 'RSA-PSS', - saltLength: 256 >> 3, - } - case 'PS384': - return { - hash: { name: 'SHA-384' }, - name: 'RSA-PSS', - saltLength: 384 >> 3, - } - case 'PS512': - return { - hash: { name: 'SHA-512' }, - name: 'RSA-PSS', - saltLength: 512 >> 3, - } - case 'RS256': - return { hash: { name: 'SHA-256' }, name: 'RSASSA-PKCS1-v1_5' } - case 'RS384': - return { hash: { name: 'SHA-384' }, name: 'RSASSA-PKCS1-v1_5' } - case 'RS512': - return { hash: { name: 'SHA-512' }, name: 'RSASSA-PKCS1-v1_5' } - case 'ES256': - return { hash: { name: 'SHA-256' }, name: 'ECDSA', namedCurve: 'P-256' } - case 'ES384': - return { hash: { name: 'SHA-384' }, name: 'ECDSA', namedCurve: 'P-384' } - case 'ES512': - return { hash: { name: 'SHA-512' }, name: 'ECDSA', namedCurve: 'P-521' } - default: - throw new JOSENotSupported( - `alg ${alg} is not supported either by JOSE or your javascript runtime`, - ) - } -} diff --git a/dist/deno/runtime/subtle_rsaes.ts b/dist/deno/runtime/subtle_rsaes.ts deleted file mode 100644 index 16fb3d3c59..0000000000 --- a/dist/deno/runtime/subtle_rsaes.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { JOSENotSupported } from '../util/errors.ts' - -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 not supported either by JOSE or your javascript runtime`, - ) - } -} diff --git a/dist/deno/runtime/timing_safe_equal.ts b/dist/deno/runtime/timing_safe_equal.ts deleted file mode 100644 index 53bc719686..0000000000 --- a/dist/deno/runtime/timing_safe_equal.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { TimingSafeEqual } from './interfaces.d.ts' - -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/dist/deno/runtime/verify.ts b/dist/deno/runtime/verify.ts deleted file mode 100644 index 6b7b893fba..0000000000 --- a/dist/deno/runtime/verify.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { VerifyFunction } from './interfaces.d.ts' -import subtleAlgorithm from './subtle_dsa.ts' -import crypto from './webcrypto.ts' -import checkKeyLength from './check_key_length.ts' -import getVerifyKey from './get_sign_verify_key.ts' - -const verify: VerifyFunction = async (alg, key: unknown, signature, data) => { - const cryptoKey = await getVerifyKey(alg, key, 'verify') - checkKeyLength(alg, cryptoKey) - const algorithm = subtleAlgorithm(alg) - try { - return await crypto.subtle.verify(algorithm, cryptoKey, signature, data) - } catch { - return false - } -} - -export default verify diff --git a/dist/deno/runtime/webcrypto.ts b/dist/deno/runtime/webcrypto.ts deleted file mode 100644 index ab307b954f..0000000000 --- a/dist/deno/runtime/webcrypto.ts +++ /dev/null @@ -1,10 +0,0 @@ -import globalThis from './global.ts' - -export default globalThis.crypto - -export function isCryptoKey(key: unknown): key is CryptoKey { - if (typeof globalThis.CryptoKey === 'undefined') { - return false - } - return key != null && key instanceof globalThis.CryptoKey -} diff --git a/dist/deno/runtime/zlib.ts b/dist/deno/runtime/zlib.ts deleted file mode 100644 index 653d1b419f..0000000000 --- a/dist/deno/runtime/zlib.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { JOSENotSupported } from '../util/errors.ts' -import type { InflateFunction, DeflateFunction } from '../types.d.ts' - -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.', - ) -} -export const deflate: DeflateFunction = async () => { - throw new JOSENotSupported( - 'JWE "zip" (Compression Algorithm) Header Parameter is not supported by your javascript runtime. You need to use the `deflateRaw` encrypt option to provide Deflate Raw implementation.', - ) -} diff --git a/dist/deno/types.d.ts b/dist/deno/types.d.ts deleted file mode 100644 index 68f40ded08..0000000000 --- a/dist/deno/types.d.ts +++ /dev/null @@ -1,691 +0,0 @@ -export type KeyObject = CryptoKey - -/** - * KeyLike are platform-specific references to keying material. - * - * [KeyObject](https://nodejs.org/api/crypto.html#crypto_class_keyobject) is a representation of a - * key/secret available in the Node.js runtime. You can obtain a KeyObject instance e.g. from: - * - * - [crypto.createPublicKey](https://nodejs.org/api/crypto.html#crypto_crypto_createpublickey_key) - * - [crypto.createPrivateKey](https://nodejs.org/api/crypto.html#crypto_crypto_createprivatekey_key) - * - [crypto.createSecretKey](https://nodejs.org/api/crypto.html#crypto_crypto_createsecretkey_key_encoding) - * - [crypto.generateKeyPair](https://nodejs.org/api/crypto.html#crypto_crypto_generatekeypair_type_options_callback) - * - [jose/jwk/parse](../functions/jwk_parse.parseJwk.md#readme) - * - [jose/util/generate_key_pair](../functions/util_generate_key_pair.generateKeyPair.md#readme) - * - [jose/util/generate_secret](../functions/util_generate_secret.generateSecret.md#readme) - * - * [CryptoKey](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey) is a representation of a - * key/secret available in the Browser and Deno runtimes. You can obtain a CryptoKey instance e.g. from: - * - * - [SubtleCrypto.importKey](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey) - * - [SubtleCrypto.generateKey](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey) - * - [jose/jwk/parse](../functions/jwk_parse.parseJwk.md#readme) - * - [jose/util/generate_key_pair](../functions/util_generate_key_pair.generateKeyPair.md#readme) - * - [jose/util/generate_secret](../functions/util_generate_secret.generateSecret.md#readme) - * - * [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. - * In Node.js the [Buffer](https://nodejs.org/api/buffer.html#buffer_buffer) class is a subclass of Uint8Array - * class. `jose` APIs accept plain Buffers wherever Uint8Array are supported as well. - * - * @example (node) Public KeyObject from a PEM public key - * ```js - * import { createPublicKey } from 'crypto' - * - * const publicKey = createPublicKey(pem) - * ``` - * - * @example (node) Private KeyObject from a PEM private key - * ```js - * import { createPrivateKey } from 'crypto' - * - * const privateKey = createPrivateKey(pem) - * ``` - * - * @example (node) Secret KeyObject from hex encoded random bytes - * ```js - * import { createSecretKey } from 'crypto' - * - * const secretKey = createSecretKey(Buffer.from('7f908df6c8bd634f769c073a48986d77677b79bc6aa19b106f976f2db18d38c2', 'hex')) - * ``` - * - * @example (all runtimes) KeyLike from a JSON Web Key (JWK) - * ```js - * import { parseJwk } from 'jose/jwk/parse' - * - * const ecPublicKey = await parseJwk({ - * crv: 'P-256', - * kty: 'EC', - * x: 'ySK38C1jBdLwDsNWKzzBHqKYEE5Cgv-qjWvorUXk9fw', - * y: '_LeQBw07cf5t57Iavn4j-BqJsAD1dpoz8gokd3sBsOo' - * }, 'ES256') - * - * const rsaPublicKey = await parseJwk({ - * kty: 'RSA', - * e: 'AQAB', - * n: '12oBZRhCiZFJLcPg59LkZZ9mdhSMTKAQZYq32k_ti5SBB6jerkh-WzOMAO664r_qyLkqHUSp3u5SbXtseZEpN3XPWGKSxjsy-1JyEFTdLSYe6f9gfrmxkUF_7DTpq0gn6rntP05g2-wFW50YO7mosfdslfrTJYWHFhJALabAeYirYD7-9kqq9ebfFMF4sRRELbv9oi36As6Q9B3Qb5_C1rAzqfao_PCsf9EPsTZsVVVkA5qoIAr47lo1ipfiBPxUCCNSdvkmDTYgvvRm6ZoMjFbvOtgyts55fXKdMWv7I9HMD5HwE9uW839PWA514qhbcIsXEYSFMPMV6fnlsiZvQQ' - * }, 'PS256') - * ``` - */ -export type KeyLike = KeyObject | CryptoKey | Uint8Array - -/** - * 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 - - [propName: string]: unknown -} - -/** - * Generic Interface for consuming operations dynamic key resolution. - * No token components have been verified at the time of this function call. - * - * If you cannot match a key suitable for the token, throw an error instead. - * - * @param protectedHeader JWE or JWS Protected Header. - * @param token The consumed JWE or JWS token. - */ -export interface GetKeyFunction { - (protectedHeader: T, token: T2): Promise -} - -/** - * 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 -} - -/** - * General JWS definition for verify function inputs, allows payload as - * Uint8Array for detached signature validation. - */ -export interface GeneralJWSInput { - /** - * 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 "signatures" member value MUST be an array of JSON objects. - * Each object represents a signature or MAC over the JWS Payload and - * the JWS Protected Header. - */ - signatures: Omit[] -} - -/** - * Flattened JWS definition. Payload is returned as an empty - * string when JWS Unencoded Payload Option - * [RFC7797](https://tools.ietf.org/html/rfc7797) is used. - */ -export interface FlattenedJWS extends Partial { - payload: string - signature: string -} - -/** - * General JWS definition. Payload is returned as an empty - * string when JWS Unencoded Payload Option - * [RFC7797](https://tools.ietf.org/html/rfc7797) is used. - */ -export interface GeneralJWS { - payload: string - signatures: Omit[] -} - -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 - - /** - * "jku" (JWK Set URL) Header Parameter. - */ - jku?: 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]: unknown -} - -/** - * 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 -} - -export interface GeneralJWE extends Omit { - recipients: Pick[] -} - -/** - * 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]: unknown -} - -/** - * Shared Interface with a "crit" property for all sign and verify operations. - */ -export interface CritOption { - /** - * An object with keys representing recognized "crit" (Critical) Header Parameter - * names. The value for those is either `true` or `false`. `true` when the - * Header Parameter MUST be integrity protected, `false` when it's irrelevant. - * - * This makes the "Extension Header Parameter "${parameter}" is not recognized" - * error go away. - * - * Use this when a given JWS/JWT/JWE profile requires the use of proprietary - * non-registered "crit" (Critical) Header Parameters. This will only make sure - * the Header Parameter is syntactically correct when provided and that it is - * optionally integrity protected. It will not process the Header Parameter in - * any way or reject if the operation if it is missing. You MUST still - * verify the Header Parameter was present and process it according to the - * profile's validation steps after the operation succeeds. - * - * The JWS extension Header Parameter `b64` is always recognized and processed - * properly. No other registered Header Parameters that need this kind of - * default built-in treatment are currently available. - */ - crit?: { - [propName: string]: boolean - } -} - -/** - * JWE Decryption options. - */ -export interface DecryptOptions extends CritOption { - /** - * A list of accepted JWE "alg" (Algorithm) Header Parameter values. - */ - keyManagementAlgorithms?: string[] - - /** - * A list of accepted JWE "enc" (Encryption Algorithm) Header Parameter values. - * By default all "enc" (Encryption Algorithm) values applicable for the used - * key/secret are allowed. - */ - 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 extends CritOption { - /** - * 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", "10 minutes", "2 hours"). - */ - 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. - * - in seconds when number (e.g. 5) - * - parsed as seconds when a string (e.g. "5 seconds", "10 minutes", "2 hours"). - */ - maxTokenAge?: string | number - - /** - * 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 extends CritOption { - /** - * A list of accepted JWS "alg" (Algorithm) Header Parameter values. - * By default all "alg" (Algorithm) values applicable for the used - * key/secret are allowed. Note: "none" is never accepted. - */ - algorithms?: string[] -} - -/** - * JWS Signing options. - */ -export interface SignOptions extends CritOption {} - -/** - * 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]: unknown -} - -/** - * 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 GeneralDecryptResult extends FlattenedDecryptResult {} - -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 GeneralVerifyResult extends FlattenedVerifyResult {} - -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/dist/deno/types.i.d.ts b/dist/deno/types.i.d.ts deleted file mode 100644 index 44ead8d979..0000000000 --- a/dist/deno/types.i.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -export type Awaited = T extends PromiseLike ? PT : never -export type AsyncOrSync = PromiseLike | T - -export interface JWEKeyManagementHeaderResults { - apu?: string - apv?: string - epk?: { x?: string; y?: string; crv?: string; kty?: string } - iv?: string - p2c?: number - p2s?: string - tag?: string - [propName: string]: unknown -} diff --git a/dist/deno/util/base64url.ts b/dist/deno/util/base64url.ts deleted file mode 100644 index f3d76163fc..0000000000 --- a/dist/deno/util/base64url.ts +++ /dev/null @@ -1,21 +0,0 @@ -import * as base64url from '../runtime/base64url.ts' - -/** - * Utility function to encode a string or Uint8Array as a base64url string. - * - * @param input Value that will be base64url-encoded. - */ -interface Base64UrlEncode { - (input: Uint8Array | string): string -} -/** - * Utility function to decode a base64url encoded string. - * - * @param input Value that will be base64url-decoded. - */ -interface Base64UrlDecode { - (input: Uint8Array | string): Uint8Array -} - -export const encode: Base64UrlEncode = base64url.encode -export const decode: Base64UrlDecode = base64url.decode diff --git a/dist/deno/util/decode_protected_header.ts b/dist/deno/util/decode_protected_header.ts deleted file mode 100644 index d11dc1c649..0000000000 --- a/dist/deno/util/decode_protected_header.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { decode as base64url } from './base64url.ts' -import { decoder } from '../lib/buffer_utils.ts' -import isObject from '../lib/is_object.ts' -import type { JWSHeaderParameters, JWEHeaderParameters } from '../types.d.ts' - -export type ProtectedHeaderParameters = JWSHeaderParameters & JWEHeaderParameters - -/** - * Decodes the Protected Header of a JWE/JWS/JWT token utilizing any JOSE serialization. - * - * @example ESM import - * ```js - * import { decodeProtectedHeader } from 'jose/util/decode_protected_header' - * ``` - * - * @example CJS import - * ```js - * const { decodeProtectedHeader } = require('jose/util/decode_protected_header') - * ``` - * - * @example Deno import - * ```js - * import { decodeProtectedHeader } from 'https://deno.land/x/jose@VERSION/util/decode_protected_header.ts' - * ``` - * - * @example Usage - * ```js - * const protectedHeader = decodeProtectedHeader(token) - * console.log(protectedHeader) - * ``` - * - * @param token JWE/JWS/JWT token in any JOSE serialization. - */ -function decodeProtectedHeader(token: string | object) { - let protectedB64u!: string - - if (typeof token === 'string') { - const parts = token.split('.') - if (parts.length === 3 || parts.length === 5) { - ;[protectedB64u] = parts - } - } else if (typeof token === 'object' && token) { - if ('protected' in token) { - protectedB64u = (<{ protected: string }>token).protected - } else { - throw new TypeError('Token does not contain a Protected Header') - } - } - - try { - if (typeof protectedB64u !== 'string' || !protectedB64u) { - throw new Error() - } - const result = JSON.parse(decoder.decode(base64url(protectedB64u!))) - if (!isObject(result)) { - throw new Error() - } - return result - } catch { - throw new TypeError('Invalid Token or Protected Header formatting') - } -} - -export { decodeProtectedHeader } -export default decodeProtectedHeader diff --git a/dist/deno/util/errors.ts b/dist/deno/util/errors.ts deleted file mode 100644 index 59ef9a38db..0000000000 --- a/dist/deno/util/errors.ts +++ /dev/null @@ -1,165 +0,0 @@ -/** - * 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. - */ - static code = 'ERR_JOSE_GENERIC' - - /** - * A unique error code for the particular error subclass. - */ - code = JOSEError.code - - 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 { - static code = 'ERR_JWT_CLAIM_VALIDATION_FAILED' - - code = JWTClaimValidationFailed.code - - /** - * 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 { - static code = 'ERR_JOSE_ALG_NOT_ALLOWED' - - code = JOSEAlgNotAllowed.code -} - -/** - * 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 { - static code = 'ERR_JOSE_NOT_SUPPORTED' - - code = JOSENotSupported.code -} - -/** - * An error subclass thrown when a JWE ciphertext decryption fails. - */ -export class JWEDecryptionFailed extends JOSEError { - static code = 'ERR_JWE_DECRYPTION_FAILED' - - code = JWEDecryptionFailed.code - - message = 'decryption operation failed' -} - -/** - * An error subclass thrown when a JWE is invalid. - */ -export class JWEInvalid extends JOSEError { - static code = 'ERR_JWE_INVALID' - - code = JWEInvalid.code -} - -/** - * An error subclass thrown when a JWS is invalid. - */ -export class JWSInvalid extends JOSEError { - static code = 'ERR_JWS_INVALID' - - code = JWSInvalid.code -} - -/** - * An error subclass thrown when a JWT is invalid. - */ -export class JWTInvalid extends JOSEError { - static code = 'ERR_JWT_INVALID' - - code = JWTInvalid.code -} - -/** - * An error subclass thrown when a JWK is invalid. - */ -export class JWKInvalid extends JOSEError { - static code = 'ERR_JWK_INVALID' - - code = JWKInvalid.code -} - -/** - * An error subclass thrown when a JWKS is invalid. - */ -export class JWKSInvalid extends JOSEError { - static code = 'ERR_JWKS_INVALID' - - code = JWKSInvalid.code -} - -/** - * An error subclass thrown when no keys match from a JWKS. - */ -export class JWKSNoMatchingKey extends JOSEError { - static code = 'ERR_JWKS_NO_MATCHING_KEY' - - code = JWKSNoMatchingKey.code - - 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 { - static code = 'ERR_JWKS_MULTIPLE_MATCHING_KEYS' - - code = JWKSMultipleMatchingKeys.code - - 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 { - static code = 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED' - - code = JWSSignatureVerificationFailed.code - - message = 'signature verification failed' -} - -/** - * An error subclass thrown when a JWT is expired. - */ -export class JWTExpired extends JWTClaimValidationFailed { - static code = 'ERR_JWT_EXPIRED' - - code = JWTExpired.code -} diff --git a/dist/deno/util/generate_key_pair.ts b/dist/deno/util/generate_key_pair.ts deleted file mode 100644 index dc9b73f820..0000000000 --- a/dist/deno/util/generate_key_pair.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { generateKeyPair as generate } from '../runtime/generate.ts' -import type { KeyLike } from '../types.d.ts' - -export interface GenerateKeyPairResult { - /** - * The generated Private Key. - */ - privateKey: Exclude - - /** - * Public Key corresponding to the generated Private Key. - */ - publicKey: Exclude -} - -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 - - /** - * A hint for RSA algorithms to generate an RSA key of a given `modulusLength` - * (Key size in bits). JOSE requires 2048 bits or larger. Default is 2048. - */ - modulusLength?: number - - /** - * (Web Cryptography API specific) The value to use as - * [SubtleCrypto.generateKey()](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey) - * `extractable` argument. Default is false. - */ - extractable?: boolean -} - -/** - * 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. - * - * Note: Under Web Cryptography API runtime the `privateKey` is generated with - * `extractable` set to `false` by default. - * - * @example ESM import - * ```js - * import { generateKeyPair } from 'jose/util/generate_key_pair' - * ``` - * - * @example CJS import - * ```js - * const { generateKeyPair } = require('jose/util/generate_key_pair') - * ``` - * - * @example Deno import - * ```js - * import { generateKeyPair } from 'https://deno.land/x/jose@VERSION/util/generate_key_pair.ts' - * ``` - * - * @example Usage - * ```js - * 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. - */ -async function generateKeyPair( - alg: string, - options?: GenerateKeyPairOptions, -): Promise { - return generate(alg, options) -} - -export { generateKeyPair } -export default generateKeyPair diff --git a/dist/deno/util/generate_secret.ts b/dist/deno/util/generate_secret.ts deleted file mode 100644 index 2fccd5d471..0000000000 --- a/dist/deno/util/generate_secret.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { generateSecret as generate } from '../runtime/generate.ts' -import type { KeyLike } from '../types.d.ts' - -export interface GenerateSecretOptions { - /** - * (Web Cryptography API specific) The value to use as - * [SubtleCrypto.generateKey()](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey) - * `extractable` argument. Default is false. - */ - extractable?: boolean -} - -/** - * Generates a symmetric secret key for a given JWA algorithm identifier. - * - * Note: Under Web Cryptography API runtime the secret key is generated with - * `extractable` set to `false` by default. - * - * @example ESM import - * ```js - * import { generateSecret } from 'jose/util/generate_secret' - * ``` - * - * @example CJS import - * ```js - * const { generateSecret } = require('jose/util/generate_secret') - * ``` - * - * @example Deno import - * ```js - * import { generateSecret } from 'https://deno.land/x/jose@VERSION/util/generate_secret.ts' - * ``` - * - * @example Usage - * ```js - * const secret = await generateSecret('HS256') - * console.log(secret) - * ``` - * - * @param alg JWA Algorithm Identifier to be used with the generated secret. - * @param options Additional options passed down to the secret generation. - */ -async function generateSecret(alg: string, options?: GenerateSecretOptions): Promise { - return generate(alg, options) -} - -export { generateSecret } -export default generateSecret diff --git a/dist/deno/util/random.ts b/dist/deno/util/random.ts deleted file mode 100644 index 1b5b16a5ee..0000000000 --- a/dist/deno/util/random.ts +++ /dev/null @@ -1,9 +0,0 @@ -import runtimeRandom from '../runtime/random.ts' - -interface GetRandomValuesFunction { - (array: Uint8Array): Uint8Array -} - -const random: GetRandomValuesFunction = runtimeRandom -export { random } -export default random diff --git a/dist/node/cjs/jwe/compact/decrypt.js b/dist/node/cjs/jwe/compact/decrypt.js deleted file mode 100644 index 794d4861eb..0000000000 --- a/dist/node/cjs/jwe/compact/decrypt.js +++ /dev/null @@ -1,28 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.compactDecrypt = void 0; -const decrypt_js_1 = require("../flattened/decrypt.js"); -const errors_js_1 = require("../../util/errors.js"); -const buffer_utils_js_1 = require("../../lib/buffer_utils.js"); -async function compactDecrypt(jwe, key, options) { - if (jwe instanceof Uint8Array) { - jwe = buffer_utils_js_1.decoder.decode(jwe); - } - if (typeof jwe !== 'string') { - throw new errors_js_1.JWEInvalid('Compact JWE must be a string or Uint8Array'); - } - const { 0: protectedHeader, 1: encryptedKey, 2: iv, 3: ciphertext, 4: tag, length, } = jwe.split('.'); - if (length !== 5) { - throw new errors_js_1.JWEInvalid('Invalid Compact JWE'); - } - const decrypted = await (0, decrypt_js_1.default)({ - ciphertext: (ciphertext || undefined), - iv: (iv || undefined), - protected: protectedHeader || undefined, - tag: (tag || undefined), - encrypted_key: encryptedKey || undefined, - }, key, options); - return { plaintext: decrypted.plaintext, protectedHeader: decrypted.protectedHeader }; -} -exports.compactDecrypt = compactDecrypt; -exports.default = compactDecrypt; diff --git a/dist/node/cjs/jwe/compact/encrypt.js b/dist/node/cjs/jwe/compact/encrypt.js deleted file mode 100644 index e37dff2a35..0000000000 --- a/dist/node/cjs/jwe/compact/encrypt.js +++ /dev/null @@ -1,31 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.CompactEncrypt = void 0; -const encrypt_js_1 = require("../flattened/encrypt.js"); -class CompactEncrypt { - constructor(plaintext) { - this._flattened = new encrypt_js_1.default(plaintext); - } - setContentEncryptionKey(cek) { - this._flattened.setContentEncryptionKey(cek); - return this; - } - setInitializationVector(iv) { - this._flattened.setInitializationVector(iv); - return this; - } - setProtectedHeader(protectedHeader) { - this._flattened.setProtectedHeader(protectedHeader); - return this; - } - setKeyManagementParameters(parameters) { - this._flattened.setKeyManagementParameters(parameters); - return this; - } - async encrypt(key, options) { - const jwe = await this._flattened.encrypt(key, options); - return [jwe.protected, jwe.encrypted_key, jwe.iv, jwe.ciphertext, jwe.tag].join('.'); - } -} -exports.CompactEncrypt = CompactEncrypt; -exports.default = CompactEncrypt; diff --git a/dist/node/cjs/jwe/flattened/decrypt.js b/dist/node/cjs/jwe/flattened/decrypt.js deleted file mode 100644 index 89fa34f7a3..0000000000 --- a/dist/node/cjs/jwe/flattened/decrypt.js +++ /dev/null @@ -1,141 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.flattenedDecrypt = void 0; -const errors_js_1 = require("../../util/errors.js"); -const is_disjoint_js_1 = require("../../lib/is_disjoint.js"); -const is_object_js_1 = require("../../lib/is_object.js"); -const base64url_js_1 = require("../../runtime/base64url.js"); -const decrypt_js_1 = require("../../runtime/decrypt.js"); -const zlib_js_1 = require("../../runtime/zlib.js"); -const decrypt_key_management_js_1 = require("../../lib/decrypt_key_management.js"); -const buffer_utils_js_1 = require("../../lib/buffer_utils.js"); -const cek_js_1 = require("../../lib/cek.js"); -const random_js_1 = require("../../runtime/random.js"); -const validate_crit_js_1 = require("../../lib/validate_crit.js"); -const validate_algorithms_js_1 = require("../../lib/validate_algorithms.js"); -const generateCek = (0, cek_js_1.default)(random_js_1.default); -const checkExtensions = validate_crit_js_1.default.bind(undefined, errors_js_1.JWEInvalid, new Map()); -const checkAlgOption = validate_algorithms_js_1.default.bind(undefined, 'keyManagementAlgorithms'); -const checkEncOption = validate_algorithms_js_1.default.bind(undefined, 'contentEncryptionAlgorithms'); -async function flattenedDecrypt(jwe, key, options) { - var _a; - if (!(0, is_object_js_1.default)(jwe)) { - throw new errors_js_1.JWEInvalid('Flattened JWE must be an object'); - } - if (jwe.protected === undefined && jwe.header === undefined && jwe.unprotected === undefined) { - throw new errors_js_1.JWEInvalid('JOSE Header missing'); - } - if (typeof jwe.iv !== 'string') { - throw new errors_js_1.JWEInvalid('JWE Initialization Vector missing or incorrect type'); - } - if (typeof jwe.ciphertext !== 'string') { - throw new errors_js_1.JWEInvalid('JWE Ciphertext missing or incorrect type'); - } - if (typeof jwe.tag !== 'string') { - throw new errors_js_1.JWEInvalid('JWE Authentication Tag missing or incorrect type'); - } - if (jwe.protected !== undefined && typeof jwe.protected !== 'string') { - throw new errors_js_1.JWEInvalid('JWE Protected Header incorrect type'); - } - if (jwe.encrypted_key !== undefined && typeof jwe.encrypted_key !== 'string') { - throw new errors_js_1.JWEInvalid('JWE Encrypted Key incorrect type'); - } - if (jwe.aad !== undefined && typeof jwe.aad !== 'string') { - throw new errors_js_1.JWEInvalid('JWE AAD incorrect type'); - } - if (jwe.header !== undefined && !(0, is_object_js_1.default)(jwe.header)) { - throw new errors_js_1.JWEInvalid('JWE Shared Unprotected Header incorrect type'); - } - if (jwe.unprotected !== undefined && !(0, is_object_js_1.default)(jwe.unprotected)) { - throw new errors_js_1.JWEInvalid('JWE Per-Recipient Unprotected Header incorrect type'); - } - let parsedProt; - if (jwe.protected) { - const protectedHeader = (0, base64url_js_1.decode)(jwe.protected); - try { - parsedProt = JSON.parse(buffer_utils_js_1.decoder.decode(protectedHeader)); - } - catch { - throw new errors_js_1.JWEInvalid('JWE Protected Header is invalid'); - } - } - if (!(0, is_disjoint_js_1.default)(parsedProt, jwe.header, jwe.unprotected)) { - throw new errors_js_1.JWEInvalid('JWE Protected, JWE Unprotected Header, and JWE Per-Recipient Unprotected Header Parameter names must be disjoint'); - } - const joseHeader = { - ...parsedProt, - ...jwe.header, - ...jwe.unprotected, - }; - checkExtensions(options === null || options === void 0 ? void 0 : options.crit, parsedProt, joseHeader); - if (joseHeader.zip !== undefined) { - if (!parsedProt || !parsedProt.zip) { - throw new errors_js_1.JWEInvalid('JWE "zip" (Compression Algorithm) Header MUST be integrity protected'); - } - if (joseHeader.zip !== 'DEF') { - throw new errors_js_1.JOSENotSupported('unsupported JWE "zip" (Compression Algorithm) Header Parameter value'); - } - } - const { alg, enc } = joseHeader; - if (typeof alg !== 'string' || !alg) { - throw new errors_js_1.JWEInvalid('missing JWE Algorithm (alg) in JWE Header'); - } - if (typeof enc !== 'string' || !enc) { - throw new errors_js_1.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 errors_js_1.JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter not allowed'); - } - if (contentEncryptionAlgorithms && !contentEncryptionAlgorithms.has(enc)) { - throw new errors_js_1.JOSEAlgNotAllowed('"enc" (Encryption Algorithm) Header Parameter not allowed'); - } - let encryptedKey; - if (jwe.encrypted_key !== undefined) { - encryptedKey = (0, base64url_js_1.decode)(jwe.encrypted_key); - } - if (typeof key === 'function') { - key = await key(parsedProt, jwe); - } - let cek; - try { - cek = await (0, decrypt_key_management_js_1.default)(alg, key, encryptedKey, joseHeader); - } - catch (err) { - if (err instanceof TypeError) { - throw err; - } - cek = generateCek(enc); - } - const iv = (0, base64url_js_1.decode)(jwe.iv); - const tag = (0, base64url_js_1.decode)(jwe.tag); - const protectedHeader = buffer_utils_js_1.encoder.encode((_a = jwe.protected) !== null && _a !== void 0 ? _a : ''); - let additionalData; - if (jwe.aad !== undefined) { - additionalData = (0, buffer_utils_js_1.concat)(protectedHeader, buffer_utils_js_1.encoder.encode('.'), buffer_utils_js_1.encoder.encode(jwe.aad)); - } - else { - additionalData = protectedHeader; - } - let plaintext = await (0, decrypt_js_1.default)(enc, cek, (0, base64url_js_1.decode)(jwe.ciphertext), iv, tag, additionalData); - if (joseHeader.zip === 'DEF') { - plaintext = await ((options === null || options === void 0 ? void 0 : options.inflateRaw) || zlib_js_1.inflate)(plaintext); - } - const result = { plaintext }; - if (jwe.protected !== undefined) { - result.protectedHeader = parsedProt; - } - if (jwe.aad !== undefined) { - result.additionalAuthenticatedData = (0, base64url_js_1.decode)(jwe.aad); - } - if (jwe.unprotected !== undefined) { - result.sharedUnprotectedHeader = jwe.unprotected; - } - if (jwe.header !== undefined) { - result.unprotectedHeader = jwe.header; - } - return result; -} -exports.flattenedDecrypt = flattenedDecrypt; -exports.default = flattenedDecrypt; diff --git a/dist/node/cjs/jwe/flattened/encrypt.js b/dist/node/cjs/jwe/flattened/encrypt.js deleted file mode 100644 index 981f68a742..0000000000 --- a/dist/node/cjs/jwe/flattened/encrypt.js +++ /dev/null @@ -1,169 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.FlattenedEncrypt = void 0; -const iv_js_1 = require("../../lib/iv.js"); -const base64url_js_1 = require("../../runtime/base64url.js"); -const random_js_1 = require("../../runtime/random.js"); -const encrypt_js_1 = require("../../runtime/encrypt.js"); -const zlib_js_1 = require("../../runtime/zlib.js"); -const encrypt_key_management_js_1 = require("../../lib/encrypt_key_management.js"); -const errors_js_1 = require("../../util/errors.js"); -const is_disjoint_js_1 = require("../../lib/is_disjoint.js"); -const buffer_utils_js_1 = require("../../lib/buffer_utils.js"); -const validate_crit_js_1 = require("../../lib/validate_crit.js"); -const generateIv = (0, iv_js_1.default)(random_js_1.default); -const checkExtensions = validate_crit_js_1.default.bind(undefined, errors_js_1.JWEInvalid, new Map()); -class FlattenedEncrypt { - constructor(plaintext) { - this._plaintext = plaintext; - } - setKeyManagementParameters(parameters) { - if (this._keyManagementParameters) { - throw new TypeError('setKeyManagementParameters can only be called once'); - } - this._keyManagementParameters = parameters; - return this; - } - setProtectedHeader(protectedHeader) { - if (this._protectedHeader) { - throw new TypeError('setProtectedHeader can only be called once'); - } - this._protectedHeader = protectedHeader; - return this; - } - setSharedUnprotectedHeader(sharedUnprotectedHeader) { - if (this._sharedUnprotectedHeader) { - throw new TypeError('setSharedUnprotectedHeader can only be called once'); - } - this._sharedUnprotectedHeader = sharedUnprotectedHeader; - return this; - } - setUnprotectedHeader(unprotectedHeader) { - if (this._unprotectedHeader) { - throw new TypeError('setUnprotectedHeader can only be called once'); - } - this._unprotectedHeader = unprotectedHeader; - return this; - } - setAdditionalAuthenticatedData(aad) { - this._aad = aad; - return this; - } - setContentEncryptionKey(cek) { - if (this._cek) { - throw new TypeError('setContentEncryptionKey can only be called once'); - } - this._cek = cek; - return this; - } - setInitializationVector(iv) { - if (this._iv) { - throw new TypeError('setInitializationVector can only be called once'); - } - this._iv = iv; - return this; - } - async encrypt(key, options) { - if (!this._protectedHeader && !this._unprotectedHeader && !this._sharedUnprotectedHeader) { - throw new errors_js_1.JWEInvalid('either setProtectedHeader, setUnprotectedHeader, or sharedUnprotectedHeader must be called before #encrypt()'); - } - if (!(0, is_disjoint_js_1.default)(this._protectedHeader, this._unprotectedHeader, this._sharedUnprotectedHeader)) { - throw new errors_js_1.JWEInvalid('JWE Shared Protected, JWE Shared Unprotected and JWE Per-Recipient Header Parameter names must be disjoint'); - } - const joseHeader = { - ...this._protectedHeader, - ...this._unprotectedHeader, - ...this._sharedUnprotectedHeader, - }; - checkExtensions(options === null || options === void 0 ? void 0 : options.crit, this._protectedHeader, joseHeader); - if (joseHeader.zip !== undefined) { - if (!this._protectedHeader || !this._protectedHeader.zip) { - throw new errors_js_1.JWEInvalid('JWE "zip" (Compression Algorithm) Header MUST be integrity protected'); - } - if (joseHeader.zip !== 'DEF') { - throw new errors_js_1.JOSENotSupported('unsupported JWE "zip" (Compression Algorithm) Header Parameter value'); - } - } - const { alg, enc } = joseHeader; - if (typeof alg !== 'string' || !alg) { - throw new errors_js_1.JWEInvalid('JWE "alg" (Algorithm) Header Parameter missing or invalid'); - } - if (typeof enc !== 'string' || !enc) { - throw new errors_js_1.JWEInvalid('JWE "enc" (Encryption Algorithm) Header Parameter missing or invalid'); - } - let encryptedKey; - 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; - { - let parameters; - ({ cek, encryptedKey, parameters } = await (0, encrypt_key_management_js_1.default)(alg, enc, key, this._cek, this._keyManagementParameters)); - if (parameters) { - if (!this._protectedHeader) { - this.setProtectedHeader(parameters); - } - else { - this._protectedHeader = { ...this._protectedHeader, ...parameters }; - } - } - } - this._iv || (this._iv = generateIv(enc)); - let additionalData; - let protectedHeader; - let aadMember; - if (this._protectedHeader) { - protectedHeader = buffer_utils_js_1.encoder.encode((0, base64url_js_1.encode)(JSON.stringify(this._protectedHeader))); - } - else { - protectedHeader = buffer_utils_js_1.encoder.encode(''); - } - if (this._aad) { - aadMember = (0, base64url_js_1.encode)(this._aad); - additionalData = (0, buffer_utils_js_1.concat)(protectedHeader, buffer_utils_js_1.encoder.encode('.'), buffer_utils_js_1.encoder.encode(aadMember)); - } - else { - additionalData = protectedHeader; - } - let ciphertext; - let tag; - if (joseHeader.zip === 'DEF') { - const deflated = await ((options === null || options === void 0 ? void 0 : options.deflateRaw) || zlib_js_1.deflate)(this._plaintext); - ({ ciphertext, tag } = await (0, encrypt_js_1.default)(enc, deflated, cek, this._iv, additionalData)); - } - else { - ; - ({ ciphertext, tag } = await (0, encrypt_js_1.default)(enc, this._plaintext, cek, this._iv, additionalData)); - } - const jwe = { - ciphertext: (0, base64url_js_1.encode)(ciphertext), - iv: (0, base64url_js_1.encode)(this._iv), - tag: (0, base64url_js_1.encode)(tag), - }; - if (encryptedKey) { - jwe.encrypted_key = (0, base64url_js_1.encode)(encryptedKey); - } - if (aadMember) { - jwe.aad = aadMember; - } - if (this._protectedHeader) { - jwe.protected = buffer_utils_js_1.decoder.decode(protectedHeader); - } - if (this._sharedUnprotectedHeader) { - jwe.unprotected = this._sharedUnprotectedHeader; - } - if (this._unprotectedHeader) { - jwe.header = this._unprotectedHeader; - } - return jwe; - } -} -exports.FlattenedEncrypt = FlattenedEncrypt; -exports.default = FlattenedEncrypt; diff --git a/dist/node/cjs/jwe/general/decrypt.js b/dist/node/cjs/jwe/general/decrypt.js deleted file mode 100644 index 93adfd841d..0000000000 --- a/dist/node/cjs/jwe/general/decrypt.js +++ /dev/null @@ -1,33 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.generalDecrypt = void 0; -const decrypt_js_1 = require("../flattened/decrypt.js"); -const errors_js_1 = require("../../util/errors.js"); -const is_object_js_1 = require("../../lib/is_object.js"); -async function generalDecrypt(jwe, key, options) { - if (!(0, is_object_js_1.default)(jwe)) { - throw new errors_js_1.JWEInvalid('General JWE must be an object'); - } - if (!Array.isArray(jwe.recipients) || !jwe.recipients.every(is_object_js_1.default)) { - throw new errors_js_1.JWEInvalid('JWE Recipients missing or incorrect type'); - } - for (const recipient of jwe.recipients) { - try { - return await (0, decrypt_js_1.default)({ - aad: jwe.aad, - ciphertext: jwe.ciphertext, - encrypted_key: recipient.encrypted_key, - header: recipient.header, - iv: jwe.iv, - protected: jwe.protected, - tag: jwe.tag, - unprotected: jwe.unprotected, - }, key, options); - } - catch { - } - } - throw new errors_js_1.JWEDecryptionFailed(); -} -exports.generalDecrypt = generalDecrypt; -exports.default = generalDecrypt; diff --git a/dist/node/cjs/jwk/embedded.js b/dist/node/cjs/jwk/embedded.js deleted file mode 100644 index 6b4c267bed..0000000000 --- a/dist/node/cjs/jwk/embedded.js +++ /dev/null @@ -1,22 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.EmbeddedJWK = void 0; -const parse_js_1 = require("./parse.js"); -const is_object_js_1 = require("../lib/is_object.js"); -const errors_js_1 = require("../util/errors.js"); -async function EmbeddedJWK(protectedHeader, token) { - const joseHeader = { - ...protectedHeader, - ...token.header, - }; - if (!(0, is_object_js_1.default)(joseHeader.jwk)) { - throw new errors_js_1.JWSInvalid('"jwk" (JSON Web Key) Header Parameter must be a JSON object'); - } - const key = await (0, parse_js_1.default)(joseHeader.jwk, joseHeader.alg, true); - if (key.type !== 'public') { - throw new errors_js_1.JWSInvalid('"jwk" (JSON Web Key) Header Parameter must be a public key'); - } - return key; -} -exports.EmbeddedJWK = EmbeddedJWK; -exports.default = EmbeddedJWK; diff --git a/dist/node/cjs/jwk/from_key_like.js b/dist/node/cjs/jwk/from_key_like.js deleted file mode 100644 index 13454de1da..0000000000 --- a/dist/node/cjs/jwk/from_key_like.js +++ /dev/null @@ -1,9 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.fromKeyLike = void 0; -const key_to_jwk_js_1 = require("../runtime/key_to_jwk.js"); -async function fromKeyLike(key) { - return (0, key_to_jwk_js_1.default)(key); -} -exports.fromKeyLike = fromKeyLike; -exports.default = fromKeyLike; diff --git a/dist/node/cjs/jwk/parse.js b/dist/node/cjs/jwk/parse.js deleted file mode 100644 index f5bd4e3d07..0000000000 --- a/dist/node/cjs/jwk/parse.js +++ /dev/null @@ -1,38 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.parseJwk = void 0; -const base64url_js_1 = require("../runtime/base64url.js"); -const jwk_to_key_js_1 = require("../runtime/jwk_to_key.js"); -const errors_js_1 = require("../util/errors.js"); -const is_object_js_1 = require("../lib/is_object.js"); -async function parseJwk(jwk, alg, octAsKeyObject) { - if (!(0, is_object_js_1.default)(jwk)) { - throw new TypeError('JWK must be an object'); - } - alg || (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'); - } - octAsKeyObject !== null && octAsKeyObject !== void 0 ? octAsKeyObject : (octAsKeyObject = jwk.ext !== true); - if (octAsKeyObject) { - return (0, jwk_to_key_js_1.default)({ ...jwk, alg, ext: false }); - } - return (0, base64url_js_1.decode)(jwk.k); - case 'RSA': - if (jwk.oth !== undefined) { - throw new errors_js_1.JOSENotSupported('RSA JWK "oth" (Other Primes Info) Parameter value is not supported'); - } - case 'EC': - case 'OKP': - return (0, jwk_to_key_js_1.default)({ ...jwk, alg }); - default: - throw new errors_js_1.JOSENotSupported('unsupported "kty" (Key Type) Parameter value'); - } -} -exports.parseJwk = parseJwk; -exports.default = parseJwk; diff --git a/dist/node/cjs/jwk/thumbprint.js b/dist/node/cjs/jwk/thumbprint.js deleted file mode 100644 index 97b6d11688..0000000000 --- a/dist/node/cjs/jwk/thumbprint.js +++ /dev/null @@ -1,47 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.calculateThumbprint = void 0; -const errors_js_1 = require("../util/errors.js"); -const digest_js_1 = require("../runtime/digest.js"); -const base64url_js_1 = require("../runtime/base64url.js"); -const buffer_utils_js_1 = require("../lib/buffer_utils.js"); -const is_object_js_1 = require("../lib/is_object.js"); -const check = (value, description) => { - if (typeof value !== 'string' || !value) { - throw new errors_js_1.JWKInvalid(`${description} missing or invalid`); - } -}; -async function calculateThumbprint(jwk, digestAlgorithm = 'sha256') { - if (!(0, is_object_js_1.default)(jwk)) { - throw new TypeError('JWK must be an object'); - } - let components; - 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 errors_js_1.JOSENotSupported('"kty" (Key Type) Parameter missing or unsupported'); - } - const data = buffer_utils_js_1.encoder.encode(JSON.stringify(components)); - return (0, base64url_js_1.encode)(await (0, digest_js_1.default)(digestAlgorithm, data)); -} -exports.calculateThumbprint = calculateThumbprint; -exports.default = calculateThumbprint; diff --git a/dist/node/cjs/jwks/remote.js b/dist/node/cjs/jwks/remote.js deleted file mode 100644 index 98015dd86f..0000000000 --- a/dist/node/cjs/jwks/remote.js +++ /dev/null @@ -1,133 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.createRemoteJWKSet = void 0; -const parse_js_1 = require("../jwk/parse.js"); -const errors_js_1 = require("../util/errors.js"); -const fetch_jwks_js_1 = require("../runtime/fetch_jwks.js"); -const is_object_js_1 = require("../lib/is_object.js"); -function getKtyFromAlg(alg) { - switch (alg.substr(0, 2)) { - case 'RS': - case 'PS': - return 'RSA'; - case 'ES': - return 'EC'; - case 'Ed': - return 'OKP'; - default: - throw new errors_js_1.JOSENotSupported('Unsupported "alg" value for a JSON Web Key Set'); - } -} -function isJWKLike(key) { - return (0, is_object_js_1.default)(key); -} -class RemoteJWKSet { - constructor(url, options) { - this._cached = new WeakMap(); - if (!(url instanceof URL)) { - throw new TypeError('url must be an instance of URL'); - } - this._url = new URL(url.href); - this._options = { agent: options === null || options === void 0 ? void 0 : options.agent }; - this._timeoutDuration = - typeof (options === null || options === void 0 ? void 0 : options.timeoutDuration) === 'number' ? options === null || options === void 0 ? void 0 : options.timeoutDuration : 5000; - this._cooldownDuration = - typeof (options === null || options === void 0 ? void 0 : options.cooldownDuration) === 'number' ? options === null || options === void 0 ? void 0 : options.cooldownDuration : 30000; - } - coolingDown() { - if (typeof this._cooldownStarted === 'undefined') { - return false; - } - return Date.now() < this._cooldownStarted + this._cooldownDuration; - } - async getKey(protectedHeader) { - if (!this._jwks) { - await this.reload(); - } - const candidates = this._jwks.keys.filter((jwk) => { - let candidate = jwk.kty === getKtyFromAlg(protectedHeader.alg); - if (candidate && typeof protectedHeader.kid === 'string') { - candidate = protectedHeader.kid === jwk.kid; - } - if (candidate && typeof jwk.alg === 'string') { - candidate = protectedHeader.alg === jwk.alg; - } - if (candidate && typeof jwk.use === 'string') { - candidate = jwk.use === 'sig'; - } - if (candidate && Array.isArray(jwk.key_ops)) { - candidate = jwk.key_ops.includes('verify'); - } - if (candidate && protectedHeader.alg === 'EdDSA') { - candidate = ['Ed25519', 'Ed448'].includes(jwk.crv); - } - 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 errors_js_1.JWKSNoMatchingKey(); - } - else if (length !== 1) { - throw new errors_js_1.JWKSMultipleMatchingKeys(); - } - if (!this._cached.has(jwk)) { - this._cached.set(jwk, {}); - } - const cached = this._cached.get(jwk); - if (cached[protectedHeader.alg] === undefined) { - const keyObject = await (0, parse_js_1.default)({ ...jwk, alg: protectedHeader.alg }); - if (keyObject.type !== 'public') { - throw new errors_js_1.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 = (0, fetch_jwks_js_1.default)(this._url, this._timeoutDuration, this._options) - .then((json) => { - if (typeof json !== 'object' || - !json || - !Array.isArray(json.keys) || - !json.keys.every(isJWKLike)) { - throw new errors_js_1.JWKSInvalid('JSON Web Key Set malformed'); - } - this._jwks = { keys: json.keys }; - this._cooldownStarted = Date.now(); - this._pendingFetch = undefined; - }) - .catch((err) => { - this._pendingFetch = undefined; - throw err; - }); - } - await this._pendingFetch; - } -} -function createRemoteJWKSet(url, options) { - return RemoteJWKSet.prototype.getKey.bind(new RemoteJWKSet(url, options)); -} -exports.createRemoteJWKSet = createRemoteJWKSet; -exports.default = createRemoteJWKSet; diff --git a/dist/node/cjs/jws/compact/sign.js b/dist/node/cjs/jws/compact/sign.js deleted file mode 100644 index b49877f00f..0000000000 --- a/dist/node/cjs/jws/compact/sign.js +++ /dev/null @@ -1,22 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.CompactSign = void 0; -const sign_js_1 = require("../flattened/sign.js"); -class CompactSign { - constructor(payload) { - this._flattened = new sign_js_1.default(payload); - } - setProtectedHeader(protectedHeader) { - this._flattened.setProtectedHeader(protectedHeader); - return this; - } - async sign(key, options) { - const jws = await this._flattened.sign(key, options); - if (jws.payload === undefined) { - throw new TypeError('use the flattened module for creating JWS with b64: false'); - } - return `${jws.protected}.${jws.payload}.${jws.signature}`; - } -} -exports.CompactSign = CompactSign; -exports.default = CompactSign; diff --git a/dist/node/cjs/jws/compact/verify.js b/dist/node/cjs/jws/compact/verify.js deleted file mode 100644 index 78589b93af..0000000000 --- a/dist/node/cjs/jws/compact/verify.js +++ /dev/null @@ -1,26 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.compactVerify = void 0; -const verify_js_1 = require("../flattened/verify.js"); -const errors_js_1 = require("../../util/errors.js"); -const buffer_utils_js_1 = require("../../lib/buffer_utils.js"); -async function compactVerify(jws, key, options) { - if (jws instanceof Uint8Array) { - jws = buffer_utils_js_1.decoder.decode(jws); - } - if (typeof jws !== 'string') { - throw new errors_js_1.JWSInvalid('Compact JWS must be a string or Uint8Array'); - } - const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split('.'); - if (length !== 3) { - throw new errors_js_1.JWSInvalid('Invalid Compact JWS'); - } - const verified = await (0, verify_js_1.default)({ - payload: (payload || undefined), - protected: protectedHeader || undefined, - signature: (signature || undefined), - }, key, options); - return { payload: verified.payload, protectedHeader: verified.protectedHeader }; -} -exports.compactVerify = compactVerify; -exports.default = compactVerify; diff --git a/dist/node/cjs/jws/flattened/sign.js b/dist/node/cjs/jws/flattened/sign.js deleted file mode 100644 index 39c5a27b86..0000000000 --- a/dist/node/cjs/jws/flattened/sign.js +++ /dev/null @@ -1,84 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.FlattenedSign = void 0; -const is_disjoint_js_1 = require("../../lib/is_disjoint.js"); -const errors_js_1 = require("../../util/errors.js"); -const buffer_utils_js_1 = require("../../lib/buffer_utils.js"); -const base64url_js_1 = require("../../runtime/base64url.js"); -const sign_js_1 = require("../../runtime/sign.js"); -const check_key_type_js_1 = require("../../lib/check_key_type.js"); -const validate_crit_js_1 = require("../../lib/validate_crit.js"); -const checkExtensions = validate_crit_js_1.default.bind(undefined, errors_js_1.JWSInvalid, new Map([['b64', true]])); -class FlattenedSign { - constructor(payload) { - this._payload = payload; - } - setProtectedHeader(protectedHeader) { - if (this._protectedHeader) { - throw new TypeError('setProtectedHeader can only be called once'); - } - this._protectedHeader = protectedHeader; - return this; - } - setUnprotectedHeader(unprotectedHeader) { - if (this._unprotectedHeader) { - throw new TypeError('setUnprotectedHeader can only be called once'); - } - this._unprotectedHeader = unprotectedHeader; - return this; - } - async sign(key, options) { - if (!this._protectedHeader && !this._unprotectedHeader) { - throw new errors_js_1.JWSInvalid('either setProtectedHeader or setUnprotectedHeader must be called before #sign()'); - } - if (!(0, is_disjoint_js_1.default)(this._protectedHeader, this._unprotectedHeader)) { - throw new errors_js_1.JWSInvalid('JWS Protected and JWS Unprotected Header Parameter names must be disjoint'); - } - const joseHeader = { - ...this._protectedHeader, - ...this._unprotectedHeader, - }; - const extensions = checkExtensions(options === null || options === void 0 ? void 0 : options.crit, this._protectedHeader, joseHeader); - let b64 = true; - if (extensions.has('b64')) { - b64 = this._protectedHeader.b64; - if (typeof b64 !== 'boolean') { - throw new errors_js_1.JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean'); - } - } - const { alg } = joseHeader; - if (typeof alg !== 'string' || !alg) { - throw new errors_js_1.JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid'); - } - (0, check_key_type_js_1.default)(alg, key, 'sign'); - let payload = this._payload; - if (b64) { - payload = buffer_utils_js_1.encoder.encode((0, base64url_js_1.encode)(payload)); - } - let protectedHeader; - if (this._protectedHeader) { - protectedHeader = buffer_utils_js_1.encoder.encode((0, base64url_js_1.encode)(JSON.stringify(this._protectedHeader))); - } - else { - protectedHeader = buffer_utils_js_1.encoder.encode(''); - } - const data = (0, buffer_utils_js_1.concat)(protectedHeader, buffer_utils_js_1.encoder.encode('.'), payload); - const signature = await (0, sign_js_1.default)(alg, key, data); - const jws = { - signature: (0, base64url_js_1.encode)(signature), - payload: '', - }; - if (b64) { - jws.payload = buffer_utils_js_1.decoder.decode(payload); - } - if (this._unprotectedHeader) { - jws.header = this._unprotectedHeader; - } - if (this._protectedHeader) { - jws.protected = buffer_utils_js_1.decoder.decode(protectedHeader); - } - return jws; - } -} -exports.FlattenedSign = FlattenedSign; -exports.default = FlattenedSign; diff --git a/dist/node/cjs/jws/flattened/verify.js b/dist/node/cjs/jws/flattened/verify.js deleted file mode 100644 index 496458cce1..0000000000 --- a/dist/node/cjs/jws/flattened/verify.js +++ /dev/null @@ -1,106 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.flattenedVerify = void 0; -const errors_js_1 = require("../../util/errors.js"); -const buffer_utils_js_1 = require("../../lib/buffer_utils.js"); -const is_disjoint_js_1 = require("../../lib/is_disjoint.js"); -const is_object_js_1 = require("../../lib/is_object.js"); -const check_key_type_js_1 = require("../../lib/check_key_type.js"); -const base64url_js_1 = require("../../runtime/base64url.js"); -const verify_js_1 = require("../../runtime/verify.js"); -const validate_crit_js_1 = require("../../lib/validate_crit.js"); -const validate_algorithms_js_1 = require("../../lib/validate_algorithms.js"); -const checkExtensions = validate_crit_js_1.default.bind(undefined, errors_js_1.JWSInvalid, new Map([['b64', true]])); -const checkAlgOption = validate_algorithms_js_1.default.bind(undefined, 'algorithms'); -async function flattenedVerify(jws, key, options) { - var _a; - if (!(0, is_object_js_1.default)(jws)) { - throw new errors_js_1.JWSInvalid('Flattened JWS must be an object'); - } - if (jws.protected === undefined && jws.header === undefined) { - throw new errors_js_1.JWSInvalid('Flattened JWS must have either of the "protected" or "header" members'); - } - if (jws.protected !== undefined && typeof jws.protected !== 'string') { - throw new errors_js_1.JWSInvalid('JWS Protected Header incorrect type'); - } - if (jws.payload === undefined) { - throw new errors_js_1.JWSInvalid('JWS Payload missing'); - } - if (typeof jws.signature !== 'string') { - throw new errors_js_1.JWSInvalid('JWS Signature missing or incorrect type'); - } - if (jws.header !== undefined && !(0, is_object_js_1.default)(jws.header)) { - throw new errors_js_1.JWSInvalid('JWS Unprotected Header incorrect type'); - } - let parsedProt = {}; - if (jws.protected) { - const protectedHeader = (0, base64url_js_1.decode)(jws.protected); - try { - parsedProt = JSON.parse(buffer_utils_js_1.decoder.decode(protectedHeader)); - } - catch { - throw new errors_js_1.JWSInvalid('JWS Protected Header is invalid'); - } - } - if (!(0, is_disjoint_js_1.default)(parsedProt, jws.header)) { - throw new errors_js_1.JWSInvalid('JWS Protected and JWS Unprotected Header Parameter names must be disjoint'); - } - const joseHeader = { - ...parsedProt, - ...jws.header, - }; - const extensions = checkExtensions(options === null || options === void 0 ? void 0 : options.crit, parsedProt, joseHeader); - let b64 = true; - if (extensions.has('b64')) { - b64 = parsedProt.b64; - if (typeof b64 !== 'boolean') { - throw new errors_js_1.JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean'); - } - } - const { alg } = joseHeader; - if (typeof alg !== 'string' || !alg) { - throw new errors_js_1.JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid'); - } - const algorithms = options && checkAlgOption(options.algorithms); - if (algorithms && !algorithms.has(alg)) { - throw new errors_js_1.JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter not allowed'); - } - if (b64) { - if (typeof jws.payload !== 'string') { - throw new errors_js_1.JWSInvalid('JWS Payload must be a string'); - } - } - else if (typeof jws.payload !== 'string' && !(jws.payload instanceof Uint8Array)) { - throw new errors_js_1.JWSInvalid('JWS Payload must be a string or an Uint8Array instance'); - } - if (typeof key === 'function') { - key = await key(parsedProt, jws); - } - (0, check_key_type_js_1.default)(alg, key, 'verify'); - const data = (0, buffer_utils_js_1.concat)(buffer_utils_js_1.encoder.encode((_a = jws.protected) !== null && _a !== void 0 ? _a : ''), buffer_utils_js_1.encoder.encode('.'), typeof jws.payload === 'string' ? buffer_utils_js_1.encoder.encode(jws.payload) : jws.payload); - const signature = (0, base64url_js_1.decode)(jws.signature); - const verified = await (0, verify_js_1.default)(alg, key, signature, data); - if (!verified) { - throw new errors_js_1.JWSSignatureVerificationFailed(); - } - let payload; - if (b64) { - payload = (0, base64url_js_1.decode)(jws.payload); - } - else if (typeof jws.payload === 'string') { - payload = buffer_utils_js_1.encoder.encode(jws.payload); - } - else { - payload = jws.payload; - } - const result = { payload }; - if (jws.protected !== undefined) { - result.protectedHeader = parsedProt; - } - if (jws.header !== undefined) { - result.unprotectedHeader = jws.header; - } - return result; -} -exports.flattenedVerify = flattenedVerify; -exports.default = flattenedVerify; diff --git a/dist/node/cjs/jws/general/sign.js b/dist/node/cjs/jws/general/sign.js deleted file mode 100644 index 502ce4059e..0000000000 --- a/dist/node/cjs/jws/general/sign.js +++ /dev/null @@ -1,76 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.GeneralSign = void 0; -const sign_js_1 = require("../flattened/sign.js"); -const errors_js_1 = require("../../util/errors.js"); -const signatureRef = new WeakMap(); -class IndividualSignature { - setProtectedHeader(protectedHeader) { - if (this._protectedHeader) { - throw new TypeError('setProtectedHeader can only be called once'); - } - this._protectedHeader = protectedHeader; - return this; - } - setUnprotectedHeader(unprotectedHeader) { - if (this._unprotectedHeader) { - throw new TypeError('setUnprotectedHeader can only be called once'); - } - this._unprotectedHeader = unprotectedHeader; - return this; - } - set _protectedHeader(value) { - signatureRef.get(this).protectedHeader = value; - } - get _protectedHeader() { - return signatureRef.get(this).protectedHeader; - } - set _unprotectedHeader(value) { - signatureRef.get(this).unprotectedHeader = value; - } - get _unprotectedHeader() { - return signatureRef.get(this).unprotectedHeader; - } -} -class GeneralSign { - constructor(payload) { - this._signatures = []; - this._payload = payload; - } - addSignature(key, options) { - const signature = new IndividualSignature(); - signatureRef.set(signature, { key, options }); - this._signatures.push(signature); - return signature; - } - async sign() { - if (!this._signatures.length) { - throw new errors_js_1.JWSInvalid('at least one signature must be added'); - } - const jws = { - signatures: [], - payload: '', - }; - let payloads = new Set(); - await Promise.all(this._signatures.map(async (sig) => { - const { protectedHeader, unprotectedHeader, options, key } = signatureRef.get(sig); - const flattened = new sign_js_1.default(this._payload); - if (protectedHeader) { - flattened.setProtectedHeader(protectedHeader); - } - if (unprotectedHeader) { - flattened.setUnprotectedHeader(unprotectedHeader); - } - const { payload, ...rest } = await flattened.sign(key, options); - payloads.add(payload); - jws.payload = payload; - jws.signatures.push(rest); - })); - if (payloads.size !== 1) { - throw new errors_js_1.JWSInvalid('inconsistent use of JWS Unencoded Payload Option (RFC7797)'); - } - return jws; - } -} -exports.GeneralSign = GeneralSign; -exports.default = GeneralSign; diff --git a/dist/node/cjs/jws/general/verify.js b/dist/node/cjs/jws/general/verify.js deleted file mode 100644 index 1705c5eccb..0000000000 --- a/dist/node/cjs/jws/general/verify.js +++ /dev/null @@ -1,29 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.generalVerify = void 0; -const verify_js_1 = require("../flattened/verify.js"); -const errors_js_1 = require("../../util/errors.js"); -const is_object_js_1 = require("../../lib/is_object.js"); -async function generalVerify(jws, key, options) { - if (!(0, is_object_js_1.default)(jws)) { - throw new errors_js_1.JWSInvalid('General JWS must be an object'); - } - if (!Array.isArray(jws.signatures) || !jws.signatures.every(is_object_js_1.default)) { - throw new errors_js_1.JWSInvalid('JWS Signatures missing or incorrect type'); - } - for (const signature of jws.signatures) { - try { - return await (0, verify_js_1.default)({ - header: signature.header, - payload: jws.payload, - protected: signature.protected, - signature: signature.signature, - }, key, options); - } - catch { - } - } - throw new errors_js_1.JWSSignatureVerificationFailed(); -} -exports.generalVerify = generalVerify; -exports.default = generalVerify; diff --git a/dist/node/cjs/jwt/decrypt.js b/dist/node/cjs/jwt/decrypt.js deleted file mode 100644 index c9a7ea9127..0000000000 --- a/dist/node/cjs/jwt/decrypt.js +++ /dev/null @@ -1,24 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.jwtDecrypt = void 0; -const decrypt_js_1 = require("../jwe/compact/decrypt.js"); -const jwt_claims_set_js_1 = require("../lib/jwt_claims_set.js"); -const errors_js_1 = require("../util/errors.js"); -async function jwtDecrypt(jwt, key, options) { - const decrypted = await (0, decrypt_js_1.default)(jwt, key, options); - const payload = (0, jwt_claims_set_js_1.default)(decrypted.protectedHeader, decrypted.plaintext, options); - const { protectedHeader } = decrypted; - if (protectedHeader.iss !== undefined && protectedHeader.iss !== payload.iss) { - throw new errors_js_1.JWTClaimValidationFailed('replicated "iss" claim header parameter mismatch', 'iss', 'mismatch'); - } - if (protectedHeader.sub !== undefined && protectedHeader.sub !== payload.sub) { - throw new errors_js_1.JWTClaimValidationFailed('replicated "sub" claim header parameter mismatch', 'sub', 'mismatch'); - } - if (protectedHeader.aud !== undefined && - JSON.stringify(protectedHeader.aud) !== JSON.stringify(payload.aud)) { - throw new errors_js_1.JWTClaimValidationFailed('replicated "aud" claim header parameter mismatch', 'aud', 'mismatch'); - } - return { payload, protectedHeader }; -} -exports.jwtDecrypt = jwtDecrypt; -exports.default = jwtDecrypt; diff --git a/dist/node/cjs/jwt/encrypt.js b/dist/node/cjs/jwt/encrypt.js deleted file mode 100644 index 9c4cad87e2..0000000000 --- a/dist/node/cjs/jwt/encrypt.js +++ /dev/null @@ -1,73 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.EncryptJWT = void 0; -const encrypt_js_1 = require("../jwe/compact/encrypt.js"); -const buffer_utils_js_1 = require("../lib/buffer_utils.js"); -const jwt_producer_js_1 = require("../lib/jwt_producer.js"); -class EncryptJWT extends jwt_producer_js_1.default { - setProtectedHeader(protectedHeader) { - if (this._protectedHeader) { - throw new TypeError('setProtectedHeader can only be called once'); - } - this._protectedHeader = protectedHeader; - return this; - } - setKeyManagementParameters(parameters) { - if (this._keyManagementParameters) { - throw new TypeError('setKeyManagementParameters can only be called once'); - } - this._keyManagementParameters = parameters; - return this; - } - setContentEncryptionKey(cek) { - if (this._cek) { - throw new TypeError('setContentEncryptionKey can only be called once'); - } - this._cek = cek; - return this; - } - setInitializationVector(iv) { - if (this._iv) { - throw new TypeError('setInitializationVector can only be called once'); - } - this._iv = iv; - return this; - } - replicateIssuerAsHeader() { - this._replicateIssuerAsHeader = true; - return this; - } - replicateSubjectAsHeader() { - this._replicateSubjectAsHeader = true; - return this; - } - replicateAudienceAsHeader() { - this._replicateAudienceAsHeader = true; - return this; - } - async encrypt(key, options) { - const enc = new encrypt_js_1.default(buffer_utils_js_1.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); - } -} -exports.EncryptJWT = EncryptJWT; -exports.default = EncryptJWT; diff --git a/dist/node/cjs/jwt/sign.js b/dist/node/cjs/jwt/sign.js deleted file mode 100644 index e14fd2d3e1..0000000000 --- a/dist/node/cjs/jwt/sign.js +++ /dev/null @@ -1,26 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.SignJWT = void 0; -const sign_js_1 = require("../jws/compact/sign.js"); -const errors_js_1 = require("../util/errors.js"); -const buffer_utils_js_1 = require("../lib/buffer_utils.js"); -const jwt_producer_js_1 = require("../lib/jwt_producer.js"); -class SignJWT extends jwt_producer_js_1.default { - setProtectedHeader(protectedHeader) { - this._protectedHeader = protectedHeader; - return this; - } - async sign(key, options) { - var _a; - const sig = new sign_js_1.default(buffer_utils_js_1.encoder.encode(JSON.stringify(this._payload))); - sig.setProtectedHeader(this._protectedHeader); - if (Array.isArray((_a = this._protectedHeader) === null || _a === void 0 ? void 0 : _a.crit) && - this._protectedHeader.crit.includes('b64') && - this._protectedHeader.b64 === false) { - throw new errors_js_1.JWTInvalid('JWTs MUST NOT use unencoded payload'); - } - return sig.sign(key, options); - } -} -exports.SignJWT = SignJWT; -exports.default = SignJWT; diff --git a/dist/node/cjs/jwt/unsecured.js b/dist/node/cjs/jwt/unsecured.js deleted file mode 100644 index e48775b877..0000000000 --- a/dist/node/cjs/jwt/unsecured.js +++ /dev/null @@ -1,37 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.UnsecuredJWT = void 0; -const buffer_utils_js_1 = require("../lib/buffer_utils.js"); -const base64url = require("../runtime/base64url.js"); -const errors_js_1 = require("../util/errors.js"); -const jwt_claims_set_js_1 = require("../lib/jwt_claims_set.js"); -const jwt_producer_js_1 = require("../lib/jwt_producer.js"); -class UnsecuredJWT extends jwt_producer_js_1.default { - encode() { - const header = base64url.encode(JSON.stringify({ alg: 'none' })); - const payload = base64url.encode(JSON.stringify(this._payload)); - return `${header}.${payload}.`; - } - static decode(jwt, options) { - if (typeof jwt !== 'string') { - throw new errors_js_1.JWTInvalid('Unsecured JWT must be a string'); - } - const { 0: encodedHeader, 1: encodedPayload, 2: signature, length } = jwt.split('.'); - if (length !== 3 || signature !== '') { - throw new errors_js_1.JWTInvalid('Invalid Unsecured JWT'); - } - let header; - try { - header = JSON.parse(buffer_utils_js_1.decoder.decode(base64url.decode(encodedHeader))); - if (header.alg !== 'none') - throw new Error(); - } - catch { - throw new errors_js_1.JWTInvalid('Invalid Unsecured JWT'); - } - const payload = (0, jwt_claims_set_js_1.default)(header, base64url.decode(encodedPayload), options); - return { payload, header }; - } -} -exports.UnsecuredJWT = UnsecuredJWT; -exports.default = UnsecuredJWT; diff --git a/dist/node/cjs/jwt/verify.js b/dist/node/cjs/jwt/verify.js deleted file mode 100644 index 6c9ad2d024..0000000000 --- a/dist/node/cjs/jwt/verify.js +++ /dev/null @@ -1,17 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.jwtVerify = void 0; -const verify_js_1 = require("../jws/compact/verify.js"); -const jwt_claims_set_js_1 = require("../lib/jwt_claims_set.js"); -const errors_js_1 = require("../util/errors.js"); -async function jwtVerify(jwt, key, options) { - var _a; - const verified = await (0, verify_js_1.default)(jwt, key, options); - if (((_a = verified.protectedHeader.crit) === null || _a === void 0 ? void 0 : _a.includes('b64')) && verified.protectedHeader.b64 === false) { - throw new errors_js_1.JWTInvalid('JWTs MUST NOT use unencoded payload'); - } - const payload = (0, jwt_claims_set_js_1.default)(verified.protectedHeader, verified.payload, options); - return { payload, protectedHeader: verified.protectedHeader }; -} -exports.jwtVerify = jwtVerify; -exports.default = jwtVerify; diff --git a/dist/node/cjs/lib/buffer_utils.js b/dist/node/cjs/lib/buffer_utils.js deleted file mode 100644 index 9a431eb835..0000000000 --- a/dist/node/cjs/lib/buffer_utils.js +++ /dev/null @@ -1,65 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.concatKdf = exports.lengthAndInput = exports.uint32be = exports.uint64be = exports.p2s = exports.concat = exports.decoder = exports.encoder = void 0; -exports.encoder = new TextEncoder(); -exports.decoder = new TextDecoder(); -const MAX_INT32 = 2 ** 32; -function concat(...buffers) { - 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; -} -exports.concat = concat; -function p2s(alg, p2sInput) { - return concat(exports.encoder.encode(alg), new Uint8Array([0]), p2sInput); -} -exports.p2s = p2s; -function writeUInt32BE(buf, value, offset) { - 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); -} -function uint64be(value) { - 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; -} -exports.uint64be = uint64be; -function uint32be(value) { - const buf = new Uint8Array(4); - writeUInt32BE(buf, value); - return buf; -} -exports.uint32be = uint32be; -function lengthAndInput(input) { - return concat(uint32be(input.length), input); -} -exports.lengthAndInput = lengthAndInput; -async function concatKdf(digest, secret, bits, value) { - const iterations = Math.ceil((bits >> 3) / 32); - let res; - 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('sha256', buf); - } - else { - res = concat(res, await digest('sha256', buf)); - } - } - res = res.slice(0, bits >> 3); - return res; -} -exports.concatKdf = concatKdf; diff --git a/dist/node/cjs/lib/cek.js b/dist/node/cjs/lib/cek.js deleted file mode 100644 index 1d6311bb93..0000000000 --- a/dist/node/cjs/lib/cek.js +++ /dev/null @@ -1,21 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.bitLengths = void 0; -const errors_js_1 = require("../util/errors.js"); -const bitLengths = new Map([ - ['A128CBC-HS256', 256], - ['A128GCM', 128], - ['A192CBC-HS384', 384], - ['A192GCM', 192], - ['A256CBC-HS512', 512], - ['A256GCM', 256], -]); -exports.bitLengths = bitLengths; -const factory = (random) => (alg) => { - const bitLength = bitLengths.get(alg); - if (!bitLength) { - throw new errors_js_1.JOSENotSupported(`Unsupported JWE Algorithm: ${alg}`); - } - return random(new Uint8Array(bitLength >> 3)); -}; -exports.default = factory; diff --git a/dist/node/cjs/lib/check_iv_length.js b/dist/node/cjs/lib/check_iv_length.js deleted file mode 100644 index d45f5b8f44..0000000000 --- a/dist/node/cjs/lib/check_iv_length.js +++ /dev/null @@ -1,10 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const errors_js_1 = require("../util/errors.js"); -const iv_js_1 = require("./iv.js"); -const checkIvLength = (enc, iv) => { - if (iv.length << 3 !== iv_js_1.bitLengths.get(enc)) { - throw new errors_js_1.JWEInvalid('Invalid Initialization Vector length'); - } -}; -exports.default = checkIvLength; diff --git a/dist/node/cjs/lib/check_key_type.js b/dist/node/cjs/lib/check_key_type.js deleted file mode 100644 index edeb6c1ffc..0000000000 --- a/dist/node/cjs/lib/check_key_type.js +++ /dev/null @@ -1,30 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const invalid_key_input_js_1 = require("../runtime/invalid_key_input.js"); -const checkKeyType = (alg, key, usage) => { - if (!(key instanceof Uint8Array) && !(key === null || key === void 0 ? void 0 : key.type)) { - throw new TypeError((0, invalid_key_input_js_1.default)(key, 'KeyObject', 'CryptoKey', 'Uint8Array')); - } - 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((0, invalid_key_input_js_1.default)(key, 'KeyObject', 'CryptoKey')); - } - if (key.type === 'secret') { - throw new TypeError('CryptoKey or KeyObject instances for asymmetric algorithms must not be of type "secret"'); - } - if (usage === 'sign' && key.type === 'public') { - throw new TypeError('CryptoKey or KeyObject instances for asymmetric algorithm signing must be of type "private"'); - } - if (usage === 'decrypt' && key.type === 'public') { - throw new TypeError('CryptoKey or KeyObject instances for asymmetric algorithm decryption must be of type "private"'); - } -}; -exports.default = checkKeyType; diff --git a/dist/node/cjs/lib/check_p2s.js b/dist/node/cjs/lib/check_p2s.js deleted file mode 100644 index 4bdeaa766c..0000000000 --- a/dist/node/cjs/lib/check_p2s.js +++ /dev/null @@ -1,9 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const errors_js_1 = require("../util/errors.js"); -function checkP2s(p2s) { - if (!(p2s instanceof Uint8Array) || p2s.length < 8) { - throw new errors_js_1.JWEInvalid('PBES2 Salt Input must be 8 or more octets'); - } -} -exports.default = checkP2s; diff --git a/dist/node/cjs/lib/decrypt_key_management.js b/dist/node/cjs/lib/decrypt_key_management.js deleted file mode 100644 index 4f83b7c135..0000000000 --- a/dist/node/cjs/lib/decrypt_key_management.js +++ /dev/null @@ -1,97 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const errors_js_1 = require("../util/errors.js"); -const aeskw_js_1 = require("../runtime/aeskw.js"); -const ECDH = require("../runtime/ecdhes.js"); -const pbes2kw_js_1 = require("../runtime/pbes2kw.js"); -const rsaes_js_1 = require("../runtime/rsaes.js"); -const aesgcmkw_js_1 = require("../runtime/aesgcmkw.js"); -const base64url_js_1 = require("../runtime/base64url.js"); -const cek_js_1 = require("../lib/cek.js"); -const parse_js_1 = require("../jwk/parse.js"); -const check_key_type_js_1 = require("./check_key_type.js"); -function assertEnryptedKey(encryptedKey) { - if (!encryptedKey) { - throw new errors_js_1.JWEInvalid('JWE Encrypted Key missing'); - } -} -function assertHeaderParameter(joseHeader, parameter, name) { - if (joseHeader[parameter] === undefined) { - throw new errors_js_1.JWEInvalid(`JOSE Header ${name} (${parameter}) missing`); - } -} -async function decryptKeyManagement(alg, key, encryptedKey, joseHeader) { - (0, check_key_type_js_1.default)(alg, key, 'decrypt'); - switch (alg) { - case 'dir': { - if (encryptedKey !== undefined) { - throw new errors_js_1.JWEInvalid('Encountered unexpected JWE Encrypted Key'); - } - return key; - } - case 'ECDH-ES': - if (encryptedKey !== undefined) { - throw new errors_js_1.JWEInvalid('Encountered unexpected JWE Encrypted Key'); - } - case 'ECDH-ES+A128KW': - case 'ECDH-ES+A192KW': - case 'ECDH-ES+A256KW': { - assertHeaderParameter(joseHeader, 'epk', 'Ephemeral Public Key'); - if (!ECDH.ecdhAllowed(key)) { - throw new errors_js_1.JOSENotSupported('ECDH-ES with the provided key is not allowed or not supported by your javascript runtime'); - } - const epk = await (0, parse_js_1.parseJwk)(joseHeader.epk, alg); - let partyUInfo; - let partyVInfo; - if (joseHeader.apu !== undefined) - partyUInfo = (0, base64url_js_1.decode)(joseHeader.apu); - if (joseHeader.apv !== undefined) - partyVInfo = (0, base64url_js_1.decode)(joseHeader.apv); - const sharedSecret = await ECDH.deriveKey(epk, key, alg === 'ECDH-ES' ? joseHeader.enc : alg, parseInt(alg.substr(-5, 3), 10) || cek_js_1.bitLengths.get(joseHeader.enc), partyUInfo, partyVInfo); - if (alg === 'ECDH-ES') { - return sharedSecret; - } - assertEnryptedKey(encryptedKey); - const kwAlg = alg.substr(-6); - return (0, aeskw_js_1.unwrap)(kwAlg, sharedSecret, encryptedKey); - } - case 'RSA1_5': - case 'RSA-OAEP': - case 'RSA-OAEP-256': - case 'RSA-OAEP-384': - case 'RSA-OAEP-512': { - assertEnryptedKey(encryptedKey); - return (0, rsaes_js_1.decrypt)(alg, key, encryptedKey); - } - case 'PBES2-HS256+A128KW': - case 'PBES2-HS384+A192KW': - case 'PBES2-HS512+A256KW': { - assertEnryptedKey(encryptedKey); - assertHeaderParameter(joseHeader, 'p2c', 'PBES2 Count'); - assertHeaderParameter(joseHeader, 'p2s', 'PBES2 Salt'); - const { p2c } = joseHeader; - const p2s = (0, base64url_js_1.decode)(joseHeader.p2s); - return (0, pbes2kw_js_1.decrypt)(alg, key, encryptedKey, p2c, p2s); - } - case 'A128KW': - case 'A192KW': - case 'A256KW': { - assertEnryptedKey(encryptedKey); - return (0, aeskw_js_1.unwrap)(alg, key, encryptedKey); - } - case 'A128GCMKW': - case 'A192GCMKW': - case 'A256GCMKW': { - assertEnryptedKey(encryptedKey); - assertHeaderParameter(joseHeader, 'iv', 'Initialization Vector'); - assertHeaderParameter(joseHeader, 'tag', 'Authentication Tag'); - const iv = (0, base64url_js_1.decode)(joseHeader.iv); - const tag = (0, base64url_js_1.decode)(joseHeader.tag); - return (0, aesgcmkw_js_1.unwrap)(alg, key, encryptedKey, iv, tag); - } - default: { - throw new errors_js_1.JOSENotSupported('unsupported or invalid "alg" (JWE Algorithm) header value'); - } - } -} -exports.default = decryptKeyManagement; diff --git a/dist/node/cjs/lib/encrypt_key_management.js b/dist/node/cjs/lib/encrypt_key_management.js deleted file mode 100644 index 212f707750..0000000000 --- a/dist/node/cjs/lib/encrypt_key_management.js +++ /dev/null @@ -1,89 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const cek_js_1 = require("../lib/cek.js"); -const errors_js_1 = require("../util/errors.js"); -const random_js_1 = require("../runtime/random.js"); -const aeskw_js_1 = require("../runtime/aeskw.js"); -const ECDH = require("../runtime/ecdhes.js"); -const pbes2kw_js_1 = require("../runtime/pbes2kw.js"); -const rsaes_js_1 = require("../runtime/rsaes.js"); -const aesgcmkw_js_1 = require("../runtime/aesgcmkw.js"); -const base64url_js_1 = require("../runtime/base64url.js"); -const from_key_like_js_1 = require("../jwk/from_key_like.js"); -const check_key_type_js_1 = require("./check_key_type.js"); -const generateCek = (0, cek_js_1.default)(random_js_1.default); -async function encryptKeyManagement(alg, enc, key, providedCek, providedParameters = {}) { - let encryptedKey; - let parameters; - let cek; - (0, check_key_type_js_1.default)(alg, key, 'encrypt'); - switch (alg) { - case 'dir': { - cek = key; - break; - } - case 'ECDH-ES': - case 'ECDH-ES+A128KW': - case 'ECDH-ES+A192KW': - case 'ECDH-ES+A256KW': { - if (!ECDH.ecdhAllowed(key)) { - throw new errors_js_1.JOSENotSupported('ECDH-ES with the provided key is not allowed or not supported by your javascript runtime'); - } - const { apu, apv } = providedParameters; - let { epk: ephemeralKey } = providedParameters; - ephemeralKey || (ephemeralKey = await ECDH.generateEpk(key)); - const { x, y, crv, kty } = await (0, from_key_like_js_1.fromKeyLike)(ephemeralKey); - const sharedSecret = await ECDH.deriveKey(key, ephemeralKey, alg === 'ECDH-ES' ? enc : alg, parseInt(alg.substr(-5, 3), 10) || cek_js_1.bitLengths.get(enc), apu, apv); - parameters = { epk: { x, y, crv, kty } }; - if (apu) - parameters.apu = (0, base64url_js_1.encode)(apu); - if (apv) - parameters.apv = (0, base64url_js_1.encode)(apv); - if (alg === 'ECDH-ES') { - cek = sharedSecret; - break; - } - cek = providedCek || generateCek(enc); - const kwAlg = alg.substr(-6); - encryptedKey = await (0, aeskw_js_1.wrap)(kwAlg, sharedSecret, cek); - break; - } - case 'RSA1_5': - case 'RSA-OAEP': - case 'RSA-OAEP-256': - case 'RSA-OAEP-384': - case 'RSA-OAEP-512': { - cek = providedCek || generateCek(enc); - encryptedKey = await (0, rsaes_js_1.encrypt)(alg, key, cek); - break; - } - case 'PBES2-HS256+A128KW': - case 'PBES2-HS384+A192KW': - case 'PBES2-HS512+A256KW': { - cek = providedCek || generateCek(enc); - const { p2c, p2s } = providedParameters; - ({ encryptedKey, ...parameters } = await (0, pbes2kw_js_1.encrypt)(alg, key, cek, p2c, p2s)); - break; - } - case 'A128KW': - case 'A192KW': - case 'A256KW': { - cek = providedCek || generateCek(enc); - encryptedKey = await (0, aeskw_js_1.wrap)(alg, key, cek); - break; - } - case 'A128GCMKW': - case 'A192GCMKW': - case 'A256GCMKW': { - cek = providedCek || generateCek(enc); - const { iv } = providedParameters; - ({ encryptedKey, ...parameters } = await (0, aesgcmkw_js_1.wrap)(alg, key, cek, iv)); - break; - } - default: { - throw new errors_js_1.JOSENotSupported('unsupported or invalid "alg" (JWE Algorithm) header value'); - } - } - return { cek, encryptedKey, parameters }; -} -exports.default = encryptKeyManagement; diff --git a/dist/node/cjs/lib/epoch.js b/dist/node/cjs/lib/epoch.js deleted file mode 100644 index a0792b4f7f..0000000000 --- a/dist/node/cjs/lib/epoch.js +++ /dev/null @@ -1,3 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = (date) => Math.floor(date.getTime() / 1000); diff --git a/dist/node/cjs/lib/is_disjoint.js b/dist/node/cjs/lib/is_disjoint.js deleted file mode 100644 index 66c2fc6c82..0000000000 --- a/dist/node/cjs/lib/is_disjoint.js +++ /dev/null @@ -1,24 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const isDisjoint = (...headers) => { - const sources = headers.filter(Boolean); - if (sources.length === 0 || sources.length === 1) { - return true; - } - let acc; - 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; -}; -exports.default = isDisjoint; diff --git a/dist/node/cjs/lib/is_object.js b/dist/node/cjs/lib/is_object.js deleted file mode 100644 index 870938b59b..0000000000 --- a/dist/node/cjs/lib/is_object.js +++ /dev/null @@ -1,19 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -function isObjectLike(value) { - return typeof value === 'object' && value !== null; -} -function isObject(input) { - if (!isObjectLike(input) || Object.prototype.toString.call(input) !== '[object Object]') { - return false; - } - if (Object.getPrototypeOf(input) === null) { - return true; - } - let proto = input; - while (Object.getPrototypeOf(proto) !== null) { - proto = Object.getPrototypeOf(proto); - } - return Object.getPrototypeOf(input) === proto; -} -exports.default = isObject; diff --git a/dist/node/cjs/lib/iv.js b/dist/node/cjs/lib/iv.js deleted file mode 100644 index a57ae9cfd3..0000000000 --- a/dist/node/cjs/lib/iv.js +++ /dev/null @@ -1,24 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.bitLengths = void 0; -const errors_js_1 = require("../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], -]); -exports.bitLengths = bitLengths; -const factory = (random) => (alg) => { - const bitLength = bitLengths.get(alg); - if (!bitLength) { - throw new errors_js_1.JOSENotSupported(`Unsupported JWE Algorithm: ${alg}`); - } - return random(new Uint8Array(bitLength >> 3)); -}; -exports.default = factory; diff --git a/dist/node/cjs/lib/jwt_claims_set.js b/dist/node/cjs/lib/jwt_claims_set.js deleted file mode 100644 index 3b9e317604..0000000000 --- a/dist/node/cjs/lib/jwt_claims_set.js +++ /dev/null @@ -1,98 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const errors_js_1 = require("../util/errors.js"); -const buffer_utils_js_1 = require("./buffer_utils.js"); -const epoch_js_1 = require("./epoch.js"); -const secs_js_1 = require("./secs.js"); -const is_object_js_1 = require("./is_object.js"); -const normalizeTyp = (value) => value.toLowerCase().replace(/^application\//, ''); -const checkAudiencePresence = (audPayload, audOption) => { - if (typeof audPayload === 'string') { - return audOption.includes(audPayload); - } - if (Array.isArray(audPayload)) { - return audOption.some(Set.prototype.has.bind(new Set(audPayload))); - } - return false; -}; -exports.default = (protectedHeader, encodedPayload, options = {}) => { - const { typ } = options; - if (typ && - (typeof protectedHeader.typ !== 'string' || - normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ))) { - throw new errors_js_1.JWTClaimValidationFailed('unexpected "typ" JWT header value', 'typ', 'check_failed'); - } - let payload; - try { - payload = JSON.parse(buffer_utils_js_1.decoder.decode(encodedPayload)); - } - catch { - } - if (!(0, is_object_js_1.default)(payload)) { - throw new errors_js_1.JWTInvalid('JWT Claims Set must be a top-level JSON object'); - } - const { issuer } = options; - if (issuer && !(Array.isArray(issuer) ? issuer : [issuer]).includes(payload.iss)) { - throw new errors_js_1.JWTClaimValidationFailed('unexpected "iss" claim value', 'iss', 'check_failed'); - } - const { subject } = options; - if (subject && payload.sub !== subject) { - throw new errors_js_1.JWTClaimValidationFailed('unexpected "sub" claim value', 'sub', 'check_failed'); - } - const { audience } = options; - if (audience && - !checkAudiencePresence(payload.aud, typeof audience === 'string' ? [audience] : audience)) { - throw new errors_js_1.JWTClaimValidationFailed('unexpected "aud" claim value', 'aud', 'check_failed'); - } - let tolerance; - switch (typeof options.clockTolerance) { - case 'string': - tolerance = (0, secs_js_1.default)(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 = (0, epoch_js_1.default)(currentDate || new Date()); - if (payload.iat !== undefined || options.maxTokenAge) { - if (typeof payload.iat !== 'number') { - throw new errors_js_1.JWTClaimValidationFailed('"iat" claim must be a number', 'iat', 'invalid'); - } - if (payload.exp === undefined && payload.iat > now + tolerance) { - throw new errors_js_1.JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', 'iat', 'check_failed'); - } - } - if (payload.nbf !== undefined) { - if (typeof payload.nbf !== 'number') { - throw new errors_js_1.JWTClaimValidationFailed('"nbf" claim must be a number', 'nbf', 'invalid'); - } - if (payload.nbf > now + tolerance) { - throw new errors_js_1.JWTClaimValidationFailed('"nbf" claim timestamp check failed', 'nbf', 'check_failed'); - } - } - if (payload.exp !== undefined) { - if (typeof payload.exp !== 'number') { - throw new errors_js_1.JWTClaimValidationFailed('"exp" claim must be a number', 'exp', 'invalid'); - } - if (payload.exp <= now - tolerance) { - throw new errors_js_1.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 : (0, secs_js_1.default)(options.maxTokenAge); - if (age - tolerance > max) { - throw new errors_js_1.JWTExpired('"iat" claim timestamp check failed (too far in the past)', 'iat', 'check_failed'); - } - if (age < 0 - tolerance) { - throw new errors_js_1.JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', 'iat', 'check_failed'); - } - } - return payload; -}; diff --git a/dist/node/cjs/lib/jwt_producer.js b/dist/node/cjs/lib/jwt_producer.js deleted file mode 100644 index 57ab4d9b5f..0000000000 --- a/dist/node/cjs/lib/jwt_producer.js +++ /dev/null @@ -1,57 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const epoch_js_1 = require("./epoch.js"); -const is_object_js_1 = require("./is_object.js"); -const secs_js_1 = require("./secs.js"); -class ProduceJWT { - constructor(payload) { - if (!(0, is_object_js_1.default)(payload)) { - throw new TypeError('JWT Claims Set MUST be an object'); - } - this._payload = payload; - } - setIssuer(issuer) { - this._payload = { ...this._payload, iss: issuer }; - return this; - } - setSubject(subject) { - this._payload = { ...this._payload, sub: subject }; - return this; - } - setAudience(audience) { - this._payload = { ...this._payload, aud: audience }; - return this; - } - setJti(jwtId) { - this._payload = { ...this._payload, jti: jwtId }; - return this; - } - setNotBefore(input) { - if (typeof input === 'number') { - this._payload = { ...this._payload, nbf: input }; - } - else { - this._payload = { ...this._payload, nbf: (0, epoch_js_1.default)(new Date()) + (0, secs_js_1.default)(input) }; - } - return this; - } - setExpirationTime(input) { - if (typeof input === 'number') { - this._payload = { ...this._payload, exp: input }; - } - else { - this._payload = { ...this._payload, exp: (0, epoch_js_1.default)(new Date()) + (0, secs_js_1.default)(input) }; - } - return this; - } - setIssuedAt(input) { - if (typeof input === 'undefined') { - this._payload = { ...this._payload, iat: (0, epoch_js_1.default)(new Date()) }; - } - else { - this._payload = { ...this._payload, iat: input }; - } - return this; - } -} -exports.default = ProduceJWT; diff --git a/dist/node/cjs/lib/secs.js b/dist/node/cjs/lib/secs.js deleted file mode 100644 index f1b6a0c15d..0000000000 --- a/dist/node/cjs/lib/secs.js +++ /dev/null @@ -1,46 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const minute = 60; -const hour = minute * 60; -const day = hour * 24; -const week = day * 7; -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; -exports.default = (str) => { - const matched = REGEX.exec(str); - if (!matched) { - throw new TypeError('Invalid time period format'); - } - const value = parseFloat(matched[1]); - const unit = matched[2].toLowerCase(); - switch (unit) { - case 'sec': - case 'secs': - case 'second': - case 'seconds': - case 's': - return Math.round(value); - case 'minute': - case 'minutes': - case 'min': - case 'mins': - case 'm': - return Math.round(value * minute); - case 'hour': - case 'hours': - case 'hr': - case 'hrs': - case 'h': - return Math.round(value * hour); - case 'day': - case 'days': - case 'd': - return Math.round(value * day); - case 'week': - case 'weeks': - case 'w': - return Math.round(value * week); - default: - return Math.round(value * year); - } -}; diff --git a/dist/node/cjs/lib/validate_algorithms.js b/dist/node/cjs/lib/validate_algorithms.js deleted file mode 100644 index 29f4e80df9..0000000000 --- a/dist/node/cjs/lib/validate_algorithms.js +++ /dev/null @@ -1,13 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const validateAlgorithms = (option, algorithms) => { - 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); -}; -exports.default = validateAlgorithms; diff --git a/dist/node/cjs/lib/validate_crit.js b/dist/node/cjs/lib/validate_crit.js deleted file mode 100644 index b0229e3b72..0000000000 --- a/dist/node/cjs/lib/validate_crit.js +++ /dev/null @@ -1,36 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const errors_js_1 = require("../util/errors.js"); -function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) { - if (joseHeader.crit !== undefined && protectedHeader.crit === undefined) { - throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected'); - } - if (!protectedHeader || protectedHeader.crit === undefined) { - return new Set(); - } - if (!Array.isArray(protectedHeader.crit) || - protectedHeader.crit.length === 0 || - protectedHeader.crit.some((input) => typeof input !== 'string' || input.length === 0)) { - throw new Err('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present'); - } - let recognized; - if (recognizedOption !== undefined) { - recognized = new Map([...Object.entries(recognizedOption), ...recognizedDefault.entries()]); - } - else { - recognized = recognizedDefault; - } - for (const parameter of protectedHeader.crit) { - if (!recognized.has(parameter)) { - throw new errors_js_1.JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`); - } - if (joseHeader[parameter] === undefined) { - throw new Err(`Extension Header Parameter "${parameter}" is missing`); - } - else if (recognized.get(parameter) && protectedHeader[parameter] === undefined) { - throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`); - } - } - return new Set(protectedHeader.crit); -} -exports.default = validateCrit; diff --git a/dist/node/cjs/runtime/aesgcmkw.js b/dist/node/cjs/runtime/aesgcmkw.js deleted file mode 100644 index b3ab6c04f7..0000000000 --- a/dist/node/cjs/runtime/aesgcmkw.js +++ /dev/null @@ -1,21 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.unwrap = exports.wrap = void 0; -const encrypt_js_1 = require("./encrypt.js"); -const decrypt_js_1 = require("./decrypt.js"); -const iv_js_1 = require("../lib/iv.js"); -const random_js_1 = require("./random.js"); -const base64url_js_1 = require("./base64url.js"); -const generateIv = (0, iv_js_1.default)(random_js_1.default); -const wrap = async (alg, key, cek, iv) => { - const jweAlgorithm = alg.substr(0, 7); - iv || (iv = generateIv(jweAlgorithm)); - const { ciphertext: encryptedKey, tag } = await (0, encrypt_js_1.default)(jweAlgorithm, cek, key, iv, new Uint8Array(0)); - return { encryptedKey, iv: (0, base64url_js_1.encode)(iv), tag: (0, base64url_js_1.encode)(tag) }; -}; -exports.wrap = wrap; -const unwrap = async (alg, key, encryptedKey, iv, tag) => { - const jweAlgorithm = alg.substr(0, 7); - return (0, decrypt_js_1.default)(jweAlgorithm, key, encryptedKey, iv, tag, new Uint8Array(0)); -}; -exports.unwrap = unwrap; diff --git a/dist/node/cjs/runtime/aeskw.js b/dist/node/cjs/runtime/aeskw.js deleted file mode 100644 index 78d7ff2a16..0000000000 --- a/dist/node/cjs/runtime/aeskw.js +++ /dev/null @@ -1,52 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.unwrap = exports.wrap = void 0; -const crypto_1 = require("crypto"); -const errors_js_1 = require("../util/errors.js"); -const buffer_utils_js_1 = require("../lib/buffer_utils.js"); -const secret_key_js_1 = require("./secret_key.js"); -const webcrypto_js_1 = require("./webcrypto.js"); -const is_key_object_js_1 = require("./is_key_object.js"); -const invalid_key_input_js_1 = require("./invalid_key_input.js"); -const ciphers_js_1 = require("./ciphers.js"); -function checkKeySize(key, alg) { - if (key.symmetricKeySize << 3 !== parseInt(alg.substr(1, 3), 10)) { - throw new TypeError(`invalid key size for alg: ${alg}`); - } -} -function ensureKeyObject(key, alg, usage) { - if ((0, is_key_object_js_1.default)(key)) { - return key; - } - if (key instanceof Uint8Array) { - return (0, secret_key_js_1.default)(key); - } - if ((0, webcrypto_js_1.isCryptoKey)(key)) { - return (0, webcrypto_js_1.getKeyObject)(key, alg, new Set([usage])); - } - throw new TypeError((0, invalid_key_input_js_1.default)(key, 'KeyObject', 'CryptoKey', 'Uint8Array')); -} -const wrap = async (alg, key, cek) => { - const size = parseInt(alg.substr(1, 3), 10); - const algorithm = `aes${size}-wrap`; - if (!(0, ciphers_js_1.default)(algorithm)) { - throw new errors_js_1.JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`); - } - const keyObject = ensureKeyObject(key, alg, 'wrapKey'); - checkKeySize(keyObject, alg); - const cipher = (0, crypto_1.createCipheriv)(algorithm, keyObject, Buffer.alloc(8, 0xa6)); - return (0, buffer_utils_js_1.concat)(cipher.update(cek), cipher.final()); -}; -exports.wrap = wrap; -const unwrap = async (alg, key, encryptedKey) => { - const size = parseInt(alg.substr(1, 3), 10); - const algorithm = `aes${size}-wrap`; - if (!(0, ciphers_js_1.default)(algorithm)) { - throw new errors_js_1.JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`); - } - const keyObject = ensureKeyObject(key, alg, 'unwrapKey'); - checkKeySize(keyObject, alg); - const cipher = (0, crypto_1.createDecipheriv)(algorithm, keyObject, Buffer.alloc(8, 0xa6)); - return (0, buffer_utils_js_1.concat)(cipher.update(encryptedKey), cipher.final()); -}; -exports.unwrap = unwrap; diff --git a/dist/node/cjs/runtime/asn1_sequence_decoder.js b/dist/node/cjs/runtime/asn1_sequence_decoder.js deleted file mode 100644 index 4f96522335..0000000000 --- a/dist/node/cjs/runtime/asn1_sequence_decoder.js +++ /dev/null @@ -1,47 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const tagInteger = 0x02; -const tagSequence = 0x30; -class Asn1SequenceDecoder { - constructor(buffer) { - if (buffer[0] !== tagSequence) { - throw new TypeError(); - } - this.buffer = buffer; - this.offset = 1; - const len = this.decodeLength(); - if (len !== buffer.length - this.offset) { - throw new TypeError(); - } - } - decodeLength() { - let length = this.buffer[this.offset++]; - if (length & 0x80) { - const nBytes = length & ~0x80; - length = 0; - for (let i = 0; i < nBytes; i++) - length = (length << 8) | this.buffer[this.offset + i]; - this.offset += nBytes; - } - return length; - } - unsignedInteger() { - if (this.buffer[this.offset++] !== tagInteger) { - throw new TypeError(); - } - let length = this.decodeLength(); - if (this.buffer[this.offset] === 0) { - this.offset++; - length--; - } - const result = this.buffer.slice(this.offset, this.offset + length); - this.offset += length; - return result; - } - end() { - if (this.offset !== this.buffer.length) { - throw new TypeError(); - } - } -} -exports.default = Asn1SequenceDecoder; diff --git a/dist/node/cjs/runtime/asn1_sequence_encoder.js b/dist/node/cjs/runtime/asn1_sequence_encoder.js deleted file mode 100644 index f980e4ac2d..0000000000 --- a/dist/node/cjs/runtime/asn1_sequence_encoder.js +++ /dev/null @@ -1,90 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const errors_js_1 = require("../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) => { - 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')], -]); -class DumbAsn1Encoder { - constructor() { - this.length = 0; - this.elements = []; - } - oidFor(oid) { - const bOid = oids.get(oid); - if (!bOid) { - throw new errors_js_1.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) { - 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) { - const len = encodeLength(octStr.length); - this.elements.push(bTagOctStr, encodeLength(octStr.length), octStr); - this.length += 1 + len.length + octStr.length; - } - bitStr(bitS) { - 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) { - 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); - } -} -exports.default = DumbAsn1Encoder; diff --git a/dist/node/cjs/runtime/base64url.js b/dist/node/cjs/runtime/base64url.js deleted file mode 100644 index f637a16750..0000000000 --- a/dist/node/cjs/runtime/base64url.js +++ /dev/null @@ -1,21 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.decode = exports.encode = void 0; -const buffer_utils_js_1 = require("../lib/buffer_utils.js"); -let encodeImpl; -function normalize(input) { - let encoded = input; - if (encoded instanceof Uint8Array) { - encoded = buffer_utils_js_1.decoder.decode(encoded); - } - return encoded; -} -if (Buffer.isEncoding('base64url')) { - encodeImpl = (input) => Buffer.from(input).toString('base64url'); -} -else { - encodeImpl = (input) => Buffer.from(input).toString('base64').replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_'); -} -exports.encode = encodeImpl; -const decode = (input) => Buffer.from(normalize(input), 'base64'); -exports.decode = decode; diff --git a/dist/node/cjs/runtime/cbc_tag.js b/dist/node/cjs/runtime/cbc_tag.js deleted file mode 100644 index 03412c2cfb..0000000000 --- a/dist/node/cjs/runtime/cbc_tag.js +++ /dev/null @@ -1,11 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const crypto_1 = require("crypto"); -const buffer_utils_js_1 = require("../lib/buffer_utils.js"); -function cbcTag(aad, iv, ciphertext, macSize, macKey, keySize) { - const macData = (0, buffer_utils_js_1.concat)(aad, iv, ciphertext, (0, buffer_utils_js_1.uint64be)(aad.length << 3)); - const hmac = (0, crypto_1.createHmac)(`sha${macSize}`, macKey); - hmac.update(macData); - return hmac.digest().slice(0, keySize >> 3); -} -exports.default = cbcTag; diff --git a/dist/node/cjs/runtime/check_cek_length.js b/dist/node/cjs/runtime/check_cek_length.js deleted file mode 100644 index 360f1be7a6..0000000000 --- a/dist/node/cjs/runtime/check_cek_length.js +++ /dev/null @@ -1,35 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const errors_js_1 = require("../util/errors.js"); -const is_key_object_js_1 = require("./is_key_object.js"); -const checkCekLength = (enc, cek) => { - let expected; - 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 errors_js_1.JOSENotSupported(`Content Encryption Algorithm ${enc} is not supported either by JOSE or your javascript runtime`); - } - if (cek instanceof Uint8Array) { - if (cek.length << 3 !== expected) { - throw new errors_js_1.JWEInvalid('Invalid Content Encryption Key length'); - } - return; - } - if ((0, is_key_object_js_1.default)(cek) && cek.type === 'secret') { - if (cek.symmetricKeySize << 3 !== expected) { - throw new errors_js_1.JWEInvalid('Invalid Content Encryption Key length'); - } - return; - } - throw new TypeError('Invalid Content Encryption Key type'); -}; -exports.default = checkCekLength; diff --git a/dist/node/cjs/runtime/check_modulus_length.js b/dist/node/cjs/runtime/check_modulus_length.js deleted file mode 100644 index 72c670eba3..0000000000 --- a/dist/node/cjs/runtime/check_modulus_length.js +++ /dev/null @@ -1,52 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.setModulusLength = exports.weakMap = void 0; -exports.weakMap = new WeakMap(); -const getLength = (buf, index) => { - let len = buf.readUInt8(1); - if ((len & 0x80) === 0) { - if (index === 0) { - return len; - } - return getLength(buf.subarray(2 + len), index - 1); - } - 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, index) => { - const len = sequence.readUInt8(1); - if ((len & 0x80) === 0) { - return getLength(sequence.subarray(2), index); - } - const num = len & 0x7f; - return getLength(sequence.subarray(2 + num), index); -}; -const getModulusLength = (key) => { - var _a, _b; - if (exports.weakMap.has(key)) { - return exports.weakMap.get(key); - } - const modulusLength = (_b = (_a = key.asymmetricKeyDetails) === null || _a === void 0 ? void 0 : _a.modulusLength) !== null && _b !== void 0 ? _b : (getLengthOfSeqIndex(key.export({ format: 'der', type: 'pkcs1' }), key.type === 'private' ? 1 : 0) - - 1) << - 3; - exports.weakMap.set(key, modulusLength); - return modulusLength; -}; -const setModulusLength = (keyObject, modulusLength) => { - exports.weakMap.set(keyObject, modulusLength); -}; -exports.setModulusLength = setModulusLength; -exports.default = (key, alg) => { - if (getModulusLength(key) < 2048) { - throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`); - } -}; diff --git a/dist/node/cjs/runtime/ciphers.js b/dist/node/cjs/runtime/ciphers.js deleted file mode 100644 index e004c84562..0000000000 --- a/dist/node/cjs/runtime/ciphers.js +++ /dev/null @@ -1,8 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const crypto_1 = require("crypto"); -let ciphers; -exports.default = (algorithm) => { - ciphers || (ciphers = new Set((0, crypto_1.getCiphers)())); - return ciphers.has(algorithm); -}; diff --git a/dist/node/cjs/runtime/decrypt.js b/dist/node/cjs/runtime/decrypt.js deleted file mode 100644 index bad1e1217b..0000000000 --- a/dist/node/cjs/runtime/decrypt.js +++ /dev/null @@ -1,92 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const crypto_1 = require("crypto"); -const check_iv_length_js_1 = require("../lib/check_iv_length.js"); -const check_cek_length_js_1 = require("./check_cek_length.js"); -const buffer_utils_js_1 = require("../lib/buffer_utils.js"); -const errors_js_1 = require("../util/errors.js"); -const timing_safe_equal_js_1 = require("./timing_safe_equal.js"); -const cbc_tag_js_1 = require("./cbc_tag.js"); -const webcrypto_js_1 = require("./webcrypto.js"); -const is_key_object_js_1 = require("./is_key_object.js"); -const invalid_key_input_js_1 = require("./invalid_key_input.js"); -const ciphers_js_1 = require("./ciphers.js"); -async function cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) { - const keySize = parseInt(enc.substr(1, 3), 10); - if ((0, is_key_object_js_1.default)(cek)) { - cek = cek.export(); - } - const encKey = cek.subarray(keySize >> 3); - const macKey = cek.subarray(0, keySize >> 3); - const macSize = parseInt(enc.substr(-3), 10); - const algorithm = `aes-${keySize}-cbc`; - if (!(0, ciphers_js_1.default)(algorithm)) { - throw new errors_js_1.JOSENotSupported(`alg ${enc} is not supported by your javascript runtime`); - } - const expectedTag = (0, cbc_tag_js_1.default)(aad, iv, ciphertext, macSize, macKey, keySize); - let macCheckPassed; - try { - macCheckPassed = (0, timing_safe_equal_js_1.default)(tag, expectedTag); - } - catch { - } - if (!macCheckPassed) { - throw new errors_js_1.JWEDecryptionFailed(); - } - let plaintext; - try { - const cipher = (0, crypto_1.createDecipheriv)(algorithm, encKey, iv); - plaintext = (0, buffer_utils_js_1.concat)(cipher.update(ciphertext), cipher.final()); - } - catch { - } - if (!plaintext) { - throw new errors_js_1.JWEDecryptionFailed(); - } - return plaintext; -} -async function gcmDecrypt(enc, cek, ciphertext, iv, tag, aad) { - const keySize = parseInt(enc.substr(1, 3), 10); - const algorithm = `aes-${keySize}-gcm`; - if (!(0, ciphers_js_1.default)(algorithm)) { - throw new errors_js_1.JOSENotSupported(`alg ${enc} is not supported by your javascript runtime`); - } - try { - const cipher = (0, crypto_1.createDecipheriv)(algorithm, cek, iv, { authTagLength: 16 }); - cipher.setAuthTag(tag); - if (aad.byteLength) { - cipher.setAAD(aad, { plaintextLength: ciphertext.length }); - } - return (0, buffer_utils_js_1.concat)(cipher.update(ciphertext), cipher.final()); - } - catch { - throw new errors_js_1.JWEDecryptionFailed(); - } -} -const decrypt = async (enc, cek, ciphertext, iv, tag, aad) => { - let key; - if ((0, webcrypto_js_1.isCryptoKey)(cek)) { - key = (0, webcrypto_js_1.getKeyObject)(cek, enc, new Set(['decrypt'])); - } - else if (cek instanceof Uint8Array || (0, is_key_object_js_1.default)(cek)) { - key = cek; - } - else { - throw new TypeError((0, invalid_key_input_js_1.default)(cek, 'KeyObject', 'CryptoKey', 'Uint8Array')); - } - (0, check_cek_length_js_1.default)(enc, key); - (0, check_iv_length_js_1.default)(enc, iv); - switch (enc) { - case 'A128CBC-HS256': - case 'A192CBC-HS384': - case 'A256CBC-HS512': - return cbcDecrypt(enc, key, ciphertext, iv, tag, aad); - case 'A128GCM': - case 'A192GCM': - case 'A256GCM': - return gcmDecrypt(enc, key, ciphertext, iv, tag, aad); - default: - throw new errors_js_1.JOSENotSupported('unsupported JWE Content Encryption Algorithm'); - } -}; -exports.default = decrypt; diff --git a/dist/node/cjs/runtime/digest.js b/dist/node/cjs/runtime/digest.js deleted file mode 100644 index 13c194a8ed..0000000000 --- a/dist/node/cjs/runtime/digest.js +++ /dev/null @@ -1,5 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const crypto_1 = require("crypto"); -const digest = (algorithm, data) => (0, crypto_1.createHash)(algorithm).update(data).digest(); -exports.default = digest; diff --git a/dist/node/cjs/runtime/dsa_digest.js b/dist/node/cjs/runtime/dsa_digest.js deleted file mode 100644 index fde4883e81..0000000000 --- a/dist/node/cjs/runtime/dsa_digest.js +++ /dev/null @@ -1,25 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const errors_js_1 = require("../util/errors.js"); -function dsaDigest(alg) { - 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 errors_js_1.JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`); - } -} -exports.default = dsaDigest; diff --git a/dist/node/cjs/runtime/ecdhes.js b/dist/node/cjs/runtime/ecdhes.js deleted file mode 100644 index cc3c4f1edc..0000000000 --- a/dist/node/cjs/runtime/ecdhes.js +++ /dev/null @@ -1,55 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.ecdhAllowed = exports.generateEpk = exports.deriveKey = void 0; -const crypto_1 = require("crypto"); -const util_1 = require("util"); -const get_named_curve_js_1 = require("./get_named_curve.js"); -const buffer_utils_js_1 = require("../lib/buffer_utils.js"); -const digest_js_1 = require("./digest.js"); -const errors_js_1 = require("../util/errors.js"); -const webcrypto_js_1 = require("./webcrypto.js"); -const is_key_object_js_1 = require("./is_key_object.js"); -const invalid_key_input_js_1 = require("./invalid_key_input.js"); -const generateKeyPair = (0, util_1.promisify)(crypto_1.generateKeyPair); -const deriveKey = async (publicKey, privateKey, algorithm, keyLength, apu = new Uint8Array(0), apv = new Uint8Array(0)) => { - const value = (0, buffer_utils_js_1.concat)((0, buffer_utils_js_1.lengthAndInput)(buffer_utils_js_1.encoder.encode(algorithm)), (0, buffer_utils_js_1.lengthAndInput)(apu), (0, buffer_utils_js_1.lengthAndInput)(apv), (0, buffer_utils_js_1.uint32be)(keyLength)); - if ((0, webcrypto_js_1.isCryptoKey)(publicKey)) { - publicKey = (0, webcrypto_js_1.getKeyObject)(publicKey, 'ECDH-ES'); - } - if (!(0, is_key_object_js_1.default)(publicKey)) { - throw new TypeError((0, invalid_key_input_js_1.default)(publicKey, 'KeyObject', 'CryptoKey')); - } - if ((0, webcrypto_js_1.isCryptoKey)(privateKey)) { - privateKey = (0, webcrypto_js_1.getKeyObject)(privateKey, 'ECDH-ES', new Set(['deriveBits', 'deriveKey'])); - } - if (!(0, is_key_object_js_1.default)(privateKey)) { - throw new TypeError((0, invalid_key_input_js_1.default)(privateKey, 'KeyObject', 'CryptoKey')); - } - const sharedSecret = (0, crypto_1.diffieHellman)({ privateKey, publicKey }); - return (0, buffer_utils_js_1.concatKdf)(digest_js_1.default, sharedSecret, keyLength, value); -}; -exports.deriveKey = deriveKey; -const generateEpk = async (key) => { - if ((0, webcrypto_js_1.isCryptoKey)(key)) { - key = (0, webcrypto_js_1.getKeyObject)(key); - } - if (!(0, is_key_object_js_1.default)(key)) { - throw new TypeError((0, invalid_key_input_js_1.default)(key, 'KeyObject', 'CryptoKey')); - } - switch (key.asymmetricKeyType) { - case 'x25519': - return (await generateKeyPair('x25519')).privateKey; - case 'x448': { - return (await generateKeyPair('x448')).privateKey; - } - case 'ec': { - const namedCurve = (0, get_named_curve_js_1.default)(key); - return (await generateKeyPair('ec', { namedCurve })).privateKey; - } - default: - throw new errors_js_1.JOSENotSupported('unsupported or invalid EPK'); - } -}; -exports.generateEpk = generateEpk; -const ecdhAllowed = (key) => ['P-256', 'P-384', 'P-521', 'X25519', 'X448'].includes((0, get_named_curve_js_1.default)(key)); -exports.ecdhAllowed = ecdhAllowed; diff --git a/dist/node/cjs/runtime/encrypt.js b/dist/node/cjs/runtime/encrypt.js deleted file mode 100644 index d2c341811f..0000000000 --- a/dist/node/cjs/runtime/encrypt.js +++ /dev/null @@ -1,70 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const crypto_1 = require("crypto"); -const check_iv_length_js_1 = require("../lib/check_iv_length.js"); -const check_cek_length_js_1 = require("./check_cek_length.js"); -const buffer_utils_js_1 = require("../lib/buffer_utils.js"); -const cbc_tag_js_1 = require("./cbc_tag.js"); -const webcrypto_js_1 = require("./webcrypto.js"); -const is_key_object_js_1 = require("./is_key_object.js"); -const invalid_key_input_js_1 = require("./invalid_key_input.js"); -const errors_js_1 = require("../util/errors.js"); -const ciphers_js_1 = require("./ciphers.js"); -async function cbcEncrypt(enc, plaintext, cek, iv, aad) { - const keySize = parseInt(enc.substr(1, 3), 10); - if ((0, is_key_object_js_1.default)(cek)) { - cek = cek.export(); - } - const encKey = cek.subarray(keySize >> 3); - const macKey = cek.subarray(0, keySize >> 3); - const algorithm = `aes-${keySize}-cbc`; - if (!(0, ciphers_js_1.default)(algorithm)) { - throw new errors_js_1.JOSENotSupported(`alg ${enc} is not supported by your javascript runtime`); - } - const cipher = (0, crypto_1.createCipheriv)(algorithm, encKey, iv); - const ciphertext = (0, buffer_utils_js_1.concat)(cipher.update(plaintext), cipher.final()); - const macSize = parseInt(enc.substr(-3), 10); - const tag = (0, cbc_tag_js_1.default)(aad, iv, ciphertext, macSize, macKey, keySize); - return { ciphertext, tag }; -} -async function gcmEncrypt(enc, plaintext, cek, iv, aad) { - const keySize = parseInt(enc.substr(1, 3), 10); - const algorithm = `aes-${keySize}-gcm`; - if (!(0, ciphers_js_1.default)(algorithm)) { - throw new errors_js_1.JOSENotSupported(`alg ${enc} is not supported by your javascript runtime`); - } - const cipher = (0, crypto_1.createCipheriv)(algorithm, cek, iv, { authTagLength: 16 }); - if (aad.byteLength) { - cipher.setAAD(aad, { plaintextLength: plaintext.length }); - } - const ciphertext = (0, buffer_utils_js_1.concat)(cipher.update(plaintext), cipher.final()); - const tag = cipher.getAuthTag(); - return { ciphertext, tag }; -} -const encrypt = async (enc, plaintext, cek, iv, aad) => { - let key; - if ((0, webcrypto_js_1.isCryptoKey)(cek)) { - key = (0, webcrypto_js_1.getKeyObject)(cek, enc, new Set(['encrypt'])); - } - else if (cek instanceof Uint8Array || (0, is_key_object_js_1.default)(cek)) { - key = cek; - } - else { - throw new TypeError((0, invalid_key_input_js_1.default)(cek, 'KeyObject', 'CryptoKey', 'Uint8Array')); - } - (0, check_cek_length_js_1.default)(enc, key); - (0, check_iv_length_js_1.default)(enc, iv); - switch (enc) { - case 'A128CBC-HS256': - case 'A192CBC-HS384': - case 'A256CBC-HS512': - return cbcEncrypt(enc, plaintext, key, iv, aad); - case 'A128GCM': - case 'A192GCM': - case 'A256GCM': - return gcmEncrypt(enc, plaintext, key, iv, aad); - default: - throw new errors_js_1.JOSENotSupported('unsupported JWE Content Encryption Algorithm'); - } -}; -exports.default = encrypt; diff --git a/dist/node/cjs/runtime/fetch_jwks.js b/dist/node/cjs/runtime/fetch_jwks.js deleted file mode 100644 index 4ec863ccb0..0000000000 --- a/dist/node/cjs/runtime/fetch_jwks.js +++ /dev/null @@ -1,36 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const http_1 = require("http"); -const https_1 = require("https"); -const events_1 = require("events"); -const errors_js_1 = require("../util/errors.js"); -const buffer_utils_js_1 = require("../lib/buffer_utils.js"); -const protocols = { - 'https:': https_1.get, - 'http:': http_1.get, -}; -const fetchJwks = async (url, timeout, options) => { - if (protocols[url.protocol] === undefined) { - throw new TypeError('Unsupported URL protocol.'); - } - const { agent } = options; - const req = protocols[url.protocol](url.href, { - agent, - timeout, - }); - const [response] = await (0, events_1.once)(req, 'response'); - if (response.statusCode !== 200) { - throw new errors_js_1.JOSEError('Expected 200 OK from the JSON Web Key Set HTTP response'); - } - const parts = []; - for await (const part of response) { - parts.push(part); - } - try { - return JSON.parse(buffer_utils_js_1.decoder.decode((0, buffer_utils_js_1.concat)(...parts))); - } - catch { - throw new errors_js_1.JOSEError('Failed to parse the JSON Web Key Set HTTP response as JSON'); - } -}; -exports.default = fetchJwks; diff --git a/dist/node/cjs/runtime/generate.js b/dist/node/cjs/runtime/generate.js deleted file mode 100644 index d01f7437da..0000000000 --- a/dist/node/cjs/runtime/generate.js +++ /dev/null @@ -1,104 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.generateKeyPair = exports.generateSecret = void 0; -const crypto_1 = require("crypto"); -const util_1 = require("util"); -const random_js_1 = require("./random.js"); -const check_modulus_length_js_1 = require("./check_modulus_length.js"); -const errors_js_1 = require("../util/errors.js"); -const generate = (0, util_1.promisify)(crypto_1.generateKeyPair); -async function generateSecret(alg, options) { - let length; - 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 errors_js_1.JOSENotSupported('unsupported or invalid JWK "alg" (Algorithm) Parameter value'); - } - return (0, crypto_1.createSecretKey)((0, random_js_1.default)(new Uint8Array(length >> 3))); -} -exports.generateSecret = generateSecret; -async function generateKeyPair(alg, options) { - var _a, _b; - 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': { - const modulusLength = (_a = options === null || options === void 0 ? void 0 : options.modulusLength) !== null && _a !== void 0 ? _a : 2048; - if (typeof modulusLength !== 'number' || modulusLength < 2048) { - throw new errors_js_1.JOSENotSupported('Invalid or unsupported modulusLength option provided, 2048 bits or larger keys must be used'); - } - const keypair = await generate('rsa', { - modulusLength, - publicExponent: 0x10001, - }); - (0, check_modulus_length_js_1.setModulusLength)(keypair.privateKey, modulusLength); - (0, check_modulus_length_js_1.setModulusLength)(keypair.publicKey, modulusLength); - return keypair; - } - 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 === null || options === void 0 ? void 0 : options.crv) { - case undefined: - case 'Ed25519': - return generate('ed25519'); - case 'Ed448': - return generate('ed448'); - default: - throw new errors_js_1.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 === null || options === void 0 ? void 0 : options.crv) { - case undefined: - case 'P-256': - case 'P-384': - case 'P-521': - return generate('ec', { namedCurve: (_b = options === null || options === void 0 ? void 0 : options.crv) !== null && _b !== void 0 ? _b : 'P-256' }); - case 'X25519': - return generate('x25519'); - case 'X448': - return generate('x448'); - default: - throw new errors_js_1.JOSENotSupported('Invalid or unsupported crv option provided, supported values are P-256, P-384, P-521, X25519, and X448'); - } - default: - throw new errors_js_1.JOSENotSupported('unsupported or invalid JWK "alg" (Algorithm) Parameter value'); - } -} -exports.generateKeyPair = generateKeyPair; diff --git a/dist/node/cjs/runtime/get_named_curve.js b/dist/node/cjs/runtime/get_named_curve.js deleted file mode 100644 index ab98bca5cc..0000000000 --- a/dist/node/cjs/runtime/get_named_curve.js +++ /dev/null @@ -1,89 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.setCurve = exports.weakMap = void 0; -const crypto_1 = require("crypto"); -const errors_js_1 = require("../util/errors.js"); -const webcrypto_js_1 = require("./webcrypto.js"); -const is_key_object_js_1 = require("./is_key_object.js"); -const invalid_key_input_js_1 = require("./invalid_key_input.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]); -exports.weakMap = new WeakMap(); -const namedCurveToJOSE = (namedCurve) => { - switch (namedCurve) { - case 'prime256v1': - return 'P-256'; - case 'secp384r1': - return 'P-384'; - case 'secp521r1': - return 'P-521'; - case 'secp256k1': - return namedCurve; - default: - throw new errors_js_1.JOSENotSupported('unsupported key curve for this operation'); - } -}; -const getNamedCurve = (key, raw) => { - var _a; - if ((0, webcrypto_js_1.isCryptoKey)(key)) { - key = (0, webcrypto_js_1.getKeyObject)(key); - } - if (!(0, is_key_object_js_1.default)(key)) { - throw new TypeError((0, invalid_key_input_js_1.default)(key, 'KeyObject', 'CryptoKey')); - } - if (key.type === 'secret') { - throw new TypeError('only "private" or "public" type keys can be used for this operation'); - } - switch (key.asymmetricKeyType) { - case 'ed25519': - case 'ed448': - return `Ed${key.asymmetricKeyType.substr(2)}`; - case 'x25519': - case 'x448': - return `X${key.asymmetricKeyType.substr(1)}`; - case 'ec': { - if (exports.weakMap.has(key)) { - return exports.weakMap.get(key); - } - let namedCurve = (_a = key.asymmetricKeyDetails) === null || _a === void 0 ? void 0 : _a.namedCurve; - if (!namedCurve && key.type === 'private') { - namedCurve = getNamedCurve((0, crypto_1.createPublicKey)(key), true); - } - else if (!namedCurve) { - 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); - if (curveOid.equals(p256)) { - namedCurve = 'prime256v1'; - } - else if (curveOid.equals(p384)) { - namedCurve = 'secp384r1'; - } - else if (curveOid.equals(p521)) { - namedCurve = 'secp521r1'; - } - else if (curveOid.equals(secp256k1)) { - namedCurve = 'secp256k1'; - } - else { - throw new errors_js_1.JOSENotSupported('unsupported key curve for this operation'); - } - } - if (raw) - return namedCurve; - const curve = namedCurveToJOSE(namedCurve); - exports.weakMap.set(key, curve); - return curve; - } - default: - throw new TypeError('Invalid asymmetric key type for this operation'); - } -}; -function setCurve(keyObject, curve) { - exports.weakMap.set(keyObject, curve); -} -exports.setCurve = setCurve; -exports.default = getNamedCurve; diff --git a/dist/node/cjs/runtime/get_sign_verify_key.js b/dist/node/cjs/runtime/get_sign_verify_key.js deleted file mode 100644 index 127114f030..0000000000 --- a/dist/node/cjs/runtime/get_sign_verify_key.js +++ /dev/null @@ -1,22 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const crypto = require("crypto"); -const webcrypto_js_1 = require("./webcrypto.js"); -const secret_key_js_1 = require("./secret_key.js"); -const invalid_key_input_js_1 = require("./invalid_key_input.js"); -function getSignVerifyKey(alg, key, usage) { - if (key instanceof Uint8Array) { - if (!alg.startsWith('HS')) { - throw new TypeError((0, invalid_key_input_js_1.default)(key, 'KeyObject', 'CryptoKey')); - } - return (0, secret_key_js_1.default)(key); - } - if (key instanceof crypto.KeyObject) { - return key; - } - if ((0, webcrypto_js_1.isCryptoKey)(key)) { - return (0, webcrypto_js_1.getKeyObject)(key, alg, new Set([usage])); - } - throw new TypeError((0, invalid_key_input_js_1.default)(key, 'KeyObject', 'CryptoKey', 'Uint8Array')); -} -exports.default = getSignVerifyKey; diff --git a/dist/node/cjs/runtime/hmac_digest.js b/dist/node/cjs/runtime/hmac_digest.js deleted file mode 100644 index c3935124c7..0000000000 --- a/dist/node/cjs/runtime/hmac_digest.js +++ /dev/null @@ -1,16 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const errors_js_1 = require("../util/errors.js"); -function hmacDigest(alg) { - switch (alg) { - case 'HS256': - return 'sha256'; - case 'HS384': - return 'sha384'; - case 'HS512': - return 'sha512'; - default: - throw new errors_js_1.JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`); - } -} -exports.default = hmacDigest; diff --git a/dist/node/cjs/runtime/invalid_key_input.js b/dist/node/cjs/runtime/invalid_key_input.js deleted file mode 100644 index 83740e7534..0000000000 --- a/dist/node/cjs/runtime/invalid_key_input.js +++ /dev/null @@ -1,38 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const util_1 = require("util"); -exports.default = (actual, ...types) => { - let msg = 'Key must be '; - if (types.length > 2) { - const last = types.pop(); - msg += `one of type ${types.join(', ')}, or ${last}.`; - } - else if (types.length === 2) { - msg += `one of type ${types[0]} or ${types[1]}.`; - } - else { - msg += `of type ${types[0]}.`; - } - if (actual == null) { - msg += ` Received ${actual}`; - } - else if (typeof actual === 'function' && actual.name) { - msg += ` Received function ${actual.name}`; - } - else if (typeof actual === 'object' && actual != null) { - if (actual.constructor && actual.constructor.name) { - msg += ` Received an instance of ${actual.constructor.name}`; - } - else { - const inspected = (0, util_1.inspect)(actual, { depth: -1 }); - msg += ` Received ${inspected}`; - } - } - else { - let inspected = (0, util_1.inspect)(actual, { colors: false }); - if (inspected.length > 25) - inspected = `${inspected.slice(0, 25)}...`; - msg += ` Received type ${typeof actual} (${inspected})`; - } - return msg; -}; diff --git a/dist/node/cjs/runtime/is_key_object.js b/dist/node/cjs/runtime/is_key_object.js deleted file mode 100644 index 6bdb2bb3ed..0000000000 --- a/dist/node/cjs/runtime/is_key_object.js +++ /dev/null @@ -1,16 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const crypto_1 = require("crypto"); -const util = require("util"); -let impl; -if (util.types.isKeyObject) { - impl = function isKeyObject(obj) { - return util.types.isKeyObject(obj); - }; -} -else { - impl = function isKeyObject(obj) { - return obj != null && obj instanceof crypto_1.KeyObject; - }; -} -exports.default = impl; diff --git a/dist/node/cjs/runtime/jwk_to_key.js b/dist/node/cjs/runtime/jwk_to_key.js deleted file mode 100644 index e152c3d729..0000000000 --- a/dist/node/cjs/runtime/jwk_to_key.js +++ /dev/null @@ -1,121 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const crypto_1 = require("crypto"); -const base64url_js_1 = require("./base64url.js"); -const errors_js_1 = require("../util/errors.js"); -const get_named_curve_js_1 = require("./get_named_curve.js"); -const check_modulus_length_js_1 = require("./check_modulus_length.js"); -const asn1_sequence_encoder_js_1 = require("./asn1_sequence_encoder.js"); -const [major, minor] = process.version - .substr(1) - .split('.') - .map((str) => parseInt(str, 10)); -const jwkImportSupported = major >= 16 || (major === 15 && minor >= 12); -const parse = (jwk) => { - if (jwkImportSupported && jwk.kty !== 'oct') { - return jwk.d - ? (0, crypto_1.createPrivateKey)({ format: 'jwk', key: jwk }) - : (0, crypto_1.createPublicKey)({ format: 'jwk', key: jwk }); - } - switch (jwk.kty) { - case 'oct': { - return (0, crypto_1.createSecretKey)((0, base64url_js_1.decode)(jwk.k)); - } - case 'RSA': { - const enc = new asn1_sequence_encoder_js_1.default(); - const isPrivate = jwk.d !== undefined; - const modulus = Buffer.from(jwk.n, 'base64'); - const exponent = Buffer.from(jwk.e, 'base64'); - if (isPrivate) { - enc.zero(); - 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 = { - key: der, - format: 'der', - type: 'pkcs1', - }; - const keyObject = isPrivate ? (0, crypto_1.createPrivateKey)(createInput) : (0, crypto_1.createPublicKey)(createInput); - (0, check_modulus_length_js_1.setModulusLength)(keyObject, modulus.length << 3); - return keyObject; - } - case 'EC': { - const enc = new asn1_sequence_encoder_js_1.default(); - const isPrivate = jwk.d !== undefined; - const pub = Buffer.concat([ - Buffer.alloc(1, 4), - Buffer.from(jwk.x, 'base64'), - Buffer.from(jwk.y, 'base64'), - ]); - if (isPrivate) { - enc.zero(); - const enc$1 = new asn1_sequence_encoder_js_1.default(); - enc$1.oidFor('ecPublicKey'); - enc$1.oidFor(jwk.crv); - enc.add(enc$1.end()); - const enc$2 = new asn1_sequence_encoder_js_1.default(); - enc$2.one(); - enc$2.octStr(Buffer.from(jwk.d, 'base64')); - const enc$3 = new asn1_sequence_encoder_js_1.default(); - enc$3.bitStr(pub); - const f2 = enc$3.end(Buffer.from([0xa1])); - enc$2.add(f2); - const f = enc$2.end(); - const enc$4 = new asn1_sequence_encoder_js_1.default(); - enc$4.add(f); - const f3 = enc$4.end(Buffer.from([0x04])); - enc.add(f3); - const der = enc.end(); - const keyObject = (0, crypto_1.createPrivateKey)({ key: der, format: 'der', type: 'pkcs8' }); - (0, get_named_curve_js_1.setCurve)(keyObject, jwk.crv); - return keyObject; - } - const enc$1 = new asn1_sequence_encoder_js_1.default(); - enc$1.oidFor('ecPublicKey'); - enc$1.oidFor(jwk.crv); - enc.add(enc$1.end()); - enc.bitStr(pub); - const der = enc.end(); - const keyObject = (0, crypto_1.createPublicKey)({ key: der, format: 'der', type: 'spki' }); - (0, get_named_curve_js_1.setCurve)(keyObject, jwk.crv); - return keyObject; - } - case 'OKP': { - const enc = new asn1_sequence_encoder_js_1.default(); - const isPrivate = jwk.d !== undefined; - if (isPrivate) { - enc.zero(); - const enc$1 = new asn1_sequence_encoder_js_1.default(); - enc$1.oidFor(jwk.crv); - enc.add(enc$1.end()); - const enc$2 = new asn1_sequence_encoder_js_1.default(); - enc$2.octStr(Buffer.from(jwk.d, 'base64')); - const f = enc$2.end(Buffer.from([0x04])); - enc.add(f); - const der = enc.end(); - return (0, crypto_1.createPrivateKey)({ key: der, format: 'der', type: 'pkcs8' }); - } - const enc$1 = new asn1_sequence_encoder_js_1.default(); - enc$1.oidFor(jwk.crv); - enc.add(enc$1.end()); - enc.bitStr(Buffer.from(jwk.x, 'base64')); - const der = enc.end(); - return (0, crypto_1.createPublicKey)({ key: der, format: 'der', type: 'spki' }); - } - default: - throw new errors_js_1.JOSENotSupported('unsupported or invalid JWK "kty" (Key Type) Parameter value'); - } -}; -exports.default = parse; diff --git a/dist/node/cjs/runtime/key_to_jwk.js b/dist/node/cjs/runtime/key_to_jwk.js deleted file mode 100644 index aea46857a9..0000000000 --- a/dist/node/cjs/runtime/key_to_jwk.js +++ /dev/null @@ -1,159 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const crypto_1 = require("crypto"); -const base64url_js_1 = require("./base64url.js"); -const asn1_sequence_decoder_js_1 = require("./asn1_sequence_decoder.js"); -const errors_js_1 = require("../util/errors.js"); -const get_named_curve_js_1 = require("./get_named_curve.js"); -const webcrypto_js_1 = require("./webcrypto.js"); -const is_key_object_js_1 = require("./is_key_object.js"); -const invalid_key_input_js_1 = require("./invalid_key_input.js"); -const [major, minor] = process.version - .substr(1) - .split('.') - .map((str) => parseInt(str, 10)); -const jwkExportSupported = major >= 16 || (major === 15 && minor >= 9); -const keyToJWK = (key) => { - let keyObject; - if ((0, webcrypto_js_1.isCryptoKey)(key)) { - if (!key.extractable) { - throw new TypeError('CryptoKey is not extractable'); - } - keyObject = (0, webcrypto_js_1.getKeyObject)(key); - } - else if ((0, is_key_object_js_1.default)(key)) { - keyObject = key; - } - else if (key instanceof Uint8Array) { - return { - kty: 'oct', - k: (0, base64url_js_1.encode)(key), - }; - } - else { - throw new TypeError((0, invalid_key_input_js_1.default)(key, 'KeyObject', 'CryptoKey', 'Uint8Array')); - } - if (jwkExportSupported) { - return keyObject.export({ format: 'jwk' }); - } - switch (keyObject.type) { - case 'secret': - return { - kty: 'oct', - k: (0, base64url_js_1.encode)(keyObject.export()), - }; - case 'private': - case 'public': { - switch (keyObject.asymmetricKeyType) { - case 'rsa': { - const der = keyObject.export({ format: 'der', type: 'pkcs1' }); - const dec = new asn1_sequence_decoder_js_1.default(der); - if (keyObject.type === 'private') { - dec.unsignedInteger(); - } - const n = (0, base64url_js_1.encode)(dec.unsignedInteger()); - const e = (0, base64url_js_1.encode)(dec.unsignedInteger()); - let jwk; - if (keyObject.type === 'private') { - jwk = { - d: (0, base64url_js_1.encode)(dec.unsignedInteger()), - p: (0, base64url_js_1.encode)(dec.unsignedInteger()), - q: (0, base64url_js_1.encode)(dec.unsignedInteger()), - dp: (0, base64url_js_1.encode)(dec.unsignedInteger()), - dq: (0, base64url_js_1.encode)(dec.unsignedInteger()), - qi: (0, base64url_js_1.encode)(dec.unsignedInteger()), - }; - } - dec.end(); - return { kty: 'RSA', n, e, ...jwk }; - } - case 'ec': { - const crv = (0, get_named_curve_js_1.default)(keyObject); - let len; - let offset; - let correction; - switch (crv) { - case 'secp256k1': - len = 64; - offset = 31 + 2; - correction = -1; - break; - case 'P-256': - len = 64; - offset = 34 + 2; - correction = -1; - break; - case 'P-384': - len = 96; - offset = 33 + 2; - correction = -3; - break; - case 'P-521': - len = 132; - offset = 33 + 2; - correction = -3; - break; - default: - throw new errors_js_1.JOSENotSupported('unsupported curve'); - } - if (keyObject.type === 'public') { - const der = keyObject.export({ type: 'spki', format: 'der' }); - return { - kty: 'EC', - crv, - x: (0, base64url_js_1.encode)(der.subarray(-len, -len / 2)), - y: (0, base64url_js_1.encode)(der.subarray(-len / 2)), - }; - } - const der = keyObject.export({ type: 'pkcs8', format: 'der' }); - if (der.length < 100) { - offset += correction; - } - return { - ...keyToJWK((0, crypto_1.createPublicKey)(keyObject)), - d: (0, base64url_js_1.encode)(der.subarray(offset, offset + len / 2)), - }; - } - case 'ed25519': - case 'x25519': { - const crv = (0, get_named_curve_js_1.default)(keyObject); - if (keyObject.type === 'public') { - const der = keyObject.export({ type: 'spki', format: 'der' }); - return { - kty: 'OKP', - crv, - x: (0, base64url_js_1.encode)(der.subarray(-32)), - }; - } - const der = keyObject.export({ type: 'pkcs8', format: 'der' }); - return { - ...keyToJWK((0, crypto_1.createPublicKey)(keyObject)), - d: (0, base64url_js_1.encode)(der.subarray(-32)), - }; - } - case 'ed448': - case 'x448': { - const crv = (0, get_named_curve_js_1.default)(keyObject); - if (keyObject.type === 'public') { - const der = keyObject.export({ type: 'spki', format: 'der' }); - return { - kty: 'OKP', - crv, - x: (0, base64url_js_1.encode)(der.subarray(crv === 'Ed448' ? -57 : -56)), - }; - } - const der = keyObject.export({ type: 'pkcs8', format: 'der' }); - return { - ...keyToJWK((0, crypto_1.createPublicKey)(keyObject)), - d: (0, base64url_js_1.encode)(der.subarray(crv === 'Ed448' ? -57 : -56)), - }; - } - default: - throw new errors_js_1.JOSENotSupported('unsupported key asymmetricKeyType'); - } - } - default: - throw new errors_js_1.JOSENotSupported('unsupported key type'); - } -}; -exports.default = keyToJWK; diff --git a/dist/node/cjs/runtime/node_key.js b/dist/node/cjs/runtime/node_key.js deleted file mode 100644 index 60378ff32a..0000000000 --- a/dist/node/cjs/runtime/node_key.js +++ /dev/null @@ -1,86 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const crypto_1 = require("crypto"); -const get_named_curve_js_1 = require("./get_named_curve.js"); -const errors_js_1 = require("../util/errors.js"); -const check_modulus_length_js_1 = require("./check_modulus_length.js"); -const [major, minor] = process.version - .substr(1) - .split('.') - .map((str) => parseInt(str, 10)); -const rsaPssParams = major >= 17 || (major === 16 && minor >= 9); -const ecCurveAlgMap = new Map([ - ['ES256', 'P-256'], - ['ES256K', 'secp256k1'], - ['ES384', 'P-384'], - ['ES512', 'P-521'], -]); -function keyForCrypto(alg, key) { - switch (alg) { - case 'EdDSA': - if (!['ed25519', 'ed448'].includes(key.asymmetricKeyType)) { - throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be ed25519 or ed448'); - } - return key; - case 'RS256': - case 'RS384': - case 'RS512': - if (key.asymmetricKeyType !== 'rsa') { - throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be rsa'); - } - (0, check_modulus_length_js_1.default)(key, alg); - return key; - case rsaPssParams && 'PS256': - case rsaPssParams && 'PS384': - case rsaPssParams && 'PS512': - if (key.asymmetricKeyType === 'rsa-pss') { - const { hashAlgorithm, mgf1HashAlgorithm, saltLength } = key.asymmetricKeyDetails; - const length = parseInt(alg.substr(-3), 10); - if (hashAlgorithm !== undefined && - (hashAlgorithm !== `sha${length}` || mgf1HashAlgorithm !== hashAlgorithm)) { - throw new TypeError(`Invalid key for this operation, its RSA-PSS parameters do not meet the requirements of "alg" ${alg}`); - } - if (saltLength !== undefined && saltLength > length >> 3) { - throw new TypeError(`Invalid key for this operation, its RSA-PSS parameter saltLength does not meet the requirements of "alg" ${alg}`); - } - } - else if (key.asymmetricKeyType !== 'rsa') { - throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be rsa or rsa-pss'); - } - (0, check_modulus_length_js_1.default)(key, alg); - return { - key, - padding: crypto_1.constants.RSA_PKCS1_PSS_PADDING, - saltLength: crypto_1.constants.RSA_PSS_SALTLEN_DIGEST, - }; - case !rsaPssParams && 'PS256': - case !rsaPssParams && 'PS384': - case !rsaPssParams && 'PS512': - if (key.asymmetricKeyType !== 'rsa') { - throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be rsa'); - } - (0, check_modulus_length_js_1.default)(key, alg); - return { - key, - padding: crypto_1.constants.RSA_PKCS1_PSS_PADDING, - saltLength: crypto_1.constants.RSA_PSS_SALTLEN_DIGEST, - }; - case 'ES256': - case 'ES256K': - case 'ES384': - case 'ES512': { - if (key.asymmetricKeyType !== 'ec') { - throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be ec'); - } - const actual = (0, get_named_curve_js_1.default)(key); - const expected = ecCurveAlgMap.get(alg); - if (actual !== expected) { - throw new TypeError(`Invalid key curve for the algorithm, its curve must be ${expected}, got ${actual}`); - } - return { dsaEncoding: 'ieee-p1363', key }; - } - default: - throw new errors_js_1.JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`); - } -} -exports.default = keyForCrypto; diff --git a/dist/node/cjs/runtime/pbes2kw.js b/dist/node/cjs/runtime/pbes2kw.js deleted file mode 100644 index 1bc570801b..0000000000 --- a/dist/node/cjs/runtime/pbes2kw.js +++ /dev/null @@ -1,45 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.decrypt = exports.encrypt = void 0; -const util_1 = require("util"); -const crypto_1 = require("crypto"); -const random_js_1 = require("./random.js"); -const buffer_utils_js_1 = require("../lib/buffer_utils.js"); -const base64url_js_1 = require("./base64url.js"); -const aeskw_js_1 = require("./aeskw.js"); -const check_p2s_js_1 = require("../lib/check_p2s.js"); -const webcrypto_js_1 = require("./webcrypto.js"); -const is_key_object_js_1 = require("./is_key_object.js"); -const invalid_key_input_js_1 = require("./invalid_key_input.js"); -const pbkdf2 = (0, util_1.promisify)(crypto_1.pbkdf2); -function getPassword(key, alg) { - if ((0, is_key_object_js_1.default)(key)) { - return key.export(); - } - if (key instanceof Uint8Array) { - return key; - } - if ((0, webcrypto_js_1.isCryptoKey)(key)) { - return (0, webcrypto_js_1.getKeyObject)(key, alg, new Set(['deriveBits', 'deriveKey'])).export(); - } - throw new TypeError((0, invalid_key_input_js_1.default)(key, 'KeyObject', 'CryptoKey', 'Uint8Array')); -} -const encrypt = async (alg, key, cek, p2c = Math.floor(Math.random() * 2049) + 2048, p2s = (0, random_js_1.default)(new Uint8Array(16))) => { - (0, check_p2s_js_1.default)(p2s); - const salt = (0, buffer_utils_js_1.p2s)(alg, p2s); - const keylen = parseInt(alg.substr(13, 3), 10) >> 3; - const password = getPassword(key, alg); - const derivedKey = await pbkdf2(password, salt, p2c, keylen, `sha${alg.substr(8, 3)}`); - const encryptedKey = await (0, aeskw_js_1.wrap)(alg.substr(-6), derivedKey, cek); - return { encryptedKey, p2c, p2s: (0, base64url_js_1.encode)(p2s) }; -}; -exports.encrypt = encrypt; -const decrypt = async (alg, key, encryptedKey, p2c, p2s) => { - (0, check_p2s_js_1.default)(p2s); - const salt = (0, buffer_utils_js_1.p2s)(alg, p2s); - const keylen = parseInt(alg.substr(13, 3), 10) >> 3; - const password = getPassword(key, alg); - const derivedKey = await pbkdf2(password, salt, p2c, keylen, `sha${alg.substr(8, 3)}`); - return (0, aeskw_js_1.unwrap)(alg.substr(-6), derivedKey, encryptedKey); -}; -exports.decrypt = decrypt; diff --git a/dist/node/cjs/runtime/random.js b/dist/node/cjs/runtime/random.js deleted file mode 100644 index 2ac8670b74..0000000000 --- a/dist/node/cjs/runtime/random.js +++ /dev/null @@ -1,4 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const crypto_1 = require("crypto"); -exports.default = crypto_1.randomFillSync; diff --git a/dist/node/cjs/runtime/rsaes.js b/dist/node/cjs/runtime/rsaes.js deleted file mode 100644 index b8aaf2869e..0000000000 --- a/dist/node/cjs/runtime/rsaes.js +++ /dev/null @@ -1,66 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.decrypt = exports.encrypt = void 0; -const crypto_1 = require("crypto"); -const check_modulus_length_js_1 = require("./check_modulus_length.js"); -const webcrypto_js_1 = require("./webcrypto.js"); -const is_key_object_js_1 = require("./is_key_object.js"); -const invalid_key_input_js_1 = require("./invalid_key_input.js"); -const checkKey = (key, alg) => { - if (key.asymmetricKeyType !== 'rsa') { - throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be rsa'); - } - (0, check_modulus_length_js_1.default)(key, alg); -}; -const resolvePadding = (alg) => { - switch (alg) { - case 'RSA-OAEP': - case 'RSA-OAEP-256': - case 'RSA-OAEP-384': - case 'RSA-OAEP-512': - return crypto_1.constants.RSA_PKCS1_OAEP_PADDING; - case 'RSA1_5': - return crypto_1.constants.RSA_PKCS1_PADDING; - default: - return undefined; - } -}; -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; - } -}; -function ensureKeyObject(key, alg, ...usages) { - if ((0, is_key_object_js_1.default)(key)) { - return key; - } - if ((0, webcrypto_js_1.isCryptoKey)(key)) { - return (0, webcrypto_js_1.getKeyObject)(key, alg, new Set(usages)); - } - throw new TypeError((0, invalid_key_input_js_1.default)(key, 'KeyObject', 'CryptoKey')); -} -const encrypt = async (alg, key, cek) => { - const padding = resolvePadding(alg); - const oaepHash = resolveOaepHash(alg); - const keyObject = ensureKeyObject(key, alg, 'wrapKey', 'encrypt'); - checkKey(keyObject, alg); - return (0, crypto_1.publicEncrypt)({ key: keyObject, oaepHash, padding }, cek); -}; -exports.encrypt = encrypt; -const decrypt = async (alg, key, encryptedKey) => { - const padding = resolvePadding(alg); - const oaepHash = resolveOaepHash(alg); - const keyObject = ensureKeyObject(key, alg, 'unwrapKey', 'decrypt'); - checkKey(keyObject, alg); - return (0, crypto_1.privateDecrypt)({ key: keyObject, oaepHash, padding }, encryptedKey); -}; -exports.decrypt = decrypt; diff --git a/dist/node/cjs/runtime/secret_key.js b/dist/node/cjs/runtime/secret_key.js deleted file mode 100644 index 3a92aa91f5..0000000000 --- a/dist/node/cjs/runtime/secret_key.js +++ /dev/null @@ -1,14 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const crypto_1 = require("crypto"); -function getSecretKey(key) { - let keyObject; - if (key instanceof Uint8Array) { - keyObject = (0, crypto_1.createSecretKey)(key); - } - else { - keyObject = key; - } - return keyObject; -} -exports.default = getSecretKey; diff --git a/dist/node/cjs/runtime/sign.js b/dist/node/cjs/runtime/sign.js deleted file mode 100644 index 6d8991bfb5..0000000000 --- a/dist/node/cjs/runtime/sign.js +++ /dev/null @@ -1,29 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const crypto = require("crypto"); -const util_1 = require("util"); -const dsa_digest_js_1 = require("./dsa_digest.js"); -const hmac_digest_js_1 = require("./hmac_digest.js"); -const node_key_js_1 = require("./node_key.js"); -const get_sign_verify_key_js_1 = require("./get_sign_verify_key.js"); -let oneShotSign; -if (crypto.sign.length > 3) { - oneShotSign = (0, util_1.promisify)(crypto.sign); -} -else { - oneShotSign = crypto.sign; -} -const sign = async (alg, key, data) => { - const keyObject = (0, get_sign_verify_key_js_1.default)(alg, key, 'sign'); - 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 = crypto.createHmac((0, hmac_digest_js_1.default)(alg), keyObject); - hmac.update(data); - return hmac.digest(); - } - return oneShotSign((0, dsa_digest_js_1.default)(alg), data, (0, node_key_js_1.default)(alg, keyObject)); -}; -exports.default = sign; diff --git a/dist/node/cjs/runtime/timing_safe_equal.js b/dist/node/cjs/runtime/timing_safe_equal.js deleted file mode 100644 index e1e4ef6100..0000000000 --- a/dist/node/cjs/runtime/timing_safe_equal.js +++ /dev/null @@ -1,5 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const crypto_1 = require("crypto"); -const timingSafeEqual = crypto_1.timingSafeEqual; -exports.default = timingSafeEqual; diff --git a/dist/node/cjs/runtime/verify.js b/dist/node/cjs/runtime/verify.js deleted file mode 100644 index 7509e18610..0000000000 --- a/dist/node/cjs/runtime/verify.js +++ /dev/null @@ -1,42 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const crypto = require("crypto"); -const util_1 = require("util"); -const dsa_digest_js_1 = require("./dsa_digest.js"); -const node_key_js_1 = require("./node_key.js"); -const sign_js_1 = require("./sign.js"); -const get_sign_verify_key_js_1 = require("./get_sign_verify_key.js"); -const [major, minor] = process.version - .substr(1) - .split('.') - .map((str) => parseInt(str, 10)); -const oneShotCallbackSupported = major >= 16 || (major === 15 && minor >= 13); -let oneShotVerify; -if (crypto.verify.length > 4 && oneShotCallbackSupported) { - oneShotVerify = (0, util_1.promisify)(crypto.verify); -} -else { - oneShotVerify = crypto.verify; -} -const verify = async (alg, key, signature, data) => { - const keyObject = (0, get_sign_verify_key_js_1.default)(alg, key, 'verify'); - if (alg.startsWith('HS')) { - const expected = await (0, sign_js_1.default)(alg, keyObject, data); - const actual = signature; - try { - return crypto.timingSafeEqual(actual, expected); - } - catch { - return false; - } - } - const algorithm = (0, dsa_digest_js_1.default)(alg); - const keyInput = (0, node_key_js_1.default)(alg, keyObject); - try { - return await oneShotVerify(algorithm, data, keyInput, signature); - } - catch { - return false; - } -}; -exports.default = verify; diff --git a/dist/node/cjs/runtime/webcrypto.js b/dist/node/cjs/runtime/webcrypto.js deleted file mode 100644 index 137fc3933c..0000000000 --- a/dist/node/cjs/runtime/webcrypto.js +++ /dev/null @@ -1,165 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.getKeyObject = exports.isCryptoKey = void 0; -const crypto = require("crypto"); -const util = require("util"); -const webcrypto = crypto.webcrypto; -exports.default = webcrypto; -let impl; -exports.isCryptoKey = impl; -if (util.types.isCryptoKey) { - exports.isCryptoKey = impl = function isCryptoKey(obj) { - return util.types.isCryptoKey(obj); - }; -} -else if (webcrypto) { - exports.isCryptoKey = impl = function isCryptoKey(obj) { - return obj != null && obj instanceof webcrypto.CryptoKey; - }; -} -else { - exports.isCryptoKey = impl = (obj) => false; -} -function getHashLength(hash) { - return parseInt(hash === null || hash === void 0 ? void 0 : hash.name.substr(4), 10); -} -function getNamedCurve(alg) { - switch (alg) { - case 'ES256': - return 'P-256'; - case 'ES384': - return 'P-384'; - case 'ES512': - return 'P-521'; - } -} -function getKeyObject(key, alg, usage) { - if (!alg) { - return crypto.KeyObject.from(key); - } - switch (alg) { - case 'HS256': - case 'HS384': - case 'HS512': { - if (key.algorithm.name !== 'HMAC') { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be HMAC.`); - } - const expected = parseInt(alg.substr(2), 10); - const actual = getHashLength(key.algorithm.hash); - if (actual !== expected) { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.hash must be SHA-${expected}.`); - } - break; - } - case 'RS256': - case 'RS384': - case 'RS512': { - if (key.algorithm.name !== 'RSASSA-PKCS1-v1_5') { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be RSASSA-PKCS1-v1_5.`); - } - const expected = parseInt(alg.substr(2), 10); - const actual = getHashLength(key.algorithm.hash); - if (actual !== expected) { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.hash must be SHA-${expected}.`); - } - break; - } - case 'PS256': - case 'PS384': - case 'PS512': { - if (key.algorithm.name !== 'RSA-PSS') { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be RSA-PSS.`); - } - const expected = parseInt(alg.substr(2), 10); - const actual = getHashLength(key.algorithm.hash); - if (actual !== expected) { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.hash must be SHA-${expected}.`); - } - break; - } - case 'ES256': - case 'ES384': - case 'ES512': { - if (key.algorithm.name !== 'ECDSA') { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be ECDSA.`); - } - const expected = getNamedCurve(alg); - const actual = key.algorithm.namedCurve; - if (actual !== expected) { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.namedCurve must be ${expected}.`); - } - break; - } - case 'A128GCM': - case 'A192GCM': - case 'A256GCM': { - if (key.algorithm.name !== 'AES-GCM') { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be AES-GCM.`); - } - const expected = parseInt(alg.substr(1, 3), 10); - const actual = key.algorithm.length; - if (actual !== expected) { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.length must be ${expected}.`); - } - break; - } - case 'A128KW': - case 'A192KW': - case 'A256KW': { - if (key.algorithm.name !== 'AES-KW') { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be AES-KW.`); - } - const expected = parseInt(alg.substr(1, 3), 10); - const actual = key.algorithm.length; - if (actual !== expected) { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.length must be ${expected}.`); - } - break; - } - case 'ECDH-ES': - if (key.algorithm.name !== 'ECDH') { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be ECDH.`); - } - break; - case 'PBES2-HS256+A128KW': - case 'PBES2-HS384+A192KW': - case 'PBES2-HS512+A256KW': - if (key.algorithm.name !== 'PBKDF2') { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be PBKDF2.`); - } - break; - case 'RSA-OAEP': - case 'RSA-OAEP-256': - case 'RSA-OAEP-384': - case 'RSA-OAEP-512': { - if (key.algorithm.name !== 'RSA-OAEP') { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be RSA-OAEP.`); - } - const expected = parseInt(alg.substr(9), 10) || 1; - const actual = getHashLength(key.algorithm.hash); - if (actual !== expected) { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.hash must be SHA-${expected}.`); - } - break; - } - default: - throw new TypeError('CryptoKey does not support this operation'); - } - if (usage && !key.usages.find(Set.prototype.has.bind(usage))) { - const usages = [...usage]; - let msg = 'CryptoKey does not support this operation, its usages must include '; - if (usages.length > 2) { - const last = usages.pop(); - msg += `one of ${usages.join(', ')}, or ${last}.`; - } - else if (usages.length === 2) { - msg += `one of ${usages[0]} or ${usages[1]}.`; - } - else { - msg += ` ${usages[0]}.`; - } - throw new TypeError(msg); - } - return crypto.KeyObject.from(key); -} -exports.getKeyObject = getKeyObject; diff --git a/dist/node/cjs/runtime/zlib.js b/dist/node/cjs/runtime/zlib.js deleted file mode 100644 index 7dcfddf49b..0000000000 --- a/dist/node/cjs/runtime/zlib.js +++ /dev/null @@ -1,11 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.deflate = exports.inflate = void 0; -const util_1 = require("util"); -const zlib_1 = require("zlib"); -const inflateRaw = (0, util_1.promisify)(zlib_1.inflateRaw); -const deflateRaw = (0, util_1.promisify)(zlib_1.deflateRaw); -const inflate = (input) => inflateRaw(input); -exports.inflate = inflate; -const deflate = (input) => deflateRaw(input); -exports.deflate = deflate; diff --git a/dist/node/cjs/util/base64url.js b/dist/node/cjs/util/base64url.js deleted file mode 100644 index 4d383b5167..0000000000 --- a/dist/node/cjs/util/base64url.js +++ /dev/null @@ -1,6 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.decode = exports.encode = void 0; -const base64url = require("../runtime/base64url.js"); -exports.encode = base64url.encode; -exports.decode = base64url.decode; diff --git a/dist/node/cjs/util/decode_protected_header.js b/dist/node/cjs/util/decode_protected_header.js deleted file mode 100644 index 3db5e335c1..0000000000 --- a/dist/node/cjs/util/decode_protected_header.js +++ /dev/null @@ -1,39 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.decodeProtectedHeader = void 0; -const base64url_js_1 = require("./base64url.js"); -const buffer_utils_js_1 = require("../lib/buffer_utils.js"); -const is_object_js_1 = require("../lib/is_object.js"); -function decodeProtectedHeader(token) { - let protectedB64u; - if (typeof token === 'string') { - const parts = token.split('.'); - if (parts.length === 3 || parts.length === 5) { - ; - [protectedB64u] = parts; - } - } - else if (typeof token === 'object' && token) { - if ('protected' in token) { - protectedB64u = token.protected; - } - else { - throw new TypeError('Token does not contain a Protected Header'); - } - } - try { - if (typeof protectedB64u !== 'string' || !protectedB64u) { - throw new Error(); - } - const result = JSON.parse(buffer_utils_js_1.decoder.decode((0, base64url_js_1.decode)(protectedB64u))); - if (!(0, is_object_js_1.default)(result)) { - throw new Error(); - } - return result; - } - catch { - throw new TypeError('Invalid Token or Protected Header formatting'); - } -} -exports.decodeProtectedHeader = decodeProtectedHeader; -exports.default = decodeProtectedHeader; diff --git a/dist/node/cjs/util/errors.js b/dist/node/cjs/util/errors.js deleted file mode 100644 index 4dcb8cd226..0000000000 --- a/dist/node/cjs/util/errors.js +++ /dev/null @@ -1,125 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.JWTExpired = exports.JWSSignatureVerificationFailed = exports.JWKSMultipleMatchingKeys = exports.JWKSNoMatchingKey = exports.JWKSInvalid = exports.JWKInvalid = exports.JWTInvalid = exports.JWSInvalid = exports.JWEInvalid = exports.JWEDecryptionFailed = exports.JOSENotSupported = exports.JOSEAlgNotAllowed = exports.JWTClaimValidationFailed = exports.JOSEError = void 0; -class JOSEError extends Error { - constructor(message) { - super(message); - this.code = JOSEError.code; - this.name = this.constructor.name; - if (Error.captureStackTrace) { - Error.captureStackTrace(this, this.constructor); - } - } -} -exports.JOSEError = JOSEError; -JOSEError.code = 'ERR_JOSE_GENERIC'; -class JWTClaimValidationFailed extends JOSEError { - constructor(message, claim = 'unspecified', reason = 'unspecified') { - super(message); - this.code = JWTClaimValidationFailed.code; - this.claim = claim; - this.reason = reason; - } -} -exports.JWTClaimValidationFailed = JWTClaimValidationFailed; -JWTClaimValidationFailed.code = 'ERR_JWT_CLAIM_VALIDATION_FAILED'; -class JOSEAlgNotAllowed extends JOSEError { - constructor() { - super(...arguments); - this.code = JOSEAlgNotAllowed.code; - } -} -exports.JOSEAlgNotAllowed = JOSEAlgNotAllowed; -JOSEAlgNotAllowed.code = 'ERR_JOSE_ALG_NOT_ALLOWED'; -class JOSENotSupported extends JOSEError { - constructor() { - super(...arguments); - this.code = JOSENotSupported.code; - } -} -exports.JOSENotSupported = JOSENotSupported; -JOSENotSupported.code = 'ERR_JOSE_NOT_SUPPORTED'; -class JWEDecryptionFailed extends JOSEError { - constructor() { - super(...arguments); - this.code = JWEDecryptionFailed.code; - this.message = 'decryption operation failed'; - } -} -exports.JWEDecryptionFailed = JWEDecryptionFailed; -JWEDecryptionFailed.code = 'ERR_JWE_DECRYPTION_FAILED'; -class JWEInvalid extends JOSEError { - constructor() { - super(...arguments); - this.code = JWEInvalid.code; - } -} -exports.JWEInvalid = JWEInvalid; -JWEInvalid.code = 'ERR_JWE_INVALID'; -class JWSInvalid extends JOSEError { - constructor() { - super(...arguments); - this.code = JWSInvalid.code; - } -} -exports.JWSInvalid = JWSInvalid; -JWSInvalid.code = 'ERR_JWS_INVALID'; -class JWTInvalid extends JOSEError { - constructor() { - super(...arguments); - this.code = JWTInvalid.code; - } -} -exports.JWTInvalid = JWTInvalid; -JWTInvalid.code = 'ERR_JWT_INVALID'; -class JWKInvalid extends JOSEError { - constructor() { - super(...arguments); - this.code = JWKInvalid.code; - } -} -exports.JWKInvalid = JWKInvalid; -JWKInvalid.code = 'ERR_JWK_INVALID'; -class JWKSInvalid extends JOSEError { - constructor() { - super(...arguments); - this.code = JWKSInvalid.code; - } -} -exports.JWKSInvalid = JWKSInvalid; -JWKSInvalid.code = 'ERR_JWKS_INVALID'; -class JWKSNoMatchingKey extends JOSEError { - constructor() { - super(...arguments); - this.code = JWKSNoMatchingKey.code; - this.message = 'no applicable key found in the JSON Web Key Set'; - } -} -exports.JWKSNoMatchingKey = JWKSNoMatchingKey; -JWKSNoMatchingKey.code = 'ERR_JWKS_NO_MATCHING_KEY'; -class JWKSMultipleMatchingKeys extends JOSEError { - constructor() { - super(...arguments); - this.code = JWKSMultipleMatchingKeys.code; - this.message = 'multiple matching keys found in the JSON Web Key Set'; - } -} -exports.JWKSMultipleMatchingKeys = JWKSMultipleMatchingKeys; -JWKSMultipleMatchingKeys.code = 'ERR_JWKS_MULTIPLE_MATCHING_KEYS'; -class JWSSignatureVerificationFailed extends JOSEError { - constructor() { - super(...arguments); - this.code = JWSSignatureVerificationFailed.code; - this.message = 'signature verification failed'; - } -} -exports.JWSSignatureVerificationFailed = JWSSignatureVerificationFailed; -JWSSignatureVerificationFailed.code = 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED'; -class JWTExpired extends JWTClaimValidationFailed { - constructor() { - super(...arguments); - this.code = JWTExpired.code; - } -} -exports.JWTExpired = JWTExpired; -JWTExpired.code = 'ERR_JWT_EXPIRED'; diff --git a/dist/node/cjs/util/generate_key_pair.js b/dist/node/cjs/util/generate_key_pair.js deleted file mode 100644 index 548636d06c..0000000000 --- a/dist/node/cjs/util/generate_key_pair.js +++ /dev/null @@ -1,9 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.generateKeyPair = void 0; -const generate_js_1 = require("../runtime/generate.js"); -async function generateKeyPair(alg, options) { - return (0, generate_js_1.generateKeyPair)(alg, options); -} -exports.generateKeyPair = generateKeyPair; -exports.default = generateKeyPair; diff --git a/dist/node/cjs/util/generate_secret.js b/dist/node/cjs/util/generate_secret.js deleted file mode 100644 index 5270b09714..0000000000 --- a/dist/node/cjs/util/generate_secret.js +++ /dev/null @@ -1,9 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.generateSecret = void 0; -const generate_js_1 = require("../runtime/generate.js"); -async function generateSecret(alg, options) { - return (0, generate_js_1.generateSecret)(alg, options); -} -exports.generateSecret = generateSecret; -exports.default = generateSecret; diff --git a/dist/node/cjs/util/random.js b/dist/node/cjs/util/random.js deleted file mode 100644 index f4c78fc47b..0000000000 --- a/dist/node/cjs/util/random.js +++ /dev/null @@ -1,7 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.random = void 0; -const random_js_1 = require("../runtime/random.js"); -const random = random_js_1.default; -exports.random = random; -exports.default = random; diff --git a/dist/node/esm/jwe/compact/decrypt.js b/dist/node/esm/jwe/compact/decrypt.js deleted file mode 100644 index e4e87c1c17..0000000000 --- a/dist/node/esm/jwe/compact/decrypt.js +++ /dev/null @@ -1,25 +0,0 @@ -import decrypt from '../flattened/decrypt.js'; -import { JWEInvalid } from '../../util/errors.js'; -import { decoder } from '../../lib/buffer_utils.js'; -async function compactDecrypt(jwe, key, options) { - if (jwe instanceof Uint8Array) { - jwe = decoder.decode(jwe); - } - if (typeof jwe !== 'string') { - throw new JWEInvalid('Compact JWE must be a string or Uint8Array'); - } - 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: (ciphertext || undefined), - iv: (iv || undefined), - protected: protectedHeader || undefined, - tag: (tag || undefined), - encrypted_key: encryptedKey || undefined, - }, key, options); - return { plaintext: decrypted.plaintext, protectedHeader: decrypted.protectedHeader }; -} -export { compactDecrypt }; -export default compactDecrypt; diff --git a/dist/node/esm/jwe/compact/encrypt.js b/dist/node/esm/jwe/compact/encrypt.js deleted file mode 100644 index 132a092398..0000000000 --- a/dist/node/esm/jwe/compact/encrypt.js +++ /dev/null @@ -1,28 +0,0 @@ -import FlattenedEncrypt from '../flattened/encrypt.js'; -class CompactEncrypt { - constructor(plaintext) { - this._flattened = new FlattenedEncrypt(plaintext); - } - setContentEncryptionKey(cek) { - this._flattened.setContentEncryptionKey(cek); - return this; - } - setInitializationVector(iv) { - this._flattened.setInitializationVector(iv); - return this; - } - setProtectedHeader(protectedHeader) { - this._flattened.setProtectedHeader(protectedHeader); - return this; - } - setKeyManagementParameters(parameters) { - this._flattened.setKeyManagementParameters(parameters); - return this; - } - async encrypt(key, options) { - const jwe = await this._flattened.encrypt(key, options); - return [jwe.protected, jwe.encrypted_key, jwe.iv, jwe.ciphertext, jwe.tag].join('.'); - } -} -export { CompactEncrypt }; -export default CompactEncrypt; diff --git a/dist/node/esm/jwe/flattened/decrypt.js b/dist/node/esm/jwe/flattened/decrypt.js deleted file mode 100644 index a60f8a4190..0000000000 --- a/dist/node/esm/jwe/flattened/decrypt.js +++ /dev/null @@ -1,138 +0,0 @@ -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 { 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 checkExtensions = validateCrit.bind(undefined, JWEInvalid, new Map()); -const checkAlgOption = validateAlgorithms.bind(undefined, 'keyManagementAlgorithms'); -const checkEncOption = validateAlgorithms.bind(undefined, 'contentEncryptionAlgorithms'); -async function flattenedDecrypt(jwe, key, options) { - var _a; - if (!isObject(jwe)) { - throw new JWEInvalid('Flattened JWE must be an object'); - } - if (jwe.protected === undefined && jwe.header === undefined && jwe.unprotected === undefined) { - throw new JWEInvalid('JOSE Header missing'); - } - if (typeof jwe.iv !== 'string') { - throw new JWEInvalid('JWE Initialization Vector missing or incorrect type'); - } - if (typeof jwe.ciphertext !== 'string') { - throw new JWEInvalid('JWE Ciphertext missing or incorrect type'); - } - if (typeof jwe.tag !== 'string') { - throw new JWEInvalid('JWE Authentication Tag missing or incorrect type'); - } - if (jwe.protected !== undefined && typeof jwe.protected !== 'string') { - throw new JWEInvalid('JWE Protected Header incorrect type'); - } - if (jwe.encrypted_key !== undefined && typeof jwe.encrypted_key !== 'string') { - throw new JWEInvalid('JWE Encrypted Key incorrect type'); - } - if (jwe.aad !== undefined && typeof jwe.aad !== 'string') { - throw new JWEInvalid('JWE AAD incorrect type'); - } - if (jwe.header !== undefined && !isObject(jwe.header)) { - throw new JWEInvalid('JWE Shared Unprotected Header incorrect type'); - } - if (jwe.unprotected !== undefined && !isObject(jwe.unprotected)) { - throw new JWEInvalid('JWE Per-Recipient Unprotected Header incorrect type'); - } - let parsedProt; - if (jwe.protected) { - const protectedHeader = base64url(jwe.protected); - try { - parsedProt = JSON.parse(decoder.decode(protectedHeader)); - } - catch { - throw new JWEInvalid('JWE Protected Header is invalid'); - } - } - 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 = { - ...parsedProt, - ...jwe.header, - ...jwe.unprotected, - }; - checkExtensions(options === null || options === void 0 ? void 0 : options.crit, parsedProt, joseHeader); - if (joseHeader.zip !== undefined) { - 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 (typeof alg !== 'string' || !alg) { - throw new JWEInvalid('missing JWE Algorithm (alg) in JWE Header'); - } - if (typeof enc !== 'string' || !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; - if (jwe.encrypted_key !== undefined) { - encryptedKey = base64url(jwe.encrypted_key); - } - if (typeof key === 'function') { - key = await key(parsedProt, jwe); - } - let cek; - try { - cek = await decryptKeyManagement(alg, key, encryptedKey, joseHeader); - } - catch (err) { - if (err instanceof TypeError) { - throw err; - } - cek = generateCek(enc); - } - const iv = base64url(jwe.iv); - const tag = base64url(jwe.tag); - const protectedHeader = encoder.encode((_a = jwe.protected) !== null && _a !== void 0 ? _a : ''); - let additionalData; - if (jwe.aad !== undefined) { - 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 === null || options === void 0 ? void 0 : options.inflateRaw) || inflate)(plaintext); - } - const result = { plaintext }; - if (jwe.protected !== undefined) { - result.protectedHeader = parsedProt; - } - if (jwe.aad !== undefined) { - result.additionalAuthenticatedData = base64url(jwe.aad); - } - if (jwe.unprotected !== undefined) { - result.sharedUnprotectedHeader = jwe.unprotected; - } - if (jwe.header !== undefined) { - result.unprotectedHeader = jwe.header; - } - return result; -} -export { flattenedDecrypt }; -export default flattenedDecrypt; diff --git a/dist/node/esm/jwe/flattened/encrypt.js b/dist/node/esm/jwe/flattened/encrypt.js deleted file mode 100644 index 371001bca7..0000000000 --- a/dist/node/esm/jwe/flattened/encrypt.js +++ /dev/null @@ -1,166 +0,0 @@ -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 checkExtensions = validateCrit.bind(undefined, JWEInvalid, new Map()); -class FlattenedEncrypt { - constructor(plaintext) { - this._plaintext = plaintext; - } - setKeyManagementParameters(parameters) { - if (this._keyManagementParameters) { - throw new TypeError('setKeyManagementParameters can only be called once'); - } - this._keyManagementParameters = parameters; - return this; - } - setProtectedHeader(protectedHeader) { - if (this._protectedHeader) { - throw new TypeError('setProtectedHeader can only be called once'); - } - this._protectedHeader = protectedHeader; - return this; - } - setSharedUnprotectedHeader(sharedUnprotectedHeader) { - if (this._sharedUnprotectedHeader) { - throw new TypeError('setSharedUnprotectedHeader can only be called once'); - } - this._sharedUnprotectedHeader = sharedUnprotectedHeader; - return this; - } - setUnprotectedHeader(unprotectedHeader) { - if (this._unprotectedHeader) { - throw new TypeError('setUnprotectedHeader can only be called once'); - } - this._unprotectedHeader = unprotectedHeader; - return this; - } - setAdditionalAuthenticatedData(aad) { - this._aad = aad; - return this; - } - setContentEncryptionKey(cek) { - if (this._cek) { - throw new TypeError('setContentEncryptionKey can only be called once'); - } - this._cek = cek; - return this; - } - setInitializationVector(iv) { - if (this._iv) { - throw new TypeError('setInitializationVector can only be called once'); - } - this._iv = iv; - return this; - } - async encrypt(key, options) { - 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 = { - ...this._protectedHeader, - ...this._unprotectedHeader, - ...this._sharedUnprotectedHeader, - }; - checkExtensions(options === null || options === void 0 ? void 0 : options.crit, this._protectedHeader, joseHeader); - if (joseHeader.zip !== undefined) { - 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 (typeof alg !== 'string' || !alg) { - throw new JWEInvalid('JWE "alg" (Algorithm) Header Parameter missing or invalid'); - } - if (typeof enc !== 'string' || !enc) { - throw new JWEInvalid('JWE "enc" (Encryption Algorithm) Header Parameter missing or invalid'); - } - let encryptedKey; - 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; - { - let parameters; - ({ 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 || (this._iv = generateIv(enc)); - let additionalData; - let protectedHeader; - let aadMember; - 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; - let tag; - if (joseHeader.zip === 'DEF') { - const deflated = await ((options === null || options === void 0 ? void 0 : 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 = { - 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 { FlattenedEncrypt }; -export default FlattenedEncrypt; diff --git a/dist/node/esm/jwe/general/decrypt.js b/dist/node/esm/jwe/general/decrypt.js deleted file mode 100644 index 0ee57ba5fc..0000000000 --- a/dist/node/esm/jwe/general/decrypt.js +++ /dev/null @@ -1,30 +0,0 @@ -import decrypt from '../flattened/decrypt.js'; -import { JWEDecryptionFailed, JWEInvalid } from '../../util/errors.js'; -import isObject from '../../lib/is_object.js'; -async function generalDecrypt(jwe, key, options) { - if (!isObject(jwe)) { - throw new JWEInvalid('General JWE must be an object'); - } - if (!Array.isArray(jwe.recipients) || !jwe.recipients.every(isObject)) { - throw new JWEInvalid('JWE Recipients missing or incorrect type'); - } - for (const recipient of jwe.recipients) { - try { - return await decrypt({ - aad: jwe.aad, - ciphertext: jwe.ciphertext, - encrypted_key: recipient.encrypted_key, - header: recipient.header, - iv: jwe.iv, - protected: jwe.protected, - tag: jwe.tag, - unprotected: jwe.unprotected, - }, key, options); - } - catch { - } - } - throw new JWEDecryptionFailed(); -} -export { generalDecrypt }; -export default generalDecrypt; diff --git a/dist/node/esm/jwk/embedded.js b/dist/node/esm/jwk/embedded.js deleted file mode 100644 index 60759f22e0..0000000000 --- a/dist/node/esm/jwk/embedded.js +++ /dev/null @@ -1,19 +0,0 @@ -import parseJwk from './parse.js'; -import isObject from '../lib/is_object.js'; -import { JWSInvalid } from '../util/errors.js'; -async function EmbeddedJWK(protectedHeader, token) { - const joseHeader = { - ...protectedHeader, - ...token.header, - }; - if (!isObject(joseHeader.jwk)) { - throw new JWSInvalid('"jwk" (JSON Web Key) Header Parameter must be a JSON object'); - } - const key = await parseJwk(joseHeader.jwk, joseHeader.alg, true); - if (key.type !== 'public') { - throw new JWSInvalid('"jwk" (JSON Web Key) Header Parameter must be a public key'); - } - return key; -} -export { EmbeddedJWK }; -export default EmbeddedJWK; diff --git a/dist/node/esm/jwk/from_key_like.js b/dist/node/esm/jwk/from_key_like.js deleted file mode 100644 index 5ea9173e1c..0000000000 --- a/dist/node/esm/jwk/from_key_like.js +++ /dev/null @@ -1,6 +0,0 @@ -import asJWK from '../runtime/key_to_jwk.js'; -async function fromKeyLike(key) { - return asJWK(key); -} -export { fromKeyLike }; -export default fromKeyLike; diff --git a/dist/node/esm/jwk/parse.js b/dist/node/esm/jwk/parse.js deleted file mode 100644 index cfa6f9492c..0000000000 --- a/dist/node/esm/jwk/parse.js +++ /dev/null @@ -1,35 +0,0 @@ -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'; -async function parseJwk(jwk, alg, octAsKeyObject) { - if (!isObject(jwk)) { - throw new TypeError('JWK must be an object'); - } - alg || (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'); - } - octAsKeyObject !== null && octAsKeyObject !== void 0 ? octAsKeyObject : (octAsKeyObject = jwk.ext !== true); - if (octAsKeyObject) { - return asKeyObject({ ...jwk, alg, ext: false }); - } - return base64url(jwk.k); - case 'RSA': - if (jwk.oth !== undefined) { - throw new JOSENotSupported('RSA JWK "oth" (Other Primes Info) Parameter value is not supported'); - } - case 'EC': - case 'OKP': - return asKeyObject({ ...jwk, alg }); - default: - throw new JOSENotSupported('unsupported "kty" (Key Type) Parameter value'); - } -} -export { parseJwk }; -export default parseJwk; diff --git a/dist/node/esm/jwk/thumbprint.js b/dist/node/esm/jwk/thumbprint.js deleted file mode 100644 index ffb569b31f..0000000000 --- a/dist/node/esm/jwk/thumbprint.js +++ /dev/null @@ -1,44 +0,0 @@ -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 isObject from '../lib/is_object.js'; -const check = (value, description) => { - if (typeof value !== 'string' || !value) { - throw new JWKInvalid(`${description} missing or invalid`); - } -}; -async function calculateThumbprint(jwk, digestAlgorithm = 'sha256') { - if (!isObject(jwk)) { - throw new TypeError('JWK must be an object'); - } - let components; - 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 { calculateThumbprint }; -export default calculateThumbprint; diff --git a/dist/node/esm/jwks/remote.js b/dist/node/esm/jwks/remote.js deleted file mode 100644 index 7665477163..0000000000 --- a/dist/node/esm/jwks/remote.js +++ /dev/null @@ -1,130 +0,0 @@ -import parseJWK from '../jwk/parse.js'; -import { JWKSInvalid, JOSENotSupported, JWKSNoMatchingKey, JWKSMultipleMatchingKeys, } from '../util/errors.js'; -import fetchJwks from '../runtime/fetch_jwks.js'; -import isObject from '../lib/is_object.js'; -function getKtyFromAlg(alg) { - 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'); - } -} -function isJWKLike(key) { - return isObject(key); -} -class RemoteJWKSet { - constructor(url, options) { - this._cached = new WeakMap(); - if (!(url instanceof URL)) { - throw new TypeError('url must be an instance of URL'); - } - this._url = new URL(url.href); - this._options = { agent: options === null || options === void 0 ? void 0 : options.agent }; - this._timeoutDuration = - typeof (options === null || options === void 0 ? void 0 : options.timeoutDuration) === 'number' ? options === null || options === void 0 ? void 0 : options.timeoutDuration : 5000; - this._cooldownDuration = - typeof (options === null || options === void 0 ? void 0 : options.cooldownDuration) === 'number' ? options === null || options === void 0 ? void 0 : options.cooldownDuration : 30000; - } - coolingDown() { - if (typeof this._cooldownStarted === 'undefined') { - return false; - } - return Date.now() < this._cooldownStarted + this._cooldownDuration; - } - async getKey(protectedHeader) { - if (!this._jwks) { - await this.reload(); - } - const candidates = this._jwks.keys.filter((jwk) => { - let candidate = jwk.kty === getKtyFromAlg(protectedHeader.alg); - if (candidate && typeof protectedHeader.kid === 'string') { - candidate = protectedHeader.kid === jwk.kid; - } - if (candidate && typeof jwk.alg === 'string') { - candidate = protectedHeader.alg === jwk.alg; - } - if (candidate && typeof jwk.use === 'string') { - candidate = jwk.use === 'sig'; - } - if (candidate && Array.isArray(jwk.key_ops)) { - candidate = jwk.key_ops.includes('verify'); - } - if (candidate && protectedHeader.alg === 'EdDSA') { - candidate = ['Ed25519', 'Ed448'].includes(jwk.crv); - } - 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 (cached[protectedHeader.alg] === undefined) { - const keyObject = await parseJWK({ ...jwk, alg: protectedHeader.alg }); - 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 = fetchJwks(this._url, this._timeoutDuration, this._options) - .then((json) => { - if (typeof json !== 'object' || - !json || - !Array.isArray(json.keys) || - !json.keys.every(isJWKLike)) { - throw new JWKSInvalid('JSON Web Key Set malformed'); - } - this._jwks = { keys: json.keys }; - this._cooldownStarted = Date.now(); - this._pendingFetch = undefined; - }) - .catch((err) => { - this._pendingFetch = undefined; - throw err; - }); - } - await this._pendingFetch; - } -} -function createRemoteJWKSet(url, options) { - return RemoteJWKSet.prototype.getKey.bind(new RemoteJWKSet(url, options)); -} -export { createRemoteJWKSet }; -export default createRemoteJWKSet; diff --git a/dist/node/esm/jws/compact/sign.js b/dist/node/esm/jws/compact/sign.js deleted file mode 100644 index 5bacca34d9..0000000000 --- a/dist/node/esm/jws/compact/sign.js +++ /dev/null @@ -1,19 +0,0 @@ -import FlattenedSign from '../flattened/sign.js'; -class CompactSign { - constructor(payload) { - this._flattened = new FlattenedSign(payload); - } - setProtectedHeader(protectedHeader) { - this._flattened.setProtectedHeader(protectedHeader); - return this; - } - async sign(key, options) { - const jws = await this._flattened.sign(key, options); - 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 { CompactSign }; -export default CompactSign; diff --git a/dist/node/esm/jws/compact/verify.js b/dist/node/esm/jws/compact/verify.js deleted file mode 100644 index aad640718b..0000000000 --- a/dist/node/esm/jws/compact/verify.js +++ /dev/null @@ -1,23 +0,0 @@ -import verify from '../flattened/verify.js'; -import { JWSInvalid } from '../../util/errors.js'; -import { decoder } from '../../lib/buffer_utils.js'; -async function compactVerify(jws, key, options) { - if (jws instanceof Uint8Array) { - jws = decoder.decode(jws); - } - if (typeof jws !== 'string') { - throw new JWSInvalid('Compact JWS must be a string or Uint8Array'); - } - const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split('.'); - if (length !== 3) { - throw new JWSInvalid('Invalid Compact JWS'); - } - const verified = await verify({ - payload: (payload || undefined), - protected: protectedHeader || undefined, - signature: (signature || undefined), - }, key, options); - return { payload: verified.payload, protectedHeader: verified.protectedHeader }; -} -export { compactVerify }; -export default compactVerify; diff --git a/dist/node/esm/jws/flattened/sign.js b/dist/node/esm/jws/flattened/sign.js deleted file mode 100644 index 35d9cb5e45..0000000000 --- a/dist/node/esm/jws/flattened/sign.js +++ /dev/null @@ -1,81 +0,0 @@ -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 checkKeyType from '../../lib/check_key_type.js'; -import validateCrit from '../../lib/validate_crit.js'; -const checkExtensions = validateCrit.bind(undefined, JWSInvalid, new Map([['b64', true]])); -class FlattenedSign { - constructor(payload) { - this._payload = payload; - } - setProtectedHeader(protectedHeader) { - if (this._protectedHeader) { - throw new TypeError('setProtectedHeader can only be called once'); - } - this._protectedHeader = protectedHeader; - return this; - } - setUnprotectedHeader(unprotectedHeader) { - if (this._unprotectedHeader) { - throw new TypeError('setUnprotectedHeader can only be called once'); - } - this._unprotectedHeader = unprotectedHeader; - return this; - } - async sign(key, options) { - 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 = { - ...this._protectedHeader, - ...this._unprotectedHeader, - }; - const extensions = checkExtensions(options === null || options === void 0 ? void 0 : options.crit, this._protectedHeader, joseHeader); - let b64 = 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 (typeof alg !== 'string' || !alg) { - throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid'); - } - checkKeyType(alg, key, 'sign'); - let payload = this._payload; - if (b64) { - payload = encoder.encode(base64url(payload)); - } - let protectedHeader; - 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 = { - signature: base64url(signature), - payload: '', - }; - 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 { FlattenedSign }; -export default FlattenedSign; diff --git a/dist/node/esm/jws/flattened/verify.js b/dist/node/esm/jws/flattened/verify.js deleted file mode 100644 index 311d0976c9..0000000000 --- a/dist/node/esm/jws/flattened/verify.js +++ /dev/null @@ -1,103 +0,0 @@ -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'; -const checkExtensions = validateCrit.bind(undefined, JWSInvalid, new Map([['b64', true]])); -const checkAlgOption = validateAlgorithms.bind(undefined, 'algorithms'); -async function flattenedVerify(jws, key, options) { - var _a; - if (!isObject(jws)) { - throw new JWSInvalid('Flattened JWS must be an object'); - } - if (jws.protected === undefined && jws.header === undefined) { - throw new JWSInvalid('Flattened JWS must have either of the "protected" or "header" members'); - } - if (jws.protected !== undefined && typeof jws.protected !== 'string') { - throw new JWSInvalid('JWS Protected Header incorrect type'); - } - if (jws.payload === undefined) { - throw new JWSInvalid('JWS Payload missing'); - } - if (typeof jws.signature !== 'string') { - throw new JWSInvalid('JWS Signature missing or incorrect type'); - } - if (jws.header !== undefined && !isObject(jws.header)) { - throw new JWSInvalid('JWS Unprotected Header incorrect type'); - } - let parsedProt = {}; - if (jws.protected) { - const protectedHeader = base64url(jws.protected); - try { - parsedProt = JSON.parse(decoder.decode(protectedHeader)); - } - catch { - throw new JWSInvalid('JWS Protected Header is invalid'); - } - } - if (!isDisjoint(parsedProt, jws.header)) { - throw new JWSInvalid('JWS Protected and JWS Unprotected Header Parameter names must be disjoint'); - } - const joseHeader = { - ...parsedProt, - ...jws.header, - }; - const extensions = checkExtensions(options === null || options === void 0 ? void 0 : options.crit, parsedProt, joseHeader); - let b64 = 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 (typeof alg !== 'string' || !alg) { - throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid'); - } - 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') { - key = await key(parsedProt, jws); - } - checkKeyType(alg, key, 'verify'); - const data = concat(encoder.encode((_a = jws.protected) !== null && _a !== void 0 ? _a : ''), 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; - if (b64) { - payload = base64url(jws.payload); - } - else if (typeof jws.payload === 'string') { - payload = encoder.encode(jws.payload); - } - else { - payload = jws.payload; - } - const result = { payload }; - if (jws.protected !== undefined) { - result.protectedHeader = parsedProt; - } - if (jws.header !== undefined) { - result.unprotectedHeader = jws.header; - } - return result; -} -export { flattenedVerify }; -export default flattenedVerify; diff --git a/dist/node/esm/jws/general/sign.js b/dist/node/esm/jws/general/sign.js deleted file mode 100644 index 7127accfa1..0000000000 --- a/dist/node/esm/jws/general/sign.js +++ /dev/null @@ -1,73 +0,0 @@ -import FlattenedSign from '../flattened/sign.js'; -import { JWSInvalid } from '../../util/errors.js'; -const signatureRef = new WeakMap(); -class IndividualSignature { - setProtectedHeader(protectedHeader) { - if (this._protectedHeader) { - throw new TypeError('setProtectedHeader can only be called once'); - } - this._protectedHeader = protectedHeader; - return this; - } - setUnprotectedHeader(unprotectedHeader) { - if (this._unprotectedHeader) { - throw new TypeError('setUnprotectedHeader can only be called once'); - } - this._unprotectedHeader = unprotectedHeader; - return this; - } - set _protectedHeader(value) { - signatureRef.get(this).protectedHeader = value; - } - get _protectedHeader() { - return signatureRef.get(this).protectedHeader; - } - set _unprotectedHeader(value) { - signatureRef.get(this).unprotectedHeader = value; - } - get _unprotectedHeader() { - return signatureRef.get(this).unprotectedHeader; - } -} -class GeneralSign { - constructor(payload) { - this._signatures = []; - this._payload = payload; - } - addSignature(key, options) { - const signature = new IndividualSignature(); - signatureRef.set(signature, { key, options }); - this._signatures.push(signature); - return signature; - } - async sign() { - if (!this._signatures.length) { - throw new JWSInvalid('at least one signature must be added'); - } - const jws = { - signatures: [], - payload: '', - }; - let payloads = new Set(); - await Promise.all(this._signatures.map(async (sig) => { - const { protectedHeader, unprotectedHeader, options, key } = signatureRef.get(sig); - const flattened = new FlattenedSign(this._payload); - if (protectedHeader) { - flattened.setProtectedHeader(protectedHeader); - } - if (unprotectedHeader) { - flattened.setUnprotectedHeader(unprotectedHeader); - } - const { payload, ...rest } = await flattened.sign(key, options); - payloads.add(payload); - jws.payload = payload; - jws.signatures.push(rest); - })); - if (payloads.size !== 1) { - throw new JWSInvalid('inconsistent use of JWS Unencoded Payload Option (RFC7797)'); - } - return jws; - } -} -export { GeneralSign }; -export default GeneralSign; diff --git a/dist/node/esm/jws/general/verify.js b/dist/node/esm/jws/general/verify.js deleted file mode 100644 index 1b97eecadd..0000000000 --- a/dist/node/esm/jws/general/verify.js +++ /dev/null @@ -1,26 +0,0 @@ -import verify from '../flattened/verify.js'; -import { JWSInvalid, JWSSignatureVerificationFailed } from '../../util/errors.js'; -import isObject from '../../lib/is_object.js'; -async function generalVerify(jws, key, options) { - if (!isObject(jws)) { - throw new JWSInvalid('General JWS must be an object'); - } - if (!Array.isArray(jws.signatures) || !jws.signatures.every(isObject)) { - throw new JWSInvalid('JWS Signatures missing or incorrect type'); - } - for (const signature of jws.signatures) { - try { - return await verify({ - header: signature.header, - payload: jws.payload, - protected: signature.protected, - signature: signature.signature, - }, key, options); - } - catch { - } - } - throw new JWSSignatureVerificationFailed(); -} -export { generalVerify }; -export default generalVerify; diff --git a/dist/node/esm/jwt/decrypt.js b/dist/node/esm/jwt/decrypt.js deleted file mode 100644 index ed1b4286c5..0000000000 --- a/dist/node/esm/jwt/decrypt.js +++ /dev/null @@ -1,21 +0,0 @@ -import decrypt from '../jwe/compact/decrypt.js'; -import jwtPayload from '../lib/jwt_claims_set.js'; -import { JWTClaimValidationFailed } from '../util/errors.js'; -async function jwtDecrypt(jwt, key, options) { - const decrypted = await decrypt(jwt, key, options); - const payload = jwtPayload(decrypted.protectedHeader, decrypted.plaintext, options); - const { protectedHeader } = decrypted; - if (protectedHeader.iss !== undefined && protectedHeader.iss !== payload.iss) { - throw new JWTClaimValidationFailed('replicated "iss" claim header parameter mismatch', 'iss', 'mismatch'); - } - if (protectedHeader.sub !== undefined && protectedHeader.sub !== payload.sub) { - throw new JWTClaimValidationFailed('replicated "sub" claim header parameter mismatch', 'sub', 'mismatch'); - } - if (protectedHeader.aud !== undefined && - JSON.stringify(protectedHeader.aud) !== JSON.stringify(payload.aud)) { - throw new JWTClaimValidationFailed('replicated "aud" claim header parameter mismatch', 'aud', 'mismatch'); - } - return { payload, protectedHeader }; -} -export { jwtDecrypt }; -export default jwtDecrypt; diff --git a/dist/node/esm/jwt/encrypt.js b/dist/node/esm/jwt/encrypt.js deleted file mode 100644 index ef8ac9156f..0000000000 --- a/dist/node/esm/jwt/encrypt.js +++ /dev/null @@ -1,70 +0,0 @@ -import CompactEncrypt from '../jwe/compact/encrypt.js'; -import { encoder } from '../lib/buffer_utils.js'; -import ProduceJWT from '../lib/jwt_producer.js'; -class EncryptJWT extends ProduceJWT { - setProtectedHeader(protectedHeader) { - if (this._protectedHeader) { - throw new TypeError('setProtectedHeader can only be called once'); - } - this._protectedHeader = protectedHeader; - return this; - } - setKeyManagementParameters(parameters) { - if (this._keyManagementParameters) { - throw new TypeError('setKeyManagementParameters can only be called once'); - } - this._keyManagementParameters = parameters; - return this; - } - setContentEncryptionKey(cek) { - if (this._cek) { - throw new TypeError('setContentEncryptionKey can only be called once'); - } - this._cek = cek; - return this; - } - setInitializationVector(iv) { - if (this._iv) { - throw new TypeError('setInitializationVector can only be called once'); - } - this._iv = iv; - return this; - } - replicateIssuerAsHeader() { - this._replicateIssuerAsHeader = true; - return this; - } - replicateSubjectAsHeader() { - this._replicateSubjectAsHeader = true; - return this; - } - replicateAudienceAsHeader() { - this._replicateAudienceAsHeader = true; - return this; - } - async encrypt(key, options) { - 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 { EncryptJWT }; -export default EncryptJWT; diff --git a/dist/node/esm/jwt/sign.js b/dist/node/esm/jwt/sign.js deleted file mode 100644 index 0707f7ebf7..0000000000 --- a/dist/node/esm/jwt/sign.js +++ /dev/null @@ -1,23 +0,0 @@ -import CompactSign from '../jws/compact/sign.js'; -import { JWTInvalid } from '../util/errors.js'; -import { encoder } from '../lib/buffer_utils.js'; -import ProduceJWT from '../lib/jwt_producer.js'; -class SignJWT extends ProduceJWT { - setProtectedHeader(protectedHeader) { - this._protectedHeader = protectedHeader; - return this; - } - async sign(key, options) { - var _a; - const sig = new CompactSign(encoder.encode(JSON.stringify(this._payload))); - sig.setProtectedHeader(this._protectedHeader); - if (Array.isArray((_a = this._protectedHeader) === null || _a === void 0 ? void 0 : _a.crit) && - this._protectedHeader.crit.includes('b64') && - this._protectedHeader.b64 === false) { - throw new JWTInvalid('JWTs MUST NOT use unencoded payload'); - } - return sig.sign(key, options); - } -} -export { SignJWT }; -export default SignJWT; diff --git a/dist/node/esm/jwt/unsecured.js b/dist/node/esm/jwt/unsecured.js deleted file mode 100644 index 0d3177ccec..0000000000 --- a/dist/node/esm/jwt/unsecured.js +++ /dev/null @@ -1,34 +0,0 @@ -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'; -class UnsecuredJWT extends ProduceJWT { - encode() { - const header = base64url.encode(JSON.stringify({ alg: 'none' })); - const payload = base64url.encode(JSON.stringify(this._payload)); - return `${header}.${payload}.`; - } - static decode(jwt, options) { - 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; - 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 { UnsecuredJWT }; -export default UnsecuredJWT; diff --git a/dist/node/esm/jwt/verify.js b/dist/node/esm/jwt/verify.js deleted file mode 100644 index 2295d81306..0000000000 --- a/dist/node/esm/jwt/verify.js +++ /dev/null @@ -1,14 +0,0 @@ -import verify from '../jws/compact/verify.js'; -import jwtPayload from '../lib/jwt_claims_set.js'; -import { JWTInvalid } from '../util/errors.js'; -async function jwtVerify(jwt, key, options) { - var _a; - const verified = await verify(jwt, key, options); - if (((_a = verified.protectedHeader.crit) === null || _a === void 0 ? void 0 : _a.includes('b64')) && verified.protectedHeader.b64 === false) { - throw new JWTInvalid('JWTs MUST NOT use unencoded payload'); - } - const payload = jwtPayload(verified.protectedHeader, verified.payload, options); - return { payload, protectedHeader: verified.protectedHeader }; -} -export { jwtVerify }; -export default jwtVerify; diff --git a/dist/node/esm/lib/buffer_utils.js b/dist/node/esm/lib/buffer_utils.js deleted file mode 100644 index d9392a633d..0000000000 --- a/dist/node/esm/lib/buffer_utils.js +++ /dev/null @@ -1,56 +0,0 @@ -export const encoder = new TextEncoder(); -export const decoder = new TextDecoder(); -const MAX_INT32 = 2 ** 32; -export function concat(...buffers) { - 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, p2sInput) { - return concat(encoder.encode(alg), new Uint8Array([0]), p2sInput); -} -function writeUInt32BE(buf, value, offset) { - 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) { - 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) { - const buf = new Uint8Array(4); - writeUInt32BE(buf, value); - return buf; -} -export function lengthAndInput(input) { - return concat(uint32be(input.length), input); -} -export async function concatKdf(digest, secret, bits, value) { - const iterations = Math.ceil((bits >> 3) / 32); - let res; - 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('sha256', buf); - } - else { - res = concat(res, await digest('sha256', buf)); - } - } - res = res.slice(0, bits >> 3); - return res; -} diff --git a/dist/node/esm/lib/cek.js b/dist/node/esm/lib/cek.js deleted file mode 100644 index 702d8a0533..0000000000 --- a/dist/node/esm/lib/cek.js +++ /dev/null @@ -1,18 +0,0 @@ -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) => (alg) => { - 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/dist/node/esm/lib/check_iv_length.js b/dist/node/esm/lib/check_iv_length.js deleted file mode 100644 index 3bb1ecb38a..0000000000 --- a/dist/node/esm/lib/check_iv_length.js +++ /dev/null @@ -1,8 +0,0 @@ -import { JWEInvalid } from '../util/errors.js'; -import { bitLengths } from './iv.js'; -const checkIvLength = (enc, iv) => { - if (iv.length << 3 !== bitLengths.get(enc)) { - throw new JWEInvalid('Invalid Initialization Vector length'); - } -}; -export default checkIvLength; diff --git a/dist/node/esm/lib/check_key_type.js b/dist/node/esm/lib/check_key_type.js deleted file mode 100644 index 4702e55436..0000000000 --- a/dist/node/esm/lib/check_key_type.js +++ /dev/null @@ -1,28 +0,0 @@ -import invalidKeyInput from '../runtime/invalid_key_input.js'; -const checkKeyType = (alg, key, usage) => { - if (!(key instanceof Uint8Array) && !(key === null || key === void 0 ? void 0 : key.type)) { - throw new TypeError(invalidKeyInput(key, 'KeyObject', 'CryptoKey', 'Uint8Array')); - } - 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(invalidKeyInput(key, 'KeyObject', 'CryptoKey')); - } - if (key.type === 'secret') { - throw new TypeError('CryptoKey or KeyObject instances for asymmetric algorithms must not be of type "secret"'); - } - if (usage === 'sign' && key.type === 'public') { - throw new TypeError('CryptoKey or KeyObject instances for asymmetric algorithm signing must be of type "private"'); - } - if (usage === 'decrypt' && key.type === 'public') { - throw new TypeError('CryptoKey or KeyObject instances for asymmetric algorithm decryption must be of type "private"'); - } -}; -export default checkKeyType; diff --git a/dist/node/esm/lib/check_p2s.js b/dist/node/esm/lib/check_p2s.js deleted file mode 100644 index a65289fa7a..0000000000 --- a/dist/node/esm/lib/check_p2s.js +++ /dev/null @@ -1,6 +0,0 @@ -import { JWEInvalid } from '../util/errors.js'; -export default function checkP2s(p2s) { - if (!(p2s instanceof Uint8Array) || p2s.length < 8) { - throw new JWEInvalid('PBES2 Salt Input must be 8 or more octets'); - } -} diff --git a/dist/node/esm/lib/decrypt_key_management.js b/dist/node/esm/lib/decrypt_key_management.js deleted file mode 100644 index d82f5c100f..0000000000 --- a/dist/node/esm/lib/decrypt_key_management.js +++ /dev/null @@ -1,95 +0,0 @@ -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'; -import { parseJwk } from '../jwk/parse.js'; -import checkKeyType from './check_key_type.js'; -function assertEnryptedKey(encryptedKey) { - if (!encryptedKey) { - throw new JWEInvalid('JWE Encrypted Key missing'); - } -} -function assertHeaderParameter(joseHeader, parameter, name) { - if (joseHeader[parameter] === undefined) { - throw new JWEInvalid(`JOSE Header ${name} (${parameter}) missing`); - } -} -async function decryptKeyManagement(alg, key, encryptedKey, joseHeader) { - checkKeyType(alg, key, 'decrypt'); - switch (alg) { - case 'dir': { - if (encryptedKey !== undefined) { - throw new JWEInvalid('Encountered unexpected JWE Encrypted Key'); - } - return key; - } - case 'ECDH-ES': - if (encryptedKey !== undefined) { - throw new JWEInvalid('Encountered unexpected JWE Encrypted Key'); - } - case 'ECDH-ES+A128KW': - case 'ECDH-ES+A192KW': - case 'ECDH-ES+A256KW': { - assertHeaderParameter(joseHeader, 'epk', 'Ephemeral Public Key'); - if (!ECDH.ecdhAllowed(key)) { - throw new JOSENotSupported('ECDH-ES with the provided key is not allowed or not supported by your javascript runtime'); - } - const epk = await parseJwk(joseHeader.epk, alg); - let partyUInfo; - let partyVInfo; - if (joseHeader.apu !== undefined) - partyUInfo = base64url(joseHeader.apu); - if (joseHeader.apv !== undefined) - partyVInfo = base64url(joseHeader.apv); - const sharedSecret = await ECDH.deriveKey(epk, key, alg === 'ECDH-ES' ? joseHeader.enc : alg, parseInt(alg.substr(-5, 3), 10) || cekLengths.get(joseHeader.enc), partyUInfo, partyVInfo); - if (alg === 'ECDH-ES') { - return sharedSecret; - } - 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': { - assertEnryptedKey(encryptedKey); - return rsaEs(alg, key, encryptedKey); - } - case 'PBES2-HS256+A128KW': - case 'PBES2-HS384+A192KW': - case 'PBES2-HS512+A256KW': { - 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': { - assertEnryptedKey(encryptedKey); - return aesKw(alg, key, encryptedKey); - } - case 'A128GCMKW': - case 'A192GCMKW': - case 'A256GCMKW': { - 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('unsupported or invalid "alg" (JWE Algorithm) header value'); - } - } -} -export default decryptKeyManagement; diff --git a/dist/node/esm/lib/encrypt_key_management.js b/dist/node/esm/lib/encrypt_key_management.js deleted file mode 100644 index 97199e204e..0000000000 --- a/dist/node/esm/lib/encrypt_key_management.js +++ /dev/null @@ -1,87 +0,0 @@ -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'; -import { fromKeyLike } from '../jwk/from_key_like.js'; -import checkKeyType from './check_key_type.js'; -const generateCek = cekFactory(random); -async function encryptKeyManagement(alg, enc, key, providedCek, providedParameters = {}) { - let encryptedKey; - let parameters; - let cek; - checkKeyType(alg, key, 'encrypt'); - switch (alg) { - case 'dir': { - cek = key; - break; - } - case 'ECDH-ES': - case 'ECDH-ES+A128KW': - case 'ECDH-ES+A192KW': - case 'ECDH-ES+A256KW': { - if (!ECDH.ecdhAllowed(key)) { - throw new JOSENotSupported('ECDH-ES with the provided key is not allowed or not supported by your javascript runtime'); - } - const { apu, apv } = providedParameters; - let { epk: ephemeralKey } = providedParameters; - ephemeralKey || (ephemeralKey = await ECDH.generateEpk(key)); - const { x, y, crv, kty } = await fromKeyLike(ephemeralKey); - const sharedSecret = await ECDH.deriveKey(key, ephemeralKey, alg === 'ECDH-ES' ? enc : alg, parseInt(alg.substr(-5, 3), 10) || cekLengths.get(enc), apu, apv); - parameters = { epk: { x, y, crv, kty } }; - if (apu) - parameters.apu = base64url(apu); - if (apv) - parameters.apv = base64url(apv); - if (alg === 'ECDH-ES') { - cek = sharedSecret; - break; - } - cek = providedCek || 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': { - cek = providedCek || generateCek(enc); - encryptedKey = await rsaEs(alg, key, cek); - break; - } - case 'PBES2-HS256+A128KW': - case 'PBES2-HS384+A192KW': - case 'PBES2-HS512+A256KW': { - cek = providedCek || generateCek(enc); - const { p2c, p2s } = providedParameters; - ({ encryptedKey, ...parameters } = await pbes2Kw(alg, key, cek, p2c, p2s)); - break; - } - case 'A128KW': - case 'A192KW': - case 'A256KW': { - cek = providedCek || generateCek(enc); - encryptedKey = await aesKw(alg, key, cek); - break; - } - case 'A128GCMKW': - case 'A192GCMKW': - case 'A256GCMKW': { - cek = providedCek || generateCek(enc); - const { iv } = providedParameters; - ({ encryptedKey, ...parameters } = await aesGcmKw(alg, key, cek, iv)); - break; - } - default: { - throw new JOSENotSupported('unsupported or invalid "alg" (JWE Algorithm) header value'); - } - } - return { cek, encryptedKey, parameters }; -} -export default encryptKeyManagement; diff --git a/dist/node/esm/lib/epoch.js b/dist/node/esm/lib/epoch.js deleted file mode 100644 index e405e4b2df..0000000000 --- a/dist/node/esm/lib/epoch.js +++ /dev/null @@ -1 +0,0 @@ -export default (date) => Math.floor(date.getTime() / 1000); diff --git a/dist/node/esm/lib/is_disjoint.js b/dist/node/esm/lib/is_disjoint.js deleted file mode 100644 index 6f643502dc..0000000000 --- a/dist/node/esm/lib/is_disjoint.js +++ /dev/null @@ -1,22 +0,0 @@ -const isDisjoint = (...headers) => { - const sources = headers.filter(Boolean); - if (sources.length === 0 || sources.length === 1) { - return true; - } - let acc; - 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/dist/node/esm/lib/is_object.js b/dist/node/esm/lib/is_object.js deleted file mode 100644 index 4955e93225..0000000000 --- a/dist/node/esm/lib/is_object.js +++ /dev/null @@ -1,16 +0,0 @@ -function isObjectLike(value) { - return typeof value === 'object' && value !== null; -} -export default function isObject(input) { - if (!isObjectLike(input) || Object.prototype.toString.call(input) !== '[object Object]') { - return false; - } - if (Object.getPrototypeOf(input) === null) { - return true; - } - let proto = input; - while (Object.getPrototypeOf(proto) !== null) { - proto = Object.getPrototypeOf(proto); - } - return Object.getPrototypeOf(input) === proto; -} diff --git a/dist/node/esm/lib/iv.js b/dist/node/esm/lib/iv.js deleted file mode 100644 index d254aa16dc..0000000000 --- a/dist/node/esm/lib/iv.js +++ /dev/null @@ -1,21 +0,0 @@ -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) => (alg) => { - 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/dist/node/esm/lib/jwt_claims_set.js b/dist/node/esm/lib/jwt_claims_set.js deleted file mode 100644 index 48eb897b77..0000000000 --- a/dist/node/esm/lib/jwt_claims_set.js +++ /dev/null @@ -1,96 +0,0 @@ -import { JWTClaimValidationFailed, JWTExpired, JWTInvalid } from '../util/errors.js'; -import { decoder } from './buffer_utils.js'; -import epoch from './epoch.js'; -import secs from './secs.js'; -import isObject from './is_object.js'; -const normalizeTyp = (value) => value.toLowerCase().replace(/^application\//, ''); -const checkAudiencePresence = (audPayload, audOption) => { - if (typeof audPayload === 'string') { - return audOption.includes(audPayload); - } - if (Array.isArray(audPayload)) { - return audOption.some(Set.prototype.has.bind(new Set(audPayload))); - } - return false; -}; -export default (protectedHeader, encodedPayload, options = {}) => { - 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; - try { - payload = JSON.parse(decoder.decode(encodedPayload)); - } - catch { - } - if (!isObject(payload)) { - throw new JWTInvalid('JWT Claims Set must be a top-level JSON object'); - } - const { issuer } = options; - if (issuer && !(Array.isArray(issuer) ? 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; - 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 (payload.iat !== undefined || options.maxTokenAge) { - if (typeof payload.iat !== 'number') { - throw new JWTClaimValidationFailed('"iat" claim must be a number', 'iat', 'invalid'); - } - if (payload.exp === undefined && payload.iat > now + tolerance) { - throw new JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', 'iat', 'check_failed'); - } - } - if (payload.nbf !== undefined) { - 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 (payload.exp !== undefined) { - 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/dist/node/esm/lib/jwt_producer.js b/dist/node/esm/lib/jwt_producer.js deleted file mode 100644 index e6b047337c..0000000000 --- a/dist/node/esm/lib/jwt_producer.js +++ /dev/null @@ -1,54 +0,0 @@ -import epoch from './epoch.js'; -import isObject from './is_object.js'; -import secs from './secs.js'; -export default class ProduceJWT { - constructor(payload) { - if (!isObject(payload)) { - throw new TypeError('JWT Claims Set MUST be an object'); - } - this._payload = payload; - } - setIssuer(issuer) { - this._payload = { ...this._payload, iss: issuer }; - return this; - } - setSubject(subject) { - this._payload = { ...this._payload, sub: subject }; - return this; - } - setAudience(audience) { - this._payload = { ...this._payload, aud: audience }; - return this; - } - setJti(jwtId) { - this._payload = { ...this._payload, jti: jwtId }; - return this; - } - setNotBefore(input) { - if (typeof input === 'number') { - this._payload = { ...this._payload, nbf: input }; - } - else { - this._payload = { ...this._payload, nbf: epoch(new Date()) + secs(input) }; - } - return this; - } - setExpirationTime(input) { - if (typeof input === 'number') { - this._payload = { ...this._payload, exp: input }; - } - else { - this._payload = { ...this._payload, exp: epoch(new Date()) + secs(input) }; - } - return this; - } - setIssuedAt(input) { - if (typeof input === 'undefined') { - this._payload = { ...this._payload, iat: epoch(new Date()) }; - } - else { - this._payload = { ...this._payload, iat: input }; - } - return this; - } -} diff --git a/dist/node/esm/lib/secs.js b/dist/node/esm/lib/secs.js deleted file mode 100644 index cf470ed8ad..0000000000 --- a/dist/node/esm/lib/secs.js +++ /dev/null @@ -1,44 +0,0 @@ -const minute = 60; -const hour = minute * 60; -const day = hour * 24; -const week = day * 7; -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; -export default (str) => { - const matched = REGEX.exec(str); - if (!matched) { - throw new TypeError('Invalid time period format'); - } - const value = parseFloat(matched[1]); - const unit = matched[2].toLowerCase(); - switch (unit) { - case 'sec': - case 'secs': - case 'second': - case 'seconds': - case 's': - return Math.round(value); - case 'minute': - case 'minutes': - case 'min': - case 'mins': - case 'm': - return Math.round(value * minute); - case 'hour': - case 'hours': - case 'hr': - case 'hrs': - case 'h': - return Math.round(value * hour); - case 'day': - case 'days': - case 'd': - return Math.round(value * day); - case 'week': - case 'weeks': - case 'w': - return Math.round(value * week); - default: - return Math.round(value * year); - } -}; diff --git a/dist/node/esm/lib/validate_algorithms.js b/dist/node/esm/lib/validate_algorithms.js deleted file mode 100644 index a6a7918571..0000000000 --- a/dist/node/esm/lib/validate_algorithms.js +++ /dev/null @@ -1,11 +0,0 @@ -const validateAlgorithms = (option, algorithms) => { - 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/dist/node/esm/lib/validate_crit.js b/dist/node/esm/lib/validate_crit.js deleted file mode 100644 index 68c69f18f5..0000000000 --- a/dist/node/esm/lib/validate_crit.js +++ /dev/null @@ -1,34 +0,0 @@ -import { JOSENotSupported } from '../util/errors.js'; -function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) { - if (joseHeader.crit !== undefined && protectedHeader.crit === undefined) { - throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected'); - } - if (!protectedHeader || protectedHeader.crit === undefined) { - return new Set(); - } - if (!Array.isArray(protectedHeader.crit) || - protectedHeader.crit.length === 0 || - protectedHeader.crit.some((input) => typeof input !== 'string' || input.length === 0)) { - throw new Err('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present'); - } - let recognized; - if (recognizedOption !== undefined) { - recognized = new Map([...Object.entries(recognizedOption), ...recognizedDefault.entries()]); - } - else { - recognized = recognizedDefault; - } - for (const parameter of protectedHeader.crit) { - if (!recognized.has(parameter)) { - throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`); - } - if (joseHeader[parameter] === undefined) { - throw new Err(`Extension Header Parameter "${parameter}" is missing`); - } - else if (recognized.get(parameter) && protectedHeader[parameter] === undefined) { - throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`); - } - } - return new Set(protectedHeader.crit); -} -export default validateCrit; diff --git a/dist/node/esm/package.json b/dist/node/esm/package.json deleted file mode 100644 index 6990891ff3..0000000000 --- a/dist/node/esm/package.json +++ /dev/null @@ -1 +0,0 @@ -{"type": "module"} diff --git a/dist/node/esm/runtime/aesgcmkw.js b/dist/node/esm/runtime/aesgcmkw.js deleted file mode 100644 index 5fd5acc5b2..0000000000 --- a/dist/node/esm/runtime/aesgcmkw.js +++ /dev/null @@ -1,16 +0,0 @@ -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 = async (alg, key, cek, iv) => { - const jweAlgorithm = alg.substr(0, 7); - iv || (iv = generateIv(jweAlgorithm)); - const { ciphertext: encryptedKey, tag } = await encrypt(jweAlgorithm, cek, key, iv, new Uint8Array(0)); - return { encryptedKey, iv: base64url(iv), tag: base64url(tag) }; -}; -export const unwrap = async (alg, key, encryptedKey, iv, tag) => { - const jweAlgorithm = alg.substr(0, 7); - return decrypt(jweAlgorithm, key, encryptedKey, iv, tag, new Uint8Array(0)); -}; diff --git a/dist/node/esm/runtime/aeskw.js b/dist/node/esm/runtime/aeskw.js deleted file mode 100644 index b3c7a0649e..0000000000 --- a/dist/node/esm/runtime/aeskw.js +++ /dev/null @@ -1,47 +0,0 @@ -import { createDecipheriv, createCipheriv } from 'crypto'; -import { JOSENotSupported } from '../util/errors.js'; -import { concat } from '../lib/buffer_utils.js'; -import getSecretKey from './secret_key.js'; -import { isCryptoKey, getKeyObject } from './webcrypto.js'; -import isKeyObject from './is_key_object.js'; -import invalidKeyInput from './invalid_key_input.js'; -import supported from './ciphers.js'; -function checkKeySize(key, alg) { - if (key.symmetricKeySize << 3 !== parseInt(alg.substr(1, 3), 10)) { - throw new TypeError(`invalid key size for alg: ${alg}`); - } -} -function ensureKeyObject(key, alg, usage) { - if (isKeyObject(key)) { - return key; - } - if (key instanceof Uint8Array) { - return getSecretKey(key); - } - if (isCryptoKey(key)) { - return getKeyObject(key, alg, new Set([usage])); - } - throw new TypeError(invalidKeyInput(key, 'KeyObject', 'CryptoKey', 'Uint8Array')); -} -export const wrap = async (alg, key, cek) => { - const size = parseInt(alg.substr(1, 3), 10); - const algorithm = `aes${size}-wrap`; - if (!supported(algorithm)) { - throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`); - } - const keyObject = ensureKeyObject(key, alg, 'wrapKey'); - checkKeySize(keyObject, alg); - const cipher = createCipheriv(algorithm, keyObject, Buffer.alloc(8, 0xa6)); - return concat(cipher.update(cek), cipher.final()); -}; -export const unwrap = async (alg, key, encryptedKey) => { - const size = parseInt(alg.substr(1, 3), 10); - const algorithm = `aes${size}-wrap`; - if (!supported(algorithm)) { - throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`); - } - const keyObject = ensureKeyObject(key, alg, 'unwrapKey'); - checkKeySize(keyObject, alg); - const cipher = createDecipheriv(algorithm, keyObject, Buffer.alloc(8, 0xa6)); - return concat(cipher.update(encryptedKey), cipher.final()); -}; diff --git a/dist/node/esm/runtime/asn1_sequence_decoder.js b/dist/node/esm/runtime/asn1_sequence_decoder.js deleted file mode 100644 index 61ba4c3116..0000000000 --- a/dist/node/esm/runtime/asn1_sequence_decoder.js +++ /dev/null @@ -1,44 +0,0 @@ -const tagInteger = 0x02; -const tagSequence = 0x30; -export default class Asn1SequenceDecoder { - constructor(buffer) { - if (buffer[0] !== tagSequence) { - throw new TypeError(); - } - this.buffer = buffer; - this.offset = 1; - const len = this.decodeLength(); - if (len !== buffer.length - this.offset) { - throw new TypeError(); - } - } - decodeLength() { - let length = this.buffer[this.offset++]; - if (length & 0x80) { - const nBytes = length & ~0x80; - length = 0; - for (let i = 0; i < nBytes; i++) - length = (length << 8) | this.buffer[this.offset + i]; - this.offset += nBytes; - } - return length; - } - unsignedInteger() { - if (this.buffer[this.offset++] !== tagInteger) { - throw new TypeError(); - } - let length = this.decodeLength(); - if (this.buffer[this.offset] === 0) { - this.offset++; - length--; - } - const result = this.buffer.slice(this.offset, this.offset + length); - this.offset += length; - return result; - } - end() { - if (this.offset !== this.buffer.length) { - throw new TypeError(); - } - } -} diff --git a/dist/node/esm/runtime/asn1_sequence_encoder.js b/dist/node/esm/runtime/asn1_sequence_encoder.js deleted file mode 100644 index e2bf458fba..0000000000 --- a/dist/node/esm/runtime/asn1_sequence_encoder.js +++ /dev/null @@ -1,87 +0,0 @@ -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) => { - 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')], -]); -export default class DumbAsn1Encoder { - constructor() { - this.length = 0; - this.elements = []; - } - oidFor(oid) { - 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) { - 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) { - const len = encodeLength(octStr.length); - this.elements.push(bTagOctStr, encodeLength(octStr.length), octStr); - this.length += 1 + len.length + octStr.length; - } - bitStr(bitS) { - 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) { - 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/dist/node/esm/runtime/base64url.js b/dist/node/esm/runtime/base64url.js deleted file mode 100644 index b92ccb4212..0000000000 --- a/dist/node/esm/runtime/base64url.js +++ /dev/null @@ -1,17 +0,0 @@ -import { decoder } from '../lib/buffer_utils.js'; -let encodeImpl; -function normalize(input) { - let encoded = input; - if (encoded instanceof Uint8Array) { - encoded = decoder.decode(encoded); - } - return encoded; -} -if (Buffer.isEncoding('base64url')) { - encodeImpl = (input) => Buffer.from(input).toString('base64url'); -} -else { - encodeImpl = (input) => Buffer.from(input).toString('base64').replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_'); -} -export const encode = encodeImpl; -export const decode = (input) => Buffer.from(normalize(input), 'base64'); diff --git a/dist/node/esm/runtime/cbc_tag.js b/dist/node/esm/runtime/cbc_tag.js deleted file mode 100644 index fa58c38b6c..0000000000 --- a/dist/node/esm/runtime/cbc_tag.js +++ /dev/null @@ -1,8 +0,0 @@ -import { createHmac } from 'crypto'; -import { concat, uint64be } from '../lib/buffer_utils.js'; -export default function cbcTag(aad, iv, ciphertext, macSize, macKey, keySize) { - 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/dist/node/esm/runtime/check_cek_length.js b/dist/node/esm/runtime/check_cek_length.js deleted file mode 100644 index a547578729..0000000000 --- a/dist/node/esm/runtime/check_cek_length.js +++ /dev/null @@ -1,33 +0,0 @@ -import { JWEInvalid, JOSENotSupported } from '../util/errors.js'; -import isKeyObject from './is_key_object.js'; -const checkCekLength = (enc, cek) => { - let expected; - 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 not supported 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 (isKeyObject(cek) && 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/dist/node/esm/runtime/check_modulus_length.js b/dist/node/esm/runtime/check_modulus_length.js deleted file mode 100644 index 690f809602..0000000000 --- a/dist/node/esm/runtime/check_modulus_length.js +++ /dev/null @@ -1,48 +0,0 @@ -export const weakMap = new WeakMap(); -const getLength = (buf, index) => { - let len = buf.readUInt8(1); - if ((len & 0x80) === 0) { - if (index === 0) { - return len; - } - return getLength(buf.subarray(2 + len), index - 1); - } - 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, index) => { - const len = sequence.readUInt8(1); - if ((len & 0x80) === 0) { - return getLength(sequence.subarray(2), index); - } - const num = len & 0x7f; - return getLength(sequence.subarray(2 + num), index); -}; -const getModulusLength = (key) => { - var _a, _b; - if (weakMap.has(key)) { - return weakMap.get(key); - } - const modulusLength = (_b = (_a = key.asymmetricKeyDetails) === null || _a === void 0 ? void 0 : _a.modulusLength) !== null && _b !== void 0 ? _b : (getLengthOfSeqIndex(key.export({ format: 'der', type: 'pkcs1' }), key.type === 'private' ? 1 : 0) - - 1) << - 3; - weakMap.set(key, modulusLength); - return modulusLength; -}; -export const setModulusLength = (keyObject, modulusLength) => { - weakMap.set(keyObject, modulusLength); -}; -export default (key, alg) => { - if (getModulusLength(key) < 2048) { - throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`); - } -}; diff --git a/dist/node/esm/runtime/ciphers.js b/dist/node/esm/runtime/ciphers.js deleted file mode 100644 index daded1d503..0000000000 --- a/dist/node/esm/runtime/ciphers.js +++ /dev/null @@ -1,6 +0,0 @@ -import { getCiphers } from 'crypto'; -let ciphers; -export default (algorithm) => { - ciphers || (ciphers = new Set(getCiphers())); - return ciphers.has(algorithm); -}; diff --git a/dist/node/esm/runtime/decrypt.js b/dist/node/esm/runtime/decrypt.js deleted file mode 100644 index f65703f089..0000000000 --- a/dist/node/esm/runtime/decrypt.js +++ /dev/null @@ -1,90 +0,0 @@ -import { createDecipheriv } from 'crypto'; -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'; -import { isCryptoKey, getKeyObject } from './webcrypto.js'; -import isKeyObject from './is_key_object.js'; -import invalidKeyInput from './invalid_key_input.js'; -import supported from './ciphers.js'; -async function cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) { - const keySize = parseInt(enc.substr(1, 3), 10); - if (isKeyObject(cek)) { - cek = cek.export(); - } - const encKey = cek.subarray(keySize >> 3); - const macKey = cek.subarray(0, keySize >> 3); - const macSize = parseInt(enc.substr(-3), 10); - const algorithm = `aes-${keySize}-cbc`; - if (!supported(algorithm)) { - throw new JOSENotSupported(`alg ${enc} is not supported by your javascript runtime`); - } - const expectedTag = cbcTag(aad, iv, ciphertext, macSize, macKey, keySize); - let macCheckPassed; - try { - macCheckPassed = timingSafeEqual(tag, expectedTag); - } - catch { - } - if (!macCheckPassed) { - throw new JWEDecryptionFailed(); - } - let plaintext; - try { - const cipher = createDecipheriv(algorithm, encKey, iv); - plaintext = concat(cipher.update(ciphertext), cipher.final()); - } - catch { - } - if (!plaintext) { - throw new JWEDecryptionFailed(); - } - return plaintext; -} -async function gcmDecrypt(enc, cek, ciphertext, iv, tag, aad) { - const keySize = parseInt(enc.substr(1, 3), 10); - const algorithm = `aes-${keySize}-gcm`; - if (!supported(algorithm)) { - throw new JOSENotSupported(`alg ${enc} is not supported by your javascript runtime`); - } - try { - const cipher = createDecipheriv(algorithm, cek, iv, { authTagLength: 16 }); - cipher.setAuthTag(tag); - if (aad.byteLength) { - cipher.setAAD(aad, { plaintextLength: ciphertext.length }); - } - return concat(cipher.update(ciphertext), cipher.final()); - } - catch { - throw new JWEDecryptionFailed(); - } -} -const decrypt = async (enc, cek, ciphertext, iv, tag, aad) => { - let key; - if (isCryptoKey(cek)) { - key = getKeyObject(cek, enc, new Set(['decrypt'])); - } - else if (cek instanceof Uint8Array || isKeyObject(cek)) { - key = cek; - } - else { - throw new TypeError(invalidKeyInput(cek, 'KeyObject', 'CryptoKey', 'Uint8Array')); - } - checkCekLength(enc, key); - checkIvLength(enc, iv); - switch (enc) { - case 'A128CBC-HS256': - case 'A192CBC-HS384': - case 'A256CBC-HS512': - return cbcDecrypt(enc, key, ciphertext, iv, tag, aad); - case 'A128GCM': - case 'A192GCM': - case 'A256GCM': - return gcmDecrypt(enc, key, ciphertext, iv, tag, aad); - default: - throw new JOSENotSupported('unsupported JWE Content Encryption Algorithm'); - } -}; -export default decrypt; diff --git a/dist/node/esm/runtime/digest.js b/dist/node/esm/runtime/digest.js deleted file mode 100644 index 0facde6c29..0000000000 --- a/dist/node/esm/runtime/digest.js +++ /dev/null @@ -1,3 +0,0 @@ -import { createHash } from 'crypto'; -const digest = (algorithm, data) => createHash(algorithm).update(data).digest(); -export default digest; diff --git a/dist/node/esm/runtime/dsa_digest.js b/dist/node/esm/runtime/dsa_digest.js deleted file mode 100644 index ce7215bd67..0000000000 --- a/dist/node/esm/runtime/dsa_digest.js +++ /dev/null @@ -1,22 +0,0 @@ -import { JOSENotSupported } from '../util/errors.js'; -export default function dsaDigest(alg) { - 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 not supported either by JOSE or your javascript runtime`); - } -} diff --git a/dist/node/esm/runtime/ecdhes.js b/dist/node/esm/runtime/ecdhes.js deleted file mode 100644 index d8f565878f..0000000000 --- a/dist/node/esm/runtime/ecdhes.js +++ /dev/null @@ -1,49 +0,0 @@ -import { diffieHellman, generateKeyPair as generateKeyPairCb } from 'crypto'; -import { promisify } from 'util'; -import getNamedCurve from './get_named_curve.js'; -import { encoder, concat, uint32be, lengthAndInput, concatKdf } from '../lib/buffer_utils.js'; -import digest from './digest.js'; -import { JOSENotSupported } from '../util/errors.js'; -import { isCryptoKey, getKeyObject } from './webcrypto.js'; -import isKeyObject from './is_key_object.js'; -import invalidKeyInput from './invalid_key_input.js'; -const generateKeyPair = promisify(generateKeyPairCb); -export const deriveKey = async (publicKey, privateKey, algorithm, keyLength, apu = new Uint8Array(0), apv = new Uint8Array(0)) => { - const value = concat(lengthAndInput(encoder.encode(algorithm)), lengthAndInput(apu), lengthAndInput(apv), uint32be(keyLength)); - if (isCryptoKey(publicKey)) { - publicKey = getKeyObject(publicKey, 'ECDH-ES'); - } - if (!isKeyObject(publicKey)) { - throw new TypeError(invalidKeyInput(publicKey, 'KeyObject', 'CryptoKey')); - } - if (isCryptoKey(privateKey)) { - privateKey = getKeyObject(privateKey, 'ECDH-ES', new Set(['deriveBits', 'deriveKey'])); - } - if (!isKeyObject(privateKey)) { - throw new TypeError(invalidKeyInput(privateKey, 'KeyObject', 'CryptoKey')); - } - const sharedSecret = diffieHellman({ privateKey, publicKey }); - return concatKdf(digest, sharedSecret, keyLength, value); -}; -export const generateEpk = async (key) => { - if (isCryptoKey(key)) { - key = getKeyObject(key); - } - if (!isKeyObject(key)) { - throw new TypeError(invalidKeyInput(key, 'KeyObject', 'CryptoKey')); - } - 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 ecdhAllowed = (key) => ['P-256', 'P-384', 'P-521', 'X25519', 'X448'].includes(getNamedCurve(key)); diff --git a/dist/node/esm/runtime/encrypt.js b/dist/node/esm/runtime/encrypt.js deleted file mode 100644 index 4c526c1da6..0000000000 --- a/dist/node/esm/runtime/encrypt.js +++ /dev/null @@ -1,68 +0,0 @@ -import { createCipheriv } from 'crypto'; -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'; -import { isCryptoKey, getKeyObject } from './webcrypto.js'; -import isKeyObject from './is_key_object.js'; -import invalidKeyInput from './invalid_key_input.js'; -import { JOSENotSupported } from '../util/errors.js'; -import supported from './ciphers.js'; -async function cbcEncrypt(enc, plaintext, cek, iv, aad) { - const keySize = parseInt(enc.substr(1, 3), 10); - if (isKeyObject(cek)) { - cek = cek.export(); - } - const encKey = cek.subarray(keySize >> 3); - const macKey = cek.subarray(0, keySize >> 3); - const algorithm = `aes-${keySize}-cbc`; - if (!supported(algorithm)) { - throw new JOSENotSupported(`alg ${enc} is not supported by your javascript runtime`); - } - 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, plaintext, cek, iv, aad) { - const keySize = parseInt(enc.substr(1, 3), 10); - const algorithm = `aes-${keySize}-gcm`; - if (!supported(algorithm)) { - throw new JOSENotSupported(`alg ${enc} is not supported by your javascript runtime`); - } - const cipher = createCipheriv(algorithm, cek, iv, { authTagLength: 16 }); - if (aad.byteLength) { - cipher.setAAD(aad, { plaintextLength: plaintext.length }); - } - const ciphertext = concat(cipher.update(plaintext), cipher.final()); - const tag = cipher.getAuthTag(); - return { ciphertext, tag }; -} -const encrypt = async (enc, plaintext, cek, iv, aad) => { - let key; - if (isCryptoKey(cek)) { - key = getKeyObject(cek, enc, new Set(['encrypt'])); - } - else if (cek instanceof Uint8Array || isKeyObject(cek)) { - key = cek; - } - else { - throw new TypeError(invalidKeyInput(cek, 'KeyObject', 'CryptoKey', 'Uint8Array')); - } - checkCekLength(enc, key); - checkIvLength(enc, iv); - switch (enc) { - case 'A128CBC-HS256': - case 'A192CBC-HS384': - case 'A256CBC-HS512': - return cbcEncrypt(enc, plaintext, key, iv, aad); - case 'A128GCM': - case 'A192GCM': - case 'A256GCM': - return gcmEncrypt(enc, plaintext, key, iv, aad); - default: - throw new JOSENotSupported('unsupported JWE Content Encryption Algorithm'); - } -}; -export default encrypt; diff --git a/dist/node/esm/runtime/fetch_jwks.js b/dist/node/esm/runtime/fetch_jwks.js deleted file mode 100644 index 9d08245da6..0000000000 --- a/dist/node/esm/runtime/fetch_jwks.js +++ /dev/null @@ -1,34 +0,0 @@ -import { get as http } from 'http'; -import { get as https } from 'https'; -import { once } from 'events'; -import { JOSEError } from '../util/errors.js'; -import { concat, decoder } from '../lib/buffer_utils.js'; -const protocols = { - 'https:': https, - 'http:': http, -}; -const fetchJwks = async (url, timeout, options) => { - if (protocols[url.protocol] === undefined) { - throw new TypeError('Unsupported URL protocol.'); - } - const { agent } = options; - const req = protocols[url.protocol](url.href, { - agent, - timeout, - }); - const [response] = await once(req, 'response'); - if (response.statusCode !== 200) { - throw new JOSEError('Expected 200 OK from the JSON Web Key Set HTTP response'); - } - const parts = []; - for await (const part of response) { - parts.push(part); - } - try { - return JSON.parse(decoder.decode(concat(...parts))); - } - catch { - throw new JOSEError('Failed to parse the JSON Web Key Set HTTP response as JSON'); - } -}; -export default fetchJwks; diff --git a/dist/node/esm/runtime/generate.js b/dist/node/esm/runtime/generate.js deleted file mode 100644 index 19ce9c421d..0000000000 --- a/dist/node/esm/runtime/generate.js +++ /dev/null @@ -1,99 +0,0 @@ -import { createSecretKey, generateKeyPair as generateKeyPairCb } from 'crypto'; -import { promisify } from 'util'; -import random from './random.js'; -import { setModulusLength } from './check_modulus_length.js'; -import { JOSENotSupported } from '../util/errors.js'; -const generate = promisify(generateKeyPairCb); -export async function generateSecret(alg, options) { - let length; - 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))); -} -export async function generateKeyPair(alg, options) { - var _a, _b; - 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': { - const modulusLength = (_a = options === null || options === void 0 ? void 0 : options.modulusLength) !== null && _a !== void 0 ? _a : 2048; - if (typeof modulusLength !== 'number' || modulusLength < 2048) { - throw new JOSENotSupported('Invalid or unsupported modulusLength option provided, 2048 bits or larger keys must be used'); - } - const keypair = await generate('rsa', { - modulusLength, - publicExponent: 0x10001, - }); - setModulusLength(keypair.privateKey, modulusLength); - setModulusLength(keypair.publicKey, modulusLength); - return keypair; - } - 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 === null || options === void 0 ? void 0 : 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 === null || options === void 0 ? void 0 : options.crv) { - case undefined: - case 'P-256': - case 'P-384': - case 'P-521': - return generate('ec', { namedCurve: (_b = options === null || options === void 0 ? void 0 : options.crv) !== null && _b !== void 0 ? _b : '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/dist/node/esm/runtime/get_named_curve.js b/dist/node/esm/runtime/get_named_curve.js deleted file mode 100644 index 4d41d86d47..0000000000 --- a/dist/node/esm/runtime/get_named_curve.js +++ /dev/null @@ -1,85 +0,0 @@ -import { createPublicKey } from 'crypto'; -import { JOSENotSupported } from '../util/errors.js'; -import { isCryptoKey, getKeyObject } from './webcrypto.js'; -import isKeyObject from './is_key_object.js'; -import invalidKeyInput from './invalid_key_input.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]); -export const weakMap = new WeakMap(); -const namedCurveToJOSE = (namedCurve) => { - switch (namedCurve) { - case 'prime256v1': - return 'P-256'; - case 'secp384r1': - return 'P-384'; - case 'secp521r1': - return 'P-521'; - case 'secp256k1': - return namedCurve; - default: - throw new JOSENotSupported('unsupported key curve for this operation'); - } -}; -const getNamedCurve = (key, raw) => { - var _a; - if (isCryptoKey(key)) { - key = getKeyObject(key); - } - if (!isKeyObject(key)) { - throw new TypeError(invalidKeyInput(key, 'KeyObject', 'CryptoKey')); - } - if (key.type === 'secret') { - throw new TypeError('only "private" or "public" type keys can be used for this operation'); - } - switch (key.asymmetricKeyType) { - case 'ed25519': - case 'ed448': - return `Ed${key.asymmetricKeyType.substr(2)}`; - case 'x25519': - case 'x448': - return `X${key.asymmetricKeyType.substr(1)}`; - case 'ec': { - if (weakMap.has(key)) { - return weakMap.get(key); - } - let namedCurve = (_a = key.asymmetricKeyDetails) === null || _a === void 0 ? void 0 : _a.namedCurve; - if (!namedCurve && key.type === 'private') { - namedCurve = getNamedCurve(createPublicKey(key), true); - } - else if (!namedCurve) { - 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); - if (curveOid.equals(p256)) { - namedCurve = 'prime256v1'; - } - else if (curveOid.equals(p384)) { - namedCurve = 'secp384r1'; - } - else if (curveOid.equals(p521)) { - namedCurve = 'secp521r1'; - } - else if (curveOid.equals(secp256k1)) { - namedCurve = 'secp256k1'; - } - else { - throw new JOSENotSupported('unsupported key curve for this operation'); - } - } - if (raw) - return namedCurve; - const curve = namedCurveToJOSE(namedCurve); - weakMap.set(key, curve); - return curve; - } - default: - throw new TypeError('Invalid asymmetric key type for this operation'); - } -}; -export function setCurve(keyObject, curve) { - weakMap.set(keyObject, curve); -} -export default getNamedCurve; diff --git a/dist/node/esm/runtime/get_sign_verify_key.js b/dist/node/esm/runtime/get_sign_verify_key.js deleted file mode 100644 index a5c7ea7e3d..0000000000 --- a/dist/node/esm/runtime/get_sign_verify_key.js +++ /dev/null @@ -1,19 +0,0 @@ -import * as crypto from 'crypto'; -import { isCryptoKey, getKeyObject } from './webcrypto.js'; -import getSecretKey from './secret_key.js'; -import invalidKeyInput from './invalid_key_input.js'; -export default function getSignVerifyKey(alg, key, usage) { - if (key instanceof Uint8Array) { - if (!alg.startsWith('HS')) { - throw new TypeError(invalidKeyInput(key, 'KeyObject', 'CryptoKey')); - } - return getSecretKey(key); - } - if (key instanceof crypto.KeyObject) { - return key; - } - if (isCryptoKey(key)) { - return getKeyObject(key, alg, new Set([usage])); - } - throw new TypeError(invalidKeyInput(key, 'KeyObject', 'CryptoKey', 'Uint8Array')); -} diff --git a/dist/node/esm/runtime/hmac_digest.js b/dist/node/esm/runtime/hmac_digest.js deleted file mode 100644 index 29d55c3e9c..0000000000 --- a/dist/node/esm/runtime/hmac_digest.js +++ /dev/null @@ -1,13 +0,0 @@ -import { JOSENotSupported } from '../util/errors.js'; -export default function hmacDigest(alg) { - switch (alg) { - case 'HS256': - return 'sha256'; - case 'HS384': - return 'sha384'; - case 'HS512': - return 'sha512'; - default: - throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`); - } -} diff --git a/dist/node/esm/runtime/invalid_key_input.js b/dist/node/esm/runtime/invalid_key_input.js deleted file mode 100644 index 86e97074b9..0000000000 --- a/dist/node/esm/runtime/invalid_key_input.js +++ /dev/null @@ -1,36 +0,0 @@ -import { inspect } from 'util'; -export default (actual, ...types) => { - let msg = 'Key must be '; - if (types.length > 2) { - const last = types.pop(); - msg += `one of type ${types.join(', ')}, or ${last}.`; - } - else if (types.length === 2) { - msg += `one of type ${types[0]} or ${types[1]}.`; - } - else { - msg += `of type ${types[0]}.`; - } - if (actual == null) { - msg += ` Received ${actual}`; - } - else if (typeof actual === 'function' && actual.name) { - msg += ` Received function ${actual.name}`; - } - else if (typeof actual === 'object' && actual != null) { - if (actual.constructor && actual.constructor.name) { - msg += ` Received an instance of ${actual.constructor.name}`; - } - else { - const inspected = inspect(actual, { depth: -1 }); - msg += ` Received ${inspected}`; - } - } - else { - let inspected = inspect(actual, { colors: false }); - if (inspected.length > 25) - inspected = `${inspected.slice(0, 25)}...`; - msg += ` Received type ${typeof actual} (${inspected})`; - } - return msg; -}; diff --git a/dist/node/esm/runtime/is_key_object.js b/dist/node/esm/runtime/is_key_object.js deleted file mode 100644 index eb1af73b66..0000000000 --- a/dist/node/esm/runtime/is_key_object.js +++ /dev/null @@ -1,14 +0,0 @@ -import { KeyObject } from 'crypto'; -import * as util from 'util'; -let impl; -if (util.types.isKeyObject) { - impl = function isKeyObject(obj) { - return util.types.isKeyObject(obj); - }; -} -else { - impl = function isKeyObject(obj) { - return obj != null && obj instanceof KeyObject; - }; -} -export default impl; diff --git a/dist/node/esm/runtime/jwk_to_key.js b/dist/node/esm/runtime/jwk_to_key.js deleted file mode 100644 index cbd0af9df2..0000000000 --- a/dist/node/esm/runtime/jwk_to_key.js +++ /dev/null @@ -1,119 +0,0 @@ -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'; -const [major, minor] = process.version - .substr(1) - .split('.') - .map((str) => parseInt(str, 10)); -const jwkImportSupported = major >= 16 || (major === 15 && minor >= 12); -const parse = (jwk) => { - if (jwkImportSupported && jwk.kty !== 'oct') { - return jwk.d - ? createPrivateKey({ format: 'jwk', key: jwk }) - : createPublicKey({ format: 'jwk', key: jwk }); - } - 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.zero(); - 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 = { - 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; - const pub = Buffer.concat([ - Buffer.alloc(1, 4), - Buffer.from(jwk.x, 'base64'), - Buffer.from(jwk.y, 'base64'), - ]); - 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 enc$3 = new Asn1SequenceEncoder(); - enc$3.bitStr(pub); - const f2 = enc$3.end(Buffer.from([0xa1])); - enc$2.add(f2); - const f = enc$2.end(); - const enc$4 = new Asn1SequenceEncoder(); - enc$4.add(f); - const f3 = enc$4.end(Buffer.from([0x04])); - enc.add(f3); - 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()); - 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'); - } -}; -export default parse; diff --git a/dist/node/esm/runtime/key_to_jwk.js b/dist/node/esm/runtime/key_to_jwk.js deleted file mode 100644 index cc55525800..0000000000 --- a/dist/node/esm/runtime/key_to_jwk.js +++ /dev/null @@ -1,157 +0,0 @@ -import { createPublicKey } from 'crypto'; -import { encode as base64url } from './base64url.js'; -import Asn1SequenceDecoder from './asn1_sequence_decoder.js'; -import { JOSENotSupported } from '../util/errors.js'; -import getNamedCurve from './get_named_curve.js'; -import { isCryptoKey, getKeyObject } from './webcrypto.js'; -import isKeyObject from './is_key_object.js'; -import invalidKeyInput from './invalid_key_input.js'; -const [major, minor] = process.version - .substr(1) - .split('.') - .map((str) => parseInt(str, 10)); -const jwkExportSupported = major >= 16 || (major === 15 && minor >= 9); -const keyToJWK = (key) => { - let keyObject; - if (isCryptoKey(key)) { - if (!key.extractable) { - throw new TypeError('CryptoKey is not extractable'); - } - keyObject = getKeyObject(key); - } - else if (isKeyObject(key)) { - keyObject = key; - } - else if (key instanceof Uint8Array) { - return { - kty: 'oct', - k: base64url(key), - }; - } - else { - throw new TypeError(invalidKeyInput(key, 'KeyObject', 'CryptoKey', 'Uint8Array')); - } - if (jwkExportSupported) { - return keyObject.export({ format: 'jwk' }); - } - switch (keyObject.type) { - case 'secret': - return { - kty: 'oct', - k: base64url(keyObject.export()), - }; - case 'private': - case 'public': { - switch (keyObject.asymmetricKeyType) { - case 'rsa': { - const der = keyObject.export({ format: 'der', type: 'pkcs1' }); - const dec = new Asn1SequenceDecoder(der); - if (keyObject.type === 'private') { - dec.unsignedInteger(); - } - const n = base64url(dec.unsignedInteger()); - const e = base64url(dec.unsignedInteger()); - let jwk; - if (keyObject.type === 'private') { - jwk = { - d: base64url(dec.unsignedInteger()), - p: base64url(dec.unsignedInteger()), - q: base64url(dec.unsignedInteger()), - dp: base64url(dec.unsignedInteger()), - dq: base64url(dec.unsignedInteger()), - qi: base64url(dec.unsignedInteger()), - }; - } - dec.end(); - return { kty: 'RSA', n, e, ...jwk }; - } - case 'ec': { - const crv = getNamedCurve(keyObject); - let len; - let offset; - let correction; - switch (crv) { - case 'secp256k1': - len = 64; - offset = 31 + 2; - correction = -1; - break; - case 'P-256': - len = 64; - offset = 34 + 2; - correction = -1; - break; - case 'P-384': - len = 96; - offset = 33 + 2; - correction = -3; - break; - case 'P-521': - len = 132; - offset = 33 + 2; - correction = -3; - break; - default: - throw new JOSENotSupported('unsupported curve'); - } - if (keyObject.type === 'public') { - const der = keyObject.export({ type: 'spki', format: 'der' }); - return { - kty: 'EC', - crv, - x: base64url(der.subarray(-len, -len / 2)), - y: base64url(der.subarray(-len / 2)), - }; - } - const der = keyObject.export({ type: 'pkcs8', format: 'der' }); - if (der.length < 100) { - offset += correction; - } - return { - ...keyToJWK(createPublicKey(keyObject)), - d: base64url(der.subarray(offset, offset + len / 2)), - }; - } - case 'ed25519': - case 'x25519': { - const crv = getNamedCurve(keyObject); - if (keyObject.type === 'public') { - const der = keyObject.export({ type: 'spki', format: 'der' }); - return { - kty: 'OKP', - crv, - x: base64url(der.subarray(-32)), - }; - } - const der = keyObject.export({ type: 'pkcs8', format: 'der' }); - return { - ...keyToJWK(createPublicKey(keyObject)), - d: base64url(der.subarray(-32)), - }; - } - case 'ed448': - case 'x448': { - const crv = getNamedCurve(keyObject); - if (keyObject.type === 'public') { - const der = keyObject.export({ type: 'spki', format: 'der' }); - return { - kty: 'OKP', - crv, - x: base64url(der.subarray(crv === 'Ed448' ? -57 : -56)), - }; - } - const der = keyObject.export({ type: 'pkcs8', format: 'der' }); - return { - ...keyToJWK(createPublicKey(keyObject)), - d: base64url(der.subarray(crv === 'Ed448' ? -57 : -56)), - }; - } - default: - throw new JOSENotSupported('unsupported key asymmetricKeyType'); - } - } - default: - throw new JOSENotSupported('unsupported key type'); - } -}; -export default keyToJWK; diff --git a/dist/node/esm/runtime/node_key.js b/dist/node/esm/runtime/node_key.js deleted file mode 100644 index dc23351549..0000000000 --- a/dist/node/esm/runtime/node_key.js +++ /dev/null @@ -1,83 +0,0 @@ -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 [major, minor] = process.version - .substr(1) - .split('.') - .map((str) => parseInt(str, 10)); -const rsaPssParams = major >= 17 || (major === 16 && minor >= 9); -const ecCurveAlgMap = new Map([ - ['ES256', 'P-256'], - ['ES256K', 'secp256k1'], - ['ES384', 'P-384'], - ['ES512', 'P-521'], -]); -export default function keyForCrypto(alg, key) { - switch (alg) { - case 'EdDSA': - if (!['ed25519', 'ed448'].includes(key.asymmetricKeyType)) { - throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be ed25519 or ed448'); - } - return key; - case 'RS256': - case 'RS384': - case 'RS512': - if (key.asymmetricKeyType !== 'rsa') { - throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be rsa'); - } - checkModulusLength(key, alg); - return key; - case rsaPssParams && 'PS256': - case rsaPssParams && 'PS384': - case rsaPssParams && 'PS512': - if (key.asymmetricKeyType === 'rsa-pss') { - const { hashAlgorithm, mgf1HashAlgorithm, saltLength } = key.asymmetricKeyDetails; - const length = parseInt(alg.substr(-3), 10); - if (hashAlgorithm !== undefined && - (hashAlgorithm !== `sha${length}` || mgf1HashAlgorithm !== hashAlgorithm)) { - throw new TypeError(`Invalid key for this operation, its RSA-PSS parameters do not meet the requirements of "alg" ${alg}`); - } - if (saltLength !== undefined && saltLength > length >> 3) { - throw new TypeError(`Invalid key for this operation, its RSA-PSS parameter saltLength does not meet the requirements of "alg" ${alg}`); - } - } - else if (key.asymmetricKeyType !== 'rsa') { - throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be rsa or rsa-pss'); - } - checkModulusLength(key, alg); - return { - key, - padding: constants.RSA_PKCS1_PSS_PADDING, - saltLength: constants.RSA_PSS_SALTLEN_DIGEST, - }; - case !rsaPssParams && 'PS256': - case !rsaPssParams && 'PS384': - case !rsaPssParams && 'PS512': - if (key.asymmetricKeyType !== 'rsa') { - throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be rsa'); - } - 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.asymmetricKeyType !== 'ec') { - throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be ec'); - } - const actual = getNamedCurve(key); - const expected = ecCurveAlgMap.get(alg); - if (actual !== expected) { - throw new TypeError(`Invalid key curve for the algorithm, its curve must be ${expected}, got ${actual}`); - } - return { dsaEncoding: 'ieee-p1363', key }; - } - default: - throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`); - } -} diff --git a/dist/node/esm/runtime/pbes2kw.js b/dist/node/esm/runtime/pbes2kw.js deleted file mode 100644 index 04dc6ce40a..0000000000 --- a/dist/node/esm/runtime/pbes2kw.js +++ /dev/null @@ -1,40 +0,0 @@ -import { promisify } from 'util'; -import { pbkdf2 as pbkdf2cb } from 'crypto'; -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 { isCryptoKey, getKeyObject } from './webcrypto.js'; -import isKeyObject from './is_key_object.js'; -import invalidKeyInput from './invalid_key_input.js'; -const pbkdf2 = promisify(pbkdf2cb); -function getPassword(key, alg) { - if (isKeyObject(key)) { - return key.export(); - } - if (key instanceof Uint8Array) { - return key; - } - if (isCryptoKey(key)) { - return getKeyObject(key, alg, new Set(['deriveBits', 'deriveKey'])).export(); - } - throw new TypeError(invalidKeyInput(key, 'KeyObject', 'CryptoKey', 'Uint8Array')); -} -export const encrypt = async (alg, key, cek, p2c = Math.floor(Math.random() * 2049) + 2048, p2s = random(new Uint8Array(16))) => { - checkP2s(p2s); - const salt = concatSalt(alg, p2s); - const keylen = parseInt(alg.substr(13, 3), 10) >> 3; - const password = getPassword(key, alg); - 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 = async (alg, key, encryptedKey, p2c, p2s) => { - checkP2s(p2s); - const salt = concatSalt(alg, p2s); - const keylen = parseInt(alg.substr(13, 3), 10) >> 3; - const password = getPassword(key, alg); - const derivedKey = await pbkdf2(password, salt, p2c, keylen, `sha${alg.substr(8, 3)}`); - return unwrap(alg.substr(-6), derivedKey, encryptedKey); -}; diff --git a/dist/node/esm/runtime/random.js b/dist/node/esm/runtime/random.js deleted file mode 100644 index 587291011a..0000000000 --- a/dist/node/esm/runtime/random.js +++ /dev/null @@ -1,2 +0,0 @@ -import { randomFillSync } from 'crypto'; -export default randomFillSync; diff --git a/dist/node/esm/runtime/rsaes.js b/dist/node/esm/runtime/rsaes.js deleted file mode 100644 index bb5867f697..0000000000 --- a/dist/node/esm/runtime/rsaes.js +++ /dev/null @@ -1,61 +0,0 @@ -import { publicEncrypt, constants, privateDecrypt } from 'crypto'; -import checkModulusLength from './check_modulus_length.js'; -import { isCryptoKey, getKeyObject } from './webcrypto.js'; -import isKeyObject from './is_key_object.js'; -import invalidKeyInput from './invalid_key_input.js'; -const checkKey = (key, alg) => { - if (key.asymmetricKeyType !== 'rsa') { - throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be rsa'); - } - checkModulusLength(key, alg); -}; -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; - default: - return undefined; - } -}; -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; - } -}; -function ensureKeyObject(key, alg, ...usages) { - if (isKeyObject(key)) { - return key; - } - if (isCryptoKey(key)) { - return getKeyObject(key, alg, new Set(usages)); - } - throw new TypeError(invalidKeyInput(key, 'KeyObject', 'CryptoKey')); -} -export const encrypt = async (alg, key, cek) => { - const padding = resolvePadding(alg); - const oaepHash = resolveOaepHash(alg); - const keyObject = ensureKeyObject(key, alg, 'wrapKey', 'encrypt'); - checkKey(keyObject, alg); - return publicEncrypt({ key: keyObject, oaepHash, padding }, cek); -}; -export const decrypt = async (alg, key, encryptedKey) => { - const padding = resolvePadding(alg); - const oaepHash = resolveOaepHash(alg); - const keyObject = ensureKeyObject(key, alg, 'unwrapKey', 'decrypt'); - checkKey(keyObject, alg); - return privateDecrypt({ key: keyObject, oaepHash, padding }, encryptedKey); -}; diff --git a/dist/node/esm/runtime/secret_key.js b/dist/node/esm/runtime/secret_key.js deleted file mode 100644 index c395546796..0000000000 --- a/dist/node/esm/runtime/secret_key.js +++ /dev/null @@ -1,11 +0,0 @@ -import { createSecretKey } from 'crypto'; -export default function getSecretKey(key) { - let keyObject; - if (key instanceof Uint8Array) { - keyObject = createSecretKey(key); - } - else { - keyObject = key; - } - return keyObject; -} diff --git a/dist/node/esm/runtime/sign.js b/dist/node/esm/runtime/sign.js deleted file mode 100644 index d6f03a4b69..0000000000 --- a/dist/node/esm/runtime/sign.js +++ /dev/null @@ -1,27 +0,0 @@ -import * as crypto from 'crypto'; -import { promisify } from 'util'; -import nodeDigest from './dsa_digest.js'; -import hmacDigest from './hmac_digest.js'; -import nodeKey from './node_key.js'; -import getSignKey from './get_sign_verify_key.js'; -let oneShotSign; -if (crypto.sign.length > 3) { - oneShotSign = promisify(crypto.sign); -} -else { - oneShotSign = crypto.sign; -} -const sign = async (alg, key, data) => { - const keyObject = getSignKey(alg, key, 'sign'); - 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 = crypto.createHmac(hmacDigest(alg), keyObject); - hmac.update(data); - return hmac.digest(); - } - return oneShotSign(nodeDigest(alg), data, nodeKey(alg, keyObject)); -}; -export default sign; diff --git a/dist/node/esm/runtime/timing_safe_equal.js b/dist/node/esm/runtime/timing_safe_equal.js deleted file mode 100644 index 901ae38bdd..0000000000 --- a/dist/node/esm/runtime/timing_safe_equal.js +++ /dev/null @@ -1,3 +0,0 @@ -import { timingSafeEqual as impl } from 'crypto'; -const timingSafeEqual = impl; -export default timingSafeEqual; diff --git a/dist/node/esm/runtime/verify.js b/dist/node/esm/runtime/verify.js deleted file mode 100644 index ccc4004921..0000000000 --- a/dist/node/esm/runtime/verify.js +++ /dev/null @@ -1,40 +0,0 @@ -import * as crypto from 'crypto'; -import { promisify } from 'util'; -import nodeDigest from './dsa_digest.js'; -import nodeKey from './node_key.js'; -import sign from './sign.js'; -import getVerifyKey from './get_sign_verify_key.js'; -const [major, minor] = process.version - .substr(1) - .split('.') - .map((str) => parseInt(str, 10)); -const oneShotCallbackSupported = major >= 16 || (major === 15 && minor >= 13); -let oneShotVerify; -if (crypto.verify.length > 4 && oneShotCallbackSupported) { - oneShotVerify = promisify(crypto.verify); -} -else { - oneShotVerify = crypto.verify; -} -const verify = async (alg, key, signature, data) => { - const keyObject = getVerifyKey(alg, key, 'verify'); - if (alg.startsWith('HS')) { - const expected = await sign(alg, keyObject, data); - const actual = signature; - try { - return crypto.timingSafeEqual(actual, expected); - } - catch { - return false; - } - } - const algorithm = nodeDigest(alg); - const keyInput = nodeKey(alg, keyObject); - try { - return await oneShotVerify(algorithm, data, keyInput, signature); - } - catch { - return false; - } -}; -export default verify; diff --git a/dist/node/esm/runtime/webcrypto.js b/dist/node/esm/runtime/webcrypto.js deleted file mode 100644 index 67d34fad74..0000000000 --- a/dist/node/esm/runtime/webcrypto.js +++ /dev/null @@ -1,161 +0,0 @@ -import * as crypto from 'crypto'; -import * as util from 'util'; -const webcrypto = crypto.webcrypto; -export default webcrypto; -let impl; -if (util.types.isCryptoKey) { - impl = function isCryptoKey(obj) { - return util.types.isCryptoKey(obj); - }; -} -else if (webcrypto) { - impl = function isCryptoKey(obj) { - return obj != null && obj instanceof webcrypto.CryptoKey; - }; -} -else { - impl = (obj) => false; -} -export { impl as isCryptoKey }; -function getHashLength(hash) { - return parseInt(hash === null || hash === void 0 ? void 0 : hash.name.substr(4), 10); -} -function getNamedCurve(alg) { - switch (alg) { - case 'ES256': - return 'P-256'; - case 'ES384': - return 'P-384'; - case 'ES512': - return 'P-521'; - } -} -export function getKeyObject(key, alg, usage) { - if (!alg) { - return crypto.KeyObject.from(key); - } - switch (alg) { - case 'HS256': - case 'HS384': - case 'HS512': { - if (key.algorithm.name !== 'HMAC') { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be HMAC.`); - } - const expected = parseInt(alg.substr(2), 10); - const actual = getHashLength(key.algorithm.hash); - if (actual !== expected) { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.hash must be SHA-${expected}.`); - } - break; - } - case 'RS256': - case 'RS384': - case 'RS512': { - if (key.algorithm.name !== 'RSASSA-PKCS1-v1_5') { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be RSASSA-PKCS1-v1_5.`); - } - const expected = parseInt(alg.substr(2), 10); - const actual = getHashLength(key.algorithm.hash); - if (actual !== expected) { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.hash must be SHA-${expected}.`); - } - break; - } - case 'PS256': - case 'PS384': - case 'PS512': { - if (key.algorithm.name !== 'RSA-PSS') { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be RSA-PSS.`); - } - const expected = parseInt(alg.substr(2), 10); - const actual = getHashLength(key.algorithm.hash); - if (actual !== expected) { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.hash must be SHA-${expected}.`); - } - break; - } - case 'ES256': - case 'ES384': - case 'ES512': { - if (key.algorithm.name !== 'ECDSA') { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be ECDSA.`); - } - const expected = getNamedCurve(alg); - const actual = key.algorithm.namedCurve; - if (actual !== expected) { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.namedCurve must be ${expected}.`); - } - break; - } - case 'A128GCM': - case 'A192GCM': - case 'A256GCM': { - if (key.algorithm.name !== 'AES-GCM') { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be AES-GCM.`); - } - const expected = parseInt(alg.substr(1, 3), 10); - const actual = key.algorithm.length; - if (actual !== expected) { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.length must be ${expected}.`); - } - break; - } - case 'A128KW': - case 'A192KW': - case 'A256KW': { - if (key.algorithm.name !== 'AES-KW') { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be AES-KW.`); - } - const expected = parseInt(alg.substr(1, 3), 10); - const actual = key.algorithm.length; - if (actual !== expected) { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.length must be ${expected}.`); - } - break; - } - case 'ECDH-ES': - if (key.algorithm.name !== 'ECDH') { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be ECDH.`); - } - break; - case 'PBES2-HS256+A128KW': - case 'PBES2-HS384+A192KW': - case 'PBES2-HS512+A256KW': - if (key.algorithm.name !== 'PBKDF2') { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be PBKDF2.`); - } - break; - case 'RSA-OAEP': - case 'RSA-OAEP-256': - case 'RSA-OAEP-384': - case 'RSA-OAEP-512': { - if (key.algorithm.name !== 'RSA-OAEP') { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be RSA-OAEP.`); - } - const expected = parseInt(alg.substr(9), 10) || 1; - const actual = getHashLength(key.algorithm.hash); - if (actual !== expected) { - throw new TypeError(`CryptoKey does not support this operation, its algorithm.hash must be SHA-${expected}.`); - } - break; - } - default: - throw new TypeError('CryptoKey does not support this operation'); - } - if (usage && !key.usages.find(Set.prototype.has.bind(usage))) { - const usages = [...usage]; - let msg = 'CryptoKey does not support this operation, its usages must include '; - if (usages.length > 2) { - const last = usages.pop(); - msg += `one of ${usages.join(', ')}, or ${last}.`; - } - else if (usages.length === 2) { - msg += `one of ${usages[0]} or ${usages[1]}.`; - } - else { - msg += ` ${usages[0]}.`; - } - throw new TypeError(msg); - } - return crypto.KeyObject.from(key); -} diff --git a/dist/node/esm/runtime/zlib.js b/dist/node/esm/runtime/zlib.js deleted file mode 100644 index 8bb72cbf18..0000000000 --- a/dist/node/esm/runtime/zlib.js +++ /dev/null @@ -1,6 +0,0 @@ -import { promisify } from 'util'; -import { inflateRaw as inflateRawCb, deflateRaw as deflateRawCb } from 'zlib'; -const inflateRaw = promisify(inflateRawCb); -const deflateRaw = promisify(deflateRawCb); -export const inflate = (input) => inflateRaw(input); -export const deflate = (input) => deflateRaw(input); diff --git a/dist/node/esm/util/base64url.js b/dist/node/esm/util/base64url.js deleted file mode 100644 index 88ce7556d6..0000000000 --- a/dist/node/esm/util/base64url.js +++ /dev/null @@ -1,3 +0,0 @@ -import * as base64url from '../runtime/base64url.js'; -export const encode = base64url.encode; -export const decode = base64url.decode; diff --git a/dist/node/esm/util/decode_protected_header.js b/dist/node/esm/util/decode_protected_header.js deleted file mode 100644 index b39c96daeb..0000000000 --- a/dist/node/esm/util/decode_protected_header.js +++ /dev/null @@ -1,36 +0,0 @@ -import { decode as base64url } from './base64url.js'; -import { decoder } from '../lib/buffer_utils.js'; -import isObject from '../lib/is_object.js'; -function decodeProtectedHeader(token) { - let protectedB64u; - if (typeof token === 'string') { - const parts = token.split('.'); - if (parts.length === 3 || parts.length === 5) { - ; - [protectedB64u] = parts; - } - } - else if (typeof token === 'object' && token) { - if ('protected' in token) { - protectedB64u = token.protected; - } - else { - throw new TypeError('Token does not contain a Protected Header'); - } - } - try { - if (typeof protectedB64u !== 'string' || !protectedB64u) { - throw new Error(); - } - const result = JSON.parse(decoder.decode(base64url(protectedB64u))); - if (!isObject(result)) { - throw new Error(); - } - return result; - } - catch { - throw new TypeError('Invalid Token or Protected Header formatting'); - } -} -export { decodeProtectedHeader }; -export default decodeProtectedHeader; diff --git a/dist/node/esm/util/errors.js b/dist/node/esm/util/errors.js deleted file mode 100644 index 52506cbd9d..0000000000 --- a/dist/node/esm/util/errors.js +++ /dev/null @@ -1,108 +0,0 @@ -export class JOSEError extends Error { - constructor(message) { - super(message); - this.code = JOSEError.code; - this.name = this.constructor.name; - if (Error.captureStackTrace) { - Error.captureStackTrace(this, this.constructor); - } - } -} -JOSEError.code = 'ERR_JOSE_GENERIC'; -export class JWTClaimValidationFailed extends JOSEError { - constructor(message, claim = 'unspecified', reason = 'unspecified') { - super(message); - this.code = JWTClaimValidationFailed.code; - this.claim = claim; - this.reason = reason; - } -} -JWTClaimValidationFailed.code = 'ERR_JWT_CLAIM_VALIDATION_FAILED'; -export class JOSEAlgNotAllowed extends JOSEError { - constructor() { - super(...arguments); - this.code = JOSEAlgNotAllowed.code; - } -} -JOSEAlgNotAllowed.code = 'ERR_JOSE_ALG_NOT_ALLOWED'; -export class JOSENotSupported extends JOSEError { - constructor() { - super(...arguments); - this.code = JOSENotSupported.code; - } -} -JOSENotSupported.code = 'ERR_JOSE_NOT_SUPPORTED'; -export class JWEDecryptionFailed extends JOSEError { - constructor() { - super(...arguments); - this.code = JWEDecryptionFailed.code; - this.message = 'decryption operation failed'; - } -} -JWEDecryptionFailed.code = 'ERR_JWE_DECRYPTION_FAILED'; -export class JWEInvalid extends JOSEError { - constructor() { - super(...arguments); - this.code = JWEInvalid.code; - } -} -JWEInvalid.code = 'ERR_JWE_INVALID'; -export class JWSInvalid extends JOSEError { - constructor() { - super(...arguments); - this.code = JWSInvalid.code; - } -} -JWSInvalid.code = 'ERR_JWS_INVALID'; -export class JWTInvalid extends JOSEError { - constructor() { - super(...arguments); - this.code = JWTInvalid.code; - } -} -JWTInvalid.code = 'ERR_JWT_INVALID'; -export class JWKInvalid extends JOSEError { - constructor() { - super(...arguments); - this.code = JWKInvalid.code; - } -} -JWKInvalid.code = 'ERR_JWK_INVALID'; -export class JWKSInvalid extends JOSEError { - constructor() { - super(...arguments); - this.code = JWKSInvalid.code; - } -} -JWKSInvalid.code = 'ERR_JWKS_INVALID'; -export class JWKSNoMatchingKey extends JOSEError { - constructor() { - super(...arguments); - this.code = JWKSNoMatchingKey.code; - this.message = 'no applicable key found in the JSON Web Key Set'; - } -} -JWKSNoMatchingKey.code = 'ERR_JWKS_NO_MATCHING_KEY'; -export class JWKSMultipleMatchingKeys extends JOSEError { - constructor() { - super(...arguments); - this.code = JWKSMultipleMatchingKeys.code; - this.message = 'multiple matching keys found in the JSON Web Key Set'; - } -} -JWKSMultipleMatchingKeys.code = 'ERR_JWKS_MULTIPLE_MATCHING_KEYS'; -export class JWSSignatureVerificationFailed extends JOSEError { - constructor() { - super(...arguments); - this.code = JWSSignatureVerificationFailed.code; - this.message = 'signature verification failed'; - } -} -JWSSignatureVerificationFailed.code = 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED'; -export class JWTExpired extends JWTClaimValidationFailed { - constructor() { - super(...arguments); - this.code = JWTExpired.code; - } -} -JWTExpired.code = 'ERR_JWT_EXPIRED'; diff --git a/dist/node/esm/util/generate_key_pair.js b/dist/node/esm/util/generate_key_pair.js deleted file mode 100644 index 733800cc06..0000000000 --- a/dist/node/esm/util/generate_key_pair.js +++ /dev/null @@ -1,6 +0,0 @@ -import { generateKeyPair as generate } from '../runtime/generate.js'; -async function generateKeyPair(alg, options) { - return generate(alg, options); -} -export { generateKeyPair }; -export default generateKeyPair; diff --git a/dist/node/esm/util/generate_secret.js b/dist/node/esm/util/generate_secret.js deleted file mode 100644 index 2d387754ee..0000000000 --- a/dist/node/esm/util/generate_secret.js +++ /dev/null @@ -1,6 +0,0 @@ -import { generateSecret as generate } from '../runtime/generate.js'; -async function generateSecret(alg, options) { - return generate(alg, options); -} -export { generateSecret }; -export default generateSecret; diff --git a/dist/node/esm/util/random.js b/dist/node/esm/util/random.js deleted file mode 100644 index d7dc7ab182..0000000000 --- a/dist/node/esm/util/random.js +++ /dev/null @@ -1,4 +0,0 @@ -import runtimeRandom from '../runtime/random.js'; -const random = runtimeRandom; -export { random }; -export default random; diff --git a/dist/types/jwe/compact/decrypt.d.ts b/dist/types/jwe/compact/decrypt.d.ts deleted file mode 100644 index a89115a26e..0000000000 --- a/dist/types/jwe/compact/decrypt.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { KeyLike, DecryptOptions, JWEHeaderParameters, GetKeyFunction, FlattenedJWE, CompactDecryptResult } from '../../types'; -export interface CompactDecryptGetKey extends GetKeyFunction { -} -declare function compactDecrypt(jwe: string | Uint8Array, key: KeyLike | CompactDecryptGetKey, options?: DecryptOptions): Promise; -export { compactDecrypt }; -export default compactDecrypt; -export type { KeyLike, DecryptOptions, CompactDecryptResult }; diff --git a/dist/types/jwe/compact/encrypt.d.ts b/dist/types/jwe/compact/encrypt.d.ts deleted file mode 100644 index 108cdd9cb6..0000000000 --- a/dist/types/jwe/compact/encrypt.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { KeyLike, JWEKeyManagementHeaderParameters, JWEHeaderParameters, EncryptOptions } from '../../types'; -declare class CompactEncrypt { - private _flattened; - constructor(plaintext: Uint8Array); - setContentEncryptionKey(cek: Uint8Array): this; - setInitializationVector(iv: Uint8Array): this; - setProtectedHeader(protectedHeader: JWEHeaderParameters): this; - setKeyManagementParameters(parameters: JWEKeyManagementHeaderParameters): this; - encrypt(key: KeyLike, options?: EncryptOptions): Promise; -} -export { CompactEncrypt }; -export default CompactEncrypt; -export type { KeyLike, JWEKeyManagementHeaderParameters, JWEHeaderParameters }; diff --git a/dist/types/jwe/flattened/decrypt.d.ts b/dist/types/jwe/flattened/decrypt.d.ts deleted file mode 100644 index bcb78f89ee..0000000000 --- a/dist/types/jwe/flattened/decrypt.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { FlattenedDecryptResult, KeyLike, FlattenedJWE, JWEHeaderParameters, DecryptOptions, GetKeyFunction } from '../../types'; -export interface FlattenedDecryptGetKey extends GetKeyFunction { -} -declare function flattenedDecrypt(jwe: FlattenedJWE, key: KeyLike | FlattenedDecryptGetKey, options?: DecryptOptions): Promise; -export { flattenedDecrypt }; -export default flattenedDecrypt; -export type { KeyLike, FlattenedJWE, JWEHeaderParameters, DecryptOptions, FlattenedDecryptResult }; diff --git a/dist/types/jwe/flattened/encrypt.d.ts b/dist/types/jwe/flattened/encrypt.d.ts deleted file mode 100644 index ba724922dc..0000000000 --- a/dist/types/jwe/flattened/encrypt.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { KeyLike, FlattenedJWE, JWEHeaderParameters, JWEKeyManagementHeaderParameters, EncryptOptions } from '../../types'; -declare class FlattenedEncrypt { - private _plaintext; - private _protectedHeader; - private _sharedUnprotectedHeader; - private _unprotectedHeader; - private _aad; - private _cek; - private _iv; - private _keyManagementParameters; - constructor(plaintext: Uint8Array); - setKeyManagementParameters(parameters: JWEKeyManagementHeaderParameters): this; - setProtectedHeader(protectedHeader: JWEHeaderParameters): this; - setSharedUnprotectedHeader(sharedUnprotectedHeader: JWEHeaderParameters): this; - setUnprotectedHeader(unprotectedHeader: JWEHeaderParameters): this; - setAdditionalAuthenticatedData(aad: Uint8Array): this; - setContentEncryptionKey(cek: Uint8Array): this; - setInitializationVector(iv: Uint8Array): this; - encrypt(key: KeyLike, options?: EncryptOptions): Promise; -} -export { FlattenedEncrypt }; -export default FlattenedEncrypt; -export type { KeyLike, FlattenedJWE, JWEHeaderParameters, JWEKeyManagementHeaderParameters }; diff --git a/dist/types/jwe/general/decrypt.d.ts b/dist/types/jwe/general/decrypt.d.ts deleted file mode 100644 index 61b71f80ca..0000000000 --- a/dist/types/jwe/general/decrypt.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { KeyLike, DecryptOptions, JWEHeaderParameters, GetKeyFunction, FlattenedJWE, GeneralJWE, GeneralDecryptResult } from '../../types'; -export interface GeneralDecryptGetKey extends GetKeyFunction { -} -declare function generalDecrypt(jwe: GeneralJWE, key: KeyLike | GeneralDecryptGetKey, options?: DecryptOptions): Promise; -export { generalDecrypt }; -export default generalDecrypt; -export type { KeyLike, GeneralJWE, DecryptOptions, GeneralDecryptResult }; diff --git a/dist/types/jwk/embedded.d.ts b/dist/types/jwk/embedded.d.ts deleted file mode 100644 index 797ef7517b..0000000000 --- a/dist/types/jwk/embedded.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -/// -import type { KeyObject, FlattenedJWSInput, JWSHeaderParameters } from '../types'; -declare function EmbeddedJWK(protectedHeader: JWSHeaderParameters, token: FlattenedJWSInput): Promise; -export { EmbeddedJWK }; -export default EmbeddedJWK; diff --git a/dist/types/jwk/from_key_like.d.ts b/dist/types/jwk/from_key_like.d.ts deleted file mode 100644 index 886c5f851e..0000000000 --- a/dist/types/jwk/from_key_like.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { JWK, KeyLike } from '../types'; -declare function fromKeyLike(key: KeyLike): Promise; -export { fromKeyLike }; -export default fromKeyLike; -export type { KeyLike, JWK }; diff --git a/dist/types/jwk/parse.d.ts b/dist/types/jwk/parse.d.ts deleted file mode 100644 index 0c1749afc3..0000000000 --- a/dist/types/jwk/parse.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { JWK, KeyLike } from '../types'; -declare function parseJwk(jwk: JWK, alg?: string, octAsKeyObject?: boolean): Promise; -export { parseJwk }; -export default parseJwk; -export type { KeyLike, JWK }; diff --git a/dist/types/jwk/thumbprint.d.ts b/dist/types/jwk/thumbprint.d.ts deleted file mode 100644 index 7e827db13d..0000000000 --- a/dist/types/jwk/thumbprint.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { JWK } from '../types'; -declare function calculateThumbprint(jwk: JWK, digestAlgorithm?: 'sha256' | 'sha384' | 'sha512'): Promise; -export { calculateThumbprint }; -export default calculateThumbprint; -export type { JWK }; diff --git a/dist/types/jwks/remote.d.ts b/dist/types/jwks/remote.d.ts deleted file mode 100644 index 63f0b6697a..0000000000 --- a/dist/types/jwks/remote.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { JWSHeaderParameters, FlattenedJWSInput, GetKeyFunction } from '../types'; -export interface RemoteJWKSetOptions { - timeoutDuration?: number; - cooldownDuration?: number; - agent?: any; -} -declare function createRemoteJWKSet(url: URL, options?: RemoteJWKSetOptions): GetKeyFunction; -export { createRemoteJWKSet }; -export default createRemoteJWKSet; diff --git a/dist/types/jws/compact/sign.d.ts b/dist/types/jws/compact/sign.d.ts deleted file mode 100644 index c5b9c3da0a..0000000000 --- a/dist/types/jws/compact/sign.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { JWSHeaderParameters, KeyLike, SignOptions } from '../../types'; -declare class CompactSign { - private _flattened; - constructor(payload: Uint8Array); - setProtectedHeader(protectedHeader: JWSHeaderParameters): this; - sign(key: KeyLike, options?: SignOptions): Promise; -} -export { CompactSign }; -export default CompactSign; -export type { JWSHeaderParameters, KeyLike }; diff --git a/dist/types/jws/compact/verify.d.ts b/dist/types/jws/compact/verify.d.ts deleted file mode 100644 index 0279df23a7..0000000000 --- a/dist/types/jws/compact/verify.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { CompactVerifyResult, FlattenedJWSInput, GetKeyFunction, JWSHeaderParameters, KeyLike, VerifyOptions } from '../../types'; -export interface CompactVerifyGetKey extends GetKeyFunction { -} -declare function compactVerify(jws: string | Uint8Array, key: KeyLike | CompactVerifyGetKey, options?: VerifyOptions): Promise; -export { compactVerify }; -export default compactVerify; -export type { KeyLike, VerifyOptions, CompactVerifyResult }; diff --git a/dist/types/jws/flattened/sign.d.ts b/dist/types/jws/flattened/sign.d.ts deleted file mode 100644 index 9e9f9612ef..0000000000 --- a/dist/types/jws/flattened/sign.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { KeyLike, FlattenedJWS, JWSHeaderParameters, SignOptions } from '../../types'; -declare class FlattenedSign { - private _payload; - private _protectedHeader; - private _unprotectedHeader; - constructor(payload: Uint8Array); - setProtectedHeader(protectedHeader: JWSHeaderParameters): this; - setUnprotectedHeader(unprotectedHeader: JWSHeaderParameters): this; - sign(key: KeyLike, options?: SignOptions): Promise; -} -export { FlattenedSign }; -export default FlattenedSign; -export type { KeyLike, FlattenedJWS, JWSHeaderParameters }; diff --git a/dist/types/jws/flattened/verify.d.ts b/dist/types/jws/flattened/verify.d.ts deleted file mode 100644 index 0cdf7025d7..0000000000 --- a/dist/types/jws/flattened/verify.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { FlattenedVerifyResult, KeyLike, FlattenedJWSInput, JWSHeaderParameters, VerifyOptions, GetKeyFunction } from '../../types'; -export interface FlattenedVerifyGetKey extends GetKeyFunction { -} -declare function flattenedVerify(jws: FlattenedJWSInput, key: KeyLike | FlattenedVerifyGetKey, options?: VerifyOptions): Promise; -export { flattenedVerify }; -export default flattenedVerify; -export type { KeyLike, FlattenedJWSInput, GetKeyFunction, JWSHeaderParameters, VerifyOptions, FlattenedVerifyResult, }; diff --git a/dist/types/jws/general/sign.d.ts b/dist/types/jws/general/sign.d.ts deleted file mode 100644 index 1d3fd9a290..0000000000 --- a/dist/types/jws/general/sign.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { KeyLike, GeneralJWS, JWSHeaderParameters, SignOptions } from '../../types'; -export interface Signature { - setProtectedHeader(protectedHeader: JWSHeaderParameters): Signature; - setUnprotectedHeader(unprotectedHeader: JWSHeaderParameters): Signature; -} -declare class GeneralSign { - private _payload; - private _signatures; - constructor(payload: Uint8Array); - addSignature(key: KeyLike, options?: SignOptions): Signature; - sign(): Promise; -} -export { GeneralSign }; -export default GeneralSign; -export type { KeyLike, GeneralJWS, JWSHeaderParameters }; diff --git a/dist/types/jws/general/verify.d.ts b/dist/types/jws/general/verify.d.ts deleted file mode 100644 index a72756a31c..0000000000 --- a/dist/types/jws/general/verify.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { GeneralJWSInput, GeneralVerifyResult, FlattenedJWSInput, GetKeyFunction, JWSHeaderParameters, KeyLike, VerifyOptions } from '../../types'; -export interface GeneralVerifyGetKey extends GetKeyFunction { -} -declare function generalVerify(jws: GeneralJWSInput, key: KeyLike | GeneralVerifyGetKey, options?: VerifyOptions): Promise; -export { generalVerify }; -export default generalVerify; -export type { KeyLike, GeneralJWSInput, VerifyOptions, GeneralVerifyResult }; diff --git a/dist/types/jwt/decrypt.d.ts b/dist/types/jwt/decrypt.d.ts deleted file mode 100644 index c7691d5bf0..0000000000 --- a/dist/types/jwt/decrypt.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { KeyLike, DecryptOptions, JWTPayload, JWTClaimVerificationOptions, GetKeyFunction, JWEHeaderParameters, FlattenedJWE, JWTDecryptResult } from '../types'; -interface JWTDecryptOptions extends DecryptOptions, JWTClaimVerificationOptions { -} -export interface JWTDecryptGetKey extends GetKeyFunction { -} -declare function jwtDecrypt(jwt: string | Uint8Array, key: KeyLike | JWTDecryptGetKey, options?: JWTDecryptOptions): Promise; -export { jwtDecrypt }; -export default jwtDecrypt; -export type { KeyLike, DecryptOptions, JWTPayload, JWTDecryptOptions, JWTDecryptResult }; diff --git a/dist/types/jwt/encrypt.d.ts b/dist/types/jwt/encrypt.d.ts deleted file mode 100644 index e8cee000c0..0000000000 --- a/dist/types/jwt/encrypt.d.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { EncryptOptions, JWEHeaderParameters, JWEKeyManagementHeaderParameters, JWTPayload, KeyLike } from '../types'; -import ProduceJWT from '../lib/jwt_producer'; -declare class EncryptJWT extends ProduceJWT { - private _cek; - private _iv; - private _keyManagementParameters; - private _protectedHeader; - private _replicateIssuerAsHeader; - private _replicateSubjectAsHeader; - private _replicateAudienceAsHeader; - setProtectedHeader(protectedHeader: JWEHeaderParameters): this; - setKeyManagementParameters(parameters: JWEKeyManagementHeaderParameters): this; - setContentEncryptionKey(cek: Uint8Array): this; - setInitializationVector(iv: Uint8Array): this; - replicateIssuerAsHeader(): this; - replicateSubjectAsHeader(): this; - replicateAudienceAsHeader(): this; - encrypt(key: KeyLike, options?: EncryptOptions): Promise; -} -export { EncryptJWT }; -export default EncryptJWT; -export type { JWEHeaderParameters, JWTPayload, KeyLike }; diff --git a/dist/types/jwt/sign.d.ts b/dist/types/jwt/sign.d.ts deleted file mode 100644 index 8be5956803..0000000000 --- a/dist/types/jwt/sign.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { JWSHeaderParameters, JWTPayload, KeyLike, SignOptions } from '../types'; -import ProduceJWT from '../lib/jwt_producer'; -declare class SignJWT extends ProduceJWT { - private _protectedHeader; - setProtectedHeader(protectedHeader: JWSHeaderParameters): this; - sign(key: KeyLike, options?: SignOptions): Promise; -} -export { SignJWT }; -export default SignJWT; -export type { JWSHeaderParameters, JWTPayload, KeyLike }; diff --git a/dist/types/jwt/unsecured.d.ts b/dist/types/jwt/unsecured.d.ts deleted file mode 100644 index c55f7c577e..0000000000 --- a/dist/types/jwt/unsecured.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { JWSHeaderParameters, JWTClaimVerificationOptions, JWTPayload } from '../types'; -import ProduceJWT from '../lib/jwt_producer'; -interface UnsecuredResult { - payload: JWTPayload; - header: JWSHeaderParameters; -} -declare class UnsecuredJWT extends ProduceJWT { - encode(): string; - static decode(jwt: string, options?: JWTClaimVerificationOptions): UnsecuredResult; -} -export { UnsecuredJWT }; -export default UnsecuredJWT; -export type { JWSHeaderParameters, JWTPayload, UnsecuredResult }; diff --git a/dist/types/jwt/verify.d.ts b/dist/types/jwt/verify.d.ts deleted file mode 100644 index 0f23f77332..0000000000 --- a/dist/types/jwt/verify.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { KeyLike, VerifyOptions, JWTPayload, JWTClaimVerificationOptions, JWSHeaderParameters, GetKeyFunction, FlattenedJWSInput, JWTVerifyResult } from '../types'; -interface JWTVerifyOptions extends VerifyOptions, JWTClaimVerificationOptions { -} -export interface JWTVerifyGetKey extends GetKeyFunction { -} -declare function jwtVerify(jwt: string | Uint8Array, key: KeyLike | JWTVerifyGetKey, options?: JWTVerifyOptions): Promise; -export { jwtVerify }; -export default jwtVerify; -export type { KeyLike, JWTPayload, JWTVerifyOptions, JWSHeaderParameters, GetKeyFunction, JWTVerifyResult, }; diff --git a/dist/types/lib/jwt_producer.d.ts b/dist/types/lib/jwt_producer.d.ts deleted file mode 100644 index 2deef0a8c8..0000000000 --- a/dist/types/lib/jwt_producer.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { JWTPayload } from '../types'; -export default class ProduceJWT { - protected _payload: JWTPayload; - constructor(payload: JWTPayload); - setIssuer(issuer: string): this; - setSubject(subject: string): this; - setAudience(audience: string | string[]): this; - setJti(jwtId: string): this; - setNotBefore(input: number | string): this; - setExpirationTime(input: number | string): this; - setIssuedAt(input?: number): this; -} diff --git a/dist/types/types.d.ts b/dist/types/types.d.ts deleted file mode 100644 index 11c2b3ac91..0000000000 --- a/dist/types/types.d.ts +++ /dev/null @@ -1,171 +0,0 @@ -/// -import type { KeyObject } from 'crypto' -export type { KeyObject } -export type KeyLike = KeyObject | CryptoKey | Uint8Array -export interface JWK { - alg?: string - crv?: string - d?: string - dp?: string - dq?: string - e?: string - ext?: boolean - k?: string - key_ops?: string[] - kid?: string - kty?: string - n?: string - oth?: Array<{ - d?: string - r?: string - t?: string - }> - p?: string - q?: string - qi?: string - use?: string - x?: string - y?: string - x5c?: string[] - x5t?: string - 'x5t#S256'?: string - x5u?: string - [propName: string]: unknown -} -export interface GetKeyFunction { - (protectedHeader: T, token: T2): Promise -} -export interface FlattenedJWSInput { - header?: JWSHeaderParameters - payload: string | Uint8Array - protected?: string - signature: string -} -export interface GeneralJWSInput { - payload: string | Uint8Array - signatures: Omit[] -} -export interface FlattenedJWS extends Partial { - payload: string - signature: string -} -export interface GeneralJWS { - payload: string - signatures: Omit[] -} -export interface JoseHeaderParameters { - kid?: string - x5t?: string - x5c?: string[] - x5u?: string - jku?: string - jwk?: Pick - typ?: string - cty?: string -} -export interface JWSHeaderParameters extends JoseHeaderParameters { - alg?: string - b64?: boolean - crit?: string[] - [propName: string]: unknown -} -export interface JWEKeyManagementHeaderParameters { - apu?: Uint8Array - apv?: Uint8Array - epk?: KeyLike - iv?: Uint8Array - p2c?: number - p2s?: Uint8Array -} -export interface FlattenedJWE { - aad?: string - ciphertext: string - encrypted_key?: string - header?: JWEHeaderParameters - iv: string - protected?: string - tag: string - unprotected?: JWEHeaderParameters -} -export interface GeneralJWE extends Omit { - recipients: Pick[] -} -export interface JWEHeaderParameters extends JoseHeaderParameters { - alg?: string - enc?: string - crit?: string[] - zip?: string - [propName: string]: unknown -} -export interface CritOption { - crit?: { - [propName: string]: boolean - } -} -export interface DecryptOptions extends CritOption { - keyManagementAlgorithms?: string[] - contentEncryptionAlgorithms?: string[] - inflateRaw?: InflateFunction -} -export interface EncryptOptions extends CritOption { - deflateRaw?: DeflateFunction -} -export interface JWTClaimVerificationOptions { - audience?: string | string[] - clockTolerance?: string | number - issuer?: string | string[] - maxTokenAge?: string | number - subject?: string - typ?: string - currentDate?: Date -} -export interface VerifyOptions extends CritOption { - algorithms?: string[] -} -export interface SignOptions extends CritOption {} -export interface JWTPayload { - iss?: string - sub?: string - aud?: string | string[] - jti?: string - nbf?: number - exp?: number - iat?: number - [propName: string]: unknown -} -export interface DeflateFunction { - (input: Uint8Array): Promise -} -export interface InflateFunction { - (input: Uint8Array): Promise -} -export interface FlattenedDecryptResult { - additionalAuthenticatedData?: Uint8Array - plaintext: Uint8Array - protectedHeader?: JWEHeaderParameters - sharedUnprotectedHeader?: JWEHeaderParameters - unprotectedHeader?: JWEHeaderParameters -} -export interface GeneralDecryptResult extends FlattenedDecryptResult {} -export interface CompactDecryptResult { - plaintext: Uint8Array - protectedHeader: JWEHeaderParameters -} -export interface FlattenedVerifyResult { - payload: Uint8Array - protectedHeader?: JWSHeaderParameters - unprotectedHeader?: JWSHeaderParameters -} -export interface GeneralVerifyResult extends FlattenedVerifyResult {} -export interface CompactVerifyResult { - payload: Uint8Array - protectedHeader: JWSHeaderParameters -} -export interface JWTVerifyResult { - payload: JWTPayload - protectedHeader: JWSHeaderParameters -} -export interface JWTDecryptResult { - payload: JWTPayload - protectedHeader: JWEHeaderParameters -} diff --git a/dist/types/util/base64url.d.ts b/dist/types/util/base64url.d.ts deleted file mode 100644 index 016c96128a..0000000000 --- a/dist/types/util/base64url.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -interface Base64UrlEncode { - (input: Uint8Array | string): string; -} -interface Base64UrlDecode { - (input: Uint8Array | string): Uint8Array; -} -export declare const encode: Base64UrlEncode; -export declare const decode: Base64UrlDecode; -export {}; diff --git a/dist/types/util/decode_protected_header.d.ts b/dist/types/util/decode_protected_header.d.ts deleted file mode 100644 index c77304ff9d..0000000000 --- a/dist/types/util/decode_protected_header.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { JWSHeaderParameters, JWEHeaderParameters } from '../types'; -export declare type ProtectedHeaderParameters = JWSHeaderParameters & JWEHeaderParameters; -declare function decodeProtectedHeader(token: string | object): ProtectedHeaderParameters; -export { decodeProtectedHeader }; -export default decodeProtectedHeader; diff --git a/dist/types/util/errors.d.ts b/dist/types/util/errors.d.ts deleted file mode 100644 index 48fb822ce7..0000000000 --- a/dist/types/util/errors.d.ts +++ /dev/null @@ -1,64 +0,0 @@ -export declare class JOSEError extends Error { - static code: string; - code: string; - constructor(message?: string); -} -export declare class JWTClaimValidationFailed extends JOSEError { - static code: string; - code: string; - claim: string; - reason: string; - constructor(message: string, claim?: string, reason?: string); -} -export declare class JOSEAlgNotAllowed extends JOSEError { - static code: string; - code: string; -} -export declare class JOSENotSupported extends JOSEError { - static code: string; - code: string; -} -export declare class JWEDecryptionFailed extends JOSEError { - static code: string; - code: string; - message: string; -} -export declare class JWEInvalid extends JOSEError { - static code: string; - code: string; -} -export declare class JWSInvalid extends JOSEError { - static code: string; - code: string; -} -export declare class JWTInvalid extends JOSEError { - static code: string; - code: string; -} -export declare class JWKInvalid extends JOSEError { - static code: string; - code: string; -} -export declare class JWKSInvalid extends JOSEError { - static code: string; - code: string; -} -export declare class JWKSNoMatchingKey extends JOSEError { - static code: string; - code: string; - message: string; -} -export declare class JWKSMultipleMatchingKeys extends JOSEError { - static code: string; - code: string; - message: string; -} -export declare class JWSSignatureVerificationFailed extends JOSEError { - static code: string; - code: string; - message: string; -} -export declare class JWTExpired extends JWTClaimValidationFailed { - static code: string; - code: string; -} diff --git a/dist/types/util/generate_key_pair.d.ts b/dist/types/util/generate_key_pair.d.ts deleted file mode 100644 index d2564ecb80..0000000000 --- a/dist/types/util/generate_key_pair.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { KeyLike } from '../types'; -export interface GenerateKeyPairResult { - privateKey: Exclude; - publicKey: Exclude; -} -export interface GenerateKeyPairOptions { - crv?: string; - modulusLength?: number; - extractable?: boolean; -} -declare function generateKeyPair(alg: string, options?: GenerateKeyPairOptions): Promise; -export { generateKeyPair }; -export default generateKeyPair; diff --git a/dist/types/util/generate_secret.d.ts b/dist/types/util/generate_secret.d.ts deleted file mode 100644 index c2673d6a96..0000000000 --- a/dist/types/util/generate_secret.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { KeyLike } from '../types'; -export interface GenerateSecretOptions { - extractable?: boolean; -} -declare function generateSecret(alg: string, options?: GenerateSecretOptions): Promise; -export { generateSecret }; -export default generateSecret; diff --git a/dist/types/util/random.d.ts b/dist/types/util/random.d.ts deleted file mode 100644 index db1d0971d4..0000000000 --- a/dist/types/util/random.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -interface GetRandomValuesFunction { - (array: Uint8Array): Uint8Array; -} -declare const random: GetRandomValuesFunction; -export { random }; -export default random; From 8b3cc9818e061c4a484792cddce33d7098337622 Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Tue, 7 Sep 2021 14:32:34 +0200 Subject: [PATCH 2/4] test: less browser and deno test duplication --- karma.conf.js | 5 +- test-browser/generate_keys.js | 92 --------------------- test-browser/generate_secrets.js | 92 --------------------- test-browser/keylike.js | 83 +++++++++++++++++++ test-cloudflare-workers/cloudflare.test.mjs | 2 +- test-deno/generate_keys.test.ts | 79 ------------------ test-deno/generate_secrets.test.ts | 76 ----------------- 7 files changed, 87 insertions(+), 342 deletions(-) delete mode 100644 test-browser/generate_keys.js delete mode 100644 test-browser/generate_secrets.js create mode 100644 test-browser/keylike.js delete mode 100644 test-deno/generate_keys.test.ts delete mode 100644 test-deno/generate_secrets.test.ts diff --git a/karma.conf.js b/karma.conf.js index c8bd01060c..7a230f2e9a 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -96,8 +96,8 @@ module.exports = function (config) { "karma-browserstack-launcher", "karma-summary-reporter", ], - files: ["dist-browser-tests/*.js"], - reporters: ["summary"], + files: ["dist-browser-tests/keylike.js"], + reporters: ["progress", "summary"], port: 9876, autoWatch: false, browserStack: { @@ -105,6 +105,7 @@ module.exports = function (config) { accessKey: process.env.BROWSERSTACK_ACCESS_KEY, }, customLaunchers: browsers, + logLevel: config.LOG_WARN, client: { qunit: { showUI: true, diff --git a/test-browser/generate_keys.js b/test-browser/generate_keys.js deleted file mode 100644 index 74ae7f6aed..0000000000 --- a/test-browser/generate_keys.js +++ /dev/null @@ -1,92 +0,0 @@ -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('extractable', async (assert) => { - let { privateKey, publicKey } = await generateKeyPair('PS256'); - assert.true(publicKey.extractable); - assert.false(privateKey.extractable); - - ({ privateKey } = await generateKeyPair('PS256', { extractable: true })); - assert.true(privateKey.extractable); -}); - -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 deleted file mode 100644 index 166544b9e5..0000000000 --- a/test-browser/generate_secrets.js +++ /dev/null @@ -1,92 +0,0 @@ -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('extractable', async (assert) => { - let secret = await generateSecret('HS256'); - assert.false(secret.extractable); - secret = await generateSecret('HS256', { extractable: true }); - assert.true(secret.extractable); -}); - -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/keylike.js b/test-browser/keylike.js new file mode 100644 index 0000000000..06a859fd23 --- /dev/null +++ b/test-browser/keylike.js @@ -0,0 +1,83 @@ +import * as Bowser from 'bowser'; + +import jwkToKey from '../dist/browser/jwk/parse.js'; +import keyToJwk from '../dist/browser/jwk/from_key_like.js'; +import calculateThumbprint from '../dist/browser/jwk/thumbprint.js'; + +const browser = Bowser.parse(window.navigator.userAgent); + +const p521 = browser.engine.name !== 'WebKit'; + +async function test(jwk, alg, assert) { + await calculateThumbprint(jwk); + const keyLike = await jwkToKey({ ...jwk, ext: true }, alg); + assert.deepEqual(await keyToJwk(keyLike), jwk); +} + +async function failing(jwk, alg, assert) { + await assert.rejects(test.bind(undefined, jwk, alg)(assert)); +} + +const expectSuccess = [ + [ + 'RS256', + '{"kty":"RSA","n":"rcbWc-i_C8NtS4CpPcMF3QC025re_zzrhv-3ElzxAsMCCepwEqxCzQtsG7mAtROdGR1N_oNPNqr3jmEZdv5C5NtpPeX_gk4-r30_JLXcGNgVbZpmWVSmUI-nrU0cC3kjMS4RUPx7uDQxAUiVUq0k13qjEbEgcZAA3nEH2zuQWg3iWSmwYL0h1VxdINQ-WZZzBJsI_ONyBS5z3-vbyhtnMbgALRZSvNcYpODrH9AEIWNJhcaBVr1vKBdNT76KOl87ilLiKE1dOr72sLJDDsVqXDfxCjU_wdt2bF-YFcKwlYa5Aj2JF-UH7KLniC3P-2sS1zduLoAPAkyLcHgVdOifhQ","e":"AQAB"}', + ], + [ + 'RS384', + '{"kty":"RSA","n":"yKV00L6PwdO6DGMgsNwuWZ0xviGMqq7nvkULJ8jyQil8viSUvxDMPDZ80CoHUkgobcBU1DasjGO9nTthPYhcpOFh8Fzat1aG-z5Ola2FBHqpdJpwb7lxsLfq6UJy1bial5RCMrLdW3NhuCxIfhnGmvq4hFLAF7gBnEfkbN9qsrzyZruEGIlNG50r779axmgnRZDZ6YS5o_DVbn27f2yCjBLVYIljW5z9CSm6_NjSYVdeNujrgQUWMIrCZiJqmRSOAvn6GliKXFL7sh5xLh_DiCx1Atr477sBxviLY-tFpeXLOqKJKqZ5GASrspxsO96roE4-I4J-7JgoxYptuKD2Bw","e":"AQAB"}', + ], + [ + 'RS512', + '{"kty":"RSA","n":"wdEr4kyCku2F8a2Y45xa1Q-jE5FlkYK6xUDuyckH6U9hhA_1OFaNfTbZ-8ZkXOp0PGzYjCqAk0YxATfnKSc1-PKnOBvBD8FRpgaT61WyOq_yM6YgDrwQvbWTr0r5copjDs4ZA9mrE-bjgvOLut4GpD4NVPWhPkgI45-yYd0H4vjuf36sCe26MBIWBTzInCUdfKTvCdh0Kk__HOENwwke6XrtzvugJymi3zlrdqztq3efJFmA4hvyLzosdBB8g0iWBXFNy51J8RCYygiSXtsPatV1FMVd6ZkTfVrvR3OYJucbuvCbqQwPDB08XjJLXKTE1eolyECk-U-Z_Cg8aNElpw","e":"AQAB"}', + ], + [ + 'PS256', + '{"kty":"RSA","n":"5Yv7aQulm2VYKjSfwPQLSEokqtWu-TxKKkRKT_570Yjk0fIg81IbK5T0SrkBzmEV5bjuoGdVMQf6bvkhOeeborTmbISEE6DCNxN_us3EWJKMKp-OSbeqbvbg252l_wPhcC5OC0Q--ryOqoRlsCKYgCmDbKNmZepGm8Nf1ayeqj3kIuKmgzU7y4dy4Le8Sq-9aHD5_QW52WqHeEnmIfrVnR7mJsrd7LY-28aflUHaEDn1TzhPPq0W_F1lMkdniM4c5JNU5_6fZ8NVla51j-pt0PmQMz-Ch97ZcnpB7DGdNyBDzdnQiabJ7sOxRK33so8cUFh3zHnaeX73XeGgrpD5XQ","e":"AQAB"}', + ], + [ + 'PS384', + '{"kty":"RSA","n":"vyJy0ZJqdGsH3-AGnaw5I35lPhFdWDxxkRn-TBx1GfhIKCjibEjZTCfzBnBdWwIUnr2fL0Vy6VZvTEUcH66r4AJy380ovOJrVIM5nhAGn8uSLCoJ2yiuKeA50gBylINvdAVG7fDzau4-1aSQ1RXILxa88raqDK1h8DQoGZLnRdiKkfNjKmXVltsvDSUxOmKelHh9WLiF2JCs0ydMCCcGDumosLBlP4LR7XfycW2cIavRdxeajL8oyRckD9-IpZLampTkr0Ja4GWHbHnAX-dXmoRDEhqlMeSpKmbm-e95jT_3SHwLj_TLlwF4HsIj-egX78lHcVJzCvhdUG7ogrbjHw","e":"AQAB"}', + ], + [ + 'PS512', + '{"kty":"RSA","n":"sSLTDqh1I2Rt26uCFrbdYuRY3lqDes8Az0GQxgatQhXgIG1jOfuEIaqnMRDuWinroRWuetR1ykQ4SxzIy31ms5PSM5sJm1SNAiynO6dxxGMNaCLt4Rgi_fAn6CD0F4mo2OLmxm1_hQH1SJSymG8p8q9Uu0IToY4KEEmHwc1kfiAosvqfLgY1-CRU8kKbFHzq28x7Jbv4WSDccJ_-Wm8BiyMkIUQfzRsC1hHiMO_NKlLwMqeSQ5XyYqsBxc80cF6Z9IIBzXewjCGGVAfYMeimPcJao6wat-PXEr5axEeBeCFU6Q7TDLcMilotGV6f6-UECUK5q2QCXtoOnZ5TO4yPzQ","e":"AQAB"}', + ], + [ + 'ES256', + '{"crv":"P-256","kty":"EC","x":"E8KpG0wpGUfRBYx8tUhd6tYaFaTZaIyHvAudXbSUFxQ","y":"gcVDlKTo-UhZ-wHDNUdoQP0M9zevurU6A5WMR07B-wQ"}', + ], + [ + 'ES384', + '{"crv":"P-384","kty":"EC","x":"HnBAtgpS-GJzTCdLBELPm1VIRoQwlk7luJIGEYWKhWtMHmOq14Hh7674Oxcc52mE","y":"jXGek8Zapkjav7mO-KB-7vEWrqNxHSoXgNn1r6C0BiqS89SVciz6O8uriPdxoWem"}', + ], + ['HS256', '{"kty":"oct","k":"iPYq7qKZWRaVmo1FiJ17M84uADey7-veCAEEsxpPTus"}'], + ['HS384', '{"kty":"oct","k":"ATgNcVOYFsjbN4GeyXOyryfqqmGp_48-uvVd5J3GsX7ExUMp3WNTDbbZK_5kTjND"}'], + [ + 'HS512', + '{"kty":"oct","k":"2O5x_zEOhSIDiGcOAOYhB1dyDU_ZW27rl-_xDpKE-8tBlL91z6p_8aYo3by6AOsa6ycx6-JC9LBAio0amINXTQ"}', + ], +]; +const expectFailure = []; + +const ES512 = [ + 'ES512', + '{"crv":"P-521","kty":"EC","x":"AIwG869tNnEGIDg2hSyvXKIOk9rWPO_riIixGliBGBV0kB57QoTrjK-g5JCtazDTcBT23igX9gvAVkLvr2oFTQ9p","y":"AeGZ0Z3JHM1rQWvmmpdfVu0zSNpmu0xPjGUE2hGhloRqF-JJV3aVMS72ZhGlbWi-O7OCcypIfndhpYgrc3qx0Y1w"}', +]; + +if (p521) { + expectSuccess.push(ES512); +} else { + expectFailure.push(ES512); +} + +for (const [alg, jwk] of expectSuccess) { + QUnit.test(`Key Import/Export ${alg}`, test.bind(undefined, JSON.parse(jwk), alg)); +} + +for (const [alg, jwk] of expectFailure) { + QUnit.test( + `(expecting failure) Key Import/Export ${alg}`, + failing.bind(undefined, JSON.parse(jwk), alg), + ); +} diff --git a/test-cloudflare-workers/cloudflare.test.mjs b/test-cloudflare-workers/cloudflare.test.mjs index b7dbbd6818..9a7df08209 100644 --- a/test-cloudflare-workers/cloudflare.test.mjs +++ b/test-cloudflare-workers/cloudflare.test.mjs @@ -79,7 +79,7 @@ const macro = async (t, testScript) => { method: 'GET', }, )); - i++ + i++; await setTimeout(1000); } while (statusCode !== 200 && statusCode !== 400); diff --git a/test-deno/generate_keys.test.ts b/test-deno/generate_keys.test.ts deleted file mode 100644 index 949aa2a7f5..0000000000 --- a/test-deno/generate_keys.test.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { - assertStrictEquals, - assertThrowsAsync, -} from 'https://deno.land/std@0.104.0/testing/asserts.ts'; - -import generateKeyPair from '../dist/deno/util/generate_key_pair.ts'; - -Deno.test('Generate PS256 keys', async () => { - await generateKeyPair('PS256'); -}); - -Deno.test('extractable', async () => { - let { privateKey, publicKey } = await generateKeyPair('PS256'); - assertStrictEquals(publicKey.extractable, true); - assertStrictEquals(privateKey.extractable, false); - - ({ privateKey } = await generateKeyPair('PS256', { extractable: true })); - assertStrictEquals(privateKey.extractable, true); -}); - -Deno.test('Generate PS384 keys', async () => { - await generateKeyPair('PS384'); -}); - -Deno.test('Generate PS512 keys', async () => { - await generateKeyPair('PS512'); -}); - -Deno.test('Generate RS256 keys', async () => { - await generateKeyPair('RS256'); -}); - -Deno.test('Generate RS384 keys', async () => { - await generateKeyPair('RS384'); -}); - -Deno.test('Generate RS512 keys', async () => { - await generateKeyPair('RS512'); -}); - -Deno.test('Generate ES256 keys', async () => { - await generateKeyPair('ES256'); -}); - -Deno.test('Generate ES384 keys', async () => { - await generateKeyPair('ES384'); -}); - -Deno.test('(expecting failure) Generate ES512 keys', async () => { - await assertThrowsAsync(() => generateKeyPair('ES512')); -}); - -Deno.test('Generate RSA-OAEP keys', async () => { - await generateKeyPair('RSA-OAEP'); -}); - -Deno.test('Generate RSA-OAEP-256 keys', async () => { - await generateKeyPair('RSA-OAEP-256'); -}); - -Deno.test('Generate RSA-OAEP-384 keys', async () => { - await generateKeyPair('RSA-OAEP-384'); -}); - -Deno.test('Generate RSA-OAEP-512 keys', async () => { - await generateKeyPair('RSA-OAEP-512'); -}); - -Deno.test('Generate ECDH-ES crv: P-256 keys', async () => { - await generateKeyPair('ECDH-ES', { crv: 'P-256' }); -}); - -Deno.test('Generate ECDH-ES crv: P-384 keys', async () => { - await generateKeyPair('ECDH-ES', { crv: 'P-384' }); -}); - -Deno.test('(expecting failure) Generate ECDH-ES crv: P-521 keys', async () => { - await assertThrowsAsync(() => generateKeyPair('ECDH-ES', { crv: 'P-521' })); -}); diff --git a/test-deno/generate_secrets.test.ts b/test-deno/generate_secrets.test.ts deleted file mode 100644 index 4025fdf2d4..0000000000 --- a/test-deno/generate_secrets.test.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { assertStrictEquals, unreachable } from 'https://deno.land/std@0.104.0/testing/asserts.ts'; - -import generateSecret from '../dist/deno/util/generate_secret.ts'; - -Deno.test('Generate HS256 secret', async () => { - await generateSecret('HS256'); -}); - -Deno.test('extractable', async () => { - let secret = await generateSecret('HS256'); - if (!(secret instanceof CryptoKey)) { - unreachable(); - } - assertStrictEquals(secret.extractable, false); - secret = await generateSecret('HS256', { extractable: true }); - if (!(secret instanceof CryptoKey)) { - unreachable(); - } - assertStrictEquals(secret.extractable, true); -}); - -Deno.test('Generate HS384 secret', async () => { - await generateSecret('HS384'); -}); - -Deno.test('Generate HS512 secret', async () => { - await generateSecret('HS512'); -}); - -Deno.test('Generate A128CBC-HS256 secret', async () => { - await generateSecret('A128CBC-HS256'); -}); - -Deno.test('Generate A192CBC-HS384 secret', async () => { - await generateSecret('A192CBC-HS384'); -}); - -Deno.test('Generate A256CBC-HS512 secret', async () => { - await generateSecret('A256CBC-HS512'); -}); - -Deno.test('Generate A128KW secret', async () => { - await generateSecret('A128KW'); -}); - -Deno.test('Generate A192KW secret', async () => { - await generateSecret('A192KW'); -}); - -Deno.test('Generate A256KW secret', async () => { - await generateSecret('A256KW'); -}); - -Deno.test('Generate A128GCMKW secret', async () => { - await generateSecret('A128GCMKW'); -}); - -Deno.test('Generate A192GCMKW secret', async () => { - await generateSecret('A192GCMKW'); -}); - -Deno.test('Generate A256GCMKW secret', async () => { - await generateSecret('A256GCMKW'); -}); - -Deno.test('Generate A128GCM secret', async () => { - await generateSecret('A128GCM'); -}); - -Deno.test('Generate A192GCM secret', async () => { - await generateSecret('A192GCM'); -}); - -Deno.test('Generate A256GCM secret', async () => { - await generateSecret('A256GCM'); -}); From 10a18f28a0f845e91579afab3573730c9b1ae478 Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Wed, 8 Sep 2021 10:04:51 +0200 Subject: [PATCH 3/4] fix: guard Sign payloads and Encrypt plaintext argument types --- src/jwe/flattened/encrypt.ts | 3 +++ src/jws/flattened/sign.ts | 3 +++ test/jwe/flattened.encrypt.test.mjs | 20 ++++++++++++++++++++ test/jws/flattened.sign.test.mjs | 20 ++++++++++++++++++++ 4 files changed, 46 insertions(+) diff --git a/src/jwe/flattened/encrypt.ts b/src/jwe/flattened/encrypt.ts index dabcfd6892..ee1fe566c7 100644 --- a/src/jwe/flattened/encrypt.ts +++ b/src/jwe/flattened/encrypt.ts @@ -73,6 +73,9 @@ class FlattenedEncrypt { * @param plaintext Binary representation of the plaintext to encrypt. */ constructor(plaintext: Uint8Array) { + if (!(plaintext instanceof Uint8Array)) { + throw new TypeError('plaintext must be an instance of Uint8Array') + } this._plaintext = plaintext } diff --git a/src/jws/flattened/sign.ts b/src/jws/flattened/sign.ts index 107795a1c4..c556f8d20d 100644 --- a/src/jws/flattened/sign.ts +++ b/src/jws/flattened/sign.ts @@ -49,6 +49,9 @@ class FlattenedSign { * @param payload Binary representation of the payload to sign. */ constructor(payload: Uint8Array) { + if (!(payload instanceof Uint8Array)) { + throw new TypeError('payload must be an instance of Uint8Array') + } this._payload = payload } diff --git a/test/jwe/flattened.encrypt.test.mjs b/test/jwe/flattened.encrypt.test.mjs index 77fd57b79a..69956586de 100644 --- a/test/jwe/flattened.encrypt.test.mjs +++ b/test/jwe/flattened.encrypt.test.mjs @@ -77,6 +77,26 @@ import(`${root}/jwe/flattened/encrypt`).then( tag: 'gEwNlfPZ-O-dG7dTFkhMyQ', }); } + { + for (const value of [ + undefined, + null, + {}, + '', + 'foo', + 1, + 0, + true, + false, + [], + new FlattenedEncrypt(new Uint8Array()), + ]) { + t.throws(() => new FlattenedEncrypt(value), { + instanceOf: TypeError, + message: 'plaintext must be an instance of Uint8Array', + }); + } + } }); test('FlattenedEncrypt.prototype.setProtectedHeader', (t) => { diff --git a/test/jws/flattened.sign.test.mjs b/test/jws/flattened.sign.test.mjs index 1a0af530a1..e0e42df288 100644 --- a/test/jws/flattened.sign.test.mjs +++ b/test/jws/flattened.sign.test.mjs @@ -46,6 +46,26 @@ import(`${root}/jws/flattened/sign`).then( signature: 'O7HdMZ_6_aEQWLGGItmCKN3pf8-nZ9mHnPfT7rrPCwk', }); } + { + for (const value of [ + undefined, + null, + {}, + '', + 'foo', + 1, + 0, + true, + false, + [], + new FlattenedSign(new Uint8Array()), + ]) { + t.throws(() => new FlattenedSign(value), { + instanceOf: TypeError, + message: 'payload must be an instance of Uint8Array', + }); + } + } }); test('FlattenedSign.prototype.setProtectedHeader', (t) => { From 649fe1d23d9292629dd8b8f07546f3fc390c0b3d Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Wed, 8 Sep 2021 10:44:29 +0200 Subject: [PATCH 4/4] chore(release): 3.16.1 --- CHANGELOG.md | 7 + dist/browser/jwe/compact/decrypt.js | 25 + dist/browser/jwe/compact/encrypt.js | 28 + dist/browser/jwe/flattened/decrypt.js | 138 ++++ dist/browser/jwe/flattened/encrypt.js | 169 +++++ dist/browser/jwe/general/decrypt.js | 30 + dist/browser/jwk/embedded.js | 19 + dist/browser/jwk/from_key_like.js | 6 + dist/browser/jwk/parse.js | 35 + dist/browser/jwk/thumbprint.js | 44 ++ dist/browser/jwks/remote.js | 130 ++++ dist/browser/jws/compact/sign.js | 19 + dist/browser/jws/compact/verify.js | 23 + dist/browser/jws/flattened/sign.js | 84 +++ dist/browser/jws/flattened/verify.js | 103 +++ dist/browser/jws/general/sign.js | 73 ++ dist/browser/jws/general/verify.js | 26 + dist/browser/jwt/decrypt.js | 21 + dist/browser/jwt/encrypt.js | 70 ++ dist/browser/jwt/sign.js | 23 + dist/browser/jwt/unsecured.js | 34 + dist/browser/jwt/verify.js | 14 + dist/browser/lib/buffer_utils.js | 56 ++ dist/browser/lib/cek.js | 18 + dist/browser/lib/check_iv_length.js | 8 + dist/browser/lib/check_key_type.js | 28 + dist/browser/lib/check_p2s.js | 6 + dist/browser/lib/decrypt_key_management.js | 95 +++ dist/browser/lib/encrypt_key_management.js | 87 +++ dist/browser/lib/epoch.js | 1 + dist/browser/lib/is_disjoint.js | 22 + dist/browser/lib/is_object.js | 16 + dist/browser/lib/iv.js | 21 + dist/browser/lib/jwt_claims_set.js | 96 +++ dist/browser/lib/jwt_producer.js | 54 ++ dist/browser/lib/secs.js | 44 ++ dist/browser/lib/validate_algorithms.js | 11 + dist/browser/lib/validate_crit.js | 34 + dist/browser/package.json | 1 + dist/browser/runtime/aesgcmkw.js | 16 + dist/browser/runtime/aeskw.js | 29 + dist/browser/runtime/base64url.js | 31 + dist/browser/runtime/bogus.js | 6 + dist/browser/runtime/check_cek_length.js | 37 + dist/browser/runtime/check_key_length.js | 15 + dist/browser/runtime/decrypt.js | 72 ++ dist/browser/runtime/digest.js | 6 + dist/browser/runtime/ecdhes.js | 34 + dist/browser/runtime/encrypt.js | 55 ++ dist/browser/runtime/fetch_jwks.js | 31 + dist/browser/runtime/generate.js | 114 +++ dist/browser/runtime/get_sign_verify_key.js | 14 + dist/browser/runtime/global.js | 10 + dist/browser/runtime/invalid_key_input.js | 25 + dist/browser/runtime/jwk_to_key.js | 115 +++ dist/browser/runtime/key_to_jwk.js | 20 + dist/browser/runtime/pbes2kw.js | 71 ++ dist/browser/runtime/random.js | 3 + dist/browser/runtime/rsaes.js | 33 + dist/browser/runtime/sign.js | 11 + dist/browser/runtime/subtle_dsa.js | 43 ++ dist/browser/runtime/subtle_rsaes.js | 12 + dist/browser/runtime/timing_safe_equal.js | 19 + dist/browser/runtime/verify.js | 16 + dist/browser/runtime/webcrypto.js | 8 + dist/browser/runtime/zlib.js | 7 + dist/browser/util/base64url.js | 3 + dist/browser/util/decode_protected_header.js | 36 + dist/browser/util/errors.js | 108 +++ dist/browser/util/generate_key_pair.js | 6 + dist/browser/util/generate_secret.js | 6 + dist/browser/util/random.js | 4 + dist/deno/README.md | 38 + dist/deno/jwe/compact/decrypt.ts | 94 +++ dist/deno/jwe/compact/encrypt.ts | 111 +++ dist/deno/jwe/flattened/decrypt.ts | 249 +++++++ dist/deno/jwe/flattened/encrypt.ts | 324 ++++++++ dist/deno/jwe/general/decrypt.ts | 107 +++ dist/deno/jwk/embedded.ts | 62 ++ dist/deno/jwk/from_key_like.ts | 39 + dist/deno/jwk/parse.ts | 90 +++ dist/deno/jwk/thumbprint.ts | 89 +++ dist/deno/jwks/remote.ts | 264 +++++++ dist/deno/jws/compact/sign.ts | 72 ++ dist/deno/jws/compact/verify.ts | 89 +++ dist/deno/jws/flattened/sign.ts | 167 +++++ dist/deno/jws/flattened/verify.ts | 201 +++++ dist/deno/jws/general/sign.ts | 163 +++++ dist/deno/jws/general/verify.ts | 99 +++ dist/deno/jwt/decrypt.ts | 103 +++ dist/deno/jwt/encrypt.ts | 181 +++++ dist/deno/jwt/sign.ts | 73 ++ dist/deno/jwt/unsecured.ts | 96 +++ dist/deno/jwt/verify.ts | 86 +++ dist/deno/lib/buffer_utils.ts | 71 ++ dist/deno/lib/cek.ts | 24 + dist/deno/lib/check_iv_length.ts | 10 + dist/deno/lib/check_key_type.ts | 51 ++ dist/deno/lib/check_p2s.ts | 7 + dist/deno/lib/decrypt_key_management.ts | 128 ++++ dist/deno/lib/encrypt_key_management.ts | 121 +++ dist/deno/lib/epoch.ts | 1 + dist/deno/lib/is_disjoint.ts | 26 + dist/deno/lib/is_object.ts | 17 + dist/deno/lib/iv.ts | 27 + dist/deno/lib/jwt_claims_set.ts | 148 ++++ dist/deno/lib/jwt_producer.ts | 108 +++ dist/deno/lib/secs.ts | 51 ++ dist/deno/lib/validate_algorithms.ts | 16 + dist/deno/lib/validate_crit.ts | 56 ++ dist/deno/runtime/aesgcmkw.ts | 39 + dist/deno/runtime/aeskw.ts | 56 ++ dist/deno/runtime/base64url.ts | 35 + dist/deno/runtime/bogus.ts | 7 + dist/deno/runtime/check_cek_length.ts | 46 ++ dist/deno/runtime/check_key_length.ts | 18 + dist/deno/runtime/decrypt.ts | 129 ++++ dist/deno/runtime/digest.ts | 11 + dist/deno/runtime/ecdhes.ts | 73 ++ dist/deno/runtime/encrypt.ts | 114 +++ dist/deno/runtime/fetch_jwks.ts | 38 + dist/deno/runtime/generate.ts | 126 ++++ dist/deno/runtime/get_sign_verify_key.ts | 23 + dist/deno/runtime/global.ts | 8 + dist/deno/runtime/interfaces.d.ts | 100 +++ dist/deno/runtime/invalid_key_input.ts | 24 + dist/deno/runtime/jwk_to_key.ts | 133 ++++ dist/deno/runtime/key_to_jwk.ts | 26 + dist/deno/runtime/pbes2kw.ts | 98 +++ dist/deno/runtime/random.ts | 5 + dist/deno/runtime/rsaes.ts | 64 ++ dist/deno/runtime/sign.ts | 14 + dist/deno/runtime/subtle_dsa.ts | 46 ++ dist/deno/runtime/subtle_rsaes.ts | 15 + dist/deno/runtime/timing_safe_equal.ts | 23 + dist/deno/runtime/verify.ts | 18 + dist/deno/runtime/webcrypto.ts | 10 + dist/deno/runtime/zlib.ts | 13 + dist/deno/types.d.ts | 691 ++++++++++++++++++ dist/deno/types.i.d.ts | 13 + dist/deno/util/base64url.ts | 21 + dist/deno/util/decode_protected_header.ts | 65 ++ dist/deno/util/errors.ts | 165 +++++ dist/deno/util/generate_key_pair.ts | 79 ++ dist/deno/util/generate_secret.ts | 48 ++ dist/deno/util/random.ts | 9 + dist/node/cjs/jwe/compact/decrypt.js | 28 + dist/node/cjs/jwe/compact/encrypt.js | 31 + dist/node/cjs/jwe/flattened/decrypt.js | 141 ++++ dist/node/cjs/jwe/flattened/encrypt.js | 172 +++++ dist/node/cjs/jwe/general/decrypt.js | 33 + dist/node/cjs/jwk/embedded.js | 22 + dist/node/cjs/jwk/from_key_like.js | 9 + dist/node/cjs/jwk/parse.js | 38 + dist/node/cjs/jwk/thumbprint.js | 47 ++ dist/node/cjs/jwks/remote.js | 133 ++++ dist/node/cjs/jws/compact/sign.js | 22 + dist/node/cjs/jws/compact/verify.js | 26 + dist/node/cjs/jws/flattened/sign.js | 87 +++ dist/node/cjs/jws/flattened/verify.js | 106 +++ dist/node/cjs/jws/general/sign.js | 76 ++ dist/node/cjs/jws/general/verify.js | 29 + dist/node/cjs/jwt/decrypt.js | 24 + dist/node/cjs/jwt/encrypt.js | 73 ++ dist/node/cjs/jwt/sign.js | 26 + dist/node/cjs/jwt/unsecured.js | 37 + dist/node/cjs/jwt/verify.js | 17 + dist/node/cjs/lib/buffer_utils.js | 65 ++ dist/node/cjs/lib/cek.js | 21 + dist/node/cjs/lib/check_iv_length.js | 10 + dist/node/cjs/lib/check_key_type.js | 30 + dist/node/cjs/lib/check_p2s.js | 9 + dist/node/cjs/lib/decrypt_key_management.js | 97 +++ dist/node/cjs/lib/encrypt_key_management.js | 89 +++ dist/node/cjs/lib/epoch.js | 3 + dist/node/cjs/lib/is_disjoint.js | 24 + dist/node/cjs/lib/is_object.js | 19 + dist/node/cjs/lib/iv.js | 24 + dist/node/cjs/lib/jwt_claims_set.js | 98 +++ dist/node/cjs/lib/jwt_producer.js | 57 ++ dist/node/cjs/lib/secs.js | 46 ++ dist/node/cjs/lib/validate_algorithms.js | 13 + dist/node/cjs/lib/validate_crit.js | 36 + dist/node/cjs/runtime/aesgcmkw.js | 21 + dist/node/cjs/runtime/aeskw.js | 52 ++ .../node/cjs/runtime/asn1_sequence_decoder.js | 47 ++ .../node/cjs/runtime/asn1_sequence_encoder.js | 90 +++ dist/node/cjs/runtime/base64url.js | 21 + dist/node/cjs/runtime/cbc_tag.js | 11 + dist/node/cjs/runtime/check_cek_length.js | 35 + dist/node/cjs/runtime/check_modulus_length.js | 52 ++ dist/node/cjs/runtime/ciphers.js | 8 + dist/node/cjs/runtime/decrypt.js | 92 +++ dist/node/cjs/runtime/digest.js | 5 + dist/node/cjs/runtime/dsa_digest.js | 25 + dist/node/cjs/runtime/ecdhes.js | 55 ++ dist/node/cjs/runtime/encrypt.js | 70 ++ dist/node/cjs/runtime/fetch_jwks.js | 36 + dist/node/cjs/runtime/generate.js | 104 +++ dist/node/cjs/runtime/get_named_curve.js | 89 +++ dist/node/cjs/runtime/get_sign_verify_key.js | 22 + dist/node/cjs/runtime/hmac_digest.js | 16 + dist/node/cjs/runtime/invalid_key_input.js | 38 + dist/node/cjs/runtime/is_key_object.js | 16 + dist/node/cjs/runtime/jwk_to_key.js | 121 +++ dist/node/cjs/runtime/key_to_jwk.js | 159 ++++ dist/node/cjs/runtime/node_key.js | 86 +++ dist/node/cjs/runtime/pbes2kw.js | 45 ++ dist/node/cjs/runtime/random.js | 4 + dist/node/cjs/runtime/rsaes.js | 66 ++ dist/node/cjs/runtime/secret_key.js | 14 + dist/node/cjs/runtime/sign.js | 29 + dist/node/cjs/runtime/timing_safe_equal.js | 5 + dist/node/cjs/runtime/verify.js | 42 ++ dist/node/cjs/runtime/webcrypto.js | 165 +++++ dist/node/cjs/runtime/zlib.js | 11 + dist/node/cjs/util/base64url.js | 6 + dist/node/cjs/util/decode_protected_header.js | 39 + dist/node/cjs/util/errors.js | 125 ++++ dist/node/cjs/util/generate_key_pair.js | 9 + dist/node/cjs/util/generate_secret.js | 9 + dist/node/cjs/util/random.js | 7 + dist/node/esm/jwe/compact/decrypt.js | 25 + dist/node/esm/jwe/compact/encrypt.js | 28 + dist/node/esm/jwe/flattened/decrypt.js | 138 ++++ dist/node/esm/jwe/flattened/encrypt.js | 169 +++++ dist/node/esm/jwe/general/decrypt.js | 30 + dist/node/esm/jwk/embedded.js | 19 + dist/node/esm/jwk/from_key_like.js | 6 + dist/node/esm/jwk/parse.js | 35 + dist/node/esm/jwk/thumbprint.js | 44 ++ dist/node/esm/jwks/remote.js | 130 ++++ dist/node/esm/jws/compact/sign.js | 19 + dist/node/esm/jws/compact/verify.js | 23 + dist/node/esm/jws/flattened/sign.js | 84 +++ dist/node/esm/jws/flattened/verify.js | 103 +++ dist/node/esm/jws/general/sign.js | 73 ++ dist/node/esm/jws/general/verify.js | 26 + dist/node/esm/jwt/decrypt.js | 21 + dist/node/esm/jwt/encrypt.js | 70 ++ dist/node/esm/jwt/sign.js | 23 + dist/node/esm/jwt/unsecured.js | 34 + dist/node/esm/jwt/verify.js | 14 + dist/node/esm/lib/buffer_utils.js | 56 ++ dist/node/esm/lib/cek.js | 18 + dist/node/esm/lib/check_iv_length.js | 8 + dist/node/esm/lib/check_key_type.js | 28 + dist/node/esm/lib/check_p2s.js | 6 + dist/node/esm/lib/decrypt_key_management.js | 95 +++ dist/node/esm/lib/encrypt_key_management.js | 87 +++ dist/node/esm/lib/epoch.js | 1 + dist/node/esm/lib/is_disjoint.js | 22 + dist/node/esm/lib/is_object.js | 16 + dist/node/esm/lib/iv.js | 21 + dist/node/esm/lib/jwt_claims_set.js | 96 +++ dist/node/esm/lib/jwt_producer.js | 54 ++ dist/node/esm/lib/secs.js | 44 ++ dist/node/esm/lib/validate_algorithms.js | 11 + dist/node/esm/lib/validate_crit.js | 34 + dist/node/esm/package.json | 1 + dist/node/esm/runtime/aesgcmkw.js | 16 + dist/node/esm/runtime/aeskw.js | 47 ++ .../node/esm/runtime/asn1_sequence_decoder.js | 44 ++ .../node/esm/runtime/asn1_sequence_encoder.js | 87 +++ dist/node/esm/runtime/base64url.js | 17 + dist/node/esm/runtime/cbc_tag.js | 8 + dist/node/esm/runtime/check_cek_length.js | 33 + dist/node/esm/runtime/check_modulus_length.js | 48 ++ dist/node/esm/runtime/ciphers.js | 6 + dist/node/esm/runtime/decrypt.js | 90 +++ dist/node/esm/runtime/digest.js | 3 + dist/node/esm/runtime/dsa_digest.js | 22 + dist/node/esm/runtime/ecdhes.js | 49 ++ dist/node/esm/runtime/encrypt.js | 68 ++ dist/node/esm/runtime/fetch_jwks.js | 34 + dist/node/esm/runtime/generate.js | 99 +++ dist/node/esm/runtime/get_named_curve.js | 85 +++ dist/node/esm/runtime/get_sign_verify_key.js | 19 + dist/node/esm/runtime/hmac_digest.js | 13 + dist/node/esm/runtime/invalid_key_input.js | 36 + dist/node/esm/runtime/is_key_object.js | 14 + dist/node/esm/runtime/jwk_to_key.js | 119 +++ dist/node/esm/runtime/key_to_jwk.js | 157 ++++ dist/node/esm/runtime/node_key.js | 83 +++ dist/node/esm/runtime/pbes2kw.js | 40 + dist/node/esm/runtime/random.js | 2 + dist/node/esm/runtime/rsaes.js | 61 ++ dist/node/esm/runtime/secret_key.js | 11 + dist/node/esm/runtime/sign.js | 27 + dist/node/esm/runtime/timing_safe_equal.js | 3 + dist/node/esm/runtime/verify.js | 40 + dist/node/esm/runtime/webcrypto.js | 161 ++++ dist/node/esm/runtime/zlib.js | 6 + dist/node/esm/util/base64url.js | 3 + dist/node/esm/util/decode_protected_header.js | 36 + dist/node/esm/util/errors.js | 108 +++ dist/node/esm/util/generate_key_pair.js | 6 + dist/node/esm/util/generate_secret.js | 6 + dist/node/esm/util/random.js | 4 + dist/types/jwe/compact/decrypt.d.ts | 7 + dist/types/jwe/compact/encrypt.d.ts | 13 + dist/types/jwe/flattened/decrypt.d.ts | 7 + dist/types/jwe/flattened/encrypt.d.ts | 23 + dist/types/jwe/general/decrypt.d.ts | 7 + dist/types/jwk/embedded.d.ts | 5 + dist/types/jwk/from_key_like.d.ts | 5 + dist/types/jwk/parse.d.ts | 5 + dist/types/jwk/thumbprint.d.ts | 5 + dist/types/jwks/remote.d.ts | 9 + dist/types/jws/compact/sign.d.ts | 10 + dist/types/jws/compact/verify.d.ts | 7 + dist/types/jws/flattened/sign.d.ts | 13 + dist/types/jws/flattened/verify.d.ts | 7 + dist/types/jws/general/sign.d.ts | 15 + dist/types/jws/general/verify.d.ts | 7 + dist/types/jwt/decrypt.d.ts | 9 + dist/types/jwt/encrypt.d.ts | 22 + dist/types/jwt/sign.d.ts | 10 + dist/types/jwt/unsecured.d.ts | 13 + dist/types/jwt/verify.d.ts | 9 + dist/types/lib/jwt_producer.d.ts | 12 + dist/types/types.d.ts | 171 +++++ dist/types/util/base64url.d.ts | 9 + dist/types/util/decode_protected_header.d.ts | 5 + dist/types/util/errors.d.ts | 64 ++ dist/types/util/generate_key_pair.d.ts | 13 + dist/types/util/generate_secret.d.ts | 7 + dist/types/util/random.d.ts | 6 + .../jwe_compact_encrypt.CompactEncrypt.md | 14 +- .../jwe_flattened_encrypt.FlattenedEncrypt.md | 20 +- docs/classes/jws_compact_sign.CompactSign.md | 8 +- .../jws_flattened_sign.FlattenedSign.md | 10 +- docs/classes/jws_general_sign.GeneralSign.md | 8 +- docs/classes/jwt_encrypt.EncryptJWT.md | 34 +- docs/classes/jwt_sign.SignJWT.md | 22 +- docs/classes/jwt_unsecured.UnsecuredJWT.md | 22 +- docs/classes/util_errors.JOSEAlgNotAllowed.md | 6 +- docs/classes/util_errors.JOSEError.md | 6 +- docs/classes/util_errors.JOSENotSupported.md | 6 +- .../util_errors.JWEDecryptionFailed.md | 8 +- docs/classes/util_errors.JWEInvalid.md | 6 +- docs/classes/util_errors.JWKInvalid.md | 6 +- docs/classes/util_errors.JWKSInvalid.md | 6 +- .../util_errors.JWKSMultipleMatchingKeys.md | 8 +- docs/classes/util_errors.JWKSNoMatchingKey.md | 8 +- docs/classes/util_errors.JWSInvalid.md | 6 +- ...l_errors.JWSSignatureVerificationFailed.md | 8 +- .../util_errors.JWTClaimValidationFailed.md | 10 +- docs/classes/util_errors.JWTExpired.md | 10 +- docs/classes/util_errors.JWTInvalid.md | 6 +- .../jwe_compact_decrypt.compactDecrypt.md | 4 +- .../jwe_flattened_decrypt.flattenedDecrypt.md | 4 +- .../jwe_general_decrypt.generalDecrypt.md | 4 +- docs/functions/jwk_embedded.EmbeddedJWK.md | 4 +- .../jwk_from_key_like.fromKeyLike.md | 4 +- docs/functions/jwk_parse.parseJwk.md | 4 +- .../jwk_thumbprint.calculateThumbprint.md | 4 +- .../jwks_remote.createRemoteJWKSet.md | 4 +- .../jws_compact_verify.compactVerify.md | 4 +- .../jws_flattened_verify.flattenedVerify.md | 4 +- .../jws_general_verify.generalVerify.md | 4 +- docs/functions/jwt_decrypt.jwtDecrypt.md | 4 +- docs/functions/jwt_verify.jwtVerify.md | 4 +- docs/functions/util_base64url.decode.md | 2 +- docs/functions/util_base64url.encode.md | 2 +- ..._protected_header.decodeProtectedHeader.md | 4 +- .../util_generate_key_pair.generateKeyPair.md | 4 +- .../util_generate_secret.generateSecret.md | 4 +- docs/functions/util_random.random.md | 2 +- ...we_compact_decrypt.CompactDecryptGetKey.md | 2 +- ...lattened_decrypt.FlattenedDecryptGetKey.md | 2 +- ...we_general_decrypt.GeneralDecryptGetKey.md | 2 +- .../jwks_remote.RemoteJWKSetOptions.md | 6 +- .../jws_compact_verify.CompactVerifyGetKey.md | 2 +- ..._flattened_verify.FlattenedVerifyGetKey.md | 2 +- docs/interfaces/jws_general_sign.Signature.md | 4 +- .../jws_general_verify.GeneralVerifyGetKey.md | 2 +- .../jwt_decrypt.JWTDecryptGetKey.md | 2 +- .../jwt_decrypt.JWTDecryptOptions.md | 22 +- .../jwt_unsecured.UnsecuredResult.md | 4 +- docs/interfaces/jwt_verify.JWTVerifyGetKey.md | 2 +- .../interfaces/jwt_verify.JWTVerifyOptions.md | 18 +- docs/interfaces/types.CompactDecryptResult.md | 4 +- docs/interfaces/types.CompactVerifyResult.md | 4 +- docs/interfaces/types.CritOption.md | 2 +- docs/interfaces/types.DecryptOptions.md | 8 +- docs/interfaces/types.DeflateFunction.md | 2 +- docs/interfaces/types.EncryptOptions.md | 4 +- .../types.FlattenedDecryptResult.md | 10 +- docs/interfaces/types.FlattenedJWE.md | 16 +- docs/interfaces/types.FlattenedJWS.md | 8 +- docs/interfaces/types.FlattenedJWSInput.md | 8 +- .../interfaces/types.FlattenedVerifyResult.md | 6 +- docs/interfaces/types.GeneralDecryptResult.md | 10 +- docs/interfaces/types.GeneralJWE.md | 14 +- docs/interfaces/types.GeneralJWS.md | 4 +- docs/interfaces/types.GeneralJWSInput.md | 4 +- docs/interfaces/types.GeneralVerifyResult.md | 6 +- docs/interfaces/types.GetKeyFunction.md | 2 +- docs/interfaces/types.InflateFunction.md | 2 +- docs/interfaces/types.JWEHeaderParameters.md | 24 +- .../types.JWEKeyManagementHeaderParameters.md | 12 +- docs/interfaces/types.JWK.md | 46 +- docs/interfaces/types.JWSHeaderParameters.md | 22 +- .../types.JWTClaimVerificationOptions.md | 14 +- docs/interfaces/types.JWTDecryptResult.md | 4 +- docs/interfaces/types.JWTPayload.md | 14 +- docs/interfaces/types.JWTVerifyResult.md | 4 +- docs/interfaces/types.JoseHeaderParameters.md | 16 +- docs/interfaces/types.SignOptions.md | 2 +- docs/interfaces/types.VerifyOptions.md | 4 +- ...enerate_key_pair.GenerateKeyPairOptions.md | 6 +- ...generate_key_pair.GenerateKeyPairResult.md | 4 +- ...l_generate_secret.GenerateSecretOptions.md | 2 +- docs/types/types.KeyLike.md | 2 +- ...tected_header.ProtectedHeaderParameters.md | 2 +- package.json | 2 +- 417 files changed, 16716 insertions(+), 336 deletions(-) create mode 100644 dist/browser/jwe/compact/decrypt.js create mode 100644 dist/browser/jwe/compact/encrypt.js create mode 100644 dist/browser/jwe/flattened/decrypt.js create mode 100644 dist/browser/jwe/flattened/encrypt.js create mode 100644 dist/browser/jwe/general/decrypt.js create mode 100644 dist/browser/jwk/embedded.js create mode 100644 dist/browser/jwk/from_key_like.js create mode 100644 dist/browser/jwk/parse.js create mode 100644 dist/browser/jwk/thumbprint.js create mode 100644 dist/browser/jwks/remote.js create mode 100644 dist/browser/jws/compact/sign.js create mode 100644 dist/browser/jws/compact/verify.js create mode 100644 dist/browser/jws/flattened/sign.js create mode 100644 dist/browser/jws/flattened/verify.js create mode 100644 dist/browser/jws/general/sign.js create mode 100644 dist/browser/jws/general/verify.js create mode 100644 dist/browser/jwt/decrypt.js create mode 100644 dist/browser/jwt/encrypt.js create mode 100644 dist/browser/jwt/sign.js create mode 100644 dist/browser/jwt/unsecured.js create mode 100644 dist/browser/jwt/verify.js create mode 100644 dist/browser/lib/buffer_utils.js create mode 100644 dist/browser/lib/cek.js create mode 100644 dist/browser/lib/check_iv_length.js create mode 100644 dist/browser/lib/check_key_type.js create mode 100644 dist/browser/lib/check_p2s.js create mode 100644 dist/browser/lib/decrypt_key_management.js create mode 100644 dist/browser/lib/encrypt_key_management.js create mode 100644 dist/browser/lib/epoch.js create mode 100644 dist/browser/lib/is_disjoint.js create mode 100644 dist/browser/lib/is_object.js create mode 100644 dist/browser/lib/iv.js create mode 100644 dist/browser/lib/jwt_claims_set.js create mode 100644 dist/browser/lib/jwt_producer.js create mode 100644 dist/browser/lib/secs.js create mode 100644 dist/browser/lib/validate_algorithms.js create mode 100644 dist/browser/lib/validate_crit.js create mode 100644 dist/browser/package.json create mode 100644 dist/browser/runtime/aesgcmkw.js create mode 100644 dist/browser/runtime/aeskw.js create mode 100644 dist/browser/runtime/base64url.js create mode 100644 dist/browser/runtime/bogus.js create mode 100644 dist/browser/runtime/check_cek_length.js create mode 100644 dist/browser/runtime/check_key_length.js create mode 100644 dist/browser/runtime/decrypt.js create mode 100644 dist/browser/runtime/digest.js create mode 100644 dist/browser/runtime/ecdhes.js create mode 100644 dist/browser/runtime/encrypt.js create mode 100644 dist/browser/runtime/fetch_jwks.js create mode 100644 dist/browser/runtime/generate.js create mode 100644 dist/browser/runtime/get_sign_verify_key.js create mode 100644 dist/browser/runtime/global.js create mode 100644 dist/browser/runtime/invalid_key_input.js create mode 100644 dist/browser/runtime/jwk_to_key.js create mode 100644 dist/browser/runtime/key_to_jwk.js create mode 100644 dist/browser/runtime/pbes2kw.js create mode 100644 dist/browser/runtime/random.js create mode 100644 dist/browser/runtime/rsaes.js create mode 100644 dist/browser/runtime/sign.js create mode 100644 dist/browser/runtime/subtle_dsa.js create mode 100644 dist/browser/runtime/subtle_rsaes.js create mode 100644 dist/browser/runtime/timing_safe_equal.js create mode 100644 dist/browser/runtime/verify.js create mode 100644 dist/browser/runtime/webcrypto.js create mode 100644 dist/browser/runtime/zlib.js create mode 100644 dist/browser/util/base64url.js create mode 100644 dist/browser/util/decode_protected_header.js create mode 100644 dist/browser/util/errors.js create mode 100644 dist/browser/util/generate_key_pair.js create mode 100644 dist/browser/util/generate_secret.js create mode 100644 dist/browser/util/random.js create mode 100644 dist/deno/README.md create mode 100644 dist/deno/jwe/compact/decrypt.ts create mode 100644 dist/deno/jwe/compact/encrypt.ts create mode 100644 dist/deno/jwe/flattened/decrypt.ts create mode 100644 dist/deno/jwe/flattened/encrypt.ts create mode 100644 dist/deno/jwe/general/decrypt.ts create mode 100644 dist/deno/jwk/embedded.ts create mode 100644 dist/deno/jwk/from_key_like.ts create mode 100644 dist/deno/jwk/parse.ts create mode 100644 dist/deno/jwk/thumbprint.ts create mode 100644 dist/deno/jwks/remote.ts create mode 100644 dist/deno/jws/compact/sign.ts create mode 100644 dist/deno/jws/compact/verify.ts create mode 100644 dist/deno/jws/flattened/sign.ts create mode 100644 dist/deno/jws/flattened/verify.ts create mode 100644 dist/deno/jws/general/sign.ts create mode 100644 dist/deno/jws/general/verify.ts create mode 100644 dist/deno/jwt/decrypt.ts create mode 100644 dist/deno/jwt/encrypt.ts create mode 100644 dist/deno/jwt/sign.ts create mode 100644 dist/deno/jwt/unsecured.ts create mode 100644 dist/deno/jwt/verify.ts create mode 100644 dist/deno/lib/buffer_utils.ts create mode 100644 dist/deno/lib/cek.ts create mode 100644 dist/deno/lib/check_iv_length.ts create mode 100644 dist/deno/lib/check_key_type.ts create mode 100644 dist/deno/lib/check_p2s.ts create mode 100644 dist/deno/lib/decrypt_key_management.ts create mode 100644 dist/deno/lib/encrypt_key_management.ts create mode 100644 dist/deno/lib/epoch.ts create mode 100644 dist/deno/lib/is_disjoint.ts create mode 100644 dist/deno/lib/is_object.ts create mode 100644 dist/deno/lib/iv.ts create mode 100644 dist/deno/lib/jwt_claims_set.ts create mode 100644 dist/deno/lib/jwt_producer.ts create mode 100644 dist/deno/lib/secs.ts create mode 100644 dist/deno/lib/validate_algorithms.ts create mode 100644 dist/deno/lib/validate_crit.ts create mode 100644 dist/deno/runtime/aesgcmkw.ts create mode 100644 dist/deno/runtime/aeskw.ts create mode 100644 dist/deno/runtime/base64url.ts create mode 100644 dist/deno/runtime/bogus.ts create mode 100644 dist/deno/runtime/check_cek_length.ts create mode 100644 dist/deno/runtime/check_key_length.ts create mode 100644 dist/deno/runtime/decrypt.ts create mode 100644 dist/deno/runtime/digest.ts create mode 100644 dist/deno/runtime/ecdhes.ts create mode 100644 dist/deno/runtime/encrypt.ts create mode 100644 dist/deno/runtime/fetch_jwks.ts create mode 100644 dist/deno/runtime/generate.ts create mode 100644 dist/deno/runtime/get_sign_verify_key.ts create mode 100644 dist/deno/runtime/global.ts create mode 100644 dist/deno/runtime/interfaces.d.ts create mode 100644 dist/deno/runtime/invalid_key_input.ts create mode 100644 dist/deno/runtime/jwk_to_key.ts create mode 100644 dist/deno/runtime/key_to_jwk.ts create mode 100644 dist/deno/runtime/pbes2kw.ts create mode 100644 dist/deno/runtime/random.ts create mode 100644 dist/deno/runtime/rsaes.ts create mode 100644 dist/deno/runtime/sign.ts create mode 100644 dist/deno/runtime/subtle_dsa.ts create mode 100644 dist/deno/runtime/subtle_rsaes.ts create mode 100644 dist/deno/runtime/timing_safe_equal.ts create mode 100644 dist/deno/runtime/verify.ts create mode 100644 dist/deno/runtime/webcrypto.ts create mode 100644 dist/deno/runtime/zlib.ts create mode 100644 dist/deno/types.d.ts create mode 100644 dist/deno/types.i.d.ts create mode 100644 dist/deno/util/base64url.ts create mode 100644 dist/deno/util/decode_protected_header.ts create mode 100644 dist/deno/util/errors.ts create mode 100644 dist/deno/util/generate_key_pair.ts create mode 100644 dist/deno/util/generate_secret.ts create mode 100644 dist/deno/util/random.ts create mode 100644 dist/node/cjs/jwe/compact/decrypt.js create mode 100644 dist/node/cjs/jwe/compact/encrypt.js create mode 100644 dist/node/cjs/jwe/flattened/decrypt.js create mode 100644 dist/node/cjs/jwe/flattened/encrypt.js create mode 100644 dist/node/cjs/jwe/general/decrypt.js create mode 100644 dist/node/cjs/jwk/embedded.js create mode 100644 dist/node/cjs/jwk/from_key_like.js create mode 100644 dist/node/cjs/jwk/parse.js create mode 100644 dist/node/cjs/jwk/thumbprint.js create mode 100644 dist/node/cjs/jwks/remote.js create mode 100644 dist/node/cjs/jws/compact/sign.js create mode 100644 dist/node/cjs/jws/compact/verify.js create mode 100644 dist/node/cjs/jws/flattened/sign.js create mode 100644 dist/node/cjs/jws/flattened/verify.js create mode 100644 dist/node/cjs/jws/general/sign.js create mode 100644 dist/node/cjs/jws/general/verify.js create mode 100644 dist/node/cjs/jwt/decrypt.js create mode 100644 dist/node/cjs/jwt/encrypt.js create mode 100644 dist/node/cjs/jwt/sign.js create mode 100644 dist/node/cjs/jwt/unsecured.js create mode 100644 dist/node/cjs/jwt/verify.js create mode 100644 dist/node/cjs/lib/buffer_utils.js create mode 100644 dist/node/cjs/lib/cek.js create mode 100644 dist/node/cjs/lib/check_iv_length.js create mode 100644 dist/node/cjs/lib/check_key_type.js create mode 100644 dist/node/cjs/lib/check_p2s.js create mode 100644 dist/node/cjs/lib/decrypt_key_management.js create mode 100644 dist/node/cjs/lib/encrypt_key_management.js create mode 100644 dist/node/cjs/lib/epoch.js create mode 100644 dist/node/cjs/lib/is_disjoint.js create mode 100644 dist/node/cjs/lib/is_object.js create mode 100644 dist/node/cjs/lib/iv.js create mode 100644 dist/node/cjs/lib/jwt_claims_set.js create mode 100644 dist/node/cjs/lib/jwt_producer.js create mode 100644 dist/node/cjs/lib/secs.js create mode 100644 dist/node/cjs/lib/validate_algorithms.js create mode 100644 dist/node/cjs/lib/validate_crit.js create mode 100644 dist/node/cjs/runtime/aesgcmkw.js create mode 100644 dist/node/cjs/runtime/aeskw.js create mode 100644 dist/node/cjs/runtime/asn1_sequence_decoder.js create mode 100644 dist/node/cjs/runtime/asn1_sequence_encoder.js create mode 100644 dist/node/cjs/runtime/base64url.js create mode 100644 dist/node/cjs/runtime/cbc_tag.js create mode 100644 dist/node/cjs/runtime/check_cek_length.js create mode 100644 dist/node/cjs/runtime/check_modulus_length.js create mode 100644 dist/node/cjs/runtime/ciphers.js create mode 100644 dist/node/cjs/runtime/decrypt.js create mode 100644 dist/node/cjs/runtime/digest.js create mode 100644 dist/node/cjs/runtime/dsa_digest.js create mode 100644 dist/node/cjs/runtime/ecdhes.js create mode 100644 dist/node/cjs/runtime/encrypt.js create mode 100644 dist/node/cjs/runtime/fetch_jwks.js create mode 100644 dist/node/cjs/runtime/generate.js create mode 100644 dist/node/cjs/runtime/get_named_curve.js create mode 100644 dist/node/cjs/runtime/get_sign_verify_key.js create mode 100644 dist/node/cjs/runtime/hmac_digest.js create mode 100644 dist/node/cjs/runtime/invalid_key_input.js create mode 100644 dist/node/cjs/runtime/is_key_object.js create mode 100644 dist/node/cjs/runtime/jwk_to_key.js create mode 100644 dist/node/cjs/runtime/key_to_jwk.js create mode 100644 dist/node/cjs/runtime/node_key.js create mode 100644 dist/node/cjs/runtime/pbes2kw.js create mode 100644 dist/node/cjs/runtime/random.js create mode 100644 dist/node/cjs/runtime/rsaes.js create mode 100644 dist/node/cjs/runtime/secret_key.js create mode 100644 dist/node/cjs/runtime/sign.js create mode 100644 dist/node/cjs/runtime/timing_safe_equal.js create mode 100644 dist/node/cjs/runtime/verify.js create mode 100644 dist/node/cjs/runtime/webcrypto.js create mode 100644 dist/node/cjs/runtime/zlib.js create mode 100644 dist/node/cjs/util/base64url.js create mode 100644 dist/node/cjs/util/decode_protected_header.js create mode 100644 dist/node/cjs/util/errors.js create mode 100644 dist/node/cjs/util/generate_key_pair.js create mode 100644 dist/node/cjs/util/generate_secret.js create mode 100644 dist/node/cjs/util/random.js create mode 100644 dist/node/esm/jwe/compact/decrypt.js create mode 100644 dist/node/esm/jwe/compact/encrypt.js create mode 100644 dist/node/esm/jwe/flattened/decrypt.js create mode 100644 dist/node/esm/jwe/flattened/encrypt.js create mode 100644 dist/node/esm/jwe/general/decrypt.js create mode 100644 dist/node/esm/jwk/embedded.js create mode 100644 dist/node/esm/jwk/from_key_like.js create mode 100644 dist/node/esm/jwk/parse.js create mode 100644 dist/node/esm/jwk/thumbprint.js create mode 100644 dist/node/esm/jwks/remote.js create mode 100644 dist/node/esm/jws/compact/sign.js create mode 100644 dist/node/esm/jws/compact/verify.js create mode 100644 dist/node/esm/jws/flattened/sign.js create mode 100644 dist/node/esm/jws/flattened/verify.js create mode 100644 dist/node/esm/jws/general/sign.js create mode 100644 dist/node/esm/jws/general/verify.js create mode 100644 dist/node/esm/jwt/decrypt.js create mode 100644 dist/node/esm/jwt/encrypt.js create mode 100644 dist/node/esm/jwt/sign.js create mode 100644 dist/node/esm/jwt/unsecured.js create mode 100644 dist/node/esm/jwt/verify.js create mode 100644 dist/node/esm/lib/buffer_utils.js create mode 100644 dist/node/esm/lib/cek.js create mode 100644 dist/node/esm/lib/check_iv_length.js create mode 100644 dist/node/esm/lib/check_key_type.js create mode 100644 dist/node/esm/lib/check_p2s.js create mode 100644 dist/node/esm/lib/decrypt_key_management.js create mode 100644 dist/node/esm/lib/encrypt_key_management.js create mode 100644 dist/node/esm/lib/epoch.js create mode 100644 dist/node/esm/lib/is_disjoint.js create mode 100644 dist/node/esm/lib/is_object.js create mode 100644 dist/node/esm/lib/iv.js create mode 100644 dist/node/esm/lib/jwt_claims_set.js create mode 100644 dist/node/esm/lib/jwt_producer.js create mode 100644 dist/node/esm/lib/secs.js create mode 100644 dist/node/esm/lib/validate_algorithms.js create mode 100644 dist/node/esm/lib/validate_crit.js create mode 100644 dist/node/esm/package.json create mode 100644 dist/node/esm/runtime/aesgcmkw.js create mode 100644 dist/node/esm/runtime/aeskw.js create mode 100644 dist/node/esm/runtime/asn1_sequence_decoder.js create mode 100644 dist/node/esm/runtime/asn1_sequence_encoder.js create mode 100644 dist/node/esm/runtime/base64url.js create mode 100644 dist/node/esm/runtime/cbc_tag.js create mode 100644 dist/node/esm/runtime/check_cek_length.js create mode 100644 dist/node/esm/runtime/check_modulus_length.js create mode 100644 dist/node/esm/runtime/ciphers.js create mode 100644 dist/node/esm/runtime/decrypt.js create mode 100644 dist/node/esm/runtime/digest.js create mode 100644 dist/node/esm/runtime/dsa_digest.js create mode 100644 dist/node/esm/runtime/ecdhes.js create mode 100644 dist/node/esm/runtime/encrypt.js create mode 100644 dist/node/esm/runtime/fetch_jwks.js create mode 100644 dist/node/esm/runtime/generate.js create mode 100644 dist/node/esm/runtime/get_named_curve.js create mode 100644 dist/node/esm/runtime/get_sign_verify_key.js create mode 100644 dist/node/esm/runtime/hmac_digest.js create mode 100644 dist/node/esm/runtime/invalid_key_input.js create mode 100644 dist/node/esm/runtime/is_key_object.js create mode 100644 dist/node/esm/runtime/jwk_to_key.js create mode 100644 dist/node/esm/runtime/key_to_jwk.js create mode 100644 dist/node/esm/runtime/node_key.js create mode 100644 dist/node/esm/runtime/pbes2kw.js create mode 100644 dist/node/esm/runtime/random.js create mode 100644 dist/node/esm/runtime/rsaes.js create mode 100644 dist/node/esm/runtime/secret_key.js create mode 100644 dist/node/esm/runtime/sign.js create mode 100644 dist/node/esm/runtime/timing_safe_equal.js create mode 100644 dist/node/esm/runtime/verify.js create mode 100644 dist/node/esm/runtime/webcrypto.js create mode 100644 dist/node/esm/runtime/zlib.js create mode 100644 dist/node/esm/util/base64url.js create mode 100644 dist/node/esm/util/decode_protected_header.js create mode 100644 dist/node/esm/util/errors.js create mode 100644 dist/node/esm/util/generate_key_pair.js create mode 100644 dist/node/esm/util/generate_secret.js create mode 100644 dist/node/esm/util/random.js create mode 100644 dist/types/jwe/compact/decrypt.d.ts create mode 100644 dist/types/jwe/compact/encrypt.d.ts create mode 100644 dist/types/jwe/flattened/decrypt.d.ts create mode 100644 dist/types/jwe/flattened/encrypt.d.ts create mode 100644 dist/types/jwe/general/decrypt.d.ts create mode 100644 dist/types/jwk/embedded.d.ts create mode 100644 dist/types/jwk/from_key_like.d.ts create mode 100644 dist/types/jwk/parse.d.ts create mode 100644 dist/types/jwk/thumbprint.d.ts create mode 100644 dist/types/jwks/remote.d.ts create mode 100644 dist/types/jws/compact/sign.d.ts create mode 100644 dist/types/jws/compact/verify.d.ts create mode 100644 dist/types/jws/flattened/sign.d.ts create mode 100644 dist/types/jws/flattened/verify.d.ts create mode 100644 dist/types/jws/general/sign.d.ts create mode 100644 dist/types/jws/general/verify.d.ts create mode 100644 dist/types/jwt/decrypt.d.ts create mode 100644 dist/types/jwt/encrypt.d.ts create mode 100644 dist/types/jwt/sign.d.ts create mode 100644 dist/types/jwt/unsecured.d.ts create mode 100644 dist/types/jwt/verify.d.ts create mode 100644 dist/types/lib/jwt_producer.d.ts create mode 100644 dist/types/types.d.ts create mode 100644 dist/types/util/base64url.d.ts create mode 100644 dist/types/util/decode_protected_header.d.ts create mode 100644 dist/types/util/errors.d.ts create mode 100644 dist/types/util/generate_key_pair.d.ts create mode 100644 dist/types/util/generate_secret.d.ts create mode 100644 dist/types/util/random.d.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c8287ed8d..3d3e8c4882 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ 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.16.1](https://github.com/panva/jose/compare/v3.16.0...v3.16.1) (2021-09-08) + + +### Bug Fixes + +* guard Sign payloads and Encrypt plaintext argument types ([10a18f2](https://github.com/panva/jose/commit/10a18f28a0f845e91579afab3573730c9b1ae478)) + ## [3.16.0](https://github.com/panva/jose/compare/v3.15.5...v3.16.0) (2021-09-07) diff --git a/dist/browser/jwe/compact/decrypt.js b/dist/browser/jwe/compact/decrypt.js new file mode 100644 index 0000000000..e4e87c1c17 --- /dev/null +++ b/dist/browser/jwe/compact/decrypt.js @@ -0,0 +1,25 @@ +import decrypt from '../flattened/decrypt.js'; +import { JWEInvalid } from '../../util/errors.js'; +import { decoder } from '../../lib/buffer_utils.js'; +async function compactDecrypt(jwe, key, options) { + if (jwe instanceof Uint8Array) { + jwe = decoder.decode(jwe); + } + if (typeof jwe !== 'string') { + throw new JWEInvalid('Compact JWE must be a string or Uint8Array'); + } + 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: (ciphertext || undefined), + iv: (iv || undefined), + protected: protectedHeader || undefined, + tag: (tag || undefined), + encrypted_key: encryptedKey || undefined, + }, key, options); + return { plaintext: decrypted.plaintext, protectedHeader: decrypted.protectedHeader }; +} +export { compactDecrypt }; +export default compactDecrypt; diff --git a/dist/browser/jwe/compact/encrypt.js b/dist/browser/jwe/compact/encrypt.js new file mode 100644 index 0000000000..132a092398 --- /dev/null +++ b/dist/browser/jwe/compact/encrypt.js @@ -0,0 +1,28 @@ +import FlattenedEncrypt from '../flattened/encrypt.js'; +class CompactEncrypt { + constructor(plaintext) { + this._flattened = new FlattenedEncrypt(plaintext); + } + setContentEncryptionKey(cek) { + this._flattened.setContentEncryptionKey(cek); + return this; + } + setInitializationVector(iv) { + this._flattened.setInitializationVector(iv); + return this; + } + setProtectedHeader(protectedHeader) { + this._flattened.setProtectedHeader(protectedHeader); + return this; + } + setKeyManagementParameters(parameters) { + this._flattened.setKeyManagementParameters(parameters); + return this; + } + async encrypt(key, options) { + const jwe = await this._flattened.encrypt(key, options); + return [jwe.protected, jwe.encrypted_key, jwe.iv, jwe.ciphertext, jwe.tag].join('.'); + } +} +export { CompactEncrypt }; +export default CompactEncrypt; diff --git a/dist/browser/jwe/flattened/decrypt.js b/dist/browser/jwe/flattened/decrypt.js new file mode 100644 index 0000000000..39e329284a --- /dev/null +++ b/dist/browser/jwe/flattened/decrypt.js @@ -0,0 +1,138 @@ +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 { 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 checkExtensions = validateCrit.bind(undefined, JWEInvalid, new Map()); +const checkAlgOption = validateAlgorithms.bind(undefined, 'keyManagementAlgorithms'); +const checkEncOption = validateAlgorithms.bind(undefined, 'contentEncryptionAlgorithms'); +async function flattenedDecrypt(jwe, key, options) { + var _a; + if (!isObject(jwe)) { + throw new JWEInvalid('Flattened JWE must be an object'); + } + if (jwe.protected === undefined && jwe.header === undefined && jwe.unprotected === undefined) { + throw new JWEInvalid('JOSE Header missing'); + } + if (typeof jwe.iv !== 'string') { + throw new JWEInvalid('JWE Initialization Vector missing or incorrect type'); + } + if (typeof jwe.ciphertext !== 'string') { + throw new JWEInvalid('JWE Ciphertext missing or incorrect type'); + } + if (typeof jwe.tag !== 'string') { + throw new JWEInvalid('JWE Authentication Tag missing or incorrect type'); + } + if (jwe.protected !== undefined && typeof jwe.protected !== 'string') { + throw new JWEInvalid('JWE Protected Header incorrect type'); + } + if (jwe.encrypted_key !== undefined && typeof jwe.encrypted_key !== 'string') { + throw new JWEInvalid('JWE Encrypted Key incorrect type'); + } + if (jwe.aad !== undefined && typeof jwe.aad !== 'string') { + throw new JWEInvalid('JWE AAD incorrect type'); + } + if (jwe.header !== undefined && !isObject(jwe.header)) { + throw new JWEInvalid('JWE Shared Unprotected Header incorrect type'); + } + if (jwe.unprotected !== undefined && !isObject(jwe.unprotected)) { + throw new JWEInvalid('JWE Per-Recipient Unprotected Header incorrect type'); + } + let parsedProt; + if (jwe.protected) { + const protectedHeader = base64url(jwe.protected); + try { + parsedProt = JSON.parse(decoder.decode(protectedHeader)); + } + catch (_b) { + throw new JWEInvalid('JWE Protected Header is invalid'); + } + } + 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 = { + ...parsedProt, + ...jwe.header, + ...jwe.unprotected, + }; + checkExtensions(options === null || options === void 0 ? void 0 : options.crit, parsedProt, joseHeader); + if (joseHeader.zip !== undefined) { + 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 (typeof alg !== 'string' || !alg) { + throw new JWEInvalid('missing JWE Algorithm (alg) in JWE Header'); + } + if (typeof enc !== 'string' || !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; + if (jwe.encrypted_key !== undefined) { + encryptedKey = base64url(jwe.encrypted_key); + } + if (typeof key === 'function') { + key = await key(parsedProt, jwe); + } + let cek; + try { + cek = await decryptKeyManagement(alg, key, encryptedKey, joseHeader); + } + catch (err) { + if (err instanceof TypeError) { + throw err; + } + cek = generateCek(enc); + } + const iv = base64url(jwe.iv); + const tag = base64url(jwe.tag); + const protectedHeader = encoder.encode((_a = jwe.protected) !== null && _a !== void 0 ? _a : ''); + let additionalData; + if (jwe.aad !== undefined) { + 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 === null || options === void 0 ? void 0 : options.inflateRaw) || inflate)(plaintext); + } + const result = { plaintext }; + if (jwe.protected !== undefined) { + result.protectedHeader = parsedProt; + } + if (jwe.aad !== undefined) { + result.additionalAuthenticatedData = base64url(jwe.aad); + } + if (jwe.unprotected !== undefined) { + result.sharedUnprotectedHeader = jwe.unprotected; + } + if (jwe.header !== undefined) { + result.unprotectedHeader = jwe.header; + } + return result; +} +export { flattenedDecrypt }; +export default flattenedDecrypt; diff --git a/dist/browser/jwe/flattened/encrypt.js b/dist/browser/jwe/flattened/encrypt.js new file mode 100644 index 0000000000..89c09f66ad --- /dev/null +++ b/dist/browser/jwe/flattened/encrypt.js @@ -0,0 +1,169 @@ +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 checkExtensions = validateCrit.bind(undefined, JWEInvalid, new Map()); +class FlattenedEncrypt { + constructor(plaintext) { + if (!(plaintext instanceof Uint8Array)) { + throw new TypeError('plaintext must be an instance of Uint8Array'); + } + this._plaintext = plaintext; + } + setKeyManagementParameters(parameters) { + if (this._keyManagementParameters) { + throw new TypeError('setKeyManagementParameters can only be called once'); + } + this._keyManagementParameters = parameters; + return this; + } + setProtectedHeader(protectedHeader) { + if (this._protectedHeader) { + throw new TypeError('setProtectedHeader can only be called once'); + } + this._protectedHeader = protectedHeader; + return this; + } + setSharedUnprotectedHeader(sharedUnprotectedHeader) { + if (this._sharedUnprotectedHeader) { + throw new TypeError('setSharedUnprotectedHeader can only be called once'); + } + this._sharedUnprotectedHeader = sharedUnprotectedHeader; + return this; + } + setUnprotectedHeader(unprotectedHeader) { + if (this._unprotectedHeader) { + throw new TypeError('setUnprotectedHeader can only be called once'); + } + this._unprotectedHeader = unprotectedHeader; + return this; + } + setAdditionalAuthenticatedData(aad) { + this._aad = aad; + return this; + } + setContentEncryptionKey(cek) { + if (this._cek) { + throw new TypeError('setContentEncryptionKey can only be called once'); + } + this._cek = cek; + return this; + } + setInitializationVector(iv) { + if (this._iv) { + throw new TypeError('setInitializationVector can only be called once'); + } + this._iv = iv; + return this; + } + async encrypt(key, options) { + 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 = { + ...this._protectedHeader, + ...this._unprotectedHeader, + ...this._sharedUnprotectedHeader, + }; + checkExtensions(options === null || options === void 0 ? void 0 : options.crit, this._protectedHeader, joseHeader); + if (joseHeader.zip !== undefined) { + 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 (typeof alg !== 'string' || !alg) { + throw new JWEInvalid('JWE "alg" (Algorithm) Header Parameter missing or invalid'); + } + if (typeof enc !== 'string' || !enc) { + throw new JWEInvalid('JWE "enc" (Encryption Algorithm) Header Parameter missing or invalid'); + } + let encryptedKey; + 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; + { + let parameters; + ({ 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 || (this._iv = generateIv(enc)); + let additionalData; + let protectedHeader; + let aadMember; + 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; + let tag; + if (joseHeader.zip === 'DEF') { + const deflated = await ((options === null || options === void 0 ? void 0 : 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 = { + 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 { FlattenedEncrypt }; +export default FlattenedEncrypt; diff --git a/dist/browser/jwe/general/decrypt.js b/dist/browser/jwe/general/decrypt.js new file mode 100644 index 0000000000..41ec149d81 --- /dev/null +++ b/dist/browser/jwe/general/decrypt.js @@ -0,0 +1,30 @@ +import decrypt from '../flattened/decrypt.js'; +import { JWEDecryptionFailed, JWEInvalid } from '../../util/errors.js'; +import isObject from '../../lib/is_object.js'; +async function generalDecrypt(jwe, key, options) { + if (!isObject(jwe)) { + throw new JWEInvalid('General JWE must be an object'); + } + if (!Array.isArray(jwe.recipients) || !jwe.recipients.every(isObject)) { + throw new JWEInvalid('JWE Recipients missing or incorrect type'); + } + for (const recipient of jwe.recipients) { + try { + return await decrypt({ + aad: jwe.aad, + ciphertext: jwe.ciphertext, + encrypted_key: recipient.encrypted_key, + header: recipient.header, + iv: jwe.iv, + protected: jwe.protected, + tag: jwe.tag, + unprotected: jwe.unprotected, + }, key, options); + } + catch (_a) { + } + } + throw new JWEDecryptionFailed(); +} +export { generalDecrypt }; +export default generalDecrypt; diff --git a/dist/browser/jwk/embedded.js b/dist/browser/jwk/embedded.js new file mode 100644 index 0000000000..60759f22e0 --- /dev/null +++ b/dist/browser/jwk/embedded.js @@ -0,0 +1,19 @@ +import parseJwk from './parse.js'; +import isObject from '../lib/is_object.js'; +import { JWSInvalid } from '../util/errors.js'; +async function EmbeddedJWK(protectedHeader, token) { + const joseHeader = { + ...protectedHeader, + ...token.header, + }; + if (!isObject(joseHeader.jwk)) { + throw new JWSInvalid('"jwk" (JSON Web Key) Header Parameter must be a JSON object'); + } + const key = await parseJwk(joseHeader.jwk, joseHeader.alg, true); + if (key.type !== 'public') { + throw new JWSInvalid('"jwk" (JSON Web Key) Header Parameter must be a public key'); + } + return key; +} +export { EmbeddedJWK }; +export default EmbeddedJWK; diff --git a/dist/browser/jwk/from_key_like.js b/dist/browser/jwk/from_key_like.js new file mode 100644 index 0000000000..5ea9173e1c --- /dev/null +++ b/dist/browser/jwk/from_key_like.js @@ -0,0 +1,6 @@ +import asJWK from '../runtime/key_to_jwk.js'; +async function fromKeyLike(key) { + return asJWK(key); +} +export { fromKeyLike }; +export default fromKeyLike; diff --git a/dist/browser/jwk/parse.js b/dist/browser/jwk/parse.js new file mode 100644 index 0000000000..cfa6f9492c --- /dev/null +++ b/dist/browser/jwk/parse.js @@ -0,0 +1,35 @@ +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'; +async function parseJwk(jwk, alg, octAsKeyObject) { + if (!isObject(jwk)) { + throw new TypeError('JWK must be an object'); + } + alg || (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'); + } + octAsKeyObject !== null && octAsKeyObject !== void 0 ? octAsKeyObject : (octAsKeyObject = jwk.ext !== true); + if (octAsKeyObject) { + return asKeyObject({ ...jwk, alg, ext: false }); + } + return base64url(jwk.k); + case 'RSA': + if (jwk.oth !== undefined) { + throw new JOSENotSupported('RSA JWK "oth" (Other Primes Info) Parameter value is not supported'); + } + case 'EC': + case 'OKP': + return asKeyObject({ ...jwk, alg }); + default: + throw new JOSENotSupported('unsupported "kty" (Key Type) Parameter value'); + } +} +export { parseJwk }; +export default parseJwk; diff --git a/dist/browser/jwk/thumbprint.js b/dist/browser/jwk/thumbprint.js new file mode 100644 index 0000000000..ffb569b31f --- /dev/null +++ b/dist/browser/jwk/thumbprint.js @@ -0,0 +1,44 @@ +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 isObject from '../lib/is_object.js'; +const check = (value, description) => { + if (typeof value !== 'string' || !value) { + throw new JWKInvalid(`${description} missing or invalid`); + } +}; +async function calculateThumbprint(jwk, digestAlgorithm = 'sha256') { + if (!isObject(jwk)) { + throw new TypeError('JWK must be an object'); + } + let components; + 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 { calculateThumbprint }; +export default calculateThumbprint; diff --git a/dist/browser/jwks/remote.js b/dist/browser/jwks/remote.js new file mode 100644 index 0000000000..7665477163 --- /dev/null +++ b/dist/browser/jwks/remote.js @@ -0,0 +1,130 @@ +import parseJWK from '../jwk/parse.js'; +import { JWKSInvalid, JOSENotSupported, JWKSNoMatchingKey, JWKSMultipleMatchingKeys, } from '../util/errors.js'; +import fetchJwks from '../runtime/fetch_jwks.js'; +import isObject from '../lib/is_object.js'; +function getKtyFromAlg(alg) { + 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'); + } +} +function isJWKLike(key) { + return isObject(key); +} +class RemoteJWKSet { + constructor(url, options) { + this._cached = new WeakMap(); + if (!(url instanceof URL)) { + throw new TypeError('url must be an instance of URL'); + } + this._url = new URL(url.href); + this._options = { agent: options === null || options === void 0 ? void 0 : options.agent }; + this._timeoutDuration = + typeof (options === null || options === void 0 ? void 0 : options.timeoutDuration) === 'number' ? options === null || options === void 0 ? void 0 : options.timeoutDuration : 5000; + this._cooldownDuration = + typeof (options === null || options === void 0 ? void 0 : options.cooldownDuration) === 'number' ? options === null || options === void 0 ? void 0 : options.cooldownDuration : 30000; + } + coolingDown() { + if (typeof this._cooldownStarted === 'undefined') { + return false; + } + return Date.now() < this._cooldownStarted + this._cooldownDuration; + } + async getKey(protectedHeader) { + if (!this._jwks) { + await this.reload(); + } + const candidates = this._jwks.keys.filter((jwk) => { + let candidate = jwk.kty === getKtyFromAlg(protectedHeader.alg); + if (candidate && typeof protectedHeader.kid === 'string') { + candidate = protectedHeader.kid === jwk.kid; + } + if (candidate && typeof jwk.alg === 'string') { + candidate = protectedHeader.alg === jwk.alg; + } + if (candidate && typeof jwk.use === 'string') { + candidate = jwk.use === 'sig'; + } + if (candidate && Array.isArray(jwk.key_ops)) { + candidate = jwk.key_ops.includes('verify'); + } + if (candidate && protectedHeader.alg === 'EdDSA') { + candidate = ['Ed25519', 'Ed448'].includes(jwk.crv); + } + 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 (cached[protectedHeader.alg] === undefined) { + const keyObject = await parseJWK({ ...jwk, alg: protectedHeader.alg }); + 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 = fetchJwks(this._url, this._timeoutDuration, this._options) + .then((json) => { + if (typeof json !== 'object' || + !json || + !Array.isArray(json.keys) || + !json.keys.every(isJWKLike)) { + throw new JWKSInvalid('JSON Web Key Set malformed'); + } + this._jwks = { keys: json.keys }; + this._cooldownStarted = Date.now(); + this._pendingFetch = undefined; + }) + .catch((err) => { + this._pendingFetch = undefined; + throw err; + }); + } + await this._pendingFetch; + } +} +function createRemoteJWKSet(url, options) { + return RemoteJWKSet.prototype.getKey.bind(new RemoteJWKSet(url, options)); +} +export { createRemoteJWKSet }; +export default createRemoteJWKSet; diff --git a/dist/browser/jws/compact/sign.js b/dist/browser/jws/compact/sign.js new file mode 100644 index 0000000000..5bacca34d9 --- /dev/null +++ b/dist/browser/jws/compact/sign.js @@ -0,0 +1,19 @@ +import FlattenedSign from '../flattened/sign.js'; +class CompactSign { + constructor(payload) { + this._flattened = new FlattenedSign(payload); + } + setProtectedHeader(protectedHeader) { + this._flattened.setProtectedHeader(protectedHeader); + return this; + } + async sign(key, options) { + const jws = await this._flattened.sign(key, options); + 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 { CompactSign }; +export default CompactSign; diff --git a/dist/browser/jws/compact/verify.js b/dist/browser/jws/compact/verify.js new file mode 100644 index 0000000000..aad640718b --- /dev/null +++ b/dist/browser/jws/compact/verify.js @@ -0,0 +1,23 @@ +import verify from '../flattened/verify.js'; +import { JWSInvalid } from '../../util/errors.js'; +import { decoder } from '../../lib/buffer_utils.js'; +async function compactVerify(jws, key, options) { + if (jws instanceof Uint8Array) { + jws = decoder.decode(jws); + } + if (typeof jws !== 'string') { + throw new JWSInvalid('Compact JWS must be a string or Uint8Array'); + } + const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split('.'); + if (length !== 3) { + throw new JWSInvalid('Invalid Compact JWS'); + } + const verified = await verify({ + payload: (payload || undefined), + protected: protectedHeader || undefined, + signature: (signature || undefined), + }, key, options); + return { payload: verified.payload, protectedHeader: verified.protectedHeader }; +} +export { compactVerify }; +export default compactVerify; diff --git a/dist/browser/jws/flattened/sign.js b/dist/browser/jws/flattened/sign.js new file mode 100644 index 0000000000..a9ec0aec95 --- /dev/null +++ b/dist/browser/jws/flattened/sign.js @@ -0,0 +1,84 @@ +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 checkKeyType from '../../lib/check_key_type.js'; +import validateCrit from '../../lib/validate_crit.js'; +const checkExtensions = validateCrit.bind(undefined, JWSInvalid, new Map([['b64', true]])); +class FlattenedSign { + constructor(payload) { + if (!(payload instanceof Uint8Array)) { + throw new TypeError('payload must be an instance of Uint8Array'); + } + this._payload = payload; + } + setProtectedHeader(protectedHeader) { + if (this._protectedHeader) { + throw new TypeError('setProtectedHeader can only be called once'); + } + this._protectedHeader = protectedHeader; + return this; + } + setUnprotectedHeader(unprotectedHeader) { + if (this._unprotectedHeader) { + throw new TypeError('setUnprotectedHeader can only be called once'); + } + this._unprotectedHeader = unprotectedHeader; + return this; + } + async sign(key, options) { + 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 = { + ...this._protectedHeader, + ...this._unprotectedHeader, + }; + const extensions = checkExtensions(options === null || options === void 0 ? void 0 : options.crit, this._protectedHeader, joseHeader); + let b64 = 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 (typeof alg !== 'string' || !alg) { + throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid'); + } + checkKeyType(alg, key, 'sign'); + let payload = this._payload; + if (b64) { + payload = encoder.encode(base64url(payload)); + } + let protectedHeader; + 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 = { + signature: base64url(signature), + payload: '', + }; + 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 { FlattenedSign }; +export default FlattenedSign; diff --git a/dist/browser/jws/flattened/verify.js b/dist/browser/jws/flattened/verify.js new file mode 100644 index 0000000000..61652d26b6 --- /dev/null +++ b/dist/browser/jws/flattened/verify.js @@ -0,0 +1,103 @@ +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'; +const checkExtensions = validateCrit.bind(undefined, JWSInvalid, new Map([['b64', true]])); +const checkAlgOption = validateAlgorithms.bind(undefined, 'algorithms'); +async function flattenedVerify(jws, key, options) { + var _a; + if (!isObject(jws)) { + throw new JWSInvalid('Flattened JWS must be an object'); + } + if (jws.protected === undefined && jws.header === undefined) { + throw new JWSInvalid('Flattened JWS must have either of the "protected" or "header" members'); + } + if (jws.protected !== undefined && typeof jws.protected !== 'string') { + throw new JWSInvalid('JWS Protected Header incorrect type'); + } + if (jws.payload === undefined) { + throw new JWSInvalid('JWS Payload missing'); + } + if (typeof jws.signature !== 'string') { + throw new JWSInvalid('JWS Signature missing or incorrect type'); + } + if (jws.header !== undefined && !isObject(jws.header)) { + throw new JWSInvalid('JWS Unprotected Header incorrect type'); + } + let parsedProt = {}; + if (jws.protected) { + const protectedHeader = base64url(jws.protected); + try { + parsedProt = JSON.parse(decoder.decode(protectedHeader)); + } + catch (_b) { + throw new JWSInvalid('JWS Protected Header is invalid'); + } + } + if (!isDisjoint(parsedProt, jws.header)) { + throw new JWSInvalid('JWS Protected and JWS Unprotected Header Parameter names must be disjoint'); + } + const joseHeader = { + ...parsedProt, + ...jws.header, + }; + const extensions = checkExtensions(options === null || options === void 0 ? void 0 : options.crit, parsedProt, joseHeader); + let b64 = 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 (typeof alg !== 'string' || !alg) { + throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid'); + } + 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') { + key = await key(parsedProt, jws); + } + checkKeyType(alg, key, 'verify'); + const data = concat(encoder.encode((_a = jws.protected) !== null && _a !== void 0 ? _a : ''), 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; + if (b64) { + payload = base64url(jws.payload); + } + else if (typeof jws.payload === 'string') { + payload = encoder.encode(jws.payload); + } + else { + payload = jws.payload; + } + const result = { payload }; + if (jws.protected !== undefined) { + result.protectedHeader = parsedProt; + } + if (jws.header !== undefined) { + result.unprotectedHeader = jws.header; + } + return result; +} +export { flattenedVerify }; +export default flattenedVerify; diff --git a/dist/browser/jws/general/sign.js b/dist/browser/jws/general/sign.js new file mode 100644 index 0000000000..7127accfa1 --- /dev/null +++ b/dist/browser/jws/general/sign.js @@ -0,0 +1,73 @@ +import FlattenedSign from '../flattened/sign.js'; +import { JWSInvalid } from '../../util/errors.js'; +const signatureRef = new WeakMap(); +class IndividualSignature { + setProtectedHeader(protectedHeader) { + if (this._protectedHeader) { + throw new TypeError('setProtectedHeader can only be called once'); + } + this._protectedHeader = protectedHeader; + return this; + } + setUnprotectedHeader(unprotectedHeader) { + if (this._unprotectedHeader) { + throw new TypeError('setUnprotectedHeader can only be called once'); + } + this._unprotectedHeader = unprotectedHeader; + return this; + } + set _protectedHeader(value) { + signatureRef.get(this).protectedHeader = value; + } + get _protectedHeader() { + return signatureRef.get(this).protectedHeader; + } + set _unprotectedHeader(value) { + signatureRef.get(this).unprotectedHeader = value; + } + get _unprotectedHeader() { + return signatureRef.get(this).unprotectedHeader; + } +} +class GeneralSign { + constructor(payload) { + this._signatures = []; + this._payload = payload; + } + addSignature(key, options) { + const signature = new IndividualSignature(); + signatureRef.set(signature, { key, options }); + this._signatures.push(signature); + return signature; + } + async sign() { + if (!this._signatures.length) { + throw new JWSInvalid('at least one signature must be added'); + } + const jws = { + signatures: [], + payload: '', + }; + let payloads = new Set(); + await Promise.all(this._signatures.map(async (sig) => { + const { protectedHeader, unprotectedHeader, options, key } = signatureRef.get(sig); + const flattened = new FlattenedSign(this._payload); + if (protectedHeader) { + flattened.setProtectedHeader(protectedHeader); + } + if (unprotectedHeader) { + flattened.setUnprotectedHeader(unprotectedHeader); + } + const { payload, ...rest } = await flattened.sign(key, options); + payloads.add(payload); + jws.payload = payload; + jws.signatures.push(rest); + })); + if (payloads.size !== 1) { + throw new JWSInvalid('inconsistent use of JWS Unencoded Payload Option (RFC7797)'); + } + return jws; + } +} +export { GeneralSign }; +export default GeneralSign; diff --git a/dist/browser/jws/general/verify.js b/dist/browser/jws/general/verify.js new file mode 100644 index 0000000000..e44ae2e50b --- /dev/null +++ b/dist/browser/jws/general/verify.js @@ -0,0 +1,26 @@ +import verify from '../flattened/verify.js'; +import { JWSInvalid, JWSSignatureVerificationFailed } from '../../util/errors.js'; +import isObject from '../../lib/is_object.js'; +async function generalVerify(jws, key, options) { + if (!isObject(jws)) { + throw new JWSInvalid('General JWS must be an object'); + } + if (!Array.isArray(jws.signatures) || !jws.signatures.every(isObject)) { + throw new JWSInvalid('JWS Signatures missing or incorrect type'); + } + for (const signature of jws.signatures) { + try { + return await verify({ + header: signature.header, + payload: jws.payload, + protected: signature.protected, + signature: signature.signature, + }, key, options); + } + catch (_a) { + } + } + throw new JWSSignatureVerificationFailed(); +} +export { generalVerify }; +export default generalVerify; diff --git a/dist/browser/jwt/decrypt.js b/dist/browser/jwt/decrypt.js new file mode 100644 index 0000000000..ed1b4286c5 --- /dev/null +++ b/dist/browser/jwt/decrypt.js @@ -0,0 +1,21 @@ +import decrypt from '../jwe/compact/decrypt.js'; +import jwtPayload from '../lib/jwt_claims_set.js'; +import { JWTClaimValidationFailed } from '../util/errors.js'; +async function jwtDecrypt(jwt, key, options) { + const decrypted = await decrypt(jwt, key, options); + const payload = jwtPayload(decrypted.protectedHeader, decrypted.plaintext, options); + const { protectedHeader } = decrypted; + if (protectedHeader.iss !== undefined && protectedHeader.iss !== payload.iss) { + throw new JWTClaimValidationFailed('replicated "iss" claim header parameter mismatch', 'iss', 'mismatch'); + } + if (protectedHeader.sub !== undefined && protectedHeader.sub !== payload.sub) { + throw new JWTClaimValidationFailed('replicated "sub" claim header parameter mismatch', 'sub', 'mismatch'); + } + if (protectedHeader.aud !== undefined && + JSON.stringify(protectedHeader.aud) !== JSON.stringify(payload.aud)) { + throw new JWTClaimValidationFailed('replicated "aud" claim header parameter mismatch', 'aud', 'mismatch'); + } + return { payload, protectedHeader }; +} +export { jwtDecrypt }; +export default jwtDecrypt; diff --git a/dist/browser/jwt/encrypt.js b/dist/browser/jwt/encrypt.js new file mode 100644 index 0000000000..ef8ac9156f --- /dev/null +++ b/dist/browser/jwt/encrypt.js @@ -0,0 +1,70 @@ +import CompactEncrypt from '../jwe/compact/encrypt.js'; +import { encoder } from '../lib/buffer_utils.js'; +import ProduceJWT from '../lib/jwt_producer.js'; +class EncryptJWT extends ProduceJWT { + setProtectedHeader(protectedHeader) { + if (this._protectedHeader) { + throw new TypeError('setProtectedHeader can only be called once'); + } + this._protectedHeader = protectedHeader; + return this; + } + setKeyManagementParameters(parameters) { + if (this._keyManagementParameters) { + throw new TypeError('setKeyManagementParameters can only be called once'); + } + this._keyManagementParameters = parameters; + return this; + } + setContentEncryptionKey(cek) { + if (this._cek) { + throw new TypeError('setContentEncryptionKey can only be called once'); + } + this._cek = cek; + return this; + } + setInitializationVector(iv) { + if (this._iv) { + throw new TypeError('setInitializationVector can only be called once'); + } + this._iv = iv; + return this; + } + replicateIssuerAsHeader() { + this._replicateIssuerAsHeader = true; + return this; + } + replicateSubjectAsHeader() { + this._replicateSubjectAsHeader = true; + return this; + } + replicateAudienceAsHeader() { + this._replicateAudienceAsHeader = true; + return this; + } + async encrypt(key, options) { + 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 { EncryptJWT }; +export default EncryptJWT; diff --git a/dist/browser/jwt/sign.js b/dist/browser/jwt/sign.js new file mode 100644 index 0000000000..0707f7ebf7 --- /dev/null +++ b/dist/browser/jwt/sign.js @@ -0,0 +1,23 @@ +import CompactSign from '../jws/compact/sign.js'; +import { JWTInvalid } from '../util/errors.js'; +import { encoder } from '../lib/buffer_utils.js'; +import ProduceJWT from '../lib/jwt_producer.js'; +class SignJWT extends ProduceJWT { + setProtectedHeader(protectedHeader) { + this._protectedHeader = protectedHeader; + return this; + } + async sign(key, options) { + var _a; + const sig = new CompactSign(encoder.encode(JSON.stringify(this._payload))); + sig.setProtectedHeader(this._protectedHeader); + if (Array.isArray((_a = this._protectedHeader) === null || _a === void 0 ? void 0 : _a.crit) && + this._protectedHeader.crit.includes('b64') && + this._protectedHeader.b64 === false) { + throw new JWTInvalid('JWTs MUST NOT use unencoded payload'); + } + return sig.sign(key, options); + } +} +export { SignJWT }; +export default SignJWT; diff --git a/dist/browser/jwt/unsecured.js b/dist/browser/jwt/unsecured.js new file mode 100644 index 0000000000..e7fa0535e5 --- /dev/null +++ b/dist/browser/jwt/unsecured.js @@ -0,0 +1,34 @@ +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'; +class UnsecuredJWT extends ProduceJWT { + encode() { + const header = base64url.encode(JSON.stringify({ alg: 'none' })); + const payload = base64url.encode(JSON.stringify(this._payload)); + return `${header}.${payload}.`; + } + static decode(jwt, options) { + 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; + try { + header = JSON.parse(decoder.decode(base64url.decode(encodedHeader))); + if (header.alg !== 'none') + throw new Error(); + } + catch (_a) { + throw new JWTInvalid('Invalid Unsecured JWT'); + } + const payload = jwtPayload(header, base64url.decode(encodedPayload), options); + return { payload, header }; + } +} +export { UnsecuredJWT }; +export default UnsecuredJWT; diff --git a/dist/browser/jwt/verify.js b/dist/browser/jwt/verify.js new file mode 100644 index 0000000000..2295d81306 --- /dev/null +++ b/dist/browser/jwt/verify.js @@ -0,0 +1,14 @@ +import verify from '../jws/compact/verify.js'; +import jwtPayload from '../lib/jwt_claims_set.js'; +import { JWTInvalid } from '../util/errors.js'; +async function jwtVerify(jwt, key, options) { + var _a; + const verified = await verify(jwt, key, options); + if (((_a = verified.protectedHeader.crit) === null || _a === void 0 ? void 0 : _a.includes('b64')) && verified.protectedHeader.b64 === false) { + throw new JWTInvalid('JWTs MUST NOT use unencoded payload'); + } + const payload = jwtPayload(verified.protectedHeader, verified.payload, options); + return { payload, protectedHeader: verified.protectedHeader }; +} +export { jwtVerify }; +export default jwtVerify; diff --git a/dist/browser/lib/buffer_utils.js b/dist/browser/lib/buffer_utils.js new file mode 100644 index 0000000000..d9392a633d --- /dev/null +++ b/dist/browser/lib/buffer_utils.js @@ -0,0 +1,56 @@ +export const encoder = new TextEncoder(); +export const decoder = new TextDecoder(); +const MAX_INT32 = 2 ** 32; +export function concat(...buffers) { + 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, p2sInput) { + return concat(encoder.encode(alg), new Uint8Array([0]), p2sInput); +} +function writeUInt32BE(buf, value, offset) { + 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) { + 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) { + const buf = new Uint8Array(4); + writeUInt32BE(buf, value); + return buf; +} +export function lengthAndInput(input) { + return concat(uint32be(input.length), input); +} +export async function concatKdf(digest, secret, bits, value) { + const iterations = Math.ceil((bits >> 3) / 32); + let res; + 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('sha256', buf); + } + else { + res = concat(res, await digest('sha256', buf)); + } + } + res = res.slice(0, bits >> 3); + return res; +} diff --git a/dist/browser/lib/cek.js b/dist/browser/lib/cek.js new file mode 100644 index 0000000000..702d8a0533 --- /dev/null +++ b/dist/browser/lib/cek.js @@ -0,0 +1,18 @@ +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) => (alg) => { + 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/dist/browser/lib/check_iv_length.js b/dist/browser/lib/check_iv_length.js new file mode 100644 index 0000000000..3bb1ecb38a --- /dev/null +++ b/dist/browser/lib/check_iv_length.js @@ -0,0 +1,8 @@ +import { JWEInvalid } from '../util/errors.js'; +import { bitLengths } from './iv.js'; +const checkIvLength = (enc, iv) => { + if (iv.length << 3 !== bitLengths.get(enc)) { + throw new JWEInvalid('Invalid Initialization Vector length'); + } +}; +export default checkIvLength; diff --git a/dist/browser/lib/check_key_type.js b/dist/browser/lib/check_key_type.js new file mode 100644 index 0000000000..4702e55436 --- /dev/null +++ b/dist/browser/lib/check_key_type.js @@ -0,0 +1,28 @@ +import invalidKeyInput from '../runtime/invalid_key_input.js'; +const checkKeyType = (alg, key, usage) => { + if (!(key instanceof Uint8Array) && !(key === null || key === void 0 ? void 0 : key.type)) { + throw new TypeError(invalidKeyInput(key, 'KeyObject', 'CryptoKey', 'Uint8Array')); + } + 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(invalidKeyInput(key, 'KeyObject', 'CryptoKey')); + } + if (key.type === 'secret') { + throw new TypeError('CryptoKey or KeyObject instances for asymmetric algorithms must not be of type "secret"'); + } + if (usage === 'sign' && key.type === 'public') { + throw new TypeError('CryptoKey or KeyObject instances for asymmetric algorithm signing must be of type "private"'); + } + if (usage === 'decrypt' && key.type === 'public') { + throw new TypeError('CryptoKey or KeyObject instances for asymmetric algorithm decryption must be of type "private"'); + } +}; +export default checkKeyType; diff --git a/dist/browser/lib/check_p2s.js b/dist/browser/lib/check_p2s.js new file mode 100644 index 0000000000..a65289fa7a --- /dev/null +++ b/dist/browser/lib/check_p2s.js @@ -0,0 +1,6 @@ +import { JWEInvalid } from '../util/errors.js'; +export default function checkP2s(p2s) { + if (!(p2s instanceof Uint8Array) || p2s.length < 8) { + throw new JWEInvalid('PBES2 Salt Input must be 8 or more octets'); + } +} diff --git a/dist/browser/lib/decrypt_key_management.js b/dist/browser/lib/decrypt_key_management.js new file mode 100644 index 0000000000..d82f5c100f --- /dev/null +++ b/dist/browser/lib/decrypt_key_management.js @@ -0,0 +1,95 @@ +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'; +import { parseJwk } from '../jwk/parse.js'; +import checkKeyType from './check_key_type.js'; +function assertEnryptedKey(encryptedKey) { + if (!encryptedKey) { + throw new JWEInvalid('JWE Encrypted Key missing'); + } +} +function assertHeaderParameter(joseHeader, parameter, name) { + if (joseHeader[parameter] === undefined) { + throw new JWEInvalid(`JOSE Header ${name} (${parameter}) missing`); + } +} +async function decryptKeyManagement(alg, key, encryptedKey, joseHeader) { + checkKeyType(alg, key, 'decrypt'); + switch (alg) { + case 'dir': { + if (encryptedKey !== undefined) { + throw new JWEInvalid('Encountered unexpected JWE Encrypted Key'); + } + return key; + } + case 'ECDH-ES': + if (encryptedKey !== undefined) { + throw new JWEInvalid('Encountered unexpected JWE Encrypted Key'); + } + case 'ECDH-ES+A128KW': + case 'ECDH-ES+A192KW': + case 'ECDH-ES+A256KW': { + assertHeaderParameter(joseHeader, 'epk', 'Ephemeral Public Key'); + if (!ECDH.ecdhAllowed(key)) { + throw new JOSENotSupported('ECDH-ES with the provided key is not allowed or not supported by your javascript runtime'); + } + const epk = await parseJwk(joseHeader.epk, alg); + let partyUInfo; + let partyVInfo; + if (joseHeader.apu !== undefined) + partyUInfo = base64url(joseHeader.apu); + if (joseHeader.apv !== undefined) + partyVInfo = base64url(joseHeader.apv); + const sharedSecret = await ECDH.deriveKey(epk, key, alg === 'ECDH-ES' ? joseHeader.enc : alg, parseInt(alg.substr(-5, 3), 10) || cekLengths.get(joseHeader.enc), partyUInfo, partyVInfo); + if (alg === 'ECDH-ES') { + return sharedSecret; + } + 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': { + assertEnryptedKey(encryptedKey); + return rsaEs(alg, key, encryptedKey); + } + case 'PBES2-HS256+A128KW': + case 'PBES2-HS384+A192KW': + case 'PBES2-HS512+A256KW': { + 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': { + assertEnryptedKey(encryptedKey); + return aesKw(alg, key, encryptedKey); + } + case 'A128GCMKW': + case 'A192GCMKW': + case 'A256GCMKW': { + 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('unsupported or invalid "alg" (JWE Algorithm) header value'); + } + } +} +export default decryptKeyManagement; diff --git a/dist/browser/lib/encrypt_key_management.js b/dist/browser/lib/encrypt_key_management.js new file mode 100644 index 0000000000..97199e204e --- /dev/null +++ b/dist/browser/lib/encrypt_key_management.js @@ -0,0 +1,87 @@ +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'; +import { fromKeyLike } from '../jwk/from_key_like.js'; +import checkKeyType from './check_key_type.js'; +const generateCek = cekFactory(random); +async function encryptKeyManagement(alg, enc, key, providedCek, providedParameters = {}) { + let encryptedKey; + let parameters; + let cek; + checkKeyType(alg, key, 'encrypt'); + switch (alg) { + case 'dir': { + cek = key; + break; + } + case 'ECDH-ES': + case 'ECDH-ES+A128KW': + case 'ECDH-ES+A192KW': + case 'ECDH-ES+A256KW': { + if (!ECDH.ecdhAllowed(key)) { + throw new JOSENotSupported('ECDH-ES with the provided key is not allowed or not supported by your javascript runtime'); + } + const { apu, apv } = providedParameters; + let { epk: ephemeralKey } = providedParameters; + ephemeralKey || (ephemeralKey = await ECDH.generateEpk(key)); + const { x, y, crv, kty } = await fromKeyLike(ephemeralKey); + const sharedSecret = await ECDH.deriveKey(key, ephemeralKey, alg === 'ECDH-ES' ? enc : alg, parseInt(alg.substr(-5, 3), 10) || cekLengths.get(enc), apu, apv); + parameters = { epk: { x, y, crv, kty } }; + if (apu) + parameters.apu = base64url(apu); + if (apv) + parameters.apv = base64url(apv); + if (alg === 'ECDH-ES') { + cek = sharedSecret; + break; + } + cek = providedCek || 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': { + cek = providedCek || generateCek(enc); + encryptedKey = await rsaEs(alg, key, cek); + break; + } + case 'PBES2-HS256+A128KW': + case 'PBES2-HS384+A192KW': + case 'PBES2-HS512+A256KW': { + cek = providedCek || generateCek(enc); + const { p2c, p2s } = providedParameters; + ({ encryptedKey, ...parameters } = await pbes2Kw(alg, key, cek, p2c, p2s)); + break; + } + case 'A128KW': + case 'A192KW': + case 'A256KW': { + cek = providedCek || generateCek(enc); + encryptedKey = await aesKw(alg, key, cek); + break; + } + case 'A128GCMKW': + case 'A192GCMKW': + case 'A256GCMKW': { + cek = providedCek || generateCek(enc); + const { iv } = providedParameters; + ({ encryptedKey, ...parameters } = await aesGcmKw(alg, key, cek, iv)); + break; + } + default: { + throw new JOSENotSupported('unsupported or invalid "alg" (JWE Algorithm) header value'); + } + } + return { cek, encryptedKey, parameters }; +} +export default encryptKeyManagement; diff --git a/dist/browser/lib/epoch.js b/dist/browser/lib/epoch.js new file mode 100644 index 0000000000..e405e4b2df --- /dev/null +++ b/dist/browser/lib/epoch.js @@ -0,0 +1 @@ +export default (date) => Math.floor(date.getTime() / 1000); diff --git a/dist/browser/lib/is_disjoint.js b/dist/browser/lib/is_disjoint.js new file mode 100644 index 0000000000..6f643502dc --- /dev/null +++ b/dist/browser/lib/is_disjoint.js @@ -0,0 +1,22 @@ +const isDisjoint = (...headers) => { + const sources = headers.filter(Boolean); + if (sources.length === 0 || sources.length === 1) { + return true; + } + let acc; + 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/dist/browser/lib/is_object.js b/dist/browser/lib/is_object.js new file mode 100644 index 0000000000..4955e93225 --- /dev/null +++ b/dist/browser/lib/is_object.js @@ -0,0 +1,16 @@ +function isObjectLike(value) { + return typeof value === 'object' && value !== null; +} +export default function isObject(input) { + if (!isObjectLike(input) || Object.prototype.toString.call(input) !== '[object Object]') { + return false; + } + if (Object.getPrototypeOf(input) === null) { + return true; + } + let proto = input; + while (Object.getPrototypeOf(proto) !== null) { + proto = Object.getPrototypeOf(proto); + } + return Object.getPrototypeOf(input) === proto; +} diff --git a/dist/browser/lib/iv.js b/dist/browser/lib/iv.js new file mode 100644 index 0000000000..d254aa16dc --- /dev/null +++ b/dist/browser/lib/iv.js @@ -0,0 +1,21 @@ +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) => (alg) => { + 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/dist/browser/lib/jwt_claims_set.js b/dist/browser/lib/jwt_claims_set.js new file mode 100644 index 0000000000..90b30a4e98 --- /dev/null +++ b/dist/browser/lib/jwt_claims_set.js @@ -0,0 +1,96 @@ +import { JWTClaimValidationFailed, JWTExpired, JWTInvalid } from '../util/errors.js'; +import { decoder } from './buffer_utils.js'; +import epoch from './epoch.js'; +import secs from './secs.js'; +import isObject from './is_object.js'; +const normalizeTyp = (value) => value.toLowerCase().replace(/^application\//, ''); +const checkAudiencePresence = (audPayload, audOption) => { + if (typeof audPayload === 'string') { + return audOption.includes(audPayload); + } + if (Array.isArray(audPayload)) { + return audOption.some(Set.prototype.has.bind(new Set(audPayload))); + } + return false; +}; +export default (protectedHeader, encodedPayload, options = {}) => { + 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; + try { + payload = JSON.parse(decoder.decode(encodedPayload)); + } + catch (_a) { + } + if (!isObject(payload)) { + throw new JWTInvalid('JWT Claims Set must be a top-level JSON object'); + } + const { issuer } = options; + if (issuer && !(Array.isArray(issuer) ? 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; + 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 (payload.iat !== undefined || options.maxTokenAge) { + if (typeof payload.iat !== 'number') { + throw new JWTClaimValidationFailed('"iat" claim must be a number', 'iat', 'invalid'); + } + if (payload.exp === undefined && payload.iat > now + tolerance) { + throw new JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', 'iat', 'check_failed'); + } + } + if (payload.nbf !== undefined) { + 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 (payload.exp !== undefined) { + 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/dist/browser/lib/jwt_producer.js b/dist/browser/lib/jwt_producer.js new file mode 100644 index 0000000000..e6b047337c --- /dev/null +++ b/dist/browser/lib/jwt_producer.js @@ -0,0 +1,54 @@ +import epoch from './epoch.js'; +import isObject from './is_object.js'; +import secs from './secs.js'; +export default class ProduceJWT { + constructor(payload) { + if (!isObject(payload)) { + throw new TypeError('JWT Claims Set MUST be an object'); + } + this._payload = payload; + } + setIssuer(issuer) { + this._payload = { ...this._payload, iss: issuer }; + return this; + } + setSubject(subject) { + this._payload = { ...this._payload, sub: subject }; + return this; + } + setAudience(audience) { + this._payload = { ...this._payload, aud: audience }; + return this; + } + setJti(jwtId) { + this._payload = { ...this._payload, jti: jwtId }; + return this; + } + setNotBefore(input) { + if (typeof input === 'number') { + this._payload = { ...this._payload, nbf: input }; + } + else { + this._payload = { ...this._payload, nbf: epoch(new Date()) + secs(input) }; + } + return this; + } + setExpirationTime(input) { + if (typeof input === 'number') { + this._payload = { ...this._payload, exp: input }; + } + else { + this._payload = { ...this._payload, exp: epoch(new Date()) + secs(input) }; + } + return this; + } + setIssuedAt(input) { + if (typeof input === 'undefined') { + this._payload = { ...this._payload, iat: epoch(new Date()) }; + } + else { + this._payload = { ...this._payload, iat: input }; + } + return this; + } +} diff --git a/dist/browser/lib/secs.js b/dist/browser/lib/secs.js new file mode 100644 index 0000000000..cf470ed8ad --- /dev/null +++ b/dist/browser/lib/secs.js @@ -0,0 +1,44 @@ +const minute = 60; +const hour = minute * 60; +const day = hour * 24; +const week = day * 7; +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; +export default (str) => { + const matched = REGEX.exec(str); + if (!matched) { + throw new TypeError('Invalid time period format'); + } + const value = parseFloat(matched[1]); + const unit = matched[2].toLowerCase(); + switch (unit) { + case 'sec': + case 'secs': + case 'second': + case 'seconds': + case 's': + return Math.round(value); + case 'minute': + case 'minutes': + case 'min': + case 'mins': + case 'm': + return Math.round(value * minute); + case 'hour': + case 'hours': + case 'hr': + case 'hrs': + case 'h': + return Math.round(value * hour); + case 'day': + case 'days': + case 'd': + return Math.round(value * day); + case 'week': + case 'weeks': + case 'w': + return Math.round(value * week); + default: + return Math.round(value * year); + } +}; diff --git a/dist/browser/lib/validate_algorithms.js b/dist/browser/lib/validate_algorithms.js new file mode 100644 index 0000000000..a6a7918571 --- /dev/null +++ b/dist/browser/lib/validate_algorithms.js @@ -0,0 +1,11 @@ +const validateAlgorithms = (option, algorithms) => { + 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/dist/browser/lib/validate_crit.js b/dist/browser/lib/validate_crit.js new file mode 100644 index 0000000000..68c69f18f5 --- /dev/null +++ b/dist/browser/lib/validate_crit.js @@ -0,0 +1,34 @@ +import { JOSENotSupported } from '../util/errors.js'; +function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) { + if (joseHeader.crit !== undefined && protectedHeader.crit === undefined) { + throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected'); + } + if (!protectedHeader || protectedHeader.crit === undefined) { + return new Set(); + } + if (!Array.isArray(protectedHeader.crit) || + protectedHeader.crit.length === 0 || + protectedHeader.crit.some((input) => typeof input !== 'string' || input.length === 0)) { + throw new Err('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present'); + } + let recognized; + if (recognizedOption !== undefined) { + recognized = new Map([...Object.entries(recognizedOption), ...recognizedDefault.entries()]); + } + else { + recognized = recognizedDefault; + } + for (const parameter of protectedHeader.crit) { + if (!recognized.has(parameter)) { + throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`); + } + if (joseHeader[parameter] === undefined) { + throw new Err(`Extension Header Parameter "${parameter}" is missing`); + } + else if (recognized.get(parameter) && protectedHeader[parameter] === undefined) { + throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`); + } + } + return new Set(protectedHeader.crit); +} +export default validateCrit; diff --git a/dist/browser/package.json b/dist/browser/package.json new file mode 100644 index 0000000000..6990891ff3 --- /dev/null +++ b/dist/browser/package.json @@ -0,0 +1 @@ +{"type": "module"} diff --git a/dist/browser/runtime/aesgcmkw.js b/dist/browser/runtime/aesgcmkw.js new file mode 100644 index 0000000000..5fd5acc5b2 --- /dev/null +++ b/dist/browser/runtime/aesgcmkw.js @@ -0,0 +1,16 @@ +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 = async (alg, key, cek, iv) => { + const jweAlgorithm = alg.substr(0, 7); + iv || (iv = generateIv(jweAlgorithm)); + const { ciphertext: encryptedKey, tag } = await encrypt(jweAlgorithm, cek, key, iv, new Uint8Array(0)); + return { encryptedKey, iv: base64url(iv), tag: base64url(tag) }; +}; +export const unwrap = async (alg, key, encryptedKey, iv, tag) => { + const jweAlgorithm = alg.substr(0, 7); + return decrypt(jweAlgorithm, key, encryptedKey, iv, tag, new Uint8Array(0)); +}; diff --git a/dist/browser/runtime/aeskw.js b/dist/browser/runtime/aeskw.js new file mode 100644 index 0000000000..30a88f1999 --- /dev/null +++ b/dist/browser/runtime/aeskw.js @@ -0,0 +1,29 @@ +import bogusWebCrypto from './bogus.js'; +import crypto, { isCryptoKey } from './webcrypto.js'; +import invalidKeyInput from './invalid_key_input.js'; +function checkKeySize(key, alg) { + if (key.algorithm.length !== parseInt(alg.substr(1, 3), 10)) { + throw new TypeError(`invalid key size for alg: ${alg}`); + } +} +function getCryptoKey(key, usage) { + if (isCryptoKey(key)) { + return key; + } + if (key instanceof Uint8Array) { + return crypto.subtle.importKey('raw', key, 'AES-KW', true, [usage]); + } + throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'Uint8Array')); +} +export const wrap = async (alg, key, cek) => { + const cryptoKey = await getCryptoKey(key, 'wrapKey'); + checkKeySize(cryptoKey, alg); + const cryptoKeyCek = await crypto.subtle.importKey('raw', cek, ...bogusWebCrypto); + return new Uint8Array(await crypto.subtle.wrapKey('raw', cryptoKeyCek, cryptoKey, 'AES-KW')); +}; +export const unwrap = async (alg, key, encryptedKey) => { + const cryptoKey = await getCryptoKey(key, 'unwrapKey'); + 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/dist/browser/runtime/base64url.js b/dist/browser/runtime/base64url.js new file mode 100644 index 0000000000..7b93f5cf31 --- /dev/null +++ b/dist/browser/runtime/base64url.js @@ -0,0 +1,31 @@ +import { encoder, decoder } from '../lib/buffer_utils.js'; +import globalThis from './global.js'; +export const encode = (input) => { + let unencoded = input; + if (typeof unencoded === 'string') { + unencoded = encoder.encode(unencoded); + } + const CHUNK_SIZE = 0x8000; + const arr = []; + for (let i = 0; i < unencoded.length; i += CHUNK_SIZE) { + arr.push(String.fromCharCode.apply(null, unencoded.subarray(i, i + CHUNK_SIZE))); + } + const base64string = globalThis.btoa(arr.join('')); + return base64string.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_'); +}; +export const decode = (input) => { + let encoded = input; + if (encoded instanceof Uint8Array) { + encoded = decoder.decode(encoded); + } + encoded = encoded.replace(/-/g, '+').replace(/_/g, '/').replace(/\s/g, ''); + try { + return new Uint8Array(globalThis + .atob(encoded) + .split('') + .map((c) => c.charCodeAt(0))); + } + catch (_a) { + throw new TypeError('The input to be decoded is not correctly encoded.'); + } +}; diff --git a/dist/browser/runtime/bogus.js b/dist/browser/runtime/bogus.js new file mode 100644 index 0000000000..79aa20214d --- /dev/null +++ b/dist/browser/runtime/bogus.js @@ -0,0 +1,6 @@ +const bogusWebCrypto = [ + { hash: { name: 'SHA-256' }, name: 'HMAC' }, + true, + ['sign'], +]; +export default bogusWebCrypto; diff --git a/dist/browser/runtime/check_cek_length.js b/dist/browser/runtime/check_cek_length.js new file mode 100644 index 0000000000..854c0e2f0b --- /dev/null +++ b/dist/browser/runtime/check_cek_length.js @@ -0,0 +1,37 @@ +import { JWEInvalid, JOSENotSupported } from '../util/errors.js'; +import { isCryptoKey } from './webcrypto.js'; +const checkCekLength = (enc, cek) => { + let expected; + 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 not supported 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 (isCryptoKey(cek)) { + const { length } = cek.algorithm; + if (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/dist/browser/runtime/check_key_length.js b/dist/browser/runtime/check_key_length.js new file mode 100644 index 0000000000..23146bfe2f --- /dev/null +++ b/dist/browser/runtime/check_key_length.js @@ -0,0 +1,15 @@ +export default (alg, key) => { + if (alg.startsWith('HS')) { + const bitlen = parseInt(alg.substr(-3), 10); + const { length } = key.algorithm; + if (typeof length !== 'number' || length < bitlen) { + throw new TypeError(`${alg} requires symmetric keys to be ${bitlen} bits or larger`); + } + } + if (alg.startsWith('RS') || alg.startsWith('PS')) { + const { modulusLength } = key.algorithm; + if (typeof modulusLength !== 'number' || modulusLength < 2048) { + throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`); + } + } +}; diff --git a/dist/browser/runtime/decrypt.js b/dist/browser/runtime/decrypt.js new file mode 100644 index 0000000000..941bfe7f1e --- /dev/null +++ b/dist/browser/runtime/decrypt.js @@ -0,0 +1,72 @@ +import { concat, uint64be } from '../lib/buffer_utils.js'; +import checkIvLength from '../lib/check_iv_length.js'; +import checkCekLength from './check_cek_length.js'; +import timingSafeEqual from './timing_safe_equal.js'; +import { JOSENotSupported, JWEDecryptionFailed } from '../util/errors.js'; +import crypto, { isCryptoKey } from './webcrypto.js'; +import invalidKeyInput from './invalid_key_input.js'; +async function cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) { + const keySize = parseInt(enc.substr(1, 3), 10); + const encKey = await crypto.subtle.importKey('raw', cek.subarray(keySize >> 3), 'AES-CBC', false, ['decrypt']); + const macKey = await crypto.subtle.importKey('raw', cek.subarray(0, keySize >> 3), { + hash: { name: `SHA-${keySize << 1}` }, + name: 'HMAC', + }, false, ['sign']); + 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; + try { + macCheckPassed = timingSafeEqual(tag, expectedTag); + } + catch (_a) { + } + if (!macCheckPassed) { + throw new JWEDecryptionFailed(); + } + let plaintext; + try { + plaintext = new Uint8Array(await crypto.subtle.decrypt({ iv, name: 'AES-CBC' }, encKey, ciphertext)); + } + catch (_b) { + } + if (!plaintext) { + throw new JWEDecryptionFailed(); + } + return plaintext; +} +async function gcmDecrypt(cek, ciphertext, iv, tag, aad) { + 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, concat(ciphertext, tag))); + } + catch (_a) { + throw new JWEDecryptionFailed(); + } +} +const decrypt = async (enc, cek, ciphertext, iv, tag, aad) => { + if (!isCryptoKey(cek) && !(cek instanceof Uint8Array)) { + throw new TypeError(invalidKeyInput(cek, 'CryptoKey', 'Uint8Array')); + } + checkCekLength(enc, cek); + checkIvLength(enc, iv); + switch (enc) { + case 'A128CBC-HS256': + case 'A192CBC-HS384': + case 'A256CBC-HS512': + return cbcDecrypt(enc, cek, ciphertext, iv, tag, aad); + case 'A128GCM': + case 'A192GCM': + case 'A256GCM': + return gcmDecrypt(cek, ciphertext, iv, tag, aad); + default: + throw new JOSENotSupported('unsupported JWE Content Encryption Algorithm'); + } +}; +export default decrypt; diff --git a/dist/browser/runtime/digest.js b/dist/browser/runtime/digest.js new file mode 100644 index 0000000000..31e03c53f1 --- /dev/null +++ b/dist/browser/runtime/digest.js @@ -0,0 +1,6 @@ +import crypto from './webcrypto.js'; +const digest = async (algorithm, data) => { + const subtleDigest = `SHA-${algorithm.substr(-3)}`; + return new Uint8Array(await crypto.subtle.digest(subtleDigest, data)); +}; +export default digest; diff --git a/dist/browser/runtime/ecdhes.js b/dist/browser/runtime/ecdhes.js new file mode 100644 index 0000000000..1b80f23060 --- /dev/null +++ b/dist/browser/runtime/ecdhes.js @@ -0,0 +1,34 @@ +import { encoder, concat, uint32be, lengthAndInput, concatKdf } from '../lib/buffer_utils.js'; +import crypto, { isCryptoKey } from './webcrypto.js'; +import digest from './digest.js'; +import invalidKeyInput from './invalid_key_input.js'; +export const deriveKey = async (publicKey, privateKey, algorithm, keyLength, apu = new Uint8Array(0), apv = new Uint8Array(0)) => { + if (!isCryptoKey(publicKey)) { + throw new TypeError(invalidKeyInput(publicKey, 'CryptoKey')); + } + if (!isCryptoKey(privateKey)) { + throw new TypeError(invalidKeyInput(privateKey, 'CryptoKey')); + } + 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.namedCurve.substr(-3), 10) / 8) << + 3)); + return concatKdf(digest, sharedSecret, keyLength, value); +}; +export const generateEpk = async (key) => { + if (!isCryptoKey(key)) { + throw new TypeError(invalidKeyInput(key, 'CryptoKey')); + } + return (await crypto.subtle.generateKey({ name: 'ECDH', namedCurve: key.algorithm.namedCurve }, true, ['deriveBits'])).privateKey; +}; +export const ecdhAllowed = (key) => { + if (!isCryptoKey(key)) { + throw new TypeError(invalidKeyInput(key, 'CryptoKey')); + } + return ['P-256', 'P-384', 'P-521'].includes(key.algorithm.namedCurve); +}; diff --git a/dist/browser/runtime/encrypt.js b/dist/browser/runtime/encrypt.js new file mode 100644 index 0000000000..0c3af6679e --- /dev/null +++ b/dist/browser/runtime/encrypt.js @@ -0,0 +1,55 @@ +import { concat, uint64be } from '../lib/buffer_utils.js'; +import checkIvLength from '../lib/check_iv_length.js'; +import checkCekLength from './check_cek_length.js'; +import crypto, { isCryptoKey } from './webcrypto.js'; +import invalidKeyInput from './invalid_key_input.js'; +import { JOSENotSupported } from '../util/errors.js'; +async function cbcEncrypt(enc, plaintext, cek, iv, aad) { + const keySize = parseInt(enc.substr(1, 3), 10); + const encKey = await crypto.subtle.importKey('raw', cek.subarray(keySize >> 3), 'AES-CBC', false, ['encrypt']); + const macKey = await crypto.subtle.importKey('raw', cek.subarray(0, keySize >> 3), { + hash: { name: `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, cek, iv, aad) { + 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 = async (enc, plaintext, cek, iv, aad) => { + if (!isCryptoKey(cek) && !(cek instanceof Uint8Array)) { + throw new TypeError(invalidKeyInput(cek, 'CryptoKey', 'Uint8Array')); + } + checkCekLength(enc, cek); + checkIvLength(enc, iv); + switch (enc) { + case 'A128CBC-HS256': + case 'A192CBC-HS384': + case 'A256CBC-HS512': + return cbcEncrypt(enc, plaintext, cek, iv, aad); + case 'A128GCM': + case 'A192GCM': + case 'A256GCM': + return gcmEncrypt(plaintext, cek, iv, aad); + default: + throw new JOSENotSupported('unsupported JWE Content Encryption Algorithm'); + } +}; +export default encrypt; diff --git a/dist/browser/runtime/fetch_jwks.js b/dist/browser/runtime/fetch_jwks.js new file mode 100644 index 0000000000..d4a49b2684 --- /dev/null +++ b/dist/browser/runtime/fetch_jwks.js @@ -0,0 +1,31 @@ +import { JOSEError } from '../util/errors.js'; +import globalThis from './global.js'; +const fetchJwks = async (url, timeout) => { + let controller; + if (typeof AbortController === 'function') { + controller = new AbortController(); + setTimeout(() => controller.abort(), timeout); + } + const response = await globalThis.fetch(url.href, { + signal: controller ? controller.signal : undefined, + redirect: 'manual', + method: 'GET', + ...(typeof globalThis.WebSocketPair === 'undefined' + ? { + referrerPolicy: 'no-referrer', + credentials: 'omit', + mode: 'cors', + } + : undefined), + }); + if (response.status !== 200) { + throw new JOSEError('Expected 200 OK from the JSON Web Key Set HTTP response'); + } + try { + return await response.json(); + } + catch (_a) { + throw new JOSEError('Failed to parse the JSON Web Key Set HTTP response as JSON'); + } +}; +export default fetchJwks; diff --git a/dist/browser/runtime/generate.js b/dist/browser/runtime/generate.js new file mode 100644 index 0000000000..196cf7f8aa --- /dev/null +++ b/dist/browser/runtime/generate.js @@ -0,0 +1,114 @@ +import crypto from './webcrypto.js'; +import { JOSENotSupported } from '../util/errors.js'; +import random from './random.js'; +export async function generateSecret(alg, options) { + var _a; + let length; + let algorithm; + let keyUsages; + switch (alg) { + case 'HS256': + case 'HS384': + case 'HS512': + length = parseInt(alg.substr(-3), 10); + algorithm = { name: 'HMAC', hash: { name: `SHA-${length}` }, 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, (_a = options === null || options === void 0 ? void 0 : options.extractable) !== null && _a !== void 0 ? _a : false, keyUsages); +} +function getModulusLengthOption(options) { + var _a; + const modulusLength = (_a = options === null || options === void 0 ? void 0 : options.modulusLength) !== null && _a !== void 0 ? _a : 2048; + if (typeof modulusLength !== 'number' || modulusLength < 2048) { + throw new JOSENotSupported('Invalid or unsupported modulusLength option provided, 2048 bits or larger keys must be used'); + } + return modulusLength; +} +export async function generateKeyPair(alg, options) { + var _a, _b; + let algorithm; + let keyUsages; + switch (alg) { + case 'PS256': + case 'PS384': + case 'PS512': + algorithm = { + name: 'RSA-PSS', + hash: { name: `SHA-${alg.substr(-3)}` }, + publicExponent: new Uint8Array([0x01, 0x00, 0x01]), + modulusLength: getModulusLengthOption(options), + }; + keyUsages = ['sign', 'verify']; + break; + case 'RS256': + case 'RS384': + case 'RS512': + algorithm = { + name: 'RSASSA-PKCS1-v1_5', + hash: { name: `SHA-${alg.substr(-3)}` }, + publicExponent: new Uint8Array([0x01, 0x00, 0x01]), + modulusLength: getModulusLengthOption(options), + }; + keyUsages = ['sign', 'verify']; + break; + case 'RSA-OAEP': + case 'RSA-OAEP-256': + case 'RSA-OAEP-384': + case 'RSA-OAEP-512': + algorithm = { + name: 'RSA-OAEP', + hash: { name: `SHA-${parseInt(alg.substr(-3), 10) || 1}` }, + publicExponent: new Uint8Array([0x01, 0x00, 0x01]), + modulusLength: getModulusLengthOption(options), + }; + 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: (_a = options === null || options === void 0 ? void 0 : options.crv) !== null && _a !== void 0 ? _a : 'P-256' }; + keyUsages = ['deriveKey', 'deriveBits']; + break; + default: + throw new JOSENotSupported('unsupported or invalid JWK "alg" (Algorithm) Parameter value'); + } + return (crypto.subtle.generateKey(algorithm, (_b = options === null || options === void 0 ? void 0 : options.extractable) !== null && _b !== void 0 ? _b : false, keyUsages)); +} diff --git a/dist/browser/runtime/get_sign_verify_key.js b/dist/browser/runtime/get_sign_verify_key.js new file mode 100644 index 0000000000..10013b1625 --- /dev/null +++ b/dist/browser/runtime/get_sign_verify_key.js @@ -0,0 +1,14 @@ +import crypto, { isCryptoKey } from './webcrypto.js'; +import invalidKeyInput from './invalid_key_input.js'; +export default function getCryptoKey(alg, key, usage) { + if (isCryptoKey(key)) { + return key; + } + if (key instanceof Uint8Array) { + if (!alg.startsWith('HS')) { + throw new TypeError(invalidKeyInput(key, 'CryptoKey')); + } + return crypto.subtle.importKey('raw', key, { hash: { name: `SHA-${alg.substr(-3)}` }, name: 'HMAC' }, false, [usage]); + } + throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'Uint8Array')); +} diff --git a/dist/browser/runtime/global.js b/dist/browser/runtime/global.js new file mode 100644 index 0000000000..14d19748a7 --- /dev/null +++ b/dist/browser/runtime/global.js @@ -0,0 +1,10 @@ +function getGlobal() { + if (typeof globalThis !== 'undefined') + return globalThis; + if (typeof self !== 'undefined') + return self; + if (typeof window !== 'undefined') + return window; + throw new Error('unable to locate global object'); +} +export default getGlobal(); diff --git a/dist/browser/runtime/invalid_key_input.js b/dist/browser/runtime/invalid_key_input.js new file mode 100644 index 0000000000..468ad288b4 --- /dev/null +++ b/dist/browser/runtime/invalid_key_input.js @@ -0,0 +1,25 @@ +export default (actual, ...types) => { + let msg = 'Key must be '; + if (types.length > 2) { + const last = types.pop(); + msg += `one of type ${types.join(', ')}, or ${last}.`; + } + else if (types.length === 2) { + msg += `one of type ${types[0]} or ${types[1]}.`; + } + else { + msg += `of type ${types[0]}.`; + } + if (actual == null) { + msg += ` Received ${actual}`; + } + else if (typeof actual === 'function' && actual.name) { + msg += ` Received function ${actual.name}`; + } + else if (typeof actual === 'object' && actual != null) { + if (actual.constructor && actual.constructor.name) { + msg += ` Received an instance of ${actual.constructor.name}`; + } + } + return msg; +}; diff --git a/dist/browser/runtime/jwk_to_key.js b/dist/browser/runtime/jwk_to_key.js new file mode 100644 index 0000000000..bf0d9a7afd --- /dev/null +++ b/dist/browser/runtime/jwk_to_key.js @@ -0,0 +1,115 @@ +import crypto from './webcrypto.js'; +import { JOSENotSupported } from '../util/errors.js'; +import { decode as base64url } from './base64url.js'; +function subtleMapping(jwk) { + let algorithm; + let keyUsages; + switch (jwk.kty) { + case 'oct': { + switch (jwk.alg) { + case 'HS256': + case 'HS384': + case 'HS512': + algorithm = { name: 'HMAC', hash: { name: `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: { name: `SHA-${jwk.alg.substr(-3)}` } }; + keyUsages = jwk.d ? ['sign'] : ['verify']; + break; + case 'RS256': + case 'RS384': + case 'RS512': + algorithm = { name: 'RSASSA-PKCS1-v1_5', hash: { name: `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: { name: `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 }; +} +const parse = async (jwk) => { + var _a, _b; + const { algorithm, keyUsages } = subtleMapping(jwk); + const rest = [ + algorithm, + (_a = jwk.ext) !== null && _a !== void 0 ? _a : false, + (_b = jwk.key_ops) !== null && _b !== void 0 ? _b : keyUsages, + ]; + if (algorithm.name === 'PBKDF2') { + return crypto.subtle.importKey('raw', base64url(jwk.k), ...rest); + } + const keyData = { ...jwk }; + delete keyData.alg; + return crypto.subtle.importKey('jwk', keyData, ...rest); +}; +export default parse; diff --git a/dist/browser/runtime/key_to_jwk.js b/dist/browser/runtime/key_to_jwk.js new file mode 100644 index 0000000000..b7ee46e95b --- /dev/null +++ b/dist/browser/runtime/key_to_jwk.js @@ -0,0 +1,20 @@ +import crypto, { isCryptoKey } from './webcrypto.js'; +import invalidKeyInput from './invalid_key_input.js'; +import { encode as base64url } from './base64url.js'; +const keyToJWK = async (key) => { + if (key instanceof Uint8Array) { + return { + kty: 'oct', + k: base64url(key), + }; + } + if (!isCryptoKey(key)) { + throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'Uint8Array')); + } + if (!key.extractable) { + throw new TypeError('non-extractable CryptoKey cannot be exported as a JWK'); + } + const { ext, key_ops, alg, use, ...jwk } = await crypto.subtle.exportKey('jwk', key); + return jwk; +}; +export default keyToJWK; diff --git a/dist/browser/runtime/pbes2kw.js b/dist/browser/runtime/pbes2kw.js new file mode 100644 index 0000000000..481c16814b --- /dev/null +++ b/dist/browser/runtime/pbes2kw.js @@ -0,0 +1,71 @@ +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, { isCryptoKey } from './webcrypto.js'; +import invalidKeyInput from './invalid_key_input.js'; +function getCryptoKey(key) { + if (key instanceof Uint8Array) { + return crypto.subtle.importKey('raw', key, 'PBKDF2', false, ['deriveBits']); + } + if (isCryptoKey(key)) { + return key; + } + throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'Uint8Array')); +} +export const encrypt = async (alg, key, cek, p2c = Math.floor(Math.random() * 2049) + 2048, p2s = random(new Uint8Array(16))) => { + checkP2s(p2s); + const salt = concatSalt(alg, p2s); + const keylen = parseInt(alg.substr(13, 3), 10); + const subtleAlg = { + hash: { name: `SHA-${alg.substr(8, 3)}` }, + iterations: p2c, + name: 'PBKDF2', + salt, + }; + const wrapAlg = { + length: keylen, + name: 'AES-KW', + }; + const cryptoKey = await getCryptoKey(key); + let derived; + 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 = async (alg, key, encryptedKey, p2c, p2s) => { + checkP2s(p2s); + const salt = concatSalt(alg, p2s); + const keylen = parseInt(alg.substr(13, 3), 10); + const subtleAlg = { + hash: { name: `SHA-${alg.substr(8, 3)}` }, + iterations: p2c, + name: 'PBKDF2', + salt, + }; + const wrapAlg = { + length: keylen, + name: 'AES-KW', + }; + const cryptoKey = await getCryptoKey(key); + let derived; + 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/dist/browser/runtime/random.js b/dist/browser/runtime/random.js new file mode 100644 index 0000000000..2728ffaa1c --- /dev/null +++ b/dist/browser/runtime/random.js @@ -0,0 +1,3 @@ +import crypto from './webcrypto.js'; +const random = crypto.getRandomValues.bind(crypto); +export default random; diff --git a/dist/browser/runtime/rsaes.js b/dist/browser/runtime/rsaes.js new file mode 100644 index 0000000000..796a56cad0 --- /dev/null +++ b/dist/browser/runtime/rsaes.js @@ -0,0 +1,33 @@ +import subtleAlgorithm from './subtle_rsaes.js'; +import bogusWebCrypto from './bogus.js'; +import crypto, { isCryptoKey } from './webcrypto.js'; +import checkKeyLength from './check_key_length.js'; +import invalidKeyInput from './invalid_key_input.js'; +export const encrypt = async (alg, key, cek) => { + if (!isCryptoKey(key)) { + throw new TypeError(invalidKeyInput(key, 'CryptoKey')); + } + checkKeyLength(alg, key); + if (key.usages.includes('encrypt')) { + return new Uint8Array(await crypto.subtle.encrypt(subtleAlgorithm(alg), key, cek)); + } + if (key.usages.includes('wrapKey')) { + 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 = async (alg, key, encryptedKey) => { + if (!isCryptoKey(key)) { + throw new TypeError(invalidKeyInput(key, 'CryptoKey')); + } + 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/dist/browser/runtime/sign.js b/dist/browser/runtime/sign.js new file mode 100644 index 0000000000..908773dee4 --- /dev/null +++ b/dist/browser/runtime/sign.js @@ -0,0 +1,11 @@ +import subtleAlgorithm from './subtle_dsa.js'; +import crypto from './webcrypto.js'; +import checkKeyLength from './check_key_length.js'; +import getSignKey from './get_sign_verify_key.js'; +const sign = async (alg, key, data) => { + const cryptoKey = await getSignKey(alg, key, 'sign'); + checkKeyLength(alg, cryptoKey); + const signature = await crypto.subtle.sign(subtleAlgorithm(alg), cryptoKey, data); + return new Uint8Array(signature); +}; +export default sign; diff --git a/dist/browser/runtime/subtle_dsa.js b/dist/browser/runtime/subtle_dsa.js new file mode 100644 index 0000000000..f4cb7427dc --- /dev/null +++ b/dist/browser/runtime/subtle_dsa.js @@ -0,0 +1,43 @@ +import { JOSENotSupported } from '../util/errors.js'; +export default function subtleDsa(alg) { + switch (alg) { + case 'HS256': + return { hash: { name: 'SHA-256' }, name: 'HMAC' }; + case 'HS384': + return { hash: { name: 'SHA-384' }, name: 'HMAC' }; + case 'HS512': + return { hash: { name: 'SHA-512' }, name: 'HMAC' }; + case 'PS256': + return { + hash: { name: 'SHA-256' }, + name: 'RSA-PSS', + saltLength: 256 >> 3, + }; + case 'PS384': + return { + hash: { name: 'SHA-384' }, + name: 'RSA-PSS', + saltLength: 384 >> 3, + }; + case 'PS512': + return { + hash: { name: 'SHA-512' }, + name: 'RSA-PSS', + saltLength: 512 >> 3, + }; + case 'RS256': + return { hash: { name: 'SHA-256' }, name: 'RSASSA-PKCS1-v1_5' }; + case 'RS384': + return { hash: { name: 'SHA-384' }, name: 'RSASSA-PKCS1-v1_5' }; + case 'RS512': + return { hash: { name: 'SHA-512' }, name: 'RSASSA-PKCS1-v1_5' }; + case 'ES256': + return { hash: { name: 'SHA-256' }, name: 'ECDSA', namedCurve: 'P-256' }; + case 'ES384': + return { hash: { name: 'SHA-384' }, name: 'ECDSA', namedCurve: 'P-384' }; + case 'ES512': + return { hash: { name: 'SHA-512' }, name: 'ECDSA', namedCurve: 'P-521' }; + default: + throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`); + } +} diff --git a/dist/browser/runtime/subtle_rsaes.js b/dist/browser/runtime/subtle_rsaes.js new file mode 100644 index 0000000000..3a399bcfa7 --- /dev/null +++ b/dist/browser/runtime/subtle_rsaes.js @@ -0,0 +1,12 @@ +import { JOSENotSupported } from '../util/errors.js'; +export default function subtleRsaEs(alg) { + 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 not supported either by JOSE or your javascript runtime`); + } +} diff --git a/dist/browser/runtime/timing_safe_equal.js b/dist/browser/runtime/timing_safe_equal.js new file mode 100644 index 0000000000..442cdccd20 --- /dev/null +++ b/dist/browser/runtime/timing_safe_equal.js @@ -0,0 +1,19 @@ +const 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/dist/browser/runtime/verify.js b/dist/browser/runtime/verify.js new file mode 100644 index 0000000000..64f788f416 --- /dev/null +++ b/dist/browser/runtime/verify.js @@ -0,0 +1,16 @@ +import subtleAlgorithm from './subtle_dsa.js'; +import crypto from './webcrypto.js'; +import checkKeyLength from './check_key_length.js'; +import getVerifyKey from './get_sign_verify_key.js'; +const verify = async (alg, key, signature, data) => { + const cryptoKey = await getVerifyKey(alg, key, 'verify'); + checkKeyLength(alg, cryptoKey); + const algorithm = subtleAlgorithm(alg); + try { + return await crypto.subtle.verify(algorithm, cryptoKey, signature, data); + } + catch (_a) { + return false; + } +}; +export default verify; diff --git a/dist/browser/runtime/webcrypto.js b/dist/browser/runtime/webcrypto.js new file mode 100644 index 0000000000..fcd333fdfd --- /dev/null +++ b/dist/browser/runtime/webcrypto.js @@ -0,0 +1,8 @@ +import globalThis from './global.js'; +export default globalThis.crypto; +export function isCryptoKey(key) { + if (typeof globalThis.CryptoKey === 'undefined') { + return false; + } + return key != null && key instanceof globalThis.CryptoKey; +} diff --git a/dist/browser/runtime/zlib.js b/dist/browser/runtime/zlib.js new file mode 100644 index 0000000000..e47cb532dc --- /dev/null +++ b/dist/browser/runtime/zlib.js @@ -0,0 +1,7 @@ +import { JOSENotSupported } from '../util/errors.js'; +export const inflate = 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.'); +}; +export const deflate = async () => { + throw new JOSENotSupported('JWE "zip" (Compression Algorithm) Header Parameter is not supported by your javascript runtime. You need to use the `deflateRaw` encrypt option to provide Deflate Raw implementation.'); +}; diff --git a/dist/browser/util/base64url.js b/dist/browser/util/base64url.js new file mode 100644 index 0000000000..88ce7556d6 --- /dev/null +++ b/dist/browser/util/base64url.js @@ -0,0 +1,3 @@ +import * as base64url from '../runtime/base64url.js'; +export const encode = base64url.encode; +export const decode = base64url.decode; diff --git a/dist/browser/util/decode_protected_header.js b/dist/browser/util/decode_protected_header.js new file mode 100644 index 0000000000..261c132033 --- /dev/null +++ b/dist/browser/util/decode_protected_header.js @@ -0,0 +1,36 @@ +import { decode as base64url } from './base64url.js'; +import { decoder } from '../lib/buffer_utils.js'; +import isObject from '../lib/is_object.js'; +function decodeProtectedHeader(token) { + let protectedB64u; + if (typeof token === 'string') { + const parts = token.split('.'); + if (parts.length === 3 || parts.length === 5) { + ; + [protectedB64u] = parts; + } + } + else if (typeof token === 'object' && token) { + if ('protected' in token) { + protectedB64u = token.protected; + } + else { + throw new TypeError('Token does not contain a Protected Header'); + } + } + try { + if (typeof protectedB64u !== 'string' || !protectedB64u) { + throw new Error(); + } + const result = JSON.parse(decoder.decode(base64url(protectedB64u))); + if (!isObject(result)) { + throw new Error(); + } + return result; + } + catch (_a) { + throw new TypeError('Invalid Token or Protected Header formatting'); + } +} +export { decodeProtectedHeader }; +export default decodeProtectedHeader; diff --git a/dist/browser/util/errors.js b/dist/browser/util/errors.js new file mode 100644 index 0000000000..52506cbd9d --- /dev/null +++ b/dist/browser/util/errors.js @@ -0,0 +1,108 @@ +export class JOSEError extends Error { + constructor(message) { + super(message); + this.code = JOSEError.code; + this.name = this.constructor.name; + if (Error.captureStackTrace) { + Error.captureStackTrace(this, this.constructor); + } + } +} +JOSEError.code = 'ERR_JOSE_GENERIC'; +export class JWTClaimValidationFailed extends JOSEError { + constructor(message, claim = 'unspecified', reason = 'unspecified') { + super(message); + this.code = JWTClaimValidationFailed.code; + this.claim = claim; + this.reason = reason; + } +} +JWTClaimValidationFailed.code = 'ERR_JWT_CLAIM_VALIDATION_FAILED'; +export class JOSEAlgNotAllowed extends JOSEError { + constructor() { + super(...arguments); + this.code = JOSEAlgNotAllowed.code; + } +} +JOSEAlgNotAllowed.code = 'ERR_JOSE_ALG_NOT_ALLOWED'; +export class JOSENotSupported extends JOSEError { + constructor() { + super(...arguments); + this.code = JOSENotSupported.code; + } +} +JOSENotSupported.code = 'ERR_JOSE_NOT_SUPPORTED'; +export class JWEDecryptionFailed extends JOSEError { + constructor() { + super(...arguments); + this.code = JWEDecryptionFailed.code; + this.message = 'decryption operation failed'; + } +} +JWEDecryptionFailed.code = 'ERR_JWE_DECRYPTION_FAILED'; +export class JWEInvalid extends JOSEError { + constructor() { + super(...arguments); + this.code = JWEInvalid.code; + } +} +JWEInvalid.code = 'ERR_JWE_INVALID'; +export class JWSInvalid extends JOSEError { + constructor() { + super(...arguments); + this.code = JWSInvalid.code; + } +} +JWSInvalid.code = 'ERR_JWS_INVALID'; +export class JWTInvalid extends JOSEError { + constructor() { + super(...arguments); + this.code = JWTInvalid.code; + } +} +JWTInvalid.code = 'ERR_JWT_INVALID'; +export class JWKInvalid extends JOSEError { + constructor() { + super(...arguments); + this.code = JWKInvalid.code; + } +} +JWKInvalid.code = 'ERR_JWK_INVALID'; +export class JWKSInvalid extends JOSEError { + constructor() { + super(...arguments); + this.code = JWKSInvalid.code; + } +} +JWKSInvalid.code = 'ERR_JWKS_INVALID'; +export class JWKSNoMatchingKey extends JOSEError { + constructor() { + super(...arguments); + this.code = JWKSNoMatchingKey.code; + this.message = 'no applicable key found in the JSON Web Key Set'; + } +} +JWKSNoMatchingKey.code = 'ERR_JWKS_NO_MATCHING_KEY'; +export class JWKSMultipleMatchingKeys extends JOSEError { + constructor() { + super(...arguments); + this.code = JWKSMultipleMatchingKeys.code; + this.message = 'multiple matching keys found in the JSON Web Key Set'; + } +} +JWKSMultipleMatchingKeys.code = 'ERR_JWKS_MULTIPLE_MATCHING_KEYS'; +export class JWSSignatureVerificationFailed extends JOSEError { + constructor() { + super(...arguments); + this.code = JWSSignatureVerificationFailed.code; + this.message = 'signature verification failed'; + } +} +JWSSignatureVerificationFailed.code = 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED'; +export class JWTExpired extends JWTClaimValidationFailed { + constructor() { + super(...arguments); + this.code = JWTExpired.code; + } +} +JWTExpired.code = 'ERR_JWT_EXPIRED'; diff --git a/dist/browser/util/generate_key_pair.js b/dist/browser/util/generate_key_pair.js new file mode 100644 index 0000000000..733800cc06 --- /dev/null +++ b/dist/browser/util/generate_key_pair.js @@ -0,0 +1,6 @@ +import { generateKeyPair as generate } from '../runtime/generate.js'; +async function generateKeyPair(alg, options) { + return generate(alg, options); +} +export { generateKeyPair }; +export default generateKeyPair; diff --git a/dist/browser/util/generate_secret.js b/dist/browser/util/generate_secret.js new file mode 100644 index 0000000000..2d387754ee --- /dev/null +++ b/dist/browser/util/generate_secret.js @@ -0,0 +1,6 @@ +import { generateSecret as generate } from '../runtime/generate.js'; +async function generateSecret(alg, options) { + return generate(alg, options); +} +export { generateSecret }; +export default generateSecret; diff --git a/dist/browser/util/random.js b/dist/browser/util/random.js new file mode 100644 index 0000000000..d7dc7ab182 --- /dev/null +++ b/dist/browser/util/random.js @@ -0,0 +1,4 @@ +import runtimeRandom from '../runtime/random.js'; +const random = runtimeRandom; +export { random }; +export default random; diff --git a/dist/deno/README.md b/dist/deno/README.md new file mode 100644 index 0000000000..5cce841bdf --- /dev/null +++ b/dist/deno/README.md @@ -0,0 +1,38 @@ +# `jose` Modules API Documentation + +> "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. + +## Available modules + +- JSON Web Tokens (JWT) + - [Signing](https://github.com/panva/jose/blob/v3.16.1/docs/classes/jwt_sign.SignJWT.md#readme) + - [Verification & Claims Set Validation](https://github.com/panva/jose/blob/v3.16.1/docs/functions/jwt_verify.jwtVerify.md#readme) + - Encrypted JSON Web Tokens + - [Encryption](https://github.com/panva/jose/blob/v3.16.1/docs/classes/jwt_encrypt.EncryptJWT.md#readme) + - [Decryption & Claims Set Validation](https://github.com/panva/jose/blob/v3.16.1/docs/functions/jwt_decrypt.jwtDecrypt.md#readme) +- JSON Web Encryption (JWE) + - Encryption - [Compact](https://github.com/panva/jose/blob/v3.16.1/docs/classes/jwe_compact_encrypt.CompactEncrypt.md#readme), [Flattened](https://github.com/panva/jose/blob/v3.16.1/docs/classes/jwe_flattened_encrypt.FlattenedEncrypt.md#readme) + - Decryption - [Compact](https://github.com/panva/jose/blob/v3.16.1/docs/functions/jwe_compact_decrypt.compactDecrypt.md#readme), [Flattened](https://github.com/panva/jose/blob/v3.16.1/docs/functions/jwe_flattened_decrypt.flattenedDecrypt.md#readme), [General](https://github.com/panva/jose/blob/v3.16.1/docs/functions/jwe_general_decrypt.generalDecrypt.md#readme) +- JSON Web Signature (JWS) + - Signing - [Compact](https://github.com/panva/jose/blob/v3.16.1/docs/classes/jws_compact_sign.CompactSign.md#readme), [Flattened](https://github.com/panva/jose/blob/v3.16.1/docs/classes/jws_flattened_sign.FlattenedSign.md#readme), [General](https://github.com/panva/jose/blob/v3.16.1/docs/classes/jws_general_sign.GeneralSign.md#readme) + - Verification - [Compact](https://github.com/panva/jose/blob/v3.16.1/docs/functions/jws_compact_verify.compactVerify.md#readme), [Flattened](https://github.com/panva/jose/blob/v3.16.1/docs/functions/jws_flattened_verify.flattenedVerify.md#readme), [General](https://github.com/panva/jose/blob/v3.16.1/docs/functions/jws_general_verify.generalVerify.md#readme) +- JSON Web Key (JWK) + - [Parsing (JWK to KeyLike)](https://github.com/panva/jose/blob/v3.16.1/docs/functions/jwk_parse.parseJwk.md#readme) + - [Conversion (KeyLike to JWK)](https://github.com/panva/jose/blob/v3.16.1/docs/functions/jwk_from_key_like.fromKeyLike.md#readme) + - [Thumbprints](https://github.com/panva/jose/blob/v3.16.1/docs/functions/jwk_thumbprint.calculateThumbprint.md#readme) + - [EmbeddedJWK](https://github.com/panva/jose/blob/v3.16.1/docs/functions/jwk_embedded.EmbeddedJWK.md#readme) +- JSON Web Key Set (JWKS) + - [Verify using a remote JWKSet](https://github.com/panva/jose/blob/v3.16.1/docs/functions/jwks_remote.createRemoteJWKSet.md#readme) +- Key Pair or Secret Generation (Generate KeyLike) + - [Asymmetric Key Pair Generation](https://github.com/panva/jose/blob/v3.16.1/docs/functions/util_generate_key_pair.generateKeyPair.md#readme) + - [Symmetric Secret Generation](https://github.com/panva/jose/blob/v3.16.1/docs/functions/util_generate_secret.generateSecret.md#readme) +- Utilities + - [Decoding Token's Protected Header](https://github.com/panva/jose/blob/v3.16.1/docs/functions/util_decode_protected_header.decodeProtectedHeader.md#readme) +- [Unsecured JWT](https://github.com/panva/jose/blob/v3.16.1/docs/classes/jwt_unsecured.UnsecuredJWT.md#readme) +- [JOSE Errors](https://github.com/panva/jose/blob/v3.16.1/docs/modules/util_errors.md#readme) + +[support-sponsor]: https://github.com/sponsors/panva diff --git a/dist/deno/jwe/compact/decrypt.ts b/dist/deno/jwe/compact/decrypt.ts new file mode 100644 index 0000000000..f2da278577 --- /dev/null +++ b/dist/deno/jwe/compact/decrypt.ts @@ -0,0 +1,94 @@ +import decrypt from '../flattened/decrypt.ts' +import { JWEInvalid } from '../../util/errors.ts' +import { decoder } from '../../lib/buffer_utils.ts' +import type { + KeyLike, + DecryptOptions, + JWEHeaderParameters, + GetKeyFunction, + FlattenedJWE, + CompactDecryptResult, +} from '../../types.d.ts' + +/** + * 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 + * ```js + * import { compactDecrypt } from 'jose/jwe/compact/decrypt' + * ``` + * + * @example CJS import + * ```js + * const { compactDecrypt } = require('jose/jwe/compact/decrypt') + * ``` + * + * @example Deno import + * ```js + * import { compactDecrypt } from 'https://deno.land/x/jose@VERSION/jwe/compact/decrypt.ts' + * ``` + * + * @example Usage + * ```js + * 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 { plaintext, protectedHeader } = await compactDecrypt(jwe, privateKey) + * + * console.log(protectedHeader) + * console.log(decoder.decode(plaintext)) + * ``` + */ +async function compactDecrypt( + jwe: string | Uint8Array, + key: KeyLike | CompactDecryptGetKey, + options?: DecryptOptions, +): Promise { + if (jwe instanceof Uint8Array) { + jwe = decoder.decode(jwe) + } + + if (typeof jwe !== 'string') { + throw new JWEInvalid('Compact JWE must be a string or Uint8Array') + } + 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: (ciphertext || undefined), + iv: (iv || undefined), + protected: protectedHeader || undefined, + tag: (tag || undefined), + encrypted_key: encryptedKey || undefined, + }, + [1]>key, + options, + ) + + return { plaintext: decrypted.plaintext, protectedHeader: decrypted.protectedHeader! } +} + +export { compactDecrypt } +export default compactDecrypt +export type { KeyLike, DecryptOptions, CompactDecryptResult } diff --git a/dist/deno/jwe/compact/encrypt.ts b/dist/deno/jwe/compact/encrypt.ts new file mode 100644 index 0000000000..bdb143ed31 --- /dev/null +++ b/dist/deno/jwe/compact/encrypt.ts @@ -0,0 +1,111 @@ +import FlattenedEncrypt from '../flattened/encrypt.ts' +import type { + KeyLike, + JWEKeyManagementHeaderParameters, + JWEHeaderParameters, + EncryptOptions, +} from '../../types.d.ts' + +/** + * The CompactEncrypt class is a utility for creating Compact JWE strings. + * + * @example ESM import + * ```js + * import { CompactEncrypt } from 'jose/jwe/compact/encrypt' + * ``` + * + * @example CJS import + * ```js + * const { CompactEncrypt } = require('jose/jwe/compact/encrypt') + * ``` + * + * @example Deno import + * ```js + * import { CompactEncrypt } from 'https://deno.land/x/jose@VERSION/jwe/compact/encrypt.ts' + * ``` + * + * @example Usage + * ```js + * const encoder = new TextEncoder() + * + * 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) + * ``` + */ +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 { CompactEncrypt } +export default CompactEncrypt +export type { KeyLike, JWEKeyManagementHeaderParameters, JWEHeaderParameters } diff --git a/dist/deno/jwe/flattened/decrypt.ts b/dist/deno/jwe/flattened/decrypt.ts new file mode 100644 index 0000000000..878dafcb18 --- /dev/null +++ b/dist/deno/jwe/flattened/decrypt.ts @@ -0,0 +1,249 @@ +import { JOSEAlgNotAllowed, JOSENotSupported, JWEInvalid } from '../../util/errors.ts' +import isDisjoint from '../../lib/is_disjoint.ts' +import isObject from '../../lib/is_object.ts' + +import { decode as base64url } from '../../runtime/base64url.ts' +import decrypt from '../../runtime/decrypt.ts' +import { inflate } from '../../runtime/zlib.ts' +import decryptKeyManagement from '../../lib/decrypt_key_management.ts' + +import type { + FlattenedDecryptResult, + KeyLike, + FlattenedJWE, + JWEHeaderParameters, + DecryptOptions, + GetKeyFunction, +} from '../../types.d.ts' +import { encoder, decoder, concat } from '../../lib/buffer_utils.ts' +import cekFactory from '../../lib/cek.ts' +import random from '../../runtime/random.ts' +import validateCrit from '../../lib/validate_crit.ts' +import validateAlgorithms from '../../lib/validate_algorithms.ts' + +const generateCek = cekFactory(random) +const checkExtensions = 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 + * ```js + * import { flattenedDecrypt } from 'jose/jwe/flattened/decrypt' + * ``` + * + * @example CJS import + * ```js + * const { flattenedDecrypt } = require('jose/jwe/flattened/decrypt') + * ``` + * + * @example Deno import + * ```js + * import { flattenedDecrypt } from 'https://deno.land/x/jose@VERSION/jwe/flattened/decrypt.ts' + * ``` + * + * @example Usage + * ```js + * 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 { + * plaintext, + * protectedHeader, + * additionalAuthenticatedData + * } = await flattenedDecrypt(jwe, privateKey) + * + * console.log(protectedHeader) + * console.log(decoder.decode(plaintext)) + * console.log(decoder.decode(additionalAuthenticatedData)) + * ``` + */ +async function flattenedDecrypt( + jwe: FlattenedJWE, + key: KeyLike | FlattenedDecryptGetKey, + options?: DecryptOptions, +): Promise { + if (!isObject(jwe)) { + throw new JWEInvalid('Flattened JWE must be an object') + } + + if (jwe.protected === undefined && jwe.header === undefined && jwe.unprotected === undefined) { + throw new JWEInvalid('JOSE Header missing') + } + + if (typeof jwe.iv !== 'string') { + throw new JWEInvalid('JWE Initialization Vector missing or incorrect type') + } + + if (typeof jwe.ciphertext !== 'string') { + throw new JWEInvalid('JWE Ciphertext missing or incorrect type') + } + + if (typeof jwe.tag !== 'string') { + throw new JWEInvalid('JWE Authentication Tag missing or incorrect type') + } + + if (jwe.protected !== undefined && typeof jwe.protected !== 'string') { + throw new JWEInvalid('JWE Protected Header incorrect type') + } + + if (jwe.encrypted_key !== undefined && typeof jwe.encrypted_key !== 'string') { + throw new JWEInvalid('JWE Encrypted Key incorrect type') + } + + if (jwe.aad !== undefined && typeof jwe.aad !== 'string') { + throw new JWEInvalid('JWE AAD incorrect type') + } + + if (jwe.header !== undefined && !isObject(jwe.header)) { + throw new JWEInvalid('JWE Shared Unprotected Header incorrect type') + } + + if (jwe.unprotected !== undefined && !isObject(jwe.unprotected)) { + throw new JWEInvalid('JWE Per-Recipient Unprotected Header incorrect type') + } + + let parsedProt!: JWEHeaderParameters + if (jwe.protected) { + const protectedHeader = base64url(jwe.protected) + try { + parsedProt = JSON.parse(decoder.decode(protectedHeader)) + } catch { + throw new JWEInvalid('JWE Protected Header is invalid') + } + } + 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, + } + + checkExtensions(options?.crit, parsedProt, joseHeader) + + if (joseHeader.zip !== undefined) { + 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 (typeof alg !== 'string' || !alg) { + throw new JWEInvalid('missing JWE Algorithm (alg) in JWE Header') + } + + if (typeof enc !== 'string' || !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 (jwe.encrypted_key !== undefined) { + encryptedKey = base64url(jwe.encrypted_key!) + } + + if (typeof key === 'function') { + 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 = generateCek(enc) + } + + const iv = base64url(jwe.iv) + const tag = base64url(jwe.tag) + + const protectedHeader: Uint8Array = encoder.encode(jwe.protected ?? '') + let additionalData: Uint8Array + + if (jwe.aad !== undefined) { + 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 (jwe.protected !== undefined) { + result.protectedHeader = parsedProt + } + + if (jwe.aad !== undefined) { + result.additionalAuthenticatedData = base64url(jwe.aad!) + } + + if (jwe.unprotected !== undefined) { + result.sharedUnprotectedHeader = jwe.unprotected + } + + if (jwe.header !== undefined) { + result.unprotectedHeader = jwe.header + } + + return result +} + +export { flattenedDecrypt } +export default flattenedDecrypt +export type { KeyLike, FlattenedJWE, JWEHeaderParameters, DecryptOptions, FlattenedDecryptResult } diff --git a/dist/deno/jwe/flattened/encrypt.ts b/dist/deno/jwe/flattened/encrypt.ts new file mode 100644 index 0000000000..77771d7cdf --- /dev/null +++ b/dist/deno/jwe/flattened/encrypt.ts @@ -0,0 +1,324 @@ +import type { + KeyLike, + FlattenedJWE, + JWEHeaderParameters, + JWEKeyManagementHeaderParameters, + EncryptOptions, +} from '../../types.d.ts' +import type { JWEKeyManagementHeaderResults } from '../../types.i.d.ts' +import ivFactory from '../../lib/iv.ts' +import { encode as base64url } from '../../runtime/base64url.ts' +import random from '../../runtime/random.ts' +import encrypt from '../../runtime/encrypt.ts' +import { deflate } from '../../runtime/zlib.ts' +import encryptKeyManagement from '../../lib/encrypt_key_management.ts' + +import { JOSENotSupported, JWEInvalid } from '../../util/errors.ts' +import isDisjoint from '../../lib/is_disjoint.ts' +import { encoder, decoder, concat } from '../../lib/buffer_utils.ts' +import validateCrit from '../../lib/validate_crit.ts' + +const generateIv = ivFactory(random) +const checkExtensions = validateCrit.bind(undefined, JWEInvalid, new Map()) + +/** + * The FlattenedEncrypt class is a utility for creating Flattened JWE + * objects. + * + * @example ESM import + * ```js + * import { FlattenedEncrypt } from 'jose/jwe/flattened/encrypt' + * ``` + * + * @example CJS import + * ```js + * const { FlattenedEncrypt } = require('jose/jwe/flattened/encrypt') + * ``` + * + * @example Deno import + * ```js + * import { FlattenedEncrypt } from 'https://deno.land/x/jose@VERSION/jwe/flattened/encrypt.ts' + * ``` + * + * @example Usage + * ```js + * const encoder = new TextEncoder() + * + * 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) + * ``` + */ +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) { + if (!(plaintext instanceof Uint8Array)) { + throw new TypeError('plaintext must be an instance of 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, + } + + checkExtensions(options?.crit, this._protectedHeader, joseHeader) + + if (joseHeader.zip !== undefined) { + 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 (typeof alg !== 'string' || !alg) { + throw new JWEInvalid('JWE "alg" (Algorithm) Header Parameter missing or invalid') + } + + if (typeof enc !== 'string' || !enc) { + throw new JWEInvalid('JWE "enc" (Encryption Algorithm) Header Parameter missing or invalid') + } + + 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 ||= 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 { FlattenedEncrypt } +export default FlattenedEncrypt +export type { KeyLike, FlattenedJWE, JWEHeaderParameters, JWEKeyManagementHeaderParameters } diff --git a/dist/deno/jwe/general/decrypt.ts b/dist/deno/jwe/general/decrypt.ts new file mode 100644 index 0000000000..68b1c3bc1c --- /dev/null +++ b/dist/deno/jwe/general/decrypt.ts @@ -0,0 +1,107 @@ +import decrypt from '../flattened/decrypt.ts' +import { JWEDecryptionFailed, JWEInvalid } from '../../util/errors.ts' +import type { + KeyLike, + DecryptOptions, + JWEHeaderParameters, + GetKeyFunction, + FlattenedJWE, + GeneralJWE, + GeneralDecryptResult, +} from '../../types.d.ts' +import isObject from '../../lib/is_object.ts' + +/** + * Interface for General JWE Decryption dynamic key resolution. + * No token components have been verified at the time of this function call. + */ +export interface GeneralDecryptGetKey extends GetKeyFunction {} + +/** + * Decrypts a General JWE. + * + * @param jwe General 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 + * ```js + * import { generalDecrypt } from 'jose/jwe/general/decrypt' + * ``` + * + * @example CJS import + * ```js + * const { generalDecrypt } = require('jose/jwe/general/decrypt') + * ``` + * + * @example Deno import + * ```js + * import { generalDecrypt } from 'https://deno.land/x/jose@VERSION/jwe/general/decrypt.ts' + * ``` + * + * @example Usage + * ```js + * const decoder = new TextDecoder() + * const jwe = { + * ciphertext: '9EzjFISUyoG-ifC2mSihfP0DPC80yeyrxhTzKt1C_VJBkxeBG0MI4Te61Pk45RAGubUvBpU9jm4', + * iv: '8Fy7A_IuoX5VXG9s', + * tag: 'W76IYV6arGRuDSaSyWrQNg', + * aad: 'VGhlIEZlbGxvd3NoaXAgb2YgdGhlIFJpbmc', + * protected: 'eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMjU2R0NNIn0', + * recipients: [ + * { + * encrypted_key: 'Z6eD4UK_yFb5ZoKvKkGAdqywEG_m0e4IYo0x8Vf30LAMJcsc-_zSgIeiF82teZyYi2YYduHKoqImk7MRnoPZOlEs0Q5BNK1OgBmSOhCE8DFyqh9Zh48TCTP6lmBQ52naqoUJFMtHzu-0LwZH26hxos0GP3Dt19O379MJB837TdKKa87skq0zHaVLAquRHOBF77GI54Bc7O49d8aOrSu1VEFGMThlW2caspPRiTSePDMDPq7_WGk50izRhB3Asl9wmP9wEeaTrkJKRnQj5ips1SAZ1hDBsqEQKKukxP1HtdcopHV5_qgwU8Hjm5EwSLMluMQuiE6hwlkXGOujZLVizA' + * } + * ] + * } + * + * const { + * plaintext, + * protectedHeader, + * additionalAuthenticatedData + * } = await generalDecrypt(jwe, privateKey) + * + * console.log(protectedHeader) + * console.log(decoder.decode(plaintext)) + * console.log(decoder.decode(additionalAuthenticatedData)) + * ``` + */ +async function generalDecrypt( + jwe: GeneralJWE, + key: KeyLike | GeneralDecryptGetKey, + options?: DecryptOptions, +): Promise { + if (!isObject(jwe)) { + throw new JWEInvalid('General JWE must be an object') + } + + if (!Array.isArray(jwe.recipients) || !jwe.recipients.every(isObject)) { + throw new JWEInvalid('JWE Recipients missing or incorrect type') + } + + for (const recipient of jwe.recipients) { + try { + return await decrypt( + { + aad: jwe.aad, + ciphertext: jwe.ciphertext, + encrypted_key: recipient.encrypted_key, + header: recipient.header, + iv: jwe.iv, + protected: jwe.protected, + tag: jwe.tag, + unprotected: jwe.unprotected, + }, + [1]>key, + options, + ) + } catch { + // + } + } + throw new JWEDecryptionFailed() +} + +export { generalDecrypt } +export default generalDecrypt +export type { KeyLike, GeneralJWE, DecryptOptions, GeneralDecryptResult } diff --git a/dist/deno/jwk/embedded.ts b/dist/deno/jwk/embedded.ts new file mode 100644 index 0000000000..05fbcc050d --- /dev/null +++ b/dist/deno/jwk/embedded.ts @@ -0,0 +1,62 @@ +import type { KeyObject, FlattenedJWSInput, JWSHeaderParameters } from '../types.d.ts' +import parseJwk from './parse.ts' +import isObject from '../lib/is_object.ts' +import { JWSInvalid } from '../util/errors.ts' + +/** + * 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 + * ```js + * import { EmbeddedJWK } from 'jose/jwk/embedded' + * ``` + * + * @example CJS import + * ```js + * const { EmbeddedJWK } = require('jose/jwk/embedded') + * ``` + * + * @example Deno import + * ```js + * import { EmbeddedJWK } from 'https://deno.land/x/jose@VERSION/jwk/embedded.ts' + * ``` + * + * @example Usage + * ```js + * 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) + * ``` + */ +async function EmbeddedJWK(protectedHeader: JWSHeaderParameters, token: FlattenedJWSInput) { + const joseHeader = { + ...protectedHeader, + ...token.header, + } + if (!isObject(joseHeader.jwk)) { + throw new JWSInvalid('"jwk" (JSON Web Key) Header Parameter must be a JSON object') + } + + const key = await parseJwk(joseHeader.jwk!, joseHeader.alg!, true) + + if (key.type !== 'public') { + throw new JWSInvalid('"jwk" (JSON Web Key) Header Parameter must be a public key') + } + + return key +} + +export { EmbeddedJWK } +export default EmbeddedJWK diff --git a/dist/deno/jwk/from_key_like.ts b/dist/deno/jwk/from_key_like.ts new file mode 100644 index 0000000000..b71492ee68 --- /dev/null +++ b/dist/deno/jwk/from_key_like.ts @@ -0,0 +1,39 @@ +import type { JWK, KeyLike } from '../types.d.ts' +import asJWK from '../runtime/key_to_jwk.ts' + +/** + * Converts a runtime-specific key representation (KeyLike) to a JWK. + * + * @param key Key representation to transform to a JWK. + * + * @example ESM import + * ```js + * import { fromKeyLike } from 'jose/jwk/from_key_like' + * ``` + * + * @example CJS import + * ```js + * const { fromKeyLike } = require('jose/jwk/from_key_like') + * ``` + * + * @example Deno import + * ```js + * import { fromKeyLike } from 'https://deno.land/x/jose@VERSION/jwk/from_key_like.ts' + * ``` + * + * @example Usage + * ```js + * const privateJwk = await fromKeyLike(privateKey) + * const publicJwk = await fromKeyLike(publicKey) + * + * console.log(privateJwk) + * console.log(publicJwk) + * ``` + */ +async function fromKeyLike(key: KeyLike): Promise { + return asJWK(key) +} + +export { fromKeyLike } +export default fromKeyLike +export type { KeyLike, JWK } diff --git a/dist/deno/jwk/parse.ts b/dist/deno/jwk/parse.ts new file mode 100644 index 0000000000..ffd92ab1c9 --- /dev/null +++ b/dist/deno/jwk/parse.ts @@ -0,0 +1,90 @@ +import { decode as base64url } from '../runtime/base64url.ts' +import asKeyObject from '../runtime/jwk_to_key.ts' +import { JOSENotSupported } from '../util/errors.ts' +import isObject from '../lib/is_object.ts' +import type { JWK, KeyLike } from '../types.d.ts' + +/** + * Converts a JWK to a runtime-specific key representation (KeyLike). 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 + * ```js + * import { parseJwk } from 'jose/jwk/parse' + * ``` + * + * @example CJS import + * ```js + * const { parseJwk } = require('jose/jwk/parse') + * ``` + * + * @example Deno import + * ```js + * import { parseJwk } from 'https://deno.land/x/jose@VERSION/jwk/parse.ts' + * ``` + * + * @example Usage + * ```js + * const ecPublicKey = await parseJwk({ + * crv: 'P-256', + * kty: 'EC', + * x: 'ySK38C1jBdLwDsNWKzzBHqKYEE5Cgv-qjWvorUXk9fw', + * y: '_LeQBw07cf5t57Iavn4j-BqJsAD1dpoz8gokd3sBsOo' + * }, 'ES256') + * + * const rsaPublicKey = await parseJwk({ + * kty: 'RSA', + * e: 'AQAB', + * n: '12oBZRhCiZFJLcPg59LkZZ9mdhSMTKAQZYq32k_ti5SBB6jerkh-WzOMAO664r_qyLkqHUSp3u5SbXtseZEpN3XPWGKSxjsy-1JyEFTdLSYe6f9gfrmxkUF_7DTpq0gn6rntP05g2-wFW50YO7mosfdslfrTJYWHFhJALabAeYirYD7-9kqq9ebfFMF4sRRELbv9oi36As6Q9B3Qb5_C1rAzqfao_PCsf9EPsTZsVVVkA5qoIAr47lo1ipfiBPxUCCNSdvkmDTYgvvRm6ZoMjFbvOtgyts55fXKdMWv7I9HMD5HwE9uW839PWA514qhbcIsXEYSFMPMV6fnlsiZvQQ' + * }, 'PS256') + * ``` + */ +async function parseJwk(jwk: JWK, alg?: string, octAsKeyObject?: boolean): Promise { + if (!isObject(jwk)) { + throw new TypeError('JWK must be an object') + } + + 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') + } + + octAsKeyObject ??= jwk.ext !== true + + if (octAsKeyObject) { + return asKeyObject({ ...jwk, alg, ext: false }) + } + + return base64url(jwk.k) + case 'RSA': + if (jwk.oth !== undefined) { + throw new JOSENotSupported( + 'RSA JWK "oth" (Other Primes Info) Parameter value is not supported', + ) + } + case 'EC': + case 'OKP': + return asKeyObject({ ...jwk, alg }) + default: + throw new JOSENotSupported('unsupported "kty" (Key Type) Parameter value') + } +} + +export { parseJwk } +export default parseJwk +export type { KeyLike, JWK } diff --git a/dist/deno/jwk/thumbprint.ts b/dist/deno/jwk/thumbprint.ts new file mode 100644 index 0000000000..ae0db83f0c --- /dev/null +++ b/dist/deno/jwk/thumbprint.ts @@ -0,0 +1,89 @@ +import { JOSENotSupported, JWKInvalid } from '../util/errors.ts' + +import digest from '../runtime/digest.ts' +import { encode as base64url } from '../runtime/base64url.ts' +import { encoder } from '../lib/buffer_utils.ts' +import type { JWK } from '../types.d.ts' +import isObject from '../lib/is_object.ts' + +const check = (value: unknown, 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 + * ```js + * import { calculateThumbprint } from 'jose/jwk/thumbprint' + * ``` + * + * @example CJS import + * ```js + * const { calculateThumbprint } = require('jose/jwk/thumbprint') + * ``` + * + * @example Deno import + * ```js + * import { calculateThumbprint } from 'https://deno.land/x/jose@VERSION/jwk/thumbprint.ts' + * ``` + * + * @example Usage + * ```js + * const thumbprint = await calculateThumbprint({ + * kty: 'RSA', + * e: 'AQAB', + * n: '12oBZRhCiZFJLcPg59LkZZ9mdhSMTKAQZYq32k_ti5SBB6jerkh-WzOMAO664r_qyLkqHUSp3u5SbXtseZEpN3XPWGKSxjsy-1JyEFTdLSYe6f9gfrmxkUF_7DTpq0gn6rntP05g2-wFW50YO7mosfdslfrTJYWHFhJALabAeYirYD7-9kqq9ebfFMF4sRRELbv9oi36As6Q9B3Qb5_C1rAzqfao_PCsf9EPsTZsVVVkA5qoIAr47lo1ipfiBPxUCCNSdvkmDTYgvvRm6ZoMjFbvOtgyts55fXKdMWv7I9HMD5HwE9uW839PWA514qhbcIsXEYSFMPMV6fnlsiZvQQ' + * }) + * + * console.log(thumbprint) + * ``` + */ +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 { calculateThumbprint } +export default calculateThumbprint +export type { JWK } diff --git a/dist/deno/jwks/remote.ts b/dist/deno/jwks/remote.ts new file mode 100644 index 0000000000..3e1bc662f6 --- /dev/null +++ b/dist/deno/jwks/remote.ts @@ -0,0 +1,264 @@ +import type { + KeyObject, + JWSHeaderParameters, + JWK, + FlattenedJWSInput, + GetKeyFunction, +} from '../types.d.ts' +import parseJWK from '../jwk/parse.ts' +import { + JWKSInvalid, + JOSENotSupported, + JWKSNoMatchingKey, + JWKSMultipleMatchingKeys, +} from '../util/errors.ts' +import fetchJwks from '../runtime/fetch_jwks.ts' +import isObject from '../lib/is_object.ts' + +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 + + /** + * An instance of [http.Agent](https://nodejs.org/api/http.html#http_class_http_agent) + * or [https.Agent](https://nodejs.org/api/https.html#https_class_https_agent) to pass + * to the [http.get](https://nodejs.org/api/http.html#http_http_get_options_callback) + * or [https.get](https://nodejs.org/api/https.html#https_https_get_options_callback) + * method's options. Use when behind an http(s) proxy. + * This is a Node.js runtime specific option, it is ignored + * when used outside of Node.js runtime. + */ + agent?: any +} + +function isJWKLike(key: unknown): key is JWK { + return isObject(key) +} + +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?: Promise + + private _options: Pick + + 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._options = { agent: options?.agent } + 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 (cached[protectedHeader.alg!] === undefined) { + const keyObject = await parseJWK({ ...jwk, alg: protectedHeader.alg! }) + + 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 = fetchJwks(this._url, this._timeoutDuration, this._options) + .then((json) => { + if ( + typeof json !== 'object' || + !json || + !Array.isArray(json.keys) || + !json.keys.every(isJWKLike) + ) { + throw new JWKSInvalid('JSON Web Key Set malformed') + } + + this._jwks = { keys: json.keys } + this._cooldownStarted = Date.now() + this._pendingFetch = undefined + }) + .catch((err: Error) => { + 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 + * ```js + * import { createRemoteJWKSet } from 'jose/jwks/remote' + * ``` + * + * @example CJS import + * ```js + * const { createRemoteJWKSet } = require('jose/jwks/remote') + * ``` + * + * @example Deno import + * ```js + * import { createRemoteJWKSet } from 'https://deno.land/x/jose@VERSION/jwks/remote.ts' + * ``` + * + * @example Usage + * ```js + * 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. + */ +function createRemoteJWKSet( + url: URL, + options?: RemoteJWKSetOptions, +): GetKeyFunction { + return RemoteJWKSet.prototype.getKey.bind(new RemoteJWKSet(url, options)) +} + +export { createRemoteJWKSet } +export default createRemoteJWKSet diff --git a/dist/deno/jws/compact/sign.ts b/dist/deno/jws/compact/sign.ts new file mode 100644 index 0000000000..17274b9b21 --- /dev/null +++ b/dist/deno/jws/compact/sign.ts @@ -0,0 +1,72 @@ +import FlattenedSign from '../flattened/sign.ts' +import type { JWSHeaderParameters, KeyLike, SignOptions } from '../../types.d.ts' + +/** + * The CompactSign class is a utility for creating Compact JWS strings. + * + * @example ESM import + * ```js + * import { CompactSign } from 'jose/jws/compact/sign' + * ``` + * + * @example CJS import + * ```js + * const { CompactSign } = require('jose/jws/compact/sign') + * ``` + * + * @example Deno import + * ```js + * import { CompactSign } from 'https://deno.land/x/jose@VERSION/jws/compact/sign.ts' + * ``` + * + * @example Usage + * ```js + * const encoder = new TextEncoder() + * + * 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) + * ``` + */ +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. + * @param options JWS Sign options. + */ + async sign(key: KeyLike, options?: SignOptions): Promise { + const jws = await this._flattened.sign(key, options) + + 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 { CompactSign } +export default CompactSign +export type { JWSHeaderParameters, KeyLike } diff --git a/dist/deno/jws/compact/verify.ts b/dist/deno/jws/compact/verify.ts new file mode 100644 index 0000000000..31da725f91 --- /dev/null +++ b/dist/deno/jws/compact/verify.ts @@ -0,0 +1,89 @@ +import verify from '../flattened/verify.ts' +import { JWSInvalid } from '../../util/errors.ts' +import { decoder } from '../../lib/buffer_utils.ts' +import type { + CompactVerifyResult, + FlattenedJWSInput, + GetKeyFunction, + JWSHeaderParameters, + KeyLike, + VerifyOptions, +} from '../../types.d.ts' + +/** + * Interface for Compact JWS Verification dynamic key resolution. + * No token components have been verified at the time of this function call. + * + * See [createRemoteJWKSet](../functions/jwks_remote.createRemoteJWKSet.md#function-createremotejwkset) + * to verify using a remote JSON Web Key Set. + */ +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 + * ```js + * import { compactVerify } from 'jose/jws/compact/verify' + * ``` + * + * @example CJS import + * ```js + * const { compactVerify } = require('jose/jws/compact/verify') + * ``` + * + * @example Deno import + * ```js + * import { compactVerify } from 'https://deno.land/x/jose@VERSION/jws/compact/verify.ts' + * ``` + * + * @example Usage + * ```js + * const decoder = new TextDecoder() + * const jws = 'eyJhbGciOiJFUzI1NiJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4.kkAs_gPPxWMI3rHuVlxHaTPfDWDoqdI8jSvuSmqV-8IHIWXg9mcAeC9ggV-45ZHRbiRJ3obUIFo1rHphPA5URg' + * + * const { payload, protectedHeader } = await compactVerify(jws, publicKey) + * + * console.log(protectedHeader) + * console.log(decoder.decode(payload)) + * ``` + */ +async function compactVerify( + jws: string | Uint8Array, + key: KeyLike | CompactVerifyGetKey, + options?: VerifyOptions, +): Promise { + if (jws instanceof Uint8Array) { + jws = decoder.decode(jws) + } + + if (typeof jws !== 'string') { + throw new JWSInvalid('Compact JWS must be a string or Uint8Array') + } + const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split('.') + + if (length !== 3) { + throw new JWSInvalid('Invalid Compact JWS') + } + + const verified = await verify( + { + payload: (payload || undefined), + protected: protectedHeader || undefined, + signature: (signature || undefined), + }, + [1]>key, + options, + ) + + return { payload: verified.payload, protectedHeader: verified.protectedHeader! } +} + +export { compactVerify } +export default compactVerify +export type { KeyLike, VerifyOptions, CompactVerifyResult } diff --git a/dist/deno/jws/flattened/sign.ts b/dist/deno/jws/flattened/sign.ts new file mode 100644 index 0000000000..9c1c533258 --- /dev/null +++ b/dist/deno/jws/flattened/sign.ts @@ -0,0 +1,167 @@ +import isDisjoint from '../../lib/is_disjoint.ts' +import { JWSInvalid } from '../../util/errors.ts' +import { encoder, decoder, concat } from '../../lib/buffer_utils.ts' + +import { encode as base64url } from '../../runtime/base64url.ts' +import sign from '../../runtime/sign.ts' +import type { KeyLike, FlattenedJWS, JWSHeaderParameters, SignOptions } from '../../types.d.ts' +import checkKeyType from '../../lib/check_key_type.ts' +import validateCrit from '../../lib/validate_crit.ts' + +const checkExtensions = validateCrit.bind(undefined, JWSInvalid, new Map([['b64', true]])) + +/** + * The FlattenedSign class is a utility for creating Flattened JWS objects. + * + * @example ESM import + * ```js + * import { FlattenedSign } from 'jose/jws/flattened/sign' + * ``` + * + * @example CJS import + * ```js + * const { FlattenedSign } = require('jose/jws/flattened/sign') + * ``` + * + * @example Deno import + * ```js + * import { FlattenedSign } from 'https://deno.land/x/jose@VERSION/jws/flattened/sign.ts' + * ``` + * + * @example Usage + * ```js + * const encoder = new TextEncoder() + * + * 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) + * ``` + */ +class FlattenedSign { + private _payload: Uint8Array + + private _protectedHeader!: JWSHeaderParameters + + private _unprotectedHeader!: JWSHeaderParameters + + /** + * @param payload Binary representation of the payload to sign. + */ + constructor(payload: Uint8Array) { + if (!(payload instanceof Uint8Array)) { + throw new TypeError('payload must be an instance of 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. + * @param options JWS Sign options. + */ + async sign(key: KeyLike, options?: SignOptions): 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(options?.crit, 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 (typeof alg !== 'string' || !alg) { + throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid') + } + + checkKeyType(alg, key, 'sign') + + 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), + payload: '', + } + + 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 { FlattenedSign } +export default FlattenedSign +export type { KeyLike, FlattenedJWS, JWSHeaderParameters } diff --git a/dist/deno/jws/flattened/verify.ts b/dist/deno/jws/flattened/verify.ts new file mode 100644 index 0000000000..1f34f68fa5 --- /dev/null +++ b/dist/deno/jws/flattened/verify.ts @@ -0,0 +1,201 @@ +import { JOSEAlgNotAllowed, JWSInvalid, JWSSignatureVerificationFailed } from '../../util/errors.ts' +import { concat, encoder, decoder } from '../../lib/buffer_utils.ts' +import isDisjoint from '../../lib/is_disjoint.ts' +import isObject from '../../lib/is_object.ts' +import checkKeyType from '../../lib/check_key_type.ts' + +import { decode as base64url } from '../../runtime/base64url.ts' +import verify from '../../runtime/verify.ts' +import validateCrit from '../../lib/validate_crit.ts' +import validateAlgorithms from '../../lib/validate_algorithms.ts' + +import type { + FlattenedVerifyResult, + KeyLike, + FlattenedJWSInput, + JWSHeaderParameters, + VerifyOptions, + GetKeyFunction, +} from '../../types.d.ts' + +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. + * + * See [createRemoteJWKSet](../functions/jwks_remote.createRemoteJWKSet.md#function-createremotejwkset) + * to verify using a remote JSON Web Key Set. + */ +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 + * ```js + * import { flattenedVerify } from 'jose/jws/flattened/verify' + * ``` + * + * @example CJS import + * ```js + * const { flattenedVerify } = require('jose/jws/flattened/verify') + * ``` + * + * @example Deno import + * ```js + * import { flattenedVerify } from 'https://deno.land/x/jose@VERSION/jws/flattened/verify.ts' + * ``` + * + * @example Usage + * ```js + * const decoder = new TextDecoder() + * const jws = { + * signature: 'FVVOXwj6kD3DqdfD9yYqfT2W9jv-Nop4kOehp_DeDGNB5dQNSPRvntBY6xH3uxlCxE8na9d_kyhYOcanpDJ0EA', + * payload: 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4', + * protected: 'eyJhbGciOiJFUzI1NiJ9' + * } + * + * const { payload, protectedHeader } = await flattenedVerify(jws, publicKey) + * + * console.log(protectedHeader) + * console.log(decoder.decode(payload)) + * ``` + */ +async function flattenedVerify( + jws: FlattenedJWSInput, + key: KeyLike | FlattenedVerifyGetKey, + options?: VerifyOptions, +): Promise { + if (!isObject(jws)) { + throw new JWSInvalid('Flattened JWS must be an object') + } + + if (jws.protected === undefined && jws.header === undefined) { + throw new JWSInvalid('Flattened JWS must have either of the "protected" or "header" members') + } + + if (jws.protected !== undefined && typeof jws.protected !== 'string') { + throw new JWSInvalid('JWS Protected Header incorrect type') + } + + if (jws.payload === undefined) { + throw new JWSInvalid('JWS Payload missing') + } + + if (typeof jws.signature !== 'string') { + throw new JWSInvalid('JWS Signature missing or incorrect type') + } + + if (jws.header !== undefined && !isObject(jws.header)) { + throw new JWSInvalid('JWS Unprotected Header incorrect type') + } + + let parsedProt: JWSHeaderParameters = {} + if (jws.protected) { + const protectedHeader = base64url(jws.protected) + try { + parsedProt = JSON.parse(decoder.decode(protectedHeader)) + } catch { + throw new JWSInvalid('JWS Protected Header is invalid') + } + } + 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(options?.crit, 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 (typeof alg !== 'string' || !alg) { + throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid') + } + + 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') { + key = await key(parsedProt, jws) + } + + checkKeyType(alg, key, 'verify') + + 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 (jws.protected !== undefined) { + result.protectedHeader = parsedProt + } + + if (jws.header !== undefined) { + result.unprotectedHeader = jws.header + } + + return result +} + +export { flattenedVerify } +export default flattenedVerify +export type { + KeyLike, + FlattenedJWSInput, + GetKeyFunction, + JWSHeaderParameters, + VerifyOptions, + FlattenedVerifyResult, +} diff --git a/dist/deno/jws/general/sign.ts b/dist/deno/jws/general/sign.ts new file mode 100644 index 0000000000..ca0b280df2 --- /dev/null +++ b/dist/deno/jws/general/sign.ts @@ -0,0 +1,163 @@ +import FlattenedSign from '../flattened/sign.ts' +import { JWSInvalid } from '../../util/errors.ts' + +import type { KeyLike, GeneralJWS, JWSHeaderParameters, SignOptions } from '../../types.d.ts' + +export interface Signature { + /** + * Sets the JWS Protected Header on the Signature object. + * + * @param protectedHeader JWS Protected Header. + */ + setProtectedHeader(protectedHeader: JWSHeaderParameters): Signature + + /** + * Sets the JWS Unprotected Header on the Signature object. + * + * @param unprotectedHeader JWS Unprotected Header. + */ + setUnprotectedHeader(unprotectedHeader: JWSHeaderParameters): Signature +} + +interface SignatureReference { + protectedHeader?: JWSHeaderParameters + unprotectedHeader?: JWSHeaderParameters + options?: SignOptions + key: KeyLike +} + +const signatureRef: WeakMap = new WeakMap() + +class IndividualSignature implements Signature { + setProtectedHeader(protectedHeader: JWSHeaderParameters) { + if (this._protectedHeader) { + throw new TypeError('setProtectedHeader can only be called once') + } + this._protectedHeader = protectedHeader + return this + } + + setUnprotectedHeader(unprotectedHeader: JWSHeaderParameters) { + if (this._unprotectedHeader) { + throw new TypeError('setUnprotectedHeader can only be called once') + } + this._unprotectedHeader = unprotectedHeader + return this + } + + private set _protectedHeader(value: JWSHeaderParameters) { + signatureRef.get(this)!.protectedHeader = value + } + + private get _protectedHeader(): JWSHeaderParameters { + return signatureRef.get(this)!.protectedHeader! + } + + private set _unprotectedHeader(value: JWSHeaderParameters) { + signatureRef.get(this)!.unprotectedHeader = value + } + + private get _unprotectedHeader(): JWSHeaderParameters { + return signatureRef.get(this)!.unprotectedHeader! + } +} + +/** + * The GeneralSign class is a utility for creating General JWS objects. + * + * @example ESM import + * ```js + * import { GeneralSign } from 'jose/jws/general/sign' + * ``` + * + * @example CJS import + * ```js + * const { GeneralSign } = require('jose/jws/general/sign') + * ``` + * + * @example Deno import + * ```js + * import { GeneralSign } from 'https://deno.land/x/jose@VERSION/jws/general/sign.ts' + * ``` + * + * @example Usage + * ```js + * const encoder = new TextEncoder() + * + * const sign = new GeneralSign(encoder.encode('It’s a dangerous business, Frodo, going out your door.')) + * + * sign + * .addSignature(ecPrivateKey) + * .setProtectedHeader({ alg: 'ES256' }) + * + * sign + * .addSignature(rsaPrivateKey) + * .setProtectedHeader({ alg: 'PS256' }) + * + * const jws = await sign.sign() + * ``` + */ +class GeneralSign { + private _payload: Uint8Array + + private _signatures: IndividualSignature[] = [] + + /** + * @param payload Binary representation of the payload to sign. + */ + constructor(payload: Uint8Array) { + this._payload = payload + } + + addSignature(key: KeyLike, options?: SignOptions): Signature { + const signature = new IndividualSignature() + signatureRef.set(signature, { key, options }) + this._signatures.push(signature) + return signature + } + + /** + * Signs and resolves the value of the General JWS object. + */ + async sign(): Promise { + if (!this._signatures.length) { + throw new JWSInvalid('at least one signature must be added') + } + + const jws: GeneralJWS = { + signatures: [], + payload: '', + } + + let payloads = new Set() + await Promise.all( + this._signatures.map(async (sig) => { + const { protectedHeader, unprotectedHeader, options, key } = signatureRef.get(sig)! + const flattened = new FlattenedSign(this._payload) + + if (protectedHeader) { + flattened.setProtectedHeader(protectedHeader) + } + + if (unprotectedHeader) { + flattened.setUnprotectedHeader(unprotectedHeader) + } + + const { payload, ...rest } = await flattened.sign(key, options) + payloads.add(payload) + jws.payload = payload + jws.signatures.push(rest) + }), + ) + + if (payloads.size !== 1) { + throw new JWSInvalid('inconsistent use of JWS Unencoded Payload Option (RFC7797)') + } + + return jws + } +} + +export { GeneralSign } +export default GeneralSign +export type { KeyLike, GeneralJWS, JWSHeaderParameters } diff --git a/dist/deno/jws/general/verify.ts b/dist/deno/jws/general/verify.ts new file mode 100644 index 0000000000..2b1254961c --- /dev/null +++ b/dist/deno/jws/general/verify.ts @@ -0,0 +1,99 @@ +import verify from '../flattened/verify.ts' +import type { + GeneralJWSInput, + GeneralVerifyResult, + FlattenedJWSInput, + GetKeyFunction, + JWSHeaderParameters, + KeyLike, + VerifyOptions, +} from '../../types.d.ts' +import { JWSInvalid, JWSSignatureVerificationFailed } from '../../util/errors.ts' +import isObject from '../../lib/is_object.ts' + +/** + * Interface for General JWS Verification dynamic key resolution. + * No token components have been verified at the time of this function call. + * + * See [createRemoteJWKSet](../functions/jwks_remote.createRemoteJWKSet.md#function-createremotejwkset) + * to verify using a remote JSON Web Key Set. + */ +export interface GeneralVerifyGetKey + extends GetKeyFunction {} + +/** + * Verifies the signature and format of and afterwards decodes the General JWS. + * + * @param jws General JWS. + * @param key Key, or a function resolving a key, to verify the JWS with. + * @param options JWS Verify options. + * + * @example ESM import + * ```js + * import { generalVerify } from 'jose/jws/general/verify' + * ``` + * + * @example CJS import + * ```js + * const { generalVerify } = require('jose/jws/general/verify') + * ``` + * + * @example Deno import + * ```js + * import { generalVerify } from 'https://deno.land/x/jose@VERSION/jws/general/verify.ts' + * ``` + * + * @example Usage + * ```js + * const decoder = new TextDecoder() + * const jws = { + * payload: 'SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4', + * signatures: [ + * { + * signature: 'FVVOXwj6kD3DqdfD9yYqfT2W9jv-Nop4kOehp_DeDGNB5dQNSPRvntBY6xH3uxlCxE8na9d_kyhYOcanpDJ0EA', + * protected: 'eyJhbGciOiJFUzI1NiJ9' + * } + * ] + * } + * + * const { payload, protectedHeader } = await generalVerify(jws, publicKey) + * + * console.log(protectedHeader) + * console.log(decoder.decode(payload)) + * ``` + */ +async function generalVerify( + jws: GeneralJWSInput, + key: KeyLike | GeneralVerifyGetKey, + options?: VerifyOptions, +): Promise { + if (!isObject(jws)) { + throw new JWSInvalid('General JWS must be an object') + } + + if (!Array.isArray(jws.signatures) || !jws.signatures.every(isObject)) { + throw new JWSInvalid('JWS Signatures missing or incorrect type') + } + + for (const signature of jws.signatures) { + try { + return await verify( + { + header: signature.header, + payload: jws.payload, + protected: signature.protected, + signature: signature.signature, + }, + [1]>key, + options, + ) + } catch { + // + } + } + throw new JWSSignatureVerificationFailed() +} + +export { generalVerify } +export default generalVerify +export type { KeyLike, GeneralJWSInput, VerifyOptions, GeneralVerifyResult } diff --git a/dist/deno/jwt/decrypt.ts b/dist/deno/jwt/decrypt.ts new file mode 100644 index 0000000000..f663816c67 --- /dev/null +++ b/dist/deno/jwt/decrypt.ts @@ -0,0 +1,103 @@ +import decrypt from '../jwe/compact/decrypt.ts' +import type { + KeyLike, + DecryptOptions, + JWTPayload, + JWTClaimVerificationOptions, + GetKeyFunction, + JWEHeaderParameters, + FlattenedJWE, + JWTDecryptResult, +} from '../types.d.ts' +import jwtPayload from '../lib/jwt_claims_set.ts' +import { JWTClaimValidationFailed } from '../util/errors.ts' + +/** + * 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 + * ```js + * import { jwtDecrypt } from 'jose/jwt/decrypt' + * ``` + * + * @example CJS import + * ```js + * const { jwtDecrypt } = require('jose/jwt/decrypt') + * ``` + * + * @example Deno import + * ```js + * import { jwtDecrypt } from 'https://deno.land/x/jose@VERSION/jwt/decrypt.ts' + * ``` + * + * @example Usage + * ```js + * const jwt = 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..KVcNLqK-3-8ZkYIC.xSwF4VxO0kUMUD2W-cifsNUxnr-swyBq-nADBptyt6y9n79-iNc5b0AALJpRwc0wwDkJw8hNOMjApNUTMsK9b-asToZ3DXFMvwfJ6n1aWefvd7RsoZ2LInWFfVAuttJDzoGB.uuexQoWHwrLMEYRElT8pBQ' + * + * const { payload, protectedHeader } = await jwtDecrypt(jwt, secretKey, { + * issuer: 'urn:example:issuer', + * audience: 'urn:example:audience' + * }) + * + * console.log(protectedHeader) + * console.log(payload) + * ``` + */ +async function jwtDecrypt( + jwt: string | Uint8Array, + 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 (protectedHeader.iss !== undefined && protectedHeader.iss !== payload.iss) { + throw new JWTClaimValidationFailed( + 'replicated "iss" claim header parameter mismatch', + 'iss', + 'mismatch', + ) + } + + if (protectedHeader.sub !== undefined && protectedHeader.sub !== payload.sub) { + throw new JWTClaimValidationFailed( + 'replicated "sub" claim header parameter mismatch', + 'sub', + 'mismatch', + ) + } + + if ( + protectedHeader.aud !== undefined && + JSON.stringify(protectedHeader.aud) !== JSON.stringify(payload.aud) + ) { + throw new JWTClaimValidationFailed( + 'replicated "aud" claim header parameter mismatch', + 'aud', + 'mismatch', + ) + } + + return { payload, protectedHeader } +} + +export { jwtDecrypt } +export default jwtDecrypt +export type { KeyLike, DecryptOptions, JWTPayload, JWTDecryptOptions, JWTDecryptResult } diff --git a/dist/deno/jwt/encrypt.ts b/dist/deno/jwt/encrypt.ts new file mode 100644 index 0000000000..0291e982c9 --- /dev/null +++ b/dist/deno/jwt/encrypt.ts @@ -0,0 +1,181 @@ +import CompactEncrypt from '../jwe/compact/encrypt.ts' +import type { + EncryptOptions, + JWEHeaderParameters, + JWEKeyManagementHeaderParameters, + JWTPayload, + KeyLike, +} from '../types.d.ts' +import { encoder } from '../lib/buffer_utils.ts' +import ProduceJWT from '../lib/jwt_producer.ts' + +/** + * The EncryptJWT class is a utility for creating Compact JWE formatted JWT strings. + * + * @example ESM import + * ```js + * import { EncryptJWT } from 'jose/jwt/encrypt' + * ``` + * + * @example CJS import + * ```js + * const { EncryptJWT } = require('jose/jwt/encrypt') + * ``` + * + * @example Deno import + * ```js + * import { EncryptJWT } from 'https://deno.land/x/jose@VERSION/jwt/encrypt.ts' + * ``` + * + * @example Usage + * ```js + * 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) + * ``` + */ +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 { EncryptJWT } +export default EncryptJWT +export type { JWEHeaderParameters, JWTPayload, KeyLike } diff --git a/dist/deno/jwt/sign.ts b/dist/deno/jwt/sign.ts new file mode 100644 index 0000000000..a86bb5f3c8 --- /dev/null +++ b/dist/deno/jwt/sign.ts @@ -0,0 +1,73 @@ +import CompactSign from '../jws/compact/sign.ts' +import { JWTInvalid } from '../util/errors.ts' +import type { JWSHeaderParameters, JWTPayload, KeyLike, SignOptions } from '../types.d.ts' +import { encoder } from '../lib/buffer_utils.ts' +import ProduceJWT from '../lib/jwt_producer.ts' + +/** + * The SignJWT class is a utility for creating Compact JWS formatted JWT strings. + * + * @example ESM import + * ```js + * import { SignJWT } from 'jose/jwt/sign' + * ``` + * + * @example CJS import + * ```js + * const { SignJWT } = require('jose/jwt/sign') + * ``` + * + * @example Deno import + * ```js + * import { SignJWT } from 'https://deno.land/x/jose@VERSION/jwt/sign.ts' + * ``` + * + * @example Usage + * ```js + * 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) + * ``` + */ +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. + * @param options JWT Sign options. + */ + async sign(key: KeyLike, options?: SignOptions): Promise { + const sig = new CompactSign(encoder.encode(JSON.stringify(this._payload))) + sig.setProtectedHeader(this._protectedHeader) + if ( + Array.isArray(this._protectedHeader?.crit) && + this._protectedHeader.crit.includes('b64') && + this._protectedHeader.b64 === false + ) { + throw new JWTInvalid('JWTs MUST NOT use unencoded payload') + } + return sig.sign(key, options) + } +} + +export { SignJWT } +export default SignJWT +export type { JWSHeaderParameters, JWTPayload, KeyLike } diff --git a/dist/deno/jwt/unsecured.ts b/dist/deno/jwt/unsecured.ts new file mode 100644 index 0000000000..c4f330bd0a --- /dev/null +++ b/dist/deno/jwt/unsecured.ts @@ -0,0 +1,96 @@ +import type { JWSHeaderParameters, JWTClaimVerificationOptions, JWTPayload } from '../types.d.ts' +import { decoder } from '../lib/buffer_utils.ts' +import * as base64url from '../runtime/base64url.ts' +import { JWTInvalid } from '../util/errors.ts' +import jwtPayload from '../lib/jwt_claims_set.ts' +import ProduceJWT from '../lib/jwt_producer.ts' + +interface UnsecuredResult { + payload: JWTPayload + header: JWSHeaderParameters +} + +/** + * The UnsecuredJWT class is a utility for dealing with `{ "alg": "none" }` Unsecured JWTs. + * + * @example ESM import + * ```js + * import { UnsecuredJWT } from 'jose/jwt/unsecured' + * ``` + * + * @example CJS import + * ```js + * const { UnsecuredJWT } = require('jose/jwt/unsecured') + * ``` + * + * @example Deno import + * ```js + * import { UnsecuredJWT } from 'https://deno.land/x/jose@VERSION/jwt/unsecured.ts' + * ``` + * + * @example Encoding + * ```js * + * 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 + * ```js * + * const payload = new UnsecuredJWT.decode(jwt, { + * issuer: 'urn:example:issuer', + * audience: 'urn:example:audience' + * }) + * + * console.log(payload) + * ``` + */ +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. + */ + static decode(jwt: string, options?: JWTClaimVerificationOptions): UnsecuredResult { + 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 { UnsecuredJWT } +export default UnsecuredJWT +export type { JWSHeaderParameters, JWTPayload, UnsecuredResult } diff --git a/dist/deno/jwt/verify.ts b/dist/deno/jwt/verify.ts new file mode 100644 index 0000000000..28e5573768 --- /dev/null +++ b/dist/deno/jwt/verify.ts @@ -0,0 +1,86 @@ +import verify from '../jws/compact/verify.ts' +import type { + KeyLike, + VerifyOptions, + JWTPayload, + JWTClaimVerificationOptions, + JWSHeaderParameters, + GetKeyFunction, + FlattenedJWSInput, + JWTVerifyResult, +} from '../types.d.ts' +import jwtPayload from '../lib/jwt_claims_set.ts' +import { JWTInvalid } from '../util/errors.ts' + +/** + * 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. + * + * See [createRemoteJWKSet](../functions/jwks_remote.createRemoteJWKSet.md#function-createremotejwkset) + * to verify using a remote JSON Web Key Set. + */ +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 + * ```js + * import { jwtVerify } from 'jose/jwt/verify' + * ``` + * + * @example CJS import + * ```js + * const { jwtVerify } = require('jose/jwt/verify') + * ``` + * + * @example Deno import + * ```js + * import { jwtVerify } from 'https://deno.land/x/jose@VERSION/jwt/verify.ts' + * ``` + * + * @example Usage + * ```js + * const jwt = 'eyJhbGciOiJFUzI1NiJ9.eyJ1cm46ZXhhbXBsZTpjbGFpbSI6dHJ1ZSwiaWF0IjoxNjA0MzE1MDc0LCJpc3MiOiJ1cm46ZXhhbXBsZTppc3N1ZXIiLCJhdWQiOiJ1cm46ZXhhbXBsZTphdWRpZW5jZSJ9.hx1nOfAT5LlXuzu8O-bhjXBGpklWDt2EsHw7-MDn49NrnwvVsstNhEnkW2ddauB7eSikFtUNeumLpFI9CWDBsg' + * + * const { payload, protectedHeader } = await jwtVerify(jwt, publicKey, { + * issuer: 'urn:example:issuer', + * audience: 'urn:example:audience' + * }) + * + * console.log(protectedHeader) + * console.log(payload) + * ``` + */ +async function jwtVerify( + jwt: string | Uint8Array, + key: KeyLike | JWTVerifyGetKey, + options?: JWTVerifyOptions, +): Promise { + const verified = await verify(jwt, key, options) + if (verified.protectedHeader.crit?.includes('b64') && verified.protectedHeader.b64 === false) { + throw new JWTInvalid('JWTs MUST NOT use unencoded payload') + } + const payload = jwtPayload(verified.protectedHeader, verified.payload, options) + return { payload, protectedHeader: verified.protectedHeader } +} + +export { jwtVerify } +export default jwtVerify +export type { + KeyLike, + JWTPayload, + JWTVerifyOptions, + JWSHeaderParameters, + GetKeyFunction, + JWTVerifyResult, +} diff --git a/dist/deno/lib/buffer_utils.ts b/dist/deno/lib/buffer_utils.ts new file mode 100644 index 0000000000..8a766438fe --- /dev/null +++ b/dist/deno/lib/buffer_utils.ts @@ -0,0 +1,71 @@ +import type { DigestFunction } from '../runtime/interfaces.d.ts' + +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: DigestFunction, + 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('sha256', buf) + } else { + res = concat(res, await digest('sha256', buf)) + } + } + res = res.slice(0, bits >> 3) + return res +} diff --git a/dist/deno/lib/cek.ts b/dist/deno/lib/cek.ts new file mode 100644 index 0000000000..1851ede8e0 --- /dev/null +++ b/dist/deno/lib/cek.ts @@ -0,0 +1,24 @@ +import { JOSENotSupported } from '../util/errors.ts' + +const bitLengths = new Map([ + ['A128CBC-HS256', 256], + ['A128GCM', 128], + ['A192CBC-HS384', 384], + ['A192GCM', 192], + ['A256CBC-HS512', 512], + ['A256GCM', 256], +]) + +const factory = + (random: (array: Uint8Array) => Uint8Array) => + (alg: string): Uint8Array => { + 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/dist/deno/lib/check_iv_length.ts b/dist/deno/lib/check_iv_length.ts new file mode 100644 index 0000000000..c6ba9d5739 --- /dev/null +++ b/dist/deno/lib/check_iv_length.ts @@ -0,0 +1,10 @@ +import { JWEInvalid } from '../util/errors.ts' +import { bitLengths } from './iv.ts' + +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/dist/deno/lib/check_key_type.ts b/dist/deno/lib/check_key_type.ts new file mode 100644 index 0000000000..eb3057e8d1 --- /dev/null +++ b/dist/deno/lib/check_key_type.ts @@ -0,0 +1,51 @@ +import type { KeyLike } from '../types.d.ts' +import invalidKeyInput from '../runtime/invalid_key_input.ts' + +const checkKeyType = ( + alg: string, + key: KeyLike, + usage: 'sign' | 'verify' | 'encrypt' | 'decrypt', +): void => { + if (!(key instanceof Uint8Array) && !key?.type) { + throw new TypeError(invalidKeyInput(key, 'KeyObject', 'CryptoKey', 'Uint8Array')) + } + + 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(invalidKeyInput(key, 'KeyObject', 'CryptoKey')) + } + + if (key.type === 'secret') { + throw new TypeError( + 'CryptoKey or KeyObject instances for asymmetric algorithms must not be of type "secret"', + ) + } + + if (usage === 'sign' && key.type === 'public') { + throw new TypeError( + 'CryptoKey or KeyObject instances for asymmetric algorithm signing must be of type "private"', + ) + } + + if (usage === 'decrypt' && key.type === 'public') { + throw new TypeError( + 'CryptoKey or KeyObject instances for asymmetric algorithm decryption must be of type "private"', + ) + } +} + +export default checkKeyType diff --git a/dist/deno/lib/check_p2s.ts b/dist/deno/lib/check_p2s.ts new file mode 100644 index 0000000000..53c6d9c85f --- /dev/null +++ b/dist/deno/lib/check_p2s.ts @@ -0,0 +1,7 @@ +import { JWEInvalid } from '../util/errors.ts' + +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/dist/deno/lib/decrypt_key_management.ts b/dist/deno/lib/decrypt_key_management.ts new file mode 100644 index 0000000000..72628cad96 --- /dev/null +++ b/dist/deno/lib/decrypt_key_management.ts @@ -0,0 +1,128 @@ +import type { JWEHeaderParameters, KeyLike } from '../types.d.ts' +import type { JWEKeyManagementHeaderResults } from '../types.i.d.ts' +import { JOSENotSupported, JWEInvalid } from '../util/errors.ts' +import { unwrap as aesKw } from '../runtime/aeskw.ts' +import * as ECDH from '../runtime/ecdhes.ts' +import { decrypt as pbes2Kw } from '../runtime/pbes2kw.ts' +import { decrypt as rsaEs } from '../runtime/rsaes.ts' +import { unwrap as aesGcmKw } from '../runtime/aesgcmkw.ts' +import { decode as base64url } from '../runtime/base64url.ts' +import { bitLengths as cekLengths } from '../lib/cek.ts' +import { parseJwk } from '../jwk/parse.ts' +import checkKeyType from './check_key_type.ts' + +function assertEnryptedKey(encryptedKey: unknown) { + if (!encryptedKey) { + throw new JWEInvalid('JWE Encrypted Key missing') + } +} + +function assertHeaderParameter( + joseHeader: { [propName: string]: unknown }, + parameter: string, + name: string, +) { + if (joseHeader[parameter] === undefined) { + throw new JWEInvalid(`JOSE Header ${name} (${parameter}) missing`) + } +} + +async function decryptKeyManagement( + alg: string, + key: KeyLike, + encryptedKey: Uint8Array | undefined, + joseHeader: JWEKeyManagementHeaderResults & JWEHeaderParameters, +): Promise { + checkKeyType(alg, key, 'decrypt') + + 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') + } + 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-ES with the provided key is not allowed or not supported by your javascript runtime', + ) + } + const epk = await parseJwk(joseHeader.epk!, alg) + let partyUInfo!: Uint8Array + let partyVInfo!: Uint8Array + if (joseHeader.apu !== undefined) partyUInfo = base64url(joseHeader.apu) + if (joseHeader.apv !== undefined) partyVInfo = base64url(joseHeader.apv) + const sharedSecret = await ECDH.deriveKey( + epk, + key, + alg === 'ECDH-ES' ? joseHeader.enc! : alg, + parseInt(alg.substr(-5, 3), 10) || cekLengths.get(joseHeader.enc!), + 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('unsupported or invalid "alg" (JWE Algorithm) header value') + } + } +} + +export default decryptKeyManagement diff --git a/dist/deno/lib/encrypt_key_management.ts b/dist/deno/lib/encrypt_key_management.ts new file mode 100644 index 0000000000..572c9c2efb --- /dev/null +++ b/dist/deno/lib/encrypt_key_management.ts @@ -0,0 +1,121 @@ +import type { KeyLike, JWEKeyManagementHeaderParameters } from '../types.d.ts' +import type { JWEKeyManagementHeaderResults } from '../types.i.d.ts' +import cekFactory, { bitLengths as cekLengths } from '../lib/cek.ts' +import { JOSENotSupported } from '../util/errors.ts' +import random from '../runtime/random.ts' +import { wrap as aesKw } from '../runtime/aeskw.ts' +import * as ECDH from '../runtime/ecdhes.ts' +import { encrypt as pbes2Kw } from '../runtime/pbes2kw.ts' +import { encrypt as rsaEs } from '../runtime/rsaes.ts' +import { wrap as aesGcmKw } from '../runtime/aesgcmkw.ts' +import { encode as base64url } from '../runtime/base64url.ts' +import { fromKeyLike } from '../jwk/from_key_like.ts' +import checkKeyType from './check_key_type.ts' + +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 + + checkKeyType(alg, key, 'encrypt') + + 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-ES with the provided key is not allowed or not supported by your javascript runtime', + ) + } + const { apu, apv } = providedParameters + let { epk: ephemeralKey } = providedParameters + ephemeralKey ||= await ECDH.generateEpk(key) + const { x, y, crv, kty } = await fromKeyLike(ephemeralKey) + const sharedSecret = await ECDH.deriveKey( + key, + ephemeralKey, + alg === 'ECDH-ES' ? enc : alg, + parseInt(alg.substr(-5, 3), 10) || cekLengths.get(enc), + apu, + apv, + ) + parameters = { epk: { x, y, crv, kty } } + 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 || 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 || 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 || 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 || generateCek(enc) + encryptedKey = await aesKw(alg, key, cek) + break + } + case 'A128GCMKW': + case 'A192GCMKW': + case 'A256GCMKW': { + // Key Wrapping (AES GCM KW) + cek = providedCek || generateCek(enc) + const { iv } = providedParameters + ;({ encryptedKey, ...parameters } = await aesGcmKw(alg, key, cek, iv)) + break + } + default: { + throw new JOSENotSupported('unsupported or invalid "alg" (JWE Algorithm) header value') + } + } + + return { cek, encryptedKey, parameters } +} + +export default encryptKeyManagement diff --git a/dist/deno/lib/epoch.ts b/dist/deno/lib/epoch.ts new file mode 100644 index 0000000000..616795a52e --- /dev/null +++ b/dist/deno/lib/epoch.ts @@ -0,0 +1 @@ +export default (date: Date) => Math.floor(date.getTime() / 1000) diff --git a/dist/deno/lib/is_disjoint.ts b/dist/deno/lib/is_disjoint.ts new file mode 100644 index 0000000000..c260352e76 --- /dev/null +++ b/dist/deno/lib/is_disjoint.ts @@ -0,0 +1,26 @@ +const isDisjoint = (...headers: Array) => { + const sources = headers.filter(Boolean) + + 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/dist/deno/lib/is_object.ts b/dist/deno/lib/is_object.ts new file mode 100644 index 0000000000..f5afee9b47 --- /dev/null +++ b/dist/deno/lib/is_object.ts @@ -0,0 +1,17 @@ +function isObjectLike(value: unknown) { + return typeof value === 'object' && value !== null +} + +export default function isObject(input: unknown): boolean { + if (!isObjectLike(input) || Object.prototype.toString.call(input) !== '[object Object]') { + return false + } + if (Object.getPrototypeOf(input) === null) { + return true + } + let proto = input + while (Object.getPrototypeOf(proto) !== null) { + proto = Object.getPrototypeOf(proto) + } + return Object.getPrototypeOf(input) === proto +} diff --git a/dist/deno/lib/iv.ts b/dist/deno/lib/iv.ts new file mode 100644 index 0000000000..11dc881fb0 --- /dev/null +++ b/dist/deno/lib/iv.ts @@ -0,0 +1,27 @@ +import { JOSENotSupported } from '../util/errors.ts' + +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) => Uint8Array) => + (alg: string): Uint8Array => { + 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/dist/deno/lib/jwt_claims_set.ts b/dist/deno/lib/jwt_claims_set.ts new file mode 100644 index 0000000000..68b2164078 --- /dev/null +++ b/dist/deno/lib/jwt_claims_set.ts @@ -0,0 +1,148 @@ +import type { + JWTPayload, + JWTClaimVerificationOptions, + JWEHeaderParameters, + JWSHeaderParameters, +} from '../types.d.ts' +import { JWTClaimValidationFailed, JWTExpired, JWTInvalid } from '../util/errors.ts' +import { decoder } from './buffer_utils.ts' +import epoch from './epoch.ts' +import secs from './secs.ts' +import isObject from './is_object.ts' + +const normalizeTyp = (value: string) => value.toLowerCase().replace(/^application\//, '') + +const checkAudiencePresence = (audPayload: unknown, audOption: unknown[]) => { + if (typeof audPayload === 'string') { + return audOption.includes(audPayload) + } + + if (Array.isArray(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))) + } + + return false +} + +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!: { [propName: string]: unknown } + try { + payload = JSON.parse(decoder.decode(encodedPayload)) + } catch { + // + } + + if (!isObject(payload)) { + throw new JWTInvalid('JWT Claims Set must be a top-level JSON object') + } + + const { issuer } = options + if (issuer && !((Array.isArray(issuer) ? 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 (payload.iat !== undefined || options.maxTokenAge) { + if (typeof payload.iat !== 'number') { + throw new JWTClaimValidationFailed('"iat" claim must be a number', 'iat', 'invalid') + } + if (payload.exp === undefined && payload.iat > now + tolerance) { + throw new JWTClaimValidationFailed( + '"iat" claim timestamp check failed (it should be in the past)', + 'iat', + 'check_failed', + ) + } + } + + if (payload.nbf !== undefined) { + 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 (payload.exp !== undefined) { + 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/dist/deno/lib/jwt_producer.ts b/dist/deno/lib/jwt_producer.ts new file mode 100644 index 0000000000..44f12657be --- /dev/null +++ b/dist/deno/lib/jwt_producer.ts @@ -0,0 +1,108 @@ +import type { JWTPayload } from '../types.d.ts' +import epoch from './epoch.ts' +import isObject from './is_object.ts' +import secs from './secs.ts' + +/** + * 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/dist/deno/lib/secs.ts b/dist/deno/lib/secs.ts new file mode 100644 index 0000000000..8d9f07f7de --- /dev/null +++ b/dist/deno/lib/secs.ts @@ -0,0 +1,51 @@ +const minute = 60 +const hour = minute * 60 +const day = hour * 24 +const week = day * 7 +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 + +export default (str: string): number => { + const matched = REGEX.exec(str) + + if (!matched) { + throw new TypeError('Invalid time period format') + } + + const value = parseFloat(matched[1]) + const unit = matched[2].toLowerCase() + + switch (unit) { + case 'sec': + case 'secs': + case 'second': + case 'seconds': + case 's': + return Math.round(value) + case 'minute': + case 'minutes': + case 'min': + case 'mins': + case 'm': + return Math.round(value * minute) + case 'hour': + case 'hours': + case 'hr': + case 'hrs': + case 'h': + return Math.round(value * hour) + case 'day': + case 'days': + case 'd': + return Math.round(value * day) + case 'week': + case 'weeks': + case 'w': + return Math.round(value * week) + // years matched + default: + return Math.round(value * year) + } +} diff --git a/dist/deno/lib/validate_algorithms.ts b/dist/deno/lib/validate_algorithms.ts new file mode 100644 index 0000000000..870efaa6ef --- /dev/null +++ b/dist/deno/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/dist/deno/lib/validate_crit.ts b/dist/deno/lib/validate_crit.ts new file mode 100644 index 0000000000..d5ea76dc55 --- /dev/null +++ b/dist/deno/lib/validate_crit.ts @@ -0,0 +1,56 @@ +import { JOSENotSupported, JWEInvalid, JWSInvalid } from '../util/errors.ts' + +interface CritCheckHeader { + b64?: boolean + crit?: string[] + [propName: string]: unknown +} + +function validateCrit( + Err: typeof JWEInvalid | typeof JWSInvalid, + recognizedDefault: Map, + recognizedOption: { [propName: string]: boolean } | undefined, + protectedHeader: CritCheckHeader, + joseHeader: CritCheckHeader, +) { + if (joseHeader.crit !== undefined && protectedHeader.crit === undefined) { + throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected') + } + + if (!protectedHeader || protectedHeader.crit === undefined) { + return new Set() + } + + if ( + !Array.isArray(protectedHeader.crit) || + protectedHeader.crit.length === 0 || + protectedHeader.crit.some((input: string) => typeof input !== 'string' || input.length === 0) + ) { + throw new Err( + '"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present', + ) + } + + let recognized: Map + if (recognizedOption !== undefined) { + recognized = new Map([...Object.entries(recognizedOption), ...recognizedDefault.entries()]) + } else { + recognized = recognizedDefault + } + + for (const parameter of protectedHeader.crit) { + if (!recognized.has(parameter)) { + throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`) + } + + if (joseHeader[parameter] === undefined) { + throw new Err(`Extension Header Parameter "${parameter}" is missing`) + } else if (recognized.get(parameter) && protectedHeader[parameter] === undefined) { + throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`) + } + } + + return new Set(protectedHeader.crit) +} + +export default validateCrit diff --git a/dist/deno/runtime/aesgcmkw.ts b/dist/deno/runtime/aesgcmkw.ts new file mode 100644 index 0000000000..159c94e3a2 --- /dev/null +++ b/dist/deno/runtime/aesgcmkw.ts @@ -0,0 +1,39 @@ +import type { AesGcmKwUnwrapFunction, AesGcmKwWrapFunction } from './interfaces.d.ts' +import encrypt from './encrypt.ts' +import decrypt from './decrypt.ts' +import ivFactory from '../lib/iv.ts' +import random from './random.ts' +import { encode as base64url } from './base64url.ts' + +const generateIv = ivFactory(random) + +export const wrap: AesGcmKwWrapFunction = async ( + alg: string, + key: unknown, + cek: Uint8Array, + iv?: Uint8Array, +) => { + const jweAlgorithm = alg.substr(0, 7) + iv ||= generateIv(jweAlgorithm) + + const { ciphertext: encryptedKey, tag } = await encrypt( + jweAlgorithm, + cek, + key, + iv, + new Uint8Array(0), + ) + + return { encryptedKey, iv: base64url(iv), tag: base64url(tag) } +} + +export const unwrap: AesGcmKwUnwrapFunction = async ( + alg: string, + key: unknown, + encryptedKey: Uint8Array, + iv: Uint8Array, + tag: Uint8Array, +) => { + const jweAlgorithm = alg.substr(0, 7) + return decrypt(jweAlgorithm, key, encryptedKey, iv, tag, new Uint8Array(0)) +} diff --git a/dist/deno/runtime/aeskw.ts b/dist/deno/runtime/aeskw.ts new file mode 100644 index 0000000000..dad57810c0 --- /dev/null +++ b/dist/deno/runtime/aeskw.ts @@ -0,0 +1,56 @@ +import type { AesKwUnwrapFunction, AesKwWrapFunction } from './interfaces.d.ts' +import bogusWebCrypto from './bogus.ts' +import crypto, { isCryptoKey } from './webcrypto.ts' +import invalidKeyInput from './invalid_key_input.ts' + +function checkKeySize(key: CryptoKey, alg: string) { + // @ts-ignore + if ((key.algorithm).length !== parseInt(alg.substr(1, 3), 10)) { + throw new TypeError(`invalid key size for alg: ${alg}`) + } +} + +function getCryptoKey(key: unknown, usage: KeyUsage) { + if (isCryptoKey(key)) { + return key + } + + if (key instanceof Uint8Array) { + return crypto.subtle.importKey('raw', key, 'AES-KW', true, [usage]) + } + + throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'Uint8Array')) +} + +export const wrap: AesKwWrapFunction = async (alg: string, key: unknown, cek: Uint8Array) => { + const cryptoKey = await getCryptoKey(key, 'wrapKey') + + 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) + + // @ts-ignore + return new Uint8Array(await crypto.subtle.wrapKey('raw', cryptoKeyCek, cryptoKey, 'AES-KW')) +} + +export const unwrap: AesKwUnwrapFunction = async ( + alg: string, + key: unknown, + encryptedKey: Uint8Array, +) => { + const cryptoKey = await getCryptoKey(key, 'unwrapKey') + + checkKeySize(cryptoKey, alg) + + // @ts-ignore + const cryptoKeyCek = await crypto.subtle.unwrapKey( + 'raw', + encryptedKey, + cryptoKey, + 'AES-KW', + ...bogusWebCrypto, + ) + + return new Uint8Array(await crypto.subtle.exportKey('raw', cryptoKeyCek)) +} diff --git a/dist/deno/runtime/base64url.ts b/dist/deno/runtime/base64url.ts new file mode 100644 index 0000000000..9bc611a646 --- /dev/null +++ b/dist/deno/runtime/base64url.ts @@ -0,0 +1,35 @@ +import { encoder, decoder } from '../lib/buffer_utils.ts' +import globalThis from './global.ts' + +export const encode = (input: Uint8Array | string) => { + let unencoded = input + if (typeof unencoded === 'string') { + unencoded = encoder.encode(unencoded) + } + const CHUNK_SIZE = 0x8000 + const arr = [] + for (let i = 0; i < unencoded.length; i += CHUNK_SIZE) { + // @ts-expect-error + arr.push(String.fromCharCode.apply(null, unencoded.subarray(i, i + CHUNK_SIZE))) + } + const base64string = globalThis.btoa(arr.join('')) + return base64string.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_') +} + +export const decode = (input: Uint8Array | string) => { + let encoded = input + if (encoded instanceof Uint8Array) { + encoded = decoder.decode(encoded) + } + encoded = encoded.replace(/-/g, '+').replace(/_/g, '/').replace(/\s/g, '') + try { + return new Uint8Array( + globalThis + .atob(encoded) + .split('') + .map((c) => c.charCodeAt(0)), + ) + } catch { + throw new TypeError('The input to be decoded is not correctly encoded.') + } +} diff --git a/dist/deno/runtime/bogus.ts b/dist/deno/runtime/bogus.ts new file mode 100644 index 0000000000..cbae5153ff --- /dev/null +++ b/dist/deno/runtime/bogus.ts @@ -0,0 +1,7 @@ +const bogusWebCrypto: [HmacImportParams, boolean, KeyUsage[]] = [ + { hash: { name: 'SHA-256' }, name: 'HMAC' }, + true, + ['sign'], +] + +export default bogusWebCrypto diff --git a/dist/deno/runtime/check_cek_length.ts b/dist/deno/runtime/check_cek_length.ts new file mode 100644 index 0000000000..6311065323 --- /dev/null +++ b/dist/deno/runtime/check_cek_length.ts @@ -0,0 +1,46 @@ +import { JWEInvalid, JOSENotSupported } from '../util/errors.ts' +import { isCryptoKey } from './webcrypto.ts' + +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 not supported 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 (isCryptoKey(cek)) { + // @ts-ignore + const { length } = cek.algorithm + if (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/dist/deno/runtime/check_key_length.ts b/dist/deno/runtime/check_key_length.ts new file mode 100644 index 0000000000..c174fe2717 --- /dev/null +++ b/dist/deno/runtime/check_key_length.ts @@ -0,0 +1,18 @@ +export default (alg: string, key: CryptoKey) => { + if (alg.startsWith('HS')) { + const bitlen = parseInt(alg.substr(-3), 10) + // @ts-ignore + const { length } = key.algorithm + if (typeof length !== 'number' || length < bitlen) { + throw new TypeError(`${alg} requires symmetric keys to be ${bitlen} bits or larger`) + } + } + + if (alg.startsWith('RS') || alg.startsWith('PS')) { + // @ts-ignore + const { modulusLength } = key.algorithm + if (typeof modulusLength !== 'number' || modulusLength < 2048) { + throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`) + } + } +} diff --git a/dist/deno/runtime/decrypt.ts b/dist/deno/runtime/decrypt.ts new file mode 100644 index 0000000000..2976830f0b --- /dev/null +++ b/dist/deno/runtime/decrypt.ts @@ -0,0 +1,129 @@ +import { concat, uint64be } from '../lib/buffer_utils.ts' + +import type { DecryptFunction } from './interfaces.d.ts' +import checkIvLength from '../lib/check_iv_length.ts' +import checkCekLength from './check_cek_length.ts' +import timingSafeEqual from './timing_safe_equal.ts' +import { JOSENotSupported, JWEDecryptionFailed } from '../util/errors.ts' +import crypto, { isCryptoKey } from './webcrypto.ts' +import invalidKeyInput from './invalid_key_input.ts' + +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.subarray(keySize >> 3), + 'AES-CBC', + false, + ['decrypt'], + ) + const macKey = await crypto.subtle.importKey( + 'raw', + cek.subarray(0, keySize >> 3), + { + hash: { name: `SHA-${keySize << 1}` }, + name: 'HMAC', + }, + false, + ['sign'], + ) + + 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 (!macCheckPassed) { + throw new JWEDecryptionFailed() + } + + let plaintext!: Uint8Array + try { + plaintext = new Uint8Array( + // @ts-ignore + await crypto.subtle.decrypt({ iv, name: 'AES-CBC' }, encKey, ciphertext), + ) + } catch { + // + } + if (!plaintext) { + 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( + // @ts-ignore + await crypto.subtle.decrypt( + { + additionalData: aad, + iv, + name: 'AES-GCM', + tagLength: 128, + }, + encKey, + concat(ciphertext, tag), + ), + ) + } catch { + throw new JWEDecryptionFailed() + } +} + +const decrypt: DecryptFunction = async ( + enc: string, + cek: unknown, + ciphertext: Uint8Array, + iv: Uint8Array, + tag: Uint8Array, + aad: Uint8Array, +) => { + if (!isCryptoKey(cek) && !(cek instanceof Uint8Array)) { + throw new TypeError(invalidKeyInput(cek, 'CryptoKey', 'Uint8Array')) + } + + checkCekLength(enc, cek) + checkIvLength(enc, iv) + + switch (enc) { + case 'A128CBC-HS256': + case 'A192CBC-HS384': + case 'A256CBC-HS512': + return cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) + case 'A128GCM': + case 'A192GCM': + case 'A256GCM': + return gcmDecrypt(cek, ciphertext, iv, tag, aad) + default: + throw new JOSENotSupported('unsupported JWE Content Encryption Algorithm') + } +} + +export default decrypt diff --git a/dist/deno/runtime/digest.ts b/dist/deno/runtime/digest.ts new file mode 100644 index 0000000000..46a3438375 --- /dev/null +++ b/dist/deno/runtime/digest.ts @@ -0,0 +1,11 @@ +import crypto from './webcrypto.ts' +import type { DigestFunction } from './interfaces.d.ts' + +const digest: DigestFunction = async ( + algorithm: 'sha256' | 'sha384' | 'sha512', + data: Uint8Array, +): Promise => { + const subtleDigest = `SHA-${algorithm.substr(-3)}` + return new Uint8Array(await crypto.subtle.digest(subtleDigest, data)) +} +export default digest diff --git a/dist/deno/runtime/ecdhes.ts b/dist/deno/runtime/ecdhes.ts new file mode 100644 index 0000000000..6a5896ced5 --- /dev/null +++ b/dist/deno/runtime/ecdhes.ts @@ -0,0 +1,73 @@ +import type { + EcdhAllowedFunction, + EcdhESDeriveKeyFunction, + GenerateEpkFunction, +} from './interfaces.d.ts' +import { encoder, concat, uint32be, lengthAndInput, concatKdf } from '../lib/buffer_utils.ts' +import crypto, { isCryptoKey } from './webcrypto.ts' +import digest from './digest.ts' +import invalidKeyInput from './invalid_key_input.ts' + +export const deriveKey: EcdhESDeriveKeyFunction = async ( + publicKey: unknown, + privateKey: unknown, + algorithm: string, + keyLength: number, + apu: Uint8Array = new Uint8Array(0), + apv: Uint8Array = new Uint8Array(0), +) => { + if (!isCryptoKey(publicKey)) { + throw new TypeError(invalidKeyInput(publicKey, 'CryptoKey')) + } + if (!isCryptoKey(privateKey)) { + throw new TypeError(invalidKeyInput(privateKey, 'CryptoKey')) + } + + 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( + // @ts-ignore + await crypto.subtle.deriveBits( + { + name: 'ECDH', + public: publicKey, + }, + privateKey, + // @ts-ignore + Math.ceil(parseInt((privateKey.algorithm).namedCurve.substr(-3), 10) / 8) << + 3, + ), + ) + + return concatKdf(digest, sharedSecret, keyLength, value) +} + +export const generateEpk: GenerateEpkFunction = async (key: unknown) => { + if (!isCryptoKey(key)) { + throw new TypeError(invalidKeyInput(key, 'CryptoKey')) + } + + return (<{ publicKey: CryptoKey; privateKey: CryptoKey }>await crypto.subtle.generateKey( + // @ts-ignore + { name: 'ECDH', namedCurve: (key.algorithm).namedCurve }, + true, + ['deriveBits'], + )).privateKey +} + +export const ecdhAllowed: EcdhAllowedFunction = (key: unknown) => { + if (!isCryptoKey(key)) { + throw new TypeError(invalidKeyInput(key, 'CryptoKey')) + } + // @ts-ignore + return ['P-256', 'P-384', 'P-521'].includes((key.algorithm).namedCurve) +} diff --git a/dist/deno/runtime/encrypt.ts b/dist/deno/runtime/encrypt.ts new file mode 100644 index 0000000000..ba890406e2 --- /dev/null +++ b/dist/deno/runtime/encrypt.ts @@ -0,0 +1,114 @@ +import { concat, uint64be } from '../lib/buffer_utils.ts' +import type { EncryptFunction } from './interfaces.d.ts' +import checkIvLength from '../lib/check_iv_length.ts' +import checkCekLength from './check_cek_length.ts' +import crypto, { isCryptoKey } from './webcrypto.ts' +import invalidKeyInput from './invalid_key_input.ts' +import { JOSENotSupported } from '../util/errors.ts' + +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.subarray(keySize >> 3), + 'AES-CBC', + false, + ['encrypt'], + ) + const macKey = await crypto.subtle.importKey( + 'raw', + cek.subarray(0, keySize >> 3), + { + hash: { name: `SHA-${keySize << 1}` }, + name: 'HMAC', + }, + false, + ['sign'], + ) + + const ciphertext = new Uint8Array( + // @ts-ignore + 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( + // @ts-ignore + 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: unknown, + iv: Uint8Array, + aad: Uint8Array, +) => { + if (!isCryptoKey(cek) && !(cek instanceof Uint8Array)) { + throw new TypeError(invalidKeyInput(cek, 'CryptoKey', 'Uint8Array')) + } + + checkCekLength(enc, cek) + checkIvLength(enc, iv) + + switch (enc) { + case 'A128CBC-HS256': + case 'A192CBC-HS384': + case 'A256CBC-HS512': + return cbcEncrypt(enc, plaintext, cek, iv, aad) + case 'A128GCM': + case 'A192GCM': + case 'A256GCM': + return gcmEncrypt(plaintext, cek, iv, aad) + default: + throw new JOSENotSupported('unsupported JWE Content Encryption Algorithm') + } +} + +export default encrypt diff --git a/dist/deno/runtime/fetch_jwks.ts b/dist/deno/runtime/fetch_jwks.ts new file mode 100644 index 0000000000..88c8fabf20 --- /dev/null +++ b/dist/deno/runtime/fetch_jwks.ts @@ -0,0 +1,38 @@ +import type { FetchFunction } from './interfaces.d.ts' +import { JOSEError } from '../util/errors.ts' +import globalThis from './global.ts' + +const fetchJwks: FetchFunction = async (url: URL, timeout: number) => { + let controller!: AbortController + if (typeof AbortController === 'function') { + controller = new AbortController() + setTimeout(() => controller.abort(), timeout) + } + + const response = await globalThis.fetch(url.href, { + signal: controller ? controller.signal : undefined, + redirect: 'manual', + method: 'GET', + // do not pass referrerPolicy, credentials, and mode when running + // in Cloudflare Workers environment + // @ts-expect-error + ...(typeof globalThis.WebSocketPair === 'undefined' + ? { + referrerPolicy: 'no-referrer', + credentials: 'omit', + mode: 'cors', + } + : undefined), + }) + + if (response.status !== 200) { + throw new JOSEError('Expected 200 OK from the JSON Web Key Set HTTP response') + } + + try { + return await response.json() + } catch { + throw new JOSEError('Failed to parse the JSON Web Key Set HTTP response as JSON') + } +} +export default fetchJwks diff --git a/dist/deno/runtime/generate.ts b/dist/deno/runtime/generate.ts new file mode 100644 index 0000000000..90893ae7ae --- /dev/null +++ b/dist/deno/runtime/generate.ts @@ -0,0 +1,126 @@ +import crypto from './webcrypto.ts' +import { JOSENotSupported } from '../util/errors.ts' +import random from './random.ts' +import type { GenerateKeyPairOptions } from '../util/generate_key_pair.ts' +import type { GenerateSecretOptions } from '../util/generate_secret.ts' + +export async function generateSecret(alg: string, options?: GenerateSecretOptions) { + let length: number + // @ts-ignore + 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: { name: `SHA-${length}` }, 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, options?.extractable ?? false, keyUsages)) + ) +} + +function getModulusLengthOption(options?: GenerateKeyPairOptions) { + const modulusLength = options?.modulusLength ?? 2048 + if (typeof modulusLength !== 'number' || modulusLength < 2048) { + throw new JOSENotSupported( + 'Invalid or unsupported modulusLength option provided, 2048 bits or larger keys must be used', + ) + } + return modulusLength +} + +export async function generateKeyPair(alg: string, options?: GenerateKeyPairOptions) { + let algorithm: RsaHashedKeyGenParams | EcKeyGenParams + let keyUsages: KeyUsage[] + + switch (alg) { + case 'PS256': + case 'PS384': + case 'PS512': + algorithm = { + name: 'RSA-PSS', + hash: { name: `SHA-${alg.substr(-3)}` }, + publicExponent: new Uint8Array([0x01, 0x00, 0x01]), + modulusLength: getModulusLengthOption(options), + } + keyUsages = ['sign', 'verify'] + break + case 'RS256': + case 'RS384': + case 'RS512': + algorithm = { + name: 'RSASSA-PKCS1-v1_5', + hash: { name: `SHA-${alg.substr(-3)}` }, + publicExponent: new Uint8Array([0x01, 0x00, 0x01]), + modulusLength: getModulusLengthOption(options), + } + keyUsages = ['sign', 'verify'] + break + case 'RSA-OAEP': + case 'RSA-OAEP-256': + case 'RSA-OAEP-384': + case 'RSA-OAEP-512': + algorithm = { + name: 'RSA-OAEP', + hash: { name: `SHA-${parseInt(alg.substr(-3), 10) || 1}` }, + publicExponent: new Uint8Array([0x01, 0x00, 0x01]), + modulusLength: getModulusLengthOption(options), + } + 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') + } + + return >( + crypto.subtle.generateKey(algorithm, options?.extractable ?? false, keyUsages) + ) +} diff --git a/dist/deno/runtime/get_sign_verify_key.ts b/dist/deno/runtime/get_sign_verify_key.ts new file mode 100644 index 0000000000..74cfeb74a4 --- /dev/null +++ b/dist/deno/runtime/get_sign_verify_key.ts @@ -0,0 +1,23 @@ +import crypto, { isCryptoKey } from './webcrypto.ts' +import invalidKeyInput from './invalid_key_input.ts' + +export default function getCryptoKey(alg: string, key: unknown, usage: KeyUsage) { + if (isCryptoKey(key)) { + return key + } + + if (key instanceof Uint8Array) { + if (!alg.startsWith('HS')) { + throw new TypeError(invalidKeyInput(key, 'CryptoKey')) + } + return crypto.subtle.importKey( + 'raw', + key, + { hash: { name: `SHA-${alg.substr(-3)}` }, name: 'HMAC' }, + false, + [usage], + ) + } + + throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'Uint8Array')) +} diff --git a/dist/deno/runtime/global.ts b/dist/deno/runtime/global.ts new file mode 100644 index 0000000000..ba85627857 --- /dev/null +++ b/dist/deno/runtime/global.ts @@ -0,0 +1,8 @@ +function getGlobal() { + if (typeof globalThis !== 'undefined') return globalThis + if (typeof self !== 'undefined') return self + if (typeof window !== 'undefined') return window + throw new Error('unable to locate global object') +} + +export default getGlobal() diff --git a/dist/deno/runtime/interfaces.d.ts b/dist/deno/runtime/interfaces.d.ts new file mode 100644 index 0000000000..3be3b22825 --- /dev/null +++ b/dist/deno/runtime/interfaces.d.ts @@ -0,0 +1,100 @@ +import type { JWK, KeyLike } from '../types.d.ts' +import type { AsyncOrSync } from '../types.i.d.ts' + +export interface TimingSafeEqual { + (a: Uint8Array, b: Uint8Array): boolean +} +export interface SignFunction { + (alg: string, key: unknown, data: Uint8Array): Promise +} +export interface VerifyFunction { + (alg: string, key: unknown, signature: Uint8Array, data: Uint8Array): Promise +} +export interface AesKwWrapFunction { + (alg: string, key: unknown, cek: Uint8Array): Promise +} +export interface AesKwUnwrapFunction { + (alg: string, key: unknown, encryptedKey: Uint8Array): Promise +} +export interface RsaEsEncryptFunction { + (alg: string, key: unknown, cek: Uint8Array): Promise +} +export interface RsaEsDecryptFunction { + (alg: string, key: unknown, encryptedKey: Uint8Array): Promise +} +export interface AesGcmKwWrapFunction { + (alg: string, key: unknown, cek: Uint8Array, iv?: Uint8Array): Promise<{ + encryptedKey: Uint8Array + iv: string + tag: string + }> +} +export interface AesGcmKwUnwrapFunction { + ( + alg: string, + key: unknown, + encryptedKey: Uint8Array, + iv: Uint8Array, + tag: Uint8Array, + ): Promise +} +export interface Pbes2KWEncryptFunction { + (alg: string, key: unknown, cek: Uint8Array, p2c?: number, p2s?: Uint8Array): Promise<{ + encryptedKey: Uint8Array + p2c: number + p2s: string + }> +} +export interface Pbes2KWDecryptFunction { + ( + alg: string, + key: unknown, + encryptedKey: Uint8Array, + p2c: number, + p2s: Uint8Array, + ): Promise +} +export interface EcdhESDeriveKeyFunction { + ( + publicKey: unknown, + privateKey: unknown, + enc: string, + keyLength: number, + apu?: Uint8Array, + apv?: Uint8Array, + ): Promise +} +export interface EcdhAllowedFunction { + (key: unknown): boolean +} +export interface GenerateEpkFunction { + (key: unknown): Promise +} +export interface EncryptFunction { + (enc: string, plaintext: Uint8Array, cek: unknown, iv: Uint8Array, aad: Uint8Array): Promise<{ + ciphertext: Uint8Array + tag: Uint8Array + }> +} +export interface DecryptFunction { + ( + enc: string, + cek: unknown, + ciphertext: Uint8Array, + iv: Uint8Array, + tag: Uint8Array, + additionalData: Uint8Array, + ): Promise +} +export interface FetchFunction { + (url: URL, timeout: number, options?: any): Promise<{ [propName: string]: unknown }> +} +export interface DigestFunction { + (digest: 'sha256' | 'sha384' | 'sha512', data: Uint8Array): AsyncOrSync +} +export interface JWKParseFunction { + (jwk: JWK): AsyncOrSync +} +export interface JWKConvertFunction { + (key: unknown): AsyncOrSync +} diff --git a/dist/deno/runtime/invalid_key_input.ts b/dist/deno/runtime/invalid_key_input.ts new file mode 100644 index 0000000000..dfcb74c9b8 --- /dev/null +++ b/dist/deno/runtime/invalid_key_input.ts @@ -0,0 +1,24 @@ +export default (actual: unknown, ...types: string[]) => { + let msg = 'Key must be ' + + if (types.length > 2) { + const last = types.pop() + msg += `one of type ${types.join(', ')}, or ${last}.` + } else if (types.length === 2) { + msg += `one of type ${types[0]} or ${types[1]}.` + } else { + msg += `of type ${types[0]}.` + } + + if (actual == null) { + msg += ` Received ${actual}` + } else if (typeof actual === 'function' && actual.name) { + msg += ` Received function ${actual.name}` + } else if (typeof actual === 'object' && actual != null) { + if (actual.constructor && actual.constructor.name) { + msg += ` Received an instance of ${actual.constructor.name}` + } + } + + return msg +} diff --git a/dist/deno/runtime/jwk_to_key.ts b/dist/deno/runtime/jwk_to_key.ts new file mode 100644 index 0000000000..8c9db9a9cd --- /dev/null +++ b/dist/deno/runtime/jwk_to_key.ts @@ -0,0 +1,133 @@ +import crypto from './webcrypto.ts' +import type { JWKParseFunction } from './interfaces.d.ts' +import { JOSENotSupported } from '../util/errors.ts' +import type { JWK } from '../types.d.ts' +import { decode as base64url } from './base64url.ts' + +function subtleMapping(jwk: JWK): { + // @ts-ignore + algorithm: RsaHashedImportParams | EcKeyAlgorithm | Algorithm + keyUsages: KeyUsage[] +} { + // @ts-ignore + 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: { name: `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: { name: `SHA-${jwk.alg.substr(-3)}` } } + keyUsages = jwk.d ? ['sign'] : ['verify'] + break + case 'RS256': + case 'RS384': + case 'RS512': + algorithm = { name: 'RSASSA-PKCS1-v1_5', hash: { name: `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: { name: `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 } +} + +const parse: JWKParseFunction = async (jwk: JWK): Promise => { + const { algorithm, keyUsages } = subtleMapping(jwk) + // @ts-ignore + const rest: [RsaHashedImportParams | EcKeyAlgorithm | Algorithm, boolean, KeyUsage[]] = [ + algorithm, + jwk.ext ?? false, + jwk.key_ops ?? keyUsages, + ] + + if (algorithm.name === 'PBKDF2') { + return crypto.subtle.importKey('raw', base64url(jwk.k!), ...rest) + } + + const keyData: JWK = { ...jwk } + delete keyData.alg + return crypto.subtle.importKey( + // @ts-ignore + 'jwk', + keyData, + ...rest, + ) +} +export default parse diff --git a/dist/deno/runtime/key_to_jwk.ts b/dist/deno/runtime/key_to_jwk.ts new file mode 100644 index 0000000000..314f9b8a89 --- /dev/null +++ b/dist/deno/runtime/key_to_jwk.ts @@ -0,0 +1,26 @@ +import crypto, { isCryptoKey } from './webcrypto.ts' +import type { JWKConvertFunction } from './interfaces.d.ts' +import type { JWK } from '../types.d.ts' +import invalidKeyInput from './invalid_key_input.ts' +import { encode as base64url } from './base64url.ts' + +const keyToJWK: JWKConvertFunction = async (key: unknown): Promise => { + if (key instanceof Uint8Array) { + return { + kty: 'oct', + k: base64url(key), + } + } + if (!isCryptoKey(key)) { + throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'Uint8Array')) + } + if (!key.extractable) { + throw new TypeError('non-extractable CryptoKey cannot be exported as a JWK') + } + // @ts-ignore + const { ext, key_ops, alg, use, ...jwk } = await crypto.subtle.exportKey('jwk', key) + + // @ts-ignore + return jwk +} +export default keyToJWK diff --git a/dist/deno/runtime/pbes2kw.ts b/dist/deno/runtime/pbes2kw.ts new file mode 100644 index 0000000000..6288b2a8b9 --- /dev/null +++ b/dist/deno/runtime/pbes2kw.ts @@ -0,0 +1,98 @@ +import type { Pbes2KWDecryptFunction, Pbes2KWEncryptFunction } from './interfaces.d.ts' +import random from './random.ts' +import { p2s as concatSalt } from '../lib/buffer_utils.ts' +import { encode as base64url } from './base64url.ts' +import { wrap, unwrap } from './aeskw.ts' +import checkP2s from '../lib/check_p2s.ts' +import crypto, { isCryptoKey } from './webcrypto.ts' +import invalidKeyInput from './invalid_key_input.ts' + +function getCryptoKey(key: unknown) { + if (key instanceof Uint8Array) { + return crypto.subtle.importKey('raw', key, 'PBKDF2', false, ['deriveBits']) + } + + if (isCryptoKey(key)) { + return key + } + + throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'Uint8Array')) +} + +export const encrypt: Pbes2KWEncryptFunction = async ( + alg: string, + key: unknown, + 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) + const subtleAlg = { + hash: { name: `SHA-${alg.substr(8, 3)}` }, + iterations: p2c, + name: 'PBKDF2', + salt, + } + const wrapAlg = { + length: keylen, + name: 'AES-KW', + } + + const cryptoKey = await getCryptoKey(key) + + let derived: CryptoKey | Uint8Array + if (cryptoKey.usages.includes('deriveBits')) { + // @ts-ignore + derived = new Uint8Array(await crypto.subtle.deriveBits(subtleAlg, cryptoKey, keylen)) + } else if (cryptoKey.usages.includes('deriveKey')) { + // @ts-ignore + 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: unknown, + encryptedKey: Uint8Array, + p2c: number, + p2s: Uint8Array, +) => { + checkP2s(p2s) + + const salt = concatSalt(alg, p2s) + const keylen = parseInt(alg.substr(13, 3), 10) + const subtleAlg = { + hash: { name: `SHA-${alg.substr(8, 3)}` }, + iterations: p2c, + name: 'PBKDF2', + salt, + } + const wrapAlg = { + length: keylen, + name: 'AES-KW', + } + + const cryptoKey = await getCryptoKey(key) + + let derived: CryptoKey | Uint8Array + if (cryptoKey.usages.includes('deriveBits')) { + // @ts-ignore + derived = new Uint8Array(await crypto.subtle.deriveBits(subtleAlg, cryptoKey, keylen)) + } else if (cryptoKey.usages.includes('deriveKey')) { + // @ts-ignore + 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/dist/deno/runtime/random.ts b/dist/deno/runtime/random.ts new file mode 100644 index 0000000000..11a0fc450d --- /dev/null +++ b/dist/deno/runtime/random.ts @@ -0,0 +1,5 @@ +import crypto from './webcrypto.ts' + +const random = crypto.getRandomValues.bind(crypto) + +export default random diff --git a/dist/deno/runtime/rsaes.ts b/dist/deno/runtime/rsaes.ts new file mode 100644 index 0000000000..95d11c1888 --- /dev/null +++ b/dist/deno/runtime/rsaes.ts @@ -0,0 +1,64 @@ +import type { RsaEsDecryptFunction, RsaEsEncryptFunction } from './interfaces.d.ts' +import subtleAlgorithm from './subtle_rsaes.ts' +import bogusWebCrypto from './bogus.ts' +import crypto, { isCryptoKey } from './webcrypto.ts' +import checkKeyLength from './check_key_length.ts' +import invalidKeyInput from './invalid_key_input.ts' + +export const encrypt: RsaEsEncryptFunction = async (alg: string, key: unknown, cek: Uint8Array) => { + if (!isCryptoKey(key)) { + throw new TypeError(invalidKeyInput(key, 'CryptoKey')) + } + checkKeyLength(alg, key) + + if (key.usages.includes('encrypt')) { + // @ts-ignore + 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( + // @ts-ignore + 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: unknown, + encryptedKey: Uint8Array, +) => { + if (!isCryptoKey(key)) { + throw new TypeError(invalidKeyInput(key, 'CryptoKey')) + } + checkKeyLength(alg, key) + + if (key.usages.includes('decrypt')) { + // @ts-ignore + return new Uint8Array(await crypto.subtle.decrypt(subtleAlgorithm(alg), key, encryptedKey)) + } + + if (key.usages.includes('unwrapKey')) { + // @ts-ignore + 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/dist/deno/runtime/sign.ts b/dist/deno/runtime/sign.ts new file mode 100644 index 0000000000..3302b070a3 --- /dev/null +++ b/dist/deno/runtime/sign.ts @@ -0,0 +1,14 @@ +import type { SignFunction } from './interfaces.d.ts' +import subtleAlgorithm from './subtle_dsa.ts' +import crypto from './webcrypto.ts' +import checkKeyLength from './check_key_length.ts' +import getSignKey from './get_sign_verify_key.ts' + +const sign: SignFunction = async (alg, key: unknown, data) => { + const cryptoKey = await getSignKey(alg, key, 'sign') + checkKeyLength(alg, cryptoKey) + const signature = await crypto.subtle.sign(subtleAlgorithm(alg), cryptoKey, data) + return new Uint8Array(signature) +} + +export default sign diff --git a/dist/deno/runtime/subtle_dsa.ts b/dist/deno/runtime/subtle_dsa.ts new file mode 100644 index 0000000000..920c2b81c4 --- /dev/null +++ b/dist/deno/runtime/subtle_dsa.ts @@ -0,0 +1,46 @@ +import { JOSENotSupported } from '../util/errors.ts' + +export default function subtleDsa(alg: string) { + switch (alg) { + case 'HS256': + return { hash: { name: 'SHA-256' }, name: 'HMAC' } + case 'HS384': + return { hash: { name: 'SHA-384' }, name: 'HMAC' } + case 'HS512': + return { hash: { name: 'SHA-512' }, name: 'HMAC' } + case 'PS256': + return { + hash: { name: 'SHA-256' }, + name: 'RSA-PSS', + saltLength: 256 >> 3, + } + case 'PS384': + return { + hash: { name: 'SHA-384' }, + name: 'RSA-PSS', + saltLength: 384 >> 3, + } + case 'PS512': + return { + hash: { name: 'SHA-512' }, + name: 'RSA-PSS', + saltLength: 512 >> 3, + } + case 'RS256': + return { hash: { name: 'SHA-256' }, name: 'RSASSA-PKCS1-v1_5' } + case 'RS384': + return { hash: { name: 'SHA-384' }, name: 'RSASSA-PKCS1-v1_5' } + case 'RS512': + return { hash: { name: 'SHA-512' }, name: 'RSASSA-PKCS1-v1_5' } + case 'ES256': + return { hash: { name: 'SHA-256' }, name: 'ECDSA', namedCurve: 'P-256' } + case 'ES384': + return { hash: { name: 'SHA-384' }, name: 'ECDSA', namedCurve: 'P-384' } + case 'ES512': + return { hash: { name: 'SHA-512' }, name: 'ECDSA', namedCurve: 'P-521' } + default: + throw new JOSENotSupported( + `alg ${alg} is not supported either by JOSE or your javascript runtime`, + ) + } +} diff --git a/dist/deno/runtime/subtle_rsaes.ts b/dist/deno/runtime/subtle_rsaes.ts new file mode 100644 index 0000000000..16fb3d3c59 --- /dev/null +++ b/dist/deno/runtime/subtle_rsaes.ts @@ -0,0 +1,15 @@ +import { JOSENotSupported } from '../util/errors.ts' + +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 not supported either by JOSE or your javascript runtime`, + ) + } +} diff --git a/dist/deno/runtime/timing_safe_equal.ts b/dist/deno/runtime/timing_safe_equal.ts new file mode 100644 index 0000000000..53bc719686 --- /dev/null +++ b/dist/deno/runtime/timing_safe_equal.ts @@ -0,0 +1,23 @@ +import type { TimingSafeEqual } from './interfaces.d.ts' + +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/dist/deno/runtime/verify.ts b/dist/deno/runtime/verify.ts new file mode 100644 index 0000000000..6b7b893fba --- /dev/null +++ b/dist/deno/runtime/verify.ts @@ -0,0 +1,18 @@ +import type { VerifyFunction } from './interfaces.d.ts' +import subtleAlgorithm from './subtle_dsa.ts' +import crypto from './webcrypto.ts' +import checkKeyLength from './check_key_length.ts' +import getVerifyKey from './get_sign_verify_key.ts' + +const verify: VerifyFunction = async (alg, key: unknown, signature, data) => { + const cryptoKey = await getVerifyKey(alg, key, 'verify') + checkKeyLength(alg, cryptoKey) + const algorithm = subtleAlgorithm(alg) + try { + return await crypto.subtle.verify(algorithm, cryptoKey, signature, data) + } catch { + return false + } +} + +export default verify diff --git a/dist/deno/runtime/webcrypto.ts b/dist/deno/runtime/webcrypto.ts new file mode 100644 index 0000000000..ab307b954f --- /dev/null +++ b/dist/deno/runtime/webcrypto.ts @@ -0,0 +1,10 @@ +import globalThis from './global.ts' + +export default globalThis.crypto + +export function isCryptoKey(key: unknown): key is CryptoKey { + if (typeof globalThis.CryptoKey === 'undefined') { + return false + } + return key != null && key instanceof globalThis.CryptoKey +} diff --git a/dist/deno/runtime/zlib.ts b/dist/deno/runtime/zlib.ts new file mode 100644 index 0000000000..653d1b419f --- /dev/null +++ b/dist/deno/runtime/zlib.ts @@ -0,0 +1,13 @@ +import { JOSENotSupported } from '../util/errors.ts' +import type { InflateFunction, DeflateFunction } from '../types.d.ts' + +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.', + ) +} +export const deflate: DeflateFunction = async () => { + throw new JOSENotSupported( + 'JWE "zip" (Compression Algorithm) Header Parameter is not supported by your javascript runtime. You need to use the `deflateRaw` encrypt option to provide Deflate Raw implementation.', + ) +} diff --git a/dist/deno/types.d.ts b/dist/deno/types.d.ts new file mode 100644 index 0000000000..68f40ded08 --- /dev/null +++ b/dist/deno/types.d.ts @@ -0,0 +1,691 @@ +export type KeyObject = CryptoKey + +/** + * KeyLike are platform-specific references to keying material. + * + * [KeyObject](https://nodejs.org/api/crypto.html#crypto_class_keyobject) is a representation of a + * key/secret available in the Node.js runtime. You can obtain a KeyObject instance e.g. from: + * + * - [crypto.createPublicKey](https://nodejs.org/api/crypto.html#crypto_crypto_createpublickey_key) + * - [crypto.createPrivateKey](https://nodejs.org/api/crypto.html#crypto_crypto_createprivatekey_key) + * - [crypto.createSecretKey](https://nodejs.org/api/crypto.html#crypto_crypto_createsecretkey_key_encoding) + * - [crypto.generateKeyPair](https://nodejs.org/api/crypto.html#crypto_crypto_generatekeypair_type_options_callback) + * - [jose/jwk/parse](../functions/jwk_parse.parseJwk.md#readme) + * - [jose/util/generate_key_pair](../functions/util_generate_key_pair.generateKeyPair.md#readme) + * - [jose/util/generate_secret](../functions/util_generate_secret.generateSecret.md#readme) + * + * [CryptoKey](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey) is a representation of a + * key/secret available in the Browser and Deno runtimes. You can obtain a CryptoKey instance e.g. from: + * + * - [SubtleCrypto.importKey](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/importKey) + * - [SubtleCrypto.generateKey](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey) + * - [jose/jwk/parse](../functions/jwk_parse.parseJwk.md#readme) + * - [jose/util/generate_key_pair](../functions/util_generate_key_pair.generateKeyPair.md#readme) + * - [jose/util/generate_secret](../functions/util_generate_secret.generateSecret.md#readme) + * + * [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. + * In Node.js the [Buffer](https://nodejs.org/api/buffer.html#buffer_buffer) class is a subclass of Uint8Array + * class. `jose` APIs accept plain Buffers wherever Uint8Array are supported as well. + * + * @example (node) Public KeyObject from a PEM public key + * ```js + * import { createPublicKey } from 'crypto' + * + * const publicKey = createPublicKey(pem) + * ``` + * + * @example (node) Private KeyObject from a PEM private key + * ```js + * import { createPrivateKey } from 'crypto' + * + * const privateKey = createPrivateKey(pem) + * ``` + * + * @example (node) Secret KeyObject from hex encoded random bytes + * ```js + * import { createSecretKey } from 'crypto' + * + * const secretKey = createSecretKey(Buffer.from('7f908df6c8bd634f769c073a48986d77677b79bc6aa19b106f976f2db18d38c2', 'hex')) + * ``` + * + * @example (all runtimes) KeyLike from a JSON Web Key (JWK) + * ```js + * import { parseJwk } from 'jose/jwk/parse' + * + * const ecPublicKey = await parseJwk({ + * crv: 'P-256', + * kty: 'EC', + * x: 'ySK38C1jBdLwDsNWKzzBHqKYEE5Cgv-qjWvorUXk9fw', + * y: '_LeQBw07cf5t57Iavn4j-BqJsAD1dpoz8gokd3sBsOo' + * }, 'ES256') + * + * const rsaPublicKey = await parseJwk({ + * kty: 'RSA', + * e: 'AQAB', + * n: '12oBZRhCiZFJLcPg59LkZZ9mdhSMTKAQZYq32k_ti5SBB6jerkh-WzOMAO664r_qyLkqHUSp3u5SbXtseZEpN3XPWGKSxjsy-1JyEFTdLSYe6f9gfrmxkUF_7DTpq0gn6rntP05g2-wFW50YO7mosfdslfrTJYWHFhJALabAeYirYD7-9kqq9ebfFMF4sRRELbv9oi36As6Q9B3Qb5_C1rAzqfao_PCsf9EPsTZsVVVkA5qoIAr47lo1ipfiBPxUCCNSdvkmDTYgvvRm6ZoMjFbvOtgyts55fXKdMWv7I9HMD5HwE9uW839PWA514qhbcIsXEYSFMPMV6fnlsiZvQQ' + * }, 'PS256') + * ``` + */ +export type KeyLike = KeyObject | CryptoKey | Uint8Array + +/** + * 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 + + [propName: string]: unknown +} + +/** + * Generic Interface for consuming operations dynamic key resolution. + * No token components have been verified at the time of this function call. + * + * If you cannot match a key suitable for the token, throw an error instead. + * + * @param protectedHeader JWE or JWS Protected Header. + * @param token The consumed JWE or JWS token. + */ +export interface GetKeyFunction { + (protectedHeader: T, token: T2): Promise +} + +/** + * 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 +} + +/** + * General JWS definition for verify function inputs, allows payload as + * Uint8Array for detached signature validation. + */ +export interface GeneralJWSInput { + /** + * 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 "signatures" member value MUST be an array of JSON objects. + * Each object represents a signature or MAC over the JWS Payload and + * the JWS Protected Header. + */ + signatures: Omit[] +} + +/** + * Flattened JWS definition. Payload is returned as an empty + * string when JWS Unencoded Payload Option + * [RFC7797](https://tools.ietf.org/html/rfc7797) is used. + */ +export interface FlattenedJWS extends Partial { + payload: string + signature: string +} + +/** + * General JWS definition. Payload is returned as an empty + * string when JWS Unencoded Payload Option + * [RFC7797](https://tools.ietf.org/html/rfc7797) is used. + */ +export interface GeneralJWS { + payload: string + signatures: Omit[] +} + +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 + + /** + * "jku" (JWK Set URL) Header Parameter. + */ + jku?: 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]: unknown +} + +/** + * 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 +} + +export interface GeneralJWE extends Omit { + recipients: Pick[] +} + +/** + * 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]: unknown +} + +/** + * Shared Interface with a "crit" property for all sign and verify operations. + */ +export interface CritOption { + /** + * An object with keys representing recognized "crit" (Critical) Header Parameter + * names. The value for those is either `true` or `false`. `true` when the + * Header Parameter MUST be integrity protected, `false` when it's irrelevant. + * + * This makes the "Extension Header Parameter "${parameter}" is not recognized" + * error go away. + * + * Use this when a given JWS/JWT/JWE profile requires the use of proprietary + * non-registered "crit" (Critical) Header Parameters. This will only make sure + * the Header Parameter is syntactically correct when provided and that it is + * optionally integrity protected. It will not process the Header Parameter in + * any way or reject if the operation if it is missing. You MUST still + * verify the Header Parameter was present and process it according to the + * profile's validation steps after the operation succeeds. + * + * The JWS extension Header Parameter `b64` is always recognized and processed + * properly. No other registered Header Parameters that need this kind of + * default built-in treatment are currently available. + */ + crit?: { + [propName: string]: boolean + } +} + +/** + * JWE Decryption options. + */ +export interface DecryptOptions extends CritOption { + /** + * A list of accepted JWE "alg" (Algorithm) Header Parameter values. + */ + keyManagementAlgorithms?: string[] + + /** + * A list of accepted JWE "enc" (Encryption Algorithm) Header Parameter values. + * By default all "enc" (Encryption Algorithm) values applicable for the used + * key/secret are allowed. + */ + 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 extends CritOption { + /** + * 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", "10 minutes", "2 hours"). + */ + 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. + * - in seconds when number (e.g. 5) + * - parsed as seconds when a string (e.g. "5 seconds", "10 minutes", "2 hours"). + */ + maxTokenAge?: string | number + + /** + * 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 extends CritOption { + /** + * A list of accepted JWS "alg" (Algorithm) Header Parameter values. + * By default all "alg" (Algorithm) values applicable for the used + * key/secret are allowed. Note: "none" is never accepted. + */ + algorithms?: string[] +} + +/** + * JWS Signing options. + */ +export interface SignOptions extends CritOption {} + +/** + * 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]: unknown +} + +/** + * 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 GeneralDecryptResult extends FlattenedDecryptResult {} + +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 GeneralVerifyResult extends FlattenedVerifyResult {} + +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/dist/deno/types.i.d.ts b/dist/deno/types.i.d.ts new file mode 100644 index 0000000000..44ead8d979 --- /dev/null +++ b/dist/deno/types.i.d.ts @@ -0,0 +1,13 @@ +export type Awaited = T extends PromiseLike ? PT : never +export type AsyncOrSync = PromiseLike | T + +export interface JWEKeyManagementHeaderResults { + apu?: string + apv?: string + epk?: { x?: string; y?: string; crv?: string; kty?: string } + iv?: string + p2c?: number + p2s?: string + tag?: string + [propName: string]: unknown +} diff --git a/dist/deno/util/base64url.ts b/dist/deno/util/base64url.ts new file mode 100644 index 0000000000..f3d76163fc --- /dev/null +++ b/dist/deno/util/base64url.ts @@ -0,0 +1,21 @@ +import * as base64url from '../runtime/base64url.ts' + +/** + * Utility function to encode a string or Uint8Array as a base64url string. + * + * @param input Value that will be base64url-encoded. + */ +interface Base64UrlEncode { + (input: Uint8Array | string): string +} +/** + * Utility function to decode a base64url encoded string. + * + * @param input Value that will be base64url-decoded. + */ +interface Base64UrlDecode { + (input: Uint8Array | string): Uint8Array +} + +export const encode: Base64UrlEncode = base64url.encode +export const decode: Base64UrlDecode = base64url.decode diff --git a/dist/deno/util/decode_protected_header.ts b/dist/deno/util/decode_protected_header.ts new file mode 100644 index 0000000000..d11dc1c649 --- /dev/null +++ b/dist/deno/util/decode_protected_header.ts @@ -0,0 +1,65 @@ +import { decode as base64url } from './base64url.ts' +import { decoder } from '../lib/buffer_utils.ts' +import isObject from '../lib/is_object.ts' +import type { JWSHeaderParameters, JWEHeaderParameters } from '../types.d.ts' + +export type ProtectedHeaderParameters = JWSHeaderParameters & JWEHeaderParameters + +/** + * Decodes the Protected Header of a JWE/JWS/JWT token utilizing any JOSE serialization. + * + * @example ESM import + * ```js + * import { decodeProtectedHeader } from 'jose/util/decode_protected_header' + * ``` + * + * @example CJS import + * ```js + * const { decodeProtectedHeader } = require('jose/util/decode_protected_header') + * ``` + * + * @example Deno import + * ```js + * import { decodeProtectedHeader } from 'https://deno.land/x/jose@VERSION/util/decode_protected_header.ts' + * ``` + * + * @example Usage + * ```js + * const protectedHeader = decodeProtectedHeader(token) + * console.log(protectedHeader) + * ``` + * + * @param token JWE/JWS/JWT token in any JOSE serialization. + */ +function decodeProtectedHeader(token: string | object) { + let protectedB64u!: string + + if (typeof token === 'string') { + const parts = token.split('.') + if (parts.length === 3 || parts.length === 5) { + ;[protectedB64u] = parts + } + } else if (typeof token === 'object' && token) { + if ('protected' in token) { + protectedB64u = (<{ protected: string }>token).protected + } else { + throw new TypeError('Token does not contain a Protected Header') + } + } + + try { + if (typeof protectedB64u !== 'string' || !protectedB64u) { + throw new Error() + } + const result = JSON.parse(decoder.decode(base64url(protectedB64u!))) + if (!isObject(result)) { + throw new Error() + } + return result + } catch { + throw new TypeError('Invalid Token or Protected Header formatting') + } +} + +export { decodeProtectedHeader } +export default decodeProtectedHeader diff --git a/dist/deno/util/errors.ts b/dist/deno/util/errors.ts new file mode 100644 index 0000000000..59ef9a38db --- /dev/null +++ b/dist/deno/util/errors.ts @@ -0,0 +1,165 @@ +/** + * 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. + */ + static code = 'ERR_JOSE_GENERIC' + + /** + * A unique error code for the particular error subclass. + */ + code = JOSEError.code + + 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 { + static code = 'ERR_JWT_CLAIM_VALIDATION_FAILED' + + code = JWTClaimValidationFailed.code + + /** + * 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 { + static code = 'ERR_JOSE_ALG_NOT_ALLOWED' + + code = JOSEAlgNotAllowed.code +} + +/** + * 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 { + static code = 'ERR_JOSE_NOT_SUPPORTED' + + code = JOSENotSupported.code +} + +/** + * An error subclass thrown when a JWE ciphertext decryption fails. + */ +export class JWEDecryptionFailed extends JOSEError { + static code = 'ERR_JWE_DECRYPTION_FAILED' + + code = JWEDecryptionFailed.code + + message = 'decryption operation failed' +} + +/** + * An error subclass thrown when a JWE is invalid. + */ +export class JWEInvalid extends JOSEError { + static code = 'ERR_JWE_INVALID' + + code = JWEInvalid.code +} + +/** + * An error subclass thrown when a JWS is invalid. + */ +export class JWSInvalid extends JOSEError { + static code = 'ERR_JWS_INVALID' + + code = JWSInvalid.code +} + +/** + * An error subclass thrown when a JWT is invalid. + */ +export class JWTInvalid extends JOSEError { + static code = 'ERR_JWT_INVALID' + + code = JWTInvalid.code +} + +/** + * An error subclass thrown when a JWK is invalid. + */ +export class JWKInvalid extends JOSEError { + static code = 'ERR_JWK_INVALID' + + code = JWKInvalid.code +} + +/** + * An error subclass thrown when a JWKS is invalid. + */ +export class JWKSInvalid extends JOSEError { + static code = 'ERR_JWKS_INVALID' + + code = JWKSInvalid.code +} + +/** + * An error subclass thrown when no keys match from a JWKS. + */ +export class JWKSNoMatchingKey extends JOSEError { + static code = 'ERR_JWKS_NO_MATCHING_KEY' + + code = JWKSNoMatchingKey.code + + 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 { + static code = 'ERR_JWKS_MULTIPLE_MATCHING_KEYS' + + code = JWKSMultipleMatchingKeys.code + + 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 { + static code = 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED' + + code = JWSSignatureVerificationFailed.code + + message = 'signature verification failed' +} + +/** + * An error subclass thrown when a JWT is expired. + */ +export class JWTExpired extends JWTClaimValidationFailed { + static code = 'ERR_JWT_EXPIRED' + + code = JWTExpired.code +} diff --git a/dist/deno/util/generate_key_pair.ts b/dist/deno/util/generate_key_pair.ts new file mode 100644 index 0000000000..dc9b73f820 --- /dev/null +++ b/dist/deno/util/generate_key_pair.ts @@ -0,0 +1,79 @@ +import { generateKeyPair as generate } from '../runtime/generate.ts' +import type { KeyLike } from '../types.d.ts' + +export interface GenerateKeyPairResult { + /** + * The generated Private Key. + */ + privateKey: Exclude + + /** + * Public Key corresponding to the generated Private Key. + */ + publicKey: Exclude +} + +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 + + /** + * A hint for RSA algorithms to generate an RSA key of a given `modulusLength` + * (Key size in bits). JOSE requires 2048 bits or larger. Default is 2048. + */ + modulusLength?: number + + /** + * (Web Cryptography API specific) The value to use as + * [SubtleCrypto.generateKey()](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey) + * `extractable` argument. Default is false. + */ + extractable?: boolean +} + +/** + * 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. + * + * Note: Under Web Cryptography API runtime the `privateKey` is generated with + * `extractable` set to `false` by default. + * + * @example ESM import + * ```js + * import { generateKeyPair } from 'jose/util/generate_key_pair' + * ``` + * + * @example CJS import + * ```js + * const { generateKeyPair } = require('jose/util/generate_key_pair') + * ``` + * + * @example Deno import + * ```js + * import { generateKeyPair } from 'https://deno.land/x/jose@VERSION/util/generate_key_pair.ts' + * ``` + * + * @example Usage + * ```js + * 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. + */ +async function generateKeyPair( + alg: string, + options?: GenerateKeyPairOptions, +): Promise { + return generate(alg, options) +} + +export { generateKeyPair } +export default generateKeyPair diff --git a/dist/deno/util/generate_secret.ts b/dist/deno/util/generate_secret.ts new file mode 100644 index 0000000000..2fccd5d471 --- /dev/null +++ b/dist/deno/util/generate_secret.ts @@ -0,0 +1,48 @@ +import { generateSecret as generate } from '../runtime/generate.ts' +import type { KeyLike } from '../types.d.ts' + +export interface GenerateSecretOptions { + /** + * (Web Cryptography API specific) The value to use as + * [SubtleCrypto.generateKey()](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey) + * `extractable` argument. Default is false. + */ + extractable?: boolean +} + +/** + * Generates a symmetric secret key for a given JWA algorithm identifier. + * + * Note: Under Web Cryptography API runtime the secret key is generated with + * `extractable` set to `false` by default. + * + * @example ESM import + * ```js + * import { generateSecret } from 'jose/util/generate_secret' + * ``` + * + * @example CJS import + * ```js + * const { generateSecret } = require('jose/util/generate_secret') + * ``` + * + * @example Deno import + * ```js + * import { generateSecret } from 'https://deno.land/x/jose@VERSION/util/generate_secret.ts' + * ``` + * + * @example Usage + * ```js + * const secret = await generateSecret('HS256') + * console.log(secret) + * ``` + * + * @param alg JWA Algorithm Identifier to be used with the generated secret. + * @param options Additional options passed down to the secret generation. + */ +async function generateSecret(alg: string, options?: GenerateSecretOptions): Promise { + return generate(alg, options) +} + +export { generateSecret } +export default generateSecret diff --git a/dist/deno/util/random.ts b/dist/deno/util/random.ts new file mode 100644 index 0000000000..1b5b16a5ee --- /dev/null +++ b/dist/deno/util/random.ts @@ -0,0 +1,9 @@ +import runtimeRandom from '../runtime/random.ts' + +interface GetRandomValuesFunction { + (array: Uint8Array): Uint8Array +} + +const random: GetRandomValuesFunction = runtimeRandom +export { random } +export default random diff --git a/dist/node/cjs/jwe/compact/decrypt.js b/dist/node/cjs/jwe/compact/decrypt.js new file mode 100644 index 0000000000..794d4861eb --- /dev/null +++ b/dist/node/cjs/jwe/compact/decrypt.js @@ -0,0 +1,28 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.compactDecrypt = void 0; +const decrypt_js_1 = require("../flattened/decrypt.js"); +const errors_js_1 = require("../../util/errors.js"); +const buffer_utils_js_1 = require("../../lib/buffer_utils.js"); +async function compactDecrypt(jwe, key, options) { + if (jwe instanceof Uint8Array) { + jwe = buffer_utils_js_1.decoder.decode(jwe); + } + if (typeof jwe !== 'string') { + throw new errors_js_1.JWEInvalid('Compact JWE must be a string or Uint8Array'); + } + const { 0: protectedHeader, 1: encryptedKey, 2: iv, 3: ciphertext, 4: tag, length, } = jwe.split('.'); + if (length !== 5) { + throw new errors_js_1.JWEInvalid('Invalid Compact JWE'); + } + const decrypted = await (0, decrypt_js_1.default)({ + ciphertext: (ciphertext || undefined), + iv: (iv || undefined), + protected: protectedHeader || undefined, + tag: (tag || undefined), + encrypted_key: encryptedKey || undefined, + }, key, options); + return { plaintext: decrypted.plaintext, protectedHeader: decrypted.protectedHeader }; +} +exports.compactDecrypt = compactDecrypt; +exports.default = compactDecrypt; diff --git a/dist/node/cjs/jwe/compact/encrypt.js b/dist/node/cjs/jwe/compact/encrypt.js new file mode 100644 index 0000000000..e37dff2a35 --- /dev/null +++ b/dist/node/cjs/jwe/compact/encrypt.js @@ -0,0 +1,31 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.CompactEncrypt = void 0; +const encrypt_js_1 = require("../flattened/encrypt.js"); +class CompactEncrypt { + constructor(plaintext) { + this._flattened = new encrypt_js_1.default(plaintext); + } + setContentEncryptionKey(cek) { + this._flattened.setContentEncryptionKey(cek); + return this; + } + setInitializationVector(iv) { + this._flattened.setInitializationVector(iv); + return this; + } + setProtectedHeader(protectedHeader) { + this._flattened.setProtectedHeader(protectedHeader); + return this; + } + setKeyManagementParameters(parameters) { + this._flattened.setKeyManagementParameters(parameters); + return this; + } + async encrypt(key, options) { + const jwe = await this._flattened.encrypt(key, options); + return [jwe.protected, jwe.encrypted_key, jwe.iv, jwe.ciphertext, jwe.tag].join('.'); + } +} +exports.CompactEncrypt = CompactEncrypt; +exports.default = CompactEncrypt; diff --git a/dist/node/cjs/jwe/flattened/decrypt.js b/dist/node/cjs/jwe/flattened/decrypt.js new file mode 100644 index 0000000000..89fa34f7a3 --- /dev/null +++ b/dist/node/cjs/jwe/flattened/decrypt.js @@ -0,0 +1,141 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.flattenedDecrypt = void 0; +const errors_js_1 = require("../../util/errors.js"); +const is_disjoint_js_1 = require("../../lib/is_disjoint.js"); +const is_object_js_1 = require("../../lib/is_object.js"); +const base64url_js_1 = require("../../runtime/base64url.js"); +const decrypt_js_1 = require("../../runtime/decrypt.js"); +const zlib_js_1 = require("../../runtime/zlib.js"); +const decrypt_key_management_js_1 = require("../../lib/decrypt_key_management.js"); +const buffer_utils_js_1 = require("../../lib/buffer_utils.js"); +const cek_js_1 = require("../../lib/cek.js"); +const random_js_1 = require("../../runtime/random.js"); +const validate_crit_js_1 = require("../../lib/validate_crit.js"); +const validate_algorithms_js_1 = require("../../lib/validate_algorithms.js"); +const generateCek = (0, cek_js_1.default)(random_js_1.default); +const checkExtensions = validate_crit_js_1.default.bind(undefined, errors_js_1.JWEInvalid, new Map()); +const checkAlgOption = validate_algorithms_js_1.default.bind(undefined, 'keyManagementAlgorithms'); +const checkEncOption = validate_algorithms_js_1.default.bind(undefined, 'contentEncryptionAlgorithms'); +async function flattenedDecrypt(jwe, key, options) { + var _a; + if (!(0, is_object_js_1.default)(jwe)) { + throw new errors_js_1.JWEInvalid('Flattened JWE must be an object'); + } + if (jwe.protected === undefined && jwe.header === undefined && jwe.unprotected === undefined) { + throw new errors_js_1.JWEInvalid('JOSE Header missing'); + } + if (typeof jwe.iv !== 'string') { + throw new errors_js_1.JWEInvalid('JWE Initialization Vector missing or incorrect type'); + } + if (typeof jwe.ciphertext !== 'string') { + throw new errors_js_1.JWEInvalid('JWE Ciphertext missing or incorrect type'); + } + if (typeof jwe.tag !== 'string') { + throw new errors_js_1.JWEInvalid('JWE Authentication Tag missing or incorrect type'); + } + if (jwe.protected !== undefined && typeof jwe.protected !== 'string') { + throw new errors_js_1.JWEInvalid('JWE Protected Header incorrect type'); + } + if (jwe.encrypted_key !== undefined && typeof jwe.encrypted_key !== 'string') { + throw new errors_js_1.JWEInvalid('JWE Encrypted Key incorrect type'); + } + if (jwe.aad !== undefined && typeof jwe.aad !== 'string') { + throw new errors_js_1.JWEInvalid('JWE AAD incorrect type'); + } + if (jwe.header !== undefined && !(0, is_object_js_1.default)(jwe.header)) { + throw new errors_js_1.JWEInvalid('JWE Shared Unprotected Header incorrect type'); + } + if (jwe.unprotected !== undefined && !(0, is_object_js_1.default)(jwe.unprotected)) { + throw new errors_js_1.JWEInvalid('JWE Per-Recipient Unprotected Header incorrect type'); + } + let parsedProt; + if (jwe.protected) { + const protectedHeader = (0, base64url_js_1.decode)(jwe.protected); + try { + parsedProt = JSON.parse(buffer_utils_js_1.decoder.decode(protectedHeader)); + } + catch { + throw new errors_js_1.JWEInvalid('JWE Protected Header is invalid'); + } + } + if (!(0, is_disjoint_js_1.default)(parsedProt, jwe.header, jwe.unprotected)) { + throw new errors_js_1.JWEInvalid('JWE Protected, JWE Unprotected Header, and JWE Per-Recipient Unprotected Header Parameter names must be disjoint'); + } + const joseHeader = { + ...parsedProt, + ...jwe.header, + ...jwe.unprotected, + }; + checkExtensions(options === null || options === void 0 ? void 0 : options.crit, parsedProt, joseHeader); + if (joseHeader.zip !== undefined) { + if (!parsedProt || !parsedProt.zip) { + throw new errors_js_1.JWEInvalid('JWE "zip" (Compression Algorithm) Header MUST be integrity protected'); + } + if (joseHeader.zip !== 'DEF') { + throw new errors_js_1.JOSENotSupported('unsupported JWE "zip" (Compression Algorithm) Header Parameter value'); + } + } + const { alg, enc } = joseHeader; + if (typeof alg !== 'string' || !alg) { + throw new errors_js_1.JWEInvalid('missing JWE Algorithm (alg) in JWE Header'); + } + if (typeof enc !== 'string' || !enc) { + throw new errors_js_1.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 errors_js_1.JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter not allowed'); + } + if (contentEncryptionAlgorithms && !contentEncryptionAlgorithms.has(enc)) { + throw new errors_js_1.JOSEAlgNotAllowed('"enc" (Encryption Algorithm) Header Parameter not allowed'); + } + let encryptedKey; + if (jwe.encrypted_key !== undefined) { + encryptedKey = (0, base64url_js_1.decode)(jwe.encrypted_key); + } + if (typeof key === 'function') { + key = await key(parsedProt, jwe); + } + let cek; + try { + cek = await (0, decrypt_key_management_js_1.default)(alg, key, encryptedKey, joseHeader); + } + catch (err) { + if (err instanceof TypeError) { + throw err; + } + cek = generateCek(enc); + } + const iv = (0, base64url_js_1.decode)(jwe.iv); + const tag = (0, base64url_js_1.decode)(jwe.tag); + const protectedHeader = buffer_utils_js_1.encoder.encode((_a = jwe.protected) !== null && _a !== void 0 ? _a : ''); + let additionalData; + if (jwe.aad !== undefined) { + additionalData = (0, buffer_utils_js_1.concat)(protectedHeader, buffer_utils_js_1.encoder.encode('.'), buffer_utils_js_1.encoder.encode(jwe.aad)); + } + else { + additionalData = protectedHeader; + } + let plaintext = await (0, decrypt_js_1.default)(enc, cek, (0, base64url_js_1.decode)(jwe.ciphertext), iv, tag, additionalData); + if (joseHeader.zip === 'DEF') { + plaintext = await ((options === null || options === void 0 ? void 0 : options.inflateRaw) || zlib_js_1.inflate)(plaintext); + } + const result = { plaintext }; + if (jwe.protected !== undefined) { + result.protectedHeader = parsedProt; + } + if (jwe.aad !== undefined) { + result.additionalAuthenticatedData = (0, base64url_js_1.decode)(jwe.aad); + } + if (jwe.unprotected !== undefined) { + result.sharedUnprotectedHeader = jwe.unprotected; + } + if (jwe.header !== undefined) { + result.unprotectedHeader = jwe.header; + } + return result; +} +exports.flattenedDecrypt = flattenedDecrypt; +exports.default = flattenedDecrypt; diff --git a/dist/node/cjs/jwe/flattened/encrypt.js b/dist/node/cjs/jwe/flattened/encrypt.js new file mode 100644 index 0000000000..bee0b1b639 --- /dev/null +++ b/dist/node/cjs/jwe/flattened/encrypt.js @@ -0,0 +1,172 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.FlattenedEncrypt = void 0; +const iv_js_1 = require("../../lib/iv.js"); +const base64url_js_1 = require("../../runtime/base64url.js"); +const random_js_1 = require("../../runtime/random.js"); +const encrypt_js_1 = require("../../runtime/encrypt.js"); +const zlib_js_1 = require("../../runtime/zlib.js"); +const encrypt_key_management_js_1 = require("../../lib/encrypt_key_management.js"); +const errors_js_1 = require("../../util/errors.js"); +const is_disjoint_js_1 = require("../../lib/is_disjoint.js"); +const buffer_utils_js_1 = require("../../lib/buffer_utils.js"); +const validate_crit_js_1 = require("../../lib/validate_crit.js"); +const generateIv = (0, iv_js_1.default)(random_js_1.default); +const checkExtensions = validate_crit_js_1.default.bind(undefined, errors_js_1.JWEInvalid, new Map()); +class FlattenedEncrypt { + constructor(plaintext) { + if (!(plaintext instanceof Uint8Array)) { + throw new TypeError('plaintext must be an instance of Uint8Array'); + } + this._plaintext = plaintext; + } + setKeyManagementParameters(parameters) { + if (this._keyManagementParameters) { + throw new TypeError('setKeyManagementParameters can only be called once'); + } + this._keyManagementParameters = parameters; + return this; + } + setProtectedHeader(protectedHeader) { + if (this._protectedHeader) { + throw new TypeError('setProtectedHeader can only be called once'); + } + this._protectedHeader = protectedHeader; + return this; + } + setSharedUnprotectedHeader(sharedUnprotectedHeader) { + if (this._sharedUnprotectedHeader) { + throw new TypeError('setSharedUnprotectedHeader can only be called once'); + } + this._sharedUnprotectedHeader = sharedUnprotectedHeader; + return this; + } + setUnprotectedHeader(unprotectedHeader) { + if (this._unprotectedHeader) { + throw new TypeError('setUnprotectedHeader can only be called once'); + } + this._unprotectedHeader = unprotectedHeader; + return this; + } + setAdditionalAuthenticatedData(aad) { + this._aad = aad; + return this; + } + setContentEncryptionKey(cek) { + if (this._cek) { + throw new TypeError('setContentEncryptionKey can only be called once'); + } + this._cek = cek; + return this; + } + setInitializationVector(iv) { + if (this._iv) { + throw new TypeError('setInitializationVector can only be called once'); + } + this._iv = iv; + return this; + } + async encrypt(key, options) { + if (!this._protectedHeader && !this._unprotectedHeader && !this._sharedUnprotectedHeader) { + throw new errors_js_1.JWEInvalid('either setProtectedHeader, setUnprotectedHeader, or sharedUnprotectedHeader must be called before #encrypt()'); + } + if (!(0, is_disjoint_js_1.default)(this._protectedHeader, this._unprotectedHeader, this._sharedUnprotectedHeader)) { + throw new errors_js_1.JWEInvalid('JWE Shared Protected, JWE Shared Unprotected and JWE Per-Recipient Header Parameter names must be disjoint'); + } + const joseHeader = { + ...this._protectedHeader, + ...this._unprotectedHeader, + ...this._sharedUnprotectedHeader, + }; + checkExtensions(options === null || options === void 0 ? void 0 : options.crit, this._protectedHeader, joseHeader); + if (joseHeader.zip !== undefined) { + if (!this._protectedHeader || !this._protectedHeader.zip) { + throw new errors_js_1.JWEInvalid('JWE "zip" (Compression Algorithm) Header MUST be integrity protected'); + } + if (joseHeader.zip !== 'DEF') { + throw new errors_js_1.JOSENotSupported('unsupported JWE "zip" (Compression Algorithm) Header Parameter value'); + } + } + const { alg, enc } = joseHeader; + if (typeof alg !== 'string' || !alg) { + throw new errors_js_1.JWEInvalid('JWE "alg" (Algorithm) Header Parameter missing or invalid'); + } + if (typeof enc !== 'string' || !enc) { + throw new errors_js_1.JWEInvalid('JWE "enc" (Encryption Algorithm) Header Parameter missing or invalid'); + } + let encryptedKey; + 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; + { + let parameters; + ({ cek, encryptedKey, parameters } = await (0, encrypt_key_management_js_1.default)(alg, enc, key, this._cek, this._keyManagementParameters)); + if (parameters) { + if (!this._protectedHeader) { + this.setProtectedHeader(parameters); + } + else { + this._protectedHeader = { ...this._protectedHeader, ...parameters }; + } + } + } + this._iv || (this._iv = generateIv(enc)); + let additionalData; + let protectedHeader; + let aadMember; + if (this._protectedHeader) { + protectedHeader = buffer_utils_js_1.encoder.encode((0, base64url_js_1.encode)(JSON.stringify(this._protectedHeader))); + } + else { + protectedHeader = buffer_utils_js_1.encoder.encode(''); + } + if (this._aad) { + aadMember = (0, base64url_js_1.encode)(this._aad); + additionalData = (0, buffer_utils_js_1.concat)(protectedHeader, buffer_utils_js_1.encoder.encode('.'), buffer_utils_js_1.encoder.encode(aadMember)); + } + else { + additionalData = protectedHeader; + } + let ciphertext; + let tag; + if (joseHeader.zip === 'DEF') { + const deflated = await ((options === null || options === void 0 ? void 0 : options.deflateRaw) || zlib_js_1.deflate)(this._plaintext); + ({ ciphertext, tag } = await (0, encrypt_js_1.default)(enc, deflated, cek, this._iv, additionalData)); + } + else { + ; + ({ ciphertext, tag } = await (0, encrypt_js_1.default)(enc, this._plaintext, cek, this._iv, additionalData)); + } + const jwe = { + ciphertext: (0, base64url_js_1.encode)(ciphertext), + iv: (0, base64url_js_1.encode)(this._iv), + tag: (0, base64url_js_1.encode)(tag), + }; + if (encryptedKey) { + jwe.encrypted_key = (0, base64url_js_1.encode)(encryptedKey); + } + if (aadMember) { + jwe.aad = aadMember; + } + if (this._protectedHeader) { + jwe.protected = buffer_utils_js_1.decoder.decode(protectedHeader); + } + if (this._sharedUnprotectedHeader) { + jwe.unprotected = this._sharedUnprotectedHeader; + } + if (this._unprotectedHeader) { + jwe.header = this._unprotectedHeader; + } + return jwe; + } +} +exports.FlattenedEncrypt = FlattenedEncrypt; +exports.default = FlattenedEncrypt; diff --git a/dist/node/cjs/jwe/general/decrypt.js b/dist/node/cjs/jwe/general/decrypt.js new file mode 100644 index 0000000000..93adfd841d --- /dev/null +++ b/dist/node/cjs/jwe/general/decrypt.js @@ -0,0 +1,33 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.generalDecrypt = void 0; +const decrypt_js_1 = require("../flattened/decrypt.js"); +const errors_js_1 = require("../../util/errors.js"); +const is_object_js_1 = require("../../lib/is_object.js"); +async function generalDecrypt(jwe, key, options) { + if (!(0, is_object_js_1.default)(jwe)) { + throw new errors_js_1.JWEInvalid('General JWE must be an object'); + } + if (!Array.isArray(jwe.recipients) || !jwe.recipients.every(is_object_js_1.default)) { + throw new errors_js_1.JWEInvalid('JWE Recipients missing or incorrect type'); + } + for (const recipient of jwe.recipients) { + try { + return await (0, decrypt_js_1.default)({ + aad: jwe.aad, + ciphertext: jwe.ciphertext, + encrypted_key: recipient.encrypted_key, + header: recipient.header, + iv: jwe.iv, + protected: jwe.protected, + tag: jwe.tag, + unprotected: jwe.unprotected, + }, key, options); + } + catch { + } + } + throw new errors_js_1.JWEDecryptionFailed(); +} +exports.generalDecrypt = generalDecrypt; +exports.default = generalDecrypt; diff --git a/dist/node/cjs/jwk/embedded.js b/dist/node/cjs/jwk/embedded.js new file mode 100644 index 0000000000..6b4c267bed --- /dev/null +++ b/dist/node/cjs/jwk/embedded.js @@ -0,0 +1,22 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.EmbeddedJWK = void 0; +const parse_js_1 = require("./parse.js"); +const is_object_js_1 = require("../lib/is_object.js"); +const errors_js_1 = require("../util/errors.js"); +async function EmbeddedJWK(protectedHeader, token) { + const joseHeader = { + ...protectedHeader, + ...token.header, + }; + if (!(0, is_object_js_1.default)(joseHeader.jwk)) { + throw new errors_js_1.JWSInvalid('"jwk" (JSON Web Key) Header Parameter must be a JSON object'); + } + const key = await (0, parse_js_1.default)(joseHeader.jwk, joseHeader.alg, true); + if (key.type !== 'public') { + throw new errors_js_1.JWSInvalid('"jwk" (JSON Web Key) Header Parameter must be a public key'); + } + return key; +} +exports.EmbeddedJWK = EmbeddedJWK; +exports.default = EmbeddedJWK; diff --git a/dist/node/cjs/jwk/from_key_like.js b/dist/node/cjs/jwk/from_key_like.js new file mode 100644 index 0000000000..13454de1da --- /dev/null +++ b/dist/node/cjs/jwk/from_key_like.js @@ -0,0 +1,9 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.fromKeyLike = void 0; +const key_to_jwk_js_1 = require("../runtime/key_to_jwk.js"); +async function fromKeyLike(key) { + return (0, key_to_jwk_js_1.default)(key); +} +exports.fromKeyLike = fromKeyLike; +exports.default = fromKeyLike; diff --git a/dist/node/cjs/jwk/parse.js b/dist/node/cjs/jwk/parse.js new file mode 100644 index 0000000000..f5bd4e3d07 --- /dev/null +++ b/dist/node/cjs/jwk/parse.js @@ -0,0 +1,38 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.parseJwk = void 0; +const base64url_js_1 = require("../runtime/base64url.js"); +const jwk_to_key_js_1 = require("../runtime/jwk_to_key.js"); +const errors_js_1 = require("../util/errors.js"); +const is_object_js_1 = require("../lib/is_object.js"); +async function parseJwk(jwk, alg, octAsKeyObject) { + if (!(0, is_object_js_1.default)(jwk)) { + throw new TypeError('JWK must be an object'); + } + alg || (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'); + } + octAsKeyObject !== null && octAsKeyObject !== void 0 ? octAsKeyObject : (octAsKeyObject = jwk.ext !== true); + if (octAsKeyObject) { + return (0, jwk_to_key_js_1.default)({ ...jwk, alg, ext: false }); + } + return (0, base64url_js_1.decode)(jwk.k); + case 'RSA': + if (jwk.oth !== undefined) { + throw new errors_js_1.JOSENotSupported('RSA JWK "oth" (Other Primes Info) Parameter value is not supported'); + } + case 'EC': + case 'OKP': + return (0, jwk_to_key_js_1.default)({ ...jwk, alg }); + default: + throw new errors_js_1.JOSENotSupported('unsupported "kty" (Key Type) Parameter value'); + } +} +exports.parseJwk = parseJwk; +exports.default = parseJwk; diff --git a/dist/node/cjs/jwk/thumbprint.js b/dist/node/cjs/jwk/thumbprint.js new file mode 100644 index 0000000000..97b6d11688 --- /dev/null +++ b/dist/node/cjs/jwk/thumbprint.js @@ -0,0 +1,47 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.calculateThumbprint = void 0; +const errors_js_1 = require("../util/errors.js"); +const digest_js_1 = require("../runtime/digest.js"); +const base64url_js_1 = require("../runtime/base64url.js"); +const buffer_utils_js_1 = require("../lib/buffer_utils.js"); +const is_object_js_1 = require("../lib/is_object.js"); +const check = (value, description) => { + if (typeof value !== 'string' || !value) { + throw new errors_js_1.JWKInvalid(`${description} missing or invalid`); + } +}; +async function calculateThumbprint(jwk, digestAlgorithm = 'sha256') { + if (!(0, is_object_js_1.default)(jwk)) { + throw new TypeError('JWK must be an object'); + } + let components; + 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 errors_js_1.JOSENotSupported('"kty" (Key Type) Parameter missing or unsupported'); + } + const data = buffer_utils_js_1.encoder.encode(JSON.stringify(components)); + return (0, base64url_js_1.encode)(await (0, digest_js_1.default)(digestAlgorithm, data)); +} +exports.calculateThumbprint = calculateThumbprint; +exports.default = calculateThumbprint; diff --git a/dist/node/cjs/jwks/remote.js b/dist/node/cjs/jwks/remote.js new file mode 100644 index 0000000000..98015dd86f --- /dev/null +++ b/dist/node/cjs/jwks/remote.js @@ -0,0 +1,133 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.createRemoteJWKSet = void 0; +const parse_js_1 = require("../jwk/parse.js"); +const errors_js_1 = require("../util/errors.js"); +const fetch_jwks_js_1 = require("../runtime/fetch_jwks.js"); +const is_object_js_1 = require("../lib/is_object.js"); +function getKtyFromAlg(alg) { + switch (alg.substr(0, 2)) { + case 'RS': + case 'PS': + return 'RSA'; + case 'ES': + return 'EC'; + case 'Ed': + return 'OKP'; + default: + throw new errors_js_1.JOSENotSupported('Unsupported "alg" value for a JSON Web Key Set'); + } +} +function isJWKLike(key) { + return (0, is_object_js_1.default)(key); +} +class RemoteJWKSet { + constructor(url, options) { + this._cached = new WeakMap(); + if (!(url instanceof URL)) { + throw new TypeError('url must be an instance of URL'); + } + this._url = new URL(url.href); + this._options = { agent: options === null || options === void 0 ? void 0 : options.agent }; + this._timeoutDuration = + typeof (options === null || options === void 0 ? void 0 : options.timeoutDuration) === 'number' ? options === null || options === void 0 ? void 0 : options.timeoutDuration : 5000; + this._cooldownDuration = + typeof (options === null || options === void 0 ? void 0 : options.cooldownDuration) === 'number' ? options === null || options === void 0 ? void 0 : options.cooldownDuration : 30000; + } + coolingDown() { + if (typeof this._cooldownStarted === 'undefined') { + return false; + } + return Date.now() < this._cooldownStarted + this._cooldownDuration; + } + async getKey(protectedHeader) { + if (!this._jwks) { + await this.reload(); + } + const candidates = this._jwks.keys.filter((jwk) => { + let candidate = jwk.kty === getKtyFromAlg(protectedHeader.alg); + if (candidate && typeof protectedHeader.kid === 'string') { + candidate = protectedHeader.kid === jwk.kid; + } + if (candidate && typeof jwk.alg === 'string') { + candidate = protectedHeader.alg === jwk.alg; + } + if (candidate && typeof jwk.use === 'string') { + candidate = jwk.use === 'sig'; + } + if (candidate && Array.isArray(jwk.key_ops)) { + candidate = jwk.key_ops.includes('verify'); + } + if (candidate && protectedHeader.alg === 'EdDSA') { + candidate = ['Ed25519', 'Ed448'].includes(jwk.crv); + } + 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 errors_js_1.JWKSNoMatchingKey(); + } + else if (length !== 1) { + throw new errors_js_1.JWKSMultipleMatchingKeys(); + } + if (!this._cached.has(jwk)) { + this._cached.set(jwk, {}); + } + const cached = this._cached.get(jwk); + if (cached[protectedHeader.alg] === undefined) { + const keyObject = await (0, parse_js_1.default)({ ...jwk, alg: protectedHeader.alg }); + if (keyObject.type !== 'public') { + throw new errors_js_1.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 = (0, fetch_jwks_js_1.default)(this._url, this._timeoutDuration, this._options) + .then((json) => { + if (typeof json !== 'object' || + !json || + !Array.isArray(json.keys) || + !json.keys.every(isJWKLike)) { + throw new errors_js_1.JWKSInvalid('JSON Web Key Set malformed'); + } + this._jwks = { keys: json.keys }; + this._cooldownStarted = Date.now(); + this._pendingFetch = undefined; + }) + .catch((err) => { + this._pendingFetch = undefined; + throw err; + }); + } + await this._pendingFetch; + } +} +function createRemoteJWKSet(url, options) { + return RemoteJWKSet.prototype.getKey.bind(new RemoteJWKSet(url, options)); +} +exports.createRemoteJWKSet = createRemoteJWKSet; +exports.default = createRemoteJWKSet; diff --git a/dist/node/cjs/jws/compact/sign.js b/dist/node/cjs/jws/compact/sign.js new file mode 100644 index 0000000000..b49877f00f --- /dev/null +++ b/dist/node/cjs/jws/compact/sign.js @@ -0,0 +1,22 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.CompactSign = void 0; +const sign_js_1 = require("../flattened/sign.js"); +class CompactSign { + constructor(payload) { + this._flattened = new sign_js_1.default(payload); + } + setProtectedHeader(protectedHeader) { + this._flattened.setProtectedHeader(protectedHeader); + return this; + } + async sign(key, options) { + const jws = await this._flattened.sign(key, options); + if (jws.payload === undefined) { + throw new TypeError('use the flattened module for creating JWS with b64: false'); + } + return `${jws.protected}.${jws.payload}.${jws.signature}`; + } +} +exports.CompactSign = CompactSign; +exports.default = CompactSign; diff --git a/dist/node/cjs/jws/compact/verify.js b/dist/node/cjs/jws/compact/verify.js new file mode 100644 index 0000000000..78589b93af --- /dev/null +++ b/dist/node/cjs/jws/compact/verify.js @@ -0,0 +1,26 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.compactVerify = void 0; +const verify_js_1 = require("../flattened/verify.js"); +const errors_js_1 = require("../../util/errors.js"); +const buffer_utils_js_1 = require("../../lib/buffer_utils.js"); +async function compactVerify(jws, key, options) { + if (jws instanceof Uint8Array) { + jws = buffer_utils_js_1.decoder.decode(jws); + } + if (typeof jws !== 'string') { + throw new errors_js_1.JWSInvalid('Compact JWS must be a string or Uint8Array'); + } + const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split('.'); + if (length !== 3) { + throw new errors_js_1.JWSInvalid('Invalid Compact JWS'); + } + const verified = await (0, verify_js_1.default)({ + payload: (payload || undefined), + protected: protectedHeader || undefined, + signature: (signature || undefined), + }, key, options); + return { payload: verified.payload, protectedHeader: verified.protectedHeader }; +} +exports.compactVerify = compactVerify; +exports.default = compactVerify; diff --git a/dist/node/cjs/jws/flattened/sign.js b/dist/node/cjs/jws/flattened/sign.js new file mode 100644 index 0000000000..2146be5cc2 --- /dev/null +++ b/dist/node/cjs/jws/flattened/sign.js @@ -0,0 +1,87 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.FlattenedSign = void 0; +const is_disjoint_js_1 = require("../../lib/is_disjoint.js"); +const errors_js_1 = require("../../util/errors.js"); +const buffer_utils_js_1 = require("../../lib/buffer_utils.js"); +const base64url_js_1 = require("../../runtime/base64url.js"); +const sign_js_1 = require("../../runtime/sign.js"); +const check_key_type_js_1 = require("../../lib/check_key_type.js"); +const validate_crit_js_1 = require("../../lib/validate_crit.js"); +const checkExtensions = validate_crit_js_1.default.bind(undefined, errors_js_1.JWSInvalid, new Map([['b64', true]])); +class FlattenedSign { + constructor(payload) { + if (!(payload instanceof Uint8Array)) { + throw new TypeError('payload must be an instance of Uint8Array'); + } + this._payload = payload; + } + setProtectedHeader(protectedHeader) { + if (this._protectedHeader) { + throw new TypeError('setProtectedHeader can only be called once'); + } + this._protectedHeader = protectedHeader; + return this; + } + setUnprotectedHeader(unprotectedHeader) { + if (this._unprotectedHeader) { + throw new TypeError('setUnprotectedHeader can only be called once'); + } + this._unprotectedHeader = unprotectedHeader; + return this; + } + async sign(key, options) { + if (!this._protectedHeader && !this._unprotectedHeader) { + throw new errors_js_1.JWSInvalid('either setProtectedHeader or setUnprotectedHeader must be called before #sign()'); + } + if (!(0, is_disjoint_js_1.default)(this._protectedHeader, this._unprotectedHeader)) { + throw new errors_js_1.JWSInvalid('JWS Protected and JWS Unprotected Header Parameter names must be disjoint'); + } + const joseHeader = { + ...this._protectedHeader, + ...this._unprotectedHeader, + }; + const extensions = checkExtensions(options === null || options === void 0 ? void 0 : options.crit, this._protectedHeader, joseHeader); + let b64 = true; + if (extensions.has('b64')) { + b64 = this._protectedHeader.b64; + if (typeof b64 !== 'boolean') { + throw new errors_js_1.JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean'); + } + } + const { alg } = joseHeader; + if (typeof alg !== 'string' || !alg) { + throw new errors_js_1.JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid'); + } + (0, check_key_type_js_1.default)(alg, key, 'sign'); + let payload = this._payload; + if (b64) { + payload = buffer_utils_js_1.encoder.encode((0, base64url_js_1.encode)(payload)); + } + let protectedHeader; + if (this._protectedHeader) { + protectedHeader = buffer_utils_js_1.encoder.encode((0, base64url_js_1.encode)(JSON.stringify(this._protectedHeader))); + } + else { + protectedHeader = buffer_utils_js_1.encoder.encode(''); + } + const data = (0, buffer_utils_js_1.concat)(protectedHeader, buffer_utils_js_1.encoder.encode('.'), payload); + const signature = await (0, sign_js_1.default)(alg, key, data); + const jws = { + signature: (0, base64url_js_1.encode)(signature), + payload: '', + }; + if (b64) { + jws.payload = buffer_utils_js_1.decoder.decode(payload); + } + if (this._unprotectedHeader) { + jws.header = this._unprotectedHeader; + } + if (this._protectedHeader) { + jws.protected = buffer_utils_js_1.decoder.decode(protectedHeader); + } + return jws; + } +} +exports.FlattenedSign = FlattenedSign; +exports.default = FlattenedSign; diff --git a/dist/node/cjs/jws/flattened/verify.js b/dist/node/cjs/jws/flattened/verify.js new file mode 100644 index 0000000000..496458cce1 --- /dev/null +++ b/dist/node/cjs/jws/flattened/verify.js @@ -0,0 +1,106 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.flattenedVerify = void 0; +const errors_js_1 = require("../../util/errors.js"); +const buffer_utils_js_1 = require("../../lib/buffer_utils.js"); +const is_disjoint_js_1 = require("../../lib/is_disjoint.js"); +const is_object_js_1 = require("../../lib/is_object.js"); +const check_key_type_js_1 = require("../../lib/check_key_type.js"); +const base64url_js_1 = require("../../runtime/base64url.js"); +const verify_js_1 = require("../../runtime/verify.js"); +const validate_crit_js_1 = require("../../lib/validate_crit.js"); +const validate_algorithms_js_1 = require("../../lib/validate_algorithms.js"); +const checkExtensions = validate_crit_js_1.default.bind(undefined, errors_js_1.JWSInvalid, new Map([['b64', true]])); +const checkAlgOption = validate_algorithms_js_1.default.bind(undefined, 'algorithms'); +async function flattenedVerify(jws, key, options) { + var _a; + if (!(0, is_object_js_1.default)(jws)) { + throw new errors_js_1.JWSInvalid('Flattened JWS must be an object'); + } + if (jws.protected === undefined && jws.header === undefined) { + throw new errors_js_1.JWSInvalid('Flattened JWS must have either of the "protected" or "header" members'); + } + if (jws.protected !== undefined && typeof jws.protected !== 'string') { + throw new errors_js_1.JWSInvalid('JWS Protected Header incorrect type'); + } + if (jws.payload === undefined) { + throw new errors_js_1.JWSInvalid('JWS Payload missing'); + } + if (typeof jws.signature !== 'string') { + throw new errors_js_1.JWSInvalid('JWS Signature missing or incorrect type'); + } + if (jws.header !== undefined && !(0, is_object_js_1.default)(jws.header)) { + throw new errors_js_1.JWSInvalid('JWS Unprotected Header incorrect type'); + } + let parsedProt = {}; + if (jws.protected) { + const protectedHeader = (0, base64url_js_1.decode)(jws.protected); + try { + parsedProt = JSON.parse(buffer_utils_js_1.decoder.decode(protectedHeader)); + } + catch { + throw new errors_js_1.JWSInvalid('JWS Protected Header is invalid'); + } + } + if (!(0, is_disjoint_js_1.default)(parsedProt, jws.header)) { + throw new errors_js_1.JWSInvalid('JWS Protected and JWS Unprotected Header Parameter names must be disjoint'); + } + const joseHeader = { + ...parsedProt, + ...jws.header, + }; + const extensions = checkExtensions(options === null || options === void 0 ? void 0 : options.crit, parsedProt, joseHeader); + let b64 = true; + if (extensions.has('b64')) { + b64 = parsedProt.b64; + if (typeof b64 !== 'boolean') { + throw new errors_js_1.JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean'); + } + } + const { alg } = joseHeader; + if (typeof alg !== 'string' || !alg) { + throw new errors_js_1.JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid'); + } + const algorithms = options && checkAlgOption(options.algorithms); + if (algorithms && !algorithms.has(alg)) { + throw new errors_js_1.JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter not allowed'); + } + if (b64) { + if (typeof jws.payload !== 'string') { + throw new errors_js_1.JWSInvalid('JWS Payload must be a string'); + } + } + else if (typeof jws.payload !== 'string' && !(jws.payload instanceof Uint8Array)) { + throw new errors_js_1.JWSInvalid('JWS Payload must be a string or an Uint8Array instance'); + } + if (typeof key === 'function') { + key = await key(parsedProt, jws); + } + (0, check_key_type_js_1.default)(alg, key, 'verify'); + const data = (0, buffer_utils_js_1.concat)(buffer_utils_js_1.encoder.encode((_a = jws.protected) !== null && _a !== void 0 ? _a : ''), buffer_utils_js_1.encoder.encode('.'), typeof jws.payload === 'string' ? buffer_utils_js_1.encoder.encode(jws.payload) : jws.payload); + const signature = (0, base64url_js_1.decode)(jws.signature); + const verified = await (0, verify_js_1.default)(alg, key, signature, data); + if (!verified) { + throw new errors_js_1.JWSSignatureVerificationFailed(); + } + let payload; + if (b64) { + payload = (0, base64url_js_1.decode)(jws.payload); + } + else if (typeof jws.payload === 'string') { + payload = buffer_utils_js_1.encoder.encode(jws.payload); + } + else { + payload = jws.payload; + } + const result = { payload }; + if (jws.protected !== undefined) { + result.protectedHeader = parsedProt; + } + if (jws.header !== undefined) { + result.unprotectedHeader = jws.header; + } + return result; +} +exports.flattenedVerify = flattenedVerify; +exports.default = flattenedVerify; diff --git a/dist/node/cjs/jws/general/sign.js b/dist/node/cjs/jws/general/sign.js new file mode 100644 index 0000000000..502ce4059e --- /dev/null +++ b/dist/node/cjs/jws/general/sign.js @@ -0,0 +1,76 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.GeneralSign = void 0; +const sign_js_1 = require("../flattened/sign.js"); +const errors_js_1 = require("../../util/errors.js"); +const signatureRef = new WeakMap(); +class IndividualSignature { + setProtectedHeader(protectedHeader) { + if (this._protectedHeader) { + throw new TypeError('setProtectedHeader can only be called once'); + } + this._protectedHeader = protectedHeader; + return this; + } + setUnprotectedHeader(unprotectedHeader) { + if (this._unprotectedHeader) { + throw new TypeError('setUnprotectedHeader can only be called once'); + } + this._unprotectedHeader = unprotectedHeader; + return this; + } + set _protectedHeader(value) { + signatureRef.get(this).protectedHeader = value; + } + get _protectedHeader() { + return signatureRef.get(this).protectedHeader; + } + set _unprotectedHeader(value) { + signatureRef.get(this).unprotectedHeader = value; + } + get _unprotectedHeader() { + return signatureRef.get(this).unprotectedHeader; + } +} +class GeneralSign { + constructor(payload) { + this._signatures = []; + this._payload = payload; + } + addSignature(key, options) { + const signature = new IndividualSignature(); + signatureRef.set(signature, { key, options }); + this._signatures.push(signature); + return signature; + } + async sign() { + if (!this._signatures.length) { + throw new errors_js_1.JWSInvalid('at least one signature must be added'); + } + const jws = { + signatures: [], + payload: '', + }; + let payloads = new Set(); + await Promise.all(this._signatures.map(async (sig) => { + const { protectedHeader, unprotectedHeader, options, key } = signatureRef.get(sig); + const flattened = new sign_js_1.default(this._payload); + if (protectedHeader) { + flattened.setProtectedHeader(protectedHeader); + } + if (unprotectedHeader) { + flattened.setUnprotectedHeader(unprotectedHeader); + } + const { payload, ...rest } = await flattened.sign(key, options); + payloads.add(payload); + jws.payload = payload; + jws.signatures.push(rest); + })); + if (payloads.size !== 1) { + throw new errors_js_1.JWSInvalid('inconsistent use of JWS Unencoded Payload Option (RFC7797)'); + } + return jws; + } +} +exports.GeneralSign = GeneralSign; +exports.default = GeneralSign; diff --git a/dist/node/cjs/jws/general/verify.js b/dist/node/cjs/jws/general/verify.js new file mode 100644 index 0000000000..1705c5eccb --- /dev/null +++ b/dist/node/cjs/jws/general/verify.js @@ -0,0 +1,29 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.generalVerify = void 0; +const verify_js_1 = require("../flattened/verify.js"); +const errors_js_1 = require("../../util/errors.js"); +const is_object_js_1 = require("../../lib/is_object.js"); +async function generalVerify(jws, key, options) { + if (!(0, is_object_js_1.default)(jws)) { + throw new errors_js_1.JWSInvalid('General JWS must be an object'); + } + if (!Array.isArray(jws.signatures) || !jws.signatures.every(is_object_js_1.default)) { + throw new errors_js_1.JWSInvalid('JWS Signatures missing or incorrect type'); + } + for (const signature of jws.signatures) { + try { + return await (0, verify_js_1.default)({ + header: signature.header, + payload: jws.payload, + protected: signature.protected, + signature: signature.signature, + }, key, options); + } + catch { + } + } + throw new errors_js_1.JWSSignatureVerificationFailed(); +} +exports.generalVerify = generalVerify; +exports.default = generalVerify; diff --git a/dist/node/cjs/jwt/decrypt.js b/dist/node/cjs/jwt/decrypt.js new file mode 100644 index 0000000000..c9a7ea9127 --- /dev/null +++ b/dist/node/cjs/jwt/decrypt.js @@ -0,0 +1,24 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.jwtDecrypt = void 0; +const decrypt_js_1 = require("../jwe/compact/decrypt.js"); +const jwt_claims_set_js_1 = require("../lib/jwt_claims_set.js"); +const errors_js_1 = require("../util/errors.js"); +async function jwtDecrypt(jwt, key, options) { + const decrypted = await (0, decrypt_js_1.default)(jwt, key, options); + const payload = (0, jwt_claims_set_js_1.default)(decrypted.protectedHeader, decrypted.plaintext, options); + const { protectedHeader } = decrypted; + if (protectedHeader.iss !== undefined && protectedHeader.iss !== payload.iss) { + throw new errors_js_1.JWTClaimValidationFailed('replicated "iss" claim header parameter mismatch', 'iss', 'mismatch'); + } + if (protectedHeader.sub !== undefined && protectedHeader.sub !== payload.sub) { + throw new errors_js_1.JWTClaimValidationFailed('replicated "sub" claim header parameter mismatch', 'sub', 'mismatch'); + } + if (protectedHeader.aud !== undefined && + JSON.stringify(protectedHeader.aud) !== JSON.stringify(payload.aud)) { + throw new errors_js_1.JWTClaimValidationFailed('replicated "aud" claim header parameter mismatch', 'aud', 'mismatch'); + } + return { payload, protectedHeader }; +} +exports.jwtDecrypt = jwtDecrypt; +exports.default = jwtDecrypt; diff --git a/dist/node/cjs/jwt/encrypt.js b/dist/node/cjs/jwt/encrypt.js new file mode 100644 index 0000000000..9c4cad87e2 --- /dev/null +++ b/dist/node/cjs/jwt/encrypt.js @@ -0,0 +1,73 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.EncryptJWT = void 0; +const encrypt_js_1 = require("../jwe/compact/encrypt.js"); +const buffer_utils_js_1 = require("../lib/buffer_utils.js"); +const jwt_producer_js_1 = require("../lib/jwt_producer.js"); +class EncryptJWT extends jwt_producer_js_1.default { + setProtectedHeader(protectedHeader) { + if (this._protectedHeader) { + throw new TypeError('setProtectedHeader can only be called once'); + } + this._protectedHeader = protectedHeader; + return this; + } + setKeyManagementParameters(parameters) { + if (this._keyManagementParameters) { + throw new TypeError('setKeyManagementParameters can only be called once'); + } + this._keyManagementParameters = parameters; + return this; + } + setContentEncryptionKey(cek) { + if (this._cek) { + throw new TypeError('setContentEncryptionKey can only be called once'); + } + this._cek = cek; + return this; + } + setInitializationVector(iv) { + if (this._iv) { + throw new TypeError('setInitializationVector can only be called once'); + } + this._iv = iv; + return this; + } + replicateIssuerAsHeader() { + this._replicateIssuerAsHeader = true; + return this; + } + replicateSubjectAsHeader() { + this._replicateSubjectAsHeader = true; + return this; + } + replicateAudienceAsHeader() { + this._replicateAudienceAsHeader = true; + return this; + } + async encrypt(key, options) { + const enc = new encrypt_js_1.default(buffer_utils_js_1.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); + } +} +exports.EncryptJWT = EncryptJWT; +exports.default = EncryptJWT; diff --git a/dist/node/cjs/jwt/sign.js b/dist/node/cjs/jwt/sign.js new file mode 100644 index 0000000000..e14fd2d3e1 --- /dev/null +++ b/dist/node/cjs/jwt/sign.js @@ -0,0 +1,26 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.SignJWT = void 0; +const sign_js_1 = require("../jws/compact/sign.js"); +const errors_js_1 = require("../util/errors.js"); +const buffer_utils_js_1 = require("../lib/buffer_utils.js"); +const jwt_producer_js_1 = require("../lib/jwt_producer.js"); +class SignJWT extends jwt_producer_js_1.default { + setProtectedHeader(protectedHeader) { + this._protectedHeader = protectedHeader; + return this; + } + async sign(key, options) { + var _a; + const sig = new sign_js_1.default(buffer_utils_js_1.encoder.encode(JSON.stringify(this._payload))); + sig.setProtectedHeader(this._protectedHeader); + if (Array.isArray((_a = this._protectedHeader) === null || _a === void 0 ? void 0 : _a.crit) && + this._protectedHeader.crit.includes('b64') && + this._protectedHeader.b64 === false) { + throw new errors_js_1.JWTInvalid('JWTs MUST NOT use unencoded payload'); + } + return sig.sign(key, options); + } +} +exports.SignJWT = SignJWT; +exports.default = SignJWT; diff --git a/dist/node/cjs/jwt/unsecured.js b/dist/node/cjs/jwt/unsecured.js new file mode 100644 index 0000000000..e48775b877 --- /dev/null +++ b/dist/node/cjs/jwt/unsecured.js @@ -0,0 +1,37 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.UnsecuredJWT = void 0; +const buffer_utils_js_1 = require("../lib/buffer_utils.js"); +const base64url = require("../runtime/base64url.js"); +const errors_js_1 = require("../util/errors.js"); +const jwt_claims_set_js_1 = require("../lib/jwt_claims_set.js"); +const jwt_producer_js_1 = require("../lib/jwt_producer.js"); +class UnsecuredJWT extends jwt_producer_js_1.default { + encode() { + const header = base64url.encode(JSON.stringify({ alg: 'none' })); + const payload = base64url.encode(JSON.stringify(this._payload)); + return `${header}.${payload}.`; + } + static decode(jwt, options) { + if (typeof jwt !== 'string') { + throw new errors_js_1.JWTInvalid('Unsecured JWT must be a string'); + } + const { 0: encodedHeader, 1: encodedPayload, 2: signature, length } = jwt.split('.'); + if (length !== 3 || signature !== '') { + throw new errors_js_1.JWTInvalid('Invalid Unsecured JWT'); + } + let header; + try { + header = JSON.parse(buffer_utils_js_1.decoder.decode(base64url.decode(encodedHeader))); + if (header.alg !== 'none') + throw new Error(); + } + catch { + throw new errors_js_1.JWTInvalid('Invalid Unsecured JWT'); + } + const payload = (0, jwt_claims_set_js_1.default)(header, base64url.decode(encodedPayload), options); + return { payload, header }; + } +} +exports.UnsecuredJWT = UnsecuredJWT; +exports.default = UnsecuredJWT; diff --git a/dist/node/cjs/jwt/verify.js b/dist/node/cjs/jwt/verify.js new file mode 100644 index 0000000000..6c9ad2d024 --- /dev/null +++ b/dist/node/cjs/jwt/verify.js @@ -0,0 +1,17 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.jwtVerify = void 0; +const verify_js_1 = require("../jws/compact/verify.js"); +const jwt_claims_set_js_1 = require("../lib/jwt_claims_set.js"); +const errors_js_1 = require("../util/errors.js"); +async function jwtVerify(jwt, key, options) { + var _a; + const verified = await (0, verify_js_1.default)(jwt, key, options); + if (((_a = verified.protectedHeader.crit) === null || _a === void 0 ? void 0 : _a.includes('b64')) && verified.protectedHeader.b64 === false) { + throw new errors_js_1.JWTInvalid('JWTs MUST NOT use unencoded payload'); + } + const payload = (0, jwt_claims_set_js_1.default)(verified.protectedHeader, verified.payload, options); + return { payload, protectedHeader: verified.protectedHeader }; +} +exports.jwtVerify = jwtVerify; +exports.default = jwtVerify; diff --git a/dist/node/cjs/lib/buffer_utils.js b/dist/node/cjs/lib/buffer_utils.js new file mode 100644 index 0000000000..9a431eb835 --- /dev/null +++ b/dist/node/cjs/lib/buffer_utils.js @@ -0,0 +1,65 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.concatKdf = exports.lengthAndInput = exports.uint32be = exports.uint64be = exports.p2s = exports.concat = exports.decoder = exports.encoder = void 0; +exports.encoder = new TextEncoder(); +exports.decoder = new TextDecoder(); +const MAX_INT32 = 2 ** 32; +function concat(...buffers) { + 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; +} +exports.concat = concat; +function p2s(alg, p2sInput) { + return concat(exports.encoder.encode(alg), new Uint8Array([0]), p2sInput); +} +exports.p2s = p2s; +function writeUInt32BE(buf, value, offset) { + 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); +} +function uint64be(value) { + 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; +} +exports.uint64be = uint64be; +function uint32be(value) { + const buf = new Uint8Array(4); + writeUInt32BE(buf, value); + return buf; +} +exports.uint32be = uint32be; +function lengthAndInput(input) { + return concat(uint32be(input.length), input); +} +exports.lengthAndInput = lengthAndInput; +async function concatKdf(digest, secret, bits, value) { + const iterations = Math.ceil((bits >> 3) / 32); + let res; + 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('sha256', buf); + } + else { + res = concat(res, await digest('sha256', buf)); + } + } + res = res.slice(0, bits >> 3); + return res; +} +exports.concatKdf = concatKdf; diff --git a/dist/node/cjs/lib/cek.js b/dist/node/cjs/lib/cek.js new file mode 100644 index 0000000000..1d6311bb93 --- /dev/null +++ b/dist/node/cjs/lib/cek.js @@ -0,0 +1,21 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.bitLengths = void 0; +const errors_js_1 = require("../util/errors.js"); +const bitLengths = new Map([ + ['A128CBC-HS256', 256], + ['A128GCM', 128], + ['A192CBC-HS384', 384], + ['A192GCM', 192], + ['A256CBC-HS512', 512], + ['A256GCM', 256], +]); +exports.bitLengths = bitLengths; +const factory = (random) => (alg) => { + const bitLength = bitLengths.get(alg); + if (!bitLength) { + throw new errors_js_1.JOSENotSupported(`Unsupported JWE Algorithm: ${alg}`); + } + return random(new Uint8Array(bitLength >> 3)); +}; +exports.default = factory; diff --git a/dist/node/cjs/lib/check_iv_length.js b/dist/node/cjs/lib/check_iv_length.js new file mode 100644 index 0000000000..d45f5b8f44 --- /dev/null +++ b/dist/node/cjs/lib/check_iv_length.js @@ -0,0 +1,10 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const errors_js_1 = require("../util/errors.js"); +const iv_js_1 = require("./iv.js"); +const checkIvLength = (enc, iv) => { + if (iv.length << 3 !== iv_js_1.bitLengths.get(enc)) { + throw new errors_js_1.JWEInvalid('Invalid Initialization Vector length'); + } +}; +exports.default = checkIvLength; diff --git a/dist/node/cjs/lib/check_key_type.js b/dist/node/cjs/lib/check_key_type.js new file mode 100644 index 0000000000..edeb6c1ffc --- /dev/null +++ b/dist/node/cjs/lib/check_key_type.js @@ -0,0 +1,30 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const invalid_key_input_js_1 = require("../runtime/invalid_key_input.js"); +const checkKeyType = (alg, key, usage) => { + if (!(key instanceof Uint8Array) && !(key === null || key === void 0 ? void 0 : key.type)) { + throw new TypeError((0, invalid_key_input_js_1.default)(key, 'KeyObject', 'CryptoKey', 'Uint8Array')); + } + 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((0, invalid_key_input_js_1.default)(key, 'KeyObject', 'CryptoKey')); + } + if (key.type === 'secret') { + throw new TypeError('CryptoKey or KeyObject instances for asymmetric algorithms must not be of type "secret"'); + } + if (usage === 'sign' && key.type === 'public') { + throw new TypeError('CryptoKey or KeyObject instances for asymmetric algorithm signing must be of type "private"'); + } + if (usage === 'decrypt' && key.type === 'public') { + throw new TypeError('CryptoKey or KeyObject instances for asymmetric algorithm decryption must be of type "private"'); + } +}; +exports.default = checkKeyType; diff --git a/dist/node/cjs/lib/check_p2s.js b/dist/node/cjs/lib/check_p2s.js new file mode 100644 index 0000000000..4bdeaa766c --- /dev/null +++ b/dist/node/cjs/lib/check_p2s.js @@ -0,0 +1,9 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const errors_js_1 = require("../util/errors.js"); +function checkP2s(p2s) { + if (!(p2s instanceof Uint8Array) || p2s.length < 8) { + throw new errors_js_1.JWEInvalid('PBES2 Salt Input must be 8 or more octets'); + } +} +exports.default = checkP2s; diff --git a/dist/node/cjs/lib/decrypt_key_management.js b/dist/node/cjs/lib/decrypt_key_management.js new file mode 100644 index 0000000000..4f83b7c135 --- /dev/null +++ b/dist/node/cjs/lib/decrypt_key_management.js @@ -0,0 +1,97 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const errors_js_1 = require("../util/errors.js"); +const aeskw_js_1 = require("../runtime/aeskw.js"); +const ECDH = require("../runtime/ecdhes.js"); +const pbes2kw_js_1 = require("../runtime/pbes2kw.js"); +const rsaes_js_1 = require("../runtime/rsaes.js"); +const aesgcmkw_js_1 = require("../runtime/aesgcmkw.js"); +const base64url_js_1 = require("../runtime/base64url.js"); +const cek_js_1 = require("../lib/cek.js"); +const parse_js_1 = require("../jwk/parse.js"); +const check_key_type_js_1 = require("./check_key_type.js"); +function assertEnryptedKey(encryptedKey) { + if (!encryptedKey) { + throw new errors_js_1.JWEInvalid('JWE Encrypted Key missing'); + } +} +function assertHeaderParameter(joseHeader, parameter, name) { + if (joseHeader[parameter] === undefined) { + throw new errors_js_1.JWEInvalid(`JOSE Header ${name} (${parameter}) missing`); + } +} +async function decryptKeyManagement(alg, key, encryptedKey, joseHeader) { + (0, check_key_type_js_1.default)(alg, key, 'decrypt'); + switch (alg) { + case 'dir': { + if (encryptedKey !== undefined) { + throw new errors_js_1.JWEInvalid('Encountered unexpected JWE Encrypted Key'); + } + return key; + } + case 'ECDH-ES': + if (encryptedKey !== undefined) { + throw new errors_js_1.JWEInvalid('Encountered unexpected JWE Encrypted Key'); + } + case 'ECDH-ES+A128KW': + case 'ECDH-ES+A192KW': + case 'ECDH-ES+A256KW': { + assertHeaderParameter(joseHeader, 'epk', 'Ephemeral Public Key'); + if (!ECDH.ecdhAllowed(key)) { + throw new errors_js_1.JOSENotSupported('ECDH-ES with the provided key is not allowed or not supported by your javascript runtime'); + } + const epk = await (0, parse_js_1.parseJwk)(joseHeader.epk, alg); + let partyUInfo; + let partyVInfo; + if (joseHeader.apu !== undefined) + partyUInfo = (0, base64url_js_1.decode)(joseHeader.apu); + if (joseHeader.apv !== undefined) + partyVInfo = (0, base64url_js_1.decode)(joseHeader.apv); + const sharedSecret = await ECDH.deriveKey(epk, key, alg === 'ECDH-ES' ? joseHeader.enc : alg, parseInt(alg.substr(-5, 3), 10) || cek_js_1.bitLengths.get(joseHeader.enc), partyUInfo, partyVInfo); + if (alg === 'ECDH-ES') { + return sharedSecret; + } + assertEnryptedKey(encryptedKey); + const kwAlg = alg.substr(-6); + return (0, aeskw_js_1.unwrap)(kwAlg, sharedSecret, encryptedKey); + } + case 'RSA1_5': + case 'RSA-OAEP': + case 'RSA-OAEP-256': + case 'RSA-OAEP-384': + case 'RSA-OAEP-512': { + assertEnryptedKey(encryptedKey); + return (0, rsaes_js_1.decrypt)(alg, key, encryptedKey); + } + case 'PBES2-HS256+A128KW': + case 'PBES2-HS384+A192KW': + case 'PBES2-HS512+A256KW': { + assertEnryptedKey(encryptedKey); + assertHeaderParameter(joseHeader, 'p2c', 'PBES2 Count'); + assertHeaderParameter(joseHeader, 'p2s', 'PBES2 Salt'); + const { p2c } = joseHeader; + const p2s = (0, base64url_js_1.decode)(joseHeader.p2s); + return (0, pbes2kw_js_1.decrypt)(alg, key, encryptedKey, p2c, p2s); + } + case 'A128KW': + case 'A192KW': + case 'A256KW': { + assertEnryptedKey(encryptedKey); + return (0, aeskw_js_1.unwrap)(alg, key, encryptedKey); + } + case 'A128GCMKW': + case 'A192GCMKW': + case 'A256GCMKW': { + assertEnryptedKey(encryptedKey); + assertHeaderParameter(joseHeader, 'iv', 'Initialization Vector'); + assertHeaderParameter(joseHeader, 'tag', 'Authentication Tag'); + const iv = (0, base64url_js_1.decode)(joseHeader.iv); + const tag = (0, base64url_js_1.decode)(joseHeader.tag); + return (0, aesgcmkw_js_1.unwrap)(alg, key, encryptedKey, iv, tag); + } + default: { + throw new errors_js_1.JOSENotSupported('unsupported or invalid "alg" (JWE Algorithm) header value'); + } + } +} +exports.default = decryptKeyManagement; diff --git a/dist/node/cjs/lib/encrypt_key_management.js b/dist/node/cjs/lib/encrypt_key_management.js new file mode 100644 index 0000000000..212f707750 --- /dev/null +++ b/dist/node/cjs/lib/encrypt_key_management.js @@ -0,0 +1,89 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const cek_js_1 = require("../lib/cek.js"); +const errors_js_1 = require("../util/errors.js"); +const random_js_1 = require("../runtime/random.js"); +const aeskw_js_1 = require("../runtime/aeskw.js"); +const ECDH = require("../runtime/ecdhes.js"); +const pbes2kw_js_1 = require("../runtime/pbes2kw.js"); +const rsaes_js_1 = require("../runtime/rsaes.js"); +const aesgcmkw_js_1 = require("../runtime/aesgcmkw.js"); +const base64url_js_1 = require("../runtime/base64url.js"); +const from_key_like_js_1 = require("../jwk/from_key_like.js"); +const check_key_type_js_1 = require("./check_key_type.js"); +const generateCek = (0, cek_js_1.default)(random_js_1.default); +async function encryptKeyManagement(alg, enc, key, providedCek, providedParameters = {}) { + let encryptedKey; + let parameters; + let cek; + (0, check_key_type_js_1.default)(alg, key, 'encrypt'); + switch (alg) { + case 'dir': { + cek = key; + break; + } + case 'ECDH-ES': + case 'ECDH-ES+A128KW': + case 'ECDH-ES+A192KW': + case 'ECDH-ES+A256KW': { + if (!ECDH.ecdhAllowed(key)) { + throw new errors_js_1.JOSENotSupported('ECDH-ES with the provided key is not allowed or not supported by your javascript runtime'); + } + const { apu, apv } = providedParameters; + let { epk: ephemeralKey } = providedParameters; + ephemeralKey || (ephemeralKey = await ECDH.generateEpk(key)); + const { x, y, crv, kty } = await (0, from_key_like_js_1.fromKeyLike)(ephemeralKey); + const sharedSecret = await ECDH.deriveKey(key, ephemeralKey, alg === 'ECDH-ES' ? enc : alg, parseInt(alg.substr(-5, 3), 10) || cek_js_1.bitLengths.get(enc), apu, apv); + parameters = { epk: { x, y, crv, kty } }; + if (apu) + parameters.apu = (0, base64url_js_1.encode)(apu); + if (apv) + parameters.apv = (0, base64url_js_1.encode)(apv); + if (alg === 'ECDH-ES') { + cek = sharedSecret; + break; + } + cek = providedCek || generateCek(enc); + const kwAlg = alg.substr(-6); + encryptedKey = await (0, aeskw_js_1.wrap)(kwAlg, sharedSecret, cek); + break; + } + case 'RSA1_5': + case 'RSA-OAEP': + case 'RSA-OAEP-256': + case 'RSA-OAEP-384': + case 'RSA-OAEP-512': { + cek = providedCek || generateCek(enc); + encryptedKey = await (0, rsaes_js_1.encrypt)(alg, key, cek); + break; + } + case 'PBES2-HS256+A128KW': + case 'PBES2-HS384+A192KW': + case 'PBES2-HS512+A256KW': { + cek = providedCek || generateCek(enc); + const { p2c, p2s } = providedParameters; + ({ encryptedKey, ...parameters } = await (0, pbes2kw_js_1.encrypt)(alg, key, cek, p2c, p2s)); + break; + } + case 'A128KW': + case 'A192KW': + case 'A256KW': { + cek = providedCek || generateCek(enc); + encryptedKey = await (0, aeskw_js_1.wrap)(alg, key, cek); + break; + } + case 'A128GCMKW': + case 'A192GCMKW': + case 'A256GCMKW': { + cek = providedCek || generateCek(enc); + const { iv } = providedParameters; + ({ encryptedKey, ...parameters } = await (0, aesgcmkw_js_1.wrap)(alg, key, cek, iv)); + break; + } + default: { + throw new errors_js_1.JOSENotSupported('unsupported or invalid "alg" (JWE Algorithm) header value'); + } + } + return { cek, encryptedKey, parameters }; +} +exports.default = encryptKeyManagement; diff --git a/dist/node/cjs/lib/epoch.js b/dist/node/cjs/lib/epoch.js new file mode 100644 index 0000000000..a0792b4f7f --- /dev/null +++ b/dist/node/cjs/lib/epoch.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.default = (date) => Math.floor(date.getTime() / 1000); diff --git a/dist/node/cjs/lib/is_disjoint.js b/dist/node/cjs/lib/is_disjoint.js new file mode 100644 index 0000000000..66c2fc6c82 --- /dev/null +++ b/dist/node/cjs/lib/is_disjoint.js @@ -0,0 +1,24 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const isDisjoint = (...headers) => { + const sources = headers.filter(Boolean); + if (sources.length === 0 || sources.length === 1) { + return true; + } + let acc; + 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; +}; +exports.default = isDisjoint; diff --git a/dist/node/cjs/lib/is_object.js b/dist/node/cjs/lib/is_object.js new file mode 100644 index 0000000000..870938b59b --- /dev/null +++ b/dist/node/cjs/lib/is_object.js @@ -0,0 +1,19 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +function isObjectLike(value) { + return typeof value === 'object' && value !== null; +} +function isObject(input) { + if (!isObjectLike(input) || Object.prototype.toString.call(input) !== '[object Object]') { + return false; + } + if (Object.getPrototypeOf(input) === null) { + return true; + } + let proto = input; + while (Object.getPrototypeOf(proto) !== null) { + proto = Object.getPrototypeOf(proto); + } + return Object.getPrototypeOf(input) === proto; +} +exports.default = isObject; diff --git a/dist/node/cjs/lib/iv.js b/dist/node/cjs/lib/iv.js new file mode 100644 index 0000000000..a57ae9cfd3 --- /dev/null +++ b/dist/node/cjs/lib/iv.js @@ -0,0 +1,24 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.bitLengths = void 0; +const errors_js_1 = require("../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], +]); +exports.bitLengths = bitLengths; +const factory = (random) => (alg) => { + const bitLength = bitLengths.get(alg); + if (!bitLength) { + throw new errors_js_1.JOSENotSupported(`Unsupported JWE Algorithm: ${alg}`); + } + return random(new Uint8Array(bitLength >> 3)); +}; +exports.default = factory; diff --git a/dist/node/cjs/lib/jwt_claims_set.js b/dist/node/cjs/lib/jwt_claims_set.js new file mode 100644 index 0000000000..3b9e317604 --- /dev/null +++ b/dist/node/cjs/lib/jwt_claims_set.js @@ -0,0 +1,98 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const errors_js_1 = require("../util/errors.js"); +const buffer_utils_js_1 = require("./buffer_utils.js"); +const epoch_js_1 = require("./epoch.js"); +const secs_js_1 = require("./secs.js"); +const is_object_js_1 = require("./is_object.js"); +const normalizeTyp = (value) => value.toLowerCase().replace(/^application\//, ''); +const checkAudiencePresence = (audPayload, audOption) => { + if (typeof audPayload === 'string') { + return audOption.includes(audPayload); + } + if (Array.isArray(audPayload)) { + return audOption.some(Set.prototype.has.bind(new Set(audPayload))); + } + return false; +}; +exports.default = (protectedHeader, encodedPayload, options = {}) => { + const { typ } = options; + if (typ && + (typeof protectedHeader.typ !== 'string' || + normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ))) { + throw new errors_js_1.JWTClaimValidationFailed('unexpected "typ" JWT header value', 'typ', 'check_failed'); + } + let payload; + try { + payload = JSON.parse(buffer_utils_js_1.decoder.decode(encodedPayload)); + } + catch { + } + if (!(0, is_object_js_1.default)(payload)) { + throw new errors_js_1.JWTInvalid('JWT Claims Set must be a top-level JSON object'); + } + const { issuer } = options; + if (issuer && !(Array.isArray(issuer) ? issuer : [issuer]).includes(payload.iss)) { + throw new errors_js_1.JWTClaimValidationFailed('unexpected "iss" claim value', 'iss', 'check_failed'); + } + const { subject } = options; + if (subject && payload.sub !== subject) { + throw new errors_js_1.JWTClaimValidationFailed('unexpected "sub" claim value', 'sub', 'check_failed'); + } + const { audience } = options; + if (audience && + !checkAudiencePresence(payload.aud, typeof audience === 'string' ? [audience] : audience)) { + throw new errors_js_1.JWTClaimValidationFailed('unexpected "aud" claim value', 'aud', 'check_failed'); + } + let tolerance; + switch (typeof options.clockTolerance) { + case 'string': + tolerance = (0, secs_js_1.default)(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 = (0, epoch_js_1.default)(currentDate || new Date()); + if (payload.iat !== undefined || options.maxTokenAge) { + if (typeof payload.iat !== 'number') { + throw new errors_js_1.JWTClaimValidationFailed('"iat" claim must be a number', 'iat', 'invalid'); + } + if (payload.exp === undefined && payload.iat > now + tolerance) { + throw new errors_js_1.JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', 'iat', 'check_failed'); + } + } + if (payload.nbf !== undefined) { + if (typeof payload.nbf !== 'number') { + throw new errors_js_1.JWTClaimValidationFailed('"nbf" claim must be a number', 'nbf', 'invalid'); + } + if (payload.nbf > now + tolerance) { + throw new errors_js_1.JWTClaimValidationFailed('"nbf" claim timestamp check failed', 'nbf', 'check_failed'); + } + } + if (payload.exp !== undefined) { + if (typeof payload.exp !== 'number') { + throw new errors_js_1.JWTClaimValidationFailed('"exp" claim must be a number', 'exp', 'invalid'); + } + if (payload.exp <= now - tolerance) { + throw new errors_js_1.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 : (0, secs_js_1.default)(options.maxTokenAge); + if (age - tolerance > max) { + throw new errors_js_1.JWTExpired('"iat" claim timestamp check failed (too far in the past)', 'iat', 'check_failed'); + } + if (age < 0 - tolerance) { + throw new errors_js_1.JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', 'iat', 'check_failed'); + } + } + return payload; +}; diff --git a/dist/node/cjs/lib/jwt_producer.js b/dist/node/cjs/lib/jwt_producer.js new file mode 100644 index 0000000000..57ab4d9b5f --- /dev/null +++ b/dist/node/cjs/lib/jwt_producer.js @@ -0,0 +1,57 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const epoch_js_1 = require("./epoch.js"); +const is_object_js_1 = require("./is_object.js"); +const secs_js_1 = require("./secs.js"); +class ProduceJWT { + constructor(payload) { + if (!(0, is_object_js_1.default)(payload)) { + throw new TypeError('JWT Claims Set MUST be an object'); + } + this._payload = payload; + } + setIssuer(issuer) { + this._payload = { ...this._payload, iss: issuer }; + return this; + } + setSubject(subject) { + this._payload = { ...this._payload, sub: subject }; + return this; + } + setAudience(audience) { + this._payload = { ...this._payload, aud: audience }; + return this; + } + setJti(jwtId) { + this._payload = { ...this._payload, jti: jwtId }; + return this; + } + setNotBefore(input) { + if (typeof input === 'number') { + this._payload = { ...this._payload, nbf: input }; + } + else { + this._payload = { ...this._payload, nbf: (0, epoch_js_1.default)(new Date()) + (0, secs_js_1.default)(input) }; + } + return this; + } + setExpirationTime(input) { + if (typeof input === 'number') { + this._payload = { ...this._payload, exp: input }; + } + else { + this._payload = { ...this._payload, exp: (0, epoch_js_1.default)(new Date()) + (0, secs_js_1.default)(input) }; + } + return this; + } + setIssuedAt(input) { + if (typeof input === 'undefined') { + this._payload = { ...this._payload, iat: (0, epoch_js_1.default)(new Date()) }; + } + else { + this._payload = { ...this._payload, iat: input }; + } + return this; + } +} +exports.default = ProduceJWT; diff --git a/dist/node/cjs/lib/secs.js b/dist/node/cjs/lib/secs.js new file mode 100644 index 0000000000..f1b6a0c15d --- /dev/null +++ b/dist/node/cjs/lib/secs.js @@ -0,0 +1,46 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const minute = 60; +const hour = minute * 60; +const day = hour * 24; +const week = day * 7; +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; +exports.default = (str) => { + const matched = REGEX.exec(str); + if (!matched) { + throw new TypeError('Invalid time period format'); + } + const value = parseFloat(matched[1]); + const unit = matched[2].toLowerCase(); + switch (unit) { + case 'sec': + case 'secs': + case 'second': + case 'seconds': + case 's': + return Math.round(value); + case 'minute': + case 'minutes': + case 'min': + case 'mins': + case 'm': + return Math.round(value * minute); + case 'hour': + case 'hours': + case 'hr': + case 'hrs': + case 'h': + return Math.round(value * hour); + case 'day': + case 'days': + case 'd': + return Math.round(value * day); + case 'week': + case 'weeks': + case 'w': + return Math.round(value * week); + default: + return Math.round(value * year); + } +}; diff --git a/dist/node/cjs/lib/validate_algorithms.js b/dist/node/cjs/lib/validate_algorithms.js new file mode 100644 index 0000000000..29f4e80df9 --- /dev/null +++ b/dist/node/cjs/lib/validate_algorithms.js @@ -0,0 +1,13 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const validateAlgorithms = (option, algorithms) => { + 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); +}; +exports.default = validateAlgorithms; diff --git a/dist/node/cjs/lib/validate_crit.js b/dist/node/cjs/lib/validate_crit.js new file mode 100644 index 0000000000..b0229e3b72 --- /dev/null +++ b/dist/node/cjs/lib/validate_crit.js @@ -0,0 +1,36 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const errors_js_1 = require("../util/errors.js"); +function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) { + if (joseHeader.crit !== undefined && protectedHeader.crit === undefined) { + throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected'); + } + if (!protectedHeader || protectedHeader.crit === undefined) { + return new Set(); + } + if (!Array.isArray(protectedHeader.crit) || + protectedHeader.crit.length === 0 || + protectedHeader.crit.some((input) => typeof input !== 'string' || input.length === 0)) { + throw new Err('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present'); + } + let recognized; + if (recognizedOption !== undefined) { + recognized = new Map([...Object.entries(recognizedOption), ...recognizedDefault.entries()]); + } + else { + recognized = recognizedDefault; + } + for (const parameter of protectedHeader.crit) { + if (!recognized.has(parameter)) { + throw new errors_js_1.JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`); + } + if (joseHeader[parameter] === undefined) { + throw new Err(`Extension Header Parameter "${parameter}" is missing`); + } + else if (recognized.get(parameter) && protectedHeader[parameter] === undefined) { + throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`); + } + } + return new Set(protectedHeader.crit); +} +exports.default = validateCrit; diff --git a/dist/node/cjs/runtime/aesgcmkw.js b/dist/node/cjs/runtime/aesgcmkw.js new file mode 100644 index 0000000000..b3ab6c04f7 --- /dev/null +++ b/dist/node/cjs/runtime/aesgcmkw.js @@ -0,0 +1,21 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.unwrap = exports.wrap = void 0; +const encrypt_js_1 = require("./encrypt.js"); +const decrypt_js_1 = require("./decrypt.js"); +const iv_js_1 = require("../lib/iv.js"); +const random_js_1 = require("./random.js"); +const base64url_js_1 = require("./base64url.js"); +const generateIv = (0, iv_js_1.default)(random_js_1.default); +const wrap = async (alg, key, cek, iv) => { + const jweAlgorithm = alg.substr(0, 7); + iv || (iv = generateIv(jweAlgorithm)); + const { ciphertext: encryptedKey, tag } = await (0, encrypt_js_1.default)(jweAlgorithm, cek, key, iv, new Uint8Array(0)); + return { encryptedKey, iv: (0, base64url_js_1.encode)(iv), tag: (0, base64url_js_1.encode)(tag) }; +}; +exports.wrap = wrap; +const unwrap = async (alg, key, encryptedKey, iv, tag) => { + const jweAlgorithm = alg.substr(0, 7); + return (0, decrypt_js_1.default)(jweAlgorithm, key, encryptedKey, iv, tag, new Uint8Array(0)); +}; +exports.unwrap = unwrap; diff --git a/dist/node/cjs/runtime/aeskw.js b/dist/node/cjs/runtime/aeskw.js new file mode 100644 index 0000000000..78d7ff2a16 --- /dev/null +++ b/dist/node/cjs/runtime/aeskw.js @@ -0,0 +1,52 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.unwrap = exports.wrap = void 0; +const crypto_1 = require("crypto"); +const errors_js_1 = require("../util/errors.js"); +const buffer_utils_js_1 = require("../lib/buffer_utils.js"); +const secret_key_js_1 = require("./secret_key.js"); +const webcrypto_js_1 = require("./webcrypto.js"); +const is_key_object_js_1 = require("./is_key_object.js"); +const invalid_key_input_js_1 = require("./invalid_key_input.js"); +const ciphers_js_1 = require("./ciphers.js"); +function checkKeySize(key, alg) { + if (key.symmetricKeySize << 3 !== parseInt(alg.substr(1, 3), 10)) { + throw new TypeError(`invalid key size for alg: ${alg}`); + } +} +function ensureKeyObject(key, alg, usage) { + if ((0, is_key_object_js_1.default)(key)) { + return key; + } + if (key instanceof Uint8Array) { + return (0, secret_key_js_1.default)(key); + } + if ((0, webcrypto_js_1.isCryptoKey)(key)) { + return (0, webcrypto_js_1.getKeyObject)(key, alg, new Set([usage])); + } + throw new TypeError((0, invalid_key_input_js_1.default)(key, 'KeyObject', 'CryptoKey', 'Uint8Array')); +} +const wrap = async (alg, key, cek) => { + const size = parseInt(alg.substr(1, 3), 10); + const algorithm = `aes${size}-wrap`; + if (!(0, ciphers_js_1.default)(algorithm)) { + throw new errors_js_1.JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`); + } + const keyObject = ensureKeyObject(key, alg, 'wrapKey'); + checkKeySize(keyObject, alg); + const cipher = (0, crypto_1.createCipheriv)(algorithm, keyObject, Buffer.alloc(8, 0xa6)); + return (0, buffer_utils_js_1.concat)(cipher.update(cek), cipher.final()); +}; +exports.wrap = wrap; +const unwrap = async (alg, key, encryptedKey) => { + const size = parseInt(alg.substr(1, 3), 10); + const algorithm = `aes${size}-wrap`; + if (!(0, ciphers_js_1.default)(algorithm)) { + throw new errors_js_1.JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`); + } + const keyObject = ensureKeyObject(key, alg, 'unwrapKey'); + checkKeySize(keyObject, alg); + const cipher = (0, crypto_1.createDecipheriv)(algorithm, keyObject, Buffer.alloc(8, 0xa6)); + return (0, buffer_utils_js_1.concat)(cipher.update(encryptedKey), cipher.final()); +}; +exports.unwrap = unwrap; diff --git a/dist/node/cjs/runtime/asn1_sequence_decoder.js b/dist/node/cjs/runtime/asn1_sequence_decoder.js new file mode 100644 index 0000000000..4f96522335 --- /dev/null +++ b/dist/node/cjs/runtime/asn1_sequence_decoder.js @@ -0,0 +1,47 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const tagInteger = 0x02; +const tagSequence = 0x30; +class Asn1SequenceDecoder { + constructor(buffer) { + if (buffer[0] !== tagSequence) { + throw new TypeError(); + } + this.buffer = buffer; + this.offset = 1; + const len = this.decodeLength(); + if (len !== buffer.length - this.offset) { + throw new TypeError(); + } + } + decodeLength() { + let length = this.buffer[this.offset++]; + if (length & 0x80) { + const nBytes = length & ~0x80; + length = 0; + for (let i = 0; i < nBytes; i++) + length = (length << 8) | this.buffer[this.offset + i]; + this.offset += nBytes; + } + return length; + } + unsignedInteger() { + if (this.buffer[this.offset++] !== tagInteger) { + throw new TypeError(); + } + let length = this.decodeLength(); + if (this.buffer[this.offset] === 0) { + this.offset++; + length--; + } + const result = this.buffer.slice(this.offset, this.offset + length); + this.offset += length; + return result; + } + end() { + if (this.offset !== this.buffer.length) { + throw new TypeError(); + } + } +} +exports.default = Asn1SequenceDecoder; diff --git a/dist/node/cjs/runtime/asn1_sequence_encoder.js b/dist/node/cjs/runtime/asn1_sequence_encoder.js new file mode 100644 index 0000000000..f980e4ac2d --- /dev/null +++ b/dist/node/cjs/runtime/asn1_sequence_encoder.js @@ -0,0 +1,90 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const errors_js_1 = require("../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) => { + 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')], +]); +class DumbAsn1Encoder { + constructor() { + this.length = 0; + this.elements = []; + } + oidFor(oid) { + const bOid = oids.get(oid); + if (!bOid) { + throw new errors_js_1.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) { + 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) { + const len = encodeLength(octStr.length); + this.elements.push(bTagOctStr, encodeLength(octStr.length), octStr); + this.length += 1 + len.length + octStr.length; + } + bitStr(bitS) { + 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) { + 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); + } +} +exports.default = DumbAsn1Encoder; diff --git a/dist/node/cjs/runtime/base64url.js b/dist/node/cjs/runtime/base64url.js new file mode 100644 index 0000000000..f637a16750 --- /dev/null +++ b/dist/node/cjs/runtime/base64url.js @@ -0,0 +1,21 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.decode = exports.encode = void 0; +const buffer_utils_js_1 = require("../lib/buffer_utils.js"); +let encodeImpl; +function normalize(input) { + let encoded = input; + if (encoded instanceof Uint8Array) { + encoded = buffer_utils_js_1.decoder.decode(encoded); + } + return encoded; +} +if (Buffer.isEncoding('base64url')) { + encodeImpl = (input) => Buffer.from(input).toString('base64url'); +} +else { + encodeImpl = (input) => Buffer.from(input).toString('base64').replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_'); +} +exports.encode = encodeImpl; +const decode = (input) => Buffer.from(normalize(input), 'base64'); +exports.decode = decode; diff --git a/dist/node/cjs/runtime/cbc_tag.js b/dist/node/cjs/runtime/cbc_tag.js new file mode 100644 index 0000000000..03412c2cfb --- /dev/null +++ b/dist/node/cjs/runtime/cbc_tag.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const crypto_1 = require("crypto"); +const buffer_utils_js_1 = require("../lib/buffer_utils.js"); +function cbcTag(aad, iv, ciphertext, macSize, macKey, keySize) { + const macData = (0, buffer_utils_js_1.concat)(aad, iv, ciphertext, (0, buffer_utils_js_1.uint64be)(aad.length << 3)); + const hmac = (0, crypto_1.createHmac)(`sha${macSize}`, macKey); + hmac.update(macData); + return hmac.digest().slice(0, keySize >> 3); +} +exports.default = cbcTag; diff --git a/dist/node/cjs/runtime/check_cek_length.js b/dist/node/cjs/runtime/check_cek_length.js new file mode 100644 index 0000000000..360f1be7a6 --- /dev/null +++ b/dist/node/cjs/runtime/check_cek_length.js @@ -0,0 +1,35 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const errors_js_1 = require("../util/errors.js"); +const is_key_object_js_1 = require("./is_key_object.js"); +const checkCekLength = (enc, cek) => { + let expected; + 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 errors_js_1.JOSENotSupported(`Content Encryption Algorithm ${enc} is not supported either by JOSE or your javascript runtime`); + } + if (cek instanceof Uint8Array) { + if (cek.length << 3 !== expected) { + throw new errors_js_1.JWEInvalid('Invalid Content Encryption Key length'); + } + return; + } + if ((0, is_key_object_js_1.default)(cek) && cek.type === 'secret') { + if (cek.symmetricKeySize << 3 !== expected) { + throw new errors_js_1.JWEInvalid('Invalid Content Encryption Key length'); + } + return; + } + throw new TypeError('Invalid Content Encryption Key type'); +}; +exports.default = checkCekLength; diff --git a/dist/node/cjs/runtime/check_modulus_length.js b/dist/node/cjs/runtime/check_modulus_length.js new file mode 100644 index 0000000000..72c670eba3 --- /dev/null +++ b/dist/node/cjs/runtime/check_modulus_length.js @@ -0,0 +1,52 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.setModulusLength = exports.weakMap = void 0; +exports.weakMap = new WeakMap(); +const getLength = (buf, index) => { + let len = buf.readUInt8(1); + if ((len & 0x80) === 0) { + if (index === 0) { + return len; + } + return getLength(buf.subarray(2 + len), index - 1); + } + 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, index) => { + const len = sequence.readUInt8(1); + if ((len & 0x80) === 0) { + return getLength(sequence.subarray(2), index); + } + const num = len & 0x7f; + return getLength(sequence.subarray(2 + num), index); +}; +const getModulusLength = (key) => { + var _a, _b; + if (exports.weakMap.has(key)) { + return exports.weakMap.get(key); + } + const modulusLength = (_b = (_a = key.asymmetricKeyDetails) === null || _a === void 0 ? void 0 : _a.modulusLength) !== null && _b !== void 0 ? _b : (getLengthOfSeqIndex(key.export({ format: 'der', type: 'pkcs1' }), key.type === 'private' ? 1 : 0) - + 1) << + 3; + exports.weakMap.set(key, modulusLength); + return modulusLength; +}; +const setModulusLength = (keyObject, modulusLength) => { + exports.weakMap.set(keyObject, modulusLength); +}; +exports.setModulusLength = setModulusLength; +exports.default = (key, alg) => { + if (getModulusLength(key) < 2048) { + throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`); + } +}; diff --git a/dist/node/cjs/runtime/ciphers.js b/dist/node/cjs/runtime/ciphers.js new file mode 100644 index 0000000000..e004c84562 --- /dev/null +++ b/dist/node/cjs/runtime/ciphers.js @@ -0,0 +1,8 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const crypto_1 = require("crypto"); +let ciphers; +exports.default = (algorithm) => { + ciphers || (ciphers = new Set((0, crypto_1.getCiphers)())); + return ciphers.has(algorithm); +}; diff --git a/dist/node/cjs/runtime/decrypt.js b/dist/node/cjs/runtime/decrypt.js new file mode 100644 index 0000000000..bad1e1217b --- /dev/null +++ b/dist/node/cjs/runtime/decrypt.js @@ -0,0 +1,92 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const crypto_1 = require("crypto"); +const check_iv_length_js_1 = require("../lib/check_iv_length.js"); +const check_cek_length_js_1 = require("./check_cek_length.js"); +const buffer_utils_js_1 = require("../lib/buffer_utils.js"); +const errors_js_1 = require("../util/errors.js"); +const timing_safe_equal_js_1 = require("./timing_safe_equal.js"); +const cbc_tag_js_1 = require("./cbc_tag.js"); +const webcrypto_js_1 = require("./webcrypto.js"); +const is_key_object_js_1 = require("./is_key_object.js"); +const invalid_key_input_js_1 = require("./invalid_key_input.js"); +const ciphers_js_1 = require("./ciphers.js"); +async function cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) { + const keySize = parseInt(enc.substr(1, 3), 10); + if ((0, is_key_object_js_1.default)(cek)) { + cek = cek.export(); + } + const encKey = cek.subarray(keySize >> 3); + const macKey = cek.subarray(0, keySize >> 3); + const macSize = parseInt(enc.substr(-3), 10); + const algorithm = `aes-${keySize}-cbc`; + if (!(0, ciphers_js_1.default)(algorithm)) { + throw new errors_js_1.JOSENotSupported(`alg ${enc} is not supported by your javascript runtime`); + } + const expectedTag = (0, cbc_tag_js_1.default)(aad, iv, ciphertext, macSize, macKey, keySize); + let macCheckPassed; + try { + macCheckPassed = (0, timing_safe_equal_js_1.default)(tag, expectedTag); + } + catch { + } + if (!macCheckPassed) { + throw new errors_js_1.JWEDecryptionFailed(); + } + let plaintext; + try { + const cipher = (0, crypto_1.createDecipheriv)(algorithm, encKey, iv); + plaintext = (0, buffer_utils_js_1.concat)(cipher.update(ciphertext), cipher.final()); + } + catch { + } + if (!plaintext) { + throw new errors_js_1.JWEDecryptionFailed(); + } + return plaintext; +} +async function gcmDecrypt(enc, cek, ciphertext, iv, tag, aad) { + const keySize = parseInt(enc.substr(1, 3), 10); + const algorithm = `aes-${keySize}-gcm`; + if (!(0, ciphers_js_1.default)(algorithm)) { + throw new errors_js_1.JOSENotSupported(`alg ${enc} is not supported by your javascript runtime`); + } + try { + const cipher = (0, crypto_1.createDecipheriv)(algorithm, cek, iv, { authTagLength: 16 }); + cipher.setAuthTag(tag); + if (aad.byteLength) { + cipher.setAAD(aad, { plaintextLength: ciphertext.length }); + } + return (0, buffer_utils_js_1.concat)(cipher.update(ciphertext), cipher.final()); + } + catch { + throw new errors_js_1.JWEDecryptionFailed(); + } +} +const decrypt = async (enc, cek, ciphertext, iv, tag, aad) => { + let key; + if ((0, webcrypto_js_1.isCryptoKey)(cek)) { + key = (0, webcrypto_js_1.getKeyObject)(cek, enc, new Set(['decrypt'])); + } + else if (cek instanceof Uint8Array || (0, is_key_object_js_1.default)(cek)) { + key = cek; + } + else { + throw new TypeError((0, invalid_key_input_js_1.default)(cek, 'KeyObject', 'CryptoKey', 'Uint8Array')); + } + (0, check_cek_length_js_1.default)(enc, key); + (0, check_iv_length_js_1.default)(enc, iv); + switch (enc) { + case 'A128CBC-HS256': + case 'A192CBC-HS384': + case 'A256CBC-HS512': + return cbcDecrypt(enc, key, ciphertext, iv, tag, aad); + case 'A128GCM': + case 'A192GCM': + case 'A256GCM': + return gcmDecrypt(enc, key, ciphertext, iv, tag, aad); + default: + throw new errors_js_1.JOSENotSupported('unsupported JWE Content Encryption Algorithm'); + } +}; +exports.default = decrypt; diff --git a/dist/node/cjs/runtime/digest.js b/dist/node/cjs/runtime/digest.js new file mode 100644 index 0000000000..13c194a8ed --- /dev/null +++ b/dist/node/cjs/runtime/digest.js @@ -0,0 +1,5 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const crypto_1 = require("crypto"); +const digest = (algorithm, data) => (0, crypto_1.createHash)(algorithm).update(data).digest(); +exports.default = digest; diff --git a/dist/node/cjs/runtime/dsa_digest.js b/dist/node/cjs/runtime/dsa_digest.js new file mode 100644 index 0000000000..fde4883e81 --- /dev/null +++ b/dist/node/cjs/runtime/dsa_digest.js @@ -0,0 +1,25 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const errors_js_1 = require("../util/errors.js"); +function dsaDigest(alg) { + 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 errors_js_1.JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`); + } +} +exports.default = dsaDigest; diff --git a/dist/node/cjs/runtime/ecdhes.js b/dist/node/cjs/runtime/ecdhes.js new file mode 100644 index 0000000000..cc3c4f1edc --- /dev/null +++ b/dist/node/cjs/runtime/ecdhes.js @@ -0,0 +1,55 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ecdhAllowed = exports.generateEpk = exports.deriveKey = void 0; +const crypto_1 = require("crypto"); +const util_1 = require("util"); +const get_named_curve_js_1 = require("./get_named_curve.js"); +const buffer_utils_js_1 = require("../lib/buffer_utils.js"); +const digest_js_1 = require("./digest.js"); +const errors_js_1 = require("../util/errors.js"); +const webcrypto_js_1 = require("./webcrypto.js"); +const is_key_object_js_1 = require("./is_key_object.js"); +const invalid_key_input_js_1 = require("./invalid_key_input.js"); +const generateKeyPair = (0, util_1.promisify)(crypto_1.generateKeyPair); +const deriveKey = async (publicKey, privateKey, algorithm, keyLength, apu = new Uint8Array(0), apv = new Uint8Array(0)) => { + const value = (0, buffer_utils_js_1.concat)((0, buffer_utils_js_1.lengthAndInput)(buffer_utils_js_1.encoder.encode(algorithm)), (0, buffer_utils_js_1.lengthAndInput)(apu), (0, buffer_utils_js_1.lengthAndInput)(apv), (0, buffer_utils_js_1.uint32be)(keyLength)); + if ((0, webcrypto_js_1.isCryptoKey)(publicKey)) { + publicKey = (0, webcrypto_js_1.getKeyObject)(publicKey, 'ECDH-ES'); + } + if (!(0, is_key_object_js_1.default)(publicKey)) { + throw new TypeError((0, invalid_key_input_js_1.default)(publicKey, 'KeyObject', 'CryptoKey')); + } + if ((0, webcrypto_js_1.isCryptoKey)(privateKey)) { + privateKey = (0, webcrypto_js_1.getKeyObject)(privateKey, 'ECDH-ES', new Set(['deriveBits', 'deriveKey'])); + } + if (!(0, is_key_object_js_1.default)(privateKey)) { + throw new TypeError((0, invalid_key_input_js_1.default)(privateKey, 'KeyObject', 'CryptoKey')); + } + const sharedSecret = (0, crypto_1.diffieHellman)({ privateKey, publicKey }); + return (0, buffer_utils_js_1.concatKdf)(digest_js_1.default, sharedSecret, keyLength, value); +}; +exports.deriveKey = deriveKey; +const generateEpk = async (key) => { + if ((0, webcrypto_js_1.isCryptoKey)(key)) { + key = (0, webcrypto_js_1.getKeyObject)(key); + } + if (!(0, is_key_object_js_1.default)(key)) { + throw new TypeError((0, invalid_key_input_js_1.default)(key, 'KeyObject', 'CryptoKey')); + } + switch (key.asymmetricKeyType) { + case 'x25519': + return (await generateKeyPair('x25519')).privateKey; + case 'x448': { + return (await generateKeyPair('x448')).privateKey; + } + case 'ec': { + const namedCurve = (0, get_named_curve_js_1.default)(key); + return (await generateKeyPair('ec', { namedCurve })).privateKey; + } + default: + throw new errors_js_1.JOSENotSupported('unsupported or invalid EPK'); + } +}; +exports.generateEpk = generateEpk; +const ecdhAllowed = (key) => ['P-256', 'P-384', 'P-521', 'X25519', 'X448'].includes((0, get_named_curve_js_1.default)(key)); +exports.ecdhAllowed = ecdhAllowed; diff --git a/dist/node/cjs/runtime/encrypt.js b/dist/node/cjs/runtime/encrypt.js new file mode 100644 index 0000000000..d2c341811f --- /dev/null +++ b/dist/node/cjs/runtime/encrypt.js @@ -0,0 +1,70 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const crypto_1 = require("crypto"); +const check_iv_length_js_1 = require("../lib/check_iv_length.js"); +const check_cek_length_js_1 = require("./check_cek_length.js"); +const buffer_utils_js_1 = require("../lib/buffer_utils.js"); +const cbc_tag_js_1 = require("./cbc_tag.js"); +const webcrypto_js_1 = require("./webcrypto.js"); +const is_key_object_js_1 = require("./is_key_object.js"); +const invalid_key_input_js_1 = require("./invalid_key_input.js"); +const errors_js_1 = require("../util/errors.js"); +const ciphers_js_1 = require("./ciphers.js"); +async function cbcEncrypt(enc, plaintext, cek, iv, aad) { + const keySize = parseInt(enc.substr(1, 3), 10); + if ((0, is_key_object_js_1.default)(cek)) { + cek = cek.export(); + } + const encKey = cek.subarray(keySize >> 3); + const macKey = cek.subarray(0, keySize >> 3); + const algorithm = `aes-${keySize}-cbc`; + if (!(0, ciphers_js_1.default)(algorithm)) { + throw new errors_js_1.JOSENotSupported(`alg ${enc} is not supported by your javascript runtime`); + } + const cipher = (0, crypto_1.createCipheriv)(algorithm, encKey, iv); + const ciphertext = (0, buffer_utils_js_1.concat)(cipher.update(plaintext), cipher.final()); + const macSize = parseInt(enc.substr(-3), 10); + const tag = (0, cbc_tag_js_1.default)(aad, iv, ciphertext, macSize, macKey, keySize); + return { ciphertext, tag }; +} +async function gcmEncrypt(enc, plaintext, cek, iv, aad) { + const keySize = parseInt(enc.substr(1, 3), 10); + const algorithm = `aes-${keySize}-gcm`; + if (!(0, ciphers_js_1.default)(algorithm)) { + throw new errors_js_1.JOSENotSupported(`alg ${enc} is not supported by your javascript runtime`); + } + const cipher = (0, crypto_1.createCipheriv)(algorithm, cek, iv, { authTagLength: 16 }); + if (aad.byteLength) { + cipher.setAAD(aad, { plaintextLength: plaintext.length }); + } + const ciphertext = (0, buffer_utils_js_1.concat)(cipher.update(plaintext), cipher.final()); + const tag = cipher.getAuthTag(); + return { ciphertext, tag }; +} +const encrypt = async (enc, plaintext, cek, iv, aad) => { + let key; + if ((0, webcrypto_js_1.isCryptoKey)(cek)) { + key = (0, webcrypto_js_1.getKeyObject)(cek, enc, new Set(['encrypt'])); + } + else if (cek instanceof Uint8Array || (0, is_key_object_js_1.default)(cek)) { + key = cek; + } + else { + throw new TypeError((0, invalid_key_input_js_1.default)(cek, 'KeyObject', 'CryptoKey', 'Uint8Array')); + } + (0, check_cek_length_js_1.default)(enc, key); + (0, check_iv_length_js_1.default)(enc, iv); + switch (enc) { + case 'A128CBC-HS256': + case 'A192CBC-HS384': + case 'A256CBC-HS512': + return cbcEncrypt(enc, plaintext, key, iv, aad); + case 'A128GCM': + case 'A192GCM': + case 'A256GCM': + return gcmEncrypt(enc, plaintext, key, iv, aad); + default: + throw new errors_js_1.JOSENotSupported('unsupported JWE Content Encryption Algorithm'); + } +}; +exports.default = encrypt; diff --git a/dist/node/cjs/runtime/fetch_jwks.js b/dist/node/cjs/runtime/fetch_jwks.js new file mode 100644 index 0000000000..4ec863ccb0 --- /dev/null +++ b/dist/node/cjs/runtime/fetch_jwks.js @@ -0,0 +1,36 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const http_1 = require("http"); +const https_1 = require("https"); +const events_1 = require("events"); +const errors_js_1 = require("../util/errors.js"); +const buffer_utils_js_1 = require("../lib/buffer_utils.js"); +const protocols = { + 'https:': https_1.get, + 'http:': http_1.get, +}; +const fetchJwks = async (url, timeout, options) => { + if (protocols[url.protocol] === undefined) { + throw new TypeError('Unsupported URL protocol.'); + } + const { agent } = options; + const req = protocols[url.protocol](url.href, { + agent, + timeout, + }); + const [response] = await (0, events_1.once)(req, 'response'); + if (response.statusCode !== 200) { + throw new errors_js_1.JOSEError('Expected 200 OK from the JSON Web Key Set HTTP response'); + } + const parts = []; + for await (const part of response) { + parts.push(part); + } + try { + return JSON.parse(buffer_utils_js_1.decoder.decode((0, buffer_utils_js_1.concat)(...parts))); + } + catch { + throw new errors_js_1.JOSEError('Failed to parse the JSON Web Key Set HTTP response as JSON'); + } +}; +exports.default = fetchJwks; diff --git a/dist/node/cjs/runtime/generate.js b/dist/node/cjs/runtime/generate.js new file mode 100644 index 0000000000..d01f7437da --- /dev/null +++ b/dist/node/cjs/runtime/generate.js @@ -0,0 +1,104 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.generateKeyPair = exports.generateSecret = void 0; +const crypto_1 = require("crypto"); +const util_1 = require("util"); +const random_js_1 = require("./random.js"); +const check_modulus_length_js_1 = require("./check_modulus_length.js"); +const errors_js_1 = require("../util/errors.js"); +const generate = (0, util_1.promisify)(crypto_1.generateKeyPair); +async function generateSecret(alg, options) { + let length; + 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 errors_js_1.JOSENotSupported('unsupported or invalid JWK "alg" (Algorithm) Parameter value'); + } + return (0, crypto_1.createSecretKey)((0, random_js_1.default)(new Uint8Array(length >> 3))); +} +exports.generateSecret = generateSecret; +async function generateKeyPair(alg, options) { + var _a, _b; + 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': { + const modulusLength = (_a = options === null || options === void 0 ? void 0 : options.modulusLength) !== null && _a !== void 0 ? _a : 2048; + if (typeof modulusLength !== 'number' || modulusLength < 2048) { + throw new errors_js_1.JOSENotSupported('Invalid or unsupported modulusLength option provided, 2048 bits or larger keys must be used'); + } + const keypair = await generate('rsa', { + modulusLength, + publicExponent: 0x10001, + }); + (0, check_modulus_length_js_1.setModulusLength)(keypair.privateKey, modulusLength); + (0, check_modulus_length_js_1.setModulusLength)(keypair.publicKey, modulusLength); + return keypair; + } + 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 === null || options === void 0 ? void 0 : options.crv) { + case undefined: + case 'Ed25519': + return generate('ed25519'); + case 'Ed448': + return generate('ed448'); + default: + throw new errors_js_1.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 === null || options === void 0 ? void 0 : options.crv) { + case undefined: + case 'P-256': + case 'P-384': + case 'P-521': + return generate('ec', { namedCurve: (_b = options === null || options === void 0 ? void 0 : options.crv) !== null && _b !== void 0 ? _b : 'P-256' }); + case 'X25519': + return generate('x25519'); + case 'X448': + return generate('x448'); + default: + throw new errors_js_1.JOSENotSupported('Invalid or unsupported crv option provided, supported values are P-256, P-384, P-521, X25519, and X448'); + } + default: + throw new errors_js_1.JOSENotSupported('unsupported or invalid JWK "alg" (Algorithm) Parameter value'); + } +} +exports.generateKeyPair = generateKeyPair; diff --git a/dist/node/cjs/runtime/get_named_curve.js b/dist/node/cjs/runtime/get_named_curve.js new file mode 100644 index 0000000000..ab98bca5cc --- /dev/null +++ b/dist/node/cjs/runtime/get_named_curve.js @@ -0,0 +1,89 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.setCurve = exports.weakMap = void 0; +const crypto_1 = require("crypto"); +const errors_js_1 = require("../util/errors.js"); +const webcrypto_js_1 = require("./webcrypto.js"); +const is_key_object_js_1 = require("./is_key_object.js"); +const invalid_key_input_js_1 = require("./invalid_key_input.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]); +exports.weakMap = new WeakMap(); +const namedCurveToJOSE = (namedCurve) => { + switch (namedCurve) { + case 'prime256v1': + return 'P-256'; + case 'secp384r1': + return 'P-384'; + case 'secp521r1': + return 'P-521'; + case 'secp256k1': + return namedCurve; + default: + throw new errors_js_1.JOSENotSupported('unsupported key curve for this operation'); + } +}; +const getNamedCurve = (key, raw) => { + var _a; + if ((0, webcrypto_js_1.isCryptoKey)(key)) { + key = (0, webcrypto_js_1.getKeyObject)(key); + } + if (!(0, is_key_object_js_1.default)(key)) { + throw new TypeError((0, invalid_key_input_js_1.default)(key, 'KeyObject', 'CryptoKey')); + } + if (key.type === 'secret') { + throw new TypeError('only "private" or "public" type keys can be used for this operation'); + } + switch (key.asymmetricKeyType) { + case 'ed25519': + case 'ed448': + return `Ed${key.asymmetricKeyType.substr(2)}`; + case 'x25519': + case 'x448': + return `X${key.asymmetricKeyType.substr(1)}`; + case 'ec': { + if (exports.weakMap.has(key)) { + return exports.weakMap.get(key); + } + let namedCurve = (_a = key.asymmetricKeyDetails) === null || _a === void 0 ? void 0 : _a.namedCurve; + if (!namedCurve && key.type === 'private') { + namedCurve = getNamedCurve((0, crypto_1.createPublicKey)(key), true); + } + else if (!namedCurve) { + 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); + if (curveOid.equals(p256)) { + namedCurve = 'prime256v1'; + } + else if (curveOid.equals(p384)) { + namedCurve = 'secp384r1'; + } + else if (curveOid.equals(p521)) { + namedCurve = 'secp521r1'; + } + else if (curveOid.equals(secp256k1)) { + namedCurve = 'secp256k1'; + } + else { + throw new errors_js_1.JOSENotSupported('unsupported key curve for this operation'); + } + } + if (raw) + return namedCurve; + const curve = namedCurveToJOSE(namedCurve); + exports.weakMap.set(key, curve); + return curve; + } + default: + throw new TypeError('Invalid asymmetric key type for this operation'); + } +}; +function setCurve(keyObject, curve) { + exports.weakMap.set(keyObject, curve); +} +exports.setCurve = setCurve; +exports.default = getNamedCurve; diff --git a/dist/node/cjs/runtime/get_sign_verify_key.js b/dist/node/cjs/runtime/get_sign_verify_key.js new file mode 100644 index 0000000000..127114f030 --- /dev/null +++ b/dist/node/cjs/runtime/get_sign_verify_key.js @@ -0,0 +1,22 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const crypto = require("crypto"); +const webcrypto_js_1 = require("./webcrypto.js"); +const secret_key_js_1 = require("./secret_key.js"); +const invalid_key_input_js_1 = require("./invalid_key_input.js"); +function getSignVerifyKey(alg, key, usage) { + if (key instanceof Uint8Array) { + if (!alg.startsWith('HS')) { + throw new TypeError((0, invalid_key_input_js_1.default)(key, 'KeyObject', 'CryptoKey')); + } + return (0, secret_key_js_1.default)(key); + } + if (key instanceof crypto.KeyObject) { + return key; + } + if ((0, webcrypto_js_1.isCryptoKey)(key)) { + return (0, webcrypto_js_1.getKeyObject)(key, alg, new Set([usage])); + } + throw new TypeError((0, invalid_key_input_js_1.default)(key, 'KeyObject', 'CryptoKey', 'Uint8Array')); +} +exports.default = getSignVerifyKey; diff --git a/dist/node/cjs/runtime/hmac_digest.js b/dist/node/cjs/runtime/hmac_digest.js new file mode 100644 index 0000000000..c3935124c7 --- /dev/null +++ b/dist/node/cjs/runtime/hmac_digest.js @@ -0,0 +1,16 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const errors_js_1 = require("../util/errors.js"); +function hmacDigest(alg) { + switch (alg) { + case 'HS256': + return 'sha256'; + case 'HS384': + return 'sha384'; + case 'HS512': + return 'sha512'; + default: + throw new errors_js_1.JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`); + } +} +exports.default = hmacDigest; diff --git a/dist/node/cjs/runtime/invalid_key_input.js b/dist/node/cjs/runtime/invalid_key_input.js new file mode 100644 index 0000000000..83740e7534 --- /dev/null +++ b/dist/node/cjs/runtime/invalid_key_input.js @@ -0,0 +1,38 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const util_1 = require("util"); +exports.default = (actual, ...types) => { + let msg = 'Key must be '; + if (types.length > 2) { + const last = types.pop(); + msg += `one of type ${types.join(', ')}, or ${last}.`; + } + else if (types.length === 2) { + msg += `one of type ${types[0]} or ${types[1]}.`; + } + else { + msg += `of type ${types[0]}.`; + } + if (actual == null) { + msg += ` Received ${actual}`; + } + else if (typeof actual === 'function' && actual.name) { + msg += ` Received function ${actual.name}`; + } + else if (typeof actual === 'object' && actual != null) { + if (actual.constructor && actual.constructor.name) { + msg += ` Received an instance of ${actual.constructor.name}`; + } + else { + const inspected = (0, util_1.inspect)(actual, { depth: -1 }); + msg += ` Received ${inspected}`; + } + } + else { + let inspected = (0, util_1.inspect)(actual, { colors: false }); + if (inspected.length > 25) + inspected = `${inspected.slice(0, 25)}...`; + msg += ` Received type ${typeof actual} (${inspected})`; + } + return msg; +}; diff --git a/dist/node/cjs/runtime/is_key_object.js b/dist/node/cjs/runtime/is_key_object.js new file mode 100644 index 0000000000..6bdb2bb3ed --- /dev/null +++ b/dist/node/cjs/runtime/is_key_object.js @@ -0,0 +1,16 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const crypto_1 = require("crypto"); +const util = require("util"); +let impl; +if (util.types.isKeyObject) { + impl = function isKeyObject(obj) { + return util.types.isKeyObject(obj); + }; +} +else { + impl = function isKeyObject(obj) { + return obj != null && obj instanceof crypto_1.KeyObject; + }; +} +exports.default = impl; diff --git a/dist/node/cjs/runtime/jwk_to_key.js b/dist/node/cjs/runtime/jwk_to_key.js new file mode 100644 index 0000000000..e152c3d729 --- /dev/null +++ b/dist/node/cjs/runtime/jwk_to_key.js @@ -0,0 +1,121 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const crypto_1 = require("crypto"); +const base64url_js_1 = require("./base64url.js"); +const errors_js_1 = require("../util/errors.js"); +const get_named_curve_js_1 = require("./get_named_curve.js"); +const check_modulus_length_js_1 = require("./check_modulus_length.js"); +const asn1_sequence_encoder_js_1 = require("./asn1_sequence_encoder.js"); +const [major, minor] = process.version + .substr(1) + .split('.') + .map((str) => parseInt(str, 10)); +const jwkImportSupported = major >= 16 || (major === 15 && minor >= 12); +const parse = (jwk) => { + if (jwkImportSupported && jwk.kty !== 'oct') { + return jwk.d + ? (0, crypto_1.createPrivateKey)({ format: 'jwk', key: jwk }) + : (0, crypto_1.createPublicKey)({ format: 'jwk', key: jwk }); + } + switch (jwk.kty) { + case 'oct': { + return (0, crypto_1.createSecretKey)((0, base64url_js_1.decode)(jwk.k)); + } + case 'RSA': { + const enc = new asn1_sequence_encoder_js_1.default(); + const isPrivate = jwk.d !== undefined; + const modulus = Buffer.from(jwk.n, 'base64'); + const exponent = Buffer.from(jwk.e, 'base64'); + if (isPrivate) { + enc.zero(); + 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 = { + key: der, + format: 'der', + type: 'pkcs1', + }; + const keyObject = isPrivate ? (0, crypto_1.createPrivateKey)(createInput) : (0, crypto_1.createPublicKey)(createInput); + (0, check_modulus_length_js_1.setModulusLength)(keyObject, modulus.length << 3); + return keyObject; + } + case 'EC': { + const enc = new asn1_sequence_encoder_js_1.default(); + const isPrivate = jwk.d !== undefined; + const pub = Buffer.concat([ + Buffer.alloc(1, 4), + Buffer.from(jwk.x, 'base64'), + Buffer.from(jwk.y, 'base64'), + ]); + if (isPrivate) { + enc.zero(); + const enc$1 = new asn1_sequence_encoder_js_1.default(); + enc$1.oidFor('ecPublicKey'); + enc$1.oidFor(jwk.crv); + enc.add(enc$1.end()); + const enc$2 = new asn1_sequence_encoder_js_1.default(); + enc$2.one(); + enc$2.octStr(Buffer.from(jwk.d, 'base64')); + const enc$3 = new asn1_sequence_encoder_js_1.default(); + enc$3.bitStr(pub); + const f2 = enc$3.end(Buffer.from([0xa1])); + enc$2.add(f2); + const f = enc$2.end(); + const enc$4 = new asn1_sequence_encoder_js_1.default(); + enc$4.add(f); + const f3 = enc$4.end(Buffer.from([0x04])); + enc.add(f3); + const der = enc.end(); + const keyObject = (0, crypto_1.createPrivateKey)({ key: der, format: 'der', type: 'pkcs8' }); + (0, get_named_curve_js_1.setCurve)(keyObject, jwk.crv); + return keyObject; + } + const enc$1 = new asn1_sequence_encoder_js_1.default(); + enc$1.oidFor('ecPublicKey'); + enc$1.oidFor(jwk.crv); + enc.add(enc$1.end()); + enc.bitStr(pub); + const der = enc.end(); + const keyObject = (0, crypto_1.createPublicKey)({ key: der, format: 'der', type: 'spki' }); + (0, get_named_curve_js_1.setCurve)(keyObject, jwk.crv); + return keyObject; + } + case 'OKP': { + const enc = new asn1_sequence_encoder_js_1.default(); + const isPrivate = jwk.d !== undefined; + if (isPrivate) { + enc.zero(); + const enc$1 = new asn1_sequence_encoder_js_1.default(); + enc$1.oidFor(jwk.crv); + enc.add(enc$1.end()); + const enc$2 = new asn1_sequence_encoder_js_1.default(); + enc$2.octStr(Buffer.from(jwk.d, 'base64')); + const f = enc$2.end(Buffer.from([0x04])); + enc.add(f); + const der = enc.end(); + return (0, crypto_1.createPrivateKey)({ key: der, format: 'der', type: 'pkcs8' }); + } + const enc$1 = new asn1_sequence_encoder_js_1.default(); + enc$1.oidFor(jwk.crv); + enc.add(enc$1.end()); + enc.bitStr(Buffer.from(jwk.x, 'base64')); + const der = enc.end(); + return (0, crypto_1.createPublicKey)({ key: der, format: 'der', type: 'spki' }); + } + default: + throw new errors_js_1.JOSENotSupported('unsupported or invalid JWK "kty" (Key Type) Parameter value'); + } +}; +exports.default = parse; diff --git a/dist/node/cjs/runtime/key_to_jwk.js b/dist/node/cjs/runtime/key_to_jwk.js new file mode 100644 index 0000000000..aea46857a9 --- /dev/null +++ b/dist/node/cjs/runtime/key_to_jwk.js @@ -0,0 +1,159 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const crypto_1 = require("crypto"); +const base64url_js_1 = require("./base64url.js"); +const asn1_sequence_decoder_js_1 = require("./asn1_sequence_decoder.js"); +const errors_js_1 = require("../util/errors.js"); +const get_named_curve_js_1 = require("./get_named_curve.js"); +const webcrypto_js_1 = require("./webcrypto.js"); +const is_key_object_js_1 = require("./is_key_object.js"); +const invalid_key_input_js_1 = require("./invalid_key_input.js"); +const [major, minor] = process.version + .substr(1) + .split('.') + .map((str) => parseInt(str, 10)); +const jwkExportSupported = major >= 16 || (major === 15 && minor >= 9); +const keyToJWK = (key) => { + let keyObject; + if ((0, webcrypto_js_1.isCryptoKey)(key)) { + if (!key.extractable) { + throw new TypeError('CryptoKey is not extractable'); + } + keyObject = (0, webcrypto_js_1.getKeyObject)(key); + } + else if ((0, is_key_object_js_1.default)(key)) { + keyObject = key; + } + else if (key instanceof Uint8Array) { + return { + kty: 'oct', + k: (0, base64url_js_1.encode)(key), + }; + } + else { + throw new TypeError((0, invalid_key_input_js_1.default)(key, 'KeyObject', 'CryptoKey', 'Uint8Array')); + } + if (jwkExportSupported) { + return keyObject.export({ format: 'jwk' }); + } + switch (keyObject.type) { + case 'secret': + return { + kty: 'oct', + k: (0, base64url_js_1.encode)(keyObject.export()), + }; + case 'private': + case 'public': { + switch (keyObject.asymmetricKeyType) { + case 'rsa': { + const der = keyObject.export({ format: 'der', type: 'pkcs1' }); + const dec = new asn1_sequence_decoder_js_1.default(der); + if (keyObject.type === 'private') { + dec.unsignedInteger(); + } + const n = (0, base64url_js_1.encode)(dec.unsignedInteger()); + const e = (0, base64url_js_1.encode)(dec.unsignedInteger()); + let jwk; + if (keyObject.type === 'private') { + jwk = { + d: (0, base64url_js_1.encode)(dec.unsignedInteger()), + p: (0, base64url_js_1.encode)(dec.unsignedInteger()), + q: (0, base64url_js_1.encode)(dec.unsignedInteger()), + dp: (0, base64url_js_1.encode)(dec.unsignedInteger()), + dq: (0, base64url_js_1.encode)(dec.unsignedInteger()), + qi: (0, base64url_js_1.encode)(dec.unsignedInteger()), + }; + } + dec.end(); + return { kty: 'RSA', n, e, ...jwk }; + } + case 'ec': { + const crv = (0, get_named_curve_js_1.default)(keyObject); + let len; + let offset; + let correction; + switch (crv) { + case 'secp256k1': + len = 64; + offset = 31 + 2; + correction = -1; + break; + case 'P-256': + len = 64; + offset = 34 + 2; + correction = -1; + break; + case 'P-384': + len = 96; + offset = 33 + 2; + correction = -3; + break; + case 'P-521': + len = 132; + offset = 33 + 2; + correction = -3; + break; + default: + throw new errors_js_1.JOSENotSupported('unsupported curve'); + } + if (keyObject.type === 'public') { + const der = keyObject.export({ type: 'spki', format: 'der' }); + return { + kty: 'EC', + crv, + x: (0, base64url_js_1.encode)(der.subarray(-len, -len / 2)), + y: (0, base64url_js_1.encode)(der.subarray(-len / 2)), + }; + } + const der = keyObject.export({ type: 'pkcs8', format: 'der' }); + if (der.length < 100) { + offset += correction; + } + return { + ...keyToJWK((0, crypto_1.createPublicKey)(keyObject)), + d: (0, base64url_js_1.encode)(der.subarray(offset, offset + len / 2)), + }; + } + case 'ed25519': + case 'x25519': { + const crv = (0, get_named_curve_js_1.default)(keyObject); + if (keyObject.type === 'public') { + const der = keyObject.export({ type: 'spki', format: 'der' }); + return { + kty: 'OKP', + crv, + x: (0, base64url_js_1.encode)(der.subarray(-32)), + }; + } + const der = keyObject.export({ type: 'pkcs8', format: 'der' }); + return { + ...keyToJWK((0, crypto_1.createPublicKey)(keyObject)), + d: (0, base64url_js_1.encode)(der.subarray(-32)), + }; + } + case 'ed448': + case 'x448': { + const crv = (0, get_named_curve_js_1.default)(keyObject); + if (keyObject.type === 'public') { + const der = keyObject.export({ type: 'spki', format: 'der' }); + return { + kty: 'OKP', + crv, + x: (0, base64url_js_1.encode)(der.subarray(crv === 'Ed448' ? -57 : -56)), + }; + } + const der = keyObject.export({ type: 'pkcs8', format: 'der' }); + return { + ...keyToJWK((0, crypto_1.createPublicKey)(keyObject)), + d: (0, base64url_js_1.encode)(der.subarray(crv === 'Ed448' ? -57 : -56)), + }; + } + default: + throw new errors_js_1.JOSENotSupported('unsupported key asymmetricKeyType'); + } + } + default: + throw new errors_js_1.JOSENotSupported('unsupported key type'); + } +}; +exports.default = keyToJWK; diff --git a/dist/node/cjs/runtime/node_key.js b/dist/node/cjs/runtime/node_key.js new file mode 100644 index 0000000000..60378ff32a --- /dev/null +++ b/dist/node/cjs/runtime/node_key.js @@ -0,0 +1,86 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const crypto_1 = require("crypto"); +const get_named_curve_js_1 = require("./get_named_curve.js"); +const errors_js_1 = require("../util/errors.js"); +const check_modulus_length_js_1 = require("./check_modulus_length.js"); +const [major, minor] = process.version + .substr(1) + .split('.') + .map((str) => parseInt(str, 10)); +const rsaPssParams = major >= 17 || (major === 16 && minor >= 9); +const ecCurveAlgMap = new Map([ + ['ES256', 'P-256'], + ['ES256K', 'secp256k1'], + ['ES384', 'P-384'], + ['ES512', 'P-521'], +]); +function keyForCrypto(alg, key) { + switch (alg) { + case 'EdDSA': + if (!['ed25519', 'ed448'].includes(key.asymmetricKeyType)) { + throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be ed25519 or ed448'); + } + return key; + case 'RS256': + case 'RS384': + case 'RS512': + if (key.asymmetricKeyType !== 'rsa') { + throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be rsa'); + } + (0, check_modulus_length_js_1.default)(key, alg); + return key; + case rsaPssParams && 'PS256': + case rsaPssParams && 'PS384': + case rsaPssParams && 'PS512': + if (key.asymmetricKeyType === 'rsa-pss') { + const { hashAlgorithm, mgf1HashAlgorithm, saltLength } = key.asymmetricKeyDetails; + const length = parseInt(alg.substr(-3), 10); + if (hashAlgorithm !== undefined && + (hashAlgorithm !== `sha${length}` || mgf1HashAlgorithm !== hashAlgorithm)) { + throw new TypeError(`Invalid key for this operation, its RSA-PSS parameters do not meet the requirements of "alg" ${alg}`); + } + if (saltLength !== undefined && saltLength > length >> 3) { + throw new TypeError(`Invalid key for this operation, its RSA-PSS parameter saltLength does not meet the requirements of "alg" ${alg}`); + } + } + else if (key.asymmetricKeyType !== 'rsa') { + throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be rsa or rsa-pss'); + } + (0, check_modulus_length_js_1.default)(key, alg); + return { + key, + padding: crypto_1.constants.RSA_PKCS1_PSS_PADDING, + saltLength: crypto_1.constants.RSA_PSS_SALTLEN_DIGEST, + }; + case !rsaPssParams && 'PS256': + case !rsaPssParams && 'PS384': + case !rsaPssParams && 'PS512': + if (key.asymmetricKeyType !== 'rsa') { + throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be rsa'); + } + (0, check_modulus_length_js_1.default)(key, alg); + return { + key, + padding: crypto_1.constants.RSA_PKCS1_PSS_PADDING, + saltLength: crypto_1.constants.RSA_PSS_SALTLEN_DIGEST, + }; + case 'ES256': + case 'ES256K': + case 'ES384': + case 'ES512': { + if (key.asymmetricKeyType !== 'ec') { + throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be ec'); + } + const actual = (0, get_named_curve_js_1.default)(key); + const expected = ecCurveAlgMap.get(alg); + if (actual !== expected) { + throw new TypeError(`Invalid key curve for the algorithm, its curve must be ${expected}, got ${actual}`); + } + return { dsaEncoding: 'ieee-p1363', key }; + } + default: + throw new errors_js_1.JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`); + } +} +exports.default = keyForCrypto; diff --git a/dist/node/cjs/runtime/pbes2kw.js b/dist/node/cjs/runtime/pbes2kw.js new file mode 100644 index 0000000000..1bc570801b --- /dev/null +++ b/dist/node/cjs/runtime/pbes2kw.js @@ -0,0 +1,45 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.decrypt = exports.encrypt = void 0; +const util_1 = require("util"); +const crypto_1 = require("crypto"); +const random_js_1 = require("./random.js"); +const buffer_utils_js_1 = require("../lib/buffer_utils.js"); +const base64url_js_1 = require("./base64url.js"); +const aeskw_js_1 = require("./aeskw.js"); +const check_p2s_js_1 = require("../lib/check_p2s.js"); +const webcrypto_js_1 = require("./webcrypto.js"); +const is_key_object_js_1 = require("./is_key_object.js"); +const invalid_key_input_js_1 = require("./invalid_key_input.js"); +const pbkdf2 = (0, util_1.promisify)(crypto_1.pbkdf2); +function getPassword(key, alg) { + if ((0, is_key_object_js_1.default)(key)) { + return key.export(); + } + if (key instanceof Uint8Array) { + return key; + } + if ((0, webcrypto_js_1.isCryptoKey)(key)) { + return (0, webcrypto_js_1.getKeyObject)(key, alg, new Set(['deriveBits', 'deriveKey'])).export(); + } + throw new TypeError((0, invalid_key_input_js_1.default)(key, 'KeyObject', 'CryptoKey', 'Uint8Array')); +} +const encrypt = async (alg, key, cek, p2c = Math.floor(Math.random() * 2049) + 2048, p2s = (0, random_js_1.default)(new Uint8Array(16))) => { + (0, check_p2s_js_1.default)(p2s); + const salt = (0, buffer_utils_js_1.p2s)(alg, p2s); + const keylen = parseInt(alg.substr(13, 3), 10) >> 3; + const password = getPassword(key, alg); + const derivedKey = await pbkdf2(password, salt, p2c, keylen, `sha${alg.substr(8, 3)}`); + const encryptedKey = await (0, aeskw_js_1.wrap)(alg.substr(-6), derivedKey, cek); + return { encryptedKey, p2c, p2s: (0, base64url_js_1.encode)(p2s) }; +}; +exports.encrypt = encrypt; +const decrypt = async (alg, key, encryptedKey, p2c, p2s) => { + (0, check_p2s_js_1.default)(p2s); + const salt = (0, buffer_utils_js_1.p2s)(alg, p2s); + const keylen = parseInt(alg.substr(13, 3), 10) >> 3; + const password = getPassword(key, alg); + const derivedKey = await pbkdf2(password, salt, p2c, keylen, `sha${alg.substr(8, 3)}`); + return (0, aeskw_js_1.unwrap)(alg.substr(-6), derivedKey, encryptedKey); +}; +exports.decrypt = decrypt; diff --git a/dist/node/cjs/runtime/random.js b/dist/node/cjs/runtime/random.js new file mode 100644 index 0000000000..2ac8670b74 --- /dev/null +++ b/dist/node/cjs/runtime/random.js @@ -0,0 +1,4 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const crypto_1 = require("crypto"); +exports.default = crypto_1.randomFillSync; diff --git a/dist/node/cjs/runtime/rsaes.js b/dist/node/cjs/runtime/rsaes.js new file mode 100644 index 0000000000..b8aaf2869e --- /dev/null +++ b/dist/node/cjs/runtime/rsaes.js @@ -0,0 +1,66 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.decrypt = exports.encrypt = void 0; +const crypto_1 = require("crypto"); +const check_modulus_length_js_1 = require("./check_modulus_length.js"); +const webcrypto_js_1 = require("./webcrypto.js"); +const is_key_object_js_1 = require("./is_key_object.js"); +const invalid_key_input_js_1 = require("./invalid_key_input.js"); +const checkKey = (key, alg) => { + if (key.asymmetricKeyType !== 'rsa') { + throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be rsa'); + } + (0, check_modulus_length_js_1.default)(key, alg); +}; +const resolvePadding = (alg) => { + switch (alg) { + case 'RSA-OAEP': + case 'RSA-OAEP-256': + case 'RSA-OAEP-384': + case 'RSA-OAEP-512': + return crypto_1.constants.RSA_PKCS1_OAEP_PADDING; + case 'RSA1_5': + return crypto_1.constants.RSA_PKCS1_PADDING; + default: + return undefined; + } +}; +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; + } +}; +function ensureKeyObject(key, alg, ...usages) { + if ((0, is_key_object_js_1.default)(key)) { + return key; + } + if ((0, webcrypto_js_1.isCryptoKey)(key)) { + return (0, webcrypto_js_1.getKeyObject)(key, alg, new Set(usages)); + } + throw new TypeError((0, invalid_key_input_js_1.default)(key, 'KeyObject', 'CryptoKey')); +} +const encrypt = async (alg, key, cek) => { + const padding = resolvePadding(alg); + const oaepHash = resolveOaepHash(alg); + const keyObject = ensureKeyObject(key, alg, 'wrapKey', 'encrypt'); + checkKey(keyObject, alg); + return (0, crypto_1.publicEncrypt)({ key: keyObject, oaepHash, padding }, cek); +}; +exports.encrypt = encrypt; +const decrypt = async (alg, key, encryptedKey) => { + const padding = resolvePadding(alg); + const oaepHash = resolveOaepHash(alg); + const keyObject = ensureKeyObject(key, alg, 'unwrapKey', 'decrypt'); + checkKey(keyObject, alg); + return (0, crypto_1.privateDecrypt)({ key: keyObject, oaepHash, padding }, encryptedKey); +}; +exports.decrypt = decrypt; diff --git a/dist/node/cjs/runtime/secret_key.js b/dist/node/cjs/runtime/secret_key.js new file mode 100644 index 0000000000..3a92aa91f5 --- /dev/null +++ b/dist/node/cjs/runtime/secret_key.js @@ -0,0 +1,14 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const crypto_1 = require("crypto"); +function getSecretKey(key) { + let keyObject; + if (key instanceof Uint8Array) { + keyObject = (0, crypto_1.createSecretKey)(key); + } + else { + keyObject = key; + } + return keyObject; +} +exports.default = getSecretKey; diff --git a/dist/node/cjs/runtime/sign.js b/dist/node/cjs/runtime/sign.js new file mode 100644 index 0000000000..6d8991bfb5 --- /dev/null +++ b/dist/node/cjs/runtime/sign.js @@ -0,0 +1,29 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const crypto = require("crypto"); +const util_1 = require("util"); +const dsa_digest_js_1 = require("./dsa_digest.js"); +const hmac_digest_js_1 = require("./hmac_digest.js"); +const node_key_js_1 = require("./node_key.js"); +const get_sign_verify_key_js_1 = require("./get_sign_verify_key.js"); +let oneShotSign; +if (crypto.sign.length > 3) { + oneShotSign = (0, util_1.promisify)(crypto.sign); +} +else { + oneShotSign = crypto.sign; +} +const sign = async (alg, key, data) => { + const keyObject = (0, get_sign_verify_key_js_1.default)(alg, key, 'sign'); + 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 = crypto.createHmac((0, hmac_digest_js_1.default)(alg), keyObject); + hmac.update(data); + return hmac.digest(); + } + return oneShotSign((0, dsa_digest_js_1.default)(alg), data, (0, node_key_js_1.default)(alg, keyObject)); +}; +exports.default = sign; diff --git a/dist/node/cjs/runtime/timing_safe_equal.js b/dist/node/cjs/runtime/timing_safe_equal.js new file mode 100644 index 0000000000..e1e4ef6100 --- /dev/null +++ b/dist/node/cjs/runtime/timing_safe_equal.js @@ -0,0 +1,5 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const crypto_1 = require("crypto"); +const timingSafeEqual = crypto_1.timingSafeEqual; +exports.default = timingSafeEqual; diff --git a/dist/node/cjs/runtime/verify.js b/dist/node/cjs/runtime/verify.js new file mode 100644 index 0000000000..7509e18610 --- /dev/null +++ b/dist/node/cjs/runtime/verify.js @@ -0,0 +1,42 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const crypto = require("crypto"); +const util_1 = require("util"); +const dsa_digest_js_1 = require("./dsa_digest.js"); +const node_key_js_1 = require("./node_key.js"); +const sign_js_1 = require("./sign.js"); +const get_sign_verify_key_js_1 = require("./get_sign_verify_key.js"); +const [major, minor] = process.version + .substr(1) + .split('.') + .map((str) => parseInt(str, 10)); +const oneShotCallbackSupported = major >= 16 || (major === 15 && minor >= 13); +let oneShotVerify; +if (crypto.verify.length > 4 && oneShotCallbackSupported) { + oneShotVerify = (0, util_1.promisify)(crypto.verify); +} +else { + oneShotVerify = crypto.verify; +} +const verify = async (alg, key, signature, data) => { + const keyObject = (0, get_sign_verify_key_js_1.default)(alg, key, 'verify'); + if (alg.startsWith('HS')) { + const expected = await (0, sign_js_1.default)(alg, keyObject, data); + const actual = signature; + try { + return crypto.timingSafeEqual(actual, expected); + } + catch { + return false; + } + } + const algorithm = (0, dsa_digest_js_1.default)(alg); + const keyInput = (0, node_key_js_1.default)(alg, keyObject); + try { + return await oneShotVerify(algorithm, data, keyInput, signature); + } + catch { + return false; + } +}; +exports.default = verify; diff --git a/dist/node/cjs/runtime/webcrypto.js b/dist/node/cjs/runtime/webcrypto.js new file mode 100644 index 0000000000..137fc3933c --- /dev/null +++ b/dist/node/cjs/runtime/webcrypto.js @@ -0,0 +1,165 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.getKeyObject = exports.isCryptoKey = void 0; +const crypto = require("crypto"); +const util = require("util"); +const webcrypto = crypto.webcrypto; +exports.default = webcrypto; +let impl; +exports.isCryptoKey = impl; +if (util.types.isCryptoKey) { + exports.isCryptoKey = impl = function isCryptoKey(obj) { + return util.types.isCryptoKey(obj); + }; +} +else if (webcrypto) { + exports.isCryptoKey = impl = function isCryptoKey(obj) { + return obj != null && obj instanceof webcrypto.CryptoKey; + }; +} +else { + exports.isCryptoKey = impl = (obj) => false; +} +function getHashLength(hash) { + return parseInt(hash === null || hash === void 0 ? void 0 : hash.name.substr(4), 10); +} +function getNamedCurve(alg) { + switch (alg) { + case 'ES256': + return 'P-256'; + case 'ES384': + return 'P-384'; + case 'ES512': + return 'P-521'; + } +} +function getKeyObject(key, alg, usage) { + if (!alg) { + return crypto.KeyObject.from(key); + } + switch (alg) { + case 'HS256': + case 'HS384': + case 'HS512': { + if (key.algorithm.name !== 'HMAC') { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be HMAC.`); + } + const expected = parseInt(alg.substr(2), 10); + const actual = getHashLength(key.algorithm.hash); + if (actual !== expected) { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.hash must be SHA-${expected}.`); + } + break; + } + case 'RS256': + case 'RS384': + case 'RS512': { + if (key.algorithm.name !== 'RSASSA-PKCS1-v1_5') { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be RSASSA-PKCS1-v1_5.`); + } + const expected = parseInt(alg.substr(2), 10); + const actual = getHashLength(key.algorithm.hash); + if (actual !== expected) { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.hash must be SHA-${expected}.`); + } + break; + } + case 'PS256': + case 'PS384': + case 'PS512': { + if (key.algorithm.name !== 'RSA-PSS') { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be RSA-PSS.`); + } + const expected = parseInt(alg.substr(2), 10); + const actual = getHashLength(key.algorithm.hash); + if (actual !== expected) { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.hash must be SHA-${expected}.`); + } + break; + } + case 'ES256': + case 'ES384': + case 'ES512': { + if (key.algorithm.name !== 'ECDSA') { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be ECDSA.`); + } + const expected = getNamedCurve(alg); + const actual = key.algorithm.namedCurve; + if (actual !== expected) { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.namedCurve must be ${expected}.`); + } + break; + } + case 'A128GCM': + case 'A192GCM': + case 'A256GCM': { + if (key.algorithm.name !== 'AES-GCM') { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be AES-GCM.`); + } + const expected = parseInt(alg.substr(1, 3), 10); + const actual = key.algorithm.length; + if (actual !== expected) { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.length must be ${expected}.`); + } + break; + } + case 'A128KW': + case 'A192KW': + case 'A256KW': { + if (key.algorithm.name !== 'AES-KW') { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be AES-KW.`); + } + const expected = parseInt(alg.substr(1, 3), 10); + const actual = key.algorithm.length; + if (actual !== expected) { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.length must be ${expected}.`); + } + break; + } + case 'ECDH-ES': + if (key.algorithm.name !== 'ECDH') { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be ECDH.`); + } + break; + case 'PBES2-HS256+A128KW': + case 'PBES2-HS384+A192KW': + case 'PBES2-HS512+A256KW': + if (key.algorithm.name !== 'PBKDF2') { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be PBKDF2.`); + } + break; + case 'RSA-OAEP': + case 'RSA-OAEP-256': + case 'RSA-OAEP-384': + case 'RSA-OAEP-512': { + if (key.algorithm.name !== 'RSA-OAEP') { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be RSA-OAEP.`); + } + const expected = parseInt(alg.substr(9), 10) || 1; + const actual = getHashLength(key.algorithm.hash); + if (actual !== expected) { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.hash must be SHA-${expected}.`); + } + break; + } + default: + throw new TypeError('CryptoKey does not support this operation'); + } + if (usage && !key.usages.find(Set.prototype.has.bind(usage))) { + const usages = [...usage]; + let msg = 'CryptoKey does not support this operation, its usages must include '; + if (usages.length > 2) { + const last = usages.pop(); + msg += `one of ${usages.join(', ')}, or ${last}.`; + } + else if (usages.length === 2) { + msg += `one of ${usages[0]} or ${usages[1]}.`; + } + else { + msg += ` ${usages[0]}.`; + } + throw new TypeError(msg); + } + return crypto.KeyObject.from(key); +} +exports.getKeyObject = getKeyObject; diff --git a/dist/node/cjs/runtime/zlib.js b/dist/node/cjs/runtime/zlib.js new file mode 100644 index 0000000000..7dcfddf49b --- /dev/null +++ b/dist/node/cjs/runtime/zlib.js @@ -0,0 +1,11 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.deflate = exports.inflate = void 0; +const util_1 = require("util"); +const zlib_1 = require("zlib"); +const inflateRaw = (0, util_1.promisify)(zlib_1.inflateRaw); +const deflateRaw = (0, util_1.promisify)(zlib_1.deflateRaw); +const inflate = (input) => inflateRaw(input); +exports.inflate = inflate; +const deflate = (input) => deflateRaw(input); +exports.deflate = deflate; diff --git a/dist/node/cjs/util/base64url.js b/dist/node/cjs/util/base64url.js new file mode 100644 index 0000000000..4d383b5167 --- /dev/null +++ b/dist/node/cjs/util/base64url.js @@ -0,0 +1,6 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.decode = exports.encode = void 0; +const base64url = require("../runtime/base64url.js"); +exports.encode = base64url.encode; +exports.decode = base64url.decode; diff --git a/dist/node/cjs/util/decode_protected_header.js b/dist/node/cjs/util/decode_protected_header.js new file mode 100644 index 0000000000..3db5e335c1 --- /dev/null +++ b/dist/node/cjs/util/decode_protected_header.js @@ -0,0 +1,39 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.decodeProtectedHeader = void 0; +const base64url_js_1 = require("./base64url.js"); +const buffer_utils_js_1 = require("../lib/buffer_utils.js"); +const is_object_js_1 = require("../lib/is_object.js"); +function decodeProtectedHeader(token) { + let protectedB64u; + if (typeof token === 'string') { + const parts = token.split('.'); + if (parts.length === 3 || parts.length === 5) { + ; + [protectedB64u] = parts; + } + } + else if (typeof token === 'object' && token) { + if ('protected' in token) { + protectedB64u = token.protected; + } + else { + throw new TypeError('Token does not contain a Protected Header'); + } + } + try { + if (typeof protectedB64u !== 'string' || !protectedB64u) { + throw new Error(); + } + const result = JSON.parse(buffer_utils_js_1.decoder.decode((0, base64url_js_1.decode)(protectedB64u))); + if (!(0, is_object_js_1.default)(result)) { + throw new Error(); + } + return result; + } + catch { + throw new TypeError('Invalid Token or Protected Header formatting'); + } +} +exports.decodeProtectedHeader = decodeProtectedHeader; +exports.default = decodeProtectedHeader; diff --git a/dist/node/cjs/util/errors.js b/dist/node/cjs/util/errors.js new file mode 100644 index 0000000000..4dcb8cd226 --- /dev/null +++ b/dist/node/cjs/util/errors.js @@ -0,0 +1,125 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.JWTExpired = exports.JWSSignatureVerificationFailed = exports.JWKSMultipleMatchingKeys = exports.JWKSNoMatchingKey = exports.JWKSInvalid = exports.JWKInvalid = exports.JWTInvalid = exports.JWSInvalid = exports.JWEInvalid = exports.JWEDecryptionFailed = exports.JOSENotSupported = exports.JOSEAlgNotAllowed = exports.JWTClaimValidationFailed = exports.JOSEError = void 0; +class JOSEError extends Error { + constructor(message) { + super(message); + this.code = JOSEError.code; + this.name = this.constructor.name; + if (Error.captureStackTrace) { + Error.captureStackTrace(this, this.constructor); + } + } +} +exports.JOSEError = JOSEError; +JOSEError.code = 'ERR_JOSE_GENERIC'; +class JWTClaimValidationFailed extends JOSEError { + constructor(message, claim = 'unspecified', reason = 'unspecified') { + super(message); + this.code = JWTClaimValidationFailed.code; + this.claim = claim; + this.reason = reason; + } +} +exports.JWTClaimValidationFailed = JWTClaimValidationFailed; +JWTClaimValidationFailed.code = 'ERR_JWT_CLAIM_VALIDATION_FAILED'; +class JOSEAlgNotAllowed extends JOSEError { + constructor() { + super(...arguments); + this.code = JOSEAlgNotAllowed.code; + } +} +exports.JOSEAlgNotAllowed = JOSEAlgNotAllowed; +JOSEAlgNotAllowed.code = 'ERR_JOSE_ALG_NOT_ALLOWED'; +class JOSENotSupported extends JOSEError { + constructor() { + super(...arguments); + this.code = JOSENotSupported.code; + } +} +exports.JOSENotSupported = JOSENotSupported; +JOSENotSupported.code = 'ERR_JOSE_NOT_SUPPORTED'; +class JWEDecryptionFailed extends JOSEError { + constructor() { + super(...arguments); + this.code = JWEDecryptionFailed.code; + this.message = 'decryption operation failed'; + } +} +exports.JWEDecryptionFailed = JWEDecryptionFailed; +JWEDecryptionFailed.code = 'ERR_JWE_DECRYPTION_FAILED'; +class JWEInvalid extends JOSEError { + constructor() { + super(...arguments); + this.code = JWEInvalid.code; + } +} +exports.JWEInvalid = JWEInvalid; +JWEInvalid.code = 'ERR_JWE_INVALID'; +class JWSInvalid extends JOSEError { + constructor() { + super(...arguments); + this.code = JWSInvalid.code; + } +} +exports.JWSInvalid = JWSInvalid; +JWSInvalid.code = 'ERR_JWS_INVALID'; +class JWTInvalid extends JOSEError { + constructor() { + super(...arguments); + this.code = JWTInvalid.code; + } +} +exports.JWTInvalid = JWTInvalid; +JWTInvalid.code = 'ERR_JWT_INVALID'; +class JWKInvalid extends JOSEError { + constructor() { + super(...arguments); + this.code = JWKInvalid.code; + } +} +exports.JWKInvalid = JWKInvalid; +JWKInvalid.code = 'ERR_JWK_INVALID'; +class JWKSInvalid extends JOSEError { + constructor() { + super(...arguments); + this.code = JWKSInvalid.code; + } +} +exports.JWKSInvalid = JWKSInvalid; +JWKSInvalid.code = 'ERR_JWKS_INVALID'; +class JWKSNoMatchingKey extends JOSEError { + constructor() { + super(...arguments); + this.code = JWKSNoMatchingKey.code; + this.message = 'no applicable key found in the JSON Web Key Set'; + } +} +exports.JWKSNoMatchingKey = JWKSNoMatchingKey; +JWKSNoMatchingKey.code = 'ERR_JWKS_NO_MATCHING_KEY'; +class JWKSMultipleMatchingKeys extends JOSEError { + constructor() { + super(...arguments); + this.code = JWKSMultipleMatchingKeys.code; + this.message = 'multiple matching keys found in the JSON Web Key Set'; + } +} +exports.JWKSMultipleMatchingKeys = JWKSMultipleMatchingKeys; +JWKSMultipleMatchingKeys.code = 'ERR_JWKS_MULTIPLE_MATCHING_KEYS'; +class JWSSignatureVerificationFailed extends JOSEError { + constructor() { + super(...arguments); + this.code = JWSSignatureVerificationFailed.code; + this.message = 'signature verification failed'; + } +} +exports.JWSSignatureVerificationFailed = JWSSignatureVerificationFailed; +JWSSignatureVerificationFailed.code = 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED'; +class JWTExpired extends JWTClaimValidationFailed { + constructor() { + super(...arguments); + this.code = JWTExpired.code; + } +} +exports.JWTExpired = JWTExpired; +JWTExpired.code = 'ERR_JWT_EXPIRED'; diff --git a/dist/node/cjs/util/generate_key_pair.js b/dist/node/cjs/util/generate_key_pair.js new file mode 100644 index 0000000000..548636d06c --- /dev/null +++ b/dist/node/cjs/util/generate_key_pair.js @@ -0,0 +1,9 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.generateKeyPair = void 0; +const generate_js_1 = require("../runtime/generate.js"); +async function generateKeyPair(alg, options) { + return (0, generate_js_1.generateKeyPair)(alg, options); +} +exports.generateKeyPair = generateKeyPair; +exports.default = generateKeyPair; diff --git a/dist/node/cjs/util/generate_secret.js b/dist/node/cjs/util/generate_secret.js new file mode 100644 index 0000000000..5270b09714 --- /dev/null +++ b/dist/node/cjs/util/generate_secret.js @@ -0,0 +1,9 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.generateSecret = void 0; +const generate_js_1 = require("../runtime/generate.js"); +async function generateSecret(alg, options) { + return (0, generate_js_1.generateSecret)(alg, options); +} +exports.generateSecret = generateSecret; +exports.default = generateSecret; diff --git a/dist/node/cjs/util/random.js b/dist/node/cjs/util/random.js new file mode 100644 index 0000000000..f4c78fc47b --- /dev/null +++ b/dist/node/cjs/util/random.js @@ -0,0 +1,7 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.random = void 0; +const random_js_1 = require("../runtime/random.js"); +const random = random_js_1.default; +exports.random = random; +exports.default = random; diff --git a/dist/node/esm/jwe/compact/decrypt.js b/dist/node/esm/jwe/compact/decrypt.js new file mode 100644 index 0000000000..e4e87c1c17 --- /dev/null +++ b/dist/node/esm/jwe/compact/decrypt.js @@ -0,0 +1,25 @@ +import decrypt from '../flattened/decrypt.js'; +import { JWEInvalid } from '../../util/errors.js'; +import { decoder } from '../../lib/buffer_utils.js'; +async function compactDecrypt(jwe, key, options) { + if (jwe instanceof Uint8Array) { + jwe = decoder.decode(jwe); + } + if (typeof jwe !== 'string') { + throw new JWEInvalid('Compact JWE must be a string or Uint8Array'); + } + 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: (ciphertext || undefined), + iv: (iv || undefined), + protected: protectedHeader || undefined, + tag: (tag || undefined), + encrypted_key: encryptedKey || undefined, + }, key, options); + return { plaintext: decrypted.plaintext, protectedHeader: decrypted.protectedHeader }; +} +export { compactDecrypt }; +export default compactDecrypt; diff --git a/dist/node/esm/jwe/compact/encrypt.js b/dist/node/esm/jwe/compact/encrypt.js new file mode 100644 index 0000000000..132a092398 --- /dev/null +++ b/dist/node/esm/jwe/compact/encrypt.js @@ -0,0 +1,28 @@ +import FlattenedEncrypt from '../flattened/encrypt.js'; +class CompactEncrypt { + constructor(plaintext) { + this._flattened = new FlattenedEncrypt(plaintext); + } + setContentEncryptionKey(cek) { + this._flattened.setContentEncryptionKey(cek); + return this; + } + setInitializationVector(iv) { + this._flattened.setInitializationVector(iv); + return this; + } + setProtectedHeader(protectedHeader) { + this._flattened.setProtectedHeader(protectedHeader); + return this; + } + setKeyManagementParameters(parameters) { + this._flattened.setKeyManagementParameters(parameters); + return this; + } + async encrypt(key, options) { + const jwe = await this._flattened.encrypt(key, options); + return [jwe.protected, jwe.encrypted_key, jwe.iv, jwe.ciphertext, jwe.tag].join('.'); + } +} +export { CompactEncrypt }; +export default CompactEncrypt; diff --git a/dist/node/esm/jwe/flattened/decrypt.js b/dist/node/esm/jwe/flattened/decrypt.js new file mode 100644 index 0000000000..a60f8a4190 --- /dev/null +++ b/dist/node/esm/jwe/flattened/decrypt.js @@ -0,0 +1,138 @@ +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 { 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 checkExtensions = validateCrit.bind(undefined, JWEInvalid, new Map()); +const checkAlgOption = validateAlgorithms.bind(undefined, 'keyManagementAlgorithms'); +const checkEncOption = validateAlgorithms.bind(undefined, 'contentEncryptionAlgorithms'); +async function flattenedDecrypt(jwe, key, options) { + var _a; + if (!isObject(jwe)) { + throw new JWEInvalid('Flattened JWE must be an object'); + } + if (jwe.protected === undefined && jwe.header === undefined && jwe.unprotected === undefined) { + throw new JWEInvalid('JOSE Header missing'); + } + if (typeof jwe.iv !== 'string') { + throw new JWEInvalid('JWE Initialization Vector missing or incorrect type'); + } + if (typeof jwe.ciphertext !== 'string') { + throw new JWEInvalid('JWE Ciphertext missing or incorrect type'); + } + if (typeof jwe.tag !== 'string') { + throw new JWEInvalid('JWE Authentication Tag missing or incorrect type'); + } + if (jwe.protected !== undefined && typeof jwe.protected !== 'string') { + throw new JWEInvalid('JWE Protected Header incorrect type'); + } + if (jwe.encrypted_key !== undefined && typeof jwe.encrypted_key !== 'string') { + throw new JWEInvalid('JWE Encrypted Key incorrect type'); + } + if (jwe.aad !== undefined && typeof jwe.aad !== 'string') { + throw new JWEInvalid('JWE AAD incorrect type'); + } + if (jwe.header !== undefined && !isObject(jwe.header)) { + throw new JWEInvalid('JWE Shared Unprotected Header incorrect type'); + } + if (jwe.unprotected !== undefined && !isObject(jwe.unprotected)) { + throw new JWEInvalid('JWE Per-Recipient Unprotected Header incorrect type'); + } + let parsedProt; + if (jwe.protected) { + const protectedHeader = base64url(jwe.protected); + try { + parsedProt = JSON.parse(decoder.decode(protectedHeader)); + } + catch { + throw new JWEInvalid('JWE Protected Header is invalid'); + } + } + 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 = { + ...parsedProt, + ...jwe.header, + ...jwe.unprotected, + }; + checkExtensions(options === null || options === void 0 ? void 0 : options.crit, parsedProt, joseHeader); + if (joseHeader.zip !== undefined) { + 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 (typeof alg !== 'string' || !alg) { + throw new JWEInvalid('missing JWE Algorithm (alg) in JWE Header'); + } + if (typeof enc !== 'string' || !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; + if (jwe.encrypted_key !== undefined) { + encryptedKey = base64url(jwe.encrypted_key); + } + if (typeof key === 'function') { + key = await key(parsedProt, jwe); + } + let cek; + try { + cek = await decryptKeyManagement(alg, key, encryptedKey, joseHeader); + } + catch (err) { + if (err instanceof TypeError) { + throw err; + } + cek = generateCek(enc); + } + const iv = base64url(jwe.iv); + const tag = base64url(jwe.tag); + const protectedHeader = encoder.encode((_a = jwe.protected) !== null && _a !== void 0 ? _a : ''); + let additionalData; + if (jwe.aad !== undefined) { + 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 === null || options === void 0 ? void 0 : options.inflateRaw) || inflate)(plaintext); + } + const result = { plaintext }; + if (jwe.protected !== undefined) { + result.protectedHeader = parsedProt; + } + if (jwe.aad !== undefined) { + result.additionalAuthenticatedData = base64url(jwe.aad); + } + if (jwe.unprotected !== undefined) { + result.sharedUnprotectedHeader = jwe.unprotected; + } + if (jwe.header !== undefined) { + result.unprotectedHeader = jwe.header; + } + return result; +} +export { flattenedDecrypt }; +export default flattenedDecrypt; diff --git a/dist/node/esm/jwe/flattened/encrypt.js b/dist/node/esm/jwe/flattened/encrypt.js new file mode 100644 index 0000000000..89c09f66ad --- /dev/null +++ b/dist/node/esm/jwe/flattened/encrypt.js @@ -0,0 +1,169 @@ +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 checkExtensions = validateCrit.bind(undefined, JWEInvalid, new Map()); +class FlattenedEncrypt { + constructor(plaintext) { + if (!(plaintext instanceof Uint8Array)) { + throw new TypeError('plaintext must be an instance of Uint8Array'); + } + this._plaintext = plaintext; + } + setKeyManagementParameters(parameters) { + if (this._keyManagementParameters) { + throw new TypeError('setKeyManagementParameters can only be called once'); + } + this._keyManagementParameters = parameters; + return this; + } + setProtectedHeader(protectedHeader) { + if (this._protectedHeader) { + throw new TypeError('setProtectedHeader can only be called once'); + } + this._protectedHeader = protectedHeader; + return this; + } + setSharedUnprotectedHeader(sharedUnprotectedHeader) { + if (this._sharedUnprotectedHeader) { + throw new TypeError('setSharedUnprotectedHeader can only be called once'); + } + this._sharedUnprotectedHeader = sharedUnprotectedHeader; + return this; + } + setUnprotectedHeader(unprotectedHeader) { + if (this._unprotectedHeader) { + throw new TypeError('setUnprotectedHeader can only be called once'); + } + this._unprotectedHeader = unprotectedHeader; + return this; + } + setAdditionalAuthenticatedData(aad) { + this._aad = aad; + return this; + } + setContentEncryptionKey(cek) { + if (this._cek) { + throw new TypeError('setContentEncryptionKey can only be called once'); + } + this._cek = cek; + return this; + } + setInitializationVector(iv) { + if (this._iv) { + throw new TypeError('setInitializationVector can only be called once'); + } + this._iv = iv; + return this; + } + async encrypt(key, options) { + 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 = { + ...this._protectedHeader, + ...this._unprotectedHeader, + ...this._sharedUnprotectedHeader, + }; + checkExtensions(options === null || options === void 0 ? void 0 : options.crit, this._protectedHeader, joseHeader); + if (joseHeader.zip !== undefined) { + 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 (typeof alg !== 'string' || !alg) { + throw new JWEInvalid('JWE "alg" (Algorithm) Header Parameter missing or invalid'); + } + if (typeof enc !== 'string' || !enc) { + throw new JWEInvalid('JWE "enc" (Encryption Algorithm) Header Parameter missing or invalid'); + } + let encryptedKey; + 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; + { + let parameters; + ({ 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 || (this._iv = generateIv(enc)); + let additionalData; + let protectedHeader; + let aadMember; + 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; + let tag; + if (joseHeader.zip === 'DEF') { + const deflated = await ((options === null || options === void 0 ? void 0 : 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 = { + 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 { FlattenedEncrypt }; +export default FlattenedEncrypt; diff --git a/dist/node/esm/jwe/general/decrypt.js b/dist/node/esm/jwe/general/decrypt.js new file mode 100644 index 0000000000..0ee57ba5fc --- /dev/null +++ b/dist/node/esm/jwe/general/decrypt.js @@ -0,0 +1,30 @@ +import decrypt from '../flattened/decrypt.js'; +import { JWEDecryptionFailed, JWEInvalid } from '../../util/errors.js'; +import isObject from '../../lib/is_object.js'; +async function generalDecrypt(jwe, key, options) { + if (!isObject(jwe)) { + throw new JWEInvalid('General JWE must be an object'); + } + if (!Array.isArray(jwe.recipients) || !jwe.recipients.every(isObject)) { + throw new JWEInvalid('JWE Recipients missing or incorrect type'); + } + for (const recipient of jwe.recipients) { + try { + return await decrypt({ + aad: jwe.aad, + ciphertext: jwe.ciphertext, + encrypted_key: recipient.encrypted_key, + header: recipient.header, + iv: jwe.iv, + protected: jwe.protected, + tag: jwe.tag, + unprotected: jwe.unprotected, + }, key, options); + } + catch { + } + } + throw new JWEDecryptionFailed(); +} +export { generalDecrypt }; +export default generalDecrypt; diff --git a/dist/node/esm/jwk/embedded.js b/dist/node/esm/jwk/embedded.js new file mode 100644 index 0000000000..60759f22e0 --- /dev/null +++ b/dist/node/esm/jwk/embedded.js @@ -0,0 +1,19 @@ +import parseJwk from './parse.js'; +import isObject from '../lib/is_object.js'; +import { JWSInvalid } from '../util/errors.js'; +async function EmbeddedJWK(protectedHeader, token) { + const joseHeader = { + ...protectedHeader, + ...token.header, + }; + if (!isObject(joseHeader.jwk)) { + throw new JWSInvalid('"jwk" (JSON Web Key) Header Parameter must be a JSON object'); + } + const key = await parseJwk(joseHeader.jwk, joseHeader.alg, true); + if (key.type !== 'public') { + throw new JWSInvalid('"jwk" (JSON Web Key) Header Parameter must be a public key'); + } + return key; +} +export { EmbeddedJWK }; +export default EmbeddedJWK; diff --git a/dist/node/esm/jwk/from_key_like.js b/dist/node/esm/jwk/from_key_like.js new file mode 100644 index 0000000000..5ea9173e1c --- /dev/null +++ b/dist/node/esm/jwk/from_key_like.js @@ -0,0 +1,6 @@ +import asJWK from '../runtime/key_to_jwk.js'; +async function fromKeyLike(key) { + return asJWK(key); +} +export { fromKeyLike }; +export default fromKeyLike; diff --git a/dist/node/esm/jwk/parse.js b/dist/node/esm/jwk/parse.js new file mode 100644 index 0000000000..cfa6f9492c --- /dev/null +++ b/dist/node/esm/jwk/parse.js @@ -0,0 +1,35 @@ +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'; +async function parseJwk(jwk, alg, octAsKeyObject) { + if (!isObject(jwk)) { + throw new TypeError('JWK must be an object'); + } + alg || (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'); + } + octAsKeyObject !== null && octAsKeyObject !== void 0 ? octAsKeyObject : (octAsKeyObject = jwk.ext !== true); + if (octAsKeyObject) { + return asKeyObject({ ...jwk, alg, ext: false }); + } + return base64url(jwk.k); + case 'RSA': + if (jwk.oth !== undefined) { + throw new JOSENotSupported('RSA JWK "oth" (Other Primes Info) Parameter value is not supported'); + } + case 'EC': + case 'OKP': + return asKeyObject({ ...jwk, alg }); + default: + throw new JOSENotSupported('unsupported "kty" (Key Type) Parameter value'); + } +} +export { parseJwk }; +export default parseJwk; diff --git a/dist/node/esm/jwk/thumbprint.js b/dist/node/esm/jwk/thumbprint.js new file mode 100644 index 0000000000..ffb569b31f --- /dev/null +++ b/dist/node/esm/jwk/thumbprint.js @@ -0,0 +1,44 @@ +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 isObject from '../lib/is_object.js'; +const check = (value, description) => { + if (typeof value !== 'string' || !value) { + throw new JWKInvalid(`${description} missing or invalid`); + } +}; +async function calculateThumbprint(jwk, digestAlgorithm = 'sha256') { + if (!isObject(jwk)) { + throw new TypeError('JWK must be an object'); + } + let components; + 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 { calculateThumbprint }; +export default calculateThumbprint; diff --git a/dist/node/esm/jwks/remote.js b/dist/node/esm/jwks/remote.js new file mode 100644 index 0000000000..7665477163 --- /dev/null +++ b/dist/node/esm/jwks/remote.js @@ -0,0 +1,130 @@ +import parseJWK from '../jwk/parse.js'; +import { JWKSInvalid, JOSENotSupported, JWKSNoMatchingKey, JWKSMultipleMatchingKeys, } from '../util/errors.js'; +import fetchJwks from '../runtime/fetch_jwks.js'; +import isObject from '../lib/is_object.js'; +function getKtyFromAlg(alg) { + 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'); + } +} +function isJWKLike(key) { + return isObject(key); +} +class RemoteJWKSet { + constructor(url, options) { + this._cached = new WeakMap(); + if (!(url instanceof URL)) { + throw new TypeError('url must be an instance of URL'); + } + this._url = new URL(url.href); + this._options = { agent: options === null || options === void 0 ? void 0 : options.agent }; + this._timeoutDuration = + typeof (options === null || options === void 0 ? void 0 : options.timeoutDuration) === 'number' ? options === null || options === void 0 ? void 0 : options.timeoutDuration : 5000; + this._cooldownDuration = + typeof (options === null || options === void 0 ? void 0 : options.cooldownDuration) === 'number' ? options === null || options === void 0 ? void 0 : options.cooldownDuration : 30000; + } + coolingDown() { + if (typeof this._cooldownStarted === 'undefined') { + return false; + } + return Date.now() < this._cooldownStarted + this._cooldownDuration; + } + async getKey(protectedHeader) { + if (!this._jwks) { + await this.reload(); + } + const candidates = this._jwks.keys.filter((jwk) => { + let candidate = jwk.kty === getKtyFromAlg(protectedHeader.alg); + if (candidate && typeof protectedHeader.kid === 'string') { + candidate = protectedHeader.kid === jwk.kid; + } + if (candidate && typeof jwk.alg === 'string') { + candidate = protectedHeader.alg === jwk.alg; + } + if (candidate && typeof jwk.use === 'string') { + candidate = jwk.use === 'sig'; + } + if (candidate && Array.isArray(jwk.key_ops)) { + candidate = jwk.key_ops.includes('verify'); + } + if (candidate && protectedHeader.alg === 'EdDSA') { + candidate = ['Ed25519', 'Ed448'].includes(jwk.crv); + } + 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 (cached[protectedHeader.alg] === undefined) { + const keyObject = await parseJWK({ ...jwk, alg: protectedHeader.alg }); + 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 = fetchJwks(this._url, this._timeoutDuration, this._options) + .then((json) => { + if (typeof json !== 'object' || + !json || + !Array.isArray(json.keys) || + !json.keys.every(isJWKLike)) { + throw new JWKSInvalid('JSON Web Key Set malformed'); + } + this._jwks = { keys: json.keys }; + this._cooldownStarted = Date.now(); + this._pendingFetch = undefined; + }) + .catch((err) => { + this._pendingFetch = undefined; + throw err; + }); + } + await this._pendingFetch; + } +} +function createRemoteJWKSet(url, options) { + return RemoteJWKSet.prototype.getKey.bind(new RemoteJWKSet(url, options)); +} +export { createRemoteJWKSet }; +export default createRemoteJWKSet; diff --git a/dist/node/esm/jws/compact/sign.js b/dist/node/esm/jws/compact/sign.js new file mode 100644 index 0000000000..5bacca34d9 --- /dev/null +++ b/dist/node/esm/jws/compact/sign.js @@ -0,0 +1,19 @@ +import FlattenedSign from '../flattened/sign.js'; +class CompactSign { + constructor(payload) { + this._flattened = new FlattenedSign(payload); + } + setProtectedHeader(protectedHeader) { + this._flattened.setProtectedHeader(protectedHeader); + return this; + } + async sign(key, options) { + const jws = await this._flattened.sign(key, options); + 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 { CompactSign }; +export default CompactSign; diff --git a/dist/node/esm/jws/compact/verify.js b/dist/node/esm/jws/compact/verify.js new file mode 100644 index 0000000000..aad640718b --- /dev/null +++ b/dist/node/esm/jws/compact/verify.js @@ -0,0 +1,23 @@ +import verify from '../flattened/verify.js'; +import { JWSInvalid } from '../../util/errors.js'; +import { decoder } from '../../lib/buffer_utils.js'; +async function compactVerify(jws, key, options) { + if (jws instanceof Uint8Array) { + jws = decoder.decode(jws); + } + if (typeof jws !== 'string') { + throw new JWSInvalid('Compact JWS must be a string or Uint8Array'); + } + const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split('.'); + if (length !== 3) { + throw new JWSInvalid('Invalid Compact JWS'); + } + const verified = await verify({ + payload: (payload || undefined), + protected: protectedHeader || undefined, + signature: (signature || undefined), + }, key, options); + return { payload: verified.payload, protectedHeader: verified.protectedHeader }; +} +export { compactVerify }; +export default compactVerify; diff --git a/dist/node/esm/jws/flattened/sign.js b/dist/node/esm/jws/flattened/sign.js new file mode 100644 index 0000000000..a9ec0aec95 --- /dev/null +++ b/dist/node/esm/jws/flattened/sign.js @@ -0,0 +1,84 @@ +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 checkKeyType from '../../lib/check_key_type.js'; +import validateCrit from '../../lib/validate_crit.js'; +const checkExtensions = validateCrit.bind(undefined, JWSInvalid, new Map([['b64', true]])); +class FlattenedSign { + constructor(payload) { + if (!(payload instanceof Uint8Array)) { + throw new TypeError('payload must be an instance of Uint8Array'); + } + this._payload = payload; + } + setProtectedHeader(protectedHeader) { + if (this._protectedHeader) { + throw new TypeError('setProtectedHeader can only be called once'); + } + this._protectedHeader = protectedHeader; + return this; + } + setUnprotectedHeader(unprotectedHeader) { + if (this._unprotectedHeader) { + throw new TypeError('setUnprotectedHeader can only be called once'); + } + this._unprotectedHeader = unprotectedHeader; + return this; + } + async sign(key, options) { + 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 = { + ...this._protectedHeader, + ...this._unprotectedHeader, + }; + const extensions = checkExtensions(options === null || options === void 0 ? void 0 : options.crit, this._protectedHeader, joseHeader); + let b64 = 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 (typeof alg !== 'string' || !alg) { + throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid'); + } + checkKeyType(alg, key, 'sign'); + let payload = this._payload; + if (b64) { + payload = encoder.encode(base64url(payload)); + } + let protectedHeader; + 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 = { + signature: base64url(signature), + payload: '', + }; + 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 { FlattenedSign }; +export default FlattenedSign; diff --git a/dist/node/esm/jws/flattened/verify.js b/dist/node/esm/jws/flattened/verify.js new file mode 100644 index 0000000000..311d0976c9 --- /dev/null +++ b/dist/node/esm/jws/flattened/verify.js @@ -0,0 +1,103 @@ +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'; +const checkExtensions = validateCrit.bind(undefined, JWSInvalid, new Map([['b64', true]])); +const checkAlgOption = validateAlgorithms.bind(undefined, 'algorithms'); +async function flattenedVerify(jws, key, options) { + var _a; + if (!isObject(jws)) { + throw new JWSInvalid('Flattened JWS must be an object'); + } + if (jws.protected === undefined && jws.header === undefined) { + throw new JWSInvalid('Flattened JWS must have either of the "protected" or "header" members'); + } + if (jws.protected !== undefined && typeof jws.protected !== 'string') { + throw new JWSInvalid('JWS Protected Header incorrect type'); + } + if (jws.payload === undefined) { + throw new JWSInvalid('JWS Payload missing'); + } + if (typeof jws.signature !== 'string') { + throw new JWSInvalid('JWS Signature missing or incorrect type'); + } + if (jws.header !== undefined && !isObject(jws.header)) { + throw new JWSInvalid('JWS Unprotected Header incorrect type'); + } + let parsedProt = {}; + if (jws.protected) { + const protectedHeader = base64url(jws.protected); + try { + parsedProt = JSON.parse(decoder.decode(protectedHeader)); + } + catch { + throw new JWSInvalid('JWS Protected Header is invalid'); + } + } + if (!isDisjoint(parsedProt, jws.header)) { + throw new JWSInvalid('JWS Protected and JWS Unprotected Header Parameter names must be disjoint'); + } + const joseHeader = { + ...parsedProt, + ...jws.header, + }; + const extensions = checkExtensions(options === null || options === void 0 ? void 0 : options.crit, parsedProt, joseHeader); + let b64 = 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 (typeof alg !== 'string' || !alg) { + throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid'); + } + 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') { + key = await key(parsedProt, jws); + } + checkKeyType(alg, key, 'verify'); + const data = concat(encoder.encode((_a = jws.protected) !== null && _a !== void 0 ? _a : ''), 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; + if (b64) { + payload = base64url(jws.payload); + } + else if (typeof jws.payload === 'string') { + payload = encoder.encode(jws.payload); + } + else { + payload = jws.payload; + } + const result = { payload }; + if (jws.protected !== undefined) { + result.protectedHeader = parsedProt; + } + if (jws.header !== undefined) { + result.unprotectedHeader = jws.header; + } + return result; +} +export { flattenedVerify }; +export default flattenedVerify; diff --git a/dist/node/esm/jws/general/sign.js b/dist/node/esm/jws/general/sign.js new file mode 100644 index 0000000000..7127accfa1 --- /dev/null +++ b/dist/node/esm/jws/general/sign.js @@ -0,0 +1,73 @@ +import FlattenedSign from '../flattened/sign.js'; +import { JWSInvalid } from '../../util/errors.js'; +const signatureRef = new WeakMap(); +class IndividualSignature { + setProtectedHeader(protectedHeader) { + if (this._protectedHeader) { + throw new TypeError('setProtectedHeader can only be called once'); + } + this._protectedHeader = protectedHeader; + return this; + } + setUnprotectedHeader(unprotectedHeader) { + if (this._unprotectedHeader) { + throw new TypeError('setUnprotectedHeader can only be called once'); + } + this._unprotectedHeader = unprotectedHeader; + return this; + } + set _protectedHeader(value) { + signatureRef.get(this).protectedHeader = value; + } + get _protectedHeader() { + return signatureRef.get(this).protectedHeader; + } + set _unprotectedHeader(value) { + signatureRef.get(this).unprotectedHeader = value; + } + get _unprotectedHeader() { + return signatureRef.get(this).unprotectedHeader; + } +} +class GeneralSign { + constructor(payload) { + this._signatures = []; + this._payload = payload; + } + addSignature(key, options) { + const signature = new IndividualSignature(); + signatureRef.set(signature, { key, options }); + this._signatures.push(signature); + return signature; + } + async sign() { + if (!this._signatures.length) { + throw new JWSInvalid('at least one signature must be added'); + } + const jws = { + signatures: [], + payload: '', + }; + let payloads = new Set(); + await Promise.all(this._signatures.map(async (sig) => { + const { protectedHeader, unprotectedHeader, options, key } = signatureRef.get(sig); + const flattened = new FlattenedSign(this._payload); + if (protectedHeader) { + flattened.setProtectedHeader(protectedHeader); + } + if (unprotectedHeader) { + flattened.setUnprotectedHeader(unprotectedHeader); + } + const { payload, ...rest } = await flattened.sign(key, options); + payloads.add(payload); + jws.payload = payload; + jws.signatures.push(rest); + })); + if (payloads.size !== 1) { + throw new JWSInvalid('inconsistent use of JWS Unencoded Payload Option (RFC7797)'); + } + return jws; + } +} +export { GeneralSign }; +export default GeneralSign; diff --git a/dist/node/esm/jws/general/verify.js b/dist/node/esm/jws/general/verify.js new file mode 100644 index 0000000000..1b97eecadd --- /dev/null +++ b/dist/node/esm/jws/general/verify.js @@ -0,0 +1,26 @@ +import verify from '../flattened/verify.js'; +import { JWSInvalid, JWSSignatureVerificationFailed } from '../../util/errors.js'; +import isObject from '../../lib/is_object.js'; +async function generalVerify(jws, key, options) { + if (!isObject(jws)) { + throw new JWSInvalid('General JWS must be an object'); + } + if (!Array.isArray(jws.signatures) || !jws.signatures.every(isObject)) { + throw new JWSInvalid('JWS Signatures missing or incorrect type'); + } + for (const signature of jws.signatures) { + try { + return await verify({ + header: signature.header, + payload: jws.payload, + protected: signature.protected, + signature: signature.signature, + }, key, options); + } + catch { + } + } + throw new JWSSignatureVerificationFailed(); +} +export { generalVerify }; +export default generalVerify; diff --git a/dist/node/esm/jwt/decrypt.js b/dist/node/esm/jwt/decrypt.js new file mode 100644 index 0000000000..ed1b4286c5 --- /dev/null +++ b/dist/node/esm/jwt/decrypt.js @@ -0,0 +1,21 @@ +import decrypt from '../jwe/compact/decrypt.js'; +import jwtPayload from '../lib/jwt_claims_set.js'; +import { JWTClaimValidationFailed } from '../util/errors.js'; +async function jwtDecrypt(jwt, key, options) { + const decrypted = await decrypt(jwt, key, options); + const payload = jwtPayload(decrypted.protectedHeader, decrypted.plaintext, options); + const { protectedHeader } = decrypted; + if (protectedHeader.iss !== undefined && protectedHeader.iss !== payload.iss) { + throw new JWTClaimValidationFailed('replicated "iss" claim header parameter mismatch', 'iss', 'mismatch'); + } + if (protectedHeader.sub !== undefined && protectedHeader.sub !== payload.sub) { + throw new JWTClaimValidationFailed('replicated "sub" claim header parameter mismatch', 'sub', 'mismatch'); + } + if (protectedHeader.aud !== undefined && + JSON.stringify(protectedHeader.aud) !== JSON.stringify(payload.aud)) { + throw new JWTClaimValidationFailed('replicated "aud" claim header parameter mismatch', 'aud', 'mismatch'); + } + return { payload, protectedHeader }; +} +export { jwtDecrypt }; +export default jwtDecrypt; diff --git a/dist/node/esm/jwt/encrypt.js b/dist/node/esm/jwt/encrypt.js new file mode 100644 index 0000000000..ef8ac9156f --- /dev/null +++ b/dist/node/esm/jwt/encrypt.js @@ -0,0 +1,70 @@ +import CompactEncrypt from '../jwe/compact/encrypt.js'; +import { encoder } from '../lib/buffer_utils.js'; +import ProduceJWT from '../lib/jwt_producer.js'; +class EncryptJWT extends ProduceJWT { + setProtectedHeader(protectedHeader) { + if (this._protectedHeader) { + throw new TypeError('setProtectedHeader can only be called once'); + } + this._protectedHeader = protectedHeader; + return this; + } + setKeyManagementParameters(parameters) { + if (this._keyManagementParameters) { + throw new TypeError('setKeyManagementParameters can only be called once'); + } + this._keyManagementParameters = parameters; + return this; + } + setContentEncryptionKey(cek) { + if (this._cek) { + throw new TypeError('setContentEncryptionKey can only be called once'); + } + this._cek = cek; + return this; + } + setInitializationVector(iv) { + if (this._iv) { + throw new TypeError('setInitializationVector can only be called once'); + } + this._iv = iv; + return this; + } + replicateIssuerAsHeader() { + this._replicateIssuerAsHeader = true; + return this; + } + replicateSubjectAsHeader() { + this._replicateSubjectAsHeader = true; + return this; + } + replicateAudienceAsHeader() { + this._replicateAudienceAsHeader = true; + return this; + } + async encrypt(key, options) { + 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 { EncryptJWT }; +export default EncryptJWT; diff --git a/dist/node/esm/jwt/sign.js b/dist/node/esm/jwt/sign.js new file mode 100644 index 0000000000..0707f7ebf7 --- /dev/null +++ b/dist/node/esm/jwt/sign.js @@ -0,0 +1,23 @@ +import CompactSign from '../jws/compact/sign.js'; +import { JWTInvalid } from '../util/errors.js'; +import { encoder } from '../lib/buffer_utils.js'; +import ProduceJWT from '../lib/jwt_producer.js'; +class SignJWT extends ProduceJWT { + setProtectedHeader(protectedHeader) { + this._protectedHeader = protectedHeader; + return this; + } + async sign(key, options) { + var _a; + const sig = new CompactSign(encoder.encode(JSON.stringify(this._payload))); + sig.setProtectedHeader(this._protectedHeader); + if (Array.isArray((_a = this._protectedHeader) === null || _a === void 0 ? void 0 : _a.crit) && + this._protectedHeader.crit.includes('b64') && + this._protectedHeader.b64 === false) { + throw new JWTInvalid('JWTs MUST NOT use unencoded payload'); + } + return sig.sign(key, options); + } +} +export { SignJWT }; +export default SignJWT; diff --git a/dist/node/esm/jwt/unsecured.js b/dist/node/esm/jwt/unsecured.js new file mode 100644 index 0000000000..0d3177ccec --- /dev/null +++ b/dist/node/esm/jwt/unsecured.js @@ -0,0 +1,34 @@ +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'; +class UnsecuredJWT extends ProduceJWT { + encode() { + const header = base64url.encode(JSON.stringify({ alg: 'none' })); + const payload = base64url.encode(JSON.stringify(this._payload)); + return `${header}.${payload}.`; + } + static decode(jwt, options) { + 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; + 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 { UnsecuredJWT }; +export default UnsecuredJWT; diff --git a/dist/node/esm/jwt/verify.js b/dist/node/esm/jwt/verify.js new file mode 100644 index 0000000000..2295d81306 --- /dev/null +++ b/dist/node/esm/jwt/verify.js @@ -0,0 +1,14 @@ +import verify from '../jws/compact/verify.js'; +import jwtPayload from '../lib/jwt_claims_set.js'; +import { JWTInvalid } from '../util/errors.js'; +async function jwtVerify(jwt, key, options) { + var _a; + const verified = await verify(jwt, key, options); + if (((_a = verified.protectedHeader.crit) === null || _a === void 0 ? void 0 : _a.includes('b64')) && verified.protectedHeader.b64 === false) { + throw new JWTInvalid('JWTs MUST NOT use unencoded payload'); + } + const payload = jwtPayload(verified.protectedHeader, verified.payload, options); + return { payload, protectedHeader: verified.protectedHeader }; +} +export { jwtVerify }; +export default jwtVerify; diff --git a/dist/node/esm/lib/buffer_utils.js b/dist/node/esm/lib/buffer_utils.js new file mode 100644 index 0000000000..d9392a633d --- /dev/null +++ b/dist/node/esm/lib/buffer_utils.js @@ -0,0 +1,56 @@ +export const encoder = new TextEncoder(); +export const decoder = new TextDecoder(); +const MAX_INT32 = 2 ** 32; +export function concat(...buffers) { + 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, p2sInput) { + return concat(encoder.encode(alg), new Uint8Array([0]), p2sInput); +} +function writeUInt32BE(buf, value, offset) { + 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) { + 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) { + const buf = new Uint8Array(4); + writeUInt32BE(buf, value); + return buf; +} +export function lengthAndInput(input) { + return concat(uint32be(input.length), input); +} +export async function concatKdf(digest, secret, bits, value) { + const iterations = Math.ceil((bits >> 3) / 32); + let res; + 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('sha256', buf); + } + else { + res = concat(res, await digest('sha256', buf)); + } + } + res = res.slice(0, bits >> 3); + return res; +} diff --git a/dist/node/esm/lib/cek.js b/dist/node/esm/lib/cek.js new file mode 100644 index 0000000000..702d8a0533 --- /dev/null +++ b/dist/node/esm/lib/cek.js @@ -0,0 +1,18 @@ +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) => (alg) => { + 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/dist/node/esm/lib/check_iv_length.js b/dist/node/esm/lib/check_iv_length.js new file mode 100644 index 0000000000..3bb1ecb38a --- /dev/null +++ b/dist/node/esm/lib/check_iv_length.js @@ -0,0 +1,8 @@ +import { JWEInvalid } from '../util/errors.js'; +import { bitLengths } from './iv.js'; +const checkIvLength = (enc, iv) => { + if (iv.length << 3 !== bitLengths.get(enc)) { + throw new JWEInvalid('Invalid Initialization Vector length'); + } +}; +export default checkIvLength; diff --git a/dist/node/esm/lib/check_key_type.js b/dist/node/esm/lib/check_key_type.js new file mode 100644 index 0000000000..4702e55436 --- /dev/null +++ b/dist/node/esm/lib/check_key_type.js @@ -0,0 +1,28 @@ +import invalidKeyInput from '../runtime/invalid_key_input.js'; +const checkKeyType = (alg, key, usage) => { + if (!(key instanceof Uint8Array) && !(key === null || key === void 0 ? void 0 : key.type)) { + throw new TypeError(invalidKeyInput(key, 'KeyObject', 'CryptoKey', 'Uint8Array')); + } + 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(invalidKeyInput(key, 'KeyObject', 'CryptoKey')); + } + if (key.type === 'secret') { + throw new TypeError('CryptoKey or KeyObject instances for asymmetric algorithms must not be of type "secret"'); + } + if (usage === 'sign' && key.type === 'public') { + throw new TypeError('CryptoKey or KeyObject instances for asymmetric algorithm signing must be of type "private"'); + } + if (usage === 'decrypt' && key.type === 'public') { + throw new TypeError('CryptoKey or KeyObject instances for asymmetric algorithm decryption must be of type "private"'); + } +}; +export default checkKeyType; diff --git a/dist/node/esm/lib/check_p2s.js b/dist/node/esm/lib/check_p2s.js new file mode 100644 index 0000000000..a65289fa7a --- /dev/null +++ b/dist/node/esm/lib/check_p2s.js @@ -0,0 +1,6 @@ +import { JWEInvalid } from '../util/errors.js'; +export default function checkP2s(p2s) { + if (!(p2s instanceof Uint8Array) || p2s.length < 8) { + throw new JWEInvalid('PBES2 Salt Input must be 8 or more octets'); + } +} diff --git a/dist/node/esm/lib/decrypt_key_management.js b/dist/node/esm/lib/decrypt_key_management.js new file mode 100644 index 0000000000..d82f5c100f --- /dev/null +++ b/dist/node/esm/lib/decrypt_key_management.js @@ -0,0 +1,95 @@ +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'; +import { parseJwk } from '../jwk/parse.js'; +import checkKeyType from './check_key_type.js'; +function assertEnryptedKey(encryptedKey) { + if (!encryptedKey) { + throw new JWEInvalid('JWE Encrypted Key missing'); + } +} +function assertHeaderParameter(joseHeader, parameter, name) { + if (joseHeader[parameter] === undefined) { + throw new JWEInvalid(`JOSE Header ${name} (${parameter}) missing`); + } +} +async function decryptKeyManagement(alg, key, encryptedKey, joseHeader) { + checkKeyType(alg, key, 'decrypt'); + switch (alg) { + case 'dir': { + if (encryptedKey !== undefined) { + throw new JWEInvalid('Encountered unexpected JWE Encrypted Key'); + } + return key; + } + case 'ECDH-ES': + if (encryptedKey !== undefined) { + throw new JWEInvalid('Encountered unexpected JWE Encrypted Key'); + } + case 'ECDH-ES+A128KW': + case 'ECDH-ES+A192KW': + case 'ECDH-ES+A256KW': { + assertHeaderParameter(joseHeader, 'epk', 'Ephemeral Public Key'); + if (!ECDH.ecdhAllowed(key)) { + throw new JOSENotSupported('ECDH-ES with the provided key is not allowed or not supported by your javascript runtime'); + } + const epk = await parseJwk(joseHeader.epk, alg); + let partyUInfo; + let partyVInfo; + if (joseHeader.apu !== undefined) + partyUInfo = base64url(joseHeader.apu); + if (joseHeader.apv !== undefined) + partyVInfo = base64url(joseHeader.apv); + const sharedSecret = await ECDH.deriveKey(epk, key, alg === 'ECDH-ES' ? joseHeader.enc : alg, parseInt(alg.substr(-5, 3), 10) || cekLengths.get(joseHeader.enc), partyUInfo, partyVInfo); + if (alg === 'ECDH-ES') { + return sharedSecret; + } + 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': { + assertEnryptedKey(encryptedKey); + return rsaEs(alg, key, encryptedKey); + } + case 'PBES2-HS256+A128KW': + case 'PBES2-HS384+A192KW': + case 'PBES2-HS512+A256KW': { + 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': { + assertEnryptedKey(encryptedKey); + return aesKw(alg, key, encryptedKey); + } + case 'A128GCMKW': + case 'A192GCMKW': + case 'A256GCMKW': { + 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('unsupported or invalid "alg" (JWE Algorithm) header value'); + } + } +} +export default decryptKeyManagement; diff --git a/dist/node/esm/lib/encrypt_key_management.js b/dist/node/esm/lib/encrypt_key_management.js new file mode 100644 index 0000000000..97199e204e --- /dev/null +++ b/dist/node/esm/lib/encrypt_key_management.js @@ -0,0 +1,87 @@ +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'; +import { fromKeyLike } from '../jwk/from_key_like.js'; +import checkKeyType from './check_key_type.js'; +const generateCek = cekFactory(random); +async function encryptKeyManagement(alg, enc, key, providedCek, providedParameters = {}) { + let encryptedKey; + let parameters; + let cek; + checkKeyType(alg, key, 'encrypt'); + switch (alg) { + case 'dir': { + cek = key; + break; + } + case 'ECDH-ES': + case 'ECDH-ES+A128KW': + case 'ECDH-ES+A192KW': + case 'ECDH-ES+A256KW': { + if (!ECDH.ecdhAllowed(key)) { + throw new JOSENotSupported('ECDH-ES with the provided key is not allowed or not supported by your javascript runtime'); + } + const { apu, apv } = providedParameters; + let { epk: ephemeralKey } = providedParameters; + ephemeralKey || (ephemeralKey = await ECDH.generateEpk(key)); + const { x, y, crv, kty } = await fromKeyLike(ephemeralKey); + const sharedSecret = await ECDH.deriveKey(key, ephemeralKey, alg === 'ECDH-ES' ? enc : alg, parseInt(alg.substr(-5, 3), 10) || cekLengths.get(enc), apu, apv); + parameters = { epk: { x, y, crv, kty } }; + if (apu) + parameters.apu = base64url(apu); + if (apv) + parameters.apv = base64url(apv); + if (alg === 'ECDH-ES') { + cek = sharedSecret; + break; + } + cek = providedCek || 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': { + cek = providedCek || generateCek(enc); + encryptedKey = await rsaEs(alg, key, cek); + break; + } + case 'PBES2-HS256+A128KW': + case 'PBES2-HS384+A192KW': + case 'PBES2-HS512+A256KW': { + cek = providedCek || generateCek(enc); + const { p2c, p2s } = providedParameters; + ({ encryptedKey, ...parameters } = await pbes2Kw(alg, key, cek, p2c, p2s)); + break; + } + case 'A128KW': + case 'A192KW': + case 'A256KW': { + cek = providedCek || generateCek(enc); + encryptedKey = await aesKw(alg, key, cek); + break; + } + case 'A128GCMKW': + case 'A192GCMKW': + case 'A256GCMKW': { + cek = providedCek || generateCek(enc); + const { iv } = providedParameters; + ({ encryptedKey, ...parameters } = await aesGcmKw(alg, key, cek, iv)); + break; + } + default: { + throw new JOSENotSupported('unsupported or invalid "alg" (JWE Algorithm) header value'); + } + } + return { cek, encryptedKey, parameters }; +} +export default encryptKeyManagement; diff --git a/dist/node/esm/lib/epoch.js b/dist/node/esm/lib/epoch.js new file mode 100644 index 0000000000..e405e4b2df --- /dev/null +++ b/dist/node/esm/lib/epoch.js @@ -0,0 +1 @@ +export default (date) => Math.floor(date.getTime() / 1000); diff --git a/dist/node/esm/lib/is_disjoint.js b/dist/node/esm/lib/is_disjoint.js new file mode 100644 index 0000000000..6f643502dc --- /dev/null +++ b/dist/node/esm/lib/is_disjoint.js @@ -0,0 +1,22 @@ +const isDisjoint = (...headers) => { + const sources = headers.filter(Boolean); + if (sources.length === 0 || sources.length === 1) { + return true; + } + let acc; + 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/dist/node/esm/lib/is_object.js b/dist/node/esm/lib/is_object.js new file mode 100644 index 0000000000..4955e93225 --- /dev/null +++ b/dist/node/esm/lib/is_object.js @@ -0,0 +1,16 @@ +function isObjectLike(value) { + return typeof value === 'object' && value !== null; +} +export default function isObject(input) { + if (!isObjectLike(input) || Object.prototype.toString.call(input) !== '[object Object]') { + return false; + } + if (Object.getPrototypeOf(input) === null) { + return true; + } + let proto = input; + while (Object.getPrototypeOf(proto) !== null) { + proto = Object.getPrototypeOf(proto); + } + return Object.getPrototypeOf(input) === proto; +} diff --git a/dist/node/esm/lib/iv.js b/dist/node/esm/lib/iv.js new file mode 100644 index 0000000000..d254aa16dc --- /dev/null +++ b/dist/node/esm/lib/iv.js @@ -0,0 +1,21 @@ +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) => (alg) => { + 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/dist/node/esm/lib/jwt_claims_set.js b/dist/node/esm/lib/jwt_claims_set.js new file mode 100644 index 0000000000..48eb897b77 --- /dev/null +++ b/dist/node/esm/lib/jwt_claims_set.js @@ -0,0 +1,96 @@ +import { JWTClaimValidationFailed, JWTExpired, JWTInvalid } from '../util/errors.js'; +import { decoder } from './buffer_utils.js'; +import epoch from './epoch.js'; +import secs from './secs.js'; +import isObject from './is_object.js'; +const normalizeTyp = (value) => value.toLowerCase().replace(/^application\//, ''); +const checkAudiencePresence = (audPayload, audOption) => { + if (typeof audPayload === 'string') { + return audOption.includes(audPayload); + } + if (Array.isArray(audPayload)) { + return audOption.some(Set.prototype.has.bind(new Set(audPayload))); + } + return false; +}; +export default (protectedHeader, encodedPayload, options = {}) => { + 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; + try { + payload = JSON.parse(decoder.decode(encodedPayload)); + } + catch { + } + if (!isObject(payload)) { + throw new JWTInvalid('JWT Claims Set must be a top-level JSON object'); + } + const { issuer } = options; + if (issuer && !(Array.isArray(issuer) ? 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; + 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 (payload.iat !== undefined || options.maxTokenAge) { + if (typeof payload.iat !== 'number') { + throw new JWTClaimValidationFailed('"iat" claim must be a number', 'iat', 'invalid'); + } + if (payload.exp === undefined && payload.iat > now + tolerance) { + throw new JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', 'iat', 'check_failed'); + } + } + if (payload.nbf !== undefined) { + 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 (payload.exp !== undefined) { + 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/dist/node/esm/lib/jwt_producer.js b/dist/node/esm/lib/jwt_producer.js new file mode 100644 index 0000000000..e6b047337c --- /dev/null +++ b/dist/node/esm/lib/jwt_producer.js @@ -0,0 +1,54 @@ +import epoch from './epoch.js'; +import isObject from './is_object.js'; +import secs from './secs.js'; +export default class ProduceJWT { + constructor(payload) { + if (!isObject(payload)) { + throw new TypeError('JWT Claims Set MUST be an object'); + } + this._payload = payload; + } + setIssuer(issuer) { + this._payload = { ...this._payload, iss: issuer }; + return this; + } + setSubject(subject) { + this._payload = { ...this._payload, sub: subject }; + return this; + } + setAudience(audience) { + this._payload = { ...this._payload, aud: audience }; + return this; + } + setJti(jwtId) { + this._payload = { ...this._payload, jti: jwtId }; + return this; + } + setNotBefore(input) { + if (typeof input === 'number') { + this._payload = { ...this._payload, nbf: input }; + } + else { + this._payload = { ...this._payload, nbf: epoch(new Date()) + secs(input) }; + } + return this; + } + setExpirationTime(input) { + if (typeof input === 'number') { + this._payload = { ...this._payload, exp: input }; + } + else { + this._payload = { ...this._payload, exp: epoch(new Date()) + secs(input) }; + } + return this; + } + setIssuedAt(input) { + if (typeof input === 'undefined') { + this._payload = { ...this._payload, iat: epoch(new Date()) }; + } + else { + this._payload = { ...this._payload, iat: input }; + } + return this; + } +} diff --git a/dist/node/esm/lib/secs.js b/dist/node/esm/lib/secs.js new file mode 100644 index 0000000000..cf470ed8ad --- /dev/null +++ b/dist/node/esm/lib/secs.js @@ -0,0 +1,44 @@ +const minute = 60; +const hour = minute * 60; +const day = hour * 24; +const week = day * 7; +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; +export default (str) => { + const matched = REGEX.exec(str); + if (!matched) { + throw new TypeError('Invalid time period format'); + } + const value = parseFloat(matched[1]); + const unit = matched[2].toLowerCase(); + switch (unit) { + case 'sec': + case 'secs': + case 'second': + case 'seconds': + case 's': + return Math.round(value); + case 'minute': + case 'minutes': + case 'min': + case 'mins': + case 'm': + return Math.round(value * minute); + case 'hour': + case 'hours': + case 'hr': + case 'hrs': + case 'h': + return Math.round(value * hour); + case 'day': + case 'days': + case 'd': + return Math.round(value * day); + case 'week': + case 'weeks': + case 'w': + return Math.round(value * week); + default: + return Math.round(value * year); + } +}; diff --git a/dist/node/esm/lib/validate_algorithms.js b/dist/node/esm/lib/validate_algorithms.js new file mode 100644 index 0000000000..a6a7918571 --- /dev/null +++ b/dist/node/esm/lib/validate_algorithms.js @@ -0,0 +1,11 @@ +const validateAlgorithms = (option, algorithms) => { + 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/dist/node/esm/lib/validate_crit.js b/dist/node/esm/lib/validate_crit.js new file mode 100644 index 0000000000..68c69f18f5 --- /dev/null +++ b/dist/node/esm/lib/validate_crit.js @@ -0,0 +1,34 @@ +import { JOSENotSupported } from '../util/errors.js'; +function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) { + if (joseHeader.crit !== undefined && protectedHeader.crit === undefined) { + throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected'); + } + if (!protectedHeader || protectedHeader.crit === undefined) { + return new Set(); + } + if (!Array.isArray(protectedHeader.crit) || + protectedHeader.crit.length === 0 || + protectedHeader.crit.some((input) => typeof input !== 'string' || input.length === 0)) { + throw new Err('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present'); + } + let recognized; + if (recognizedOption !== undefined) { + recognized = new Map([...Object.entries(recognizedOption), ...recognizedDefault.entries()]); + } + else { + recognized = recognizedDefault; + } + for (const parameter of protectedHeader.crit) { + if (!recognized.has(parameter)) { + throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`); + } + if (joseHeader[parameter] === undefined) { + throw new Err(`Extension Header Parameter "${parameter}" is missing`); + } + else if (recognized.get(parameter) && protectedHeader[parameter] === undefined) { + throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`); + } + } + return new Set(protectedHeader.crit); +} +export default validateCrit; diff --git a/dist/node/esm/package.json b/dist/node/esm/package.json new file mode 100644 index 0000000000..6990891ff3 --- /dev/null +++ b/dist/node/esm/package.json @@ -0,0 +1 @@ +{"type": "module"} diff --git a/dist/node/esm/runtime/aesgcmkw.js b/dist/node/esm/runtime/aesgcmkw.js new file mode 100644 index 0000000000..5fd5acc5b2 --- /dev/null +++ b/dist/node/esm/runtime/aesgcmkw.js @@ -0,0 +1,16 @@ +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 = async (alg, key, cek, iv) => { + const jweAlgorithm = alg.substr(0, 7); + iv || (iv = generateIv(jweAlgorithm)); + const { ciphertext: encryptedKey, tag } = await encrypt(jweAlgorithm, cek, key, iv, new Uint8Array(0)); + return { encryptedKey, iv: base64url(iv), tag: base64url(tag) }; +}; +export const unwrap = async (alg, key, encryptedKey, iv, tag) => { + const jweAlgorithm = alg.substr(0, 7); + return decrypt(jweAlgorithm, key, encryptedKey, iv, tag, new Uint8Array(0)); +}; diff --git a/dist/node/esm/runtime/aeskw.js b/dist/node/esm/runtime/aeskw.js new file mode 100644 index 0000000000..b3c7a0649e --- /dev/null +++ b/dist/node/esm/runtime/aeskw.js @@ -0,0 +1,47 @@ +import { createDecipheriv, createCipheriv } from 'crypto'; +import { JOSENotSupported } from '../util/errors.js'; +import { concat } from '../lib/buffer_utils.js'; +import getSecretKey from './secret_key.js'; +import { isCryptoKey, getKeyObject } from './webcrypto.js'; +import isKeyObject from './is_key_object.js'; +import invalidKeyInput from './invalid_key_input.js'; +import supported from './ciphers.js'; +function checkKeySize(key, alg) { + if (key.symmetricKeySize << 3 !== parseInt(alg.substr(1, 3), 10)) { + throw new TypeError(`invalid key size for alg: ${alg}`); + } +} +function ensureKeyObject(key, alg, usage) { + if (isKeyObject(key)) { + return key; + } + if (key instanceof Uint8Array) { + return getSecretKey(key); + } + if (isCryptoKey(key)) { + return getKeyObject(key, alg, new Set([usage])); + } + throw new TypeError(invalidKeyInput(key, 'KeyObject', 'CryptoKey', 'Uint8Array')); +} +export const wrap = async (alg, key, cek) => { + const size = parseInt(alg.substr(1, 3), 10); + const algorithm = `aes${size}-wrap`; + if (!supported(algorithm)) { + throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`); + } + const keyObject = ensureKeyObject(key, alg, 'wrapKey'); + checkKeySize(keyObject, alg); + const cipher = createCipheriv(algorithm, keyObject, Buffer.alloc(8, 0xa6)); + return concat(cipher.update(cek), cipher.final()); +}; +export const unwrap = async (alg, key, encryptedKey) => { + const size = parseInt(alg.substr(1, 3), 10); + const algorithm = `aes${size}-wrap`; + if (!supported(algorithm)) { + throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`); + } + const keyObject = ensureKeyObject(key, alg, 'unwrapKey'); + checkKeySize(keyObject, alg); + const cipher = createDecipheriv(algorithm, keyObject, Buffer.alloc(8, 0xa6)); + return concat(cipher.update(encryptedKey), cipher.final()); +}; diff --git a/dist/node/esm/runtime/asn1_sequence_decoder.js b/dist/node/esm/runtime/asn1_sequence_decoder.js new file mode 100644 index 0000000000..61ba4c3116 --- /dev/null +++ b/dist/node/esm/runtime/asn1_sequence_decoder.js @@ -0,0 +1,44 @@ +const tagInteger = 0x02; +const tagSequence = 0x30; +export default class Asn1SequenceDecoder { + constructor(buffer) { + if (buffer[0] !== tagSequence) { + throw new TypeError(); + } + this.buffer = buffer; + this.offset = 1; + const len = this.decodeLength(); + if (len !== buffer.length - this.offset) { + throw new TypeError(); + } + } + decodeLength() { + let length = this.buffer[this.offset++]; + if (length & 0x80) { + const nBytes = length & ~0x80; + length = 0; + for (let i = 0; i < nBytes; i++) + length = (length << 8) | this.buffer[this.offset + i]; + this.offset += nBytes; + } + return length; + } + unsignedInteger() { + if (this.buffer[this.offset++] !== tagInteger) { + throw new TypeError(); + } + let length = this.decodeLength(); + if (this.buffer[this.offset] === 0) { + this.offset++; + length--; + } + const result = this.buffer.slice(this.offset, this.offset + length); + this.offset += length; + return result; + } + end() { + if (this.offset !== this.buffer.length) { + throw new TypeError(); + } + } +} diff --git a/dist/node/esm/runtime/asn1_sequence_encoder.js b/dist/node/esm/runtime/asn1_sequence_encoder.js new file mode 100644 index 0000000000..e2bf458fba --- /dev/null +++ b/dist/node/esm/runtime/asn1_sequence_encoder.js @@ -0,0 +1,87 @@ +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) => { + 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')], +]); +export default class DumbAsn1Encoder { + constructor() { + this.length = 0; + this.elements = []; + } + oidFor(oid) { + 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) { + 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) { + const len = encodeLength(octStr.length); + this.elements.push(bTagOctStr, encodeLength(octStr.length), octStr); + this.length += 1 + len.length + octStr.length; + } + bitStr(bitS) { + 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) { + 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/dist/node/esm/runtime/base64url.js b/dist/node/esm/runtime/base64url.js new file mode 100644 index 0000000000..b92ccb4212 --- /dev/null +++ b/dist/node/esm/runtime/base64url.js @@ -0,0 +1,17 @@ +import { decoder } from '../lib/buffer_utils.js'; +let encodeImpl; +function normalize(input) { + let encoded = input; + if (encoded instanceof Uint8Array) { + encoded = decoder.decode(encoded); + } + return encoded; +} +if (Buffer.isEncoding('base64url')) { + encodeImpl = (input) => Buffer.from(input).toString('base64url'); +} +else { + encodeImpl = (input) => Buffer.from(input).toString('base64').replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_'); +} +export const encode = encodeImpl; +export const decode = (input) => Buffer.from(normalize(input), 'base64'); diff --git a/dist/node/esm/runtime/cbc_tag.js b/dist/node/esm/runtime/cbc_tag.js new file mode 100644 index 0000000000..fa58c38b6c --- /dev/null +++ b/dist/node/esm/runtime/cbc_tag.js @@ -0,0 +1,8 @@ +import { createHmac } from 'crypto'; +import { concat, uint64be } from '../lib/buffer_utils.js'; +export default function cbcTag(aad, iv, ciphertext, macSize, macKey, keySize) { + 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/dist/node/esm/runtime/check_cek_length.js b/dist/node/esm/runtime/check_cek_length.js new file mode 100644 index 0000000000..a547578729 --- /dev/null +++ b/dist/node/esm/runtime/check_cek_length.js @@ -0,0 +1,33 @@ +import { JWEInvalid, JOSENotSupported } from '../util/errors.js'; +import isKeyObject from './is_key_object.js'; +const checkCekLength = (enc, cek) => { + let expected; + 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 not supported 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 (isKeyObject(cek) && 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/dist/node/esm/runtime/check_modulus_length.js b/dist/node/esm/runtime/check_modulus_length.js new file mode 100644 index 0000000000..690f809602 --- /dev/null +++ b/dist/node/esm/runtime/check_modulus_length.js @@ -0,0 +1,48 @@ +export const weakMap = new WeakMap(); +const getLength = (buf, index) => { + let len = buf.readUInt8(1); + if ((len & 0x80) === 0) { + if (index === 0) { + return len; + } + return getLength(buf.subarray(2 + len), index - 1); + } + 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, index) => { + const len = sequence.readUInt8(1); + if ((len & 0x80) === 0) { + return getLength(sequence.subarray(2), index); + } + const num = len & 0x7f; + return getLength(sequence.subarray(2 + num), index); +}; +const getModulusLength = (key) => { + var _a, _b; + if (weakMap.has(key)) { + return weakMap.get(key); + } + const modulusLength = (_b = (_a = key.asymmetricKeyDetails) === null || _a === void 0 ? void 0 : _a.modulusLength) !== null && _b !== void 0 ? _b : (getLengthOfSeqIndex(key.export({ format: 'der', type: 'pkcs1' }), key.type === 'private' ? 1 : 0) - + 1) << + 3; + weakMap.set(key, modulusLength); + return modulusLength; +}; +export const setModulusLength = (keyObject, modulusLength) => { + weakMap.set(keyObject, modulusLength); +}; +export default (key, alg) => { + if (getModulusLength(key) < 2048) { + throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`); + } +}; diff --git a/dist/node/esm/runtime/ciphers.js b/dist/node/esm/runtime/ciphers.js new file mode 100644 index 0000000000..daded1d503 --- /dev/null +++ b/dist/node/esm/runtime/ciphers.js @@ -0,0 +1,6 @@ +import { getCiphers } from 'crypto'; +let ciphers; +export default (algorithm) => { + ciphers || (ciphers = new Set(getCiphers())); + return ciphers.has(algorithm); +}; diff --git a/dist/node/esm/runtime/decrypt.js b/dist/node/esm/runtime/decrypt.js new file mode 100644 index 0000000000..f65703f089 --- /dev/null +++ b/dist/node/esm/runtime/decrypt.js @@ -0,0 +1,90 @@ +import { createDecipheriv } from 'crypto'; +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'; +import { isCryptoKey, getKeyObject } from './webcrypto.js'; +import isKeyObject from './is_key_object.js'; +import invalidKeyInput from './invalid_key_input.js'; +import supported from './ciphers.js'; +async function cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) { + const keySize = parseInt(enc.substr(1, 3), 10); + if (isKeyObject(cek)) { + cek = cek.export(); + } + const encKey = cek.subarray(keySize >> 3); + const macKey = cek.subarray(0, keySize >> 3); + const macSize = parseInt(enc.substr(-3), 10); + const algorithm = `aes-${keySize}-cbc`; + if (!supported(algorithm)) { + throw new JOSENotSupported(`alg ${enc} is not supported by your javascript runtime`); + } + const expectedTag = cbcTag(aad, iv, ciphertext, macSize, macKey, keySize); + let macCheckPassed; + try { + macCheckPassed = timingSafeEqual(tag, expectedTag); + } + catch { + } + if (!macCheckPassed) { + throw new JWEDecryptionFailed(); + } + let plaintext; + try { + const cipher = createDecipheriv(algorithm, encKey, iv); + plaintext = concat(cipher.update(ciphertext), cipher.final()); + } + catch { + } + if (!plaintext) { + throw new JWEDecryptionFailed(); + } + return plaintext; +} +async function gcmDecrypt(enc, cek, ciphertext, iv, tag, aad) { + const keySize = parseInt(enc.substr(1, 3), 10); + const algorithm = `aes-${keySize}-gcm`; + if (!supported(algorithm)) { + throw new JOSENotSupported(`alg ${enc} is not supported by your javascript runtime`); + } + try { + const cipher = createDecipheriv(algorithm, cek, iv, { authTagLength: 16 }); + cipher.setAuthTag(tag); + if (aad.byteLength) { + cipher.setAAD(aad, { plaintextLength: ciphertext.length }); + } + return concat(cipher.update(ciphertext), cipher.final()); + } + catch { + throw new JWEDecryptionFailed(); + } +} +const decrypt = async (enc, cek, ciphertext, iv, tag, aad) => { + let key; + if (isCryptoKey(cek)) { + key = getKeyObject(cek, enc, new Set(['decrypt'])); + } + else if (cek instanceof Uint8Array || isKeyObject(cek)) { + key = cek; + } + else { + throw new TypeError(invalidKeyInput(cek, 'KeyObject', 'CryptoKey', 'Uint8Array')); + } + checkCekLength(enc, key); + checkIvLength(enc, iv); + switch (enc) { + case 'A128CBC-HS256': + case 'A192CBC-HS384': + case 'A256CBC-HS512': + return cbcDecrypt(enc, key, ciphertext, iv, tag, aad); + case 'A128GCM': + case 'A192GCM': + case 'A256GCM': + return gcmDecrypt(enc, key, ciphertext, iv, tag, aad); + default: + throw new JOSENotSupported('unsupported JWE Content Encryption Algorithm'); + } +}; +export default decrypt; diff --git a/dist/node/esm/runtime/digest.js b/dist/node/esm/runtime/digest.js new file mode 100644 index 0000000000..0facde6c29 --- /dev/null +++ b/dist/node/esm/runtime/digest.js @@ -0,0 +1,3 @@ +import { createHash } from 'crypto'; +const digest = (algorithm, data) => createHash(algorithm).update(data).digest(); +export default digest; diff --git a/dist/node/esm/runtime/dsa_digest.js b/dist/node/esm/runtime/dsa_digest.js new file mode 100644 index 0000000000..ce7215bd67 --- /dev/null +++ b/dist/node/esm/runtime/dsa_digest.js @@ -0,0 +1,22 @@ +import { JOSENotSupported } from '../util/errors.js'; +export default function dsaDigest(alg) { + 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 not supported either by JOSE or your javascript runtime`); + } +} diff --git a/dist/node/esm/runtime/ecdhes.js b/dist/node/esm/runtime/ecdhes.js new file mode 100644 index 0000000000..d8f565878f --- /dev/null +++ b/dist/node/esm/runtime/ecdhes.js @@ -0,0 +1,49 @@ +import { diffieHellman, generateKeyPair as generateKeyPairCb } from 'crypto'; +import { promisify } from 'util'; +import getNamedCurve from './get_named_curve.js'; +import { encoder, concat, uint32be, lengthAndInput, concatKdf } from '../lib/buffer_utils.js'; +import digest from './digest.js'; +import { JOSENotSupported } from '../util/errors.js'; +import { isCryptoKey, getKeyObject } from './webcrypto.js'; +import isKeyObject from './is_key_object.js'; +import invalidKeyInput from './invalid_key_input.js'; +const generateKeyPair = promisify(generateKeyPairCb); +export const deriveKey = async (publicKey, privateKey, algorithm, keyLength, apu = new Uint8Array(0), apv = new Uint8Array(0)) => { + const value = concat(lengthAndInput(encoder.encode(algorithm)), lengthAndInput(apu), lengthAndInput(apv), uint32be(keyLength)); + if (isCryptoKey(publicKey)) { + publicKey = getKeyObject(publicKey, 'ECDH-ES'); + } + if (!isKeyObject(publicKey)) { + throw new TypeError(invalidKeyInput(publicKey, 'KeyObject', 'CryptoKey')); + } + if (isCryptoKey(privateKey)) { + privateKey = getKeyObject(privateKey, 'ECDH-ES', new Set(['deriveBits', 'deriveKey'])); + } + if (!isKeyObject(privateKey)) { + throw new TypeError(invalidKeyInput(privateKey, 'KeyObject', 'CryptoKey')); + } + const sharedSecret = diffieHellman({ privateKey, publicKey }); + return concatKdf(digest, sharedSecret, keyLength, value); +}; +export const generateEpk = async (key) => { + if (isCryptoKey(key)) { + key = getKeyObject(key); + } + if (!isKeyObject(key)) { + throw new TypeError(invalidKeyInput(key, 'KeyObject', 'CryptoKey')); + } + 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 ecdhAllowed = (key) => ['P-256', 'P-384', 'P-521', 'X25519', 'X448'].includes(getNamedCurve(key)); diff --git a/dist/node/esm/runtime/encrypt.js b/dist/node/esm/runtime/encrypt.js new file mode 100644 index 0000000000..4c526c1da6 --- /dev/null +++ b/dist/node/esm/runtime/encrypt.js @@ -0,0 +1,68 @@ +import { createCipheriv } from 'crypto'; +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'; +import { isCryptoKey, getKeyObject } from './webcrypto.js'; +import isKeyObject from './is_key_object.js'; +import invalidKeyInput from './invalid_key_input.js'; +import { JOSENotSupported } from '../util/errors.js'; +import supported from './ciphers.js'; +async function cbcEncrypt(enc, plaintext, cek, iv, aad) { + const keySize = parseInt(enc.substr(1, 3), 10); + if (isKeyObject(cek)) { + cek = cek.export(); + } + const encKey = cek.subarray(keySize >> 3); + const macKey = cek.subarray(0, keySize >> 3); + const algorithm = `aes-${keySize}-cbc`; + if (!supported(algorithm)) { + throw new JOSENotSupported(`alg ${enc} is not supported by your javascript runtime`); + } + 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, plaintext, cek, iv, aad) { + const keySize = parseInt(enc.substr(1, 3), 10); + const algorithm = `aes-${keySize}-gcm`; + if (!supported(algorithm)) { + throw new JOSENotSupported(`alg ${enc} is not supported by your javascript runtime`); + } + const cipher = createCipheriv(algorithm, cek, iv, { authTagLength: 16 }); + if (aad.byteLength) { + cipher.setAAD(aad, { plaintextLength: plaintext.length }); + } + const ciphertext = concat(cipher.update(plaintext), cipher.final()); + const tag = cipher.getAuthTag(); + return { ciphertext, tag }; +} +const encrypt = async (enc, plaintext, cek, iv, aad) => { + let key; + if (isCryptoKey(cek)) { + key = getKeyObject(cek, enc, new Set(['encrypt'])); + } + else if (cek instanceof Uint8Array || isKeyObject(cek)) { + key = cek; + } + else { + throw new TypeError(invalidKeyInput(cek, 'KeyObject', 'CryptoKey', 'Uint8Array')); + } + checkCekLength(enc, key); + checkIvLength(enc, iv); + switch (enc) { + case 'A128CBC-HS256': + case 'A192CBC-HS384': + case 'A256CBC-HS512': + return cbcEncrypt(enc, plaintext, key, iv, aad); + case 'A128GCM': + case 'A192GCM': + case 'A256GCM': + return gcmEncrypt(enc, plaintext, key, iv, aad); + default: + throw new JOSENotSupported('unsupported JWE Content Encryption Algorithm'); + } +}; +export default encrypt; diff --git a/dist/node/esm/runtime/fetch_jwks.js b/dist/node/esm/runtime/fetch_jwks.js new file mode 100644 index 0000000000..9d08245da6 --- /dev/null +++ b/dist/node/esm/runtime/fetch_jwks.js @@ -0,0 +1,34 @@ +import { get as http } from 'http'; +import { get as https } from 'https'; +import { once } from 'events'; +import { JOSEError } from '../util/errors.js'; +import { concat, decoder } from '../lib/buffer_utils.js'; +const protocols = { + 'https:': https, + 'http:': http, +}; +const fetchJwks = async (url, timeout, options) => { + if (protocols[url.protocol] === undefined) { + throw new TypeError('Unsupported URL protocol.'); + } + const { agent } = options; + const req = protocols[url.protocol](url.href, { + agent, + timeout, + }); + const [response] = await once(req, 'response'); + if (response.statusCode !== 200) { + throw new JOSEError('Expected 200 OK from the JSON Web Key Set HTTP response'); + } + const parts = []; + for await (const part of response) { + parts.push(part); + } + try { + return JSON.parse(decoder.decode(concat(...parts))); + } + catch { + throw new JOSEError('Failed to parse the JSON Web Key Set HTTP response as JSON'); + } +}; +export default fetchJwks; diff --git a/dist/node/esm/runtime/generate.js b/dist/node/esm/runtime/generate.js new file mode 100644 index 0000000000..19ce9c421d --- /dev/null +++ b/dist/node/esm/runtime/generate.js @@ -0,0 +1,99 @@ +import { createSecretKey, generateKeyPair as generateKeyPairCb } from 'crypto'; +import { promisify } from 'util'; +import random from './random.js'; +import { setModulusLength } from './check_modulus_length.js'; +import { JOSENotSupported } from '../util/errors.js'; +const generate = promisify(generateKeyPairCb); +export async function generateSecret(alg, options) { + let length; + 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))); +} +export async function generateKeyPair(alg, options) { + var _a, _b; + 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': { + const modulusLength = (_a = options === null || options === void 0 ? void 0 : options.modulusLength) !== null && _a !== void 0 ? _a : 2048; + if (typeof modulusLength !== 'number' || modulusLength < 2048) { + throw new JOSENotSupported('Invalid or unsupported modulusLength option provided, 2048 bits or larger keys must be used'); + } + const keypair = await generate('rsa', { + modulusLength, + publicExponent: 0x10001, + }); + setModulusLength(keypair.privateKey, modulusLength); + setModulusLength(keypair.publicKey, modulusLength); + return keypair; + } + 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 === null || options === void 0 ? void 0 : 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 === null || options === void 0 ? void 0 : options.crv) { + case undefined: + case 'P-256': + case 'P-384': + case 'P-521': + return generate('ec', { namedCurve: (_b = options === null || options === void 0 ? void 0 : options.crv) !== null && _b !== void 0 ? _b : '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/dist/node/esm/runtime/get_named_curve.js b/dist/node/esm/runtime/get_named_curve.js new file mode 100644 index 0000000000..4d41d86d47 --- /dev/null +++ b/dist/node/esm/runtime/get_named_curve.js @@ -0,0 +1,85 @@ +import { createPublicKey } from 'crypto'; +import { JOSENotSupported } from '../util/errors.js'; +import { isCryptoKey, getKeyObject } from './webcrypto.js'; +import isKeyObject from './is_key_object.js'; +import invalidKeyInput from './invalid_key_input.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]); +export const weakMap = new WeakMap(); +const namedCurveToJOSE = (namedCurve) => { + switch (namedCurve) { + case 'prime256v1': + return 'P-256'; + case 'secp384r1': + return 'P-384'; + case 'secp521r1': + return 'P-521'; + case 'secp256k1': + return namedCurve; + default: + throw new JOSENotSupported('unsupported key curve for this operation'); + } +}; +const getNamedCurve = (key, raw) => { + var _a; + if (isCryptoKey(key)) { + key = getKeyObject(key); + } + if (!isKeyObject(key)) { + throw new TypeError(invalidKeyInput(key, 'KeyObject', 'CryptoKey')); + } + if (key.type === 'secret') { + throw new TypeError('only "private" or "public" type keys can be used for this operation'); + } + switch (key.asymmetricKeyType) { + case 'ed25519': + case 'ed448': + return `Ed${key.asymmetricKeyType.substr(2)}`; + case 'x25519': + case 'x448': + return `X${key.asymmetricKeyType.substr(1)}`; + case 'ec': { + if (weakMap.has(key)) { + return weakMap.get(key); + } + let namedCurve = (_a = key.asymmetricKeyDetails) === null || _a === void 0 ? void 0 : _a.namedCurve; + if (!namedCurve && key.type === 'private') { + namedCurve = getNamedCurve(createPublicKey(key), true); + } + else if (!namedCurve) { + 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); + if (curveOid.equals(p256)) { + namedCurve = 'prime256v1'; + } + else if (curveOid.equals(p384)) { + namedCurve = 'secp384r1'; + } + else if (curveOid.equals(p521)) { + namedCurve = 'secp521r1'; + } + else if (curveOid.equals(secp256k1)) { + namedCurve = 'secp256k1'; + } + else { + throw new JOSENotSupported('unsupported key curve for this operation'); + } + } + if (raw) + return namedCurve; + const curve = namedCurveToJOSE(namedCurve); + weakMap.set(key, curve); + return curve; + } + default: + throw new TypeError('Invalid asymmetric key type for this operation'); + } +}; +export function setCurve(keyObject, curve) { + weakMap.set(keyObject, curve); +} +export default getNamedCurve; diff --git a/dist/node/esm/runtime/get_sign_verify_key.js b/dist/node/esm/runtime/get_sign_verify_key.js new file mode 100644 index 0000000000..a5c7ea7e3d --- /dev/null +++ b/dist/node/esm/runtime/get_sign_verify_key.js @@ -0,0 +1,19 @@ +import * as crypto from 'crypto'; +import { isCryptoKey, getKeyObject } from './webcrypto.js'; +import getSecretKey from './secret_key.js'; +import invalidKeyInput from './invalid_key_input.js'; +export default function getSignVerifyKey(alg, key, usage) { + if (key instanceof Uint8Array) { + if (!alg.startsWith('HS')) { + throw new TypeError(invalidKeyInput(key, 'KeyObject', 'CryptoKey')); + } + return getSecretKey(key); + } + if (key instanceof crypto.KeyObject) { + return key; + } + if (isCryptoKey(key)) { + return getKeyObject(key, alg, new Set([usage])); + } + throw new TypeError(invalidKeyInput(key, 'KeyObject', 'CryptoKey', 'Uint8Array')); +} diff --git a/dist/node/esm/runtime/hmac_digest.js b/dist/node/esm/runtime/hmac_digest.js new file mode 100644 index 0000000000..29d55c3e9c --- /dev/null +++ b/dist/node/esm/runtime/hmac_digest.js @@ -0,0 +1,13 @@ +import { JOSENotSupported } from '../util/errors.js'; +export default function hmacDigest(alg) { + switch (alg) { + case 'HS256': + return 'sha256'; + case 'HS384': + return 'sha384'; + case 'HS512': + return 'sha512'; + default: + throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`); + } +} diff --git a/dist/node/esm/runtime/invalid_key_input.js b/dist/node/esm/runtime/invalid_key_input.js new file mode 100644 index 0000000000..86e97074b9 --- /dev/null +++ b/dist/node/esm/runtime/invalid_key_input.js @@ -0,0 +1,36 @@ +import { inspect } from 'util'; +export default (actual, ...types) => { + let msg = 'Key must be '; + if (types.length > 2) { + const last = types.pop(); + msg += `one of type ${types.join(', ')}, or ${last}.`; + } + else if (types.length === 2) { + msg += `one of type ${types[0]} or ${types[1]}.`; + } + else { + msg += `of type ${types[0]}.`; + } + if (actual == null) { + msg += ` Received ${actual}`; + } + else if (typeof actual === 'function' && actual.name) { + msg += ` Received function ${actual.name}`; + } + else if (typeof actual === 'object' && actual != null) { + if (actual.constructor && actual.constructor.name) { + msg += ` Received an instance of ${actual.constructor.name}`; + } + else { + const inspected = inspect(actual, { depth: -1 }); + msg += ` Received ${inspected}`; + } + } + else { + let inspected = inspect(actual, { colors: false }); + if (inspected.length > 25) + inspected = `${inspected.slice(0, 25)}...`; + msg += ` Received type ${typeof actual} (${inspected})`; + } + return msg; +}; diff --git a/dist/node/esm/runtime/is_key_object.js b/dist/node/esm/runtime/is_key_object.js new file mode 100644 index 0000000000..eb1af73b66 --- /dev/null +++ b/dist/node/esm/runtime/is_key_object.js @@ -0,0 +1,14 @@ +import { KeyObject } from 'crypto'; +import * as util from 'util'; +let impl; +if (util.types.isKeyObject) { + impl = function isKeyObject(obj) { + return util.types.isKeyObject(obj); + }; +} +else { + impl = function isKeyObject(obj) { + return obj != null && obj instanceof KeyObject; + }; +} +export default impl; diff --git a/dist/node/esm/runtime/jwk_to_key.js b/dist/node/esm/runtime/jwk_to_key.js new file mode 100644 index 0000000000..cbd0af9df2 --- /dev/null +++ b/dist/node/esm/runtime/jwk_to_key.js @@ -0,0 +1,119 @@ +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'; +const [major, minor] = process.version + .substr(1) + .split('.') + .map((str) => parseInt(str, 10)); +const jwkImportSupported = major >= 16 || (major === 15 && minor >= 12); +const parse = (jwk) => { + if (jwkImportSupported && jwk.kty !== 'oct') { + return jwk.d + ? createPrivateKey({ format: 'jwk', key: jwk }) + : createPublicKey({ format: 'jwk', key: jwk }); + } + 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.zero(); + 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 = { + 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; + const pub = Buffer.concat([ + Buffer.alloc(1, 4), + Buffer.from(jwk.x, 'base64'), + Buffer.from(jwk.y, 'base64'), + ]); + 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 enc$3 = new Asn1SequenceEncoder(); + enc$3.bitStr(pub); + const f2 = enc$3.end(Buffer.from([0xa1])); + enc$2.add(f2); + const f = enc$2.end(); + const enc$4 = new Asn1SequenceEncoder(); + enc$4.add(f); + const f3 = enc$4.end(Buffer.from([0x04])); + enc.add(f3); + 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()); + 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'); + } +}; +export default parse; diff --git a/dist/node/esm/runtime/key_to_jwk.js b/dist/node/esm/runtime/key_to_jwk.js new file mode 100644 index 0000000000..cc55525800 --- /dev/null +++ b/dist/node/esm/runtime/key_to_jwk.js @@ -0,0 +1,157 @@ +import { createPublicKey } from 'crypto'; +import { encode as base64url } from './base64url.js'; +import Asn1SequenceDecoder from './asn1_sequence_decoder.js'; +import { JOSENotSupported } from '../util/errors.js'; +import getNamedCurve from './get_named_curve.js'; +import { isCryptoKey, getKeyObject } from './webcrypto.js'; +import isKeyObject from './is_key_object.js'; +import invalidKeyInput from './invalid_key_input.js'; +const [major, minor] = process.version + .substr(1) + .split('.') + .map((str) => parseInt(str, 10)); +const jwkExportSupported = major >= 16 || (major === 15 && minor >= 9); +const keyToJWK = (key) => { + let keyObject; + if (isCryptoKey(key)) { + if (!key.extractable) { + throw new TypeError('CryptoKey is not extractable'); + } + keyObject = getKeyObject(key); + } + else if (isKeyObject(key)) { + keyObject = key; + } + else if (key instanceof Uint8Array) { + return { + kty: 'oct', + k: base64url(key), + }; + } + else { + throw new TypeError(invalidKeyInput(key, 'KeyObject', 'CryptoKey', 'Uint8Array')); + } + if (jwkExportSupported) { + return keyObject.export({ format: 'jwk' }); + } + switch (keyObject.type) { + case 'secret': + return { + kty: 'oct', + k: base64url(keyObject.export()), + }; + case 'private': + case 'public': { + switch (keyObject.asymmetricKeyType) { + case 'rsa': { + const der = keyObject.export({ format: 'der', type: 'pkcs1' }); + const dec = new Asn1SequenceDecoder(der); + if (keyObject.type === 'private') { + dec.unsignedInteger(); + } + const n = base64url(dec.unsignedInteger()); + const e = base64url(dec.unsignedInteger()); + let jwk; + if (keyObject.type === 'private') { + jwk = { + d: base64url(dec.unsignedInteger()), + p: base64url(dec.unsignedInteger()), + q: base64url(dec.unsignedInteger()), + dp: base64url(dec.unsignedInteger()), + dq: base64url(dec.unsignedInteger()), + qi: base64url(dec.unsignedInteger()), + }; + } + dec.end(); + return { kty: 'RSA', n, e, ...jwk }; + } + case 'ec': { + const crv = getNamedCurve(keyObject); + let len; + let offset; + let correction; + switch (crv) { + case 'secp256k1': + len = 64; + offset = 31 + 2; + correction = -1; + break; + case 'P-256': + len = 64; + offset = 34 + 2; + correction = -1; + break; + case 'P-384': + len = 96; + offset = 33 + 2; + correction = -3; + break; + case 'P-521': + len = 132; + offset = 33 + 2; + correction = -3; + break; + default: + throw new JOSENotSupported('unsupported curve'); + } + if (keyObject.type === 'public') { + const der = keyObject.export({ type: 'spki', format: 'der' }); + return { + kty: 'EC', + crv, + x: base64url(der.subarray(-len, -len / 2)), + y: base64url(der.subarray(-len / 2)), + }; + } + const der = keyObject.export({ type: 'pkcs8', format: 'der' }); + if (der.length < 100) { + offset += correction; + } + return { + ...keyToJWK(createPublicKey(keyObject)), + d: base64url(der.subarray(offset, offset + len / 2)), + }; + } + case 'ed25519': + case 'x25519': { + const crv = getNamedCurve(keyObject); + if (keyObject.type === 'public') { + const der = keyObject.export({ type: 'spki', format: 'der' }); + return { + kty: 'OKP', + crv, + x: base64url(der.subarray(-32)), + }; + } + const der = keyObject.export({ type: 'pkcs8', format: 'der' }); + return { + ...keyToJWK(createPublicKey(keyObject)), + d: base64url(der.subarray(-32)), + }; + } + case 'ed448': + case 'x448': { + const crv = getNamedCurve(keyObject); + if (keyObject.type === 'public') { + const der = keyObject.export({ type: 'spki', format: 'der' }); + return { + kty: 'OKP', + crv, + x: base64url(der.subarray(crv === 'Ed448' ? -57 : -56)), + }; + } + const der = keyObject.export({ type: 'pkcs8', format: 'der' }); + return { + ...keyToJWK(createPublicKey(keyObject)), + d: base64url(der.subarray(crv === 'Ed448' ? -57 : -56)), + }; + } + default: + throw new JOSENotSupported('unsupported key asymmetricKeyType'); + } + } + default: + throw new JOSENotSupported('unsupported key type'); + } +}; +export default keyToJWK; diff --git a/dist/node/esm/runtime/node_key.js b/dist/node/esm/runtime/node_key.js new file mode 100644 index 0000000000..dc23351549 --- /dev/null +++ b/dist/node/esm/runtime/node_key.js @@ -0,0 +1,83 @@ +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 [major, minor] = process.version + .substr(1) + .split('.') + .map((str) => parseInt(str, 10)); +const rsaPssParams = major >= 17 || (major === 16 && minor >= 9); +const ecCurveAlgMap = new Map([ + ['ES256', 'P-256'], + ['ES256K', 'secp256k1'], + ['ES384', 'P-384'], + ['ES512', 'P-521'], +]); +export default function keyForCrypto(alg, key) { + switch (alg) { + case 'EdDSA': + if (!['ed25519', 'ed448'].includes(key.asymmetricKeyType)) { + throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be ed25519 or ed448'); + } + return key; + case 'RS256': + case 'RS384': + case 'RS512': + if (key.asymmetricKeyType !== 'rsa') { + throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be rsa'); + } + checkModulusLength(key, alg); + return key; + case rsaPssParams && 'PS256': + case rsaPssParams && 'PS384': + case rsaPssParams && 'PS512': + if (key.asymmetricKeyType === 'rsa-pss') { + const { hashAlgorithm, mgf1HashAlgorithm, saltLength } = key.asymmetricKeyDetails; + const length = parseInt(alg.substr(-3), 10); + if (hashAlgorithm !== undefined && + (hashAlgorithm !== `sha${length}` || mgf1HashAlgorithm !== hashAlgorithm)) { + throw new TypeError(`Invalid key for this operation, its RSA-PSS parameters do not meet the requirements of "alg" ${alg}`); + } + if (saltLength !== undefined && saltLength > length >> 3) { + throw new TypeError(`Invalid key for this operation, its RSA-PSS parameter saltLength does not meet the requirements of "alg" ${alg}`); + } + } + else if (key.asymmetricKeyType !== 'rsa') { + throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be rsa or rsa-pss'); + } + checkModulusLength(key, alg); + return { + key, + padding: constants.RSA_PKCS1_PSS_PADDING, + saltLength: constants.RSA_PSS_SALTLEN_DIGEST, + }; + case !rsaPssParams && 'PS256': + case !rsaPssParams && 'PS384': + case !rsaPssParams && 'PS512': + if (key.asymmetricKeyType !== 'rsa') { + throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be rsa'); + } + 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.asymmetricKeyType !== 'ec') { + throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be ec'); + } + const actual = getNamedCurve(key); + const expected = ecCurveAlgMap.get(alg); + if (actual !== expected) { + throw new TypeError(`Invalid key curve for the algorithm, its curve must be ${expected}, got ${actual}`); + } + return { dsaEncoding: 'ieee-p1363', key }; + } + default: + throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`); + } +} diff --git a/dist/node/esm/runtime/pbes2kw.js b/dist/node/esm/runtime/pbes2kw.js new file mode 100644 index 0000000000..04dc6ce40a --- /dev/null +++ b/dist/node/esm/runtime/pbes2kw.js @@ -0,0 +1,40 @@ +import { promisify } from 'util'; +import { pbkdf2 as pbkdf2cb } from 'crypto'; +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 { isCryptoKey, getKeyObject } from './webcrypto.js'; +import isKeyObject from './is_key_object.js'; +import invalidKeyInput from './invalid_key_input.js'; +const pbkdf2 = promisify(pbkdf2cb); +function getPassword(key, alg) { + if (isKeyObject(key)) { + return key.export(); + } + if (key instanceof Uint8Array) { + return key; + } + if (isCryptoKey(key)) { + return getKeyObject(key, alg, new Set(['deriveBits', 'deriveKey'])).export(); + } + throw new TypeError(invalidKeyInput(key, 'KeyObject', 'CryptoKey', 'Uint8Array')); +} +export const encrypt = async (alg, key, cek, p2c = Math.floor(Math.random() * 2049) + 2048, p2s = random(new Uint8Array(16))) => { + checkP2s(p2s); + const salt = concatSalt(alg, p2s); + const keylen = parseInt(alg.substr(13, 3), 10) >> 3; + const password = getPassword(key, alg); + 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 = async (alg, key, encryptedKey, p2c, p2s) => { + checkP2s(p2s); + const salt = concatSalt(alg, p2s); + const keylen = parseInt(alg.substr(13, 3), 10) >> 3; + const password = getPassword(key, alg); + const derivedKey = await pbkdf2(password, salt, p2c, keylen, `sha${alg.substr(8, 3)}`); + return unwrap(alg.substr(-6), derivedKey, encryptedKey); +}; diff --git a/dist/node/esm/runtime/random.js b/dist/node/esm/runtime/random.js new file mode 100644 index 0000000000..587291011a --- /dev/null +++ b/dist/node/esm/runtime/random.js @@ -0,0 +1,2 @@ +import { randomFillSync } from 'crypto'; +export default randomFillSync; diff --git a/dist/node/esm/runtime/rsaes.js b/dist/node/esm/runtime/rsaes.js new file mode 100644 index 0000000000..bb5867f697 --- /dev/null +++ b/dist/node/esm/runtime/rsaes.js @@ -0,0 +1,61 @@ +import { publicEncrypt, constants, privateDecrypt } from 'crypto'; +import checkModulusLength from './check_modulus_length.js'; +import { isCryptoKey, getKeyObject } from './webcrypto.js'; +import isKeyObject from './is_key_object.js'; +import invalidKeyInput from './invalid_key_input.js'; +const checkKey = (key, alg) => { + if (key.asymmetricKeyType !== 'rsa') { + throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be rsa'); + } + checkModulusLength(key, alg); +}; +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; + default: + return undefined; + } +}; +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; + } +}; +function ensureKeyObject(key, alg, ...usages) { + if (isKeyObject(key)) { + return key; + } + if (isCryptoKey(key)) { + return getKeyObject(key, alg, new Set(usages)); + } + throw new TypeError(invalidKeyInput(key, 'KeyObject', 'CryptoKey')); +} +export const encrypt = async (alg, key, cek) => { + const padding = resolvePadding(alg); + const oaepHash = resolveOaepHash(alg); + const keyObject = ensureKeyObject(key, alg, 'wrapKey', 'encrypt'); + checkKey(keyObject, alg); + return publicEncrypt({ key: keyObject, oaepHash, padding }, cek); +}; +export const decrypt = async (alg, key, encryptedKey) => { + const padding = resolvePadding(alg); + const oaepHash = resolveOaepHash(alg); + const keyObject = ensureKeyObject(key, alg, 'unwrapKey', 'decrypt'); + checkKey(keyObject, alg); + return privateDecrypt({ key: keyObject, oaepHash, padding }, encryptedKey); +}; diff --git a/dist/node/esm/runtime/secret_key.js b/dist/node/esm/runtime/secret_key.js new file mode 100644 index 0000000000..c395546796 --- /dev/null +++ b/dist/node/esm/runtime/secret_key.js @@ -0,0 +1,11 @@ +import { createSecretKey } from 'crypto'; +export default function getSecretKey(key) { + let keyObject; + if (key instanceof Uint8Array) { + keyObject = createSecretKey(key); + } + else { + keyObject = key; + } + return keyObject; +} diff --git a/dist/node/esm/runtime/sign.js b/dist/node/esm/runtime/sign.js new file mode 100644 index 0000000000..d6f03a4b69 --- /dev/null +++ b/dist/node/esm/runtime/sign.js @@ -0,0 +1,27 @@ +import * as crypto from 'crypto'; +import { promisify } from 'util'; +import nodeDigest from './dsa_digest.js'; +import hmacDigest from './hmac_digest.js'; +import nodeKey from './node_key.js'; +import getSignKey from './get_sign_verify_key.js'; +let oneShotSign; +if (crypto.sign.length > 3) { + oneShotSign = promisify(crypto.sign); +} +else { + oneShotSign = crypto.sign; +} +const sign = async (alg, key, data) => { + const keyObject = getSignKey(alg, key, 'sign'); + 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 = crypto.createHmac(hmacDigest(alg), keyObject); + hmac.update(data); + return hmac.digest(); + } + return oneShotSign(nodeDigest(alg), data, nodeKey(alg, keyObject)); +}; +export default sign; diff --git a/dist/node/esm/runtime/timing_safe_equal.js b/dist/node/esm/runtime/timing_safe_equal.js new file mode 100644 index 0000000000..901ae38bdd --- /dev/null +++ b/dist/node/esm/runtime/timing_safe_equal.js @@ -0,0 +1,3 @@ +import { timingSafeEqual as impl } from 'crypto'; +const timingSafeEqual = impl; +export default timingSafeEqual; diff --git a/dist/node/esm/runtime/verify.js b/dist/node/esm/runtime/verify.js new file mode 100644 index 0000000000..ccc4004921 --- /dev/null +++ b/dist/node/esm/runtime/verify.js @@ -0,0 +1,40 @@ +import * as crypto from 'crypto'; +import { promisify } from 'util'; +import nodeDigest from './dsa_digest.js'; +import nodeKey from './node_key.js'; +import sign from './sign.js'; +import getVerifyKey from './get_sign_verify_key.js'; +const [major, minor] = process.version + .substr(1) + .split('.') + .map((str) => parseInt(str, 10)); +const oneShotCallbackSupported = major >= 16 || (major === 15 && minor >= 13); +let oneShotVerify; +if (crypto.verify.length > 4 && oneShotCallbackSupported) { + oneShotVerify = promisify(crypto.verify); +} +else { + oneShotVerify = crypto.verify; +} +const verify = async (alg, key, signature, data) => { + const keyObject = getVerifyKey(alg, key, 'verify'); + if (alg.startsWith('HS')) { + const expected = await sign(alg, keyObject, data); + const actual = signature; + try { + return crypto.timingSafeEqual(actual, expected); + } + catch { + return false; + } + } + const algorithm = nodeDigest(alg); + const keyInput = nodeKey(alg, keyObject); + try { + return await oneShotVerify(algorithm, data, keyInput, signature); + } + catch { + return false; + } +}; +export default verify; diff --git a/dist/node/esm/runtime/webcrypto.js b/dist/node/esm/runtime/webcrypto.js new file mode 100644 index 0000000000..67d34fad74 --- /dev/null +++ b/dist/node/esm/runtime/webcrypto.js @@ -0,0 +1,161 @@ +import * as crypto from 'crypto'; +import * as util from 'util'; +const webcrypto = crypto.webcrypto; +export default webcrypto; +let impl; +if (util.types.isCryptoKey) { + impl = function isCryptoKey(obj) { + return util.types.isCryptoKey(obj); + }; +} +else if (webcrypto) { + impl = function isCryptoKey(obj) { + return obj != null && obj instanceof webcrypto.CryptoKey; + }; +} +else { + impl = (obj) => false; +} +export { impl as isCryptoKey }; +function getHashLength(hash) { + return parseInt(hash === null || hash === void 0 ? void 0 : hash.name.substr(4), 10); +} +function getNamedCurve(alg) { + switch (alg) { + case 'ES256': + return 'P-256'; + case 'ES384': + return 'P-384'; + case 'ES512': + return 'P-521'; + } +} +export function getKeyObject(key, alg, usage) { + if (!alg) { + return crypto.KeyObject.from(key); + } + switch (alg) { + case 'HS256': + case 'HS384': + case 'HS512': { + if (key.algorithm.name !== 'HMAC') { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be HMAC.`); + } + const expected = parseInt(alg.substr(2), 10); + const actual = getHashLength(key.algorithm.hash); + if (actual !== expected) { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.hash must be SHA-${expected}.`); + } + break; + } + case 'RS256': + case 'RS384': + case 'RS512': { + if (key.algorithm.name !== 'RSASSA-PKCS1-v1_5') { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be RSASSA-PKCS1-v1_5.`); + } + const expected = parseInt(alg.substr(2), 10); + const actual = getHashLength(key.algorithm.hash); + if (actual !== expected) { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.hash must be SHA-${expected}.`); + } + break; + } + case 'PS256': + case 'PS384': + case 'PS512': { + if (key.algorithm.name !== 'RSA-PSS') { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be RSA-PSS.`); + } + const expected = parseInt(alg.substr(2), 10); + const actual = getHashLength(key.algorithm.hash); + if (actual !== expected) { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.hash must be SHA-${expected}.`); + } + break; + } + case 'ES256': + case 'ES384': + case 'ES512': { + if (key.algorithm.name !== 'ECDSA') { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be ECDSA.`); + } + const expected = getNamedCurve(alg); + const actual = key.algorithm.namedCurve; + if (actual !== expected) { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.namedCurve must be ${expected}.`); + } + break; + } + case 'A128GCM': + case 'A192GCM': + case 'A256GCM': { + if (key.algorithm.name !== 'AES-GCM') { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be AES-GCM.`); + } + const expected = parseInt(alg.substr(1, 3), 10); + const actual = key.algorithm.length; + if (actual !== expected) { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.length must be ${expected}.`); + } + break; + } + case 'A128KW': + case 'A192KW': + case 'A256KW': { + if (key.algorithm.name !== 'AES-KW') { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be AES-KW.`); + } + const expected = parseInt(alg.substr(1, 3), 10); + const actual = key.algorithm.length; + if (actual !== expected) { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.length must be ${expected}.`); + } + break; + } + case 'ECDH-ES': + if (key.algorithm.name !== 'ECDH') { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be ECDH.`); + } + break; + case 'PBES2-HS256+A128KW': + case 'PBES2-HS384+A192KW': + case 'PBES2-HS512+A256KW': + if (key.algorithm.name !== 'PBKDF2') { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be PBKDF2.`); + } + break; + case 'RSA-OAEP': + case 'RSA-OAEP-256': + case 'RSA-OAEP-384': + case 'RSA-OAEP-512': { + if (key.algorithm.name !== 'RSA-OAEP') { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be RSA-OAEP.`); + } + const expected = parseInt(alg.substr(9), 10) || 1; + const actual = getHashLength(key.algorithm.hash); + if (actual !== expected) { + throw new TypeError(`CryptoKey does not support this operation, its algorithm.hash must be SHA-${expected}.`); + } + break; + } + default: + throw new TypeError('CryptoKey does not support this operation'); + } + if (usage && !key.usages.find(Set.prototype.has.bind(usage))) { + const usages = [...usage]; + let msg = 'CryptoKey does not support this operation, its usages must include '; + if (usages.length > 2) { + const last = usages.pop(); + msg += `one of ${usages.join(', ')}, or ${last}.`; + } + else if (usages.length === 2) { + msg += `one of ${usages[0]} or ${usages[1]}.`; + } + else { + msg += ` ${usages[0]}.`; + } + throw new TypeError(msg); + } + return crypto.KeyObject.from(key); +} diff --git a/dist/node/esm/runtime/zlib.js b/dist/node/esm/runtime/zlib.js new file mode 100644 index 0000000000..8bb72cbf18 --- /dev/null +++ b/dist/node/esm/runtime/zlib.js @@ -0,0 +1,6 @@ +import { promisify } from 'util'; +import { inflateRaw as inflateRawCb, deflateRaw as deflateRawCb } from 'zlib'; +const inflateRaw = promisify(inflateRawCb); +const deflateRaw = promisify(deflateRawCb); +export const inflate = (input) => inflateRaw(input); +export const deflate = (input) => deflateRaw(input); diff --git a/dist/node/esm/util/base64url.js b/dist/node/esm/util/base64url.js new file mode 100644 index 0000000000..88ce7556d6 --- /dev/null +++ b/dist/node/esm/util/base64url.js @@ -0,0 +1,3 @@ +import * as base64url from '../runtime/base64url.js'; +export const encode = base64url.encode; +export const decode = base64url.decode; diff --git a/dist/node/esm/util/decode_protected_header.js b/dist/node/esm/util/decode_protected_header.js new file mode 100644 index 0000000000..b39c96daeb --- /dev/null +++ b/dist/node/esm/util/decode_protected_header.js @@ -0,0 +1,36 @@ +import { decode as base64url } from './base64url.js'; +import { decoder } from '../lib/buffer_utils.js'; +import isObject from '../lib/is_object.js'; +function decodeProtectedHeader(token) { + let protectedB64u; + if (typeof token === 'string') { + const parts = token.split('.'); + if (parts.length === 3 || parts.length === 5) { + ; + [protectedB64u] = parts; + } + } + else if (typeof token === 'object' && token) { + if ('protected' in token) { + protectedB64u = token.protected; + } + else { + throw new TypeError('Token does not contain a Protected Header'); + } + } + try { + if (typeof protectedB64u !== 'string' || !protectedB64u) { + throw new Error(); + } + const result = JSON.parse(decoder.decode(base64url(protectedB64u))); + if (!isObject(result)) { + throw new Error(); + } + return result; + } + catch { + throw new TypeError('Invalid Token or Protected Header formatting'); + } +} +export { decodeProtectedHeader }; +export default decodeProtectedHeader; diff --git a/dist/node/esm/util/errors.js b/dist/node/esm/util/errors.js new file mode 100644 index 0000000000..52506cbd9d --- /dev/null +++ b/dist/node/esm/util/errors.js @@ -0,0 +1,108 @@ +export class JOSEError extends Error { + constructor(message) { + super(message); + this.code = JOSEError.code; + this.name = this.constructor.name; + if (Error.captureStackTrace) { + Error.captureStackTrace(this, this.constructor); + } + } +} +JOSEError.code = 'ERR_JOSE_GENERIC'; +export class JWTClaimValidationFailed extends JOSEError { + constructor(message, claim = 'unspecified', reason = 'unspecified') { + super(message); + this.code = JWTClaimValidationFailed.code; + this.claim = claim; + this.reason = reason; + } +} +JWTClaimValidationFailed.code = 'ERR_JWT_CLAIM_VALIDATION_FAILED'; +export class JOSEAlgNotAllowed extends JOSEError { + constructor() { + super(...arguments); + this.code = JOSEAlgNotAllowed.code; + } +} +JOSEAlgNotAllowed.code = 'ERR_JOSE_ALG_NOT_ALLOWED'; +export class JOSENotSupported extends JOSEError { + constructor() { + super(...arguments); + this.code = JOSENotSupported.code; + } +} +JOSENotSupported.code = 'ERR_JOSE_NOT_SUPPORTED'; +export class JWEDecryptionFailed extends JOSEError { + constructor() { + super(...arguments); + this.code = JWEDecryptionFailed.code; + this.message = 'decryption operation failed'; + } +} +JWEDecryptionFailed.code = 'ERR_JWE_DECRYPTION_FAILED'; +export class JWEInvalid extends JOSEError { + constructor() { + super(...arguments); + this.code = JWEInvalid.code; + } +} +JWEInvalid.code = 'ERR_JWE_INVALID'; +export class JWSInvalid extends JOSEError { + constructor() { + super(...arguments); + this.code = JWSInvalid.code; + } +} +JWSInvalid.code = 'ERR_JWS_INVALID'; +export class JWTInvalid extends JOSEError { + constructor() { + super(...arguments); + this.code = JWTInvalid.code; + } +} +JWTInvalid.code = 'ERR_JWT_INVALID'; +export class JWKInvalid extends JOSEError { + constructor() { + super(...arguments); + this.code = JWKInvalid.code; + } +} +JWKInvalid.code = 'ERR_JWK_INVALID'; +export class JWKSInvalid extends JOSEError { + constructor() { + super(...arguments); + this.code = JWKSInvalid.code; + } +} +JWKSInvalid.code = 'ERR_JWKS_INVALID'; +export class JWKSNoMatchingKey extends JOSEError { + constructor() { + super(...arguments); + this.code = JWKSNoMatchingKey.code; + this.message = 'no applicable key found in the JSON Web Key Set'; + } +} +JWKSNoMatchingKey.code = 'ERR_JWKS_NO_MATCHING_KEY'; +export class JWKSMultipleMatchingKeys extends JOSEError { + constructor() { + super(...arguments); + this.code = JWKSMultipleMatchingKeys.code; + this.message = 'multiple matching keys found in the JSON Web Key Set'; + } +} +JWKSMultipleMatchingKeys.code = 'ERR_JWKS_MULTIPLE_MATCHING_KEYS'; +export class JWSSignatureVerificationFailed extends JOSEError { + constructor() { + super(...arguments); + this.code = JWSSignatureVerificationFailed.code; + this.message = 'signature verification failed'; + } +} +JWSSignatureVerificationFailed.code = 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED'; +export class JWTExpired extends JWTClaimValidationFailed { + constructor() { + super(...arguments); + this.code = JWTExpired.code; + } +} +JWTExpired.code = 'ERR_JWT_EXPIRED'; diff --git a/dist/node/esm/util/generate_key_pair.js b/dist/node/esm/util/generate_key_pair.js new file mode 100644 index 0000000000..733800cc06 --- /dev/null +++ b/dist/node/esm/util/generate_key_pair.js @@ -0,0 +1,6 @@ +import { generateKeyPair as generate } from '../runtime/generate.js'; +async function generateKeyPair(alg, options) { + return generate(alg, options); +} +export { generateKeyPair }; +export default generateKeyPair; diff --git a/dist/node/esm/util/generate_secret.js b/dist/node/esm/util/generate_secret.js new file mode 100644 index 0000000000..2d387754ee --- /dev/null +++ b/dist/node/esm/util/generate_secret.js @@ -0,0 +1,6 @@ +import { generateSecret as generate } from '../runtime/generate.js'; +async function generateSecret(alg, options) { + return generate(alg, options); +} +export { generateSecret }; +export default generateSecret; diff --git a/dist/node/esm/util/random.js b/dist/node/esm/util/random.js new file mode 100644 index 0000000000..d7dc7ab182 --- /dev/null +++ b/dist/node/esm/util/random.js @@ -0,0 +1,4 @@ +import runtimeRandom from '../runtime/random.js'; +const random = runtimeRandom; +export { random }; +export default random; diff --git a/dist/types/jwe/compact/decrypt.d.ts b/dist/types/jwe/compact/decrypt.d.ts new file mode 100644 index 0000000000..a89115a26e --- /dev/null +++ b/dist/types/jwe/compact/decrypt.d.ts @@ -0,0 +1,7 @@ +import type { KeyLike, DecryptOptions, JWEHeaderParameters, GetKeyFunction, FlattenedJWE, CompactDecryptResult } from '../../types'; +export interface CompactDecryptGetKey extends GetKeyFunction { +} +declare function compactDecrypt(jwe: string | Uint8Array, key: KeyLike | CompactDecryptGetKey, options?: DecryptOptions): Promise; +export { compactDecrypt }; +export default compactDecrypt; +export type { KeyLike, DecryptOptions, CompactDecryptResult }; diff --git a/dist/types/jwe/compact/encrypt.d.ts b/dist/types/jwe/compact/encrypt.d.ts new file mode 100644 index 0000000000..108cdd9cb6 --- /dev/null +++ b/dist/types/jwe/compact/encrypt.d.ts @@ -0,0 +1,13 @@ +import type { KeyLike, JWEKeyManagementHeaderParameters, JWEHeaderParameters, EncryptOptions } from '../../types'; +declare class CompactEncrypt { + private _flattened; + constructor(plaintext: Uint8Array); + setContentEncryptionKey(cek: Uint8Array): this; + setInitializationVector(iv: Uint8Array): this; + setProtectedHeader(protectedHeader: JWEHeaderParameters): this; + setKeyManagementParameters(parameters: JWEKeyManagementHeaderParameters): this; + encrypt(key: KeyLike, options?: EncryptOptions): Promise; +} +export { CompactEncrypt }; +export default CompactEncrypt; +export type { KeyLike, JWEKeyManagementHeaderParameters, JWEHeaderParameters }; diff --git a/dist/types/jwe/flattened/decrypt.d.ts b/dist/types/jwe/flattened/decrypt.d.ts new file mode 100644 index 0000000000..bcb78f89ee --- /dev/null +++ b/dist/types/jwe/flattened/decrypt.d.ts @@ -0,0 +1,7 @@ +import type { FlattenedDecryptResult, KeyLike, FlattenedJWE, JWEHeaderParameters, DecryptOptions, GetKeyFunction } from '../../types'; +export interface FlattenedDecryptGetKey extends GetKeyFunction { +} +declare function flattenedDecrypt(jwe: FlattenedJWE, key: KeyLike | FlattenedDecryptGetKey, options?: DecryptOptions): Promise; +export { flattenedDecrypt }; +export default flattenedDecrypt; +export type { KeyLike, FlattenedJWE, JWEHeaderParameters, DecryptOptions, FlattenedDecryptResult }; diff --git a/dist/types/jwe/flattened/encrypt.d.ts b/dist/types/jwe/flattened/encrypt.d.ts new file mode 100644 index 0000000000..ba724922dc --- /dev/null +++ b/dist/types/jwe/flattened/encrypt.d.ts @@ -0,0 +1,23 @@ +import type { KeyLike, FlattenedJWE, JWEHeaderParameters, JWEKeyManagementHeaderParameters, EncryptOptions } from '../../types'; +declare class FlattenedEncrypt { + private _plaintext; + private _protectedHeader; + private _sharedUnprotectedHeader; + private _unprotectedHeader; + private _aad; + private _cek; + private _iv; + private _keyManagementParameters; + constructor(plaintext: Uint8Array); + setKeyManagementParameters(parameters: JWEKeyManagementHeaderParameters): this; + setProtectedHeader(protectedHeader: JWEHeaderParameters): this; + setSharedUnprotectedHeader(sharedUnprotectedHeader: JWEHeaderParameters): this; + setUnprotectedHeader(unprotectedHeader: JWEHeaderParameters): this; + setAdditionalAuthenticatedData(aad: Uint8Array): this; + setContentEncryptionKey(cek: Uint8Array): this; + setInitializationVector(iv: Uint8Array): this; + encrypt(key: KeyLike, options?: EncryptOptions): Promise; +} +export { FlattenedEncrypt }; +export default FlattenedEncrypt; +export type { KeyLike, FlattenedJWE, JWEHeaderParameters, JWEKeyManagementHeaderParameters }; diff --git a/dist/types/jwe/general/decrypt.d.ts b/dist/types/jwe/general/decrypt.d.ts new file mode 100644 index 0000000000..61b71f80ca --- /dev/null +++ b/dist/types/jwe/general/decrypt.d.ts @@ -0,0 +1,7 @@ +import type { KeyLike, DecryptOptions, JWEHeaderParameters, GetKeyFunction, FlattenedJWE, GeneralJWE, GeneralDecryptResult } from '../../types'; +export interface GeneralDecryptGetKey extends GetKeyFunction { +} +declare function generalDecrypt(jwe: GeneralJWE, key: KeyLike | GeneralDecryptGetKey, options?: DecryptOptions): Promise; +export { generalDecrypt }; +export default generalDecrypt; +export type { KeyLike, GeneralJWE, DecryptOptions, GeneralDecryptResult }; diff --git a/dist/types/jwk/embedded.d.ts b/dist/types/jwk/embedded.d.ts new file mode 100644 index 0000000000..797ef7517b --- /dev/null +++ b/dist/types/jwk/embedded.d.ts @@ -0,0 +1,5 @@ +/// +import type { KeyObject, FlattenedJWSInput, JWSHeaderParameters } from '../types'; +declare function EmbeddedJWK(protectedHeader: JWSHeaderParameters, token: FlattenedJWSInput): Promise; +export { EmbeddedJWK }; +export default EmbeddedJWK; diff --git a/dist/types/jwk/from_key_like.d.ts b/dist/types/jwk/from_key_like.d.ts new file mode 100644 index 0000000000..886c5f851e --- /dev/null +++ b/dist/types/jwk/from_key_like.d.ts @@ -0,0 +1,5 @@ +import type { JWK, KeyLike } from '../types'; +declare function fromKeyLike(key: KeyLike): Promise; +export { fromKeyLike }; +export default fromKeyLike; +export type { KeyLike, JWK }; diff --git a/dist/types/jwk/parse.d.ts b/dist/types/jwk/parse.d.ts new file mode 100644 index 0000000000..0c1749afc3 --- /dev/null +++ b/dist/types/jwk/parse.d.ts @@ -0,0 +1,5 @@ +import type { JWK, KeyLike } from '../types'; +declare function parseJwk(jwk: JWK, alg?: string, octAsKeyObject?: boolean): Promise; +export { parseJwk }; +export default parseJwk; +export type { KeyLike, JWK }; diff --git a/dist/types/jwk/thumbprint.d.ts b/dist/types/jwk/thumbprint.d.ts new file mode 100644 index 0000000000..7e827db13d --- /dev/null +++ b/dist/types/jwk/thumbprint.d.ts @@ -0,0 +1,5 @@ +import type { JWK } from '../types'; +declare function calculateThumbprint(jwk: JWK, digestAlgorithm?: 'sha256' | 'sha384' | 'sha512'): Promise; +export { calculateThumbprint }; +export default calculateThumbprint; +export type { JWK }; diff --git a/dist/types/jwks/remote.d.ts b/dist/types/jwks/remote.d.ts new file mode 100644 index 0000000000..63f0b6697a --- /dev/null +++ b/dist/types/jwks/remote.d.ts @@ -0,0 +1,9 @@ +import type { JWSHeaderParameters, FlattenedJWSInput, GetKeyFunction } from '../types'; +export interface RemoteJWKSetOptions { + timeoutDuration?: number; + cooldownDuration?: number; + agent?: any; +} +declare function createRemoteJWKSet(url: URL, options?: RemoteJWKSetOptions): GetKeyFunction; +export { createRemoteJWKSet }; +export default createRemoteJWKSet; diff --git a/dist/types/jws/compact/sign.d.ts b/dist/types/jws/compact/sign.d.ts new file mode 100644 index 0000000000..c5b9c3da0a --- /dev/null +++ b/dist/types/jws/compact/sign.d.ts @@ -0,0 +1,10 @@ +import type { JWSHeaderParameters, KeyLike, SignOptions } from '../../types'; +declare class CompactSign { + private _flattened; + constructor(payload: Uint8Array); + setProtectedHeader(protectedHeader: JWSHeaderParameters): this; + sign(key: KeyLike, options?: SignOptions): Promise; +} +export { CompactSign }; +export default CompactSign; +export type { JWSHeaderParameters, KeyLike }; diff --git a/dist/types/jws/compact/verify.d.ts b/dist/types/jws/compact/verify.d.ts new file mode 100644 index 0000000000..0279df23a7 --- /dev/null +++ b/dist/types/jws/compact/verify.d.ts @@ -0,0 +1,7 @@ +import type { CompactVerifyResult, FlattenedJWSInput, GetKeyFunction, JWSHeaderParameters, KeyLike, VerifyOptions } from '../../types'; +export interface CompactVerifyGetKey extends GetKeyFunction { +} +declare function compactVerify(jws: string | Uint8Array, key: KeyLike | CompactVerifyGetKey, options?: VerifyOptions): Promise; +export { compactVerify }; +export default compactVerify; +export type { KeyLike, VerifyOptions, CompactVerifyResult }; diff --git a/dist/types/jws/flattened/sign.d.ts b/dist/types/jws/flattened/sign.d.ts new file mode 100644 index 0000000000..9e9f9612ef --- /dev/null +++ b/dist/types/jws/flattened/sign.d.ts @@ -0,0 +1,13 @@ +import type { KeyLike, FlattenedJWS, JWSHeaderParameters, SignOptions } from '../../types'; +declare class FlattenedSign { + private _payload; + private _protectedHeader; + private _unprotectedHeader; + constructor(payload: Uint8Array); + setProtectedHeader(protectedHeader: JWSHeaderParameters): this; + setUnprotectedHeader(unprotectedHeader: JWSHeaderParameters): this; + sign(key: KeyLike, options?: SignOptions): Promise; +} +export { FlattenedSign }; +export default FlattenedSign; +export type { KeyLike, FlattenedJWS, JWSHeaderParameters }; diff --git a/dist/types/jws/flattened/verify.d.ts b/dist/types/jws/flattened/verify.d.ts new file mode 100644 index 0000000000..0cdf7025d7 --- /dev/null +++ b/dist/types/jws/flattened/verify.d.ts @@ -0,0 +1,7 @@ +import type { FlattenedVerifyResult, KeyLike, FlattenedJWSInput, JWSHeaderParameters, VerifyOptions, GetKeyFunction } from '../../types'; +export interface FlattenedVerifyGetKey extends GetKeyFunction { +} +declare function flattenedVerify(jws: FlattenedJWSInput, key: KeyLike | FlattenedVerifyGetKey, options?: VerifyOptions): Promise; +export { flattenedVerify }; +export default flattenedVerify; +export type { KeyLike, FlattenedJWSInput, GetKeyFunction, JWSHeaderParameters, VerifyOptions, FlattenedVerifyResult, }; diff --git a/dist/types/jws/general/sign.d.ts b/dist/types/jws/general/sign.d.ts new file mode 100644 index 0000000000..1d3fd9a290 --- /dev/null +++ b/dist/types/jws/general/sign.d.ts @@ -0,0 +1,15 @@ +import type { KeyLike, GeneralJWS, JWSHeaderParameters, SignOptions } from '../../types'; +export interface Signature { + setProtectedHeader(protectedHeader: JWSHeaderParameters): Signature; + setUnprotectedHeader(unprotectedHeader: JWSHeaderParameters): Signature; +} +declare class GeneralSign { + private _payload; + private _signatures; + constructor(payload: Uint8Array); + addSignature(key: KeyLike, options?: SignOptions): Signature; + sign(): Promise; +} +export { GeneralSign }; +export default GeneralSign; +export type { KeyLike, GeneralJWS, JWSHeaderParameters }; diff --git a/dist/types/jws/general/verify.d.ts b/dist/types/jws/general/verify.d.ts new file mode 100644 index 0000000000..a72756a31c --- /dev/null +++ b/dist/types/jws/general/verify.d.ts @@ -0,0 +1,7 @@ +import type { GeneralJWSInput, GeneralVerifyResult, FlattenedJWSInput, GetKeyFunction, JWSHeaderParameters, KeyLike, VerifyOptions } from '../../types'; +export interface GeneralVerifyGetKey extends GetKeyFunction { +} +declare function generalVerify(jws: GeneralJWSInput, key: KeyLike | GeneralVerifyGetKey, options?: VerifyOptions): Promise; +export { generalVerify }; +export default generalVerify; +export type { KeyLike, GeneralJWSInput, VerifyOptions, GeneralVerifyResult }; diff --git a/dist/types/jwt/decrypt.d.ts b/dist/types/jwt/decrypt.d.ts new file mode 100644 index 0000000000..c7691d5bf0 --- /dev/null +++ b/dist/types/jwt/decrypt.d.ts @@ -0,0 +1,9 @@ +import type { KeyLike, DecryptOptions, JWTPayload, JWTClaimVerificationOptions, GetKeyFunction, JWEHeaderParameters, FlattenedJWE, JWTDecryptResult } from '../types'; +interface JWTDecryptOptions extends DecryptOptions, JWTClaimVerificationOptions { +} +export interface JWTDecryptGetKey extends GetKeyFunction { +} +declare function jwtDecrypt(jwt: string | Uint8Array, key: KeyLike | JWTDecryptGetKey, options?: JWTDecryptOptions): Promise; +export { jwtDecrypt }; +export default jwtDecrypt; +export type { KeyLike, DecryptOptions, JWTPayload, JWTDecryptOptions, JWTDecryptResult }; diff --git a/dist/types/jwt/encrypt.d.ts b/dist/types/jwt/encrypt.d.ts new file mode 100644 index 0000000000..e8cee000c0 --- /dev/null +++ b/dist/types/jwt/encrypt.d.ts @@ -0,0 +1,22 @@ +import type { EncryptOptions, JWEHeaderParameters, JWEKeyManagementHeaderParameters, JWTPayload, KeyLike } from '../types'; +import ProduceJWT from '../lib/jwt_producer'; +declare class EncryptJWT extends ProduceJWT { + private _cek; + private _iv; + private _keyManagementParameters; + private _protectedHeader; + private _replicateIssuerAsHeader; + private _replicateSubjectAsHeader; + private _replicateAudienceAsHeader; + setProtectedHeader(protectedHeader: JWEHeaderParameters): this; + setKeyManagementParameters(parameters: JWEKeyManagementHeaderParameters): this; + setContentEncryptionKey(cek: Uint8Array): this; + setInitializationVector(iv: Uint8Array): this; + replicateIssuerAsHeader(): this; + replicateSubjectAsHeader(): this; + replicateAudienceAsHeader(): this; + encrypt(key: KeyLike, options?: EncryptOptions): Promise; +} +export { EncryptJWT }; +export default EncryptJWT; +export type { JWEHeaderParameters, JWTPayload, KeyLike }; diff --git a/dist/types/jwt/sign.d.ts b/dist/types/jwt/sign.d.ts new file mode 100644 index 0000000000..8be5956803 --- /dev/null +++ b/dist/types/jwt/sign.d.ts @@ -0,0 +1,10 @@ +import type { JWSHeaderParameters, JWTPayload, KeyLike, SignOptions } from '../types'; +import ProduceJWT from '../lib/jwt_producer'; +declare class SignJWT extends ProduceJWT { + private _protectedHeader; + setProtectedHeader(protectedHeader: JWSHeaderParameters): this; + sign(key: KeyLike, options?: SignOptions): Promise; +} +export { SignJWT }; +export default SignJWT; +export type { JWSHeaderParameters, JWTPayload, KeyLike }; diff --git a/dist/types/jwt/unsecured.d.ts b/dist/types/jwt/unsecured.d.ts new file mode 100644 index 0000000000..c55f7c577e --- /dev/null +++ b/dist/types/jwt/unsecured.d.ts @@ -0,0 +1,13 @@ +import type { JWSHeaderParameters, JWTClaimVerificationOptions, JWTPayload } from '../types'; +import ProduceJWT from '../lib/jwt_producer'; +interface UnsecuredResult { + payload: JWTPayload; + header: JWSHeaderParameters; +} +declare class UnsecuredJWT extends ProduceJWT { + encode(): string; + static decode(jwt: string, options?: JWTClaimVerificationOptions): UnsecuredResult; +} +export { UnsecuredJWT }; +export default UnsecuredJWT; +export type { JWSHeaderParameters, JWTPayload, UnsecuredResult }; diff --git a/dist/types/jwt/verify.d.ts b/dist/types/jwt/verify.d.ts new file mode 100644 index 0000000000..0f23f77332 --- /dev/null +++ b/dist/types/jwt/verify.d.ts @@ -0,0 +1,9 @@ +import type { KeyLike, VerifyOptions, JWTPayload, JWTClaimVerificationOptions, JWSHeaderParameters, GetKeyFunction, FlattenedJWSInput, JWTVerifyResult } from '../types'; +interface JWTVerifyOptions extends VerifyOptions, JWTClaimVerificationOptions { +} +export interface JWTVerifyGetKey extends GetKeyFunction { +} +declare function jwtVerify(jwt: string | Uint8Array, key: KeyLike | JWTVerifyGetKey, options?: JWTVerifyOptions): Promise; +export { jwtVerify }; +export default jwtVerify; +export type { KeyLike, JWTPayload, JWTVerifyOptions, JWSHeaderParameters, GetKeyFunction, JWTVerifyResult, }; diff --git a/dist/types/lib/jwt_producer.d.ts b/dist/types/lib/jwt_producer.d.ts new file mode 100644 index 0000000000..2deef0a8c8 --- /dev/null +++ b/dist/types/lib/jwt_producer.d.ts @@ -0,0 +1,12 @@ +import type { JWTPayload } from '../types'; +export default class ProduceJWT { + protected _payload: JWTPayload; + constructor(payload: JWTPayload); + setIssuer(issuer: string): this; + setSubject(subject: string): this; + setAudience(audience: string | string[]): this; + setJti(jwtId: string): this; + setNotBefore(input: number | string): this; + setExpirationTime(input: number | string): this; + setIssuedAt(input?: number): this; +} diff --git a/dist/types/types.d.ts b/dist/types/types.d.ts new file mode 100644 index 0000000000..11c2b3ac91 --- /dev/null +++ b/dist/types/types.d.ts @@ -0,0 +1,171 @@ +/// +import type { KeyObject } from 'crypto' +export type { KeyObject } +export type KeyLike = KeyObject | CryptoKey | Uint8Array +export interface JWK { + alg?: string + crv?: string + d?: string + dp?: string + dq?: string + e?: string + ext?: boolean + k?: string + key_ops?: string[] + kid?: string + kty?: string + n?: string + oth?: Array<{ + d?: string + r?: string + t?: string + }> + p?: string + q?: string + qi?: string + use?: string + x?: string + y?: string + x5c?: string[] + x5t?: string + 'x5t#S256'?: string + x5u?: string + [propName: string]: unknown +} +export interface GetKeyFunction { + (protectedHeader: T, token: T2): Promise +} +export interface FlattenedJWSInput { + header?: JWSHeaderParameters + payload: string | Uint8Array + protected?: string + signature: string +} +export interface GeneralJWSInput { + payload: string | Uint8Array + signatures: Omit[] +} +export interface FlattenedJWS extends Partial { + payload: string + signature: string +} +export interface GeneralJWS { + payload: string + signatures: Omit[] +} +export interface JoseHeaderParameters { + kid?: string + x5t?: string + x5c?: string[] + x5u?: string + jku?: string + jwk?: Pick + typ?: string + cty?: string +} +export interface JWSHeaderParameters extends JoseHeaderParameters { + alg?: string + b64?: boolean + crit?: string[] + [propName: string]: unknown +} +export interface JWEKeyManagementHeaderParameters { + apu?: Uint8Array + apv?: Uint8Array + epk?: KeyLike + iv?: Uint8Array + p2c?: number + p2s?: Uint8Array +} +export interface FlattenedJWE { + aad?: string + ciphertext: string + encrypted_key?: string + header?: JWEHeaderParameters + iv: string + protected?: string + tag: string + unprotected?: JWEHeaderParameters +} +export interface GeneralJWE extends Omit { + recipients: Pick[] +} +export interface JWEHeaderParameters extends JoseHeaderParameters { + alg?: string + enc?: string + crit?: string[] + zip?: string + [propName: string]: unknown +} +export interface CritOption { + crit?: { + [propName: string]: boolean + } +} +export interface DecryptOptions extends CritOption { + keyManagementAlgorithms?: string[] + contentEncryptionAlgorithms?: string[] + inflateRaw?: InflateFunction +} +export interface EncryptOptions extends CritOption { + deflateRaw?: DeflateFunction +} +export interface JWTClaimVerificationOptions { + audience?: string | string[] + clockTolerance?: string | number + issuer?: string | string[] + maxTokenAge?: string | number + subject?: string + typ?: string + currentDate?: Date +} +export interface VerifyOptions extends CritOption { + algorithms?: string[] +} +export interface SignOptions extends CritOption {} +export interface JWTPayload { + iss?: string + sub?: string + aud?: string | string[] + jti?: string + nbf?: number + exp?: number + iat?: number + [propName: string]: unknown +} +export interface DeflateFunction { + (input: Uint8Array): Promise +} +export interface InflateFunction { + (input: Uint8Array): Promise +} +export interface FlattenedDecryptResult { + additionalAuthenticatedData?: Uint8Array + plaintext: Uint8Array + protectedHeader?: JWEHeaderParameters + sharedUnprotectedHeader?: JWEHeaderParameters + unprotectedHeader?: JWEHeaderParameters +} +export interface GeneralDecryptResult extends FlattenedDecryptResult {} +export interface CompactDecryptResult { + plaintext: Uint8Array + protectedHeader: JWEHeaderParameters +} +export interface FlattenedVerifyResult { + payload: Uint8Array + protectedHeader?: JWSHeaderParameters + unprotectedHeader?: JWSHeaderParameters +} +export interface GeneralVerifyResult extends FlattenedVerifyResult {} +export interface CompactVerifyResult { + payload: Uint8Array + protectedHeader: JWSHeaderParameters +} +export interface JWTVerifyResult { + payload: JWTPayload + protectedHeader: JWSHeaderParameters +} +export interface JWTDecryptResult { + payload: JWTPayload + protectedHeader: JWEHeaderParameters +} diff --git a/dist/types/util/base64url.d.ts b/dist/types/util/base64url.d.ts new file mode 100644 index 0000000000..016c96128a --- /dev/null +++ b/dist/types/util/base64url.d.ts @@ -0,0 +1,9 @@ +interface Base64UrlEncode { + (input: Uint8Array | string): string; +} +interface Base64UrlDecode { + (input: Uint8Array | string): Uint8Array; +} +export declare const encode: Base64UrlEncode; +export declare const decode: Base64UrlDecode; +export {}; diff --git a/dist/types/util/decode_protected_header.d.ts b/dist/types/util/decode_protected_header.d.ts new file mode 100644 index 0000000000..c77304ff9d --- /dev/null +++ b/dist/types/util/decode_protected_header.d.ts @@ -0,0 +1,5 @@ +import type { JWSHeaderParameters, JWEHeaderParameters } from '../types'; +export declare type ProtectedHeaderParameters = JWSHeaderParameters & JWEHeaderParameters; +declare function decodeProtectedHeader(token: string | object): ProtectedHeaderParameters; +export { decodeProtectedHeader }; +export default decodeProtectedHeader; diff --git a/dist/types/util/errors.d.ts b/dist/types/util/errors.d.ts new file mode 100644 index 0000000000..48fb822ce7 --- /dev/null +++ b/dist/types/util/errors.d.ts @@ -0,0 +1,64 @@ +export declare class JOSEError extends Error { + static code: string; + code: string; + constructor(message?: string); +} +export declare class JWTClaimValidationFailed extends JOSEError { + static code: string; + code: string; + claim: string; + reason: string; + constructor(message: string, claim?: string, reason?: string); +} +export declare class JOSEAlgNotAllowed extends JOSEError { + static code: string; + code: string; +} +export declare class JOSENotSupported extends JOSEError { + static code: string; + code: string; +} +export declare class JWEDecryptionFailed extends JOSEError { + static code: string; + code: string; + message: string; +} +export declare class JWEInvalid extends JOSEError { + static code: string; + code: string; +} +export declare class JWSInvalid extends JOSEError { + static code: string; + code: string; +} +export declare class JWTInvalid extends JOSEError { + static code: string; + code: string; +} +export declare class JWKInvalid extends JOSEError { + static code: string; + code: string; +} +export declare class JWKSInvalid extends JOSEError { + static code: string; + code: string; +} +export declare class JWKSNoMatchingKey extends JOSEError { + static code: string; + code: string; + message: string; +} +export declare class JWKSMultipleMatchingKeys extends JOSEError { + static code: string; + code: string; + message: string; +} +export declare class JWSSignatureVerificationFailed extends JOSEError { + static code: string; + code: string; + message: string; +} +export declare class JWTExpired extends JWTClaimValidationFailed { + static code: string; + code: string; +} diff --git a/dist/types/util/generate_key_pair.d.ts b/dist/types/util/generate_key_pair.d.ts new file mode 100644 index 0000000000..d2564ecb80 --- /dev/null +++ b/dist/types/util/generate_key_pair.d.ts @@ -0,0 +1,13 @@ +import type { KeyLike } from '../types'; +export interface GenerateKeyPairResult { + privateKey: Exclude; + publicKey: Exclude; +} +export interface GenerateKeyPairOptions { + crv?: string; + modulusLength?: number; + extractable?: boolean; +} +declare function generateKeyPair(alg: string, options?: GenerateKeyPairOptions): Promise; +export { generateKeyPair }; +export default generateKeyPair; diff --git a/dist/types/util/generate_secret.d.ts b/dist/types/util/generate_secret.d.ts new file mode 100644 index 0000000000..c2673d6a96 --- /dev/null +++ b/dist/types/util/generate_secret.d.ts @@ -0,0 +1,7 @@ +import type { KeyLike } from '../types'; +export interface GenerateSecretOptions { + extractable?: boolean; +} +declare function generateSecret(alg: string, options?: GenerateSecretOptions): Promise; +export { generateSecret }; +export default generateSecret; diff --git a/dist/types/util/random.d.ts b/dist/types/util/random.d.ts new file mode 100644 index 0000000000..db1d0971d4 --- /dev/null +++ b/dist/types/util/random.d.ts @@ -0,0 +1,6 @@ +interface GetRandomValuesFunction { + (array: Uint8Array): Uint8Array; +} +declare const random: GetRandomValuesFunction; +export { random }; +export default random; diff --git a/docs/classes/jwe_compact_encrypt.CompactEncrypt.md b/docs/classes/jwe_compact_encrypt.CompactEncrypt.md index 21e18f6560..106935152b 100644 --- a/docs/classes/jwe_compact_encrypt.CompactEncrypt.md +++ b/docs/classes/jwe_compact_encrypt.CompactEncrypt.md @@ -16,7 +16,7 @@ const { CompactEncrypt } = require('jose/jwe/compact/encrypt') **`example`** Deno import ```js -import { CompactEncrypt } from 'https://deno.land/x/jose@v3.16.0/jwe/compact/encrypt.ts' +import { CompactEncrypt } from 'https://deno.land/x/jose@v3.16.1/jwe/compact/encrypt.ts' ``` **`example`** Usage @@ -58,7 +58,7 @@ console.log(jwe) #### Defined in -[jwe/compact/encrypt.ts:44](https://github.com/panva/jose/blob/v3.16.0/src/jwe/compact/encrypt.ts#L44) +[jwe/compact/encrypt.ts:44](https://github.com/panva/jose/blob/v3.16.1/src/jwe/compact/encrypt.ts#L44) ## Methods @@ -81,7 +81,7 @@ Encrypts and resolves the value of the Compact JWE string. #### Defined in -[jwe/compact/encrypt.ts:102](https://github.com/panva/jose/blob/v3.16.0/src/jwe/compact/encrypt.ts#L102) +[jwe/compact/encrypt.ts:102](https://github.com/panva/jose/blob/v3.16.1/src/jwe/compact/encrypt.ts#L102) ___ @@ -106,7 +106,7 @@ test and vector validation purposes. #### Defined in -[jwe/compact/encrypt.ts:56](https://github.com/panva/jose/blob/v3.16.0/src/jwe/compact/encrypt.ts#L56) +[jwe/compact/encrypt.ts:56](https://github.com/panva/jose/blob/v3.16.1/src/jwe/compact/encrypt.ts#L56) ___ @@ -131,7 +131,7 @@ intended for test and vector validation purposes. #### Defined in -[jwe/compact/encrypt.ts:69](https://github.com/panva/jose/blob/v3.16.0/src/jwe/compact/encrypt.ts#L69) +[jwe/compact/encrypt.ts:69](https://github.com/panva/jose/blob/v3.16.1/src/jwe/compact/encrypt.ts#L69) ___ @@ -155,7 +155,7 @@ intended for test and vector validation purposes. #### Defined in -[jwe/compact/encrypt.ts:91](https://github.com/panva/jose/blob/v3.16.0/src/jwe/compact/encrypt.ts#L91) +[jwe/compact/encrypt.ts:91](https://github.com/panva/jose/blob/v3.16.1/src/jwe/compact/encrypt.ts#L91) ___ @@ -177,4 +177,4 @@ Sets the JWE Protected Header on the CompactEncrypt object. #### Defined in -[jwe/compact/encrypt.ts:79](https://github.com/panva/jose/blob/v3.16.0/src/jwe/compact/encrypt.ts#L79) +[jwe/compact/encrypt.ts:79](https://github.com/panva/jose/blob/v3.16.1/src/jwe/compact/encrypt.ts#L79) diff --git a/docs/classes/jwe_flattened_encrypt.FlattenedEncrypt.md b/docs/classes/jwe_flattened_encrypt.FlattenedEncrypt.md index 50b87246c2..61881d07f2 100644 --- a/docs/classes/jwe_flattened_encrypt.FlattenedEncrypt.md +++ b/docs/classes/jwe_flattened_encrypt.FlattenedEncrypt.md @@ -17,7 +17,7 @@ const { FlattenedEncrypt } = require('jose/jwe/flattened/encrypt') **`example`** Deno import ```js -import { FlattenedEncrypt } from 'https://deno.land/x/jose@v3.16.0/jwe/flattened/encrypt.ts' +import { FlattenedEncrypt } from 'https://deno.land/x/jose@v3.16.1/jwe/flattened/encrypt.ts' ``` **`example`** Usage @@ -63,7 +63,7 @@ console.log(jwe) #### Defined in -[jwe/flattened/encrypt.ts:75](https://github.com/panva/jose/blob/v3.16.0/src/jwe/flattened/encrypt.ts#L75) +[jwe/flattened/encrypt.ts:75](https://github.com/panva/jose/blob/v3.16.1/src/jwe/flattened/encrypt.ts#L75) ## Methods @@ -86,7 +86,7 @@ Encrypts and resolves the value of the Flattened JWE object. #### Defined in -[jwe/flattened/encrypt.ts:182](https://github.com/panva/jose/blob/v3.16.0/src/jwe/flattened/encrypt.ts#L182) +[jwe/flattened/encrypt.ts:185](https://github.com/panva/jose/blob/v3.16.1/src/jwe/flattened/encrypt.ts#L185) ___ @@ -108,7 +108,7 @@ Sets the Additional Authenticated Data on the FlattenedEncrypt object. #### Defined in -[jwe/flattened/encrypt.ts:139](https://github.com/panva/jose/blob/v3.16.0/src/jwe/flattened/encrypt.ts#L139) +[jwe/flattened/encrypt.ts:142](https://github.com/panva/jose/blob/v3.16.1/src/jwe/flattened/encrypt.ts#L142) ___ @@ -133,7 +133,7 @@ test and vector validation purposes. #### Defined in -[jwe/flattened/encrypt.ts:152](https://github.com/panva/jose/blob/v3.16.0/src/jwe/flattened/encrypt.ts#L152) +[jwe/flattened/encrypt.ts:155](https://github.com/panva/jose/blob/v3.16.1/src/jwe/flattened/encrypt.ts#L155) ___ @@ -158,7 +158,7 @@ intended for test and vector validation purposes. #### Defined in -[jwe/flattened/encrypt.ts:168](https://github.com/panva/jose/blob/v3.16.0/src/jwe/flattened/encrypt.ts#L168) +[jwe/flattened/encrypt.ts:171](https://github.com/panva/jose/blob/v3.16.1/src/jwe/flattened/encrypt.ts#L171) ___ @@ -183,7 +183,7 @@ Other parameters will always be randomly generated when needed and missing. #### Defined in -[jwe/flattened/encrypt.ts:87](https://github.com/panva/jose/blob/v3.16.0/src/jwe/flattened/encrypt.ts#L87) +[jwe/flattened/encrypt.ts:90](https://github.com/panva/jose/blob/v3.16.1/src/jwe/flattened/encrypt.ts#L90) ___ @@ -205,7 +205,7 @@ Sets the JWE Protected Header on the FlattenedEncrypt object. #### Defined in -[jwe/flattened/encrypt.ts:100](https://github.com/panva/jose/blob/v3.16.0/src/jwe/flattened/encrypt.ts#L100) +[jwe/flattened/encrypt.ts:103](https://github.com/panva/jose/blob/v3.16.1/src/jwe/flattened/encrypt.ts#L103) ___ @@ -227,7 +227,7 @@ Sets the JWE Shared Unprotected Header on the FlattenedEncrypt object. #### Defined in -[jwe/flattened/encrypt.ts:113](https://github.com/panva/jose/blob/v3.16.0/src/jwe/flattened/encrypt.ts#L113) +[jwe/flattened/encrypt.ts:116](https://github.com/panva/jose/blob/v3.16.1/src/jwe/flattened/encrypt.ts#L116) ___ @@ -249,4 +249,4 @@ Sets the JWE Per-Recipient Unprotected Header on the FlattenedEncrypt object. #### Defined in -[jwe/flattened/encrypt.ts:126](https://github.com/panva/jose/blob/v3.16.0/src/jwe/flattened/encrypt.ts#L126) +[jwe/flattened/encrypt.ts:129](https://github.com/panva/jose/blob/v3.16.1/src/jwe/flattened/encrypt.ts#L129) diff --git a/docs/classes/jws_compact_sign.CompactSign.md b/docs/classes/jws_compact_sign.CompactSign.md index 97e0f86d42..a6d4328ab1 100644 --- a/docs/classes/jws_compact_sign.CompactSign.md +++ b/docs/classes/jws_compact_sign.CompactSign.md @@ -16,7 +16,7 @@ const { CompactSign } = require('jose/jws/compact/sign') **`example`** Deno import ```js -import { CompactSign } from 'https://deno.land/x/jose@v3.16.0/jws/compact/sign.ts' +import { CompactSign } from 'https://deno.land/x/jose@v3.16.1/jws/compact/sign.ts' ``` **`example`** Usage @@ -55,7 +55,7 @@ console.log(jws) #### Defined in -[jws/compact/sign.ts:39](https://github.com/panva/jose/blob/v3.16.0/src/jws/compact/sign.ts#L39) +[jws/compact/sign.ts:39](https://github.com/panva/jose/blob/v3.16.1/src/jws/compact/sign.ts#L39) ## Methods @@ -77,7 +77,7 @@ Sets the JWS Protected Header on the Sign object. #### Defined in -[jws/compact/sign.ts:48](https://github.com/panva/jose/blob/v3.16.0/src/jws/compact/sign.ts#L48) +[jws/compact/sign.ts:48](https://github.com/panva/jose/blob/v3.16.1/src/jws/compact/sign.ts#L48) ___ @@ -100,4 +100,4 @@ Signs and resolves the value of the Compact JWS string. #### Defined in -[jws/compact/sign.ts:59](https://github.com/panva/jose/blob/v3.16.0/src/jws/compact/sign.ts#L59) +[jws/compact/sign.ts:59](https://github.com/panva/jose/blob/v3.16.1/src/jws/compact/sign.ts#L59) diff --git a/docs/classes/jws_flattened_sign.FlattenedSign.md b/docs/classes/jws_flattened_sign.FlattenedSign.md index cc73c5b1b4..a832db1953 100644 --- a/docs/classes/jws_flattened_sign.FlattenedSign.md +++ b/docs/classes/jws_flattened_sign.FlattenedSign.md @@ -16,7 +16,7 @@ const { FlattenedSign } = require('jose/jws/flattened/sign') **`example`** Deno import ```js -import { FlattenedSign } from 'https://deno.land/x/jose@v3.16.0/jws/flattened/sign.ts' +import { FlattenedSign } from 'https://deno.land/x/jose@v3.16.1/jws/flattened/sign.ts' ``` **`example`** Usage @@ -55,7 +55,7 @@ console.log(jws) #### Defined in -[jws/flattened/sign.ts:51](https://github.com/panva/jose/blob/v3.16.0/src/jws/flattened/sign.ts#L51) +[jws/flattened/sign.ts:51](https://github.com/panva/jose/blob/v3.16.1/src/jws/flattened/sign.ts#L51) ## Methods @@ -77,7 +77,7 @@ Sets the JWS Protected Header on the FlattenedSign object. #### Defined in -[jws/flattened/sign.ts:60](https://github.com/panva/jose/blob/v3.16.0/src/jws/flattened/sign.ts#L60) +[jws/flattened/sign.ts:63](https://github.com/panva/jose/blob/v3.16.1/src/jws/flattened/sign.ts#L63) ___ @@ -99,7 +99,7 @@ Sets the JWS Unprotected Header on the FlattenedSign object. #### Defined in -[jws/flattened/sign.ts:73](https://github.com/panva/jose/blob/v3.16.0/src/jws/flattened/sign.ts#L73) +[jws/flattened/sign.ts:76](https://github.com/panva/jose/blob/v3.16.1/src/jws/flattened/sign.ts#L76) ___ @@ -122,4 +122,4 @@ Signs and resolves the value of the Flattened JWS object. #### Defined in -[jws/flattened/sign.ts:87](https://github.com/panva/jose/blob/v3.16.0/src/jws/flattened/sign.ts#L87) +[jws/flattened/sign.ts:90](https://github.com/panva/jose/blob/v3.16.1/src/jws/flattened/sign.ts#L90) diff --git a/docs/classes/jws_general_sign.GeneralSign.md b/docs/classes/jws_general_sign.GeneralSign.md index eb42b9bdf6..00a9cbf874 100644 --- a/docs/classes/jws_general_sign.GeneralSign.md +++ b/docs/classes/jws_general_sign.GeneralSign.md @@ -16,7 +16,7 @@ const { GeneralSign } = require('jose/jws/general/sign') **`example`** Deno import ```js -import { GeneralSign } from 'https://deno.land/x/jose@v3.16.0/jws/general/sign.ts' +import { GeneralSign } from 'https://deno.land/x/jose@v3.16.1/jws/general/sign.ts' ``` **`example`** Usage @@ -61,7 +61,7 @@ const jws = await sign.sign() #### Defined in -[jws/general/sign.ts:108](https://github.com/panva/jose/blob/v3.16.0/src/jws/general/sign.ts#L108) +[jws/general/sign.ts:108](https://github.com/panva/jose/blob/v3.16.1/src/jws/general/sign.ts#L108) ## Methods @@ -82,7 +82,7 @@ const jws = await sign.sign() #### Defined in -[jws/general/sign.ts:112](https://github.com/panva/jose/blob/v3.16.0/src/jws/general/sign.ts#L112) +[jws/general/sign.ts:112](https://github.com/panva/jose/blob/v3.16.1/src/jws/general/sign.ts#L112) ___ @@ -98,4 +98,4 @@ Signs and resolves the value of the General JWS object. #### Defined in -[jws/general/sign.ts:122](https://github.com/panva/jose/blob/v3.16.0/src/jws/general/sign.ts#L122) +[jws/general/sign.ts:122](https://github.com/panva/jose/blob/v3.16.1/src/jws/general/sign.ts#L122) diff --git a/docs/classes/jwt_encrypt.EncryptJWT.md b/docs/classes/jwt_encrypt.EncryptJWT.md index 97be161a71..2af711d866 100644 --- a/docs/classes/jwt_encrypt.EncryptJWT.md +++ b/docs/classes/jwt_encrypt.EncryptJWT.md @@ -16,7 +16,7 @@ const { EncryptJWT } = require('jose/jwt/encrypt') **`example`** Deno import ```js -import { EncryptJWT } from 'https://deno.land/x/jose@v3.16.0/jwt/encrypt.ts' +import { EncryptJWT } from 'https://deno.land/x/jose@v3.16.1/jwt/encrypt.ts' ``` **`example`** Usage @@ -80,7 +80,7 @@ ProduceJWT.constructor #### Defined in -[lib/jwt_producer.ts:15](https://github.com/panva/jose/blob/v3.16.0/src/lib/jwt_producer.ts#L15) +[lib/jwt_producer.ts:15](https://github.com/panva/jose/blob/v3.16.1/src/lib/jwt_producer.ts#L15) ## Methods @@ -103,7 +103,7 @@ Encrypts and returns the JWT. #### Defined in -[jwt/encrypt.ts:154](https://github.com/panva/jose/blob/v3.16.0/src/jwt/encrypt.ts#L154) +[jwt/encrypt.ts:154](https://github.com/panva/jose/blob/v3.16.1/src/jwt/encrypt.ts#L154) ___ @@ -120,7 +120,7 @@ Replicates the "aud" (Audience) Claim as a JWE Protected Header Parameter as per #### Defined in -[jwt/encrypt.ts:143](https://github.com/panva/jose/blob/v3.16.0/src/jwt/encrypt.ts#L143) +[jwt/encrypt.ts:143](https://github.com/panva/jose/blob/v3.16.1/src/jwt/encrypt.ts#L143) ___ @@ -137,7 +137,7 @@ Replicates the "iss" (Issuer) Claim as a JWE Protected Header Parameter as per #### Defined in -[jwt/encrypt.ts:125](https://github.com/panva/jose/blob/v3.16.0/src/jwt/encrypt.ts#L125) +[jwt/encrypt.ts:125](https://github.com/panva/jose/blob/v3.16.1/src/jwt/encrypt.ts#L125) ___ @@ -154,7 +154,7 @@ Replicates the "sub" (Subject) Claim as a JWE Protected Header Parameter as per #### Defined in -[jwt/encrypt.ts:134](https://github.com/panva/jose/blob/v3.16.0/src/jwt/encrypt.ts#L134) +[jwt/encrypt.ts:134](https://github.com/panva/jose/blob/v3.16.1/src/jwt/encrypt.ts#L134) ___ @@ -180,7 +180,7 @@ ProduceJWT.setAudience #### Defined in -[lib/jwt_producer.ts:47](https://github.com/panva/jose/blob/v3.16.0/src/lib/jwt_producer.ts#L47) +[lib/jwt_producer.ts:47](https://github.com/panva/jose/blob/v3.16.1/src/lib/jwt_producer.ts#L47) ___ @@ -205,7 +205,7 @@ test and vector validation purposes. #### Defined in -[jwt/encrypt.ts:97](https://github.com/panva/jose/blob/v3.16.0/src/jwt/encrypt.ts#L97) +[jwt/encrypt.ts:97](https://github.com/panva/jose/blob/v3.16.1/src/jwt/encrypt.ts#L97) ___ @@ -231,7 +231,7 @@ ProduceJWT.setExpirationTime #### Defined in -[lib/jwt_producer.ts:85](https://github.com/panva/jose/blob/v3.16.0/src/lib/jwt_producer.ts#L85) +[lib/jwt_producer.ts:85](https://github.com/panva/jose/blob/v3.16.1/src/lib/jwt_producer.ts#L85) ___ @@ -256,7 +256,7 @@ intended for test and vector validation purposes. #### Defined in -[jwt/encrypt.ts:113](https://github.com/panva/jose/blob/v3.16.0/src/jwt/encrypt.ts#L113) +[jwt/encrypt.ts:113](https://github.com/panva/jose/blob/v3.16.1/src/jwt/encrypt.ts#L113) ___ @@ -282,7 +282,7 @@ ProduceJWT.setIssuedAt #### Defined in -[lib/jwt_producer.ts:100](https://github.com/panva/jose/blob/v3.16.0/src/lib/jwt_producer.ts#L100) +[lib/jwt_producer.ts:100](https://github.com/panva/jose/blob/v3.16.1/src/lib/jwt_producer.ts#L100) ___ @@ -308,7 +308,7 @@ ProduceJWT.setIssuer #### Defined in -[lib/jwt_producer.ts:27](https://github.com/panva/jose/blob/v3.16.0/src/lib/jwt_producer.ts#L27) +[lib/jwt_producer.ts:27](https://github.com/panva/jose/blob/v3.16.1/src/lib/jwt_producer.ts#L27) ___ @@ -334,7 +334,7 @@ ProduceJWT.setJti #### Defined in -[lib/jwt_producer.ts:57](https://github.com/panva/jose/blob/v3.16.0/src/lib/jwt_producer.ts#L57) +[lib/jwt_producer.ts:57](https://github.com/panva/jose/blob/v3.16.1/src/lib/jwt_producer.ts#L57) ___ @@ -359,7 +359,7 @@ Other parameters will always be randomly generated when needed and missing. #### Defined in -[jwt/encrypt.ts:81](https://github.com/panva/jose/blob/v3.16.0/src/jwt/encrypt.ts#L81) +[jwt/encrypt.ts:81](https://github.com/panva/jose/blob/v3.16.1/src/jwt/encrypt.ts#L81) ___ @@ -385,7 +385,7 @@ ProduceJWT.setNotBefore #### Defined in -[lib/jwt_producer.ts:69](https://github.com/panva/jose/blob/v3.16.0/src/lib/jwt_producer.ts#L69) +[lib/jwt_producer.ts:69](https://github.com/panva/jose/blob/v3.16.1/src/lib/jwt_producer.ts#L69) ___ @@ -407,7 +407,7 @@ Sets the JWE Protected Header on the EncryptJWT object. #### Defined in -[jwt/encrypt.ts:65](https://github.com/panva/jose/blob/v3.16.0/src/jwt/encrypt.ts#L65) +[jwt/encrypt.ts:65](https://github.com/panva/jose/blob/v3.16.1/src/jwt/encrypt.ts#L65) ___ @@ -433,4 +433,4 @@ ProduceJWT.setSubject #### Defined in -[lib/jwt_producer.ts:37](https://github.com/panva/jose/blob/v3.16.0/src/lib/jwt_producer.ts#L37) +[lib/jwt_producer.ts:37](https://github.com/panva/jose/blob/v3.16.1/src/lib/jwt_producer.ts#L37) diff --git a/docs/classes/jwt_sign.SignJWT.md b/docs/classes/jwt_sign.SignJWT.md index 9cd9952eac..f540d4c135 100644 --- a/docs/classes/jwt_sign.SignJWT.md +++ b/docs/classes/jwt_sign.SignJWT.md @@ -16,7 +16,7 @@ const { SignJWT } = require('jose/jwt/sign') **`example`** Deno import ```js -import { SignJWT } from 'https://deno.land/x/jose@v3.16.0/jwt/sign.ts' +import { SignJWT } from 'https://deno.land/x/jose@v3.16.1/jwt/sign.ts' ``` **`example`** Usage @@ -74,7 +74,7 @@ ProduceJWT.constructor #### Defined in -[lib/jwt_producer.ts:15](https://github.com/panva/jose/blob/v3.16.0/src/lib/jwt_producer.ts#L15) +[lib/jwt_producer.ts:15](https://github.com/panva/jose/blob/v3.16.1/src/lib/jwt_producer.ts#L15) ## Methods @@ -100,7 +100,7 @@ ProduceJWT.setAudience #### Defined in -[lib/jwt_producer.ts:47](https://github.com/panva/jose/blob/v3.16.0/src/lib/jwt_producer.ts#L47) +[lib/jwt_producer.ts:47](https://github.com/panva/jose/blob/v3.16.1/src/lib/jwt_producer.ts#L47) ___ @@ -126,7 +126,7 @@ ProduceJWT.setExpirationTime #### Defined in -[lib/jwt_producer.ts:85](https://github.com/panva/jose/blob/v3.16.0/src/lib/jwt_producer.ts#L85) +[lib/jwt_producer.ts:85](https://github.com/panva/jose/blob/v3.16.1/src/lib/jwt_producer.ts#L85) ___ @@ -152,7 +152,7 @@ ProduceJWT.setIssuedAt #### Defined in -[lib/jwt_producer.ts:100](https://github.com/panva/jose/blob/v3.16.0/src/lib/jwt_producer.ts#L100) +[lib/jwt_producer.ts:100](https://github.com/panva/jose/blob/v3.16.1/src/lib/jwt_producer.ts#L100) ___ @@ -178,7 +178,7 @@ ProduceJWT.setIssuer #### Defined in -[lib/jwt_producer.ts:27](https://github.com/panva/jose/blob/v3.16.0/src/lib/jwt_producer.ts#L27) +[lib/jwt_producer.ts:27](https://github.com/panva/jose/blob/v3.16.1/src/lib/jwt_producer.ts#L27) ___ @@ -204,7 +204,7 @@ ProduceJWT.setJti #### Defined in -[lib/jwt_producer.ts:57](https://github.com/panva/jose/blob/v3.16.0/src/lib/jwt_producer.ts#L57) +[lib/jwt_producer.ts:57](https://github.com/panva/jose/blob/v3.16.1/src/lib/jwt_producer.ts#L57) ___ @@ -230,7 +230,7 @@ ProduceJWT.setNotBefore #### Defined in -[lib/jwt_producer.ts:69](https://github.com/panva/jose/blob/v3.16.0/src/lib/jwt_producer.ts#L69) +[lib/jwt_producer.ts:69](https://github.com/panva/jose/blob/v3.16.1/src/lib/jwt_producer.ts#L69) ___ @@ -252,7 +252,7 @@ Sets the JWS Protected Header on the SignJWT object. #### Defined in -[jwt/sign.ts:46](https://github.com/panva/jose/blob/v3.16.0/src/jwt/sign.ts#L46) +[jwt/sign.ts:46](https://github.com/panva/jose/blob/v3.16.1/src/jwt/sign.ts#L46) ___ @@ -278,7 +278,7 @@ ProduceJWT.setSubject #### Defined in -[lib/jwt_producer.ts:37](https://github.com/panva/jose/blob/v3.16.0/src/lib/jwt_producer.ts#L37) +[lib/jwt_producer.ts:37](https://github.com/panva/jose/blob/v3.16.1/src/lib/jwt_producer.ts#L37) ___ @@ -301,4 +301,4 @@ Signs and returns the JWT. #### Defined in -[jwt/sign.ts:57](https://github.com/panva/jose/blob/v3.16.0/src/jwt/sign.ts#L57) +[jwt/sign.ts:57](https://github.com/panva/jose/blob/v3.16.1/src/jwt/sign.ts#L57) diff --git a/docs/classes/jwt_unsecured.UnsecuredJWT.md b/docs/classes/jwt_unsecured.UnsecuredJWT.md index f5b1e615f4..3b27b7c019 100644 --- a/docs/classes/jwt_unsecured.UnsecuredJWT.md +++ b/docs/classes/jwt_unsecured.UnsecuredJWT.md @@ -16,7 +16,7 @@ const { UnsecuredJWT } = require('jose/jwt/unsecured') **`example`** Deno import ```js -import { UnsecuredJWT } from 'https://deno.land/x/jose@v3.16.0/jwt/unsecured.ts' +import { UnsecuredJWT } from 'https://deno.land/x/jose@v3.16.1/jwt/unsecured.ts' ``` **`example`** Encoding @@ -83,7 +83,7 @@ ProduceJWT.constructor #### Defined in -[lib/jwt_producer.ts:15](https://github.com/panva/jose/blob/v3.16.0/src/lib/jwt_producer.ts#L15) +[lib/jwt_producer.ts:15](https://github.com/panva/jose/blob/v3.16.1/src/lib/jwt_producer.ts#L15) ## Methods @@ -99,7 +99,7 @@ Encodes the Unsecured JWT. #### Defined in -[jwt/unsecured.ts:57](https://github.com/panva/jose/blob/v3.16.0/src/jwt/unsecured.ts#L57) +[jwt/unsecured.ts:57](https://github.com/panva/jose/blob/v3.16.1/src/jwt/unsecured.ts#L57) ___ @@ -125,7 +125,7 @@ ProduceJWT.setAudience #### Defined in -[lib/jwt_producer.ts:47](https://github.com/panva/jose/blob/v3.16.0/src/lib/jwt_producer.ts#L47) +[lib/jwt_producer.ts:47](https://github.com/panva/jose/blob/v3.16.1/src/lib/jwt_producer.ts#L47) ___ @@ -151,7 +151,7 @@ ProduceJWT.setExpirationTime #### Defined in -[lib/jwt_producer.ts:85](https://github.com/panva/jose/blob/v3.16.0/src/lib/jwt_producer.ts#L85) +[lib/jwt_producer.ts:85](https://github.com/panva/jose/blob/v3.16.1/src/lib/jwt_producer.ts#L85) ___ @@ -177,7 +177,7 @@ ProduceJWT.setIssuedAt #### Defined in -[lib/jwt_producer.ts:100](https://github.com/panva/jose/blob/v3.16.0/src/lib/jwt_producer.ts#L100) +[lib/jwt_producer.ts:100](https://github.com/panva/jose/blob/v3.16.1/src/lib/jwt_producer.ts#L100) ___ @@ -203,7 +203,7 @@ ProduceJWT.setIssuer #### Defined in -[lib/jwt_producer.ts:27](https://github.com/panva/jose/blob/v3.16.0/src/lib/jwt_producer.ts#L27) +[lib/jwt_producer.ts:27](https://github.com/panva/jose/blob/v3.16.1/src/lib/jwt_producer.ts#L27) ___ @@ -229,7 +229,7 @@ ProduceJWT.setJti #### Defined in -[lib/jwt_producer.ts:57](https://github.com/panva/jose/blob/v3.16.0/src/lib/jwt_producer.ts#L57) +[lib/jwt_producer.ts:57](https://github.com/panva/jose/blob/v3.16.1/src/lib/jwt_producer.ts#L57) ___ @@ -255,7 +255,7 @@ ProduceJWT.setNotBefore #### Defined in -[lib/jwt_producer.ts:69](https://github.com/panva/jose/blob/v3.16.0/src/lib/jwt_producer.ts#L69) +[lib/jwt_producer.ts:69](https://github.com/panva/jose/blob/v3.16.1/src/lib/jwt_producer.ts#L69) ___ @@ -281,7 +281,7 @@ ProduceJWT.setSubject #### Defined in -[lib/jwt_producer.ts:37](https://github.com/panva/jose/blob/v3.16.0/src/lib/jwt_producer.ts#L37) +[lib/jwt_producer.ts:37](https://github.com/panva/jose/blob/v3.16.1/src/lib/jwt_producer.ts#L37) ___ @@ -304,4 +304,4 @@ Decodes an unsecured JWT. #### Defined in -[jwt/unsecured.ts:70](https://github.com/panva/jose/blob/v3.16.0/src/jwt/unsecured.ts#L70) +[jwt/unsecured.ts:70](https://github.com/panva/jose/blob/v3.16.1/src/jwt/unsecured.ts#L70) diff --git a/docs/classes/util_errors.JOSEAlgNotAllowed.md b/docs/classes/util_errors.JOSEAlgNotAllowed.md index 883acbb0f3..6c5baceed7 100644 --- a/docs/classes/util_errors.JOSEAlgNotAllowed.md +++ b/docs/classes/util_errors.JOSEAlgNotAllowed.md @@ -39,7 +39,7 @@ An error subclass thrown when a JOSE Algorithm is not allowed per developer pref #### Defined in -[util/errors.ts:16](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L16) +[util/errors.ts:16](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L16) ## Properties @@ -55,7 +55,7 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:56](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L56) +[util/errors.ts:56](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L56) ___ @@ -71,4 +71,4 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:54](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L54) +[util/errors.ts:54](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L54) diff --git a/docs/classes/util_errors.JOSEError.md b/docs/classes/util_errors.JOSEError.md index 37cf2c3797..2ca492c214 100644 --- a/docs/classes/util_errors.JOSEError.md +++ b/docs/classes/util_errors.JOSEError.md @@ -64,7 +64,7 @@ Error.constructor #### Defined in -[util/errors.ts:16](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L16) +[util/errors.ts:16](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L16) ## Properties @@ -76,7 +76,7 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:14](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L14) +[util/errors.ts:14](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L14) ___ @@ -88,4 +88,4 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:9](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L9) +[util/errors.ts:9](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L9) diff --git a/docs/classes/util_errors.JOSENotSupported.md b/docs/classes/util_errors.JOSENotSupported.md index f996bc0ab8..d599025318 100644 --- a/docs/classes/util_errors.JOSENotSupported.md +++ b/docs/classes/util_errors.JOSENotSupported.md @@ -40,7 +40,7 @@ implementation or JOSE in general. #### Defined in -[util/errors.ts:16](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L16) +[util/errors.ts:16](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L16) ## Properties @@ -56,7 +56,7 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:66](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L66) +[util/errors.ts:66](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L66) ___ @@ -72,4 +72,4 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:64](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L64) +[util/errors.ts:64](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L64) diff --git a/docs/classes/util_errors.JWEDecryptionFailed.md b/docs/classes/util_errors.JWEDecryptionFailed.md index 3fcb999ff0..16b498571e 100644 --- a/docs/classes/util_errors.JWEDecryptionFailed.md +++ b/docs/classes/util_errors.JWEDecryptionFailed.md @@ -40,7 +40,7 @@ An error subclass thrown when a JWE ciphertext decryption fails. #### Defined in -[util/errors.ts:16](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L16) +[util/errors.ts:16](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L16) ## Properties @@ -56,7 +56,7 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:75](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L75) +[util/errors.ts:75](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L75) ___ @@ -70,7 +70,7 @@ JOSEError.message #### Defined in -[util/errors.ts:77](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L77) +[util/errors.ts:77](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L77) ___ @@ -86,4 +86,4 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:73](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L73) +[util/errors.ts:73](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L73) diff --git a/docs/classes/util_errors.JWEInvalid.md b/docs/classes/util_errors.JWEInvalid.md index 977de4c18b..a843920da5 100644 --- a/docs/classes/util_errors.JWEInvalid.md +++ b/docs/classes/util_errors.JWEInvalid.md @@ -39,7 +39,7 @@ An error subclass thrown when a JWE is invalid. #### Defined in -[util/errors.ts:16](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L16) +[util/errors.ts:16](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L16) ## Properties @@ -55,7 +55,7 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:86](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L86) +[util/errors.ts:86](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L86) ___ @@ -71,4 +71,4 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:84](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L84) +[util/errors.ts:84](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L84) diff --git a/docs/classes/util_errors.JWKInvalid.md b/docs/classes/util_errors.JWKInvalid.md index 63feed940e..9e407b6ee4 100644 --- a/docs/classes/util_errors.JWKInvalid.md +++ b/docs/classes/util_errors.JWKInvalid.md @@ -39,7 +39,7 @@ An error subclass thrown when a JWK is invalid. #### Defined in -[util/errors.ts:16](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L16) +[util/errors.ts:16](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L16) ## Properties @@ -55,7 +55,7 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:113](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L113) +[util/errors.ts:113](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L113) ___ @@ -71,4 +71,4 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:111](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L111) +[util/errors.ts:111](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L111) diff --git a/docs/classes/util_errors.JWKSInvalid.md b/docs/classes/util_errors.JWKSInvalid.md index c6801c4f6a..cec1009282 100644 --- a/docs/classes/util_errors.JWKSInvalid.md +++ b/docs/classes/util_errors.JWKSInvalid.md @@ -39,7 +39,7 @@ An error subclass thrown when a JWKS is invalid. #### Defined in -[util/errors.ts:16](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L16) +[util/errors.ts:16](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L16) ## Properties @@ -55,7 +55,7 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:122](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L122) +[util/errors.ts:122](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L122) ___ @@ -71,4 +71,4 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:120](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L120) +[util/errors.ts:120](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L120) diff --git a/docs/classes/util_errors.JWKSMultipleMatchingKeys.md b/docs/classes/util_errors.JWKSMultipleMatchingKeys.md index ed1433c92b..3fb153e8c1 100644 --- a/docs/classes/util_errors.JWKSMultipleMatchingKeys.md +++ b/docs/classes/util_errors.JWKSMultipleMatchingKeys.md @@ -40,7 +40,7 @@ An error subclass thrown when multiple keys match from a JWKS. #### Defined in -[util/errors.ts:16](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L16) +[util/errors.ts:16](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L16) ## Properties @@ -56,7 +56,7 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:142](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L142) +[util/errors.ts:142](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L142) ___ @@ -70,7 +70,7 @@ JOSEError.message #### Defined in -[util/errors.ts:144](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L144) +[util/errors.ts:144](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L144) ___ @@ -86,4 +86,4 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:140](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L140) +[util/errors.ts:140](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L140) diff --git a/docs/classes/util_errors.JWKSNoMatchingKey.md b/docs/classes/util_errors.JWKSNoMatchingKey.md index 5ea725d942..f8133580c5 100644 --- a/docs/classes/util_errors.JWKSNoMatchingKey.md +++ b/docs/classes/util_errors.JWKSNoMatchingKey.md @@ -40,7 +40,7 @@ An error subclass thrown when no keys match from a JWKS. #### Defined in -[util/errors.ts:16](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L16) +[util/errors.ts:16](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L16) ## Properties @@ -56,7 +56,7 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:131](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L131) +[util/errors.ts:131](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L131) ___ @@ -70,7 +70,7 @@ JOSEError.message #### Defined in -[util/errors.ts:133](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L133) +[util/errors.ts:133](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L133) ___ @@ -86,4 +86,4 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:129](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L129) +[util/errors.ts:129](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L129) diff --git a/docs/classes/util_errors.JWSInvalid.md b/docs/classes/util_errors.JWSInvalid.md index 7619414334..3d1fea61b6 100644 --- a/docs/classes/util_errors.JWSInvalid.md +++ b/docs/classes/util_errors.JWSInvalid.md @@ -39,7 +39,7 @@ An error subclass thrown when a JWS is invalid. #### Defined in -[util/errors.ts:16](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L16) +[util/errors.ts:16](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L16) ## Properties @@ -55,7 +55,7 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:95](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L95) +[util/errors.ts:95](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L95) ___ @@ -71,4 +71,4 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:93](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L93) +[util/errors.ts:93](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L93) diff --git a/docs/classes/util_errors.JWSSignatureVerificationFailed.md b/docs/classes/util_errors.JWSSignatureVerificationFailed.md index 01505add92..b01e41b685 100644 --- a/docs/classes/util_errors.JWSSignatureVerificationFailed.md +++ b/docs/classes/util_errors.JWSSignatureVerificationFailed.md @@ -40,7 +40,7 @@ An error subclass thrown when JWS signature verification fails. #### Defined in -[util/errors.ts:16](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L16) +[util/errors.ts:16](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L16) ## Properties @@ -56,7 +56,7 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:153](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L153) +[util/errors.ts:153](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L153) ___ @@ -70,7 +70,7 @@ JOSEError.message #### Defined in -[util/errors.ts:155](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L155) +[util/errors.ts:155](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L155) ___ @@ -86,4 +86,4 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:151](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L151) +[util/errors.ts:151](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L151) diff --git a/docs/classes/util_errors.JWTClaimValidationFailed.md b/docs/classes/util_errors.JWTClaimValidationFailed.md index c4f9a7fe4b..deb6ae3628 100644 --- a/docs/classes/util_errors.JWTClaimValidationFailed.md +++ b/docs/classes/util_errors.JWTClaimValidationFailed.md @@ -45,7 +45,7 @@ An error subclass thrown when a JWT Claim Set member validation fails. #### Defined in -[util/errors.ts:43](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L43) +[util/errors.ts:43](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L43) ## Properties @@ -57,7 +57,7 @@ The Claim for which the validation failed. #### Defined in -[util/errors.ts:36](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L36) +[util/errors.ts:36](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L36) ___ @@ -73,7 +73,7 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:31](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L31) +[util/errors.ts:31](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L31) ___ @@ -85,7 +85,7 @@ Reason code for the validation failure. #### Defined in -[util/errors.ts:41](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L41) +[util/errors.ts:41](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L41) ___ @@ -101,4 +101,4 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:29](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L29) +[util/errors.ts:29](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L29) diff --git a/docs/classes/util_errors.JWTExpired.md b/docs/classes/util_errors.JWTExpired.md index 04912bfb1a..59fce7de4c 100644 --- a/docs/classes/util_errors.JWTExpired.md +++ b/docs/classes/util_errors.JWTExpired.md @@ -43,7 +43,7 @@ An error subclass thrown when a JWT is expired. #### Defined in -[util/errors.ts:43](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L43) +[util/errors.ts:43](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L43) ## Properties @@ -59,7 +59,7 @@ The Claim for which the validation failed. #### Defined in -[util/errors.ts:36](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L36) +[util/errors.ts:36](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L36) ___ @@ -75,7 +75,7 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:164](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L164) +[util/errors.ts:164](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L164) ___ @@ -91,7 +91,7 @@ Reason code for the validation failure. #### Defined in -[util/errors.ts:41](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L41) +[util/errors.ts:41](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L41) ___ @@ -107,4 +107,4 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:162](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L162) +[util/errors.ts:162](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L162) diff --git a/docs/classes/util_errors.JWTInvalid.md b/docs/classes/util_errors.JWTInvalid.md index b7226e1a35..2b11cae33d 100644 --- a/docs/classes/util_errors.JWTInvalid.md +++ b/docs/classes/util_errors.JWTInvalid.md @@ -39,7 +39,7 @@ An error subclass thrown when a JWT is invalid. #### Defined in -[util/errors.ts:16](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L16) +[util/errors.ts:16](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L16) ## Properties @@ -55,7 +55,7 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:104](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L104) +[util/errors.ts:104](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L104) ___ @@ -71,4 +71,4 @@ A unique error code for the particular error subclass. #### Defined in -[util/errors.ts:102](https://github.com/panva/jose/blob/v3.16.0/src/util/errors.ts#L102) +[util/errors.ts:102](https://github.com/panva/jose/blob/v3.16.1/src/util/errors.ts#L102) diff --git a/docs/functions/jwe_compact_decrypt.compactDecrypt.md b/docs/functions/jwe_compact_decrypt.compactDecrypt.md index a930808640..ad71b7d5aa 100644 --- a/docs/functions/jwe_compact_decrypt.compactDecrypt.md +++ b/docs/functions/jwe_compact_decrypt.compactDecrypt.md @@ -18,7 +18,7 @@ const { compactDecrypt } = require('jose/jwe/compact/decrypt') **`example`** Deno import ```js -import { compactDecrypt } from 'https://deno.land/x/jose@v3.16.0/jwe/compact/decrypt.ts' +import { compactDecrypt } from 'https://deno.land/x/jose@v3.16.1/jwe/compact/decrypt.ts' ``` **`example`** Usage @@ -46,4 +46,4 @@ console.log(decoder.decode(plaintext)) #### Defined in -[jwe/compact/decrypt.ts:52](https://github.com/panva/jose/blob/v3.16.0/src/jwe/compact/decrypt.ts#L52) +[jwe/compact/decrypt.ts:52](https://github.com/panva/jose/blob/v3.16.1/src/jwe/compact/decrypt.ts#L52) diff --git a/docs/functions/jwe_flattened_decrypt.flattenedDecrypt.md b/docs/functions/jwe_flattened_decrypt.flattenedDecrypt.md index b716ae6fe2..d971873da2 100644 --- a/docs/functions/jwe_flattened_decrypt.flattenedDecrypt.md +++ b/docs/functions/jwe_flattened_decrypt.flattenedDecrypt.md @@ -18,7 +18,7 @@ const { flattenedDecrypt } = require('jose/jwe/flattened/decrypt') **`example`** Deno import ```js -import { flattenedDecrypt } from 'https://deno.land/x/jose@v3.16.0/jwe/flattened/decrypt.ts' +import { flattenedDecrypt } from 'https://deno.land/x/jose@v3.16.1/jwe/flattened/decrypt.ts' ``` **`example`** Usage @@ -58,4 +58,4 @@ console.log(decoder.decode(additionalAuthenticatedData)) #### Defined in -[jwe/flattened/decrypt.ts:81](https://github.com/panva/jose/blob/v3.16.0/src/jwe/flattened/decrypt.ts#L81) +[jwe/flattened/decrypt.ts:81](https://github.com/panva/jose/blob/v3.16.1/src/jwe/flattened/decrypt.ts#L81) diff --git a/docs/functions/jwe_general_decrypt.generalDecrypt.md b/docs/functions/jwe_general_decrypt.generalDecrypt.md index 5aec427d16..8a2fea66d7 100644 --- a/docs/functions/jwe_general_decrypt.generalDecrypt.md +++ b/docs/functions/jwe_general_decrypt.generalDecrypt.md @@ -18,7 +18,7 @@ const { generalDecrypt } = require('jose/jwe/general/decrypt') **`example`** Deno import ```js -import { generalDecrypt } from 'https://deno.land/x/jose@v3.16.0/jwe/general/decrypt.ts' +import { generalDecrypt } from 'https://deno.land/x/jose@v3.16.1/jwe/general/decrypt.ts' ``` **`example`** Usage @@ -62,4 +62,4 @@ console.log(decoder.decode(additionalAuthenticatedData)) #### Defined in -[jwe/general/decrypt.ts:69](https://github.com/panva/jose/blob/v3.16.0/src/jwe/general/decrypt.ts#L69) +[jwe/general/decrypt.ts:69](https://github.com/panva/jose/blob/v3.16.1/src/jwe/general/decrypt.ts#L69) diff --git a/docs/functions/jwk_embedded.EmbeddedJWK.md b/docs/functions/jwk_embedded.EmbeddedJWK.md index 831fcc825f..0c72dcc683 100644 --- a/docs/functions/jwk_embedded.EmbeddedJWK.md +++ b/docs/functions/jwk_embedded.EmbeddedJWK.md @@ -22,7 +22,7 @@ const { EmbeddedJWK } = require('jose/jwk/embedded') **`example`** Deno import ```js -import { EmbeddedJWK } from 'https://deno.land/x/jose@v3.16.0/jwk/embedded.ts' +import { EmbeddedJWK } from 'https://deno.land/x/jose@v3.16.1/jwk/embedded.ts' ``` **`example`** Usage @@ -53,4 +53,4 @@ console.log(payload) #### Defined in -[jwk/embedded.ts:43](https://github.com/panva/jose/blob/v3.16.0/src/jwk/embedded.ts#L43) +[jwk/embedded.ts:43](https://github.com/panva/jose/blob/v3.16.1/src/jwk/embedded.ts#L43) diff --git a/docs/functions/jwk_from_key_like.fromKeyLike.md b/docs/functions/jwk_from_key_like.fromKeyLike.md index a09744a528..afeac79299 100644 --- a/docs/functions/jwk_from_key_like.fromKeyLike.md +++ b/docs/functions/jwk_from_key_like.fromKeyLike.md @@ -18,7 +18,7 @@ const { fromKeyLike } = require('jose/jwk/from_key_like') **`example`** Deno import ```js -import { fromKeyLike } from 'https://deno.land/x/jose@v3.16.0/jwk/from_key_like.ts' +import { fromKeyLike } from 'https://deno.land/x/jose@v3.16.1/jwk/from_key_like.ts' ``` **`example`** Usage @@ -42,4 +42,4 @@ console.log(publicJwk) #### Defined in -[jwk/from_key_like.ts:33](https://github.com/panva/jose/blob/v3.16.0/src/jwk/from_key_like.ts#L33) +[jwk/from_key_like.ts:33](https://github.com/panva/jose/blob/v3.16.1/src/jwk/from_key_like.ts#L33) diff --git a/docs/functions/jwk_parse.parseJwk.md b/docs/functions/jwk_parse.parseJwk.md index 1b91f57009..b1fb617bc1 100644 --- a/docs/functions/jwk_parse.parseJwk.md +++ b/docs/functions/jwk_parse.parseJwk.md @@ -21,7 +21,7 @@ const { parseJwk } = require('jose/jwk/parse') **`example`** Deno import ```js -import { parseJwk } from 'https://deno.land/x/jose@v3.16.0/jwk/parse.ts' +import { parseJwk } from 'https://deno.land/x/jose@v3.16.1/jwk/parse.ts' ``` **`example`** Usage @@ -54,4 +54,4 @@ const rsaPublicKey = await parseJwk({ #### Defined in -[jwk/parse.ts:50](https://github.com/panva/jose/blob/v3.16.0/src/jwk/parse.ts#L50) +[jwk/parse.ts:50](https://github.com/panva/jose/blob/v3.16.1/src/jwk/parse.ts#L50) diff --git a/docs/functions/jwk_thumbprint.calculateThumbprint.md b/docs/functions/jwk_thumbprint.calculateThumbprint.md index 06503acf5e..9cb432f6f9 100644 --- a/docs/functions/jwk_thumbprint.calculateThumbprint.md +++ b/docs/functions/jwk_thumbprint.calculateThumbprint.md @@ -19,7 +19,7 @@ const { calculateThumbprint } = require('jose/jwk/thumbprint') **`example`** Deno import ```js -import { calculateThumbprint } from 'https://deno.land/x/jose@v3.16.0/jwk/thumbprint.ts' +import { calculateThumbprint } from 'https://deno.land/x/jose@v3.16.1/jwk/thumbprint.ts' ``` **`example`** Usage @@ -46,4 +46,4 @@ console.log(thumbprint) #### Defined in -[jwk/thumbprint.ts:49](https://github.com/panva/jose/blob/v3.16.0/src/jwk/thumbprint.ts#L49) +[jwk/thumbprint.ts:49](https://github.com/panva/jose/blob/v3.16.1/src/jwk/thumbprint.ts#L49) diff --git a/docs/functions/jwks_remote.createRemoteJWKSet.md b/docs/functions/jwks_remote.createRemoteJWKSet.md index 2b015b8f29..3e3fcd0ba1 100644 --- a/docs/functions/jwks_remote.createRemoteJWKSet.md +++ b/docs/functions/jwks_remote.createRemoteJWKSet.md @@ -21,7 +21,7 @@ const { createRemoteJWKSet } = require('jose/jwks/remote') **`example`** Deno import ```js -import { createRemoteJWKSet } from 'https://deno.land/x/jose@v3.16.0/jwks/remote.ts' +import { createRemoteJWKSet } from 'https://deno.land/x/jose@v3.16.1/jwks/remote.ts' ``` **`example`** Usage @@ -51,4 +51,4 @@ console.log(payload) #### Defined in -[jwks/remote.ts:256](https://github.com/panva/jose/blob/v3.16.0/src/jwks/remote.ts#L256) +[jwks/remote.ts:256](https://github.com/panva/jose/blob/v3.16.1/src/jwks/remote.ts#L256) diff --git a/docs/functions/jws_compact_verify.compactVerify.md b/docs/functions/jws_compact_verify.compactVerify.md index 36a7b4bf36..7567f75a15 100644 --- a/docs/functions/jws_compact_verify.compactVerify.md +++ b/docs/functions/jws_compact_verify.compactVerify.md @@ -18,7 +18,7 @@ const { compactVerify } = require('jose/jws/compact/verify') **`example`** Deno import ```js -import { compactVerify } from 'https://deno.land/x/jose@v3.16.0/jws/compact/verify.ts' +import { compactVerify } from 'https://deno.land/x/jose@v3.16.1/jws/compact/verify.ts' ``` **`example`** Usage @@ -46,4 +46,4 @@ console.log(decoder.decode(payload)) #### Defined in -[jws/compact/verify.ts:56](https://github.com/panva/jose/blob/v3.16.0/src/jws/compact/verify.ts#L56) +[jws/compact/verify.ts:56](https://github.com/panva/jose/blob/v3.16.1/src/jws/compact/verify.ts#L56) diff --git a/docs/functions/jws_flattened_verify.flattenedVerify.md b/docs/functions/jws_flattened_verify.flattenedVerify.md index cd615019ad..93794e7f33 100644 --- a/docs/functions/jws_flattened_verify.flattenedVerify.md +++ b/docs/functions/jws_flattened_verify.flattenedVerify.md @@ -18,7 +18,7 @@ const { flattenedVerify } = require('jose/jws/flattened/verify') **`example`** Deno import ```js -import { flattenedVerify } from 'https://deno.land/x/jose@v3.16.0/jws/flattened/verify.ts' +import { flattenedVerify } from 'https://deno.land/x/jose@v3.16.1/jws/flattened/verify.ts' ``` **`example`** Usage @@ -50,4 +50,4 @@ console.log(decoder.decode(payload)) #### Defined in -[jws/flattened/verify.ts:71](https://github.com/panva/jose/blob/v3.16.0/src/jws/flattened/verify.ts#L71) +[jws/flattened/verify.ts:71](https://github.com/panva/jose/blob/v3.16.1/src/jws/flattened/verify.ts#L71) diff --git a/docs/functions/jws_general_verify.generalVerify.md b/docs/functions/jws_general_verify.generalVerify.md index e9ba0a5085..8c654a41e7 100644 --- a/docs/functions/jws_general_verify.generalVerify.md +++ b/docs/functions/jws_general_verify.generalVerify.md @@ -18,7 +18,7 @@ const { generalVerify } = require('jose/jws/general/verify') **`example`** Deno import ```js -import { generalVerify } from 'https://deno.land/x/jose@v3.16.0/jws/general/verify.ts' +import { generalVerify } from 'https://deno.land/x/jose@v3.16.1/jws/general/verify.ts' ``` **`example`** Usage @@ -54,4 +54,4 @@ console.log(decoder.decode(payload)) #### Defined in -[jws/general/verify.ts:65](https://github.com/panva/jose/blob/v3.16.0/src/jws/general/verify.ts#L65) +[jws/general/verify.ts:65](https://github.com/panva/jose/blob/v3.16.1/src/jws/general/verify.ts#L65) diff --git a/docs/functions/jwt_decrypt.jwtDecrypt.md b/docs/functions/jwt_decrypt.jwtDecrypt.md index dedbc83198..c63400e879 100644 --- a/docs/functions/jwt_decrypt.jwtDecrypt.md +++ b/docs/functions/jwt_decrypt.jwtDecrypt.md @@ -18,7 +18,7 @@ const { jwtDecrypt } = require('jose/jwt/decrypt') **`example`** Deno import ```js -import { jwtDecrypt } from 'https://deno.land/x/jose@v3.16.0/jwt/decrypt.ts' +import { jwtDecrypt } from 'https://deno.land/x/jose@v3.16.1/jwt/decrypt.ts' ``` **`example`** Usage @@ -48,4 +48,4 @@ console.log(payload) #### Defined in -[jwt/decrypt.ts:61](https://github.com/panva/jose/blob/v3.16.0/src/jwt/decrypt.ts#L61) +[jwt/decrypt.ts:61](https://github.com/panva/jose/blob/v3.16.1/src/jwt/decrypt.ts#L61) diff --git a/docs/functions/jwt_verify.jwtVerify.md b/docs/functions/jwt_verify.jwtVerify.md index cdcd2f0a3c..e4726eba2e 100644 --- a/docs/functions/jwt_verify.jwtVerify.md +++ b/docs/functions/jwt_verify.jwtVerify.md @@ -18,7 +18,7 @@ const { jwtVerify } = require('jose/jwt/verify') **`example`** Deno import ```js -import { jwtVerify } from 'https://deno.land/x/jose@v3.16.0/jwt/verify.ts' +import { jwtVerify } from 'https://deno.land/x/jose@v3.16.1/jwt/verify.ts' ``` **`example`** Usage @@ -48,4 +48,4 @@ console.log(payload) #### Defined in -[jwt/verify.ts:64](https://github.com/panva/jose/blob/v3.16.0/src/jwt/verify.ts#L64) +[jwt/verify.ts:64](https://github.com/panva/jose/blob/v3.16.1/src/jwt/verify.ts#L64) diff --git a/docs/functions/util_base64url.decode.md b/docs/functions/util_base64url.decode.md index 579c10d87d..7e90b6e18d 100644 --- a/docs/functions/util_base64url.decode.md +++ b/docs/functions/util_base64url.decode.md @@ -16,4 +16,4 @@ #### Defined in -[util/base64url.ts:21](https://github.com/panva/jose/blob/v3.16.0/src/util/base64url.ts#L21) +[util/base64url.ts:21](https://github.com/panva/jose/blob/v3.16.1/src/util/base64url.ts#L21) diff --git a/docs/functions/util_base64url.encode.md b/docs/functions/util_base64url.encode.md index 35e0f5262c..62b500752d 100644 --- a/docs/functions/util_base64url.encode.md +++ b/docs/functions/util_base64url.encode.md @@ -16,4 +16,4 @@ #### Defined in -[util/base64url.ts:20](https://github.com/panva/jose/blob/v3.16.0/src/util/base64url.ts#L20) +[util/base64url.ts:20](https://github.com/panva/jose/blob/v3.16.1/src/util/base64url.ts#L20) diff --git a/docs/functions/util_decode_protected_header.decodeProtectedHeader.md b/docs/functions/util_decode_protected_header.decodeProtectedHeader.md index 5058204919..458e1ee5d0 100644 --- a/docs/functions/util_decode_protected_header.decodeProtectedHeader.md +++ b/docs/functions/util_decode_protected_header.decodeProtectedHeader.md @@ -18,7 +18,7 @@ const { decodeProtectedHeader } = require('jose/util/decode_protected_header') **`example`** Deno import ```js -import { decodeProtectedHeader } from 'https://deno.land/x/jose@v3.16.0/util/decode_protected_header.ts' +import { decodeProtectedHeader } from 'https://deno.land/x/jose@v3.16.1/util/decode_protected_header.ts' ``` **`example`** Usage @@ -39,4 +39,4 @@ console.log(protectedHeader) #### Defined in -[util/decode_protected_header.ts:34](https://github.com/panva/jose/blob/v3.16.0/src/util/decode_protected_header.ts#L34) +[util/decode_protected_header.ts:34](https://github.com/panva/jose/blob/v3.16.1/src/util/decode_protected_header.ts#L34) diff --git a/docs/functions/util_generate_key_pair.generateKeyPair.md b/docs/functions/util_generate_key_pair.generateKeyPair.md index 415d80a673..52465b877b 100644 --- a/docs/functions/util_generate_key_pair.generateKeyPair.md +++ b/docs/functions/util_generate_key_pair.generateKeyPair.md @@ -23,7 +23,7 @@ const { generateKeyPair } = require('jose/util/generate_key_pair') **`example`** Deno import ```js -import { generateKeyPair } from 'https://deno.land/x/jose@v3.16.0/util/generate_key_pair.ts' +import { generateKeyPair } from 'https://deno.land/x/jose@v3.16.1/util/generate_key_pair.ts' ``` **`example`** Usage @@ -46,4 +46,4 @@ console.log(privateKey) #### Defined in -[util/generate_key_pair.ts:71](https://github.com/panva/jose/blob/v3.16.0/src/util/generate_key_pair.ts#L71) +[util/generate_key_pair.ts:71](https://github.com/panva/jose/blob/v3.16.1/src/util/generate_key_pair.ts#L71) diff --git a/docs/functions/util_generate_secret.generateSecret.md b/docs/functions/util_generate_secret.generateSecret.md index 52f0972b89..76ec38584e 100644 --- a/docs/functions/util_generate_secret.generateSecret.md +++ b/docs/functions/util_generate_secret.generateSecret.md @@ -21,7 +21,7 @@ const { generateSecret } = require('jose/util/generate_secret') **`example`** Deno import ```js -import { generateSecret } from 'https://deno.land/x/jose@v3.16.0/util/generate_secret.ts' +import { generateSecret } from 'https://deno.land/x/jose@v3.16.1/util/generate_secret.ts' ``` **`example`** Usage @@ -43,4 +43,4 @@ console.log(secret) #### Defined in -[util/generate_secret.ts:43](https://github.com/panva/jose/blob/v3.16.0/src/util/generate_secret.ts#L43) +[util/generate_secret.ts:43](https://github.com/panva/jose/blob/v3.16.1/src/util/generate_secret.ts#L43) diff --git a/docs/functions/util_random.random.md b/docs/functions/util_random.random.md index c62f6b6280..73789bd9cf 100644 --- a/docs/functions/util_random.random.md +++ b/docs/functions/util_random.random.md @@ -16,4 +16,4 @@ #### Defined in -[util/random.ts:7](https://github.com/panva/jose/blob/v3.16.0/src/util/random.ts#L7) +[util/random.ts:7](https://github.com/panva/jose/blob/v3.16.1/src/util/random.ts#L7) diff --git a/docs/interfaces/jwe_compact_decrypt.CompactDecryptGetKey.md b/docs/interfaces/jwe_compact_decrypt.CompactDecryptGetKey.md index 7b6efb0766..c0d274e0cc 100644 --- a/docs/interfaces/jwe_compact_decrypt.CompactDecryptGetKey.md +++ b/docs/interfaces/jwe_compact_decrypt.CompactDecryptGetKey.md @@ -30,4 +30,4 @@ No token components have been verified at the time of this function call. #### Defined in -[types.d.ts:152](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L152) +[types.d.ts:152](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L152) diff --git a/docs/interfaces/jwe_flattened_decrypt.FlattenedDecryptGetKey.md b/docs/interfaces/jwe_flattened_decrypt.FlattenedDecryptGetKey.md index 15d31eb833..a91e035eb7 100644 --- a/docs/interfaces/jwe_flattened_decrypt.FlattenedDecryptGetKey.md +++ b/docs/interfaces/jwe_flattened_decrypt.FlattenedDecryptGetKey.md @@ -30,4 +30,4 @@ No token components have been verified at the time of this function call. #### Defined in -[types.d.ts:152](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L152) +[types.d.ts:152](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L152) diff --git a/docs/interfaces/jwe_general_decrypt.GeneralDecryptGetKey.md b/docs/interfaces/jwe_general_decrypt.GeneralDecryptGetKey.md index d0bac8f9b6..4a519dafdb 100644 --- a/docs/interfaces/jwe_general_decrypt.GeneralDecryptGetKey.md +++ b/docs/interfaces/jwe_general_decrypt.GeneralDecryptGetKey.md @@ -30,4 +30,4 @@ No token components have been verified at the time of this function call. #### Defined in -[types.d.ts:152](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L152) +[types.d.ts:152](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L152) diff --git a/docs/interfaces/jwks_remote.RemoteJWKSetOptions.md b/docs/interfaces/jwks_remote.RemoteJWKSetOptions.md index d51462b7e3..bfe35da87a 100644 --- a/docs/interfaces/jwks_remote.RemoteJWKSetOptions.md +++ b/docs/interfaces/jwks_remote.RemoteJWKSetOptions.md @@ -28,7 +28,7 @@ when used outside of Node.js runtime. #### Defined in -[jwks/remote.ts:61](https://github.com/panva/jose/blob/v3.16.0/src/jwks/remote.ts#L61) +[jwks/remote.ts:61](https://github.com/panva/jose/blob/v3.16.1/src/jwks/remote.ts#L61) ___ @@ -41,7 +41,7 @@ after a previous successful fetch. Default is 30000. #### Defined in -[jwks/remote.ts:50](https://github.com/panva/jose/blob/v3.16.0/src/jwks/remote.ts#L50) +[jwks/remote.ts:50](https://github.com/panva/jose/blob/v3.16.1/src/jwks/remote.ts#L50) ___ @@ -54,4 +54,4 @@ aborted and the verification will fail. Default is 5000. #### Defined in -[jwks/remote.ts:44](https://github.com/panva/jose/blob/v3.16.0/src/jwks/remote.ts#L44) +[jwks/remote.ts:44](https://github.com/panva/jose/blob/v3.16.1/src/jwks/remote.ts#L44) diff --git a/docs/interfaces/jws_compact_verify.CompactVerifyGetKey.md b/docs/interfaces/jws_compact_verify.CompactVerifyGetKey.md index 407c8328b9..abec6896c6 100644 --- a/docs/interfaces/jws_compact_verify.CompactVerifyGetKey.md +++ b/docs/interfaces/jws_compact_verify.CompactVerifyGetKey.md @@ -33,4 +33,4 @@ to verify using a remote JSON Web Key Set. #### Defined in -[types.d.ts:152](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L152) +[types.d.ts:152](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L152) diff --git a/docs/interfaces/jws_flattened_verify.FlattenedVerifyGetKey.md b/docs/interfaces/jws_flattened_verify.FlattenedVerifyGetKey.md index c1a37e6e53..d5e61721fe 100644 --- a/docs/interfaces/jws_flattened_verify.FlattenedVerifyGetKey.md +++ b/docs/interfaces/jws_flattened_verify.FlattenedVerifyGetKey.md @@ -33,4 +33,4 @@ to verify using a remote JSON Web Key Set. #### Defined in -[types.d.ts:152](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L152) +[types.d.ts:152](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L152) diff --git a/docs/interfaces/jws_general_sign.Signature.md b/docs/interfaces/jws_general_sign.Signature.md index 8f11766a1a..cef6e8e551 100644 --- a/docs/interfaces/jws_general_sign.Signature.md +++ b/docs/interfaces/jws_general_sign.Signature.md @@ -29,7 +29,7 @@ Sets the JWS Protected Header on the Signature object. #### Defined in -[jws/general/sign.ts:12](https://github.com/panva/jose/blob/v3.16.0/src/jws/general/sign.ts#L12) +[jws/general/sign.ts:12](https://github.com/panva/jose/blob/v3.16.1/src/jws/general/sign.ts#L12) ___ @@ -51,4 +51,4 @@ Sets the JWS Unprotected Header on the Signature object. #### Defined in -[jws/general/sign.ts:19](https://github.com/panva/jose/blob/v3.16.0/src/jws/general/sign.ts#L19) +[jws/general/sign.ts:19](https://github.com/panva/jose/blob/v3.16.1/src/jws/general/sign.ts#L19) diff --git a/docs/interfaces/jws_general_verify.GeneralVerifyGetKey.md b/docs/interfaces/jws_general_verify.GeneralVerifyGetKey.md index 0dfff14522..63fc55f1c5 100644 --- a/docs/interfaces/jws_general_verify.GeneralVerifyGetKey.md +++ b/docs/interfaces/jws_general_verify.GeneralVerifyGetKey.md @@ -33,4 +33,4 @@ to verify using a remote JSON Web Key Set. #### Defined in -[types.d.ts:152](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L152) +[types.d.ts:152](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L152) diff --git a/docs/interfaces/jwt_decrypt.JWTDecryptGetKey.md b/docs/interfaces/jwt_decrypt.JWTDecryptGetKey.md index d94071cf66..298841f4a3 100644 --- a/docs/interfaces/jwt_decrypt.JWTDecryptGetKey.md +++ b/docs/interfaces/jwt_decrypt.JWTDecryptGetKey.md @@ -30,4 +30,4 @@ No token components have been verified at the time of this function call. #### Defined in -[types.d.ts:152](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L152) +[types.d.ts:152](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L152) diff --git a/docs/interfaces/jwt_decrypt.JWTDecryptOptions.md b/docs/interfaces/jwt_decrypt.JWTDecryptOptions.md index 552010e6a4..14113f4abf 100644 --- a/docs/interfaces/jwt_decrypt.JWTDecryptOptions.md +++ b/docs/interfaces/jwt_decrypt.JWTDecryptOptions.md @@ -42,7 +42,7 @@ Expected JWT "aud" (Audience) Claim value(s). #### Defined in -[types.d.ts:486](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L486) +[types.d.ts:486](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L486) ___ @@ -60,7 +60,7 @@ Expected clock tolerance #### Defined in -[types.d.ts:493](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L493) +[types.d.ts:493](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L493) ___ @@ -78,7 +78,7 @@ key/secret are allowed. #### Defined in -[types.d.ts:459](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L459) +[types.d.ts:459](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L459) ___ @@ -115,7 +115,7 @@ default built-in treatment are currently available. #### Defined in -[types.d.ts:440](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L440) +[types.d.ts:440](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L440) ___ @@ -131,7 +131,7 @@ Date to use when comparing NumericDate claims, defaults to `new Date()`. #### Defined in -[types.d.ts:520](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L520) +[types.d.ts:520](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L520) ___ @@ -148,7 +148,7 @@ when you expect JWEs with compressed plaintext. #### Defined in -[types.d.ts:465](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L465) +[types.d.ts:465](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L465) ___ @@ -164,7 +164,7 @@ Expected JWT "iss" (Issuer) Claim value(s). #### Defined in -[types.d.ts:498](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L498) +[types.d.ts:498](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L498) ___ @@ -180,7 +180,7 @@ A list of accepted JWE "alg" (Algorithm) Header Parameter values. #### Defined in -[types.d.ts:452](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L452) +[types.d.ts:452](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L452) ___ @@ -198,7 +198,7 @@ Maximum time elapsed (in seconds) from the JWT "iat" (Issued At) Claim value. #### Defined in -[types.d.ts:505](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L505) +[types.d.ts:505](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L505) ___ @@ -214,7 +214,7 @@ Expected JWT "sub" (Subject) Claim value. #### Defined in -[types.d.ts:510](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L510) +[types.d.ts:510](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L510) ___ @@ -230,4 +230,4 @@ Expected JWT "typ" (Type) Header Parameter value. #### Defined in -[types.d.ts:515](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L515) +[types.d.ts:515](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L515) diff --git a/docs/interfaces/jwt_unsecured.UnsecuredResult.md b/docs/interfaces/jwt_unsecured.UnsecuredResult.md index 4b29fef834..898d73e835 100644 --- a/docs/interfaces/jwt_unsecured.UnsecuredResult.md +++ b/docs/interfaces/jwt_unsecured.UnsecuredResult.md @@ -17,7 +17,7 @@ #### Defined in -[jwt/unsecured.ts:10](https://github.com/panva/jose/blob/v3.16.0/src/jwt/unsecured.ts#L10) +[jwt/unsecured.ts:10](https://github.com/panva/jose/blob/v3.16.1/src/jwt/unsecured.ts#L10) ___ @@ -27,4 +27,4 @@ ___ #### Defined in -[jwt/unsecured.ts:9](https://github.com/panva/jose/blob/v3.16.0/src/jwt/unsecured.ts#L9) +[jwt/unsecured.ts:9](https://github.com/panva/jose/blob/v3.16.1/src/jwt/unsecured.ts#L9) diff --git a/docs/interfaces/jwt_verify.JWTVerifyGetKey.md b/docs/interfaces/jwt_verify.JWTVerifyGetKey.md index ad5b013fa1..ada80efdd9 100644 --- a/docs/interfaces/jwt_verify.JWTVerifyGetKey.md +++ b/docs/interfaces/jwt_verify.JWTVerifyGetKey.md @@ -33,4 +33,4 @@ to verify using a remote JSON Web Key Set. #### Defined in -[types.d.ts:152](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L152) +[types.d.ts:152](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L152) diff --git a/docs/interfaces/jwt_verify.JWTVerifyOptions.md b/docs/interfaces/jwt_verify.JWTVerifyOptions.md index c65c1dedce..1c3e03c3cd 100644 --- a/docs/interfaces/jwt_verify.JWTVerifyOptions.md +++ b/docs/interfaces/jwt_verify.JWTVerifyOptions.md @@ -42,7 +42,7 @@ key/secret are allowed. Note: "none" is never accepted. #### Defined in -[types.d.ts:532](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L532) +[types.d.ts:532](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L532) ___ @@ -58,7 +58,7 @@ Expected JWT "aud" (Audience) Claim value(s). #### Defined in -[types.d.ts:486](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L486) +[types.d.ts:486](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L486) ___ @@ -76,7 +76,7 @@ Expected clock tolerance #### Defined in -[types.d.ts:493](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L493) +[types.d.ts:493](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L493) ___ @@ -113,7 +113,7 @@ default built-in treatment are currently available. #### Defined in -[types.d.ts:440](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L440) +[types.d.ts:440](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L440) ___ @@ -129,7 +129,7 @@ Date to use when comparing NumericDate claims, defaults to `new Date()`. #### Defined in -[types.d.ts:520](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L520) +[types.d.ts:520](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L520) ___ @@ -145,7 +145,7 @@ Expected JWT "iss" (Issuer) Claim value(s). #### Defined in -[types.d.ts:498](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L498) +[types.d.ts:498](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L498) ___ @@ -163,7 +163,7 @@ Maximum time elapsed (in seconds) from the JWT "iat" (Issued At) Claim value. #### Defined in -[types.d.ts:505](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L505) +[types.d.ts:505](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L505) ___ @@ -179,7 +179,7 @@ Expected JWT "sub" (Subject) Claim value. #### Defined in -[types.d.ts:510](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L510) +[types.d.ts:510](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L510) ___ @@ -195,4 +195,4 @@ Expected JWT "typ" (Type) Header Parameter value. #### Defined in -[types.d.ts:515](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L515) +[types.d.ts:515](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L515) diff --git a/docs/interfaces/types.CompactDecryptResult.md b/docs/interfaces/types.CompactDecryptResult.md index b36d34cf65..38409b9ada 100644 --- a/docs/interfaces/types.CompactDecryptResult.md +++ b/docs/interfaces/types.CompactDecryptResult.md @@ -19,7 +19,7 @@ Plaintext. #### Defined in -[types.d.ts:633](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L633) +[types.d.ts:633](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L633) ___ @@ -31,4 +31,4 @@ JWE Protected Header. #### Defined in -[types.d.ts:638](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L638) +[types.d.ts:638](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L638) diff --git a/docs/interfaces/types.CompactVerifyResult.md b/docs/interfaces/types.CompactVerifyResult.md index 442fcda4cc..22b5a656a6 100644 --- a/docs/interfaces/types.CompactVerifyResult.md +++ b/docs/interfaces/types.CompactVerifyResult.md @@ -19,7 +19,7 @@ JWS Payload. #### Defined in -[types.d.ts:664](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L664) +[types.d.ts:664](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L664) ___ @@ -31,4 +31,4 @@ JWS Protected Header. #### Defined in -[types.d.ts:669](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L669) +[types.d.ts:669](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L669) diff --git a/docs/interfaces/types.CritOption.md b/docs/interfaces/types.CritOption.md index 7bbba5caa7..de3c1e1a46 100644 --- a/docs/interfaces/types.CritOption.md +++ b/docs/interfaces/types.CritOption.md @@ -53,4 +53,4 @@ default built-in treatment are currently available. #### Defined in -[types.d.ts:440](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L440) +[types.d.ts:440](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L440) diff --git a/docs/interfaces/types.DecryptOptions.md b/docs/interfaces/types.DecryptOptions.md index 36eda0e8ac..572b63de81 100644 --- a/docs/interfaces/types.DecryptOptions.md +++ b/docs/interfaces/types.DecryptOptions.md @@ -33,7 +33,7 @@ key/secret are allowed. #### Defined in -[types.d.ts:459](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L459) +[types.d.ts:459](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L459) ___ @@ -70,7 +70,7 @@ default built-in treatment are currently available. #### Defined in -[types.d.ts:440](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L440) +[types.d.ts:440](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L440) ___ @@ -83,7 +83,7 @@ when you expect JWEs with compressed plaintext. #### Defined in -[types.d.ts:465](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L465) +[types.d.ts:465](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L465) ___ @@ -95,4 +95,4 @@ A list of accepted JWE "alg" (Algorithm) Header Parameter values. #### Defined in -[types.d.ts:452](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L452) +[types.d.ts:452](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L452) diff --git a/docs/interfaces/types.DeflateFunction.md b/docs/interfaces/types.DeflateFunction.md index 1eeb0a70a3..b35b52c9dd 100644 --- a/docs/interfaces/types.DeflateFunction.md +++ b/docs/interfaces/types.DeflateFunction.md @@ -22,4 +22,4 @@ Deflate Raw implementation, e.g. promisified [zlib.deflateRaw](https://nodejs.or #### Defined in -[types.d.ts:590](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L590) +[types.d.ts:590](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L590) diff --git a/docs/interfaces/types.EncryptOptions.md b/docs/interfaces/types.EncryptOptions.md index d167a4cbcf..4bed2c4fb5 100644 --- a/docs/interfaces/types.EncryptOptions.md +++ b/docs/interfaces/types.EncryptOptions.md @@ -52,7 +52,7 @@ default built-in treatment are currently available. #### Defined in -[types.d.ts:440](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L440) +[types.d.ts:440](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L440) ___ @@ -65,4 +65,4 @@ when you will be producing JWEs with compressed plaintext. #### Defined in -[types.d.ts:476](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L476) +[types.d.ts:476](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L476) diff --git a/docs/interfaces/types.FlattenedDecryptResult.md b/docs/interfaces/types.FlattenedDecryptResult.md index 73039c4444..2930e7fb9d 100644 --- a/docs/interfaces/types.FlattenedDecryptResult.md +++ b/docs/interfaces/types.FlattenedDecryptResult.md @@ -28,7 +28,7 @@ JWE AAD. #### Defined in -[types.d.ts:604](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L604) +[types.d.ts:604](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L604) ___ @@ -40,7 +40,7 @@ Plaintext. #### Defined in -[types.d.ts:609](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L609) +[types.d.ts:609](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L609) ___ @@ -52,7 +52,7 @@ JWE Protected Header. #### Defined in -[types.d.ts:614](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L614) +[types.d.ts:614](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L614) ___ @@ -64,7 +64,7 @@ JWE Shared Unprotected Header. #### Defined in -[types.d.ts:619](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L619) +[types.d.ts:619](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L619) ___ @@ -76,4 +76,4 @@ JWE Per-Recipient Unprotected Header. #### Defined in -[types.d.ts:624](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L624) +[types.d.ts:624](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L624) diff --git a/docs/interfaces/types.FlattenedJWE.md b/docs/interfaces/types.FlattenedJWE.md index 26ec430422..9a5836afcc 100644 --- a/docs/interfaces/types.FlattenedJWE.md +++ b/docs/interfaces/types.FlattenedJWE.md @@ -31,7 +31,7 @@ encrypted. #### Defined in -[types.d.ts:324](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L324) +[types.d.ts:324](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L324) ___ @@ -44,7 +44,7 @@ BASE64URL(JWE Ciphertext). #### Defined in -[types.d.ts:330](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L330) +[types.d.ts:330](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L330) ___ @@ -58,7 +58,7 @@ non-empty; otherwise, it MUST be absent. #### Defined in -[types.d.ts:337](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L337) +[types.d.ts:337](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L337) ___ @@ -75,7 +75,7 @@ integrity protected. #### Defined in -[types.d.ts:347](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L347) +[types.d.ts:347](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L347) ___ @@ -89,7 +89,7 @@ Vector value is non-empty; otherwise, it MUST be absent. #### Defined in -[types.d.ts:354](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L354) +[types.d.ts:354](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L354) ___ @@ -104,7 +104,7 @@ Header Parameter values are integrity protected. #### Defined in -[types.d.ts:362](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L362) +[types.d.ts:362](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L362) ___ @@ -118,7 +118,7 @@ value is non-empty; otherwise, it MUST be absent. #### Defined in -[types.d.ts:369](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L369) +[types.d.ts:369](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L369) ___ @@ -134,4 +134,4 @@ These Header Parameter values are not integrity protected. #### Defined in -[types.d.ts:378](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L378) +[types.d.ts:378](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L378) diff --git a/docs/interfaces/types.FlattenedJWS.md b/docs/interfaces/types.FlattenedJWS.md index 540c7815d8..e6a33c0544 100644 --- a/docs/interfaces/types.FlattenedJWS.md +++ b/docs/interfaces/types.FlattenedJWS.md @@ -39,7 +39,7 @@ Partial.header #### Defined in -[types.d.ts:167](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L167) +[types.d.ts:167](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L167) ___ @@ -53,7 +53,7 @@ Partial.payload #### Defined in -[types.d.ts:217](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L217) +[types.d.ts:217](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L217) ___ @@ -72,7 +72,7 @@ Partial.protected #### Defined in -[types.d.ts:182](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L182) +[types.d.ts:182](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L182) ___ @@ -86,4 +86,4 @@ Partial.signature #### Defined in -[types.d.ts:218](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L218) +[types.d.ts:218](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L218) diff --git a/docs/interfaces/types.FlattenedJWSInput.md b/docs/interfaces/types.FlattenedJWSInput.md index 44b5640d66..5ddb567ef2 100644 --- a/docs/interfaces/types.FlattenedJWSInput.md +++ b/docs/interfaces/types.FlattenedJWSInput.md @@ -28,7 +28,7 @@ Parameter values are not integrity protected. #### Defined in -[types.d.ts:167](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L167) +[types.d.ts:167](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L167) ___ @@ -42,7 +42,7 @@ the value passed may also be a Uint8Array. #### Defined in -[types.d.ts:174](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L174) +[types.d.ts:174](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L174) ___ @@ -57,7 +57,7 @@ Header Parameter values are integrity protected. #### Defined in -[types.d.ts:182](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L182) +[types.d.ts:182](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L182) ___ @@ -70,4 +70,4 @@ BASE64URL(JWS Signature). #### Defined in -[types.d.ts:188](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L188) +[types.d.ts:188](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L188) diff --git a/docs/interfaces/types.FlattenedVerifyResult.md b/docs/interfaces/types.FlattenedVerifyResult.md index 56b24f0c00..725a77e4ae 100644 --- a/docs/interfaces/types.FlattenedVerifyResult.md +++ b/docs/interfaces/types.FlattenedVerifyResult.md @@ -26,7 +26,7 @@ JWS Payload. #### Defined in -[types.d.ts:645](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L645) +[types.d.ts:645](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L645) ___ @@ -38,7 +38,7 @@ JWS Protected Header. #### Defined in -[types.d.ts:650](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L650) +[types.d.ts:650](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L650) ___ @@ -50,4 +50,4 @@ JWS Unprotected Header. #### Defined in -[types.d.ts:655](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L655) +[types.d.ts:655](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L655) diff --git a/docs/interfaces/types.GeneralDecryptResult.md b/docs/interfaces/types.GeneralDecryptResult.md index 528c8f7262..c729423c78 100644 --- a/docs/interfaces/types.GeneralDecryptResult.md +++ b/docs/interfaces/types.GeneralDecryptResult.md @@ -32,7 +32,7 @@ JWE AAD. #### Defined in -[types.d.ts:604](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L604) +[types.d.ts:604](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L604) ___ @@ -48,7 +48,7 @@ Plaintext. #### Defined in -[types.d.ts:609](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L609) +[types.d.ts:609](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L609) ___ @@ -64,7 +64,7 @@ JWE Protected Header. #### Defined in -[types.d.ts:614](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L614) +[types.d.ts:614](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L614) ___ @@ -80,7 +80,7 @@ JWE Shared Unprotected Header. #### Defined in -[types.d.ts:619](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L619) +[types.d.ts:619](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L619) ___ @@ -96,4 +96,4 @@ JWE Per-Recipient Unprotected Header. #### Defined in -[types.d.ts:624](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L624) +[types.d.ts:624](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L624) diff --git a/docs/interfaces/types.GeneralJWE.md b/docs/interfaces/types.GeneralJWE.md index ec106ae48d..a1acfbb916 100644 --- a/docs/interfaces/types.GeneralJWE.md +++ b/docs/interfaces/types.GeneralJWE.md @@ -38,7 +38,7 @@ Omit.aad #### Defined in -[types.d.ts:324](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L324) +[types.d.ts:324](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L324) ___ @@ -55,7 +55,7 @@ Omit.ciphertext #### Defined in -[types.d.ts:330](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L330) +[types.d.ts:330](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L330) ___ @@ -73,7 +73,7 @@ Omit.iv #### Defined in -[types.d.ts:354](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L354) +[types.d.ts:354](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L354) ___ @@ -92,7 +92,7 @@ Omit.protected #### Defined in -[types.d.ts:362](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L362) +[types.d.ts:362](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L362) ___ @@ -102,7 +102,7 @@ ___ #### Defined in -[types.d.ts:382](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L382) +[types.d.ts:382](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L382) ___ @@ -120,7 +120,7 @@ Omit.tag #### Defined in -[types.d.ts:369](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L369) +[types.d.ts:369](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L369) ___ @@ -140,4 +140,4 @@ Omit.unprotected #### Defined in -[types.d.ts:378](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L378) +[types.d.ts:378](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L378) diff --git a/docs/interfaces/types.GeneralJWS.md b/docs/interfaces/types.GeneralJWS.md index e0610b9dbf..fbfbd44c2c 100644 --- a/docs/interfaces/types.GeneralJWS.md +++ b/docs/interfaces/types.GeneralJWS.md @@ -21,7 +21,7 @@ string when JWS Unencoded Payload Option #### Defined in -[types.d.ts:227](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L227) +[types.d.ts:227](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L227) ___ @@ -31,4 +31,4 @@ ___ #### Defined in -[types.d.ts:228](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L228) +[types.d.ts:228](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L228) diff --git a/docs/interfaces/types.GeneralJWSInput.md b/docs/interfaces/types.GeneralJWSInput.md index 420d550072..df0c112282 100644 --- a/docs/interfaces/types.GeneralJWSInput.md +++ b/docs/interfaces/types.GeneralJWSInput.md @@ -24,7 +24,7 @@ the value passed may also be a Uint8Array. #### Defined in -[types.d.ts:201](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L201) +[types.d.ts:201](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L201) ___ @@ -38,4 +38,4 @@ the JWS Protected Header. #### Defined in -[types.d.ts:208](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L208) +[types.d.ts:208](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L208) diff --git a/docs/interfaces/types.GeneralVerifyResult.md b/docs/interfaces/types.GeneralVerifyResult.md index 3bab5d8db9..e89d237aa7 100644 --- a/docs/interfaces/types.GeneralVerifyResult.md +++ b/docs/interfaces/types.GeneralVerifyResult.md @@ -30,7 +30,7 @@ JWS Payload. #### Defined in -[types.d.ts:645](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L645) +[types.d.ts:645](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L645) ___ @@ -46,7 +46,7 @@ JWS Protected Header. #### Defined in -[types.d.ts:650](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L650) +[types.d.ts:650](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L650) ___ @@ -62,4 +62,4 @@ JWS Unprotected Header. #### Defined in -[types.d.ts:655](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L655) +[types.d.ts:655](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L655) diff --git a/docs/interfaces/types.GetKeyFunction.md b/docs/interfaces/types.GetKeyFunction.md index cf122c23dc..758366f2ee 100644 --- a/docs/interfaces/types.GetKeyFunction.md +++ b/docs/interfaces/types.GetKeyFunction.md @@ -53,4 +53,4 @@ If you cannot match a key suitable for the token, throw an error instead. #### Defined in -[types.d.ts:152](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L152) +[types.d.ts:152](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L152) diff --git a/docs/interfaces/types.InflateFunction.md b/docs/interfaces/types.InflateFunction.md index 9ea3dd1c67..57c0271fc0 100644 --- a/docs/interfaces/types.InflateFunction.md +++ b/docs/interfaces/types.InflateFunction.md @@ -22,4 +22,4 @@ Inflate Raw implementation, e.g. promisified [zlib.inflateRaw](https://nodejs.or #### Defined in -[types.d.ts:597](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L597) +[types.d.ts:597](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L597) diff --git a/docs/interfaces/types.JWEHeaderParameters.md b/docs/interfaces/types.JWEHeaderParameters.md index 1e0599f824..0dc2556f66 100644 --- a/docs/interfaces/types.JWEHeaderParameters.md +++ b/docs/interfaces/types.JWEHeaderParameters.md @@ -44,7 +44,7 @@ JWE "alg" (Algorithm) Header Parameter. #### Defined in -[types.d.ts:393](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L393) +[types.d.ts:393](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L393) ___ @@ -56,7 +56,7 @@ JWE "crit" (Critical) Header Parameter. #### Defined in -[types.d.ts:403](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L403) +[types.d.ts:403](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L403) ___ @@ -72,7 +72,7 @@ ___ #### Defined in -[types.d.ts:270](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L270) +[types.d.ts:270](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L270) ___ @@ -84,7 +84,7 @@ JWE "enc" (Encryption Algorithm) Header Parameter. #### Defined in -[types.d.ts:398](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L398) +[types.d.ts:398](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L398) ___ @@ -100,7 +100,7 @@ ___ #### Defined in -[types.d.ts:255](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L255) +[types.d.ts:255](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L255) ___ @@ -116,7 +116,7 @@ ___ #### Defined in -[types.d.ts:260](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L260) +[types.d.ts:260](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L260) ___ @@ -132,7 +132,7 @@ ___ #### Defined in -[types.d.ts:235](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L235) +[types.d.ts:235](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L235) ___ @@ -148,7 +148,7 @@ ___ #### Defined in -[types.d.ts:265](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L265) +[types.d.ts:265](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L265) ___ @@ -164,7 +164,7 @@ ___ #### Defined in -[types.d.ts:245](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L245) +[types.d.ts:245](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L245) ___ @@ -180,7 +180,7 @@ ___ #### Defined in -[types.d.ts:240](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L240) +[types.d.ts:240](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L240) ___ @@ -196,7 +196,7 @@ ___ #### Defined in -[types.d.ts:250](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L250) +[types.d.ts:250](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L250) ___ @@ -208,4 +208,4 @@ JWE "zip" (Compression Algorithm) Header Parameter. #### Defined in -[types.d.ts:408](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L408) +[types.d.ts:408](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L408) diff --git a/docs/interfaces/types.JWEKeyManagementHeaderParameters.md b/docs/interfaces/types.JWEKeyManagementHeaderParameters.md index b699e4acbb..9a732ad3af 100644 --- a/docs/interfaces/types.JWEKeyManagementHeaderParameters.md +++ b/docs/interfaces/types.JWEKeyManagementHeaderParameters.md @@ -23,7 +23,7 @@ Recognized JWE Key Management-related Header Parameters. #### Defined in -[types.d.ts:305](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L305) +[types.d.ts:305](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L305) ___ @@ -33,7 +33,7 @@ ___ #### Defined in -[types.d.ts:306](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L306) +[types.d.ts:306](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L306) ___ @@ -43,7 +43,7 @@ ___ #### Defined in -[types.d.ts:307](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L307) +[types.d.ts:307](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L307) ___ @@ -53,7 +53,7 @@ ___ #### Defined in -[types.d.ts:308](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L308) +[types.d.ts:308](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L308) ___ @@ -63,7 +63,7 @@ ___ #### Defined in -[types.d.ts:309](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L309) +[types.d.ts:309](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L309) ___ @@ -73,4 +73,4 @@ ___ #### Defined in -[types.d.ts:310](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L310) +[types.d.ts:310](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L310) diff --git a/docs/interfaces/types.JWK.md b/docs/interfaces/types.JWK.md index 81abf03bd4..bcdb37610a 100644 --- a/docs/interfaces/types.JWK.md +++ b/docs/interfaces/types.JWK.md @@ -47,7 +47,7 @@ JWK "alg" (Algorithm) Parameter. #### Defined in -[types.d.ts:84](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L84) +[types.d.ts:84](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L84) ___ @@ -57,7 +57,7 @@ ___ #### Defined in -[types.d.ts:85](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L85) +[types.d.ts:85](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L85) ___ @@ -67,7 +67,7 @@ ___ #### Defined in -[types.d.ts:86](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L86) +[types.d.ts:86](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L86) ___ @@ -77,7 +77,7 @@ ___ #### Defined in -[types.d.ts:87](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L87) +[types.d.ts:87](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L87) ___ @@ -87,7 +87,7 @@ ___ #### Defined in -[types.d.ts:88](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L88) +[types.d.ts:88](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L88) ___ @@ -97,7 +97,7 @@ ___ #### Defined in -[types.d.ts:89](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L89) +[types.d.ts:89](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L89) ___ @@ -109,7 +109,7 @@ JWK "ext" (Extractable) Parameter. #### Defined in -[types.d.ts:93](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L93) +[types.d.ts:93](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L93) ___ @@ -119,7 +119,7 @@ ___ #### Defined in -[types.d.ts:94](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L94) +[types.d.ts:94](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L94) ___ @@ -131,7 +131,7 @@ JWK "key_ops" (Key Operations) Parameter. #### Defined in -[types.d.ts:98](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L98) +[types.d.ts:98](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L98) ___ @@ -143,7 +143,7 @@ JWK "kid" (Key ID) Parameter. #### Defined in -[types.d.ts:102](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L102) +[types.d.ts:102](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L102) ___ @@ -155,7 +155,7 @@ JWK "kty" (Key Type) Parameter. #### Defined in -[types.d.ts:106](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L106) +[types.d.ts:106](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L106) ___ @@ -165,7 +165,7 @@ ___ #### Defined in -[types.d.ts:107](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L107) +[types.d.ts:107](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L107) ___ @@ -175,7 +175,7 @@ ___ #### Defined in -[types.d.ts:108](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L108) +[types.d.ts:108](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L108) ___ @@ -185,7 +185,7 @@ ___ #### Defined in -[types.d.ts:113](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L113) +[types.d.ts:113](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L113) ___ @@ -195,7 +195,7 @@ ___ #### Defined in -[types.d.ts:114](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L114) +[types.d.ts:114](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L114) ___ @@ -205,7 +205,7 @@ ___ #### Defined in -[types.d.ts:115](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L115) +[types.d.ts:115](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L115) ___ @@ -217,7 +217,7 @@ JWK "use" (Public Key Use) Parameter. #### Defined in -[types.d.ts:119](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L119) +[types.d.ts:119](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L119) ___ @@ -227,7 +227,7 @@ ___ #### Defined in -[types.d.ts:120](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L120) +[types.d.ts:120](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L120) ___ @@ -239,7 +239,7 @@ JWK "x5c" (X.509 Certificate Chain) Parameter. #### Defined in -[types.d.ts:125](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L125) +[types.d.ts:125](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L125) ___ @@ -251,7 +251,7 @@ JWK "x5t" (X.509 Certificate SHA-1 Thumbprint) Parameter. #### Defined in -[types.d.ts:129](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L129) +[types.d.ts:129](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L129) ___ @@ -263,7 +263,7 @@ ___ #### Defined in -[types.d.ts:133](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L133) +[types.d.ts:133](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L133) ___ @@ -275,7 +275,7 @@ JWK "x5u" (X.509 URL) Parameter. #### Defined in -[types.d.ts:137](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L137) +[types.d.ts:137](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L137) ___ @@ -285,4 +285,4 @@ ___ #### Defined in -[types.d.ts:121](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L121) +[types.d.ts:121](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L121) diff --git a/docs/interfaces/types.JWSHeaderParameters.md b/docs/interfaces/types.JWSHeaderParameters.md index 0b0bcbc4c0..e07ebfd5e9 100644 --- a/docs/interfaces/types.JWSHeaderParameters.md +++ b/docs/interfaces/types.JWSHeaderParameters.md @@ -43,7 +43,7 @@ JWS "alg" (Algorithm) Header Parameter. #### Defined in -[types.d.ts:281](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L281) +[types.d.ts:281](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L281) ___ @@ -57,7 +57,7 @@ representation and the JWS Signing Input computation as per #### Defined in -[types.d.ts:288](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L288) +[types.d.ts:288](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L288) ___ @@ -69,7 +69,7 @@ JWS "crit" (Critical) Header Parameter. #### Defined in -[types.d.ts:293](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L293) +[types.d.ts:293](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L293) ___ @@ -85,7 +85,7 @@ ___ #### Defined in -[types.d.ts:270](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L270) +[types.d.ts:270](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L270) ___ @@ -101,7 +101,7 @@ ___ #### Defined in -[types.d.ts:255](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L255) +[types.d.ts:255](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L255) ___ @@ -117,7 +117,7 @@ ___ #### Defined in -[types.d.ts:260](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L260) +[types.d.ts:260](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L260) ___ @@ -133,7 +133,7 @@ ___ #### Defined in -[types.d.ts:235](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L235) +[types.d.ts:235](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L235) ___ @@ -149,7 +149,7 @@ ___ #### Defined in -[types.d.ts:265](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L265) +[types.d.ts:265](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L265) ___ @@ -165,7 +165,7 @@ ___ #### Defined in -[types.d.ts:245](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L245) +[types.d.ts:245](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L245) ___ @@ -181,7 +181,7 @@ ___ #### Defined in -[types.d.ts:240](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L240) +[types.d.ts:240](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L240) ___ @@ -197,4 +197,4 @@ ___ #### Defined in -[types.d.ts:250](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L250) +[types.d.ts:250](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L250) diff --git a/docs/interfaces/types.JWTClaimVerificationOptions.md b/docs/interfaces/types.JWTClaimVerificationOptions.md index 453f20601a..ca810f9fe9 100644 --- a/docs/interfaces/types.JWTClaimVerificationOptions.md +++ b/docs/interfaces/types.JWTClaimVerificationOptions.md @@ -34,7 +34,7 @@ Expected JWT "aud" (Audience) Claim value(s). #### Defined in -[types.d.ts:486](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L486) +[types.d.ts:486](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L486) ___ @@ -48,7 +48,7 @@ Expected clock tolerance #### Defined in -[types.d.ts:493](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L493) +[types.d.ts:493](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L493) ___ @@ -60,7 +60,7 @@ Date to use when comparing NumericDate claims, defaults to `new Date()`. #### Defined in -[types.d.ts:520](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L520) +[types.d.ts:520](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L520) ___ @@ -72,7 +72,7 @@ Expected JWT "iss" (Issuer) Claim value(s). #### Defined in -[types.d.ts:498](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L498) +[types.d.ts:498](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L498) ___ @@ -86,7 +86,7 @@ Maximum time elapsed (in seconds) from the JWT "iat" (Issued At) Claim value. #### Defined in -[types.d.ts:505](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L505) +[types.d.ts:505](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L505) ___ @@ -98,7 +98,7 @@ Expected JWT "sub" (Subject) Claim value. #### Defined in -[types.d.ts:510](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L510) +[types.d.ts:510](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L510) ___ @@ -110,4 +110,4 @@ Expected JWT "typ" (Type) Header Parameter value. #### Defined in -[types.d.ts:515](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L515) +[types.d.ts:515](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L515) diff --git a/docs/interfaces/types.JWTDecryptResult.md b/docs/interfaces/types.JWTDecryptResult.md index 60dda00792..420892ac10 100644 --- a/docs/interfaces/types.JWTDecryptResult.md +++ b/docs/interfaces/types.JWTDecryptResult.md @@ -19,7 +19,7 @@ JWT Claims Set. #### Defined in -[types.d.ts:688](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L688) +[types.d.ts:688](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L688) ___ @@ -31,4 +31,4 @@ JWE Protected Header. #### Defined in -[types.d.ts:693](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L693) +[types.d.ts:693](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L693) diff --git a/docs/interfaces/types.JWTPayload.md b/docs/interfaces/types.JWTPayload.md index 06659e8afb..a584bae9d0 100644 --- a/docs/interfaces/types.JWTPayload.md +++ b/docs/interfaces/types.JWTPayload.md @@ -33,7 +33,7 @@ JWT Audience [RFC7519#section-4.1.3](https://tools.ietf.org/html/rfc7519#section #### Defined in -[types.d.ts:558](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L558) +[types.d.ts:558](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L558) ___ @@ -45,7 +45,7 @@ JWT Expiration Time - [RFC7519#section-4.1.4](https://tools.ietf.org/html/rfc751 #### Defined in -[types.d.ts:573](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L573) +[types.d.ts:573](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L573) ___ @@ -57,7 +57,7 @@ JWT Issued At - [RFC7519#section-4.1.6](https://tools.ietf.org/html/rfc7519#sect #### Defined in -[types.d.ts:578](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L578) +[types.d.ts:578](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L578) ___ @@ -69,7 +69,7 @@ JWT Issuer - [RFC7519#section-4.1.1](https://tools.ietf.org/html/rfc7519#section #### Defined in -[types.d.ts:548](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L548) +[types.d.ts:548](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L548) ___ @@ -81,7 +81,7 @@ JWT ID - [RFC7519#section-4.1.7](https://tools.ietf.org/html/rfc7519#section-4.1 #### Defined in -[types.d.ts:563](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L563) +[types.d.ts:563](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L563) ___ @@ -93,7 +93,7 @@ JWT Not Before - [RFC7519#section-4.1.5](https://tools.ietf.org/html/rfc7519#sec #### Defined in -[types.d.ts:568](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L568) +[types.d.ts:568](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L568) ___ @@ -105,4 +105,4 @@ JWT Subject - [RFC7519#section-4.1.2](https://tools.ietf.org/html/rfc7519#sectio #### Defined in -[types.d.ts:553](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L553) +[types.d.ts:553](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L553) diff --git a/docs/interfaces/types.JWTVerifyResult.md b/docs/interfaces/types.JWTVerifyResult.md index 5a1a1e7346..a4562ce378 100644 --- a/docs/interfaces/types.JWTVerifyResult.md +++ b/docs/interfaces/types.JWTVerifyResult.md @@ -19,7 +19,7 @@ JWT Claims Set. #### Defined in -[types.d.ts:676](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L676) +[types.d.ts:676](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L676) ___ @@ -31,4 +31,4 @@ JWS Protected Header. #### Defined in -[types.d.ts:681](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L681) +[types.d.ts:681](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L681) diff --git a/docs/interfaces/types.JoseHeaderParameters.md b/docs/interfaces/types.JoseHeaderParameters.md index eaadcbac7a..57221a05d6 100644 --- a/docs/interfaces/types.JoseHeaderParameters.md +++ b/docs/interfaces/types.JoseHeaderParameters.md @@ -33,7 +33,7 @@ #### Defined in -[types.d.ts:270](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L270) +[types.d.ts:270](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L270) ___ @@ -45,7 +45,7 @@ ___ #### Defined in -[types.d.ts:255](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L255) +[types.d.ts:255](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L255) ___ @@ -57,7 +57,7 @@ ___ #### Defined in -[types.d.ts:260](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L260) +[types.d.ts:260](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L260) ___ @@ -69,7 +69,7 @@ ___ #### Defined in -[types.d.ts:235](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L235) +[types.d.ts:235](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L235) ___ @@ -81,7 +81,7 @@ ___ #### Defined in -[types.d.ts:265](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L265) +[types.d.ts:265](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L265) ___ @@ -93,7 +93,7 @@ ___ #### Defined in -[types.d.ts:245](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L245) +[types.d.ts:245](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L245) ___ @@ -105,7 +105,7 @@ ___ #### Defined in -[types.d.ts:240](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L240) +[types.d.ts:240](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L240) ___ @@ -117,4 +117,4 @@ ___ #### Defined in -[types.d.ts:250](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L250) +[types.d.ts:250](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L250) diff --git a/docs/interfaces/types.SignOptions.md b/docs/interfaces/types.SignOptions.md index 26b60bde0e..8945a6898e 100644 --- a/docs/interfaces/types.SignOptions.md +++ b/docs/interfaces/types.SignOptions.md @@ -51,4 +51,4 @@ default built-in treatment are currently available. #### Defined in -[types.d.ts:440](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L440) +[types.d.ts:440](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L440) diff --git a/docs/interfaces/types.VerifyOptions.md b/docs/interfaces/types.VerifyOptions.md index d3bd2a4385..39acbe2f26 100644 --- a/docs/interfaces/types.VerifyOptions.md +++ b/docs/interfaces/types.VerifyOptions.md @@ -31,7 +31,7 @@ key/secret are allowed. Note: "none" is never accepted. #### Defined in -[types.d.ts:532](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L532) +[types.d.ts:532](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L532) ___ @@ -68,4 +68,4 @@ default built-in treatment are currently available. #### Defined in -[types.d.ts:440](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L440) +[types.d.ts:440](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L440) diff --git a/docs/interfaces/util_generate_key_pair.GenerateKeyPairOptions.md b/docs/interfaces/util_generate_key_pair.GenerateKeyPairOptions.md index 1d1969c8d0..42254468bb 100644 --- a/docs/interfaces/util_generate_key_pair.GenerateKeyPairOptions.md +++ b/docs/interfaces/util_generate_key_pair.GenerateKeyPairOptions.md @@ -22,7 +22,7 @@ the given JWA algorithm identifier. #### Defined in -[util/generate_key_pair.ts:22](https://github.com/panva/jose/blob/v3.16.0/src/util/generate_key_pair.ts#L22) +[util/generate_key_pair.ts:22](https://github.com/panva/jose/blob/v3.16.1/src/util/generate_key_pair.ts#L22) ___ @@ -36,7 +36,7 @@ ___ #### Defined in -[util/generate_key_pair.ts:35](https://github.com/panva/jose/blob/v3.16.0/src/util/generate_key_pair.ts#L35) +[util/generate_key_pair.ts:35](https://github.com/panva/jose/blob/v3.16.1/src/util/generate_key_pair.ts#L35) ___ @@ -49,4 +49,4 @@ A hint for RSA algorithms to generate an RSA key of a given `modulusLength` #### Defined in -[util/generate_key_pair.ts:28](https://github.com/panva/jose/blob/v3.16.0/src/util/generate_key_pair.ts#L28) +[util/generate_key_pair.ts:28](https://github.com/panva/jose/blob/v3.16.1/src/util/generate_key_pair.ts#L28) diff --git a/docs/interfaces/util_generate_key_pair.GenerateKeyPairResult.md b/docs/interfaces/util_generate_key_pair.GenerateKeyPairResult.md index f2c163838b..03166923e5 100644 --- a/docs/interfaces/util_generate_key_pair.GenerateKeyPairResult.md +++ b/docs/interfaces/util_generate_key_pair.GenerateKeyPairResult.md @@ -19,7 +19,7 @@ The generated Private Key. #### Defined in -[util/generate_key_pair.ts:8](https://github.com/panva/jose/blob/v3.16.0/src/util/generate_key_pair.ts#L8) +[util/generate_key_pair.ts:8](https://github.com/panva/jose/blob/v3.16.1/src/util/generate_key_pair.ts#L8) ___ @@ -31,4 +31,4 @@ Public Key corresponding to the generated Private Key. #### Defined in -[util/generate_key_pair.ts:13](https://github.com/panva/jose/blob/v3.16.0/src/util/generate_key_pair.ts#L13) +[util/generate_key_pair.ts:13](https://github.com/panva/jose/blob/v3.16.1/src/util/generate_key_pair.ts#L13) diff --git a/docs/interfaces/util_generate_secret.GenerateSecretOptions.md b/docs/interfaces/util_generate_secret.GenerateSecretOptions.md index 7fb85e993e..b214ca32e1 100644 --- a/docs/interfaces/util_generate_secret.GenerateSecretOptions.md +++ b/docs/interfaces/util_generate_secret.GenerateSecretOptions.md @@ -20,4 +20,4 @@ #### Defined in -[util/generate_secret.ts:10](https://github.com/panva/jose/blob/v3.16.0/src/util/generate_secret.ts#L10) +[util/generate_secret.ts:10](https://github.com/panva/jose/blob/v3.16.1/src/util/generate_secret.ts#L10) diff --git a/docs/types/types.KeyLike.md b/docs/types/types.KeyLike.md index 5291fb6f19..d24a43d176 100644 --- a/docs/types/types.KeyLike.md +++ b/docs/types/types.KeyLike.md @@ -73,4 +73,4 @@ const rsaPublicKey = await parseJwk({ #### Defined in -[types.d.ts:74](https://github.com/panva/jose/blob/v3.16.0/src/types.d.ts#L74) +[types.d.ts:74](https://github.com/panva/jose/blob/v3.16.1/src/types.d.ts#L74) diff --git a/docs/types/util_decode_protected_header.ProtectedHeaderParameters.md b/docs/types/util_decode_protected_header.ProtectedHeaderParameters.md index df272adec3..806a9590b9 100644 --- a/docs/types/util_decode_protected_header.ProtectedHeaderParameters.md +++ b/docs/types/util_decode_protected_header.ProtectedHeaderParameters.md @@ -6,4 +6,4 @@ #### Defined in -[util/decode_protected_header.ts:6](https://github.com/panva/jose/blob/v3.16.0/src/util/decode_protected_header.ts#L6) +[util/decode_protected_header.ts:6](https://github.com/panva/jose/blob/v3.16.1/src/util/decode_protected_header.ts#L6) diff --git a/package.json b/package.json index 2da7b310e1..6c79381fc7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "jose", - "version": "3.16.0", + "version": "3.16.1", "description": "Universal 'JSON Web Almost Everything' - JWA, JWS, JWE, JWT, JWK with no dependencies", "keywords": [ "browser",