crypto_key.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.checkEncCryptoKey = exports.checkSigCryptoKey = void 0;
  4. function unusable(name, prop = 'algorithm.name') {
  5. return new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
  6. }
  7. function isAlgorithm(algorithm, name) {
  8. return algorithm.name === name;
  9. }
  10. function getHashLength(hash) {
  11. return parseInt(hash.name.slice(4), 10);
  12. }
  13. function getNamedCurve(alg) {
  14. switch (alg) {
  15. case 'ES256':
  16. return 'P-256';
  17. case 'ES384':
  18. return 'P-384';
  19. case 'ES512':
  20. return 'P-521';
  21. default:
  22. throw new Error('unreachable');
  23. }
  24. }
  25. function checkUsage(key, usages) {
  26. if (usages.length && !usages.some((expected) => key.usages.includes(expected))) {
  27. let msg = 'CryptoKey does not support this operation, its usages must include ';
  28. if (usages.length > 2) {
  29. const last = usages.pop();
  30. msg += `one of ${usages.join(', ')}, or ${last}.`;
  31. }
  32. else if (usages.length === 2) {
  33. msg += `one of ${usages[0]} or ${usages[1]}.`;
  34. }
  35. else {
  36. msg += `${usages[0]}.`;
  37. }
  38. throw new TypeError(msg);
  39. }
  40. }
  41. function checkSigCryptoKey(key, alg, ...usages) {
  42. switch (alg) {
  43. case 'HS256':
  44. case 'HS384':
  45. case 'HS512': {
  46. if (!isAlgorithm(key.algorithm, 'HMAC'))
  47. throw unusable('HMAC');
  48. const expected = parseInt(alg.slice(2), 10);
  49. const actual = getHashLength(key.algorithm.hash);
  50. if (actual !== expected)
  51. throw unusable(`SHA-${expected}`, 'algorithm.hash');
  52. break;
  53. }
  54. case 'RS256':
  55. case 'RS384':
  56. case 'RS512': {
  57. if (!isAlgorithm(key.algorithm, 'RSASSA-PKCS1-v1_5'))
  58. throw unusable('RSASSA-PKCS1-v1_5');
  59. const expected = parseInt(alg.slice(2), 10);
  60. const actual = getHashLength(key.algorithm.hash);
  61. if (actual !== expected)
  62. throw unusable(`SHA-${expected}`, 'algorithm.hash');
  63. break;
  64. }
  65. case 'PS256':
  66. case 'PS384':
  67. case 'PS512': {
  68. if (!isAlgorithm(key.algorithm, 'RSA-PSS'))
  69. throw unusable('RSA-PSS');
  70. const expected = parseInt(alg.slice(2), 10);
  71. const actual = getHashLength(key.algorithm.hash);
  72. if (actual !== expected)
  73. throw unusable(`SHA-${expected}`, 'algorithm.hash');
  74. break;
  75. }
  76. case 'EdDSA': {
  77. if (key.algorithm.name !== 'Ed25519' && key.algorithm.name !== 'Ed448') {
  78. throw unusable('Ed25519 or Ed448');
  79. }
  80. break;
  81. }
  82. case 'ES256':
  83. case 'ES384':
  84. case 'ES512': {
  85. if (!isAlgorithm(key.algorithm, 'ECDSA'))
  86. throw unusable('ECDSA');
  87. const expected = getNamedCurve(alg);
  88. const actual = key.algorithm.namedCurve;
  89. if (actual !== expected)
  90. throw unusable(expected, 'algorithm.namedCurve');
  91. break;
  92. }
  93. default:
  94. throw new TypeError('CryptoKey does not support this operation');
  95. }
  96. checkUsage(key, usages);
  97. }
  98. exports.checkSigCryptoKey = checkSigCryptoKey;
  99. function checkEncCryptoKey(key, alg, ...usages) {
  100. switch (alg) {
  101. case 'A128GCM':
  102. case 'A192GCM':
  103. case 'A256GCM': {
  104. if (!isAlgorithm(key.algorithm, 'AES-GCM'))
  105. throw unusable('AES-GCM');
  106. const expected = parseInt(alg.slice(1, 4), 10);
  107. const actual = key.algorithm.length;
  108. if (actual !== expected)
  109. throw unusable(expected, 'algorithm.length');
  110. break;
  111. }
  112. case 'A128KW':
  113. case 'A192KW':
  114. case 'A256KW': {
  115. if (!isAlgorithm(key.algorithm, 'AES-KW'))
  116. throw unusable('AES-KW');
  117. const expected = parseInt(alg.slice(1, 4), 10);
  118. const actual = key.algorithm.length;
  119. if (actual !== expected)
  120. throw unusable(expected, 'algorithm.length');
  121. break;
  122. }
  123. case 'ECDH': {
  124. switch (key.algorithm.name) {
  125. case 'ECDH':
  126. case 'X25519':
  127. case 'X448':
  128. break;
  129. default:
  130. throw unusable('ECDH, X25519, or X448');
  131. }
  132. break;
  133. }
  134. case 'PBES2-HS256+A128KW':
  135. case 'PBES2-HS384+A192KW':
  136. case 'PBES2-HS512+A256KW':
  137. if (!isAlgorithm(key.algorithm, 'PBKDF2'))
  138. throw unusable('PBKDF2');
  139. break;
  140. case 'RSA-OAEP':
  141. case 'RSA-OAEP-256':
  142. case 'RSA-OAEP-384':
  143. case 'RSA-OAEP-512': {
  144. if (!isAlgorithm(key.algorithm, 'RSA-OAEP'))
  145. throw unusable('RSA-OAEP');
  146. const expected = parseInt(alg.slice(9), 10) || 1;
  147. const actual = getHashLength(key.algorithm.hash);
  148. if (actual !== expected)
  149. throw unusable(`SHA-${expected}`, 'algorithm.hash');
  150. break;
  151. }
  152. default:
  153. throw new TypeError('CryptoKey does not support this operation');
  154. }
  155. checkUsage(key, usages);
  156. }
  157. exports.checkEncCryptoKey = checkEncCryptoKey;