Skip to content

Commit 07574af

Browse files
committed
CryptoKeyのextractable: falseが問題ないようにする
- `genAlgorithmForSignAndVerify`の第2引数はhash文字列を指定するように - `verifyDraftSignature`のdefaultsはいらないことに気づいた - `importPrivateKey`/`importPublicKey`にextractableを指定できるように - `parseSignInfo`の第2引数がwebcrypto.CryptoKey['algorithm']を受け付けるように
1 parent 7d227cb commit 07574af

File tree

14 files changed

+335
-254
lines changed

14 files changed

+335
-254
lines changed

dist/draft/verify.d.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
/// <reference types="node" />
22
import { ParsedDraftSignature } from "../types";
33
import { parseSignInfo } from "../shared/verify";
4-
import { type SignInfoDefaults } from "../utils";
54
import type { webcrypto } from "node:crypto";
65
/**
76
* @deprecated Use `parseSignInfo`
@@ -13,5 +12,4 @@ export declare const genSignInfoDraft: typeof parseSignInfo;
1312
* @param key public key
1413
* @param errorLogger: If you want to log errors, set function
1514
*/
16-
export declare function verifyDraftSignature(parsed: ParsedDraftSignature['value'], key: string | webcrypto.CryptoKey, errorLogger?: ((message: any) => any)): Promise<boolean>;
17-
export declare function verifyDraftSignature(parsed: ParsedDraftSignature['value'], key: string | webcrypto.CryptoKey, defaults: SignInfoDefaults, errorLogger?: (message: any) => any): Promise<boolean>;
15+
export declare function verifyDraftSignature(parsed: ParsedDraftSignature['value'], key: string | webcrypto.CryptoKey, errorLogger?: (message: any) => any): Promise<boolean>;

dist/index.cjs

+121-104
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ __export(src_exports, {
7979
numberToUint8Array: () => numberToUint8Array,
8080
objectLcKeys: () => objectLcKeys,
8181
parseAlgorithmIdentifier: () => parseAlgorithmIdentifier,
82+
parseAndImportPublicKey: () => parseAndImportPublicKey,
8283
parseDraftRequest: () => parseDraftRequest,
8384
parseDraftRequestSignatureHeader: () => parseDraftRequestSignatureHeader,
8485
parsePkcs1: () => parsePkcs1,
@@ -164,6 +165,102 @@ function genSpkiFromPkcs1(input) {
164165
]);
165166
}
166167

