feat: 초기 프로젝트 설정 및 룰.md 파일 추가

This commit is contained in:
2025-07-28 09:53:31 +09:00
commit 09a4d38512
8165 changed files with 1021855 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
import { COSEALG } from '../../cose.js';
/**
* Generate a digest of the provided data.
*
* @param data The data to generate a digest of
* @param algorithm A COSE algorithm ID that maps to a desired SHA algorithm
*/
export declare function digest(data: Uint8Array, algorithm: COSEALG): Promise<Uint8Array>;
//# sourceMappingURL=digest.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"digest.d.ts","sourceRoot":"","sources":["../../../../src/helpers/iso/isoCrypto/digest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAIxC;;;;;GAKG;AACH,wBAAsB,MAAM,CAC1B,IAAI,EAAE,UAAU,EAChB,SAAS,EAAE,OAAO,GACjB,OAAO,CAAC,UAAU,CAAC,CAQrB"}

View File

@@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.digest = digest;
const mapCoseAlgToWebCryptoAlg_js_1 = require("./mapCoseAlgToWebCryptoAlg.js");
const getWebCrypto_js_1 = require("./getWebCrypto.js");
/**
* Generate a digest of the provided data.
*
* @param data The data to generate a digest of
* @param algorithm A COSE algorithm ID that maps to a desired SHA algorithm
*/
async function digest(data, algorithm) {
const WebCrypto = await (0, getWebCrypto_js_1.getWebCrypto)();
const subtleAlgorithm = (0, mapCoseAlgToWebCryptoAlg_js_1.mapCoseAlgToWebCryptoAlg)(algorithm);
const hashed = await WebCrypto.subtle.digest(subtleAlgorithm, data);
return new Uint8Array(hashed);
}

View File

@@ -0,0 +1,7 @@
/**
* Fill up the provided bytes array with random bytes equal to its length.
*
* @returns the same bytes array passed into the method
*/
export declare function getRandomValues(array: Uint8Array): Promise<Uint8Array>;
//# sourceMappingURL=getRandomValues.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"getRandomValues.d.ts","sourceRoot":"","sources":["../../../../src/helpers/iso/isoCrypto/getRandomValues.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAM5E"}

View File

@@ -0,0 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getRandomValues = getRandomValues;
const getWebCrypto_js_1 = require("./getWebCrypto.js");
/**
* Fill up the provided bytes array with random bytes equal to its length.
*
* @returns the same bytes array passed into the method
*/
async function getRandomValues(array) {
const WebCrypto = await (0, getWebCrypto_js_1.getWebCrypto)();
WebCrypto.getRandomValues(array);
return array;
}

View File

@@ -0,0 +1,14 @@
import type { Crypto } from '../../../types/index.js';
/**
* Try to get an instance of the Crypto API from the current runtime. Should support Node,
* as well as others, like Deno, that implement Web APIs.
*/
export declare function getWebCrypto(): Promise<Crypto>;
export declare class MissingWebCrypto extends Error {
constructor();
}
export declare const _getWebCryptoInternals: {
stubThisGlobalThisCrypto: () => import("crypto").webcrypto.Crypto;
setCachedCrypto: (newCrypto: Crypto | undefined) => void;
};
//# sourceMappingURL=getWebCrypto.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"getWebCrypto.d.ts","sourceRoot":"","sources":["../../../../src/helpers/iso/isoCrypto/getWebCrypto.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAItD;;;GAGG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAgC9C;AAED,qBAAa,gBAAiB,SAAQ,KAAK;;CAM1C;AAGD,eAAO,MAAM,sBAAsB;;iCAGJ,MAAM,GAAG,SAAS;CAGhD,CAAC"}

View File

