@sphereon/ssi-sdk.mdl-mdoc 0.37.2-next.34 → 0.38.0
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.
- package/dist/index.cjs +488 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +488 -36
- package/dist/index.js.map +1 -1
- package/package.json +15 -15
- package/src/agent/mDLMdoc.ts +149 -21
- package/src/functions/index.ts +312 -13
package/dist/index.d.cts
CHANGED
|
@@ -119,16 +119,22 @@ declare const mdocSupportMethods: Array<string>;
|
|
|
119
119
|
declare class MDLMdoc implements IAgentPlugin {
|
|
120
120
|
readonly schema: any;
|
|
121
121
|
readonly methods: ImDLMdoc;
|
|
122
|
-
private readonly
|
|
122
|
+
private readonly staticTrustAnchors;
|
|
123
|
+
private readonly trustAnchorProvider?;
|
|
124
|
+
private readonly blindlyTrustedAnchorProvider?;
|
|
123
125
|
private opts;
|
|
124
126
|
constructor(args?: {
|
|
125
127
|
trustAnchors?: string[];
|
|
128
|
+
trustAnchorProvider?: () => string[];
|
|
129
|
+
blindlyTrustedAnchorProvider?: () => string[];
|
|
126
130
|
opts?: {
|
|
127
131
|
trustRootWhenNoAnchors?: boolean;
|
|
128
132
|
allowSingleNoCAChainElement?: boolean;
|
|
129
133
|
blindlyTrustedAnchors?: string[];
|
|
130
134
|
};
|
|
131
135
|
});
|
|
136
|
+
private get trustAnchors();
|
|
137
|
+
private get effectiveBlindlyTrustedAnchors();
|
|
132
138
|
/**
|
|
133
139
|
* Processes and verifies the provided mdoc, generates device response and presentation submission tokens.
|
|
134
140
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -119,16 +119,22 @@ declare const mdocSupportMethods: Array<string>;
|
|
|
119
119
|
declare class MDLMdoc implements IAgentPlugin {
|
|
120
120
|
readonly schema: any;
|
|
121
121
|
readonly methods: ImDLMdoc;
|
|
122
|
-
private readonly
|
|
122
|
+
private readonly staticTrustAnchors;
|
|
123
|
+
private readonly trustAnchorProvider?;
|
|
124
|
+
private readonly blindlyTrustedAnchorProvider?;
|
|
123
125
|
private opts;
|
|
124
126
|
constructor(args?: {
|
|
125
127
|
trustAnchors?: string[];
|
|
128
|
+
trustAnchorProvider?: () => string[];
|
|
129
|
+
blindlyTrustedAnchorProvider?: () => string[];
|
|
126
130
|
opts?: {
|
|
127
131
|
trustRootWhenNoAnchors?: boolean;
|
|
128
132
|
allowSingleNoCAChainElement?: boolean;
|
|
129
133
|
blindlyTrustedAnchors?: string[];
|
|
130
134
|
};
|
|
131
135
|
});
|
|
136
|
+
private get trustAnchors();
|
|
137
|
+
private get effectiveBlindlyTrustedAnchors();
|
|
132
138
|
/**
|
|
133
139
|
* Processes and verifies the provided mdoc, generates device response and presentation submission tokens.
|
|
134
140
|
*
|
package/dist/index.js
CHANGED
|
@@ -2056,15 +2056,315 @@ import { derToPEM, getCertificateInfo, getSubjectDN, pemOrDerToX509Certificate,
|
|
|
2056
2056
|
import * as crypto from "crypto";
|
|
2057
2057
|
import { CryptoEngine, setEngine } from "pkijs";
|
|
2058
2058
|
import { fromString } from "uint8arrays/from-string";
|
|
2059
|
+
import { toString as u8aToString } from "uint8arrays/to-string";
|
|
2059
2060
|
var { com } = mdocPkg;
|
|
2060
2061
|
var CoseJoseKeyMappingService = com.sphereon.crypto.CoseJoseKeyMappingService;
|
|
2061
2062
|
var KeyInfo = mdocPkg.com.sphereon.crypto.KeyInfo;
|
|
2062
2063
|
var DateTimeUtils = mdocPkg.com.sphereon.kmp.DateTimeUtils;
|
|
2063
|
-
var decodeFrom = mdocPkg.com.sphereon.kmp.decodeFrom;
|
|
2064
|
-
var encodeTo = mdocPkg.com.sphereon.kmp.encodeTo;
|
|
2065
|
-
var Encoding = mdocPkg.com.sphereon.kmp.Encoding;
|
|
2066
2064
|
var SignatureAlgorithm = mdocPkg.com.sphereon.crypto.generic.SignatureAlgorithm;
|
|
2067
2065
|
var DefaultCallbacks = mdocPkg.com.sphereon.crypto.DefaultCallbacks;
|
|
2066
|
+
function toU8(bytes) {
|
|
2067
|
+
if (bytes instanceof Uint8Array) return bytes;
|
|
2068
|
+
if (ArrayBuffer.isView(bytes)) {
|
|
2069
|
+
const v = bytes;
|
|
2070
|
+
return new Uint8Array(v.buffer, v.byteOffset, v.byteLength);
|
|
2071
|
+
}
|
|
2072
|
+
if (Array.isArray(bytes)) return Uint8Array.from(bytes.map((b) => b & 255));
|
|
2073
|
+
throw new Error("unsupported raw bytes type");
|
|
2074
|
+
}
|
|
2075
|
+
__name(toU8, "toU8");
|
|
2076
|
+
function extractIssuerAuthRawParts(rawInput) {
|
|
2077
|
+
const u8 = toU8(rawInput);
|
|
2078
|
+
let pos = 0;
|
|
2079
|
+
const readHead = /* @__PURE__ */ __name(() => {
|
|
2080
|
+
const b = u8[pos++];
|
|
2081
|
+
const mt = b >> 5;
|
|
2082
|
+
const info = b & 31;
|
|
2083
|
+
let len;
|
|
2084
|
+
if (info < 24) len = info;
|
|
2085
|
+
else if (info === 24) {
|
|
2086
|
+
len = u8[pos];
|
|
2087
|
+
pos += 1;
|
|
2088
|
+
} else if (info === 25) {
|
|
2089
|
+
len = u8[pos] << 8 | u8[pos + 1];
|
|
2090
|
+
pos += 2;
|
|
2091
|
+
} else if (info === 26) {
|
|
2092
|
+
len = u8[pos] * 16777216 + (u8[pos + 1] << 16) + (u8[pos + 2] << 8) + u8[pos + 3];
|
|
2093
|
+
pos += 4;
|
|
2094
|
+
} else throw new Error("unsupported cbor length info " + info);
|
|
2095
|
+
return {
|
|
2096
|
+
mt,
|
|
2097
|
+
len
|
|
2098
|
+
};
|
|
2099
|
+
}, "readHead");
|
|
2100
|
+
const skip = /* @__PURE__ */ __name(() => {
|
|
2101
|
+
const h = readHead();
|
|
2102
|
+
switch (h.mt) {
|
|
2103
|
+
case 0:
|
|
2104
|
+
case 1:
|
|
2105
|
+
case 7:
|
|
2106
|
+
return;
|
|
2107
|
+
case 2:
|
|
2108
|
+
case 3:
|
|
2109
|
+
pos += h.len;
|
|
2110
|
+
return;
|
|
2111
|
+
case 4:
|
|
2112
|
+
for (let i = 0; i < h.len; i++) skip();
|
|
2113
|
+
return;
|
|
2114
|
+
case 5:
|
|
2115
|
+
for (let i = 0; i < h.len * 2; i++) skip();
|
|
2116
|
+
return;
|
|
2117
|
+
case 6:
|
|
2118
|
+
skip();
|
|
2119
|
+
return;
|
|
2120
|
+
}
|
|
2121
|
+
}, "skip");
|
|
2122
|
+
const readBstr = /* @__PURE__ */ __name(() => {
|
|
2123
|
+
const h = readHead();
|
|
2124
|
+
if (h.mt !== 2) throw new Error("expected bstr, got mt " + h.mt);
|
|
2125
|
+
const out = u8.slice(pos, pos + h.len);
|
|
2126
|
+
pos += h.len;
|
|
2127
|
+
return out;
|
|
2128
|
+
}, "readBstr");
|
|
2129
|
+
const readTstr = /* @__PURE__ */ __name(() => {
|
|
2130
|
+
const h = readHead();
|
|
2131
|
+
if (h.mt !== 3) throw new Error("expected tstr, got mt " + h.mt);
|
|
2132
|
+
const out = new TextDecoder().decode(u8.slice(pos, pos + h.len));
|
|
2133
|
+
pos += h.len;
|
|
2134
|
+
return out;
|
|
2135
|
+
}, "readTstr");
|
|
2136
|
+
const outer = readHead();
|
|
2137
|
+
if (outer.mt !== 5) return void 0;
|
|
2138
|
+
for (let i = 0; i < outer.len; i++) {
|
|
2139
|
+
const key = readTstr();
|
|
2140
|
+
if (key === "issuerAuth") {
|
|
2141
|
+
const arr = readHead();
|
|
2142
|
+
if (arr.mt !== 4 || arr.len !== 4) throw new Error("issuerAuth is not a 4-element array");
|
|
2143
|
+
const protectedBytes = readBstr();
|
|
2144
|
+
skip();
|
|
2145
|
+
const payloadBytes = readBstr();
|
|
2146
|
+
return {
|
|
2147
|
+
protectedBytes,
|
|
2148
|
+
payloadBytes
|
|
2149
|
+
};
|
|
2150
|
+
}
|
|
2151
|
+
skip();
|
|
2152
|
+
}
|
|
2153
|
+
return void 0;
|
|
2154
|
+
}
|
|
2155
|
+
__name(extractIssuerAuthRawParts, "extractIssuerAuthRawParts");
|
|
2156
|
+
function encodeBstrHeader(len) {
|
|
2157
|
+
if (len < 24) return new Uint8Array([
|
|
2158
|
+
64 | len
|
|
2159
|
+
]);
|
|
2160
|
+
if (len < 256) return new Uint8Array([
|
|
2161
|
+
88,
|
|
2162
|
+
len
|
|
2163
|
+
]);
|
|
2164
|
+
if (len < 65536) return new Uint8Array([
|
|
2165
|
+
89,
|
|
2166
|
+
len >> 8 & 255,
|
|
2167
|
+
len & 255
|
|
2168
|
+
]);
|
|
2169
|
+
return new Uint8Array([
|
|
2170
|
+
90,
|
|
2171
|
+
len >>> 24 & 255,
|
|
2172
|
+
len >> 16 & 255,
|
|
2173
|
+
len >> 8 & 255,
|
|
2174
|
+
len & 255
|
|
2175
|
+
]);
|
|
2176
|
+
}
|
|
2177
|
+
__name(encodeBstrHeader, "encodeBstrHeader");
|
|
2178
|
+
function concatU8(parts) {
|
|
2179
|
+
let total = 0;
|
|
2180
|
+
for (const p of parts) total += p.length;
|
|
2181
|
+
const out = new Uint8Array(total);
|
|
2182
|
+
let off = 0;
|
|
2183
|
+
for (const p of parts) {
|
|
2184
|
+
out.set(p, off);
|
|
2185
|
+
off += p.length;
|
|
2186
|
+
}
|
|
2187
|
+
return out;
|
|
2188
|
+
}
|
|
2189
|
+
__name(concatU8, "concatU8");
|
|
2190
|
+
function buildSig1Structure(protectedBytes, payloadBytes) {
|
|
2191
|
+
const sig1Label = new Uint8Array([
|
|
2192
|
+
106,
|
|
2193
|
+
83,
|
|
2194
|
+
105,
|
|
2195
|
+
103,
|
|
2196
|
+
110,
|
|
2197
|
+
97,
|
|
2198
|
+
116,
|
|
2199
|
+
117,
|
|
2200
|
+
114,
|
|
2201
|
+
101,
|
|
2202
|
+
49
|
|
2203
|
+
]);
|
|
2204
|
+
return concatU8([
|
|
2205
|
+
new Uint8Array([
|
|
2206
|
+
132
|
|
2207
|
+
]),
|
|
2208
|
+
sig1Label,
|
|
2209
|
+
encodeBstrHeader(protectedBytes.length),
|
|
2210
|
+
protectedBytes,
|
|
2211
|
+
new Uint8Array([
|
|
2212
|
+
64
|
|
2213
|
+
]),
|
|
2214
|
+
encodeBstrHeader(payloadBytes.length),
|
|
2215
|
+
payloadBytes
|
|
2216
|
+
]);
|
|
2217
|
+
}
|
|
2218
|
+
__name(buildSig1Structure, "buildSig1Structure");
|
|
2219
|
+
function derEcdsaToRaw(der, coordSize) {
|
|
2220
|
+
let offset = 0;
|
|
2221
|
+
if (der[offset++] !== 48) throw new Error("Invalid DER ECDSA signature: missing SEQUENCE tag");
|
|
2222
|
+
let seqLen = der[offset++];
|
|
2223
|
+
if (seqLen & 128) {
|
|
2224
|
+
const numBytes = seqLen & 127;
|
|
2225
|
+
seqLen = 0;
|
|
2226
|
+
for (let i = 0; i < numBytes; i++) seqLen = seqLen << 8 | der[offset++];
|
|
2227
|
+
}
|
|
2228
|
+
const readInt = /* @__PURE__ */ __name(() => {
|
|
2229
|
+
if (der[offset++] !== 2) throw new Error("Invalid DER ECDSA signature: missing INTEGER tag");
|
|
2230
|
+
const len = der[offset++];
|
|
2231
|
+
let val = der.slice(offset, offset + len);
|
|
2232
|
+
offset += len;
|
|
2233
|
+
let start = 0;
|
|
2234
|
+
while (start < val.length - 1 && val[start] === 0) start++;
|
|
2235
|
+
val = val.slice(start);
|
|
2236
|
+
if (val.length > coordSize) throw new Error(`Invalid DER ECDSA signature: integer (${val.length}) exceeds ${coordSize}`);
|
|
2237
|
+
const out = new Uint8Array(coordSize);
|
|
2238
|
+
out.set(val, coordSize - val.length);
|
|
2239
|
+
return out;
|
|
2240
|
+
}, "readInt");
|
|
2241
|
+
const r = readInt();
|
|
2242
|
+
const s = readInt();
|
|
2243
|
+
return concatU8([
|
|
2244
|
+
r,
|
|
2245
|
+
s
|
|
2246
|
+
]);
|
|
2247
|
+
}
|
|
2248
|
+
__name(derEcdsaToRaw, "derEcdsaToRaw");
|
|
2249
|
+
function decodeKmsSignatureToRaw(signature, coordSize) {
|
|
2250
|
+
const normalized = signature.trim().replace(/\s+/g, "").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
2251
|
+
const bytes = fromString(normalized, "base64url");
|
|
2252
|
+
if (bytes.length > coordSize * 2 && bytes[0] === 48) {
|
|
2253
|
+
return derEcdsaToRaw(bytes, coordSize);
|
|
2254
|
+
}
|
|
2255
|
+
return bytes;
|
|
2256
|
+
}
|
|
2257
|
+
__name(decodeKmsSignatureToRaw, "decodeKmsSignatureToRaw");
|
|
2258
|
+
function cborHeader(buf, off) {
|
|
2259
|
+
const ib = buf[off];
|
|
2260
|
+
const major = ib >> 5;
|
|
2261
|
+
const ai = ib & 31;
|
|
2262
|
+
if (ai < 24) return {
|
|
2263
|
+
major,
|
|
2264
|
+
headerLen: 1,
|
|
2265
|
+
argument: ai
|
|
2266
|
+
};
|
|
2267
|
+
if (ai === 24) return {
|
|
2268
|
+
major,
|
|
2269
|
+
headerLen: 2,
|
|
2270
|
+
argument: buf[off + 1]
|
|
2271
|
+
};
|
|
2272
|
+
if (ai === 25) return {
|
|
2273
|
+
major,
|
|
2274
|
+
headerLen: 3,
|
|
2275
|
+
argument: buf[off + 1] << 8 | buf[off + 2]
|
|
2276
|
+
};
|
|
2277
|
+
if (ai === 26) return {
|
|
2278
|
+
major,
|
|
2279
|
+
headerLen: 5,
|
|
2280
|
+
argument: buf[off + 1] * 16777216 + (buf[off + 2] << 16) + (buf[off + 3] << 8) + buf[off + 4]
|
|
2281
|
+
};
|
|
2282
|
+
if (ai === 27) {
|
|
2283
|
+
let v = 0;
|
|
2284
|
+
for (let i = 1; i <= 8; i++) v = v * 256 + buf[off + i];
|
|
2285
|
+
return {
|
|
2286
|
+
major,
|
|
2287
|
+
headerLen: 9,
|
|
2288
|
+
argument: v
|
|
2289
|
+
};
|
|
2290
|
+
}
|
|
2291
|
+
throw new Error(`unsupported CBOR additional-info ${ai} at offset ${off}`);
|
|
2292
|
+
}
|
|
2293
|
+
__name(cborHeader, "cborHeader");
|
|
2294
|
+
function cborItemLen(buf, off) {
|
|
2295
|
+
const h = cborHeader(buf, off);
|
|
2296
|
+
let total = h.headerLen;
|
|
2297
|
+
switch (h.major) {
|
|
2298
|
+
case 0:
|
|
2299
|
+
case 1:
|
|
2300
|
+
case 7:
|
|
2301
|
+
break;
|
|
2302
|
+
case 2:
|
|
2303
|
+
case 3:
|
|
2304
|
+
total += h.argument;
|
|
2305
|
+
break;
|
|
2306
|
+
case 4:
|
|
2307
|
+
for (let i = 0; i < h.argument; i++) total += cborItemLen(buf, off + total);
|
|
2308
|
+
break;
|
|
2309
|
+
case 5:
|
|
2310
|
+
for (let i = 0; i < h.argument * 2; i++) total += cborItemLen(buf, off + total);
|
|
2311
|
+
break;
|
|
2312
|
+
case 6:
|
|
2313
|
+
total += cborItemLen(buf, off + total);
|
|
2314
|
+
break;
|
|
2315
|
+
default:
|
|
2316
|
+
throw new Error(`unsupported CBOR major type ${h.major}`);
|
|
2317
|
+
}
|
|
2318
|
+
return total;
|
|
2319
|
+
}
|
|
2320
|
+
__name(cborItemLen, "cborItemLen");
|
|
2321
|
+
function reconstructMdocDeviceAuthSigStructure(sig) {
|
|
2322
|
+
if (sig[0] !== 132) return sig;
|
|
2323
|
+
let off = 1;
|
|
2324
|
+
off += cborItemLen(sig, off);
|
|
2325
|
+
off += cborItemLen(sig, off);
|
|
2326
|
+
off += cborItemLen(sig, off);
|
|
2327
|
+
const payloadStart = off;
|
|
2328
|
+
const ph = cborHeader(sig, payloadStart);
|
|
2329
|
+
if (ph.major !== 2) return sig;
|
|
2330
|
+
const daStart = payloadStart + ph.headerLen;
|
|
2331
|
+
const da = sig.subarray(daStart, daStart + ph.argument);
|
|
2332
|
+
if (da[0] !== 132) return sig;
|
|
2333
|
+
let d = 1;
|
|
2334
|
+
d += cborItemLen(da, d);
|
|
2335
|
+
d += cborItemLen(da, d);
|
|
2336
|
+
d += cborItemLen(da, d);
|
|
2337
|
+
const e4 = da.subarray(d, d + cborItemLen(da, d));
|
|
2338
|
+
const e4Tagged = concatU8([
|
|
2339
|
+
new Uint8Array([
|
|
2340
|
+
216,
|
|
2341
|
+
24
|
|
2342
|
+
]),
|
|
2343
|
+
encodeBstrHeader(e4.length),
|
|
2344
|
+
e4
|
|
2345
|
+
]);
|
|
2346
|
+
const daCorrected = concatU8([
|
|
2347
|
+
da.subarray(0, d),
|
|
2348
|
+
e4Tagged
|
|
2349
|
+
]);
|
|
2350
|
+
const deviceAuthBytes = concatU8([
|
|
2351
|
+
new Uint8Array([
|
|
2352
|
+
216,
|
|
2353
|
+
24
|
|
2354
|
+
]),
|
|
2355
|
+
encodeBstrHeader(daCorrected.length),
|
|
2356
|
+
daCorrected
|
|
2357
|
+
]);
|
|
2358
|
+
const newPayload = concatU8([
|
|
2359
|
+
encodeBstrHeader(deviceAuthBytes.length),
|
|
2360
|
+
deviceAuthBytes
|
|
2361
|
+
]);
|
|
2362
|
+
return concatU8([
|
|
2363
|
+
sig.subarray(0, payloadStart),
|
|
2364
|
+
newPayload
|
|
2365
|
+
]);
|
|
2366
|
+
}
|
|
2367
|
+
__name(reconstructMdocDeviceAuthSigStructure, "reconstructMdocDeviceAuthSigStructure");
|
|
2068
2368
|
var CoseCryptoService = class {
|
|
2069
2369
|
static {
|
|
2070
2370
|
__name(this, "CoseCryptoService");
|
|
@@ -2081,7 +2381,21 @@ var CoseCryptoService = class {
|
|
|
2081
2381
|
throw Error("No context provided. Please provide a context with the setContext method or constructor");
|
|
2082
2382
|
}
|
|
2083
2383
|
const { keyInfo, alg, value } = input;
|
|
2384
|
+
let toBeSigned = toU8(value);
|
|
2385
|
+
try {
|
|
2386
|
+
toBeSigned = reconstructMdocDeviceAuthSigStructure(toBeSigned);
|
|
2387
|
+
} catch (e) {
|
|
2388
|
+
console.log(`(mdl-mdoc:sign) Sig_structure tag-24 reconstruction failed, signing kmp original: ${e?.message}`);
|
|
2389
|
+
}
|
|
2390
|
+
try {
|
|
2391
|
+
let hex = "";
|
|
2392
|
+
for (let i = 0; i < toBeSigned.length; i++) hex += (toBeSigned[i] & 255).toString(16).padStart(2, "0");
|
|
2393
|
+
console.log(`(mdl-mdoc:sign) ToBeSigned len=${toBeSigned.length} hex=${hex}`);
|
|
2394
|
+
} catch (e) {
|
|
2395
|
+
console.log(`(mdl-mdoc:sign) ToBeSigned hex failed: ${e?.message}`);
|
|
2396
|
+
}
|
|
2084
2397
|
let kmsKeyRef = keyInfo.kmsKeyRef ?? void 0;
|
|
2398
|
+
const fallbackKeyRefs = [];
|
|
2085
2399
|
if (!kmsKeyRef) {
|
|
2086
2400
|
const key = keyInfo.key;
|
|
2087
2401
|
if (key == null) {
|
|
@@ -2089,21 +2403,49 @@ var CoseCryptoService = class {
|
|
|
2089
2403
|
}
|
|
2090
2404
|
const resolvedKeyInfo = com.sphereon.crypto.ResolvedKeyInfo.Static.fromKeyInfo(keyInfo, key);
|
|
2091
2405
|
const jwkKeyInfo = CoseJoseKeyMappingService.toResolvedJwkKeyInfo(resolvedKeyInfo);
|
|
2092
|
-
const
|
|
2406
|
+
const thumbprint = calculateJwkThumbprint({
|
|
2093
2407
|
jwk: jwkKeyInfo.key.toJsonDTO()
|
|
2094
|
-
})
|
|
2408
|
+
});
|
|
2409
|
+
const kid = jwkKeyInfo.kid ?? thumbprint ?? jwkKeyInfo.key.getKidAsString(true);
|
|
2095
2410
|
if (!kid) {
|
|
2096
2411
|
return Promise.reject(Error("No kid present and not kmsKeyRef provided"));
|
|
2097
2412
|
}
|
|
2098
2413
|
kmsKeyRef = kid;
|
|
2414
|
+
if (thumbprint && thumbprint !== kid) {
|
|
2415
|
+
fallbackKeyRefs.push(thumbprint);
|
|
2416
|
+
}
|
|
2099
2417
|
}
|
|
2100
|
-
const
|
|
2418
|
+
const doSign = /* @__PURE__ */ __name((keyRef) => this.context.agent.keyManagerSign({
|
|
2101
2419
|
algorithm: alg.jose.value,
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2420
|
+
// Pass the raw ToBeSigned (COSE Sig_structure) bytes as base64. The previous `encodeTo(value, UTF8)`
|
|
2421
|
+
// interpreted the binary CBOR as UTF-8 text, corrupting every non-ASCII byte before the KMS even saw it
|
|
2422
|
+
// (the MUSAP bridge then signed the mangled bytes -> verifier "Signature invalid"). base64 round-trips losslessly.
|
|
2423
|
+
data: u8aToString(toBeSigned, "base64"),
|
|
2424
|
+
encoding: "base64",
|
|
2425
|
+
keyRef
|
|
2426
|
+
}), "doSign");
|
|
2427
|
+
let result;
|
|
2428
|
+
try {
|
|
2429
|
+
result = await doSign(kmsKeyRef);
|
|
2430
|
+
} catch (error) {
|
|
2431
|
+
let signed;
|
|
2432
|
+
for (const ref of fallbackKeyRefs) {
|
|
2433
|
+
try {
|
|
2434
|
+
signed = await doSign(ref);
|
|
2435
|
+
break;
|
|
2436
|
+
} catch {
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
2439
|
+
if (signed === void 0) {
|
|
2440
|
+
throw error;
|
|
2441
|
+
}
|
|
2442
|
+
result = signed;
|
|
2443
|
+
}
|
|
2444
|
+
const joseAlg = alg.jose?.value;
|
|
2445
|
+
const coordSize = joseAlg === "ES512" ? 66 : joseAlg === "ES384" ? 48 : 32;
|
|
2446
|
+
const raw = decodeKmsSignatureToRaw(result, coordSize);
|
|
2447
|
+
console.log(`(mdl-mdoc:sign) signature decoded: alg=${joseAlg}, inputChars=${result.length}, rawLen=${raw.length} (expected ${coordSize * 2})`);
|
|
2448
|
+
return Int8Array.from(raw);
|
|
2107
2449
|
}
|
|
2108
2450
|
async verify1Async(input, keyInfo, requireX5Chain) {
|
|
2109
2451
|
const getCertAndKey = /* @__PURE__ */ __name(async (x5c2) => {
|
|
@@ -2153,9 +2495,22 @@ var CoseCryptoService = class {
|
|
|
2153
2495
|
const issuerCoseKeyInfo = new KeyInfo(kid, issuerCoseKey, coseKeyInfo.opts, coseKeyInfo.keyVisibility, issuerCoseKey.getSignatureAlgorithm() ?? coseKeyInfo.signatureAlgorithm, x5c, coseKeyInfo.kmsKeyRef, coseKeyInfo.kms, coseKeyInfo.keyType ?? issuerCoseKey.getKty());
|
|
2154
2496
|
const recalculatedToBeSigned = input.toBeSignedJson(issuerCoseKeyInfo, SignatureAlgorithm.Static.fromCose(coseAlg));
|
|
2155
2497
|
const key = CoseJoseKeyMappingService.toJoseJwk(issuerCoseKeyInfo.key).toJsonDTO();
|
|
2498
|
+
let data = fromString(recalculatedToBeSigned.base64UrlValue, "base64url");
|
|
2499
|
+
const signatureBytes = fromString(sign1Json.signature, "base64url");
|
|
2500
|
+
const rawMdocBytes = globalThis.__sphereon_mdoc_raw_bytes;
|
|
2501
|
+
if (rawMdocBytes) {
|
|
2502
|
+
try {
|
|
2503
|
+
const extracted = extractIssuerAuthRawParts(rawMdocBytes);
|
|
2504
|
+
if (extracted) {
|
|
2505
|
+
data = buildSig1Structure(extracted.protectedBytes, extracted.payloadBytes);
|
|
2506
|
+
}
|
|
2507
|
+
} catch (e) {
|
|
2508
|
+
console.warn("[mdl-mdoc verify] failed to reparse raw mdoc; falling back to kmp-computed Sig_structure:", e.message);
|
|
2509
|
+
}
|
|
2510
|
+
}
|
|
2156
2511
|
const valid = await verifyRawSignature({
|
|
2157
|
-
data
|
|
2158
|
-
signature:
|
|
2512
|
+
data,
|
|
2513
|
+
signature: signatureBytes,
|
|
2159
2514
|
key
|
|
2160
2515
|
});
|
|
2161
2516
|
return {
|
|
@@ -2276,9 +2631,9 @@ var CoseCryptoServiceJS = com2.sphereon.crypto.CoseCryptoServiceJS;
|
|
|
2276
2631
|
var CoseJoseKeyMappingService2 = com2.sphereon.crypto.CoseJoseKeyMappingService;
|
|
2277
2632
|
var KeyInfo2 = com2.sphereon.crypto.KeyInfo;
|
|
2278
2633
|
var DateTimeUtils2 = com2.sphereon.kmp.DateTimeUtils;
|
|
2279
|
-
var
|
|
2280
|
-
var
|
|
2281
|
-
var
|
|
2634
|
+
var decodeFrom = com2.sphereon.kmp.decodeFrom;
|
|
2635
|
+
var encodeTo = com2.sphereon.kmp.encodeTo;
|
|
2636
|
+
var Encoding = com2.sphereon.kmp.Encoding;
|
|
2282
2637
|
var MdocValidations = com2.sphereon.mdoc.data.MdocValidations;
|
|
2283
2638
|
var MdocOid4vpService = com2.sphereon.mdoc.oid4vp.MdocOid4vpServiceJs;
|
|
2284
2639
|
var Jwk = com2.sphereon.crypto.jose.Jwk;
|
|
@@ -2305,14 +2660,31 @@ var MDLMdoc = class {
|
|
|
2305
2660
|
mdocOid4vpHolderPresent: this.mdocOid4vpHolderPresent.bind(this),
|
|
2306
2661
|
mdocOid4vpRPVerify: this.mdocOid4vpRPVerify.bind(this)
|
|
2307
2662
|
};
|
|
2308
|
-
|
|
2663
|
+
staticTrustAnchors;
|
|
2664
|
+
trustAnchorProvider;
|
|
2665
|
+
blindlyTrustedAnchorProvider;
|
|
2309
2666
|
opts;
|
|
2310
2667
|
constructor(args) {
|
|
2311
|
-
this.
|
|
2668
|
+
this.staticTrustAnchors = args?.trustAnchors ?? [];
|
|
2669
|
+
this.trustAnchorProvider = args?.trustAnchorProvider;
|
|
2670
|
+
this.blindlyTrustedAnchorProvider = args?.blindlyTrustedAnchorProvider;
|
|
2312
2671
|
this.opts = args?.opts ?? {
|
|
2313
2672
|
trustRootWhenNoAnchors: true
|
|
2314
2673
|
};
|
|
2315
2674
|
}
|
|
2675
|
+
// Live-merged anchors: static (constructor) + provider (runtime/user). Read on every verification.
|
|
2676
|
+
get trustAnchors() {
|
|
2677
|
+
return [
|
|
2678
|
+
...this.staticTrustAnchors,
|
|
2679
|
+
...this.trustAnchorProvider?.() ?? []
|
|
2680
|
+
];
|
|
2681
|
+
}
|
|
2682
|
+
get effectiveBlindlyTrustedAnchors() {
|
|
2683
|
+
return [
|
|
2684
|
+
...this.opts.blindlyTrustedAnchors ?? [],
|
|
2685
|
+
...this.blindlyTrustedAnchorProvider?.() ?? []
|
|
2686
|
+
];
|
|
2687
|
+
}
|
|
2316
2688
|
/**
|
|
2317
2689
|
* Processes and verifies the provided mdoc, generates device response and presentation submission tokens.
|
|
2318
2690
|
*
|
|
@@ -2353,22 +2725,36 @@ var MDLMdoc = class {
|
|
|
2353
2725
|
const result = await validate(match.document);
|
|
2354
2726
|
if (!result.error || responseUri.includes("openid.net")) {
|
|
2355
2727
|
try {
|
|
2356
|
-
const
|
|
2728
|
+
const matchDeviceKeyInfo = match.deviceKeyInfo;
|
|
2729
|
+
const deviceKeyInfoSource = matchDeviceKeyInfo ?? result.keyInfo;
|
|
2730
|
+
console.log(`(mdl-mdoc:deviceKey) amend: match.deviceKeyInfo present=${!!matchDeviceKeyInfo}, match.deviceKeyInfo.key present=${!!matchDeviceKeyInfo?.key}, result.keyInfo present=${!!result.keyInfo}, result.keyInfo.key present=${!!result.keyInfo?.key}, source=${matchDeviceKeyInfo ? "match.deviceKeyInfo" : "result.keyInfo"}`);
|
|
2731
|
+
const cborKey = deviceKeyInfoSource?.key ? CoseKeyCbor.Static.fromDTO(deviceKeyInfoSource.key) : void 0;
|
|
2357
2732
|
if (!cborKey) {
|
|
2358
|
-
throw Error("No key found
|
|
2733
|
+
throw Error("No device (public) key found to amend: neither match.deviceKeyInfo.key nor result.keyInfo.key is populated. The mdoc MSO device public key is required to resolve the hardware-backed KMS key for signing.");
|
|
2359
2734
|
}
|
|
2360
2735
|
let jwk = CoseJoseKeyMappingService2.toJoseJwk(cborKey).toJsonDTO();
|
|
2361
|
-
if (!
|
|
2362
|
-
const keyInfo =
|
|
2363
|
-
const
|
|
2736
|
+
if (!deviceKeyInfoSource?.kmsKeyRef) {
|
|
2737
|
+
const keyInfo = deviceKeyInfoSource;
|
|
2738
|
+
const thumbprint = calculateJwkThumbprint2({
|
|
2364
2739
|
jwk
|
|
2365
2740
|
});
|
|
2366
|
-
const
|
|
2367
|
-
|
|
2368
|
-
|
|
2741
|
+
const kid = jwk.kid ?? thumbprint;
|
|
2742
|
+
console.log(`(mdl-mdoc:deviceKey) amend: resolved device public jwk kid=${jwk.kid}, thumbprint=${thumbprint}`);
|
|
2743
|
+
let key;
|
|
2744
|
+
try {
|
|
2745
|
+
key = await _context.agent.keyManagerGet({
|
|
2746
|
+
kid
|
|
2747
|
+
});
|
|
2748
|
+
} catch (e) {
|
|
2749
|
+
console.log(`(mdl-mdoc:deviceKey) amend: keyManagerGet by kid '${kid}' failed (${e?.message}); retrying by thumbprint '${thumbprint}'`);
|
|
2750
|
+
key = await _context.agent.keyManagerGet({
|
|
2751
|
+
kid: thumbprint
|
|
2752
|
+
});
|
|
2753
|
+
}
|
|
2369
2754
|
const kms = key.kms;
|
|
2370
|
-
const kmsKeyRef = key.meta?.kmsKeyRef;
|
|
2371
|
-
|
|
2755
|
+
const kmsKeyRef = key.meta?.kmsKeyRef ?? key.kid;
|
|
2756
|
+
console.log(`(mdl-mdoc:deviceKey) amend: resolved hardware KMS key kms=${kms}, kmsKeyRef=${kmsKeyRef}`);
|
|
2757
|
+
const updateCborKey = cborKey.copy(false, cborKey.kty, cborKey.kid ?? new CborByteString(decodeFrom(kid, Encoding.UTF8)));
|
|
2372
2758
|
const deviceKeyInfo = KeyInfo2.Static.fromDTO(keyInfo).copy(kid, updateCborKey, keyInfo.opts, keyInfo.keyVisibility, keyInfo.signatureAlgorithm, keyInfo.x5c, kmsKeyRef, kms);
|
|
2373
2759
|
const updateMatch = match.copy(match.inputDescriptor, match.document, match.documentError, deviceKeyInfo);
|
|
2374
2760
|
match = updateMatch;
|
|
@@ -2388,9 +2774,74 @@ var MDLMdoc = class {
|
|
|
2388
2774
|
}
|
|
2389
2775
|
return Promise.reject(Error("No matching documents found"));
|
|
2390
2776
|
}
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2777
|
+
try {
|
|
2778
|
+
console.log(`(mdl-mdoc:deviceResponse) args: clientId=${clientId}, responseUri=${responseUri}, authorizationRequestNonce=${authorizationRequestNonce}, docCount=${docsAndDescriptors.length}`);
|
|
2779
|
+
try {
|
|
2780
|
+
console.log(`(mdl-mdoc:deviceResponse) presentationDefinition=${JSON.stringify(presentationDefinition)}`);
|
|
2781
|
+
} catch (e) {
|
|
2782
|
+
console.log(`(mdl-mdoc:deviceResponse) presentationDefinition stringify failed: ${e?.message}`);
|
|
2783
|
+
}
|
|
2784
|
+
docsAndDescriptors.forEach((d, idx) => {
|
|
2785
|
+
const dk = d?.deviceKeyInfo;
|
|
2786
|
+
let docType = void 0;
|
|
2787
|
+
try {
|
|
2788
|
+
docType = d?.document?.docType?.value ?? d?.document?.MSO?.value?.docType?.value ?? d?.document?.getDocType?.();
|
|
2789
|
+
} catch {
|
|
2790
|
+
}
|
|
2791
|
+
console.log(`(mdl-mdoc:deviceResponse) doc[${idx}]: inputDescriptor.id=${d?.inputDescriptor?.id?.value ?? d?.inputDescriptor?.id}, docType=${docType}, document present=${!!d?.document}, documentError present=${!!d?.documentError}, deviceKeyInfo present=${!!dk}, deviceKeyInfo.key present=${!!dk?.key}, deviceKeyInfo.kid=${dk?.kid}, kmsKeyRef=${dk?.kmsKeyRef}, kms=${dk?.kms}, signatureAlgorithm=${dk?.signatureAlgorithm}, x5c present=${!!dk?.x5c}`);
|
|
2792
|
+
try {
|
|
2793
|
+
const dkJson = dk?.toJson ? dk.toJson() : dk;
|
|
2794
|
+
console.log(`(mdl-mdoc:deviceResponse) doc[${idx}] deviceKeyInfo=${JSON.stringify(dkJson)}`);
|
|
2795
|
+
} catch (e) {
|
|
2796
|
+
console.log(`(mdl-mdoc:deviceResponse) doc[${idx}] deviceKeyInfo serialize failed: ${e?.message}`);
|
|
2797
|
+
}
|
|
2798
|
+
try {
|
|
2799
|
+
const keyJson = dk?.key?.toJson ? dk.key.toJson() : dk?.key;
|
|
2800
|
+
console.log(`(mdl-mdoc:deviceResponse) doc[${idx}] deviceKeyInfo.key=${JSON.stringify(keyJson)}`);
|
|
2801
|
+
} catch (e) {
|
|
2802
|
+
console.log(`(mdl-mdoc:deviceResponse) doc[${idx}] deviceKeyInfo.key serialize failed: ${e?.message}`);
|
|
2803
|
+
}
|
|
2804
|
+
});
|
|
2805
|
+
} catch (e) {
|
|
2806
|
+
console.log(`(mdl-mdoc:deviceResponse) argument logging failed: ${e?.message}`);
|
|
2807
|
+
}
|
|
2808
|
+
let deviceResponse;
|
|
2809
|
+
try {
|
|
2810
|
+
deviceResponse = await oid4vpService.createDeviceResponse(docsAndDescriptors, presentationDefinition, clientId, responseUri, authorizationRequestNonce);
|
|
2811
|
+
} catch (e) {
|
|
2812
|
+
console.log(`(mdl-mdoc:deviceResponse) createDeviceResponse failed: ${e?.message}`);
|
|
2813
|
+
console.log(`(mdl-mdoc:deviceResponse) STACK: ${e?.stack}`);
|
|
2814
|
+
throw e;
|
|
2815
|
+
}
|
|
2816
|
+
try {
|
|
2817
|
+
console.log(`(mdl-mdoc:deviceResponse) createDeviceResponse returned: present=${!!deviceResponse}, type=${typeof deviceResponse}`);
|
|
2818
|
+
const dr = deviceResponse;
|
|
2819
|
+
try {
|
|
2820
|
+
const docs = dr?.documents ?? dr?.b3p_1 ?? void 0;
|
|
2821
|
+
console.log(`(mdl-mdoc:deviceResponse) deviceResponse.version present=${!!dr?.version}, status present=${dr?.status != null}, documents present=${!!docs}, documentsCount=${docs?.length ?? docs?.size ?? "n/a"}`);
|
|
2822
|
+
} catch (e) {
|
|
2823
|
+
console.log(`(mdl-mdoc:deviceResponse) deviceResponse structure probe failed: ${e?.message}`);
|
|
2824
|
+
}
|
|
2825
|
+
} catch {
|
|
2826
|
+
}
|
|
2827
|
+
let vp_token;
|
|
2828
|
+
try {
|
|
2829
|
+
const encoded = deviceResponse.cborEncode();
|
|
2830
|
+
console.log(`(mdl-mdoc:deviceResponse) cborEncode OK, byteLen=${encoded?.length}`);
|
|
2831
|
+
vp_token = encodeTo(encoded, Encoding.BASE64URL);
|
|
2832
|
+
} catch (e) {
|
|
2833
|
+
console.log(`(mdl-mdoc:deviceResponse) cborEncode failed: ${e?.message}`);
|
|
2834
|
+
console.log(`(mdl-mdoc:deviceResponse) cborEncode STACK: ${e?.stack}`);
|
|
2835
|
+
throw e;
|
|
2836
|
+
}
|
|
2837
|
+
let presentation_submission;
|
|
2838
|
+
try {
|
|
2839
|
+
presentation_submission = Oid4VPPresentationSubmission.Static.fromPresentationDefinition(presentationDefinition);
|
|
2840
|
+
} catch (e) {
|
|
2841
|
+
console.log(`(mdl-mdoc:deviceResponse) fromPresentationDefinition failed: ${e?.message}`);
|
|
2842
|
+
console.log(`(mdl-mdoc:deviceResponse) fromPresentationDefinition STACK: ${e?.stack}`);
|
|
2843
|
+
throw e;
|
|
2844
|
+
}
|
|
2394
2845
|
return {
|
|
2395
2846
|
vp_token,
|
|
2396
2847
|
presentation_submission
|
|
@@ -2406,7 +2857,7 @@ var MDLMdoc = class {
|
|
|
2406
2857
|
*/
|
|
2407
2858
|
async mdocOid4vpRPVerify(args, _context) {
|
|
2408
2859
|
const { vp_token, presentation_submission, trustAnchors } = args;
|
|
2409
|
-
const deviceResponse = com3.sphereon.mdoc.data.device.DeviceResponseCbor.Static.cborDecode(
|
|
2860
|
+
const deviceResponse = com3.sphereon.mdoc.data.device.DeviceResponseCbor.Static.cborDecode(decodeFrom(vp_token, Encoding.BASE64URL));
|
|
2410
2861
|
if (!deviceResponse.documents) {
|
|
2411
2862
|
return Promise.reject(Error(`No documents found in vp_token`));
|
|
2412
2863
|
}
|
|
@@ -2492,7 +2943,8 @@ var MDLMdoc = class {
|
|
|
2492
2943
|
trustAnchors: Array.from(trustAnchors),
|
|
2493
2944
|
opts: {
|
|
2494
2945
|
...args?.opts,
|
|
2495
|
-
...this.opts
|
|
2946
|
+
...this.opts,
|
|
2947
|
+
blindlyTrustedAnchors: this.effectiveBlindlyTrustedAnchors
|
|
2496
2948
|
}
|
|
2497
2949
|
});
|
|
2498
2950
|
console.log(`x509 validation for ${validationResult.error ? "Error" : "Success"}. message: ${validationResult.message}, details: ${validationResult.detailMessage}`);
|
|
@@ -2526,7 +2978,7 @@ export {
|
|
|
2526
2978
|
CoseJoseKeyMappingService2 as CoseJoseKeyMappingService,
|
|
2527
2979
|
CoseKeyCbor,
|
|
2528
2980
|
DateTimeUtils2 as DateTimeUtils,
|
|
2529
|
-
|
|
2981
|
+
Encoding,
|
|
2530
2982
|
Jwk,
|
|
2531
2983
|
KeyInfo2 as KeyInfo,
|
|
2532
2984
|
MDLMdoc,
|
|
@@ -2534,8 +2986,8 @@ export {
|
|
|
2534
2986
|
MdocValidations,
|
|
2535
2987
|
Oid4VPPresentationSubmission,
|
|
2536
2988
|
X509CallbackService,
|
|
2537
|
-
|
|
2538
|
-
|
|
2989
|
+
decodeFrom,
|
|
2990
|
+
encodeTo,
|
|
2539
2991
|
logger,
|
|
2540
2992
|
mdocSupportMethods,
|
|
2541
2993
|
schema
|