Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
assertRejects,
} from '@std/assert';
import { returnsNext, stub } from '@std/testing/mock';
import { lessThan, parse } from '@std/semver';

import { verifyAuthenticationResponse } from './verifyAuthenticationResponse.ts';

Expand Down Expand Up @@ -838,6 +839,69 @@ Deno.test('should throw when topOrigin is set despite crossOrigin being false',
}
});

Deno.test(
'should verify ML-DSA-44 authentication response',
/**
* ML-DSA is only supported in Deno v2.8.2+
*/
{ ignore: lessThan(parse(Deno.version.deno), parse('2.8.2')) },
async () => {
const verification = await verifyAuthenticationResponse({
response: {
id: '-EM9FDFIdFVeqWdTycRjoZVN2ZS4vnVE-MBpg7k0pl4jpuqj4GnMCW3Wqlm2WWI2PQ',
rawId: '-EM9FDFIdFVeqWdTycRjoZVN2ZS4vnVE-MBpg7k0pl4jpuqj4GnMCW3Wqlm2WWI2PQ',
response: {
authenticatorData: 'dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvAFAAAACA',
clientDataJSON:
'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiSmkxNTk3MWpTRVNhOWhhQ1VZYjdzX3BNaFY4RE5Od1lUOFdiNXpiRW8xNTFBYjdzX011VC1fTUlqbm91c2ZhRjJRM2VtRkF4N0drcFhrVFVtTWljVFEiLCJvcmlnaW4iOiJodHRwczovL3dlYmF1dGhuLmlvIiwiY3Jvc3NPcmlnaW4iOmZhbHNlLCJvdGhlcl9rZXlzX2Nhbl9iZV9hZGRlZF9oZXJlIjoiZG8gbm90IGNvbXBhcmUgY2xpZW50RGF0YUpTT04gYWdhaW5zdCBhIHRlbXBsYXRlLiBTZWUgaHR0cHM6Ly9nb28uZ2wveWFiUGV4In0',
signature:
'e7L-Xli-2lj9ZlP2s26sbrvFGLkVrz74BZnDsLW-7HOhj7AcEl5Zgtm3VLvLtcrfqyKE0PTuFrswsikm7t6ddhxXphxWcSo4ggarl6ODQk8NdPCYoFhoK8qwpqKZKmJAl9xDsJE1HAudrWLgq_747JV4QmGLizK0_oJgGM7WLd5xVYvKsl14odBFjU_ZBCrjB0UHIMg8aAq1727yZnY1eiNeF_sEmci_pigYCo-MbxbHmQWPp-U75sGSPPfK0soN2-29_aIxRO4Fg8P37WrwVUrEFdG2PFNgAhcM-ljjyv3mkCfsLUiQNuS-a0cn6MeygREc2HBwE6ChS351-dpNTbkfnb-o1fA6suP1sh3-i7YZrEn9e2J7UZxIAEJPpmuKxYFA4Fj0lAGUhi3lvnkWPOnS8BUjPr5q5z5iEbyL4MokDP75G723Tyy-5L8u1pLmlSLiuwvuW5MBkEhjVVj0RpVSnCoqzwE9A9ZmqZx5wv5gQEi4hAA64mSoXGdUZ5EGkPGrrIDjGyIOrLjuHOSZ6hjyioZvMA1nCQJ76oaL5-Pn1FR1VTurI5ccTWrDAo5sHuo8uGjx9bsyy_aMT3Nzosu29PArTm0AkJFd7INXky0L9itCmhujSnali9zTO8UuwV0G8sZeB2BG4VZN2nkjT1Ib8VeBnSMTlIFVOI2JHlD9kePZuV3nCuAvK8j5qH5OPJoEeJzuxGHP2k7f0941kzyW9sjBaD90HEusVGGgST0qWigEKU3kKaO_Du5ZngcqlmKnnFVKXQk5mEV5nFs9ia76sKe9FKYUp_ZxsVFATcjXETW5GuXF1qIj0ZTCSmhn8V_cqEH29fQWyy9qxNa6kkKc4koZUP36B-h5yVawIDdfyjl-VueUvUyEunPv1EyqXQaf9bo-WThxD_5v3Bd2sYTOI__0PIsUvCASjZJMQU4jpwyXoR2EsLWDRD4fsAxLmdao0iXNxdlH0Ys2MqkXkkMbIylccEHkFjbm_VB5tPYQkFRqqRX13KUyYqqTpaT6MdD8IpltlzJxcNLd9mazUvOfSaf5ho2FFtv8TMubekKU8b92MoPQpjeS1DJ9y2pvMrtIiZP0Lm0WTeniN6luRfUN-4v5GU6FPajkOPLNV9OXJKLREhrA_SvbDldSF9RtWZOqIk1WeTlbnEWlejtwWFoLSScCSfExu6bu_vv9NKK-E8mTWF8_f4bCvlZQp58BEsTHrZuBiQzH34Z5wPeOZuuQlqbAquIS4_W6z_XmNW-d4FhIp2U3y9sYC7wpo1M7N7MB3HKwAliPVgsNHBRI4ZLZ-dL3FCyCMThKJqQMNrMcRif_Mm5Du--Atjn1UH2u2gAxiBA6IY7uSlSn-OJEO-m8qeif8zsdvVhXtJMxNAWZHhQ4QuRFgjuDgxy1nVuhGHdmXi6tseiiC2NQ9iqGuBRetexfz84R93RVSbKMkYlvBU1KPe8ARVf_N52C1KC9F2b3Uo5To9iD2lXShcsGkQkcAX5gjmhy4jrmTv5-pUJYAHa6A9Vorr59D7-Y-CVvVX59YJB9-kMT8wzHQdj2XimbcLKnS5Z4BKsMMEIt01LVkdHcBP9tKBQ20e-Kmf25wsUr9TqFa7ukQEhfLwgflIBbobAJoGKFC2_3fIKaEBuoAOoErASxPClLNAbBqG1JAdrAq9Ki3WC46aN4b-Q6ykfbk2azLAxOzFftJuhLWGLLCkOxbxjfaUrRJ51h8Dwrpy2xBT1qWurNnfFTrzScouK-R8G4SfsyaSiejiaLYLsWZVCcpeH_S8cqQuBFCMpQfxiPn2reOgMFhSzbdSDkzwUTQsjGq94QTs7bdS0LlyRb4OUa0s3szGSIa7n4vQ10uc9gzHlDxEqgaKSpPlVDyvZs58GC3PCZ2HJiiVbuc508_rV1xuydd7asPlyaOAMXImKPxp7d6rAGLbDOQOKS4U9sr6wKQVPnfPqg7TvmtuXTJS5Y_M6mutU7Bn8y6qmbjt5EtoETTSORHfx71ySMLZ8zxveJdsaNow6lfjvI0myk8oSDIucRar1j9G2m13B3K2Kr0URBweH6JkJz3Z7mYFTe09B6GMzIOcPoaYzzJP_PSrpuAfvb6V0AwVCX_HixF2qkCvcdrLyvGaGkkkYh32T2Renu7QWj8Wz06MvimWYCA4pB8SPJpjyw8mNZHOWJXgkI8hgD90O_rDF8mhEIMbDtfTZdOPjekS1a7-LNUGM6ajWLzDehU5YQBzTuGwgoPd2RV0E68iYR6QplHTmhh5vToa7eHvbQrYn8NUzJ6CP5YXcoxl7H9HsQ3AXDHmCtZ3e5p4FLV-Lz64_hVJWaTLOgHecFGAFqXMmnp1BtoKlzwbMnXaFMVaT1T7CkC_XZsoggQA1WFO3vFuXpnw4D6BPNGTmEZrEmINmfBVeFHB4SHDPJXDYX4wwTK8kgUpCHSI8ozIYFy0nw4uJqhkAYjXnvbEeCPsPkf7SPGS7xujgIdlYbtizeg-op2ZyI020Jt-hx2GogXRD_bsNcHaToWZ90fTI8M_Y1-F8iMJG4OnxinHlHnTj7R6wRuM2AZ4-Ov_yhd9w6yXenoKh56RReHCbYAvGCt3aDDyOrcX9WX7VePrBHH3C9ubCwj3PNcuP16or5ho6XRNlXC1s63J99dgi42FWatXeYdUvvcmK7fKxFZWSCXko-cArTT1KqgucxXg8wMk7gaGSwfb2j3pNt1hf4y5MOJQ-HbS0uhuywUbBiHBe8ns6FzUJpM4T8sNXAfbslBk1nIYU9BCMn1Veqw8puCYcwkjWJgxrKU_d2Jx0b8DKpIbbdFKkrdR4vAGRTJ74IgWPuk7wZTSWCddJAB4Q1PU1nbXO3MsxxzlQrWXY1jD9Zp3E69NEUss4qMTT6u5W-RG6RB6ge6sOt47l40v3IO-1LgsCwJtFyQzks0msArf0MSSQ9HreubNnjYqaMOqgUleX4-a0P8BhQwOhwt7C6zyGCnbcBiQx0RWAs0mvf-k5mgqn9Ij5mpGoGVV5L4OhBdY6pm51h7v02bgoWlzUzZHImgBhQtkx0jlBM9XeCIo4t8EQ4ZbqGmLsbj3CTu7KZbc9uQJkWyXSov2WWMvzZfOgCHbizXOGazd47v44BDRMXIiUmJzI1ZXiFkqPB0NftBw80ZnCHlpeq1Nzq8_QQHiM2R1SEsc_T1QQcSlJTVmBpdnqesbv9AAAAAAAAAAAAAAAAAAAAAAAAAAAAABMhLDo',
userHandle: 'd2ViYXV0aG5pby1tbC1kc2EtNDQ',
},
type: 'public-key',
clientExtensionResults: {},
},
expectedChallenge:
'Ji15971jSESa9haCUYb7s_pMhV8DNNwYT8Wb5zbEo151Ab7s_MuT-_MIjnousfaF2Q3emFAx7GkpXkTUmMicTQ',
expectedOrigin: 'https://webauthn.io',
expectedRPID: 'webauthn.io',
credential: {
id: '',
counter: 7,
publicKey: isoBase64URL.toBuffer(
'owEHAzgvIFkFIC4AIUrgARve17AEk0W30POluaL08p91eLXkktSjmAlmZdNTWhtUFj3wkseZEt4xpmWarG28Za86i7yq-B4df3uOuq3zQVTKOQUWJLWGJ3-wUUuyywPtkdgSqzQdcli6xMgwnVqh9r6FVL9Xp7x3kgjUVDqhux_k1D2d4ts2zqi1rUrSF6FNX139g3dd1VnUNQrMLdrwohR9CmE0fZ6Am4Df_OV2JxOrUEPzMFi5SeBcrU1oSj2lX_91gY179PO0wIOtTa1KzWvwOYa_KjOj9Ow16AtmsXrcpL-jYW4_bFn4kpT9G-vDG4qPFDpint62g0DDjEt7JrF288aIZXOpsbVmnjw2_O_5pFFvFpH32gD7_NdmvE6PSymNxPcTCnMzY3xv5wJXiEDhO21E85n78Oay4k7PzWHvzQxlJldIYw-9TfKZXqZa6sIbE-LyZj_Y2FV1Owd4WLvKCNcO-IIP3XFcZ7__XPZtAsBTJ5Z5w18jRnlMNKTygva-F2Ec65tA2skED9PnVyS_WjtZN5VjbhuU-D9DIDXEgUjitdcXWbCruDjxaBwjuDFXOI9cYdp4n-KWCZGJdX9QFHDGkvX6zDXupFrFV1q1JeKCayuMJjL3Z44AMF2UtjNODzhlviE8neX5NSfXdf36FWGFER6D6YCGGvooW8EBCx8OLPRNGGwoKBrEflr_ISYIdyw8-rDkAG0-bka_ulzfg8uTY8BXNu0HhqsteUPni4HlhUXMb0yI1DbLi5hTTkpBEBfmjzTJ8JMDe9sOOaqU2PrOzvIs5c7fx_VBqQZbF6amei2Y41okZJWwW0LWNvL2JQ_Yj9deHMczichCHWVX3uCL-SfPL3AaLeWLPjTAejU-H1Lnn2jWQeHtiRxBL1eleZNmJVqFbrgclcMXirM6rrmPrsbFe41fDF3Hm1KgcKkpZMPSICijfDCT4csVeLDxmsg9aDYwboxigOVHZa-zAmePLBZrPJIWDNEHNBG9CdEG-RfeshvnRbPerB1zLzA9jP-Jj55_Xd4igau4FEc7dLWgyn2b2Q3aMAaDnKCzEScd301WeuZtutm6flzqDPCUTJnoniUHuO__bALWkzIxe5rHW6wQ_wPBEX32bQNN-gtI6_yiw-UTwu3egro3tDp7ZzHkMSslF9FHD7divbmeEzsE8N4iOwO5kWFt2jY9VpjGXAhyCcGZtWU68SzllOpWzvuacFjlE5KZ_c4nHhYdaphJAjXvbkog-vGUwjffCXe9gQhIliwPzREtccZdgyLKiBAlypp0pwVKe6disU9-2kflk_BXPRf1PkBEqO41ySFZWLb6eSij9FrIXtPAo4RFmeKPLoYT-ce3gi8_XftVv7MDl9s0hoFlgh5vTh1xMdpxEt-6BxdesEF3zJycxNY4QFVkUKE78geXogQFz2QE7kW4ncTXjq4IydHOKX9Bp2P8uGcCJ6dzW3PFE-Zurf1klV-rkvT7xE-Tds7CPeWkrRr_Ckhn6rQ2Z3-Sjz5bgIRHiBnd0iZfm6ZgD77nVHY7ztaSmUQ7JWbeFSz0eoYExgXi7HfSdV77DlHxIjcNlrSh58SGWfkSwUVboOUJKy_B3EbBDeweqn1pf7QIjAJnYL7WiogmAku2UxEBQijtPAusmyhLf0_aTEFFc3zdGutHim3dzAKfJucy2aBm8ViQxY_U1N26WVO6sfui7dZVhqkQniZLCq8N_xqEMqWV6utksRHOvITvB_SqmeDacy2ZfiSogU8K5G0',
),
},
});

assert(verification.verified);
},
);

