@kya-os/mcp-i 1.7.8 → 1.7.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -245,39 +245,73 @@ class DelegationCredentialVerifier {
|
|
|
245
245
|
const vcWithoutProof = { ...vc };
|
|
246
246
|
delete vcWithoutProof.proof;
|
|
247
247
|
// The proof.proofValue is base64url-encoded Ed25519 signature
|
|
248
|
-
// The proof.jws is an alternative JWS-based signature format
|
|
249
|
-
const
|
|
250
|
-
if (!
|
|
248
|
+
// The proof.jws is an alternative JWS-based signature format (header.payload.signature)
|
|
249
|
+
const rawProofValue = vc.proof?.proofValue || vc.proof?.jws;
|
|
250
|
+
if (!rawProofValue) {
|
|
251
251
|
return {
|
|
252
252
|
valid: false,
|
|
253
253
|
reason: 'Proof missing proofValue or jws',
|
|
254
254
|
durationMs: Date.now() - startTime,
|
|
255
255
|
};
|
|
256
256
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
//
|
|
257
|
+
// Extract signature bytes and construct signing input
|
|
258
|
+
// Handle both JWS format (header.payload.signature) and proofValue format
|
|
259
|
+
let signatureBase64url;
|
|
260
|
+
let signingInput;
|
|
261
|
+
if (rawProofValue.includes('.')) {
|
|
262
|
+
// JWS format with b64:false (standard for Ed25519Signature2020)
|
|
263
|
+
// The signing input is: base64url(header) + "." + payload_bytes
|
|
264
|
+
const jwsParts = rawProofValue.split('.');
|
|
265
|
+
if (jwsParts.length !== 3) {
|
|
266
|
+
return {
|
|
267
|
+
valid: false,
|
|
268
|
+
reason: `Invalid JWS format: expected 3 parts, got ${jwsParts.length}`,
|
|
269
|
+
durationMs: Date.now() - startTime,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
const [headerB64, payloadB64, signatureB64] = jwsParts;
|
|
273
|
+
signatureBase64url = signatureB64;
|
|
274
|
+
// For b64:false JWS, the signing input is the detached payload format:
|
|
275
|
+
// ASCII(BASE64URL(UTF8(JWS Protected Header))) || '.' || JWS Payload
|
|
276
|
+
// The payload is the hash of the document (for Ed25519Signature2020)
|
|
277
|
+
// Per RFC 7797 (JWS Unencoded Payload Option)
|
|
278
|
+
// Construct proof options for hashing (everything in proof except signature fields)
|
|
279
|
+
const proofOptions = { ...vc.proof };
|
|
280
|
+
delete proofOptions.proofValue;
|
|
281
|
+
delete proofOptions.jws;
|
|
282
|
+
delete proofOptions.signatureValue;
|
|
283
|
+
const canonicalDoc = (0, json_canonicalize_1.canonicalize)(vcWithoutProof);
|
|
284
|
+
const canonicalProof = (0, json_canonicalize_1.canonicalize)(proofOptions);
|
|
285
|
+
// Hash both and concatenate (payload for JWS)
|
|
286
|
+
const docHash = (0, crypto_1.createHash)('sha256').update(canonicalDoc, 'utf8').digest();
|
|
287
|
+
const proofHash = (0, crypto_1.createHash)('sha256').update(canonicalProof, 'utf8').digest();
|
|
288
|
+
const payloadBytes = Buffer.concat([proofHash, docHash]);
|
|
289
|
+
// JWS signing input: header + "." + payload_bytes
|
|
290
|
+
const headerBytes = Buffer.from(headerB64, 'utf8');
|
|
291
|
+
const separator = Buffer.from('.', 'utf8');
|
|
292
|
+
signingInput = Buffer.concat([headerBytes, separator, payloadBytes]);
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
// proofValue is raw base64url signature (Ed25519Signature2020 native format)
|
|
296
|
+
signatureBase64url = rawProofValue;
|
|
263
297
|
// Construct proof options (everything in proof except proofValue)
|
|
264
298
|
const proofOptions = { ...vc.proof };
|
|
265
299
|
delete proofOptions.proofValue;
|
|
266
300
|
delete proofOptions.jws;
|
|
267
301
|
delete proofOptions.signatureValue;
|
|
268
|
-
// Create signing input: hash(canonicalize(
|
|
302
|
+
// Create signing input: hash(canonicalize(proofOptions)) || hash(canonicalize(document))
|
|
269
303
|
const canonicalDoc = (0, json_canonicalize_1.canonicalize)(vcWithoutProof);
|
|
270
304
|
const canonicalProof = (0, json_canonicalize_1.canonicalize)(proofOptions);
|
|
271
|
-
// For Ed25519Signature2020, signing input is:
|
|
272
|
-
// SHA-256(canonicalize(proofOptions)) || SHA-256(canonicalize(document))
|
|
273
305
|
const docHash = (0, crypto_1.createHash)('sha256').update(canonicalDoc, 'utf8').digest();
|
|
274
306
|
const proofHash = (0, crypto_1.createHash)('sha256').update(canonicalProof, 'utf8').digest();
|
|
275
|
-
|
|
307
|
+
signingInput = Buffer.concat([proofHash, docHash]);
|
|
308
|
+
}
|
|
309
|
+
try {
|
|
276
310
|
// Decode the base64url signature
|
|
277
|
-
const signatureBytes = Buffer.from(
|
|
311
|
+
const signatureBytes = Buffer.from(signatureBase64url, 'base64url');
|
|
278
312
|
// Use subtle crypto for Ed25519 verification
|
|
279
313
|
const cryptoKey = await globalThis.crypto.subtle.importKey('jwk', publicKeyJwk, { name: 'Ed25519' }, false, ['verify']);
|
|
280
|
-
const isValid = await globalThis.crypto.subtle.verify({ name: 'Ed25519' }, cryptoKey, signatureBytes, signingInput);
|
|
314
|
+
const isValid = await globalThis.crypto.subtle.verify({ name: 'Ed25519' }, cryptoKey, new Uint8Array(signatureBytes), new Uint8Array(signingInput));
|
|
281
315
|
if (!isValid) {
|
|
282
316
|
return {
|
|
283
317
|
valid: false,
|