signing.js 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. import { JOSENotSupported } from '../util/errors.js';
  2. import { checkSigCryptoKey } from './crypto_key.js';
  3. import { invalidKeyInput } from './invalid_key_input.js';
  4. export function checkKeyLength(alg, key) {
  5. if (alg.startsWith('RS') || alg.startsWith('PS')) {
  6. const { modulusLength } = key.algorithm;
  7. if (typeof modulusLength !== 'number' || modulusLength < 2048) {
  8. throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);
  9. }
  10. }
  11. }
  12. function subtleAlgorithm(alg, algorithm) {
  13. const hash = `SHA-${alg.slice(-3)}`;
  14. switch (alg) {
  15. case 'HS256':
  16. case 'HS384':
  17. case 'HS512':
  18. return { hash, name: 'HMAC' };
  19. case 'PS256':
  20. case 'PS384':
  21. case 'PS512':
  22. return { hash, name: 'RSA-PSS', saltLength: parseInt(alg.slice(-3), 10) >> 3 };
  23. case 'RS256':
  24. case 'RS384':
  25. case 'RS512':
  26. return { hash, name: 'RSASSA-PKCS1-v1_5' };
  27. case 'ES256':
  28. case 'ES384':
  29. case 'ES512':
  30. return { hash, name: 'ECDSA', namedCurve: algorithm.namedCurve };
  31. case 'Ed25519':
  32. case 'EdDSA':
  33. return { name: 'Ed25519' };
  34. case 'ML-DSA-44':
  35. case 'ML-DSA-65':
  36. case 'ML-DSA-87':
  37. return { name: alg };
  38. default:
  39. throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
  40. }
  41. }
  42. async function getSigKey(alg, key, usage) {
  43. if (key instanceof Uint8Array) {
  44. if (!alg.startsWith('HS')) {
  45. throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'KeyObject', 'JSON Web Key'));
  46. }
  47. return crypto.subtle.importKey('raw', key, { hash: `SHA-${alg.slice(-3)}`, name: 'HMAC' }, false, [usage]);
  48. }
  49. checkSigCryptoKey(key, alg, usage);
  50. return key;
  51. }
  52. export async function sign(alg, key, data) {
  53. const cryptoKey = await getSigKey(alg, key, 'sign');
  54. checkKeyLength(alg, cryptoKey);
  55. const signature = await crypto.subtle.sign(subtleAlgorithm(alg, cryptoKey.algorithm), cryptoKey, data);
  56. return new Uint8Array(signature);
  57. }
  58. export async function verify(alg, key, signature, data) {
  59. const cryptoKey = await getSigKey(alg, key, 'verify');
  60. checkKeyLength(alg, cryptoKey);
  61. const algorithm = subtleAlgorithm(alg, cryptoKey.algorithm);
  62. try {
  63. return await crypto.subtle.verify(algorithm, cryptoKey, signature, data);
  64. }
  65. catch {
  66. return false;
  67. }
  68. }