// Deno.test(
// 'should verify ML-DSA-65 authentication response',
// /**
// * ML-DSA is only supported in Deno v2.8.2+
// */
// { ignore: lessThan(parse(Deno.version.deno), parse('2.8.2')) },
// async () => {
// const verification = await verifyAuthenticationResponse({});

// assert(verification.verified);
// });

// Deno.test(
// 'should verify ML-DSA-87 authentication response',
// /**
// * ML-DSA is only supported in Deno v2.8.2+
// */
// { ignore: lessThan(parse(Deno.version.deno), parse('2.8.2')) },
// async () => {
// const verification = await verifyAuthenticationResponse({});

// assert(verification.verified);
// });

/**
* Assertion examples below
*/
Expand Down
25 changes: 25 additions & 0 deletions packages/server/src/helpers/cose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ export type COSEPublicKeyRSA = COSEPublicKey & {
set(key: COSEKEYS.e, value: Uint8Array_): void;
};

/**
* Values specific for AKP (ML-DSA) public keys
*/
export type COSEPublicKeyAKP = COSEPublicKey & {
// Getters
get(key: COSEKEYS.pub): Uint8Array_ | undefined;
// Setters
set(key: COSEKEYS.pub, value: Uint8Array_): void;
};

/**
* A type guard for determining if a COSE public key is an OKP key pair
*/
Expand Down Expand Up @@ -92,6 +102,16 @@ export function isCOSEPublicKeyRSA(
return isCOSEKty(kty) && kty === COSEKTY.RSA;
}

