mirror of
https://github.com/danbulant/jose
synced 2026-05-19 20:38:42 +00:00
155 lines
6.2 KiB
JavaScript
155 lines
6.2 KiB
JavaScript
import * as crypto from 'crypto';
|
|
import * as util from 'util';
|
|
const webcrypto = crypto.webcrypto;
|
|
export default webcrypto;
|
|
export const isCryptoKey = util.types.isCryptoKey
|
|
? (obj) => util.types.isCryptoKey(obj)
|
|
:
|
|
(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';
|
|
}
|
|
}
|
|
export function getKeyObject(key, alg, usage) {
|
|
switch (alg) {
|
|
case undefined:
|
|
break;
|
|
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 'EdDSA': {
|
|
if (key.algorithm.name !== 'NODE-ED25519' && key.algorithm.name !== 'NODE-ED448') {
|
|
throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be NODE-ED25519 or NODE-ED448.`);
|
|
}
|
|
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);
|
|
}
|