Skip to content

Commit

Permalink
draftがWeb Crypto APIで動作するように
Browse files Browse the repository at this point in the history
0.0.0-alpha.15
  • Loading branch information
tamaina committed Mar 3, 2024
1 parent 15ae1e5 commit 8286028
Show file tree
Hide file tree
Showing 26 changed files with 896 additions and 1,047 deletions.
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
@misskey-dev/node-http-message-signatures
----

(WIP) Implementation of [HTTP Signatures "Draft", RFC 9421](https://datatracker.ietf.org/doc/rfc9421/), [RFC 3230](https://datatracker.ietf.org/doc/rfc3230/) and [RFC 9530](https://datatracker.ietf.org/doc/rfc9530/) for Node.js.
(WIP) Implementation of [HTTP Signatures "Draft", RFC 9421](https://datatracker.ietf.org/doc/rfc9421/), [RFC 3230](https://datatracker.ietf.org/doc/rfc3230/) and [RFC 9530](https://datatracker.ietf.org/doc/rfc9530/) for JavaScript.

It is created for Misskey's ActivityPub implementation.

We initially started working on it with the intention of using it in Node.js, but since we rewrote it to Web Crypto API, it may also work in browsers and edge workers.

## Context
### HTTP Signatures "Draft" and RFC 9421
[RFC 9421](https://datatracker.ietf.org/doc/rfc9421/) is the standard used for signing HTTP communications, but has been used since draft in the world of ActivityPub server-to-server communications with Misskey, Mastodon, and others.
Expand Down Expand Up @@ -117,8 +119,8 @@ fastify.post('/inbox', { config: { rawBody: true } }, async (request, reply) =>
return;
}

// Verify
const verifyResult = verifyDraftSignature(parsed!.value, keys.rsa4096.publicKey, errorLogger);
// Verify Signature
const verifyResult = await verifyDraftSignature(parsed!.value, keys.rsa4096.publicKey, errorLogger);
if (!verifyResult) {
reply.code(401);
return;
Expand Down Expand Up @@ -147,7 +149,7 @@ function targetSupportsRFC9421(url) {

const includeHeaders = ['(request-target)', 'date', 'host', 'digest'];

export function send(url: string, body: string, keyId: string) {
export async function send(url: string, body: string, keyId: string) {
const privateKeyPem = privateKeyMap.get(keyId);
const u = new URL(url);

Expand All @@ -168,7 +170,7 @@ export function send(url: string, body: string, keyId: string) {
// Draft
request.headers['Digest'] = genRFC3230DigestHeader(body);

signAsDraftToRequest(request, { keyId, privateKeyPem }, includeHeaders);
await signAsDraftToRequest(request, { keyId, privateKeyPem }, includeHeaders);

fetch(u, {
method: request.method,
Expand Down
21 changes: 21 additions & 0 deletions dist/draft/const.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Draftのalgorithm用
*/
export declare const keyHashAlgosForDraftEncofing: {
readonly SHA: "sha1";
readonly 'SHA-1': "sha1";
readonly 'SHA-256': "sha256";
readonly 'SHA-384': "sha384";
readonly 'SHA-512': "sha512";
readonly MD5: "md5";
};
/**
* Draftのalgorithm用
*/
export declare const keyHashAlgosForDraftDecoding: {
readonly sha1: "SHA";
readonly sha256: "SHA-256";
readonly sha384: "SHA-384";
readonly sha512: "SHA-512";
readonly md5: "MD5";
};
3 changes: 3 additions & 0 deletions dist/draft/parse.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/**
* Parse Request
*/
import { RequestParseOptions } from "../parse.js";
import type { ParsedDraftSignature, IncomingRequest } from '../types.js';
export declare const DraftSignatureHeaderKeys: readonly ["keyId", "algorithm", "created", "expires", "opaque", "headers", "signature"];
Expand Down
17 changes: 6 additions & 11 deletions dist/draft/sign.d.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
import type { PrivateKey, RequestLike, SignatureHashAlgorithm } from '../types.js';
/// <reference types="node" />
import type { webcrypto as crypto } from 'node:crypto';
import type { PrivateKey, RequestLike, SignInfo, SignatureHashAlgorithmUpperSnake } from '../types.js';
export declare function getDraftAlgoString(algorithm: SignInfo): string;
export declare function genDraftSigningString(request: RequestLike, includeHeaders: string[], additional?: {
keyId: string;
algorithm: string;
created?: string;
expires?: string;
opaque?: string;
}): string;
export declare function genDraftSignature(signingString: string, privateKey: string, hashAlgorithm: SignatureHashAlgorithm | null): string;
export declare function genDraftSignature(privateKey: crypto.CryptoKey, signingString: string): Promise<string>;
export declare function genDraftSignatureHeader(includeHeaders: string[], keyId: string, signature: string, algorithm: string): string;
export declare function signAsDraftToRequest(request: RequestLike, key: PrivateKey, includeHeaders: string[], opts?: {
hashAlgorithm?: SignatureHashAlgorithm;
web?: boolean;
}): {
signingString: string;
signature: string;
signatureHeader: string;
};
export declare function signAsDraftToRequestWeb(request: RequestLike, key: PrivateKey, includeHeaders: string[], opts?: {
hashAlgorithm?: SignatureHashAlgorithm;
hashAlgorithm?: SignatureHashAlgorithmUpperSnake;
}): Promise<{
signingString: string;
signature: string;
Expand Down
22 changes: 17 additions & 5 deletions dist/draft/verify.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
import type { ParsedDraftSignature } from '../types.js';
export declare function verifyDraftSignature(parsed: ParsedDraftSignature['value'], publicKeyPem: string, errorLogger?: ((message: any) => any)): boolean;
/**
* Experimental
* @experimental Testing Web Crypto API
* Verify Request (Parsed)
*/
export declare function webVerifyDraftSignature(parsed: ParsedDraftSignature['value'], publicKeyPem: string, errorLogger?: ((message: any) => any)): Promise<boolean>;
import type { ParsedDraftSignature, SignInfo } from '../types.js';
import { ParsedAlgorithmIdentifier } from '../pem/spki.js';
export declare class DraftKeyHashValidationError extends Error {
constructor(message: string);
}
/**
* 鍵のアルゴリズムとDraft仕様のalgorithmをもとに、キーとハッシュアルゴリズムをまとめる
* 呼び出しの公開鍵の種類が提供されたものと一致しない場合はエラーを投げる
* @param algorithm ヘッダーのアルゴリズム(Draft仕様)
* @param publicKey 実際の公開鍵
*/
export declare function genSignInfoDraft(algorithm: string | undefined, parsed: ParsedAlgorithmIdentifier, errorLogger?: ((message: any) => any)): SignInfo;
/**
* Verify a draft signature
*/
export declare function verifyDraftSignature(parsed: ParsedDraftSignature['value'], publicKeyPem: string, errorLogger?: ((message: any) => any)): Promise<boolean>;
Loading

0 comments on commit 8286028

Please sign in to comment.