/**
* A type guard for determining if a COSE public key is an AKP key pair
*/
export function isCOSEPublicKeyAKP(
cosePublicKey: COSEPublicKey,
): cosePublicKey is COSEPublicKeyAKP {
const kty = cosePublicKey.get(COSEKEYS.kty);
return isCOSEKty(kty) && kty === COSEKTY.AKP;
}

/**
* COSE Keys
*
Expand All @@ -106,6 +126,7 @@ export enum COSEKEYS {
y = -3,
n = -1,
e = -2,
pub = -1,
}

/**
Expand All @@ -117,6 +138,7 @@ export enum COSEKTY {
OKP = 1,
EC2 = 2,
RSA = 3,
AKP = 7,
}

export function isCOSEKty(kty: number | undefined): kty is COSEKTY {
Expand Down Expand Up @@ -154,6 +176,9 @@ export enum COSEALG {
PS384 = -38,
PS512 = -39,
ES256K = -47,
ML_DSA_44 = -48,
ML_DSA_65 = -49,
ML_DSA_87 = -50,
RS256 = -257,
RS384 = -258,
RS512 = -259,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { getWebCrypto } from './getWebCrypto.ts';

export async function importKey(opts: {
/**
* Convert a JWK-formatted public key into a WebCrypto CryptoKey that can be used for
* signature verification
*/
export async function importJWKKey(opts: {
keyData: JsonWebKey;
algorithm: AlgorithmIdentifier | RsaHashedImportParams | EcKeyImportParams;
}): Promise<CryptoKey> {
const WebCrypto = await getWebCrypto();

const { keyData, algorithm } = opts;

return WebCrypto.subtle.importKey('jwk', keyData, algorithm, false, [
'verify',
]);
return WebCrypto.subtle.importKey('jwk', keyData, algorithm, false, ['verify']);
}
Original file line number Diff line number Diff line change
@@ -1,26 +1,32 @@
import { COSEALG } from '../../cose.ts';
import { SubtleCryptoKeyAlgName } from './structs.ts';
import type { SubtleCryptoKeyAlgName } from './structs.ts';

