diff options
3 files changed, 41 insertions, 31 deletions
diff --git a/packages/server/src/helpers/iso/isoCrypto/unwrapEC2Signature.ts b/packages/server/src/helpers/iso/isoCrypto/unwrapEC2Signature.ts new file mode 100644 index 0000000..259e3fe --- /dev/null +++ b/packages/server/src/helpers/iso/isoCrypto/unwrapEC2Signature.ts @@ -0,0 +1,36 @@ +import { ECDSASigValue } from '@peculiar/asn1-ecc'; +import { AsnParser } from '@peculiar/asn1-schema'; + +import { isoUint8Array } from '../'; + +/** + * EC2 signatures are wrapped in ASN.1 structure, so we need to peel it apart + */ +export function unwrapEC2Signature(signature: Uint8Array): Uint8Array { + const parsedSignature = AsnParser.parse(signature, ECDSASigValue); + let rBytes = new Uint8Array(parsedSignature.r); + let sBytes = new Uint8Array(parsedSignature.s); + + if (shouldRemoveLeadingZero(rBytes)) { + rBytes = rBytes.slice(1); + } + + if (shouldRemoveLeadingZero(sBytes)) { + sBytes = sBytes.slice(1); + } + + const finalSignature = isoUint8Array.concat([rBytes, sBytes]); + + return finalSignature; +} + +/** + * Determine if the DER-specific `00` byte at the start of an ECDSA signature byte sequence + * should be removed based on the following logic: + * + * "If the leading byte is 0x0, and the the high order bit on the second byte is not set to 0, + * then remove the leading 0x0 byte" + */ +function shouldRemoveLeadingZero(bytes: Uint8Array): boolean { + return bytes[0] === 0x0 && (bytes[1] & (1 << 7)) !== 0; +} diff --git a/packages/server/src/helpers/iso/isoCrypto/verify.ts b/packages/server/src/helpers/iso/isoCrypto/verify.ts index b995e7a..67f33cb 100644 --- a/packages/server/src/helpers/iso/isoCrypto/verify.ts +++ b/packages/server/src/helpers/iso/isoCrypto/verify.ts @@ -9,6 +9,7 @@ import { import { verifyEC2 } from './verifyEC2'; import { verifyRSA } from './verifyRSA'; import { verifyOKP } from './verifyOKP'; +import { unwrapEC2Signature } from './unwrapEC2Signature'; /** * Verify signatures with their public key. Supports EC2 and RSA public keys. @@ -22,7 +23,8 @@ export async function verify(opts: { const { cosePublicKey, signature, data, shaHashOverride } = opts; if (isCOSEPublicKeyEC2(cosePublicKey)) { - return verifyEC2({ cosePublicKey, signature, data, shaHashOverride }); + const unwrappedSignature = unwrapEC2Signature(signature); + return verifyEC2({ cosePublicKey, signature: unwrappedSignature, data, shaHashOverride }); } else if (isCOSEPublicKeyRSA(cosePublicKey)) { return verifyRSA({ cosePublicKey, signature, data, shaHashOverride }); } else if (isCOSEPublicKeyOKP(cosePublicKey)) { diff --git a/packages/server/src/helpers/iso/isoCrypto/verifyEC2.ts b/packages/server/src/helpers/iso/isoCrypto/verifyEC2.ts index b86f57f..716e650 100644 --- a/packages/server/src/helpers/iso/isoCrypto/verifyEC2.ts +++ b/packages/server/src/helpers/iso/isoCrypto/verifyEC2.ts @@ -1,11 +1,9 @@ import WebCrypto from '@simplewebauthn/iso-webcrypto'; -import { ECDSASigValue } from '@peculiar/asn1-ecc'; -import { AsnParser } from '@peculiar/asn1-schema'; import { COSEALG, COSECRV, COSEKEYS, COSEPublicKeyEC2 } from '../../cose'; import { mapCoseAlgToWebCryptoAlg } from './mapCoseAlgToWebCryptoAlg'; import { importKey } from './importKey'; -import { isoBase64URL, isoUint8Array } from '../index'; +import { isoBase64URL } from '../index'; import { SubtleCryptoCrv } from './structs'; /** @@ -87,31 +85,5 @@ export async function verifyEC2(opts: { hash: { name: subtleAlg }, }; - // The signature is wrapped in ASN.1 structure, so we need to peel it apart - const parsedSignature = AsnParser.parse(signature, ECDSASigValue); - let rBytes = new Uint8Array(parsedSignature.r); - let sBytes = new Uint8Array(parsedSignature.s); - - if (shouldRemoveLeadingZero(rBytes)) { - rBytes = rBytes.slice(1); - } - - if (shouldRemoveLeadingZero(sBytes)) { - sBytes = sBytes.slice(1); - } - - const finalSignature = isoUint8Array.concat([rBytes, sBytes]); - - return WebCrypto.subtle.verify(verifyAlgorithm, key, finalSignature, data); -} - -/** - * Determine if the DER-specific `00` byte at the start of an ECDSA signature byte sequence - * should be removed based on the following logic: - * - * "If the leading byte is 0x0, and the the high order bit on the second byte is not set to 0, - * then remove the leading 0x0 byte" - */ -function shouldRemoveLeadingZero(bytes: Uint8Array): boolean { - return bytes[0] === 0x0 && (bytes[1] & (1 << 7)) !== 0; + return WebCrypto.subtle.verify(verifyAlgorithm, key, signature, data); } |