168+
// src/draft/const.ts
169+
var keyHashAlgosForDraftEncofing = {
170+
"SHA": "sha1",
171+
"SHA-1": "sha1",
172+
"SHA-256": "sha256",
173+
"SHA-384": "sha384",
174+
"SHA-512": "sha512",
175+
"MD5": "md5"
176+
};
177+
var keyHashAlgosForDraftDecoding = {
178+
"sha1": "SHA",
179+
"sha256": "SHA-256",
180+
"sha384": "SHA-384",
181+
"sha512": "SHA-512",
182+
"md5": "MD5"
183+
};
184+
185+
// src/shared/verify.ts
186+
var KeyHashValidationError = class extends Error {
187+
constructor(message) {
188+
super(message);
189+
}
190+
};
191+
function buildErrorMessage(providedAlgorithm, real) {
192+
return `Provided algorithm does not match the public key type: provided=${providedAlgorithm}, real=${real}`;
193+
}
194+
function parseSignInfo(algorithm, real, errorLogger) {
195+
algorithm = algorithm?.toLowerCase();
196+
const realKeyType = typeof real === "string" ? real : "algorithm" in real ? getPublicKeyAlgorithmNameFromOid(real.algorithm) : real.name;
197+
if (realKeyType === "RSA-PSS") {
198+
if (algorithm === "rsa-pss-sha512") {
199+
return { name: "RSA-PSS", hash: "SHA-512" };
200+
}
201+
}
202+
if (realKeyType === "RSASSA-PKCS1-v1_5") {
203+
if (!algorithm || algorithm === "hs2019" || algorithm === "rsa-sha256" || algorithm === "rsa-v1_5-sha256") {
204+
return { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" };
205+
}
206+
if (algorithm === "rsa-pss-sha512") {
207+
return { name: "RSA-PSS", hash: "SHA-512" };
208+
}
209+
const [parsedName, hash] = algorithm.split("-");
210+
if (!hash || !(hash in keyHashAlgosForDraftDecoding)) {
211+
throw new KeyHashValidationError(`unsupported hash: ${hash}`);
212+
}
213+
if (parsedName === "rsa") {
214+
return { name: "RSASSA-PKCS1-v1_5", hash: keyHashAlgosForDraftDecoding[hash] };
215+
}
216+
throw new KeyHashValidationError(buildErrorMessage(algorithm, realKeyType));
217+
}
218+
if (realKeyType === "EC") {
219+
const namedCurve = "parameter" in real ? getNistCurveFromOid(real.parameter) : real.namedCurve;
220+
if (!namedCurve)
221+
throw new KeyHashValidationError("could not get namedCurve");
222+
if (!algorithm || algorithm === "hs2019" || algorithm === "ecdsa-sha256") {
223+
return { name: "ECDSA", hash: "SHA-256", namedCurve };
224+
}
225+
if (algorithm === "ecdsa-p256-sha256") {
226+
if (namedCurve !== "P-256") {
227+
throw new KeyHashValidationError(`curve is not P-256: ${namedCurve}`);
228+
}
229+
return { name: "ECDSA", hash: "SHA-256", namedCurve };
230+
}
231+
if (algorithm === "ecdsa-p384-sha384") {
232+
if (namedCurve !== "P-384") {
233+
throw new KeyHashValidationError(`curve is not P-384: ${namedCurve}`);
234+
}
235+
return { name: "ECDSA", hash: "SHA-256", namedCurve };
236+
}
237+
const [dsaOrDH, hash] = algorithm.split("-");
238+
if (!hash || !(hash in keyHashAlgosForDraftDecoding)) {
239+
throw new KeyHashValidationError(`unsupported hash: ${hash}`);
240+
}
241+
if (dsaOrDH === "ecdsa") {
242+
return { name: "ECDSA", hash: keyHashAlgosForDraftDecoding[hash], namedCurve };
243+
}
244+
if (dsaOrDH === "ecdh") {
245+
return { name: "ECDH", hash: keyHashAlgosForDraftDecoding[hash], namedCurve };
246+
}
247+
throw new KeyHashValidationError(buildErrorMessage(algorithm, realKeyType));
248+
}
249+
if (realKeyType === "Ed25519") {
250+
if (!algorithm || algorithm === "hs2019" || algorithm === "ed25519-sha512" || algorithm === "ed25519") {
251+
return { name: "Ed25519" };
252+
}
253+
throw new KeyHashValidationError(buildErrorMessage(algorithm, realKeyType));
254+
}
255+
if (realKeyType === "Ed448") {
256+
if (!algorithm || algorithm === "hs2019" || algorithm === "ed448") {
257+
return { name: "Ed448" };
258+
}
259+
throw new KeyHashValidationError(buildErrorMessage(algorithm, realKeyType));
260+
}
261+
throw new KeyHashValidationError(`unsupported keyAlgorithm: ${realKeyType} (provided: ${algorithm})`);
262+
}
263+
167264
// src/pem/spki.ts
168265
var SpkiParseError = class extends Error {
169266
constructor(message) {
@@ -270,6 +367,22 @@ async function importPublicKey(key, keyUsages = ["verify"], defaults = defaultSi
270367
const parsedPublicKey = parsePublicKey(key);
271368
return await (await getWebcrypto()).subtle.importKey("spki", parsedPublicKey.der, genSignInfo(parsedPublicKey, defaults), false, keyUsages);
272369
}
370+
async function parseAndImportPublicKey(source, keyUsages = ["verify"], providedAlgorithm, errorLogger) {
371+
if (typeof source === "string" || typeof source === "object" && !("type" in source) && (source instanceof Uint8Array || source instanceof ArrayBuffer || Array.isArray(source) || "enc" in source)) {
372+
const keyAlgorithmIdentifier = parsePublicKey(source);
373+
const signInfo2 = parseSignInfo(providedAlgorithm, keyAlgorithmIdentifier, errorLogger);
374+
const publicKey = await (await getWebcrypto()).subtle.importKey("spki", keyAlgorithmIdentifier.der, signInfo2, false, keyUsages);
375+
return {
376+
publicKey,
377+
algorithm: genAlgorithmForSignAndVerify(publicKey.algorithm, "hash" in signInfo2 ? signInfo2.hash : null)
378+
};
379+
}
380+
const signInfo = parseSignInfo(providedAlgorithm, source.algorithm, errorLogger);
381+
return {
382+
publicKey: source,
383+
algorithm: genAlgorithmForSignAndVerify(source.algorithm, "hash" in signInfo ? signInfo.hash : null)
384+
};
385+
}
273386

274387
// src/utils.ts
275388
async function getWebcrypto() {
@@ -358,10 +471,10 @@ function genSignInfo(parsed, defaults = defaultSignInfoDefaults) {
358471
}
359472
throw new KeyValidationError("Unknown algorithm");
360473
}
361-
function genAlgorithmForSignAndVerify(algorithm, defaults = defaultSignInfoDefaults) {
474+
function genAlgorithmForSignAndVerify(keyAlgorithm, hashAlgorithm) {
362475
return {
363-
hash: defaults.hash,
364-
...algorithm
476+
hash: hashAlgorithm,
477+
...keyAlgorithm
365478
};
366479
}
367480
function splitPer64Chars(str) {
@@ -404,26 +517,9 @@ function parsePkcs8(input) {
404517
async function importPrivateKey(key, keyUsages = ["sign"], defaults = defaultSignInfoDefaults) {
405518
const parsedPrivateKey = parsePkcs8(key);
406519
const importParams = genSignInfo(parsedPrivateKey, defaults);
407-
return await (await getWebcrypto()).subtle.importKey("pkcs8", parsedPrivateKey.der, importParams, false, keyUsages);
520+
return await (await getWebcrypto()).subtle.importKey("pkcs8", parsedPrivateKey.der, importParams, true, keyUsages);
408521
}
409522

410-
// src/draft/const.ts
411-
var keyHashAlgosForDraftEncofing = {
412-
"SHA": "sha1",
413-
"SHA-1": "sha1",
414-
"SHA-256": "sha256",
415-
"SHA-384": "sha384",
416-
"SHA-512": "sha512",
417-
"MD5": "md5"
418-
};
419-
var keyHashAlgosForDraftDecoding = {
420-
"sha1": "SHA",
421-
"sha256": "SHA-256",
422-
"sha384": "SHA-384",
423-
"sha512": "SHA-512",
424-
"md5": "MD5"
425-
};
426-
427523
// src/draft/sign.ts
428524
function getDraftAlgoString(keyAlgorithm, hashAlgorithm) {
429525
const verifyHash = () => {
@@ -898,92 +994,12 @@ async function verifyDigestHeader(request, rawBody, failOnNoDigest = true, error
898994
return true;
899995
}
900996

901-
// src/shared/verify.ts
902-
var KeyHashValidationError = class extends Error {
903-
constructor(message) {
904-
super(message);
905-
}
906-
};
907-
function buildErrorMessage(providedAlgorithm, real) {
908-
return `Provided algorithm does not match the public key type: provided=${providedAlgorithm}, real=${real}`;
909-
}
910-
function parseSignInfo(algorithm, parsed, errorLogger) {
911-
algorithm = algorithm?.toLowerCase();
912-
const realKeyType = getPublicKeyAlgorithmNameFromOid(parsed.algorithm);
913-
if (realKeyType === "RSA-PSS") {
914-
if (algorithm === "rsa-pss-sha512") {
915-
return { name: "RSA-PSS", hash: "SHA-512" };
916-
}
917-
}
918-
if (realKeyType === "RSASSA-PKCS1-v1_5") {
919-
if (!algorithm || algorithm === "hs2019" || algorithm === "rsa-sha256" || algorithm === "rsa-v1_5-sha256") {
920-
return { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" };
921-
}
922-
if (algorithm === "rsa-pss-sha512") {
923-
return { name: "RSA-PSS", hash: "SHA-512" };
924-
}
925-
const [parsedName, hash] = algorithm.split("-");
926-
if (!hash || !(hash in keyHashAlgosForDraftDecoding)) {
927-
throw new KeyHashValidationError(`unsupported hash: ${hash}`);
928-
}
929-
if (parsedName === "rsa") {
930-
return { name: "RSASSA-PKCS1-v1_5", hash: keyHashAlgosForDraftDecoding[hash] };
931-
}
932-
throw new KeyHashValidationError(buildErrorMessage(algorithm, parsed.algorithm));
933-
}
934-
if (realKeyType === "EC") {
935-
if (!algorithm || algorithm === "hs2019" || algorithm === "ecdsa-sha256") {
936-
return { name: "ECDSA", hash: "SHA-256", namedCurve: getNistCurveFromOid(parsed.parameter) };
937-
}
938-
if (algorithm === "ecdsa-p256-sha256") {
939-
const namedCurve = getNistCurveFromOid(parsed.parameter);
940-
if (namedCurve !== "P-256") {
941-
throw new KeyHashValidationError(`curve is not P-256: ${namedCurve}`);
942-
}
943-
return { name: "ECDSA", hash: "SHA-256", namedCurve };
944-
}
945-
if (algorithm === "ecdsa-p384-sha384") {
946-
const namedCurve = getNistCurveFromOid(parsed.parameter);
947-
if (namedCurve !== "P-384") {
948-
throw new KeyHashValidationError(`curve is not P-384: ${namedCurve}`);
949-
}
950-
return { name: "ECDSA", hash: "SHA-256", namedCurve: getNistCurveFromOid(parsed.parameter) };
951-
}
952-
const [dsaOrDH, hash] = algorithm.split("-");
953-
if (!hash || !(hash in keyHashAlgosForDraftDecoding)) {
954-
throw new KeyHashValidationError(`unsupported hash: ${hash}`);
955-
}
956-
if (dsaOrDH === "ecdsa") {
957-
return { name: "ECDSA", hash: keyHashAlgosForDraftDecoding[hash], namedCurve: getNistCurveFromOid(parsed.parameter) };
958-
}
959-
if (dsaOrDH === "ecdh") {
960-
return { name: "ECDH", hash: keyHashAlgosForDraftDecoding[hash], namedCurve: getNistCurveFromOid(parsed.parameter) };
961-
}
962-
throw new KeyHashValidationError(buildErrorMessage(algorithm, parsed.algorithm));
963-
}
964-
if (realKeyType === "Ed25519") {
965-
if (!algorithm || algorithm === "hs2019" || algorithm === "ed25519-sha512" || algorithm === "ed25519") {
966-
return { name: "Ed25519" };
967-
}
968-
throw new KeyHashValidationError(buildErrorMessage(algorithm, parsed.algorithm));
969-
}
970-
if (realKeyType === "Ed448") {
971-
if (!algorithm || algorithm === "hs2019" || algorithm === "ed448") {
972-
return { name: "Ed448" };
973-
}
974-
throw new KeyHashValidationError(buildErrorMessage(algorithm, parsed.algorithm));
975-
}
976-
throw new KeyHashValidationError(`unsupported keyAlgorithm: ${realKeyType} (provided: ${algorithm})`);
977-
}
978-
979997
// src/draft/verify.ts
980998
var genSignInfoDraft = parseSignInfo;
981-
async function verifyDraftSignature(parsed, key, p3, p4) {
982-
const errorLogger = p3 && typeof p3 === "function" ? p3 : p4;
983-
const defaults = p3 && typeof p3 === "object" ? p3 : defaultSignInfoDefaults;
999+
async function verifyDraftSignature(parsed, key, errorLogger) {
9841000
try {
985-
const publicKey = typeof key === "string" ? await importPublicKey(key, ["verify"]) : key;
986-
const verify = await (await getWebcrypto()).subtle.verify(genAlgorithmForSignAndVerify(publicKey.algorithm, defaults), publicKey, decodeBase64ToUint8Array(parsed.params.signature), new TextEncoder().encode(parsed.signingString));
1001+
const { publicKey, algorithm } = await parseAndImportPublicKey(key, ["verify"], parsed.algorithm);
1002+
const verify = await (await getWebcrypto()).subtle.verify(algorithm, publicKey, decodeBase64ToUint8Array(parsed.params.signature), new TextEncoder().encode(parsed.signingString));
9871003
if (verify !== true)
9881004
throw new Error(`verification simply failed, result: ${verify}`);
9891005
return verify;
@@ -1044,6 +1060,7 @@ async function verifyDraftSignature(parsed, key, p3, p4) {
10441060
numberToUint8Array,
10451061
objectLcKeys,
10461062
parseAlgorithmIdentifier,
1063+
parseAndImportPublicKey,
10471064
parseDraftRequest,
10481065
parseDraftRequestSignatureHeader,
10491066
parsePkcs1,

0 commit comments

Comments
 (0)