@@ -0,0 +1,54 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports._getWebCryptoInternals = exports.MissingWebCrypto = void 0;
exports.getWebCrypto = getWebCrypto;
let webCrypto = undefined;
/**
* Try to get an instance of the Crypto API from the current runtime. Should support Node,
* as well as others, like Deno, that implement Web APIs.
*/
function getWebCrypto() {
/**
* Hello there! If you came here wondering why this method is asynchronous when use of
* `globalThis.crypto` is not, it's to minimize a bunch of refactor related to making this
* synchronous. For example, `generateRegistrationOptions()` and `generateAuthenticationOptions()`
* become synchronous if we make this synchronous (since nothing else in that method is async)
* which represents a breaking API change in this library's core API.
*
* TODO: If it's after February 2025 when you read this then consider whether it still makes sense
* to keep this method asynchronous.
*/
const toResolve = new Promise((resolve, reject) => {
if (webCrypto) {
return resolve(webCrypto);
}
/**
* Naively attempt to access Crypto as a global object, which popular ESM-centric run-times
* support (and Node v20+)
*/
const _globalThisCrypto = exports._getWebCryptoInternals.stubThisGlobalThisCrypto();
if (_globalThisCrypto) {
webCrypto = _globalThisCrypto;
return resolve(webCrypto);
}
// We tried to access it both in Node and globally, so bail out
return reject(new MissingWebCrypto());
});
return toResolve;
}
class MissingWebCrypto extends Error {
constructor() {
const message = 'An instance of the Crypto API could not be located';
super(message);
this.name = 'MissingWebCrypto';
}
}
exports.MissingWebCrypto = MissingWebCrypto;
// Make it possible to stub return values during testing
exports._getWebCryptoInternals = {
stubThisGlobalThisCrypto: () => globalThis.crypto,
// Make it possible to reset the `webCrypto` at the top of the file
setCachedCrypto: (newCrypto) => {
webCrypto = newCrypto;
},
};

View File

@@ -0,0 +1,5 @@
export declare function importKey(opts: {
keyData: JsonWebKey;
algorithm: AlgorithmIdentifier | RsaHashedImportParams | EcKeyImportParams;
}): Promise<CryptoKey>;
//# sourceMappingURL=importKey.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"importKey.d.ts","sourceRoot":"","sources":["../../../../src/helpers/iso/isoCrypto/importKey.ts"],"names":[],"mappings":"AAEA,wBAAsB,SAAS,CAAC,IAAI,EAAE;IACpC,OAAO,EAAE,UAAU,CAAC;IACpB,SAAS,EAAE,mBAAmB,GAAG,qBAAqB,GAAG,iBAAiB,CAAC;CAC5E,GAAG,OAAO,CAAC,SAAS,CAAC,CAQrB"}

View File

@@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.importKey = importKey;
const getWebCrypto_js_1 = require("./getWebCrypto.js");
async function importKey(opts) {
const WebCrypto = await (0, getWebCrypto_js_1.getWebCrypto)();
const { keyData, algorithm } = opts;
return WebCrypto.subtle.importKey('jwk', keyData, algorithm, false, [
'verify',
]);
}

View File

@@ -0,0 +1,8 @@
/**
* A runtime-agnostic collection of methods for working with the WebCrypto API
* @module
*/
export { digest } from './digest.js';
export { getRandomValues } from './getRandomValues.js';
export { verify } from './verify.js';
//# sourceMappingURL=index.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/helpers/iso/isoCrypto/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC"}

View File

@@ -0,0 +1,13 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.verify = exports.getRandomValues = exports.digest = void 0;
/**
* A runtime-agnostic collection of methods for working with the WebCrypto API
* @module
*/
var digest_js_1 = require("./digest.js");
Object.defineProperty(exports, "digest", { enumerable: true, get: function () { return digest_js_1.digest; } });
var getRandomValues_js_1 = require("./getRandomValues.js");
Object.defineProperty(exports, "getRandomValues", { enumerable: true, get: function () { return getRandomValues_js_1.getRandomValues; } });
var verify_js_1 = require("./verify.js");
Object.defineProperty(exports, "verify", { enumerable: true, get: function () { return verify_js_1.verify; } });