/**
* Convert a COSE alg ID into a corresponding key algorithm string value that WebCrypto APIs expect
*
* Unless otherwise specified, mappings were referenced from
* https://w3c.github.io/webcrypto/#jwk-mapping-alg
*/
export function mapCoseAlgToWebCryptoKeyAlgName(
alg: COSEALG,
): SubtleCryptoKeyAlgName {
if ([COSEALG.EdDSA].indexOf(alg) >= 0) {
return 'Ed25519';
} else if (
[COSEALG.ES256, COSEALG.ES384, COSEALG.ES512, COSEALG.ES256K].indexOf(
alg,
) >= 0
) {
} else if ([COSEALG.ES256, COSEALG.ES384, COSEALG.ES512, COSEALG.ES256K].indexOf(alg) >= 0) {
return 'ECDSA';
} else if (
[COSEALG.RS256, COSEALG.RS384, COSEALG.RS512, COSEALG.RS1].indexOf(alg) >= 0
) {
} else if ([COSEALG.RS256, COSEALG.RS384, COSEALG.RS512, COSEALG.RS1].indexOf(alg) >= 0) {
return 'RSASSA-PKCS1-v1_5';
} else if ([COSEALG.PS256, COSEALG.PS384, COSEALG.PS512].indexOf(alg) >= 0) {
return 'RSA-PSS';
} else if ([COSEALG.ML_DSA_44].indexOf(alg) >= 0) {
// https://wicg.github.io/webcrypto-modern-algos/#ml-dsa-registration
return 'ML-DSA-44';
} else if ([COSEALG.ML_DSA_65].indexOf(alg) >= 0) {
// https://wicg.github.io/webcrypto-modern-algos/#ml-dsa-registration
return 'ML-DSA-65';
} else if ([COSEALG.ML_DSA_87].indexOf(alg) >= 0) {
// https://wicg.github.io/webcrypto-modern-algos/#ml-dsa-registration
return 'ML-DSA-87';
}

throw new Error(
Expand Down
3 changes: 3 additions & 0 deletions packages/server/src/helpers/iso/isoCrypto/structs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@ export type SubtleCryptoCrv = 'P-256' | 'P-384' | 'P-521' | 'Ed25519';
export type SubtleCryptoKeyAlgName =
| 'ECDSA'
| 'Ed25519'
| 'ML-DSA-44'
| 'ML-DSA-65'
| 'ML-DSA-87'
| 'RSASSA-PKCS1-v1_5'
| 'RSA-PSS';
4 changes: 4 additions & 0 deletions packages/server/src/helpers/iso/isoCrypto/verify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import {
COSEKEYS,
type COSEPublicKey,
isCOSECrv,
isCOSEPublicKeyAKP,
isCOSEPublicKeyEC2,
isCOSEPublicKeyOKP,
isCOSEPublicKeyRSA,
} from '../../cose.ts';
import { verifyAKP } from './verifyAKP.ts';
import { verifyEC2 } from './verifyEC2.ts';
import { verifyRSA } from './verifyRSA.ts';
import { verifyOKP } from './verifyOKP.ts';
Expand Down Expand Up @@ -40,6 +42,8 @@ export function verify(opts: {
return verifyRSA({ cosePublicKey, signature, data, shaHashOverride });
} else if (isCOSEPublicKeyOKP(cosePublicKey)) {
return verifyOKP({ cosePublicKey, signature, data });
} else if (isCOSEPublicKeyAKP(cosePublicKey)) {
return verifyAKP({ cosePublicKey, signature, data });
}

const kty = cosePublicKey.get(COSEKEYS.kty);
Expand Down
68 changes: 68 additions & 0 deletions packages/server/src/helpers/iso/isoCrypto/verifyAKP.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { COSEKEYS, type COSEPublicKeyAKP, isCOSEAlg } from '../../cose.ts';
import { isoBase64URL } from '../../index.ts';
import { importJWKKey } from './importJWKKey.ts';
import { getWebCrypto } from './getWebCrypto.ts';
import { mapCoseAlgToWebCryptoKeyAlgName } from './mapCoseAlgToWebCryptoKeyAlgName.ts';
import type { Base64URLString, Uint8Array_ } from '../../../types/index.ts';

/** AKP, a.k.a ML-DSA */
export async function verifyAKP(opts: {
cosePublicKey: COSEPublicKeyAKP;
signature: Uint8Array_;
data: Uint8Array_;
}): Promise<boolean> {
const { cosePublicKey, signature, data } = opts;

const WebCrypto = await getWebCrypto();

const alg = cosePublicKey.get(COSEKEYS.alg);
const pub = cosePublicKey.get(COSEKEYS.pub);

if (!alg) {
throw new Error('Public key was missing alg (AKP)');
}

if (!isCOSEAlg(alg)) {
throw new Error(`Public key had invalid alg ${alg} (AKP)`);
}

if (!pub) {
throw new Error('Public key was missing pub (AKP)');
}

const webCryptoAlg = mapCoseAlgToWebCryptoKeyAlgName(alg);

// See https://wicg.github.io/webcrypto-modern-algos/#ml-dsa-operations-import-key -> "jwk"
const keyData: JsonWebKeyAKP = {
kty: 'AKP',
alg: webCryptoAlg,
pub: isoBase64URL.fromBuffer(pub),
ext: false,
};

/**
* ML-DSA support is pretty cutting edge, so take some steps to help RP's understand this instead
* of them getting a `NotSupportedError: Unrecognized algorithm name` and trying to interpret it.
*/
let key: Awaited<ReturnType<typeof importJWKKey>>;
try {
key = await importJWKKey({ keyData, algorithm: webCryptoAlg });
} catch (err) {
const _err = err as Error;
if (_err.name === 'NotSupportedError') {
throw new Error(
`This runtime's WebCrypto.subtle does not support use of ${webCryptoAlg}. See the \`cause\` property of this error for more info`,
{ cause: err },
);
} else {
throw err;
}
}

return WebCrypto.subtle.verify(webCryptoAlg, key, signature, data);
}

type JsonWebKeyAKP = JsonWebKey & {
// https://www.rfc-editor.org/rfc/rfc9964.html#section-8.1.6.1
pub?: Base64URLString;
};
7 changes: 2 additions & 5 deletions packages/server/src/helpers/iso/isoCrypto/verifyEC2.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { type COSEALG, COSECRV, COSEKEYS, type COSEPublicKeyEC2 } from '../../cose.ts';
import { mapCoseAlgToWebCryptoAlg } from './mapCoseAlgToWebCryptoAlg.ts';
import { importKey } from './importKey.ts';
import { importJWKKey } from './importJWKKey.ts';
import { isoBase64URL } from '../index.ts';
import type { SubtleCryptoCrv } from './structs.ts';
import { getWebCrypto } from './getWebCrypto.ts';
Expand Down Expand Up @@ -71,10 +71,7 @@ export async function verifyEC2(opts: {
namedCurve: _crv,
};

const key = await importKey({
keyData,
algorithm: keyAlgorithm,
});
const key = await importJWKKey({ keyData, algorithm: keyAlgorithm });

// Determine which SHA algorithm to use for signature verification
let subtleAlg = mapCoseAlgToWebCryptoAlg(alg);
Expand Down
7 changes: 2 additions & 5 deletions packages/server/src/helpers/iso/isoCrypto/verifyOKP.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { COSECRV, COSEKEYS, type COSEPublicKeyOKP, isCOSEAlg } from '../../cose.ts';
import { isoBase64URL } from '../../index.ts';
import type { SubtleCryptoCrv } from './structs.ts';
import { importKey } from './importKey.ts';
import { importJWKKey } from './importJWKKey.ts';
import { getWebCrypto } from './getWebCrypto.ts';
import type { Uint8Array_ } from '../../../types/index.ts';

Expand Down Expand Up @@ -56,10 +56,7 @@ export async function verifyOKP(opts: {
namedCurve: _crv,
};

const key = await importKey({
keyData,
algorithm: keyAlgorithm,
});
const key = await importJWKKey({ keyData, algorithm: keyAlgorithm });

const verifyAlgorithm: AlgorithmIdentifier = {
name: _crv,
Expand Down
7 changes: 2 additions & 5 deletions packages/server/src/helpers/iso/isoCrypto/verifyRSA.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { type COSEALG, COSEKEYS, type COSEPublicKeyRSA, isCOSEAlg } from '../../cose.ts';
import { mapCoseAlgToWebCryptoAlg } from './mapCoseAlgToWebCryptoAlg.ts';
import { importKey } from './importKey.ts';
import { importJWKKey } from './importJWKKey.ts';
import { isoBase64URL } from '../index.ts';
import { mapCoseAlgToWebCryptoKeyAlgName } from './mapCoseAlgToWebCryptoKeyAlgName.ts';
import { getWebCrypto } from './getWebCrypto.ts';
Expand Down Expand Up @@ -99,10 +99,7 @@ export async function verifyRSA(opts: {
);
}

const key = await importKey({
keyData,
algorithm: keyAlgorithm,
});
const key = await importJWKKey({ keyData, algorithm: keyAlgorithm });

return WebCrypto.subtle.verify(verifyAlgorithm, key, signature, data);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { isoBase64URL, isoUint8Array } from '../helpers/iso/index.ts';
export type GenerateRegistrationOptionsOpts = Parameters<typeof generateRegistrationOptions>[0];

/**
* Supported crypto algo identifiers
* Supported crypto algo identifiers.
* See https://w3c.github.io/webauthn/#sctn-alg-identifier
* and https://www.iana.org/assignments/cose/cose.xhtml#algorithms
*/
Expand All @@ -32,6 +32,12 @@ export const supportedCOSEAlgorithmIdentifiers: COSEAlgorithmIdentifier[] = [
-38,
// RSASSA-PSS w/ SHA-512
-39,
// ML-DSA-44
-48,
// ML-DSA-65
-49,
// ML-DSA-87
-50,
// RSASSA-PKCS1-v1_5 w/ SHA-256
-257,
// RSASSA-PKCS1-v1_5 w/ SHA-384
Expand Down
Loading