From afbfd0681b05bf3158cd121a35497646dc1eb991 Mon Sep 17 00:00:00 2001 From: Wiktor Kwapisiewicz Date: Wed, 6 Mar 2024 15:27:40 +0100 Subject: [PATCH] Add support for P-521 curve Sadly Deno doesn't support it. See: https://github.com/denoland/deno/issues/13449#issuecomment-1879050683 --- fixtures/p521.txt | 1 + fixtures/p521.txt.ignore | 2 ++ fixtures/p521.txt.sig | 10 ++++++++++ formats.ts | 22 ++++++++++++++++++---- sig_parser.ts | 3 ++- verifier_test.ts | 9 ++++++++- 6 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 fixtures/p521.txt create mode 100644 fixtures/p521.txt.ignore create mode 100644 fixtures/p521.txt.sig diff --git a/fixtures/p521.txt b/fixtures/p521.txt new file mode 100644 index 0000000..f442c1b --- /dev/null +++ b/fixtures/p521.txt @@ -0,0 +1 @@ +Sure, here is P-265 fixture ;) diff --git a/fixtures/p521.txt.ignore b/fixtures/p521.txt.ignore new file mode 100644 index 0000000..42b1deb --- /dev/null +++ b/fixtures/p521.txt.ignore @@ -0,0 +1,2 @@ +Deno doesn't support P-521 due to their underlying crypto lib not supporting it. +See: https://github.com/denoland/deno/issues/13449#issuecomment-1879050683 diff --git a/fixtures/p521.txt.sig b/fixtures/p521.txt.sig new file mode 100644 index 0000000..69d9b15 --- /dev/null +++ b/fixtures/p521.txt.sig @@ -0,0 +1,10 @@ +-----BEGIN SSH SIGNATURE----- +U1NIU0lHAAAAAQAAAKwAAAATZWNkc2Etc2hhMi1uaXN0cDUyMQAAAAhuaXN0cDUyMQAAAI +UEABon2x0D7m1Dxnfxp9HhV3VddppTwwIpGxjj1u3ukoP/mEsH+LGMTu+ZMacofZpZRiGZ +5TyghUKep6pErZjffhnwAaMUI1M9kgK/QJVDpqiwiaRjRD4QXzVjxRhIsGPx11bCrxiuHJ +muoPPo8tibOuq8PHvYB9RIz3IZjy6BrV8w6cqlAAAABGZpbGUAAAAAAAAABnNoYTUxMgAA +AKcAAAATZWNkc2Etc2hhMi1uaXN0cDUyMQAAAIwAAABCAd0AAb8B0I3EziNuDnVnRKNk4t +3qtJqQ4w0fZhaguZ3LbSSwj4qAsIytsIdyD8MF04hm6lh+NzJa24Kt5uHSh7PbAAAAQgH+ +fCBwwS5/AWWrtEdrlxK5Tu2pVFLofJRoO5mDn80pHidM8IHQhecJmGY02e/G5dUpSoY/q3 +r6xnimpmfqKKrKUw== +-----END SSH SIGNATURE----- diff --git a/formats.ts b/formats.ts index a249812..f78da0b 100644 --- a/formats.ts +++ b/formats.ts @@ -10,7 +10,10 @@ export type Pubkey = { key: Uint8Array; toString(): string; } | { - pk_algo: "ecdsa-sha2-nistp256" | "ecdsa-sha2-nistp384"; + pk_algo: + | "ecdsa-sha2-nistp256" + | "ecdsa-sha2-nistp384" + | "ecdsa-sha2-nistp521"; curve: string; point: Uint8Array; toString(): string; @@ -40,7 +43,8 @@ export function parsePubkey( }, }; } else if ( - pk_algo === "ecdsa-sha2-nistp256" || pk_algo === "ecdsa-sha2-nistp384" + pk_algo === "ecdsa-sha2-nistp256" || pk_algo === "ecdsa-sha2-nistp384" || + pk_algo === "ecdsa-sha2-nistp521" ) { const curve = publickey.readString().toString(); pubkey = { @@ -91,7 +95,8 @@ export function convertPublicKey(publickey: Pubkey): { format: "raw", }; } else if ( - pk_algo === "ecdsa-sha2-nistp256" || pk_algo === "ecdsa-sha2-nistp384" + pk_algo === "ecdsa-sha2-nistp256" || pk_algo === "ecdsa-sha2-nistp384" || + pk_algo === "ecdsa-sha2-nistp521" ) { if (publickey.point[0] !== 0x04) { throw new Error("Only uncompressed (0x04) format is supported"); @@ -102,9 +107,12 @@ export function convertPublicKey(publickey: Pubkey): { let crv; if (pk_algo === "ecdsa-sha2-nistp256") { crv = "P-256"; - } else { + } else if (pk_algo === "ecdsa-sha2-nistp384") { crv = "P-384"; } + { + crv = "P-521"; + } return { keyData: { kty: "EC", @@ -142,6 +150,12 @@ export function convertAlgorithm(sig_algo: string) { namedCurve: "P-384", hash: { name: "SHA-384" }, }; + } else if (sig_algo === "ecdsa-sha2-nistp521") { + return { + name: "ECDSA", + namedCurve: "P-521", + hash: { name: "SHA-512" }, + }; } else { throw new Error(`Unsupported algo: ${sig_algo}`); } diff --git a/sig_parser.ts b/sig_parser.ts index 0e37c93..5f6a577 100644 --- a/sig_parser.ts +++ b/sig_parser.ts @@ -33,7 +33,8 @@ export function parse(signature: DataView | string): Sig { const sig_bytes = raw_signature.readString(); let bytes; if ( - sig_algo === "ecdsa-sha2-nistp256" || sig_algo === "ecdsa-sha2-nistp384" + sig_algo === "ecdsa-sha2-nistp256" || sig_algo === "ecdsa-sha2-nistp384" || + sig_algo === "ecdsa-sha2-nistp512" ) { let r = new Uint8Array(sig_bytes.readString().bytes()); if (r[0] === 0x00 && r.length % 2 == 1) { diff --git a/verifier_test.ts b/verifier_test.ts index 3f95d36..eb388f7 100644 --- a/verifier_test.ts +++ b/verifier_test.ts @@ -1,11 +1,18 @@ import { assertEquals } from "https://deno.land/std@0.217.0/assert/mod.ts"; +import { existsSync } from "https://deno.land/std@0.217.0/fs/mod.ts"; import { verify } from "./index.ts"; import { parse } from "./sig_parser.ts"; for await (const entry of Deno.readDir("fixtures")) { if (entry.name.endsWith(".sig")) { Deno.test( - { permissions: { read: true, write: true, run: true }, name: entry.name }, + { + permissions: { read: true, write: true, run: true }, + ignore: existsSync( + `fixtures/${entry.name.replace(/\.sig$/, ".ignore")}`, + ), + name: entry.name, + }, async () => { const signature = parse( await Deno.readTextFile(`fixtures/${entry.name}`),