View File

@@ -0,0 +1,7 @@
import { SubtleCryptoAlg } from './structs.js';
import { COSEALG } from '../../cose.js';
/**
* Convert a COSE alg ID into a corresponding string value that WebCrypto APIs expect
*/
export declare function mapCoseAlgToWebCryptoAlg(alg: COSEALG): SubtleCryptoAlg;
//# sourceMappingURL=mapCoseAlgToWebCryptoAlg.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"mapCoseAlgToWebCryptoAlg.d.ts","sourceRoot":"","sources":["../../../../src/helpers/iso/isoCrypto/mapCoseAlgToWebCryptoAlg.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,OAAO,GAAG,eAAe,CAetE"}

View File

@@ -0,0 +1,23 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.mapCoseAlgToWebCryptoAlg = mapCoseAlgToWebCryptoAlg;
const cose_js_1 = require("../../cose.js");
/**
* Convert a COSE alg ID into a corresponding string value that WebCrypto APIs expect
*/
function mapCoseAlgToWebCryptoAlg(alg) {
if ([cose_js_1.COSEALG.RS1].indexOf(alg) >= 0) {
return 'SHA-1';
}
else if ([cose_js_1.COSEALG.ES256, cose_js_1.COSEALG.PS256, cose_js_1.COSEALG.RS256].indexOf(alg) >= 0) {
return 'SHA-256';
}
else if ([cose_js_1.COSEALG.ES384, cose_js_1.COSEALG.PS384, cose_js_1.COSEALG.RS384].indexOf(alg) >= 0) {
return 'SHA-384';
}
else if ([cose_js_1.COSEALG.ES512, cose_js_1.COSEALG.PS512, cose_js_1.COSEALG.RS512, cose_js_1.COSEALG.EdDSA].indexOf(alg) >=
0) {
return 'SHA-512';
}
throw new Error(`Could not map COSE alg value of ${alg} to a WebCrypto alg`);
}

View File

@@ -0,0 +1,7 @@
import { COSEALG } from '../../cose.js';
import { SubtleCryptoKeyAlgName } from './structs.js';
/**
* Convert a COSE alg ID into a corresponding key algorithm string value that WebCrypto APIs expect
*/
export declare function mapCoseAlgToWebCryptoKeyAlgName(alg: COSEALG): SubtleCryptoKeyAlgName;
//# sourceMappingURL=mapCoseAlgToWebCryptoKeyAlgName.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"mapCoseAlgToWebCryptoKeyAlgName.d.ts","sourceRoot":"","sources":["../../../../src/helpers/iso/isoCrypto/mapCoseAlgToWebCryptoKeyAlgName.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAEtD;;GAEG;AACH,wBAAgB,+BAA+B,CAC7C,GAAG,EAAE,OAAO,GACX,sBAAsB,CAoBxB"}

View File

@@ -0,0 +1,22 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.mapCoseAlgToWebCryptoKeyAlgName = mapCoseAlgToWebCryptoKeyAlgName;
const cose_js_1 = require("../../cose.js");
/**
* Convert a COSE alg ID into a corresponding key algorithm string value that WebCrypto APIs expect
*/
function mapCoseAlgToWebCryptoKeyAlgName(alg) {
if ([cose_js_1.COSEALG.EdDSA].indexOf(alg) >= 0) {
return 'Ed25519';
}
else if ([cose_js_1.COSEALG.ES256, cose_js_1.COSEALG.ES384, cose_js_1.COSEALG.ES512, cose_js_1.COSEALG.ES256K].indexOf(alg) >= 0) {
return 'ECDSA';
}
else if ([cose_js_1.COSEALG.RS256, cose_js_1.COSEALG.RS384, cose_js_1.COSEALG.RS512, cose_js_1.COSEALG.RS1].indexOf(alg) >= 0) {
return 'RSASSA-PKCS1-v1_5';
}
else if ([cose_js_1.COSEALG.PS256, cose_js_1.COSEALG.PS384, cose_js_1.COSEALG.PS512].indexOf(alg) >= 0) {
return 'RSA-PSS';
}
throw new Error(`Could not map COSE alg value of ${alg} to a WebCrypto key alg name`);
}

