From c53be990994e8c31a07627f2fe1a50e65888336c Mon Sep 17 00:00:00 2001 From: A-Chronicle Date: Thu, 21 May 2026 14:30:48 +0530 Subject: [PATCH] fix(mercury,castor): replace unsafe JWK as any casts with runtime type validation Remove unsafe `as any` casts when accessing `x` and `kid` fields on publicKeyJwk. Use the SDKs existing `expect()` utility and explicit type guards to validate that JWK coordinates are present before passing them to cryptographic operations. - DIDCommDIDResolver: use `expect()` instead of `as any` for `x`, drop unnecessary `as any` for `kid` (already typed on JWK.Base) - prism/index.ts: replace `as any` on `x` with typeof guard throwing InvalidKeyError when x is missing or not a string - Add test: missing JWK x coordinate in DIDDoc throws InvalidKeyError Fixes #625 Signed-off-by: A-Chronicle --- .../lib/sdk/src/castor/methods/prism/index.ts | 7 ++++-- .../lib/sdk/src/mercury/DIDCommDIDResolver.ts | 4 ++-- .../tests/mercury/didcomm/DIDResolver.test.ts | 24 +++++++++++++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/packages/lib/sdk/src/castor/methods/prism/index.ts b/packages/lib/sdk/src/castor/methods/prism/index.ts index c404b5470..b47abd381 100644 --- a/packages/lib/sdk/src/castor/methods/prism/index.ts +++ b/packages/lib/sdk/src/castor/methods/prism/index.ts @@ -309,8 +309,11 @@ export class PrismDIDMethod const { usage, index } = this.getUsageFromId(verificationMethod.id); if (verificationMethod.publicKeyJwk) { - // TODO need to properly parse JWK into key / raw - const raw = base64.base64url.baseDecode(verificationMethod.publicKeyJwk.x as any); + const xValue = verificationMethod.publicKeyJwk.x; + if (typeof xValue !== 'string') { + throw new Domain.CastorError.InvalidKeyError('Invalid JWK: x coordinate is missing or not a string'); + } + const raw = base64.base64url.baseDecode(xValue); if (verificationMethod.publicKeyJwk.crv === Domain.Curve.SECP256K1) { return this.createProtos(new Secp256k1PublicKey(raw), usage, index); diff --git a/packages/lib/sdk/src/mercury/DIDCommDIDResolver.ts b/packages/lib/sdk/src/mercury/DIDCommDIDResolver.ts index a677c689e..2bff1daea 100644 --- a/packages/lib/sdk/src/mercury/DIDCommDIDResolver.ts +++ b/packages/lib/sdk/src/mercury/DIDCommDIDResolver.ts @@ -41,8 +41,8 @@ export class DIDCommDIDResolver implements DIDComm.DIDResolver { keyAgreements.push(method.id); break; } - const publicKeyBase64 = method.publicKeyJwk?.x as any; - const publicKeyKid = (method.publicKeyJwk as any).kid; + const publicKeyBase64 = expect(method.publicKeyJwk?.x, CastorError.InvalidKeyError); + const publicKeyKid = method.publicKeyJwk?.kid; const kty = (curve === Curve.ED25519 || curve === Curve.X25519) ? "OKP" : "EC"; verificationMethods.push({ controller: method.controller, diff --git a/packages/lib/sdk/tests/mercury/didcomm/DIDResolver.test.ts b/packages/lib/sdk/tests/mercury/didcomm/DIDResolver.test.ts index f11d1d234..8c050c0d6 100644 --- a/packages/lib/sdk/tests/mercury/didcomm/DIDResolver.test.ts +++ b/packages/lib/sdk/tests/mercury/didcomm/DIDResolver.test.ts @@ -97,4 +97,28 @@ describe("Mercury DIDComm DIDResolver", () => { }); }); }); + + describe("JWK validation", () => { + it("should throw InvalidKeyError when JWK x coordinate is missing", async () => { + const idDid = Domain.DID.fromString("did:test:id"); + const vm = new Domain.DIDDocument.VerificationMethod( + "vm-ED25519", + "1", + "Ed25519VerificationKey2018", + { crv: Domain.Curve.ED25519, kid: "kid" } as any + ); + + const castor: Pick = { + resolveDID: async (): Promise => + new Domain.DIDDocument(idDid, [ + new Domain.DIDDocument.Authentication([], [vm]), + ]), + }; + + const sut = new DIDCommDIDResolver(castor as any); + await expect(sut.resolve(idDid.toString())).rejects.toThrow( + Domain.CastorError.InvalidKeyError + ); + }); + }); });