Skip to content

Commit 1949fc6

Browse files
committed
0.0.3
1 parent 792892c commit 1949fc6

16 files changed

+290
-79
lines changed

dist/draft/sign.d.ts

+16-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
/// <reference types="node" />
22
import type { webcrypto } from 'node:crypto';
3-
import type { PrivateKey, RequestLike, SignInfo, SignatureHashAlgorithmUpperSnake } from '../types.js';
4-
export declare function getDraftAlgoString(algorithm: SignInfo): string;
3+
import type { PrivateKey, RequestLike, SignatureHashAlgorithmUpperSnake } from '../types.js';
4+
/**
5+
* Get the algorithm string for draft encoding
6+
* @param keyAlgorithm Comes from `privateKey.algorithm.name` e.g. 'RSASSA-PKCS1-v1_5'
7+
* @param hashAlgorithm e.g. 'SHA-256'
8+
* @returns string e.g. 'rsa-sha256'
9+
*/
10+
export declare function getDraftAlgoString(keyAlgorithm: string, hashAlgorithm: NonNullable<SignatureHashAlgorithmUpperSnake>): string;
511
export declare function genDraftSigningString(request: RequestLike, includeHeaders: string[], additional?: {
612
keyId: string;
713
algorithm: string;
@@ -11,6 +17,14 @@ export declare function genDraftSigningString(request: RequestLike, includeHeade
1117
}): string;
1218
export declare function genDraftSignature(privateKey: webcrypto.CryptoKey, signingString: string): Promise<string>;
1319
export declare function genDraftSignatureHeader(includeHeaders: string[], keyId: string, signature: string, algorithm: string): string;
20+
/**
21+
*
22+
* @param request Request object to sign
23+
* @param key Private key to sign
24+
* @param includeHeaders Headers to build the sigining string
25+
* @param opts
26+
* @returns result object
27+
*/
1428
export declare function signAsDraftToRequest(request: RequestLike, key: PrivateKey, includeHeaders: string[], opts?: {
1529
hashAlgorithm?: SignatureHashAlgorithmUpperSnake;
1630
}): Promise<{

dist/draft/verify.d.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1+
/// <reference types="node" />
12
import { ParsedDraftSignature } from "../types";
23
import { parseSignInfo } from "../shared/verify";
4+
import type { webcrypto } from "node:crypto";
35
/**
46
* @deprecated Use `parseSignInfo`
57
*/
68
export declare const genSignInfoDraft: typeof parseSignInfo;
79
/**
810
* Verify a draft signature
11+
* @param parsed ParsedDraftSignature['value']
12+
* @param key public key
13+
* @param errorLogger: If you want to log errors, set function
914
*/
10-
export declare function verifyDraftSignature(parsed: ParsedDraftSignature['value'], publicKeyPem: string, 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

+29-19
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ __export(src_exports, {
6868
getNistCurveFromOid: () => getNistCurveFromOid,
6969
getPublicKeyAlgorithmNameFromOid: () => getPublicKeyAlgorithmNameFromOid,
7070
getWebcrypto: () => getWebcrypto,
71+
importPrivateKey: () => importPrivateKey,
72+
importPublicKey: () => importPublicKey,
7173
keyHashAlgosForDraftDecoding: () => keyHashAlgosForDraftDecoding,
7274
keyHashAlgosForDraftEncofing: () => keyHashAlgosForDraftEncofing,
7375
lcObjectGet: () => lcObjectGet,
@@ -262,6 +264,10 @@ function parsePublicKey(input) {
262264
}
263265
}
264266
}
267+
async function importPublicKey(key, keyUsages, defaults) {
268+
const parsedPublicKey = parsePublicKey(key);
269+
return await (await getWebcrypto()).subtle.importKey("spki", parsedPublicKey.der, genSignInfo(parsedPublicKey), false, keyUsages);
270+
}
265271

266272
// src/utils.ts
267273
async function getWebcrypto() {
@@ -386,6 +392,11 @@ function parsePkcs8(input) {
386392
attributesRaw: attributes ? asn1ToArrayBuffer(attributes) : null
387393
};
388394
}
395+
async function importPrivateKey(key, keyUsages, defaults) {
396+
const parsedPrivateKey = parsePkcs8(key);
397+
const importParams = genSignInfo(parsedPrivateKey, defaults);
398+
return await (await getWebcrypto()).subtle.importKey("pkcs8", parsedPrivateKey.der, importParams, false, keyUsages);
399+
}
389400

390401
// src/draft/const.ts
391402
var keyHashAlgosForDraftEncofing = {
@@ -405,29 +416,29 @@ var keyHashAlgosForDraftDecoding = {
405416
};
406417

407418
// src/draft/sign.ts
408-
function getDraftAlgoString(algorithm) {
419+
function getDraftAlgoString(keyAlgorithm, hashAlgorithm) {
409420
const verifyHash = () => {
410-
if (!algorithm.hash)
421+
if (!hashAlgorithm)
411422
throw new Error(`hash is required`);
412-
if (!(algorithm.hash in keyHashAlgosForDraftEncofing))
413-
throw new Error(`unsupported hash: ${algorithm.hash}`);
423+
if (!(hashAlgorithm in keyHashAlgosForDraftEncofing))
424+
throw new Error(`unsupported hash: ${hashAlgorithm}`);
414425
};
415-
if (algorithm.name === "RSASSA-PKCS1-v1_5") {
426+
if (keyAlgorithm === "RSASSA-PKCS1-v1_5") {
416427
verifyHash();
417-
return `rsa-${keyHashAlgosForDraftEncofing[algorithm.hash]}`;
428+
return `rsa-${keyHashAlgosForDraftEncofing[hashAlgorithm]}`;
418429
}
419-
if (algorithm.name === "ECDSA") {
430+
if (keyAlgorithm === "ECDSA") {
420431
verifyHash();
421-
return `ecdsa-${keyHashAlgosForDraftEncofing[algorithm.hash]}`;
432+
return `ecdsa-${keyHashAlgosForDraftEncofing[hashAlgorithm]}`;
422433
}
423-
if (algorithm.name === "ECDH") {
434+
if (keyAlgorithm === "ECDH") {
424435
verifyHash();
425-
return `ecdh-${keyHashAlgosForDraftEncofing[algorithm.hash]}`;
436+
return `ecdh-${keyHashAlgosForDraftEncofing[hashAlgorithm]}`;
426437
}
427-
if (algorithm.name === "Ed25519") {
438+
if (keyAlgorithm === "Ed25519") {
428439
return `ed25519-sha512`;
429440
}
430-
if (algorithm.name === "Ed448") {
441+
if (keyAlgorithm === "Ed448") {
431442
return `ed448`;
432443
}
433444
throw new Error(`unsupported keyAlgorithm`);
@@ -467,10 +478,8 @@ function genDraftSignatureHeader(includeHeaders, keyId, signature, algorithm) {
467478
}
468479
async function signAsDraftToRequest(request, key, includeHeaders, opts = {}) {
469480
const hash = opts?.hashAlgorithm || "SHA-256";
470-
const parsedPrivateKey = parsePkcs8(key.privateKeyPem);
471-
const importParams = genSignInfo(parsedPrivateKey, { hash, ec: "DSA" });
472-
const privateKey = await (await getWebcrypto()).subtle.importKey("pkcs8", parsedPrivateKey.der, importParams, false, ["sign"]);
473-
const algoString = getDraftAlgoString(importParams);
481+
const privateKey = "privateKey" in key ? key.privateKey : await importPrivateKey(key.privateKeyPem, ["sign"], { hash, ec: "DSA" });
482+
const algoString = getDraftAlgoString(privateKey.algorithm.name, hash);
474483
const signingString = genDraftSigningString(request, includeHeaders, { keyId: key.keyId, algorithm: algoString });
475484
const signature = await genDraftSignature(privateKey, signingString);
476485
const signatureHeader = genDraftSignatureHeader(includeHeaders, key.keyId, signature, algoString);
@@ -958,10 +967,9 @@ function parseSignInfo(algorithm, parsed, errorLogger) {
958967

959968
// src/draft/verify.ts
960969
var genSignInfoDraft = parseSignInfo;
961-
async function verifyDraftSignature(parsed, publicKeyPem, errorLogger) {
970+
async function verifyDraftSignature(parsed, key, errorLogger) {
962971
try {
963-
const parsedSpki = parsePublicKey(publicKeyPem);
964-
const publicKey = await (await getWebcrypto()).subtle.importKey("spki", parsedSpki.der, genSignInfo(parsedSpki), false, ["verify"]);
972+
const publicKey = typeof key === "string" ? await importPublicKey(key, ["verify"]) : key;
965973
const verify = await (await getWebcrypto()).subtle.verify(publicKey.algorithm, publicKey, decodeBase64ToUint8Array(parsed.params.signature), new TextEncoder().encode(parsed.signingString));
966974
return verify;
967975
} catch (e) {
@@ -1010,6 +1018,8 @@ async function verifyDraftSignature(parsed, publicKeyPem, errorLogger) {
10101018
getNistCurveFromOid,
10111019
getPublicKeyAlgorithmNameFromOid,
10121020
getWebcrypto,
1021+
importPrivateKey,
1022+
importPublicKey,
10131023
keyHashAlgosForDraftDecoding,
10141024
keyHashAlgosForDraftEncofing,
10151025
lcObjectGet,

dist/index.mjs

+27-19
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,10 @@ function parsePublicKey(input) {
165165
}
166166
}
167167
}
168+
async function importPublicKey(key, keyUsages, defaults) {
169+
const parsedPublicKey = parsePublicKey(key);
170+
return await (await getWebcrypto()).subtle.importKey("spki", parsedPublicKey.der, genSignInfo(parsedPublicKey), false, keyUsages);
171+
}
168172

169173
// src/utils.ts
170174
async function getWebcrypto() {
@@ -289,6 +293,11 @@ function parsePkcs8(input) {
289293
attributesRaw: attributes ? asn1ToArrayBuffer(attributes) : null
290294
};
291295
}
296+
async function importPrivateKey(key, keyUsages, defaults) {
297+
const parsedPrivateKey = parsePkcs8(key);
298+
const importParams = genSignInfo(parsedPrivateKey, defaults);
299+
return await (await getWebcrypto()).subtle.importKey("pkcs8", parsedPrivateKey.der, importParams, false, keyUsages);
300+
}
292301

293302
// src/draft/const.ts
294303
var keyHashAlgosForDraftEncofing = {
@@ -308,29 +317,29 @@ var keyHashAlgosForDraftDecoding = {
308317
};
309318

310319
// src/draft/sign.ts
311-
function getDraftAlgoString(algorithm) {
320+
function getDraftAlgoString(keyAlgorithm, hashAlgorithm) {
312321
const verifyHash = () => {
313-
if (!algorithm.hash)
322+
if (!hashAlgorithm)
314323
throw new Error(`hash is required`);
315-
if (!(algorithm.hash in keyHashAlgosForDraftEncofing))
316-
throw new Error(`unsupported hash: ${algorithm.hash}`);
324+
if (!(hashAlgorithm in keyHashAlgosForDraftEncofing))
325+
throw new Error(`unsupported hash: ${hashAlgorithm}`);
317326
};
318-
if (algorithm.name === "RSASSA-PKCS1-v1_5") {
327+
if (keyAlgorithm === "RSASSA-PKCS1-v1_5") {
319328
verifyHash();
320-
return `rsa-${keyHashAlgosForDraftEncofing[algorithm.hash]}`;
329+
return `rsa-${keyHashAlgosForDraftEncofing[hashAlgorithm]}`;
321330
}
322-
if (algorithm.name === "ECDSA") {
331+
if (keyAlgorithm === "ECDSA") {
323332
verifyHash();
324-
return `ecdsa-${keyHashAlgosForDraftEncofing[algorithm.hash]}`;
333+
return `ecdsa-${keyHashAlgosForDraftEncofing[hashAlgorithm]}`;
325334
}
326-
if (algorithm.name === "ECDH") {
335+
if (keyAlgorithm === "ECDH") {
327336
verifyHash();
328-
return `ecdh-${keyHashAlgosForDraftEncofing[algorithm.hash]}`;
337+
return `ecdh-${keyHashAlgosForDraftEncofing[hashAlgorithm]}`;
329338
}
330-
if (algorithm.name === "Ed25519") {
339+
if (keyAlgorithm === "Ed25519") {
331340
return `ed25519-sha512`;
332341
}
333-
if (algorithm.name === "Ed448") {
342+
if (keyAlgorithm === "Ed448") {
334343
return `ed448`;
335344
}
336345
throw new Error(`unsupported keyAlgorithm`);
@@ -370,10 +379,8 @@ function genDraftSignatureHeader(includeHeaders, keyId, signature, algorithm) {
370379
}
371380
async function signAsDraftToRequest(request, key, includeHeaders, opts = {}) {
372381
const hash = opts?.hashAlgorithm || "SHA-256";
373-
const parsedPrivateKey = parsePkcs8(key.privateKeyPem);
374-
const importParams = genSignInfo(parsedPrivateKey, { hash, ec: "DSA" });
375-
const privateKey = await (await getWebcrypto()).subtle.importKey("pkcs8", parsedPrivateKey.der, importParams, false, ["sign"]);
376-
const algoString = getDraftAlgoString(importParams);
382+
const privateKey = "privateKey" in key ? key.privateKey : await importPrivateKey(key.privateKeyPem, ["sign"], { hash, ec: "DSA" });
383+
const algoString = getDraftAlgoString(privateKey.algorithm.name, hash);
377384
const signingString = genDraftSigningString(request, includeHeaders, { keyId: key.keyId, algorithm: algoString });
378385
const signature = await genDraftSignature(privateKey, signingString);
379386
const signatureHeader = genDraftSignatureHeader(includeHeaders, key.keyId, signature, algoString);
@@ -861,10 +868,9 @@ function parseSignInfo(algorithm, parsed, errorLogger) {
861868

862869
// src/draft/verify.ts
863870
var genSignInfoDraft = parseSignInfo;
864-
async function verifyDraftSignature(parsed, publicKeyPem, errorLogger) {
871+
async function verifyDraftSignature(parsed, key, errorLogger) {
865872
try {
866-
const parsedSpki = parsePublicKey(publicKeyPem);
867-
const publicKey = await (await getWebcrypto()).subtle.importKey("spki", parsedSpki.der, genSignInfo(parsedSpki), false, ["verify"]);
873+
const publicKey = typeof key === "string" ? await importPublicKey(key, ["verify"]) : key;
868874
const verify = await (await getWebcrypto()).subtle.verify(publicKey.algorithm, publicKey, decodeBase64ToUint8Array(parsed.params.signature), new TextEncoder().encode(parsed.signingString));
869875
return verify;
870876
} catch (e) {
@@ -912,6 +918,8 @@ export {
912918
getNistCurveFromOid,
913919
getPublicKeyAlgorithmNameFromOid,
914920
getWebcrypto,
921+
importPrivateKey,
922+
importPublicKey,
915923
keyHashAlgosForDraftDecoding,
916924
keyHashAlgosForDraftEncofing,
917925
lcObjectGet,

dist/pem/pkcs8.d.ts

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
/// <reference types="node" />
12
import ASN1 from '@lapo/asn1js';
2-
import { ParsedAlgorithmIdentifierBase } from './spki';
3+
import { ParsedAlgorithmIdentifierBase } from './spki.js';
4+
import { genSignInfo } from '../utils.js';
5+
import type { webcrypto } from 'node:crypto';
36
export declare class Pkcs8ParseError extends Error {
47
constructor(message: string);
58
}
@@ -26,3 +29,12 @@ export type ParsedPkcs8 = ParsedAlgorithmIdentifierBase & {
2629
* @returns
2730
*/
2831
export declare function parsePkcs8(input: ASN1.StreamOrBinary): ParsedPkcs8;
32+
/**
33+
* Parse private key and run `crypto.subtle.importKey`
34+
* (only supports PKCS#8)
35+
* @param key string or ArrayBuffer
36+
* @param keyUsages e.g. ['verify']
37+
* @param defaults
38+
* @returns CryptoKey
39+
*/
40+
export declare function importPrivateKey(key: ASN1.StreamOrBinary, keyUsages: webcrypto.KeyUsage[], defaults?: Parameters<typeof genSignInfo>[1]): Promise<webcrypto.CryptoKey>;

dist/pem/spki.d.ts

+11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
/// <reference types="node" />
12
import ASN1 from '@lapo/asn1js';
23
import { ECNamedCurve, KeyAlgorithmName } from '../types';
4+
import type { webcrypto } from 'node:crypto';
5+
import { genSignInfo } from '../utils';
36
export declare class SpkiParseError extends Error {
47
constructor(message: string);
58
}
@@ -91,3 +94,11 @@ export declare function parseSpki(input: ASN1.StreamOrBinary): SpkiParsedAlgorit
9194
* @returns parsed object
9295
*/
9396
export declare function parsePublicKey(input: ASN1.StreamOrBinary): SpkiParsedAlgorithmIdentifier;
97+
/**
98+
* Parse public key and run `crypto.subtle.importKey`
99+
* @param key string or ArrayBuffer
100+
* @param keyUsages e.g. ['verify']
101+
* @param defaults
102+
* @returns CryptoKey
103+
*/
104+
export declare function importPublicKey(key: ASN1.StreamOrBinary, keyUsages: webcrypto.CryptoKey['usages'], defaults?: Parameters<typeof genSignInfo>[1]): Promise<webcrypto.CryptoKey>;

dist/types.d.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
/// <reference types="node" />
22
/// <reference types="node" />
3+
/// <reference types="node" />
34
import type { IncomingMessage } from "http";
45
import type { Http2ServerRequest } from "http2";
6+
import type { webcrypto } from "node:crypto";
57
export type RequestLike = {
68
url: string;
79
method: string;
@@ -47,10 +49,15 @@ export type SignInfoEd448 = {
4749
context?: string;
4850
};
4951
export type SignInfo = SignInfoRSAPSS | SignInfoRSA | SignInfoEC | SignInfoEd25519 | SignInfoEd448;
50-
export type PrivateKey = {
52+
export type PrivateKeyWithPem = {
5153
privateKeyPem: string;
5254
keyId: string;
5355
};
56+
export type PrivateKeyWithCryptoKey = {
57+
privateKey: webcrypto.CryptoKey;
58+
keyId: string;
59+
};
60+
export type PrivateKey = PrivateKeyWithPem | PrivateKeyWithCryptoKey;
5461
export type KeyAlgorithmName = 'RSA-PSS' | 'RSASSA-PKCS1-v1_5' | 'DSA' | 'DH' | 'KEA' | 'EC' | 'Ed25519' | 'Ed448';
5562
export type ECNamedCurve = 'P-192' | 'P-224' | 'P-256' | 'P-384' | 'P-521';
5663
export type SignatureHashAlgorithmUpperSnake = 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512' | null;

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@misskey-dev/node-http-message-signatures",
3-
"version": "0.0.2",
3+
"version": "0.0.3",
44
"description": "",
55
"type": "module",
66
"engines": {

0 commit comments

Comments
 (0)