View File

@@ -0,0 +1,4 @@
export type SubtleCryptoAlg = 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512';
export type SubtleCryptoCrv = 'P-256' | 'P-384' | 'P-521' | 'Ed25519';
export type SubtleCryptoKeyAlgName = 'ECDSA' | 'Ed25519' | 'RSASSA-PKCS1-v1_5' | 'RSA-PSS';
//# sourceMappingURL=structs.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"structs.d.ts","sourceRoot":"","sources":["../../../../src/helpers/iso/isoCrypto/structs.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAC1E,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;AACtE,MAAM,MAAM,sBAAsB,GAC9B,OAAO,GACP,SAAS,GACT,mBAAmB,GACnB,SAAS,CAAC"}

View File

@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@@ -0,0 +1,8 @@
import { COSECRV } from '../../cose.js';
/**
* In WebAuthn, EC2 signatures are wrapped in ASN.1 structure so we need to peel r and s apart.
*
* See https://www.w3.org/TR/webauthn-2/#sctn-signature-attestation-types
*/
export declare function unwrapEC2Signature(signature: Uint8Array, crv: COSECRV): Uint8Array;
//# sourceMappingURL=unwrapEC2Signature.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"unwrapEC2Signature.d.ts","sourceRoot":"","sources":["../../../../src/helpers/iso/isoCrypto/unwrapEC2Signature.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAGxC;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,GAAG,UAAU,CAelF"}

View File

@@ -0,0 +1,76 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.unwrapEC2Signature = unwrapEC2Signature;
const asn1_schema_1 = require("@peculiar/asn1-schema");
const asn1_ecc_1 = require("@peculiar/asn1-ecc");
const cose_js_1 = require("../../cose.js");
const index_js_1 = require("../index.js");
/**
* In WebAuthn, EC2 signatures are wrapped in ASN.1 structure so we need to peel r and s apart.
*
* See https://www.w3.org/TR/webauthn-2/#sctn-signature-attestation-types
*/
function unwrapEC2Signature(signature, crv) {
const parsedSignature = asn1_schema_1.AsnParser.parse(signature, asn1_ecc_1.ECDSASigValue);
const rBytes = new Uint8Array(parsedSignature.r);
const sBytes = new Uint8Array(parsedSignature.s);
const componentLength = getSignatureComponentLength(crv);
const rNormalizedBytes = toNormalizedBytes(rBytes, componentLength);
const sNormalizedBytes = toNormalizedBytes(sBytes, componentLength);
const finalSignature = index_js_1.isoUint8Array.concat([
rNormalizedBytes,
sNormalizedBytes,
]);
return finalSignature;
}
/**
* The SubtleCrypto Web Crypto API expects ECDSA signatures with `r` and `s` values to be encoded
* to a specific length depending on the order of the curve. This function returns the expected
* byte-length for each of the `r` and `s` signature components.
*
* See <https://www.w3.org/TR/WebCryptoAPI/#ecdsa-operations>
*/
function getSignatureComponentLength(crv) {
switch (crv) {
case cose_js_1.COSECRV.P256:
return 32;
case cose_js_1.COSECRV.P384:
return 48;
case cose_js_1.COSECRV.P521:
return 66;
default:
throw new Error(`Unexpected COSE crv value of ${crv} (EC2)`);
}
}
/**
* Converts the ASN.1 integer representation to bytes of a specific length `n`.
*
* DER encodes integers as big-endian byte arrays, with as small as possible representation and
* requires a leading `0` byte to disambiguate between negative and positive numbers. This means
* that `r` and `s` can potentially not be the expected byte-length that is needed by the
* SubtleCrypto Web Crypto API: if there are leading `0`s it can be shorter than expected, and if
* it has a leading `1` bit, it can be one byte longer.
*
* See <https://www.itu.int/rec/T-REC-X.690-202102-I/en>
* See <https://www.w3.org/TR/WebCryptoAPI/#ecdsa-operations>
*/
function toNormalizedBytes(bytes, componentLength) {
let normalizedBytes;
if (bytes.length < componentLength) {
// In case the bytes are shorter than expected, we need to pad it with leading `0`s.
normalizedBytes = new Uint8Array(componentLength);
normalizedBytes.set(bytes, componentLength - bytes.length);
}
else if (bytes.length === componentLength) {
normalizedBytes = bytes;
}
else if (bytes.length === componentLength + 1 && bytes[0] === 0 && (bytes[1] & 0x80) === 0x80) {
// The bytes contain a leading `0` to encode that the integer is positive. This leading `0`
// needs to be removed for compatibility with the SubtleCrypto Web Crypto API.
normalizedBytes = bytes.subarray(1);
}
else {
throw new Error(`Invalid signature component length ${bytes.length}, expected ${componentLength}`);
}
return normalizedBytes;
}

