pptx-viewer-core 1.2.4 → 1.2.6
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/CHANGELOG.md +8 -0
- package/dist/{SvgExporter-CYyO9c5A.d.mts → SvgExporter-BKbDaGaC.d.mts} +1 -1
- package/dist/{SvgExporter-DdjrIx33.d.ts → SvgExporter-CG73UVb9.d.ts} +1 -1
- package/dist/cli/index.d.mts +2 -2
- package/dist/cli/index.d.ts +2 -2
- package/dist/cli/index.js +0 -0
- package/dist/cli/index.mjs +0 -0
- package/dist/converter/index.d.mts +3 -3
- package/dist/converter/index.d.ts +3 -3
- package/dist/converter/index.js +0 -0
- package/dist/converter/index.mjs +0 -0
- package/dist/index.d.mts +126 -7
- package/dist/index.d.ts +126 -7
- package/dist/index.js +403 -56
- package/dist/index.mjs +402 -57
- package/dist/{presentation-BRAUjTRt.d.mts → presentation-CLc4eS3z.d.mts} +10 -0
- package/dist/{presentation-BRAUjTRt.d.ts → presentation-CLc4eS3z.d.ts} +10 -0
- package/dist/signature-node/index.d.mts +17 -7
- package/dist/signature-node/index.d.ts +17 -7
- package/dist/signature-node/index.js +297 -209
- package/dist/signature-node/index.mjs +295 -207
- package/dist/{text-operations-CkW4BO91.d.mts → text-operations-CCKEVX_5.d.mts} +1 -1
- package/dist/{text-operations-BJUOhA1w.d.ts → text-operations-oN04X1yi.d.ts} +1 -1
- package/package.json +1 -1
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
var xmldom = require('@xmldom/xmldom');
|
|
4
4
|
var xmlCrypto = require('xml-crypto');
|
|
5
|
-
var
|
|
5
|
+
var crypto2 = require('crypto');
|
|
6
6
|
var path = require('path');
|
|
7
7
|
var tls = require('tls');
|
|
8
|
-
var
|
|
8
|
+
var forge3 = require('node-forge');
|
|
9
9
|
var http = require('http');
|
|
10
10
|
var https = require('https');
|
|
11
11
|
var fs = require('fs/promises');
|
|
@@ -13,10 +13,10 @@ var JSZip = require('jszip');
|
|
|
13
13
|
|
|
14
14
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
15
15
|
|
|
16
|
-
var
|
|
16
|
+
var crypto2__default = /*#__PURE__*/_interopDefault(crypto2);
|
|
17
17
|
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
18
18
|
var tls__default = /*#__PURE__*/_interopDefault(tls);
|
|
19
|
-
var
|
|
19
|
+
var forge3__default = /*#__PURE__*/_interopDefault(forge3);
|
|
20
20
|
var http__default = /*#__PURE__*/_interopDefault(http);
|
|
21
21
|
var https__default = /*#__PURE__*/_interopDefault(https);
|
|
22
22
|
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
@@ -219,6 +219,89 @@ function canonicalizeSignedInfoXml(signedInfoXml) {
|
|
|
219
219
|
}
|
|
220
220
|
return canonicalizeNode(signedInfoDoc.documentElement, "http://www.w3.org/2001/10/xml-exc-c14n#");
|
|
221
221
|
}
|
|
222
|
+
|
|
223
|
+
// src/signature-node/pem-utils.ts
|
|
224
|
+
function firstPemBlockForLabel(text, label) {
|
|
225
|
+
const begin = `-----BEGIN ${label}-----`;
|
|
226
|
+
const end = `-----END ${label}-----`;
|
|
227
|
+
const beginIndex = text.indexOf(begin);
|
|
228
|
+
if (beginIndex === -1) {
|
|
229
|
+
return void 0;
|
|
230
|
+
}
|
|
231
|
+
const endIndex = text.indexOf(end, beginIndex + begin.length);
|
|
232
|
+
if (endIndex === -1) {
|
|
233
|
+
return void 0;
|
|
234
|
+
}
|
|
235
|
+
return { index: beginIndex, block: text.slice(beginIndex, endIndex + end.length) };
|
|
236
|
+
}
|
|
237
|
+
function extractPemBlocks(text, label) {
|
|
238
|
+
const begin = `-----BEGIN ${label}-----`;
|
|
239
|
+
const end = `-----END ${label}-----`;
|
|
240
|
+
const blocks = [];
|
|
241
|
+
let searchFrom = 0;
|
|
242
|
+
for (; ; ) {
|
|
243
|
+
const beginIndex = text.indexOf(begin, searchFrom);
|
|
244
|
+
if (beginIndex === -1) {
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
const contentStart = beginIndex + begin.length;
|
|
248
|
+
const endIndex = text.indexOf(end, contentStart);
|
|
249
|
+
if (endIndex === -1) {
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
blocks.push(text.slice(beginIndex, endIndex + end.length));
|
|
253
|
+
searchFrom = endIndex + end.length;
|
|
254
|
+
}
|
|
255
|
+
return blocks;
|
|
256
|
+
}
|
|
257
|
+
function extractFirstPemBlock(text, labels) {
|
|
258
|
+
let best;
|
|
259
|
+
for (const label of labels) {
|
|
260
|
+
const found = firstPemBlockForLabel(text, label);
|
|
261
|
+
if (found && (!best || found.index < best.index)) {
|
|
262
|
+
best = found;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return best?.block;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// src/signature-node/timestamp-tag-scanner.ts
|
|
269
|
+
var MAX_TAG_WINDOW = 256;
|
|
270
|
+
var OPEN_TAG_PATTERN = /^<(?:[\w.-]+:)?(?:EncapsulatedTimeStamp|SignatureTimeStamp)\b[^>]*>/i;
|
|
271
|
+
var CLOSE_TAG_PATTERN = /^<\/(?:[\w.-]+:)?(?:EncapsulatedTimeStamp|SignatureTimeStamp)>/i;
|
|
272
|
+
function findCloseTagIndex(xml, fromIndex) {
|
|
273
|
+
let searchFrom = fromIndex;
|
|
274
|
+
for (; ; ) {
|
|
275
|
+
const ltIndex = xml.indexOf("<", searchFrom);
|
|
276
|
+
if (ltIndex === -1) {
|
|
277
|
+
return void 0;
|
|
278
|
+
}
|
|
279
|
+
const window = xml.slice(ltIndex, ltIndex + MAX_TAG_WINDOW);
|
|
280
|
+
if (CLOSE_TAG_PATTERN.test(window)) {
|
|
281
|
+
return ltIndex;
|
|
282
|
+
}
|
|
283
|
+
searchFrom = ltIndex + 1;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
function findTimestampTagContent(xml) {
|
|
287
|
+
let searchFrom = 0;
|
|
288
|
+
for (; ; ) {
|
|
289
|
+
const ltIndex = xml.indexOf("<", searchFrom);
|
|
290
|
+
if (ltIndex === -1) {
|
|
291
|
+
return void 0;
|
|
292
|
+
}
|
|
293
|
+
const window = xml.slice(ltIndex, ltIndex + MAX_TAG_WINDOW);
|
|
294
|
+
const openMatch = OPEN_TAG_PATTERN.exec(window);
|
|
295
|
+
if (openMatch) {
|
|
296
|
+
const contentStart = ltIndex + openMatch[0].length;
|
|
297
|
+
const closeIndex = findCloseTagIndex(xml, contentStart);
|
|
298
|
+
return closeIndex === void 0 ? void 0 : xml.slice(contentStart, closeIndex);
|
|
299
|
+
}
|
|
300
|
+
searchFrom = ltIndex + 1;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// src/signature-node/pki-validation.ts
|
|
222
305
|
function certPemFromBase64(certBase64) {
|
|
223
306
|
try {
|
|
224
307
|
const der = Buffer.from(certBase64, "base64");
|
|
@@ -239,7 +322,7 @@ ${lines.join("\n")}
|
|
|
239
322
|
}
|
|
240
323
|
function certFingerprintSha256(certPem) {
|
|
241
324
|
try {
|
|
242
|
-
const cert = new
|
|
325
|
+
const cert = new crypto2__default.default.X509Certificate(certPem);
|
|
243
326
|
return cert.fingerprint256.replace(/:/g, "").toLowerCase();
|
|
244
327
|
} catch {
|
|
245
328
|
return void 0;
|
|
@@ -248,12 +331,173 @@ function certFingerprintSha256(certPem) {
|
|
|
248
331
|
function asn1Child(node, index) {
|
|
249
332
|
return Array.isArray(node.value) ? node.value[index] : void 0;
|
|
250
333
|
}
|
|
334
|
+
async function evaluateTimestampAuthority(signatureXml) {
|
|
335
|
+
try {
|
|
336
|
+
const content = findTimestampTagContent(signatureXml);
|
|
337
|
+
if (!content?.trim()) {
|
|
338
|
+
return { status: "not-present" };
|
|
339
|
+
}
|
|
340
|
+
const tokenBase64 = content.replace(/\s+/g, "");
|
|
341
|
+
const tokenDer = Buffer.from(tokenBase64, "base64");
|
|
342
|
+
if (tokenDer.length === 0) {
|
|
343
|
+
return { status: "invalid", error: "Empty timestamp token." };
|
|
344
|
+
}
|
|
345
|
+
const asn1 = forge3__default.default.asn1.fromDer(forge3__default.default.util.createBuffer(tokenDer.toString("binary")));
|
|
346
|
+
const contentType = asn1Child(asn1, 0);
|
|
347
|
+
if (!contentType) {
|
|
348
|
+
return {
|
|
349
|
+
status: "invalid",
|
|
350
|
+
error: "Malformed timestamp token structure."
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
return { status: "valid" };
|
|
354
|
+
} catch (err) {
|
|
355
|
+
return {
|
|
356
|
+
status: "error",
|
|
357
|
+
error: `Timestamp evaluation failed: ${String(err)}`
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// src/signature-node/certificate-utils.ts
|
|
363
|
+
var PRIVATE_KEY_PEM_LABELS = [
|
|
364
|
+
"RSA PRIVATE KEY",
|
|
365
|
+
"EC PRIVATE KEY",
|
|
366
|
+
"ENCRYPTED PRIVATE KEY",
|
|
367
|
+
"PRIVATE KEY"
|
|
368
|
+
];
|
|
369
|
+
function certificateInfoFromBase64(certBase64) {
|
|
370
|
+
try {
|
|
371
|
+
const certificate = new crypto2__default.default.X509Certificate(Buffer.from(certBase64, "base64"));
|
|
372
|
+
return {
|
|
373
|
+
subject: certificate.subject || void 0,
|
|
374
|
+
issuer: certificate.issuer || void 0,
|
|
375
|
+
serialNumber: certificate.serialNumber || void 0,
|
|
376
|
+
validFrom: certificate.validFrom || void 0,
|
|
377
|
+
validTo: certificate.validTo || void 0
|
|
378
|
+
};
|
|
379
|
+
} catch {
|
|
380
|
+
return void 0;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
function validateCertificateChain(certBase64List, additionalRootsPem) {
|
|
384
|
+
if (certBase64List.length === 0) {
|
|
385
|
+
return { status: "not-checked" };
|
|
386
|
+
}
|
|
387
|
+
try {
|
|
388
|
+
const chain = certBase64List.map((value) => {
|
|
389
|
+
const der = forge3__default.default.util.decode64(value);
|
|
390
|
+
return forge3__default.default.pki.certificateFromAsn1(forge3__default.default.asn1.fromDer(der));
|
|
391
|
+
});
|
|
392
|
+
const rootPem = [...tls__default.default.rootCertificates, ...additionalRootsPem];
|
|
393
|
+
const caStore = forge3__default.default.pki.createCaStore(rootPem);
|
|
394
|
+
const verified = forge3__default.default.pki.verifyCertificateChain(caStore, chain);
|
|
395
|
+
return verified ? { status: "trusted" } : {
|
|
396
|
+
status: "untrusted",
|
|
397
|
+
error: "Certificate chain is not trusted."
|
|
398
|
+
};
|
|
399
|
+
} catch (error) {
|
|
400
|
+
return {
|
|
401
|
+
status: "untrusted",
|
|
402
|
+
error: `Certificate trust validation failed: ${String(error)}`
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
function signatureAlgorithmToVerifyAlgorithm(signatureMethod) {
|
|
407
|
+
switch (signatureMethod) {
|
|
408
|
+
case "http://www.w3.org/2000/09/xmldsig#rsa-sha1":
|
|
409
|
+
return "RSA-SHA1";
|
|
410
|
+
case "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256":
|
|
411
|
+
return "RSA-SHA256";
|
|
412
|
+
case "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384":
|
|
413
|
+
return "RSA-SHA384";
|
|
414
|
+
case "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512":
|
|
415
|
+
return "RSA-SHA512";
|
|
416
|
+
default:
|
|
417
|
+
return void 0;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
function verifySignatureValue(signatureXml, certBase64List) {
|
|
421
|
+
try {
|
|
422
|
+
const parser = new xmldom.DOMParser();
|
|
423
|
+
const doc = parser.parseFromString(signatureXml, "text/xml");
|
|
424
|
+
const signatureNode = doc.getElementsByTagNameNS(XMLDSIG_NS, "Signature")[0];
|
|
425
|
+
if (!signatureNode) {
|
|
426
|
+
return "not-checked";
|
|
427
|
+
}
|
|
428
|
+
const certPem = certBase64List.length > 0 ? certPemFromBase64(certBase64List[0]) : void 0;
|
|
429
|
+
if (!certPem) {
|
|
430
|
+
return "not-checked";
|
|
431
|
+
}
|
|
432
|
+
const signedInfoNode = doc.getElementsByTagNameNS(XMLDSIG_NS, "SignedInfo")[0];
|
|
433
|
+
const signatureValueNode = doc.getElementsByTagNameNS(XMLDSIG_NS, "SignatureValue")[0];
|
|
434
|
+
if (!signedInfoNode || !signatureValueNode) {
|
|
435
|
+
return "invalid";
|
|
436
|
+
}
|
|
437
|
+
const canonicalizationMethod = doc.getElementsByTagNameNS(XMLDSIG_NS, "CanonicalizationMethod").item(0)?.getAttribute("Algorithm") ?? "http://www.w3.org/2001/10/xml-exc-c14n#";
|
|
438
|
+
const signatureMethod = doc.getElementsByTagNameNS(XMLDSIG_NS, "SignatureMethod").item(0)?.getAttribute("Algorithm");
|
|
439
|
+
const verifyAlgorithm = signatureAlgorithmToVerifyAlgorithm(signatureMethod ?? void 0);
|
|
440
|
+
if (!verifyAlgorithm) {
|
|
441
|
+
return "invalid";
|
|
442
|
+
}
|
|
443
|
+
const canonicalSignedInfo = canonicalizeNode(signedInfoNode, canonicalizationMethod);
|
|
444
|
+
const signatureValueBase64 = signatureValueNode.textContent?.replace(/\s+/g, "").trim() ?? "";
|
|
445
|
+
if (signatureValueBase64.length === 0) {
|
|
446
|
+
return "invalid";
|
|
447
|
+
}
|
|
448
|
+
const verifier = crypto2__default.default.createVerify(verifyAlgorithm);
|
|
449
|
+
verifier.update(Buffer.from(canonicalSignedInfo, "utf8"));
|
|
450
|
+
verifier.end();
|
|
451
|
+
const isValid = verifier.verify(certPem, Buffer.from(signatureValueBase64, "base64"));
|
|
452
|
+
return isValid ? "verified" : "invalid";
|
|
453
|
+
} catch {
|
|
454
|
+
return "invalid";
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
function loadSigningMaterialFromBuffer(certificateBuffer, certificatePath, certificatePassword) {
|
|
458
|
+
const extension = path__default.default.extname(certificatePath).toLowerCase();
|
|
459
|
+
if (extension === ".pfx" || extension === ".p12") {
|
|
460
|
+
const p12Der = forge3__default.default.util.createBuffer(Buffer.from(certificateBuffer).toString("binary"));
|
|
461
|
+
const p12Asn1 = forge3__default.default.asn1.fromDer(p12Der);
|
|
462
|
+
const p12 = forge3__default.default.pkcs12.pkcs12FromAsn1(p12Asn1, certificatePassword || "");
|
|
463
|
+
const keyBag = p12.getBags({
|
|
464
|
+
bagType: forge3__default.default.pki.oids.pkcs8ShroudedKeyBag
|
|
465
|
+
})[forge3__default.default.pki.oids.pkcs8ShroudedKeyBag];
|
|
466
|
+
const certBag = p12.getBags({ bagType: forge3__default.default.pki.oids.certBag })[forge3__default.default.pki.oids.certBag];
|
|
467
|
+
if (!keyBag || keyBag.length === 0 || !keyBag[0]?.key) {
|
|
468
|
+
throw new Error("No private key found in PKCS#12 certificate.");
|
|
469
|
+
}
|
|
470
|
+
if (!certBag || certBag.length === 0 || !certBag[0]?.cert) {
|
|
471
|
+
throw new Error("No certificate found in PKCS#12 certificate.");
|
|
472
|
+
}
|
|
473
|
+
return {
|
|
474
|
+
privateKeyPem: forge3__default.default.pki.privateKeyToPem(keyBag[0].key),
|
|
475
|
+
certificatePem: forge3__default.default.pki.certificateToPem(certBag[0].cert)
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
const pem = Buffer.from(certificateBuffer).toString("utf8");
|
|
479
|
+
const privateKeyPem = extractFirstPemBlock(pem, PRIVATE_KEY_PEM_LABELS);
|
|
480
|
+
const certificatePem = extractFirstPemBlock(pem, ["CERTIFICATE"]);
|
|
481
|
+
if (!privateKeyPem || !certificatePem) {
|
|
482
|
+
throw new Error("PEM certificate must contain both private key and certificate.");
|
|
483
|
+
}
|
|
484
|
+
return {
|
|
485
|
+
privateKeyPem,
|
|
486
|
+
certificatePem
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
function pemCertificateToBase64(pem) {
|
|
490
|
+
return pem.replace(/-----BEGIN CERTIFICATE-----/g, "").replace(/-----END CERTIFICATE-----/g, "").replace(/\s+/g, "").trim();
|
|
491
|
+
}
|
|
492
|
+
function asn1Child2(node, index) {
|
|
493
|
+
return Array.isArray(node.value) ? node.value[index] : void 0;
|
|
494
|
+
}
|
|
251
495
|
function asn1Bytes(node) {
|
|
252
496
|
return typeof node.value === "string" ? node.value : "";
|
|
253
497
|
}
|
|
254
498
|
function extractOcspUrls(certPem) {
|
|
255
499
|
try {
|
|
256
|
-
const cert = new
|
|
500
|
+
const cert = new crypto2__default.default.X509Certificate(certPem);
|
|
257
501
|
const infoAccess = cert.infoAccess;
|
|
258
502
|
if (!infoAccess) {
|
|
259
503
|
return [];
|
|
@@ -316,45 +560,45 @@ function httpPost(url, body, contentType) {
|
|
|
316
560
|
var SHA1_OID = "1.3.14.3.2.26";
|
|
317
561
|
function buildOcspRequestDer(leafPem, issuerPem) {
|
|
318
562
|
try {
|
|
319
|
-
const leaf =
|
|
320
|
-
const issuer =
|
|
321
|
-
const issuerNameDer =
|
|
322
|
-
const issuerNameHash =
|
|
323
|
-
const pubKeyDer =
|
|
324
|
-
const pubKeyAsn1 =
|
|
325
|
-
const bitString =
|
|
563
|
+
const leaf = forge3__default.default.pki.certificateFromPem(leafPem);
|
|
564
|
+
const issuer = forge3__default.default.pki.certificateFromPem(issuerPem);
|
|
565
|
+
const issuerNameDer = forge3__default.default.asn1.toDer(forge3__default.default.pki.distinguishedNameToAsn1(issuer.subject)).getBytes();
|
|
566
|
+
const issuerNameHash = forge3__default.default.md.sha1.create().update(issuerNameDer).digest().getBytes();
|
|
567
|
+
const pubKeyDer = forge3__default.default.asn1.toDer(forge3__default.default.pki.publicKeyToAsn1(issuer.publicKey)).getBytes();
|
|
568
|
+
const pubKeyAsn1 = forge3__default.default.asn1.fromDer(pubKeyDer);
|
|
569
|
+
const bitString = asn1Child2(pubKeyAsn1, 1);
|
|
326
570
|
const rawKey = bitString ? asn1Bytes(bitString).substring(1) : "";
|
|
327
|
-
const issuerKeyHash =
|
|
328
|
-
const serialBytes =
|
|
329
|
-
const request =
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
571
|
+
const issuerKeyHash = forge3__default.default.md.sha1.create().update(rawKey).digest().getBytes();
|
|
572
|
+
const serialBytes = forge3__default.default.util.hexToBytes(leaf.serialNumber);
|
|
573
|
+
const request = forge3__default.default.asn1.create(forge3__default.default.asn1.Class.UNIVERSAL, forge3__default.default.asn1.Type.SEQUENCE, true, [
|
|
574
|
+
forge3__default.default.asn1.create(forge3__default.default.asn1.Class.UNIVERSAL, forge3__default.default.asn1.Type.SEQUENCE, true, [
|
|
575
|
+
forge3__default.default.asn1.create(forge3__default.default.asn1.Class.UNIVERSAL, forge3__default.default.asn1.Type.SEQUENCE, true, [
|
|
576
|
+
forge3__default.default.asn1.create(forge3__default.default.asn1.Class.UNIVERSAL, forge3__default.default.asn1.Type.SEQUENCE, true, [
|
|
577
|
+
forge3__default.default.asn1.create(forge3__default.default.asn1.Class.UNIVERSAL, forge3__default.default.asn1.Type.SEQUENCE, true, [
|
|
578
|
+
forge3__default.default.asn1.create(forge3__default.default.asn1.Class.UNIVERSAL, forge3__default.default.asn1.Type.SEQUENCE, true, [
|
|
579
|
+
forge3__default.default.asn1.create(
|
|
580
|
+
forge3__default.default.asn1.Class.UNIVERSAL,
|
|
581
|
+
forge3__default.default.asn1.Type.OID,
|
|
338
582
|
false,
|
|
339
|
-
|
|
583
|
+
forge3__default.default.asn1.oidToDer(SHA1_OID).getBytes()
|
|
340
584
|
),
|
|
341
|
-
|
|
585
|
+
forge3__default.default.asn1.create(forge3__default.default.asn1.Class.UNIVERSAL, forge3__default.default.asn1.Type.NULL, false, "")
|
|
342
586
|
]),
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
587
|
+
forge3__default.default.asn1.create(
|
|
588
|
+
forge3__default.default.asn1.Class.UNIVERSAL,
|
|
589
|
+
forge3__default.default.asn1.Type.OCTETSTRING,
|
|
346
590
|
false,
|
|
347
591
|
issuerNameHash
|
|
348
592
|
),
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
593
|
+
forge3__default.default.asn1.create(
|
|
594
|
+
forge3__default.default.asn1.Class.UNIVERSAL,
|
|
595
|
+
forge3__default.default.asn1.Type.OCTETSTRING,
|
|
352
596
|
false,
|
|
353
597
|
issuerKeyHash
|
|
354
598
|
),
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
599
|
+
forge3__default.default.asn1.create(
|
|
600
|
+
forge3__default.default.asn1.Class.UNIVERSAL,
|
|
601
|
+
forge3__default.default.asn1.Type.INTEGER,
|
|
358
602
|
false,
|
|
359
603
|
serialBytes
|
|
360
604
|
)
|
|
@@ -363,50 +607,50 @@ function buildOcspRequestDer(leafPem, issuerPem) {
|
|
|
363
607
|
])
|
|
364
608
|
])
|
|
365
609
|
]);
|
|
366
|
-
return Buffer.from(
|
|
610
|
+
return Buffer.from(forge3__default.default.asn1.toDer(request).getBytes(), "binary");
|
|
367
611
|
} catch {
|
|
368
612
|
return void 0;
|
|
369
613
|
}
|
|
370
614
|
}
|
|
371
615
|
function parseOcspResponseStatus(data) {
|
|
372
616
|
try {
|
|
373
|
-
const asn1 =
|
|
374
|
-
const statusNode =
|
|
617
|
+
const asn1 = forge3__default.default.asn1.fromDer(forge3__default.default.util.createBuffer(data.toString("binary")));
|
|
618
|
+
const statusNode = asn1Child2(asn1, 0);
|
|
375
619
|
if (!statusNode || asn1Bytes(statusNode) !== "\0") {
|
|
376
620
|
return "error";
|
|
377
621
|
}
|
|
378
|
-
const respBytesWrapper =
|
|
622
|
+
const respBytesWrapper = asn1Child2(asn1, 1);
|
|
379
623
|
if (!respBytesWrapper) {
|
|
380
624
|
return "unknown";
|
|
381
625
|
}
|
|
382
|
-
const respBytesSeq =
|
|
626
|
+
const respBytesSeq = asn1Child2(respBytesWrapper, 0);
|
|
383
627
|
if (!respBytesSeq) {
|
|
384
628
|
return "unknown";
|
|
385
629
|
}
|
|
386
|
-
const respOctet =
|
|
630
|
+
const respOctet = asn1Child2(respBytesSeq, 1);
|
|
387
631
|
if (!respOctet) {
|
|
388
632
|
return "unknown";
|
|
389
633
|
}
|
|
390
|
-
const basicResp =
|
|
391
|
-
const tbsData =
|
|
634
|
+
const basicResp = forge3__default.default.asn1.fromDer(forge3__default.default.util.createBuffer(asn1Bytes(respOctet)));
|
|
635
|
+
const tbsData = asn1Child2(basicResp, 0);
|
|
392
636
|
if (!tbsData) {
|
|
393
637
|
return "unknown";
|
|
394
638
|
}
|
|
395
|
-
const first =
|
|
396
|
-
const responsesIdx = first?.tagClass ===
|
|
397
|
-
const responses =
|
|
639
|
+
const first = asn1Child2(tbsData, 0);
|
|
640
|
+
const responsesIdx = first?.tagClass === forge3__default.default.asn1.Class.CONTEXT_SPECIFIC && first.type === 0 ? 3 : 2;
|
|
641
|
+
const responses = asn1Child2(tbsData, responsesIdx);
|
|
398
642
|
if (!responses) {
|
|
399
643
|
return "unknown";
|
|
400
644
|
}
|
|
401
|
-
const single =
|
|
645
|
+
const single = asn1Child2(responses, 0);
|
|
402
646
|
if (!single) {
|
|
403
647
|
return "unknown";
|
|
404
648
|
}
|
|
405
|
-
const certStatus =
|
|
649
|
+
const certStatus = asn1Child2(single, 1);
|
|
406
650
|
if (!certStatus) {
|
|
407
651
|
return "unknown";
|
|
408
652
|
}
|
|
409
|
-
if (certStatus.tagClass ===
|
|
653
|
+
if (certStatus.tagClass === forge3__default.default.asn1.Class.CONTEXT_SPECIFIC) {
|
|
410
654
|
if (certStatus.type === 0) {
|
|
411
655
|
return "good";
|
|
412
656
|
}
|
|
@@ -449,164 +693,8 @@ async function evaluateCertificateRevocation(leafCertPem, issuerCertPem) {
|
|
|
449
693
|
checkedCrlUrls
|
|
450
694
|
};
|
|
451
695
|
}
|
|
452
|
-
var TIMESTAMP_TAG_REGEX = /<(?:[\w.-]+:)?(?:EncapsulatedTimeStamp|SignatureTimeStamp)[^>]*>([\s\S]*?)<\/(?:[\w.-]+:)?(?:EncapsulatedTimeStamp|SignatureTimeStamp)>/i;
|
|
453
|
-
async function evaluateTimestampAuthority(signatureXml) {
|
|
454
|
-
try {
|
|
455
|
-
const match = TIMESTAMP_TAG_REGEX.exec(signatureXml);
|
|
456
|
-
if (!match?.[1]?.trim()) {
|
|
457
|
-
return { status: "not-present" };
|
|
458
|
-
}
|
|
459
|
-
const tokenBase64 = match[1].replace(/\s+/g, "");
|
|
460
|
-
const tokenDer = Buffer.from(tokenBase64, "base64");
|
|
461
|
-
if (tokenDer.length === 0) {
|
|
462
|
-
return { status: "invalid", error: "Empty timestamp token." };
|
|
463
|
-
}
|
|
464
|
-
const asn1 = forge__default.default.asn1.fromDer(forge__default.default.util.createBuffer(tokenDer.toString("binary")));
|
|
465
|
-
const contentType = asn1Child(asn1, 0);
|
|
466
|
-
if (!contentType) {
|
|
467
|
-
return {
|
|
468
|
-
status: "invalid",
|
|
469
|
-
error: "Malformed timestamp token structure."
|
|
470
|
-
};
|
|
471
|
-
}
|
|
472
|
-
return { status: "valid" };
|
|
473
|
-
} catch (err) {
|
|
474
|
-
return {
|
|
475
|
-
status: "error",
|
|
476
|
-
error: `Timestamp evaluation failed: ${String(err)}`
|
|
477
|
-
};
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
// src/signature-node/certificate-utils.ts
|
|
482
|
-
function certificateInfoFromBase64(certBase64) {
|
|
483
|
-
try {
|
|
484
|
-
const certificate = new crypto__default.default.X509Certificate(Buffer.from(certBase64, "base64"));
|
|
485
|
-
return {
|
|
486
|
-
subject: certificate.subject || void 0,
|
|
487
|
-
issuer: certificate.issuer || void 0,
|
|
488
|
-
serialNumber: certificate.serialNumber || void 0,
|
|
489
|
-
validFrom: certificate.validFrom || void 0,
|
|
490
|
-
validTo: certificate.validTo || void 0
|
|
491
|
-
};
|
|
492
|
-
} catch {
|
|
493
|
-
return void 0;
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
function validateCertificateChain(certBase64List, additionalRootsPem) {
|
|
497
|
-
if (certBase64List.length === 0) {
|
|
498
|
-
return { status: "not-checked" };
|
|
499
|
-
}
|
|
500
|
-
try {
|
|
501
|
-
const chain = certBase64List.map((value) => {
|
|
502
|
-
const der = forge__default.default.util.decode64(value);
|
|
503
|
-
return forge__default.default.pki.certificateFromAsn1(forge__default.default.asn1.fromDer(der));
|
|
504
|
-
});
|
|
505
|
-
const rootPem = [...tls__default.default.rootCertificates, ...additionalRootsPem];
|
|
506
|
-
const caStore = forge__default.default.pki.createCaStore(rootPem);
|
|
507
|
-
const verified = forge__default.default.pki.verifyCertificateChain(caStore, chain);
|
|
508
|
-
return verified ? { status: "trusted" } : {
|
|
509
|
-
status: "untrusted",
|
|
510
|
-
error: "Certificate chain is not trusted."
|
|
511
|
-
};
|
|
512
|
-
} catch (error) {
|
|
513
|
-
return {
|
|
514
|
-
status: "untrusted",
|
|
515
|
-
error: `Certificate trust validation failed: ${String(error)}`
|
|
516
|
-
};
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
function signatureAlgorithmToVerifyAlgorithm(signatureMethod) {
|
|
520
|
-
switch (signatureMethod) {
|
|
521
|
-
case "http://www.w3.org/2000/09/xmldsig#rsa-sha1":
|
|
522
|
-
return "RSA-SHA1";
|
|
523
|
-
case "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256":
|
|
524
|
-
return "RSA-SHA256";
|
|
525
|
-
case "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384":
|
|
526
|
-
return "RSA-SHA384";
|
|
527
|
-
case "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512":
|
|
528
|
-
return "RSA-SHA512";
|
|
529
|
-
default:
|
|
530
|
-
return void 0;
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
function verifySignatureValue(signatureXml, certBase64List) {
|
|
534
|
-
try {
|
|
535
|
-
const parser = new xmldom.DOMParser();
|
|
536
|
-
const doc = parser.parseFromString(signatureXml, "text/xml");
|
|
537
|
-
const signatureNode = doc.getElementsByTagNameNS(XMLDSIG_NS, "Signature")[0];
|
|
538
|
-
if (!signatureNode) {
|
|
539
|
-
return "not-checked";
|
|
540
|
-
}
|
|
541
|
-
const certPem = certBase64List.length > 0 ? certPemFromBase64(certBase64List[0]) : void 0;
|
|
542
|
-
if (!certPem) {
|
|
543
|
-
return "not-checked";
|
|
544
|
-
}
|
|
545
|
-
const signedInfoNode = doc.getElementsByTagNameNS(XMLDSIG_NS, "SignedInfo")[0];
|
|
546
|
-
const signatureValueNode = doc.getElementsByTagNameNS(XMLDSIG_NS, "SignatureValue")[0];
|
|
547
|
-
if (!signedInfoNode || !signatureValueNode) {
|
|
548
|
-
return "invalid";
|
|
549
|
-
}
|
|
550
|
-
const canonicalizationMethod = doc.getElementsByTagNameNS(XMLDSIG_NS, "CanonicalizationMethod").item(0)?.getAttribute("Algorithm") ?? "http://www.w3.org/2001/10/xml-exc-c14n#";
|
|
551
|
-
const signatureMethod = doc.getElementsByTagNameNS(XMLDSIG_NS, "SignatureMethod").item(0)?.getAttribute("Algorithm");
|
|
552
|
-
const verifyAlgorithm = signatureAlgorithmToVerifyAlgorithm(signatureMethod ?? void 0);
|
|
553
|
-
if (!verifyAlgorithm) {
|
|
554
|
-
return "invalid";
|
|
555
|
-
}
|
|
556
|
-
const canonicalSignedInfo = canonicalizeNode(signedInfoNode, canonicalizationMethod);
|
|
557
|
-
const signatureValueBase64 = signatureValueNode.textContent?.replace(/\s+/g, "").trim() ?? "";
|
|
558
|
-
if (signatureValueBase64.length === 0) {
|
|
559
|
-
return "invalid";
|
|
560
|
-
}
|
|
561
|
-
const verifier = crypto__default.default.createVerify(verifyAlgorithm);
|
|
562
|
-
verifier.update(Buffer.from(canonicalSignedInfo, "utf8"));
|
|
563
|
-
verifier.end();
|
|
564
|
-
const isValid = verifier.verify(certPem, Buffer.from(signatureValueBase64, "base64"));
|
|
565
|
-
return isValid ? "verified" : "invalid";
|
|
566
|
-
} catch {
|
|
567
|
-
return "invalid";
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
function loadSigningMaterialFromBuffer(certificateBuffer, certificatePath, certificatePassword) {
|
|
571
|
-
const extension = path__default.default.extname(certificatePath).toLowerCase();
|
|
572
|
-
if (extension === ".pfx" || extension === ".p12") {
|
|
573
|
-
const p12Der = forge__default.default.util.createBuffer(Buffer.from(certificateBuffer).toString("binary"));
|
|
574
|
-
const p12Asn1 = forge__default.default.asn1.fromDer(p12Der);
|
|
575
|
-
const p12 = forge__default.default.pkcs12.pkcs12FromAsn1(p12Asn1, certificatePassword || "");
|
|
576
|
-
const keyBag = p12.getBags({
|
|
577
|
-
bagType: forge__default.default.pki.oids.pkcs8ShroudedKeyBag
|
|
578
|
-
})[forge__default.default.pki.oids.pkcs8ShroudedKeyBag];
|
|
579
|
-
const certBag = p12.getBags({ bagType: forge__default.default.pki.oids.certBag })[forge__default.default.pki.oids.certBag];
|
|
580
|
-
if (!keyBag || keyBag.length === 0 || !keyBag[0]?.key) {
|
|
581
|
-
throw new Error("No private key found in PKCS#12 certificate.");
|
|
582
|
-
}
|
|
583
|
-
if (!certBag || certBag.length === 0 || !certBag[0]?.cert) {
|
|
584
|
-
throw new Error("No certificate found in PKCS#12 certificate.");
|
|
585
|
-
}
|
|
586
|
-
return {
|
|
587
|
-
privateKeyPem: forge__default.default.pki.privateKeyToPem(keyBag[0].key),
|
|
588
|
-
certificatePem: forge__default.default.pki.certificateToPem(certBag[0].cert)
|
|
589
|
-
};
|
|
590
|
-
}
|
|
591
|
-
const pem = Buffer.from(certificateBuffer).toString("utf8");
|
|
592
|
-
const privateKeyMatch = pem.match(
|
|
593
|
-
/-----BEGIN (?:RSA |EC |ENCRYPTED )?PRIVATE KEY-----[\s\S]+?-----END (?:RSA |EC |ENCRYPTED )?PRIVATE KEY-----/m
|
|
594
|
-
);
|
|
595
|
-
const certMatch = pem.match(/-----BEGIN CERTIFICATE-----[\s\S]+?-----END CERTIFICATE-----/m);
|
|
596
|
-
if (!privateKeyMatch || !certMatch) {
|
|
597
|
-
throw new Error("PEM certificate must contain both private key and certificate.");
|
|
598
|
-
}
|
|
599
|
-
return {
|
|
600
|
-
privateKeyPem: privateKeyMatch[0],
|
|
601
|
-
certificatePem: certMatch[0]
|
|
602
|
-
};
|
|
603
|
-
}
|
|
604
|
-
function pemCertificateToBase64(pem) {
|
|
605
|
-
return pem.replace(/-----BEGIN CERTIFICATE-----/g, "").replace(/-----END CERTIFICATE-----/g, "").replace(/\s+/g, "").trim();
|
|
606
|
-
}
|
|
607
696
|
function extractPemCertificatesFromText(text) {
|
|
608
|
-
|
|
609
|
-
return matches.map((value) => value.trim()).filter((value) => value.length > 0);
|
|
697
|
+
return extractPemBlocks(text, "CERTIFICATE").map((value) => value.trim()).filter((value) => value.length > 0);
|
|
610
698
|
}
|
|
611
699
|
function parseBooleanEnv(envValue) {
|
|
612
700
|
if (!envValue) {
|
|
@@ -747,7 +835,7 @@ function computeDigestBase642(content, digestAlgorithmUri) {
|
|
|
747
835
|
if (!hashName) {
|
|
748
836
|
return void 0;
|
|
749
837
|
}
|
|
750
|
-
return
|
|
838
|
+
return crypto2__default.default.createHash(hashName).update(Buffer.from(content)).digest("base64");
|
|
751
839
|
}
|
|
752
840
|
async function buildReferenceChecksFromSignatureXml(zip, signatureXml) {
|
|
753
841
|
const parser = new xmldom.DOMParser();
|
|
@@ -1080,7 +1168,7 @@ async function buildOfficeReferenceList(zip) {
|
|
|
1080
1168
|
continue;
|
|
1081
1169
|
}
|
|
1082
1170
|
const entryBytes = await entry.async("uint8array");
|
|
1083
|
-
const digestValue =
|
|
1171
|
+
const digestValue = crypto2__default.default.createHash("sha256").update(Buffer.from(entryBytes)).digest("base64");
|
|
1084
1172
|
references.push({
|
|
1085
1173
|
uri: `/${normalizePartPath(entryPath)}`,
|
|
1086
1174
|
digestMethod,
|
|
@@ -1096,7 +1184,7 @@ function buildOfficeSignatureXml(references, privateKeyPem, certificatePem) {
|
|
|
1096
1184
|
).join("");
|
|
1097
1185
|
const signedInfoXml = `<SignedInfo xmlns="${XMLDSIG_NS}"><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>${signedInfoReferencesXml}</SignedInfo>`;
|
|
1098
1186
|
const canonicalSignedInfo = canonicalizeSignedInfoXml(signedInfoXml);
|
|
1099
|
-
const signer =
|
|
1187
|
+
const signer = crypto2__default.default.createSign("RSA-SHA256");
|
|
1100
1188
|
signer.update(Buffer.from(canonicalSignedInfo, "utf8"));
|
|
1101
1189
|
signer.end();
|
|
1102
1190
|
const signatureValueBase64 = signer.sign(privateKeyPem).toString("base64");
|