View File

@@ -0,0 +1,11 @@
import { COSEALG, COSEPublicKey } from '../../cose.js';
/**
* Verify signatures with their public key. Supports EC2 and RSA public keys.
*/
export declare function verify(opts: {
cosePublicKey: COSEPublicKey;
signature: Uint8Array;
data: Uint8Array;
shaHashOverride?: COSEALG;
}): Promise<boolean>;
//# sourceMappingURL=verify.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../../../src/helpers/iso/isoCrypto/verify.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EAEP,aAAa,EAKd,MAAM,eAAe,CAAC;AAMvB;;GAEG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE;IAC3B,aAAa,EAAE,aAAa,CAAC;IAC7B,SAAS,EAAE,UAAU,CAAC;IACtB,IAAI,EAAE,UAAU,CAAC;IACjB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,GAAG,OAAO,CAAC,OAAO,CAAC,CAyBnB"}

View File

@@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.verify = verify;
const cose_js_1 = require("../../cose.js");
const verifyEC2_js_1 = require("./verifyEC2.js");
const verifyRSA_js_1 = require("./verifyRSA.js");
const verifyOKP_js_1 = require("./verifyOKP.js");
const unwrapEC2Signature_js_1 = require("./unwrapEC2Signature.js");
/**
* Verify signatures with their public key. Supports EC2 and RSA public keys.
*/
function verify(opts) {
const { cosePublicKey, signature, data, shaHashOverride } = opts;
if ((0, cose_js_1.isCOSEPublicKeyEC2)(cosePublicKey)) {
const crv = cosePublicKey.get(cose_js_1.COSEKEYS.crv);
if (!(0, cose_js_1.isCOSECrv)(crv)) {
throw new Error(`unknown COSE curve ${crv}`);
}
const unwrappedSignature = (0, unwrapEC2Signature_js_1.unwrapEC2Signature)(signature, crv);
return (0, verifyEC2_js_1.verifyEC2)({
cosePublicKey,
signature: unwrappedSignature,
data,
shaHashOverride,
});
}
else if ((0, cose_js_1.isCOSEPublicKeyRSA)(cosePublicKey)) {
return (0, verifyRSA_js_1.verifyRSA)({ cosePublicKey, signature, data, shaHashOverride });
}
else if ((0, cose_js_1.isCOSEPublicKeyOKP)(cosePublicKey)) {
return (0, verifyOKP_js_1.verifyOKP)({ cosePublicKey, signature, data });
}
const kty = cosePublicKey.get(cose_js_1.COSEKEYS.kty);
throw new Error(`Signature verification with public key of kty ${kty} is not supported by this method`);
}

View File

@@ -0,0 +1,11 @@
import { COSEALG, COSEPublicKeyEC2 } from '../../cose.js';
/**
* Verify a signature using an EC2 public key
*/
export declare function verifyEC2(opts: {
cosePublicKey: COSEPublicKeyEC2;
signature: Uint8Array;
data: Uint8Array;
shaHashOverride?: COSEALG;
}): Promise<boolean>;
//# sourceMappingURL=verifyEC2.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"verifyEC2.d.ts","sourceRoot":"","sources":["../../../../src/helpers/iso/isoCrypto/verifyEC2.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAqB,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAO7E;;GAEG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE;IACpC,aAAa,EAAE,gBAAgB,CAAC;IAChC,SAAS,EAAE,UAAU,CAAC;IACtB,IAAI,EAAE,UAAU,CAAC;IACjB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,GAAG,OAAO,CAAC,OAAO,CAAC,CA0EnB"}

View File

@@ -0,0 +1,76 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.verifyEC2 = verifyEC2;
const cose_js_1 = require("../../cose.js");
const mapCoseAlgToWebCryptoAlg_js_1 = require("./mapCoseAlgToWebCryptoAlg.js");
const importKey_js_1 = require("./importKey.js");
const index_js_1 = require("../index.js");
const getWebCrypto_js_1 = require("./getWebCrypto.js");
/**
* Verify a signature using an EC2 public key
*/
async function verifyEC2(opts) {
const { cosePublicKey, signature, data, shaHashOverride } = opts;
const WebCrypto = await (0, getWebCrypto_js_1.getWebCrypto)();
// Import the public key
const alg = cosePublicKey.get(cose_js_1.COSEKEYS.alg);
const crv = cosePublicKey.get(cose_js_1.COSEKEYS.crv);
const x = cosePublicKey.get(cose_js_1.COSEKEYS.x);
const y = cosePublicKey.get(cose_js_1.COSEKEYS.y);
if (!alg) {
throw new Error('Public key was missing alg (EC2)');
}
if (!crv) {
throw new Error('Public key was missing crv (EC2)');
}
if (!x) {
throw new Error('Public key was missing x (EC2)');
}
if (!y) {
throw new Error('Public key was missing y (EC2)');
}
let _crv;
if (crv === cose_js_1.COSECRV.P256) {
_crv = 'P-256';
}
else if (crv === cose_js_1.COSECRV.P384) {
_crv = 'P-384';
}
else if (crv === cose_js_1.COSECRV.P521) {
_crv = 'P-521';
}
else {
throw new Error(`Unexpected COSE crv value of ${crv} (EC2)`);
}
const keyData = {
kty: 'EC',
crv: _crv,
x: index_js_1.isoBase64URL.fromBuffer(x),
y: index_js_1.isoBase64URL.fromBuffer(y),
ext: false,
};
const keyAlgorithm = {
/**
* Note to future self: you can't use `mapCoseAlgToWebCryptoKeyAlgName()` here because some
* leaf certs from actual devices specified an RSA SHA value for `alg` (e.g. `-257`) which
* would then map here to `'RSASSA-PKCS1-v1_5'`. We always want `'ECDSA'` here so we'll
* hard-code this.
*/
name: 'ECDSA',
namedCurve: _crv,
};
const key = await (0, importKey_js_1.importKey)({
keyData,
algorithm: keyAlgorithm,
});
// Determine which SHA algorithm to use for signature verification
let subtleAlg = (0, mapCoseAlgToWebCryptoAlg_js_1.mapCoseAlgToWebCryptoAlg)(alg);
if (shaHashOverride) {
subtleAlg = (0, mapCoseAlgToWebCryptoAlg_js_1.mapCoseAlgToWebCryptoAlg)(shaHashOverride);
}
const verifyAlgorithm = {
name: 'ECDSA',
hash: { name: subtleAlg },
};
return WebCrypto.subtle.verify(verifyAlgorithm, key, signature, data);
}

View File

@@ -0,0 +1,7 @@
import { COSEPublicKeyOKP } from '../../cose.js';
export declare function verifyOKP(opts: {
cosePublicKey: COSEPublicKeyOKP;
signature: Uint8Array;
data: Uint8Array;
}): Promise<boolean>;
//# sourceMappingURL=verifyOKP.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"verifyOKP.d.ts","sourceRoot":"","sources":["../../../../src/helpers/iso/isoCrypto/verifyOKP.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,gBAAgB,EAAa,MAAM,eAAe,CAAC;AAM/E,wBAAsB,SAAS,CAAC,IAAI,EAAE;IACpC,aAAa,EAAE,gBAAgB,CAAC;IAChC,SAAS,EAAE,UAAU,CAAC;IACtB,IAAI,EAAE,UAAU,CAAC;CAClB,GAAG,OAAO,CAAC,OAAO,CAAC,CAyDnB"}

View File

@@ -0,0 +1,54 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.verifyOKP = verifyOKP;
const cose_js_1 = require("../../cose.js");
const index_js_1 = require("../../index.js");
const importKey_js_1 = require("./importKey.js");
const getWebCrypto_js_1 = require("./getWebCrypto.js");
async function verifyOKP(opts) {
const { cosePublicKey, signature, data } = opts;
const WebCrypto = await (0, getWebCrypto_js_1.getWebCrypto)();
const alg = cosePublicKey.get(cose_js_1.COSEKEYS.alg);
const crv = cosePublicKey.get(cose_js_1.COSEKEYS.crv);
const x = cosePublicKey.get(cose_js_1.COSEKEYS.x);
if (!alg) {
throw new Error('Public key was missing alg (OKP)');
}
if (!(0, cose_js_1.isCOSEAlg)(alg)) {
throw new Error(`Public key had invalid alg ${alg} (OKP)`);
}
if (!crv) {
throw new Error('Public key was missing crv (OKP)');
}
if (!x) {
throw new Error('Public key was missing x (OKP)');
}
// Pulled key import steps from here:
// https://wicg.github.io/webcrypto-secure-curves/#ed25519-operations
let _crv;
if (crv === cose_js_1.COSECRV.ED25519) {
_crv = 'Ed25519';
}
else {
throw new Error(`Unexpected COSE crv value of ${crv} (OKP)`);
}
const keyData = {
kty: 'OKP',
crv: _crv,
alg: 'EdDSA',
x: index_js_1.isoBase64URL.fromBuffer(x),
ext: false,
};
const keyAlgorithm = {
name: _crv,
namedCurve: _crv,
};
const key = await (0, importKey_js_1.importKey)({
keyData,
algorithm: keyAlgorithm,
});
const verifyAlgorithm = {
name: _crv,
};
return WebCrypto.subtle.verify(verifyAlgorithm, key, signature, data);
}

View File

@@ -0,0 +1,11 @@
import { COSEALG, COSEPublicKeyRSA } from '../../cose.js';
/**
* Verify a signature using an RSA public key
*/
export declare function verifyRSA(opts: {
cosePublicKey: COSEPublicKeyRSA;
signature: Uint8Array;
data: Uint8Array;
shaHashOverride?: COSEALG;
}): Promise<boolean>;
//# sourceMappingURL=verifyRSA.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"verifyRSA.d.ts","sourceRoot":"","sources":["../../../../src/helpers/iso/isoCrypto/verifyRSA.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAY,gBAAgB,EAAa,MAAM,eAAe,CAAC;AAO/E;;GAEG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE;IACpC,aAAa,EAAE,gBAAgB,CAAC;IAChC,SAAS,EAAE,UAAU,CAAC;IACtB,IAAI,EAAE,UAAU,CAAC;IACjB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,GAAG,OAAO,CAAC,OAAO,CAAC,CA2FnB"}

View File

@@ -0,0 +1,94 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.verifyRSA = verifyRSA;
const cose_js_1 = require("../../cose.js");
const mapCoseAlgToWebCryptoAlg_js_1 = require("./mapCoseAlgToWebCryptoAlg.js");
const importKey_js_1 = require("./importKey.js");
const index_js_1 = require("../index.js");
const mapCoseAlgToWebCryptoKeyAlgName_js_1 = require("./mapCoseAlgToWebCryptoKeyAlgName.js");
const getWebCrypto_js_1 = require("./getWebCrypto.js");
/**
* Verify a signature using an RSA public key
*/
async function verifyRSA(opts) {
const { cosePublicKey, signature, data, shaHashOverride } = opts;
const WebCrypto = await (0, getWebCrypto_js_1.getWebCrypto)();
const alg = cosePublicKey.get(cose_js_1.COSEKEYS.alg);
const n = cosePublicKey.get(cose_js_1.COSEKEYS.n);
const e = cosePublicKey.get(cose_js_1.COSEKEYS.e);
if (!alg) {
throw new Error('Public key was missing alg (RSA)');
}
if (!(0, cose_js_1.isCOSEAlg)(alg)) {
throw new Error(`Public key had invalid alg ${alg} (RSA)`);
}
if (!n) {
throw new Error('Public key was missing n (RSA)');
}
if (!e) {
throw new Error('Public key was missing e (RSA)');
}
const keyData = {
kty: 'RSA',
alg: '',
n: index_js_1.isoBase64URL.fromBuffer(n),
e: index_js_1.isoBase64URL.fromBuffer(e),
ext: false,
};
const keyAlgorithm = {
name: (0, mapCoseAlgToWebCryptoKeyAlgName_js_1.mapCoseAlgToWebCryptoKeyAlgName)(alg),
hash: { name: (0, mapCoseAlgToWebCryptoAlg_js_1.mapCoseAlgToWebCryptoAlg)(alg) },
};
const verifyAlgorithm = {
name: (0, mapCoseAlgToWebCryptoKeyAlgName_js_1.mapCoseAlgToWebCryptoKeyAlgName)(alg),
};
if (shaHashOverride) {
keyAlgorithm.hash.name = (0, mapCoseAlgToWebCryptoAlg_js_1.mapCoseAlgToWebCryptoAlg)(shaHashOverride);
}
if (keyAlgorithm.name === 'RSASSA-PKCS1-v1_5') {
if (keyAlgorithm.hash.name === 'SHA-256') {
keyData.alg = 'RS256';
}
else if (keyAlgorithm.hash.name === 'SHA-384') {
keyData.alg = 'RS384';
}
else if (keyAlgorithm.hash.name === 'SHA-512') {
keyData.alg = 'RS512';
}
else if (keyAlgorithm.hash.name === 'SHA-1') {
keyData.alg = 'RS1';
}
}
else if (keyAlgorithm.name === 'RSA-PSS') {
/**
* salt length. The default value is 20 but the convention is to use hLen, the length of the
* output of the hash function in bytes. A salt length of zero is permitted and will result in
* a deterministic signature value. The actual salt length used can be determined from the
* signature value.
*
* From https://www.cryptosys.net/pki/manpki/pki_rsaschemes.html
*/
let saltLength = 0;
if (keyAlgorithm.hash.name === 'SHA-256') {
keyData.alg = 'PS256';
saltLength = 32; // 256 bits => 32 bytes
}
else if (keyAlgorithm.hash.name === 'SHA-384') {
keyData.alg = 'PS384';
saltLength = 48; // 384 bits => 48 bytes
}
else if (keyAlgorithm.hash.name === 'SHA-512') {
keyData.alg = 'PS512';
saltLength = 64; // 512 bits => 64 bytes
}
verifyAlgorithm.saltLength = saltLength;
}
else {
throw new Error(`Unexpected RSA key algorithm ${alg} (${keyAlgorithm.name})`);
}
const key = await (0, importKey_js_1.importKey)({
keyData,
algorithm: keyAlgorithm,
});
return WebCrypto.subtle.verify(verifyAlgorithm, key, signature, data);
}