summaryrefslogtreecommitdiffstats
path: root/toolkit/components/certviewer
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /toolkit/components/certviewer
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/certviewer')
-rw-r--r--toolkit/components/certviewer/AboutCertViewerChild.sys.mjs8
-rw-r--r--toolkit/components/certviewer/AboutCertViewerParent.sys.mjs43
-rw-r--r--toolkit/components/certviewer/content/certDecoder.mjs1267
-rw-r--r--toolkit/components/certviewer/content/certviewer.css8
-rw-r--r--toolkit/components/certviewer/content/certviewer.html113
-rw-r--r--toolkit/components/certviewer/content/certviewer.mjs475
-rw-r--r--toolkit/components/certviewer/content/components/about-certificate-items.mjs33
-rw-r--r--toolkit/components/certviewer/content/components/about-certificate-section.css7
-rw-r--r--toolkit/components/certviewer/content/components/about-certificate-section.mjs114
-rw-r--r--toolkit/components/certviewer/content/components/certificate-section.css72
-rw-r--r--toolkit/components/certviewer/content/components/certificate-section.mjs93
-rw-r--r--toolkit/components/certviewer/content/components/certificate-tabs-section.mjs123
-rw-r--r--toolkit/components/certviewer/content/components/error-section.css23
-rw-r--r--toolkit/components/certviewer/content/components/error-section.mjs31
-rw-r--r--toolkit/components/certviewer/content/components/info-group-container.mjs65
-rw-r--r--toolkit/components/certviewer/content/components/info-group.css38
-rw-r--r--toolkit/components/certviewer/content/components/info-group.mjs93
-rw-r--r--toolkit/components/certviewer/content/components/info-item.css69
-rw-r--r--toolkit/components/certviewer/content/components/info-item.mjs173
-rw-r--r--toolkit/components/certviewer/content/components/list-item.css46
-rw-r--r--toolkit/components/certviewer/content/components/list-item.mjs58
-rw-r--r--toolkit/components/certviewer/content/components/utils.mjs26
-rw-r--r--toolkit/components/certviewer/content/vendor/pkijs.js24083
-rw-r--r--toolkit/components/certviewer/jar.mn12
-rw-r--r--toolkit/components/certviewer/moz.build19
-rw-r--r--toolkit/components/certviewer/tests/browser/adjustedCerts.js261
-rw-r--r--toolkit/components/certviewer/tests/browser/browser.toml38
-rw-r--r--toolkit/components/certviewer/tests/browser/browser_aboutcertificateviewer.js81
-rw-r--r--toolkit/components/certviewer/tests/browser/browser_certificateTabLink.js61
-rw-r--r--toolkit/components/certviewer/tests/browser/browser_checkAuthorityKeyID.js50
-rw-r--r--toolkit/components/certviewer/tests/browser/browser_checkLongHex.js38
-rw-r--r--toolkit/components/certviewer/tests/browser/browser_checkMissingCommonName.js50
-rw-r--r--toolkit/components/certviewer/tests/browser/browser_checkNonEmptyFields.js82
-rw-r--r--toolkit/components/certviewer/tests/browser/browser_checkNonRepeatedCertTabs.js131
-rw-r--r--toolkit/components/certviewer/tests/browser/browser_checkNonUndefinedStrings.js49
-rw-r--r--toolkit/components/certviewer/tests/browser/browser_checkOCSP.js46
-rw-r--r--toolkit/components/certviewer/tests/browser/browser_checkStandAlonePage.js86
-rw-r--r--toolkit/components/certviewer/tests/browser/browser_checkValiditySection.js57
-rw-r--r--toolkit/components/certviewer/tests/browser/browser_downloadLink.js126
-rw-r--r--toolkit/components/certviewer/tests/browser/browser_handleMultipleCertsURL.js251
-rw-r--r--toolkit/components/certviewer/tests/browser/browser_openTabAndSendCertInfo.js271
-rw-r--r--toolkit/components/certviewer/tests/browser/browser_renderCertToUI.js192
-rw-r--r--toolkit/components/certviewer/tests/browser/dummy_page.html9
-rw-r--r--toolkit/components/certviewer/tests/browser/head.js124
-rw-r--r--toolkit/components/certviewer/tests/chrome/CSoutput.mjs144
-rw-r--r--toolkit/components/certviewer/tests/chrome/chrome.toml13
-rw-r--r--toolkit/components/certviewer/tests/chrome/parseOutput.mjs330
-rw-r--r--toolkit/components/certviewer/tests/chrome/test_adjustCertInformation.html45
-rw-r--r--toolkit/components/certviewer/tests/chrome/test_certDecoder.html39
-rw-r--r--toolkit/components/certviewer/tests/chrome/test_certDecoderFields.html84
-rw-r--r--toolkit/components/certviewer/tests/chrome/test_kebabCaseInAdjustCertInformation.html106
51 files changed, 29856 insertions, 0 deletions
diff --git a/toolkit/components/certviewer/AboutCertViewerChild.sys.mjs b/toolkit/components/certviewer/AboutCertViewerChild.sys.mjs
new file mode 100644
index 0000000000..0ac58ceb66
--- /dev/null
+++ b/toolkit/components/certviewer/AboutCertViewerChild.sys.mjs
@@ -0,0 +1,8 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import { RemotePageChild } from "resource://gre/actors/RemotePageChild.sys.mjs";
+
+export class AboutCertViewerChild extends RemotePageChild {}
diff --git a/toolkit/components/certviewer/AboutCertViewerParent.sys.mjs b/toolkit/components/certviewer/AboutCertViewerParent.sys.mjs
new file mode 100644
index 0000000000..62838bbdf7
--- /dev/null
+++ b/toolkit/components/certviewer/AboutCertViewerParent.sys.mjs
@@ -0,0 +1,43 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const TYPE_CA = 1;
+const TYPE_USER = 2;
+const TYPE_EMAIL = 4;
+const TYPE_SERVER = 8;
+
+export class AboutCertViewerParent extends JSWindowActorParent {
+ getCertificates() {
+ let certs = {
+ [TYPE_CA]: [],
+ [TYPE_USER]: [],
+ [TYPE_EMAIL]: [],
+ [TYPE_SERVER]: [],
+ };
+ let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
+ Ci.nsIX509CertDB
+ );
+ let certcache = certdb.getCerts();
+ for (let cert of certcache) {
+ for (let certType of Object.keys(certs).map(Number)) {
+ if (certType & cert.certType) {
+ certs[certType].push({
+ displayName: cert.displayName,
+ derb64: cert.getBase64DERString(),
+ });
+ }
+ }
+ }
+ return certs;
+ }
+
+ receiveMessage(aMessage) {
+ switch (aMessage.name) {
+ case "getCertificates":
+ return this.getCertificates();
+ }
+
+ return undefined;
+ }
+}
diff --git a/toolkit/components/certviewer/content/certDecoder.mjs b/toolkit/components/certviewer/content/certDecoder.mjs
new file mode 100644
index 0000000000..3929f5ff2d
--- /dev/null
+++ b/toolkit/components/certviewer/content/certDecoder.mjs
@@ -0,0 +1,1267 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import {
+ Certificate,
+ ECNamedCurves,
+ ECPublicKey,
+ RSAPublicKey,
+} from "./vendor/pkijs.js";
+
+const getTimeZone = () => {
+ let timeZone = new Date().toString().match(/\(([A-Za-z\s].*)\)/);
+ if (timeZone === null) {
+ // America/Chicago
+ timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
+ } else if (timeZone.length > 1) {
+ timeZone = timeZone[1]; // Central Daylight Time
+ } else {
+ timeZone = "Local Time"; // not sure if this is right, but let's go with it for now
+ }
+ return timeZone;
+};
+
+const getPublicKeyInfo = x509 => {
+ let publicKey = x509.subjectPublicKeyInfo.parsedKey;
+ if (publicKey instanceof RSAPublicKey) {
+ let modulusJSON = publicKey.modulus.toJSON();
+ let modulusHex = modulusJSON.valueBlock.valueHex;
+ return {
+ e: publicKey.publicExponent.toJSON().valueBlock.valueDec,
+ kty: "RSA",
+ n: hashify(modulusHex),
+ keysize: modulusHex.length * 4, // key size in bits
+ };
+ }
+ if (publicKey instanceof ECPublicKey) {
+ let x = hashify(publicKey.x);
+ let y = hashify(publicKey.y);
+ let curve = ECNamedCurves.find(publicKey.namedCurve);
+ let keysize = curve ? curve.size * 8 : undefined;
+ return {
+ kty: "Elliptic Curve",
+ keysize,
+ x, // x coordinate
+ y, // y coordinate
+ xy: `04:${x}:${y}`, // 04 (uncompressed) public key
+ };
+ }
+ return { kty: "Unknown" };
+};
+
+const getX509Ext = (extensions, v) => {
+ for (var extension in extensions) {
+ if (extensions[extension].extnID === v) {
+ return extensions[extension].toJSON().parsedValue;
+ }
+ }
+ return undefined;
+};
+
+const getKeyUsages = (x509, criticalExtensions) => {
+ let keyUsages = {
+ critical: criticalExtensions.includes("2.5.29.15"),
+ purposes: [],
+ };
+
+ let keyUsagesBS = getX509Ext(x509.extensions, "2.5.29.15");
+ if (keyUsagesBS !== undefined) {
+ // parse the bit string, shifting as necessary
+ let unusedBits = keyUsagesBS.valueBlock.unusedBits;
+ keyUsagesBS = parseInt(keyUsagesBS.valueBlock.valueHex, 16) >> unusedBits;
+
+ // iterate through the bit string
+ strings.keyUsages.slice(unusedBits - 1).forEach(usage => {
+ if (keyUsagesBS & 1) {
+ keyUsages.purposes.push(usage);
+ }
+
+ keyUsagesBS = keyUsagesBS >> 1;
+ });
+
+ // reverse the order for legibility
+ keyUsages.purposes.reverse();
+ }
+
+ return keyUsages;
+};
+
+const parseSubsidiary = distinguishedNames => {
+ const subsidiary = {
+ cn: "",
+ dn: [],
+ entries: [],
+ };
+
+ distinguishedNames.forEach(dn => {
+ const distinguishedName = strings.names[dn.type];
+ const value = dn.value.valueBlock.value;
+
+ if (distinguishedName === undefined) {
+ subsidiary.dn.push(`OID.${dn.type}=${value}`);
+ subsidiary.entries.push([`OID.${dn.type}`, value]);
+ } else if (distinguishedName.short === undefined) {
+ subsidiary.dn.push(`OID.${dn.type}=${value}`);
+ subsidiary.entries.push([distinguishedName.long, value]);
+ } else {
+ subsidiary.dn.push(`${distinguishedName.short}=${value}`);
+ subsidiary.entries.push([distinguishedName.long, value]);
+
+ // add the common name for tab display
+ if (distinguishedName.short === "cn") {
+ subsidiary.cn = value;
+ }
+ }
+ });
+
+ // turn path into a string
+ subsidiary.dn = subsidiary.dn.join(", ");
+
+ return subsidiary;
+};
+
+const getSubjectAltNames = (x509, criticalExtensions) => {
+ let san = getX509Ext(x509.extensions, "2.5.29.17");
+ if (san && san.hasOwnProperty("altNames")) {
+ san = Object.keys(san.altNames).map(index => {
+ const type = san.altNames[index].type;
+
+ switch (type) {
+ case 4: // directory
+ return [
+ strings.san[type],
+ parseSubsidiary(san.altNames[index].value.typesAndValues).dn,
+ ];
+ case 7: // ip address
+ let address = san.altNames[index].value.valueBlock.valueHex;
+
+ if (address.length === 8) {
+ // ipv4
+ return [
+ strings.san[type],
+ address
+ .match(/.{1,2}/g)
+ .map(x => parseInt(x, 16))
+ .join("."),
+ ];
+ } else if (address.length === 32) {
+ // ipv6
+ return [
+ strings.san[type],
+ address
+ .toLowerCase()
+ .match(/.{1,4}/g)
+ .join(":")
+ .replace(/\b:?(?:0+:?){2,}/, "::"),
+ ];
+ }
+ return [strings.san[type], "Unknown IP address"];
+
+ default:
+ return [strings.san[type], san.altNames[index].value];
+ }
+ });
+ } else {
+ san = [];
+ }
+ san = {
+ altNames: san,
+ critical: criticalExtensions.includes("2.5.29.17"),
+ };
+ return san;
+};
+
+const getBasicConstraints = (x509, criticalExtensions) => {
+ let basicConstraints;
+ const basicConstraintsExt = getX509Ext(x509.extensions, "2.5.29.19");
+ if (basicConstraintsExt) {
+ basicConstraints = {
+ cA: basicConstraintsExt.cA !== undefined && basicConstraintsExt.cA,
+ critical: criticalExtensions.includes("2.5.29.19"),
+ };
+ }
+ return basicConstraints;
+};
+
+const getEKeyUsages = (x509, criticalExtensions) => {
+ let eKeyUsages = getX509Ext(x509.extensions, "2.5.29.37");
+ if (eKeyUsages) {
+ eKeyUsages = {
+ critical: criticalExtensions.includes("2.5.29.37"),
+ purposes: eKeyUsages.keyPurposes.map(x => strings.eKU[x] || x),
+ };
+ }
+ return eKeyUsages;
+};
+
+const getSubjectKeyID = (x509, criticalExtensions) => {
+ let sKID = getX509Ext(x509.extensions, "2.5.29.14");
+ if (sKID) {
+ sKID = {
+ critical: criticalExtensions.includes("2.5.29.14"),
+ id: hashify(sKID.valueBlock.valueHex),
+ };
+ }
+ return sKID;
+};
+
+const getAuthorityKeyID = (x509, criticalExtensions) => {
+ let aKID = getX509Ext(x509.extensions, "2.5.29.35");
+ if (!aKID || !aKID.keyIdentifier) {
+ return null;
+ }
+ aKID = {
+ critical: criticalExtensions.includes("2.5.29.35"),
+ id: hashify(aKID.keyIdentifier.valueBlock.valueHex),
+ };
+ return aKID;
+};
+
+const getCRLPoints = (x509, criticalExtensions) => {
+ let crlPoints = getX509Ext(x509.extensions, "2.5.29.31");
+ if (crlPoints) {
+ crlPoints = {
+ critical: criticalExtensions.includes("2.5.29.31"),
+ points: crlPoints.distributionPoints.map(
+ x => x.distributionPoint[0].value
+ ),
+ };
+ }
+ return crlPoints;
+};
+
+const getOcspStaple = (x509, criticalExtensions) => {
+ let ocspStaple = getX509Ext(x509.extensions, "1.3.6.1.5.5.7.1.24");
+ if (ocspStaple && ocspStaple.valueBeforeDecode === "3003020105") {
+ ocspStaple = {
+ critical: criticalExtensions.includes("1.3.6.1.5.5.7.1.24"),
+ required: true,
+ };
+ } else {
+ ocspStaple = {
+ critical: criticalExtensions.includes("1.3.6.1.5.5.7.1.24"),
+ required: false,
+ };
+ }
+ return ocspStaple;
+};
+
+const getAuthorityInfoAccess = (x509, criticalExtensions) => {
+ let aia = getX509Ext(x509.extensions, "1.3.6.1.5.5.7.1.1");
+ if (aia) {
+ aia = aia.accessDescriptions.map(x => {
+ return {
+ location: x.accessLocation.value,
+ method: strings.aia[x.accessMethod],
+ };
+ });
+ }
+
+ aia = {
+ descriptions: aia,
+ critical: criticalExtensions.includes("1.3.6.1.5.5.7.1.1"),
+ };
+ return aia;
+};
+
+const getSCTs = (x509, criticalExtensions) => {
+ let scts = getX509Ext(x509.extensions, "1.3.6.1.4.1.11129.2.4.2");
+ if (scts) {
+ scts = Object.keys(scts.timestamps).map(x => {
+ let logId = scts.timestamps[x].logID.toLowerCase();
+ let sctsTimestamp = scts.timestamps[x].timestamp;
+ return {
+ logId: hashify(logId),
+ name: ctLogNames.hasOwnProperty(logId) ? ctLogNames[logId] : undefined,
+ signatureAlgorithm: `${scts.timestamps[x].hashAlgorithm.replace(
+ "sha",
+ "SHA-"
+ )} ${scts.timestamps[x].signatureAlgorithm.toUpperCase()}`,
+ timestamp: `${sctsTimestamp.toLocaleString()} (${getTimeZone()})`,
+ timestampUTC: sctsTimestamp.toUTCString(),
+ version: scts.timestamps[x].version + 1,
+ };
+ });
+ } else {
+ scts = [];
+ }
+
+ scts = {
+ critical: criticalExtensions.includes("1.3.6.1.4.1.11129.2.4.2"),
+ timestamps: scts,
+ };
+ return scts;
+};
+
+const getCertificatePolicies = (x509, criticalExtensions) => {
+ let cp = getX509Ext(x509.extensions, "2.5.29.32");
+ if (cp && cp.hasOwnProperty("certificatePolicies")) {
+ cp = cp.certificatePolicies.map(x => {
+ let id = x.policyIdentifier;
+ let certName = strings.cps.hasOwnProperty(id)
+ ? strings.cps[id].name
+ : undefined;
+ let qualifiers = undefined;
+ let value = strings.cps.hasOwnProperty(id)
+ ? strings.cps[id].value
+ : undefined;
+
+ // ansi organization identifiers
+ if (id.startsWith("2.16.840.")) {
+ value = id;
+ id = "2.16.840";
+ certName = strings.cps["2.16.840"].name;
+ }
+
+ // statement identifiers
+ if (id.startsWith("1.3.6.1.4.1")) {
+ value = id;
+ id = "1.3.6.1.4.1";
+ certName = strings.cps["1.3.6.1.4.1"].name;
+ }
+
+ if (x.hasOwnProperty("policyQualifiers")) {
+ qualifiers = x.policyQualifiers.map(qualifier => {
+ let qualifierId = qualifier.policyQualifierId;
+ let qualifierName = strings.cps.hasOwnProperty(qualifierId)
+ ? strings.cps[qualifierId].name
+ : undefined;
+ let qualifierValue = qualifier.qualifier.valueBlock.value;
+
+ // sometimes they are multiple qualifier subblocks, and for now we'll
+ // only return the first one because it's getting really messy at this point
+ if (Array.isArray(qualifierValue) && qualifierValue.length === 1) {
+ qualifierValue = qualifierValue[0].valueBlock.value;
+ } else if (
+ Array.isArray(qualifierValue) &&
+ qualifierValue.length > 1
+ ) {
+ qualifierValue = "(currently unsupported)";
+ }
+
+ return {
+ qualifierId,
+ qualifierName,
+ qualifierValue,
+ };
+ });
+ }
+
+ return {
+ id,
+ name: certName,
+ qualifiers,
+ value,
+ };
+ });
+ }
+
+ cp = {
+ critical: criticalExtensions.includes("2.5.29.32"),
+ policies: cp,
+ };
+ return cp;
+};
+
+const getMicrosoftCryptographicExtensions = (x509, criticalExtensions) => {
+ // now let's parse the Microsoft cryptographic extensions
+ let msCrypto = {
+ caVersion: getX509Ext(x509.extensions, "1.3.6.1.4.1.311.21.1"),
+ certificatePolicies: getX509Ext(x509.extensions, "1.3.6.1.4.1.311.21.10"),
+ certificateTemplate: getX509Ext(x509.extensions, "1.3.6.1.4.1.311.21.7"),
+ certificateType: getX509Ext(x509.extensions, "1.3.6.1.4.1.311.20.2"),
+ previousHash: getX509Ext(x509.extensions, "1.3.6.1.4.1.311.21.2"),
+ };
+
+ if (
+ msCrypto.caVersion &&
+ Number.isInteger(msCrypto.caVersion.keyIndex) &&
+ Number.isInteger(msCrypto.caVersion.certificateIndex)
+ ) {
+ msCrypto.caVersion = {
+ critical: criticalExtensions.includes("1.3.6.1.4.1.311.21.1"),
+ caRenewals: msCrypto.caVersion.certificateIndex,
+ keyReuses:
+ msCrypto.caVersion.certificateIndex - msCrypto.caVersion.keyIndex,
+ };
+ }
+
+ if (msCrypto.certificatePolicies) {
+ msCrypto.certificatePolicies = {
+ critical: criticalExtensions.includes("1.3.6.1.4.1.311.21.10"),
+ purposes: msCrypto.certificatePolicies.certificatePolicies.map(
+ x => strings.eKU[x.policyIdentifier] || x.policyIdentifier
+ ),
+ };
+ }
+
+ if (msCrypto.certificateTemplate) {
+ msCrypto.certificateTemplate = {
+ critical: criticalExtensions.includes("1.3.6.1.4.1.311.21.7"),
+ id: msCrypto.certificateTemplate.extnID,
+ major: msCrypto.certificateTemplate.templateMajorVersion,
+ minor: msCrypto.certificateTemplate.templateMinorVersion,
+ };
+ }
+
+ if (msCrypto.certificateType) {
+ msCrypto.certificateType = {
+ critical: criticalExtensions.includes("1.3.6.1.4.1.311.20.2"),
+ type:
+ strings.microsoftCertificateTypes[
+ msCrypto.certificateType.valueBlock.value
+ ] || "Unknown",
+ };
+ }
+
+ if (msCrypto.previousHash) {
+ msCrypto.previousHash = {
+ critical: criticalExtensions.includes("1.3.6.1.4.1.311.21.2"),
+ previousHash: hashify(msCrypto.previousHash.valueBlock.valueHex),
+ };
+ }
+
+ msCrypto.exists = !!(
+ msCrypto.caVersion ||
+ msCrypto.certificatePolicies ||
+ msCrypto.certificateTemplate ||
+ msCrypto.certificateType ||
+ msCrypto.previousHash
+ );
+
+ return msCrypto;
+};
+
+const b64ToPEM = string => {
+ let wrapped = string.match(/.{1,64}/g).join("\r\n");
+ return `-----BEGIN CERTIFICATE-----\r\n${wrapped}\r\n-----END CERTIFICATE-----\r\n`;
+};
+
+export const parse = async certificate => {
+ // certificate could be an array of BER or an array of buffers
+ const supportedExtensions = [
+ "1.3.6.1.4.1.311.20.2", // microsoft certificate type
+ "1.3.6.1.4.1.311.21.2", // microsoft certificate previous hash
+ "1.3.6.1.4.1.311.21.7", // microsoft certificate template
+ "1.3.6.1.4.1.311.21.1", // microsoft certification authority renewal
+ "1.3.6.1.4.1.311.21.10", // microsoft certificate policies
+ "1.3.6.1.4.1.11129.2.4.2", // embedded scts
+ "1.3.6.1.5.5.7.1.1", // authority info access
+ "1.3.6.1.5.5.7.1.24", // ocsp stapling
+ "1.3.101.77", // ct redaction - deprecated and not displayed
+ "2.5.29.14", // subject key identifier
+ "2.5.29.15", // key usages
+ "2.5.29.17", // subject alt names
+ "2.5.29.19", // basic constraints
+ "2.5.29.31", // crl points
+ "2.5.29.32", // certificate policies
+ "2.5.29.35", // authority key identifier
+ "2.5.29.37", // extended key usage
+ ];
+
+ let timeZone = getTimeZone();
+
+ // parse the certificate
+ let x509 = Certificate.fromBER(certificate);
+
+ // convert the cert to PEM
+ const certPEM = b64ToPEM(
+ btoa(String.fromCharCode.apply(null, new Uint8Array(certificate)))
+ );
+
+ // get which extensions are critical
+ const criticalExtensions = [];
+ if (x509.extensions) {
+ x509.extensions.forEach(ext => {
+ if (ext.hasOwnProperty("critical") && ext.critical === true) {
+ criticalExtensions.push(ext.extnID);
+ }
+ });
+ }
+ const spki = getPublicKeyInfo(x509);
+ const keyUsages = getKeyUsages(x509, criticalExtensions);
+ const san = getSubjectAltNames(x509, criticalExtensions);
+ const basicConstraints = getBasicConstraints(x509, criticalExtensions);
+ const eKeyUsages = getEKeyUsages(x509, criticalExtensions);
+ const sKID = getSubjectKeyID(x509, criticalExtensions);
+ const aKID = getAuthorityKeyID(x509, criticalExtensions);
+ const crlPoints = getCRLPoints(x509, criticalExtensions);
+ const ocspStaple = getOcspStaple(x509, criticalExtensions);
+ const aia = getAuthorityInfoAccess(x509, criticalExtensions);
+ const scts = getSCTs(x509, criticalExtensions);
+ const cp = getCertificatePolicies(x509, criticalExtensions);
+ const msCrypto = getMicrosoftCryptographicExtensions(
+ x509,
+ criticalExtensions
+ );
+
+ // determine which extensions weren't supported
+ let unsupportedExtensions = [];
+ if (x509.extensions) {
+ x509.extensions.forEach(ext => {
+ if (!supportedExtensions.includes(ext.extnID)) {
+ unsupportedExtensions.push(ext.extnID);
+ }
+ });
+ }
+
+ // the output shell
+ return {
+ ext: {
+ aia,
+ aKID,
+ basicConstraints,
+ crlPoints,
+ cp,
+ eKeyUsages,
+ keyUsages,
+ msCrypto,
+ ocspStaple,
+ scts,
+ sKID,
+ san,
+ },
+ files: {
+ der: undefined, // TODO: implement!
+ pem: encodeURI(certPEM),
+ },
+ fingerprint: {
+ sha1: await hash("SHA-1", certificate),
+ sha256: await hash("SHA-256", certificate),
+ },
+ issuer: parseSubsidiary(x509.issuer.typesAndValues),
+ notBefore: `${x509.notBefore.value.toLocaleString()} (${timeZone})`,
+ notBeforeUTC: x509.notBefore.value.toUTCString(),
+ notAfter: `${x509.notAfter.value.toLocaleString()} (${timeZone})`,
+ notAfterUTC: x509.notAfter.value.toUTCString(),
+ subject: parseSubsidiary(x509.subject.typesAndValues),
+ serialNumber: hashify(getObjPath(x509, "serialNumber.valueBlock.valueHex")),
+ signature: {
+ name: strings.signature[getObjPath(x509, "signature.algorithmId")],
+ type: getObjPath(x509, "signature.algorithmId"),
+ },
+ subjectPublicKeyInfo: spki,
+ unsupportedExtensions,
+ version: (x509.version + 1).toString(),
+ };
+};
+
+const ctLogNames = {
+ "9606c02c690033aa1d145f59c6e2648d0549f0df96aab8db915a70d8ecf390a5":
+ "Akamai CT",
+ "39376f545f7b4607f59742d768cd5d2437bf3473b6534a4834bcf72e681c83c9":
+ "Alpha CT",
+ a577ac9ced7548dd8f025b67a241089df86e0f476ec203c2ecbedb185f282638: "CNNIC CT",
+ cdb5179b7fc1c046feea31136a3f8f002e6182faf8896fecc8b2f5b5ab604900: "Certly.IO",
+ "1fbc36e002ede97f40199e86b3573b8a4217d80187746ad0da03a06054d20df4":
+ "Cloudflare “Nimbus2017”",
+ db74afeecb29ecb1feca3e716d2ce5b9aabb36f7847183c75d9d4f37b61fbf64:
+ "Cloudflare “Nimbus2018”",
+ "747eda8331ad331091219cce254f4270c2bffd5e422008c6373579e6107bcc56":
+ "Cloudflare “Nimbus2019”",
+ "5ea773f9df56c0e7b536487dd049e0327a919a0c84a112128418759681714558":
+ "Cloudflare “Nimbus2020”",
+ "4494652eb0eeceafc44007d8a8fe28c0dae682bed8cb31b53fd33396b5b681a8":
+ "Cloudflare “Nimbus2021”",
+ "41c8cab1df22464a10c6a13a0942875e4e318b1b03ebeb4bc768f090629606f6":
+ "Cloudflare “Nimbus2022”",
+ "7a328c54d8b72db620ea38e0521ee98416703213854d3bd22bc13a57a352eb52":
+ "Cloudflare “Nimbus2023”",
+ "6ff141b5647e4222f7ef052cefae7c21fd608e27d2af5a6e9f4b8a37d6633ee5":
+ "DigiCert Nessie2018",
+ fe446108b1d01ab78a62ccfeab6ab2b2babff3abdad80a4d8b30df2d0008830c:
+ "DigiCert Nessie2019",
+ c652a0ec48ceb3fcab170992c43a87413309e80065a26252401ba3362a17c565:
+ "DigiCert Nessie2020",
+ eec095ee8d72640f92e3c3b91bc712a3696a097b4b6a1a1438e647b2cbedc5f9:
+ "DigiCert Nessie2021",
+ "51a3b0f5fd01799c566db837788f0ca47acc1b27cbf79e88429a0dfed48b05e5":
+ "DigiCert Nessie2022",
+ b3737707e18450f86386d605a9dc11094a792db1670c0b87dcf0030e7936a59a:
+ "DigiCert Nessie2023",
+ "5614069a2fd7c2ecd3f5e1bd44b23ec74676b9bc99115cc0ef949855d689d0dd":
+ "DigiCert Server",
+ "8775bfe7597cf88c43995fbdf36eff568d475636ff4ab560c1b4eaff5ea0830f":
+ "DigiCert Server 2",
+ c1164ae0a772d2d4392dc80ac10770d4f0c49bde991a4840c1fa075164f63360:
+ "DigiCert Yeti2018",
+ e2694bae26e8e94009e8861bb63b83d43ee7fe7488fba48f2893019dddf1dbfe:
+ "DigiCert Yeti2019",
+ f095a459f200d18240102d2f93888ead4bfe1d47e399e1d034a6b0a8aa8eb273:
+ "DigiCert Yeti2020",
+ "5cdc4392fee6ab4544b15e9ad456e61037fbd5fa47dca17394b25ee6f6c70eca":
+ "DigiCert Yeti2021",
+ "2245450759552456963fa12ff1f76d86e0232663adc04b7f5dc6835c6ee20f02":
+ "DigiCert Yeti2022",
+ "35cf191bbfb16c57bf0fad4c6d42cbbbb627202651ea3fe12aefa803c33bd64c":
+ "DigiCert Yeti2023",
+ "717ea7420975be84a2723553f1777c26dd51af4e102144094d9019b462fb6668": "GDCA 1",
+ "14308d90ccd030135005c01ca526d81e84e87624e39b6248e08f724aea3bb42a": "GDCA 2",
+ c9cf890a21109c666cc17a3ed065c930d0e0135a9feba85af14210b8072421aa:
+ "GDCA CT #1",
+ "924a30f909336ff435d6993a10ac75a2c641728e7fc2d659ae6188ffad40ce01":
+ "GDCA CT #2",
+ fad4c97cc49ee2f8ac85c5ea5cea09d0220dbbf4e49c6b50662ff868f86b8c28:
+ "Google “Argon2017”",
+ a4501269055a15545e6211ab37bc103f62ae5576a45e4b1714453e1b22106a25:
+ "Google “Argon2018”",
+ "63f2dbcde83bcc2ccf0b728427576b33a48d61778fbd75a638b1c768544bd88d":
+ "Google “Argon2019”",
+ b21e05cc8ba2cd8a204e8766f92bb98a2520676bdafa70e7b249532def8b905e:
+ "Google “Argon2020”",
+ f65c942fd1773022145418083094568ee34d131933bfdf0c2f200bcc4ef164e3:
+ "Google “Argon2021”",
+ "2979bef09e393921f056739f63a577e5be577d9c600af8f94d5d265c255dc784":
+ "Google “Argon2022”",
+ "68f698f81f6482be3a8ceeb9281d4cfc71515d6793d444d10a67acbb4f4ffbc4":
+ "Google “Aviator”",
+ c3bf03a7e1ca8841c607bae3ff4270fca5ec45b186ebbe4e2cf3fc778630f5f6:
+ "Google “Crucible”",
+ "1d024b8eb1498b344dfd87ea3efc0996f7506f235d1d497061a4773c439c25fb":
+ "Google “Daedalus”",
+ "293c519654c83965baaa50fc5807d4b76fbf587a2972dca4c30cf4e54547f478":
+ "Google “Icarus”",
+ a4b90990b418581487bb13a2cc67700a3c359804f91bdfb8e377cd0ec80ddc10:
+ "Google “Pilot”",
+ ee4bbdb775ce60bae142691fabe19e66a30f7e5fb072d88300c47b897aa8fdcb:
+ "Google “Rocketeer”",
+ bbd9dfbc1f8a71b593942397aa927b473857950aab52e81a909664368e1ed185:
+ "Google “Skydiver”",
+ "52eb4b225ec896974850675f23e43bc1d021e3214ce52ecd5fa87c203cdfca03":
+ "Google “Solera2018”",
+ "0b760e9a8b9a682f88985b15e947501a56446bba8830785c3842994386450c00":
+ "Google “Solera2019”",
+ "1fc72ce5a1b799f400c359bff96ca3913548e8644220610952e9ba1774f7bac7":
+ "Google “Solera2020”",
+ a3c99845e80ab7ce00157b3742df0207dd272b2b602ecf98ee2c12db9c5ae7e7:
+ "Google “Solera2021”",
+ "697aafca1a6b536fae21205046debad7e0eaea13d2432e6e9d8fb379f2b9aaf3":
+ "Google “Solera2022”",
+ a899d8780c9290aaf462f31880ccfbd52451e970d0fbf591ef75b0d99b645681:
+ "Google “Submariner”",
+ b0cc83e5a5f97d6baf7c09cc284904872ac7e88b132c6350b7c6fd26e16c6c77:
+ "Google “Testtube”",
+ b10cd559a6d67846811f7df9a51532739ac48d703bea0323da5d38755bc0ad4e:
+ "Google “Xenon2018”",
+ "084114980071532c16190460bcfc47fdc2653afa292c72b37ff863ae29ccc9f0":
+ "Google “Xenon2019”",
+ "07b75c1be57d68fff1b0c61d2315c7bae6577c5794b76aeebc613a1a69d3a21c":
+ "Google “Xenon2020”",
+ "7d3ef2f88fff88556824c2c0ca9e5289792bc50e78097f2e6a9768997e22f0d7":
+ "Google “Xenon2021”",
+ "46a555eb75fa912030b5a28969f4f37d112c4174befd49b885abf2fc70fe6d47":
+ "Google “Xenon2022”",
+ "7461b4a09cfb3d41d75159575b2e7649a445a8d27709b0cc564a6482b7eb41a3": "Izenpe",
+ "8941449c70742e06b9fc9ce7b116ba0024aa36d59af44f0204404f00f7ea8566":
+ "Izenpe “Argi”",
+ "296afa2d568bca0d2ea844956ae9721fc35fa355ecda99693aafd458a71aefdd":
+ "Let“s Encrypt ”Clicky”",
+ "537b69a3564335a9c04904e39593b2c298eb8d7a6e83023635c627248cd6b440":
+ "Nordu “flimsy”",
+ aae70b7f3cb8d566c86c2f16979c9f445f69ab0eb4535589b2f77a030104f3cd:
+ "Nordu “plausible”",
+ e0127629e90496564e3d0147984498aa48f8adb16600eb7902a1ef9909906273:
+ "PuChuangSiDa CT",
+ cf55e28923497c340d5206d05353aeb25834b52f1f8dc9526809f212efdd7ca6:
+ "SHECA CT 1",
+ "32dc59c2d4c41968d56e14bc61ac8f0e45db39faf3c155aa4252f5001fa0c623":
+ "SHECA CT 2",
+ db76fdadac65e7d09508886e2159bd8b90352f5fead3e3dc5e22eb350acc7b98:
+ "Sectigo (Comodo) “Dodo” CT",
+ "6f5376ac31f03119d89900a45115ff77151c11d902c10029068db2089a37d913":
+ "Sectigo (Comodo) “Mammoth” CT",
+ "5581d4c2169036014aea0b9b573c53f0c0e43878702508172fa3aa1d0713d30c":
+ "Sectigo (Comodo) “Sabre” CT",
+ "34bb6ad6c3df9c03eea8a499ff7891486c9d5e5cac92d01f7bfd1bce19db48ef":
+ "StartCom",
+ ddeb1d2b7a0d4fa6208b81ad8168707e2e8e9d01d55c888d3d11c4cdb6ecbecc: "Symantec",
+ a7ce4a4e6207e0addee5fdaa4b1f86768767b5d002a55d47310e7e670a95eab2:
+ "Symantec Deneb",
+ "15970488d7b997a05beb52512adee8d2e8b4a3165264121a9fabfbd5f85ad93f":
+ "Symantec “Sirius”",
+ bc78e1dfc5f63c684649334da10fa15f0979692009c081b4f3f6917f3ed9b8a5:
+ "Symantec “Vega”",
+ b0b784bc81c0ddc47544e883f05985bb9077d134d8ab88b2b2e533980b8e508b:
+ "Up In The Air “Behind the Sofa”",
+ ac3b9aed7fa9674757159e6d7d575672f9d98100941e9bdeffeca1313b75782d: "Venafi",
+ "03019df3fd85a69a8ebd1facc6da9ba73e469774fe77f579fc5a08b8328c1d6b":
+ "Venafi Gen2 CT",
+ "41b2dc2e89e63ce4af1ba7bb29bf68c6dee6f9f1cc047e30dffae3b3ba259263": "WoSign",
+ "63d0006026dde10bb0601f452446965ee2b6ea2cd4fbc95ac866a550af9075b7":
+ "WoSign 2",
+ "9e4ff73dc3ce220b69217c899e468076abf8d78636d5ccfc85a31a75628ba88b":
+ "WoSign CT #1",
+ "659b3350f43b12cc5ea5ab4ec765d3fde6c88243777778e72003f9eb2b8c3129":
+ "Let's Encrypt Oak 2019",
+ e712f2b0377e1a62fb8ec90c6184f1ea7b37cb561d11265bf3e0f34bf241546e:
+ "Let's Encrypt Oak 2020",
+ "9420bc1e8ed58d6c88731f828b222c0dd1da4d5e6c4f943d61db4e2f584da2c2":
+ "Let's Encrypt Oak 2021",
+ dfa55eab68824f1f6cadeeb85f4e3e5aeacda212a46a5e8e3b12c020445c2a73:
+ "Let's Encrypt Oak 2022",
+ b73efb24df9c4dba75f239c5ba58f46c5dfc42cf7a9f35c49e1d098125edb499:
+ "Let's Encrypt Oak 2023",
+ "849f5f7f58d2bf7b54ecbd74611cea45c49c98f1d6481bc6f69e8c174f24f3cf":
+ "Let's Encrypt Testflume 2019",
+ c63f2218c37d56a6aa06b596da8e53d4d7156d1e9bac8e44d2202de64d69d9dc:
+ "Let's Encrypt Testflume 2020",
+ "03edf1da9776b6f38c341e39ed9d707a7570369cf9844f327fe9e14138361b60":
+ "Let's Encrypt Testflume 2021",
+ "2327efda352510dbc019ef491ae3ff1cc5a479bce37878360ee318cffb64f8c8":
+ "Let's Encrypt Testflume 2022",
+ "5534b7ab5a6ac3a7cbeba65487b2a2d71b48f650fa17c5197c97a0cb2076f3c6":
+ "Let's Encrypt Testflume 2023",
+};
+
+const strings = {
+ ux: {
+ upload: "Upload Certificate",
+ },
+
+ names: {
+ // Directory Pilot Attributes
+ "0.9.2342.19200300.100.1.1": {
+ short: "uid",
+ long: "User ID",
+ },
+ "0.9.2342.19200300.100.1.25": {
+ short: "dc",
+ long: "Domain Component",
+ },
+
+ // PKCS-9
+ "1.2.840.113549.1.9.1": {
+ short: "e",
+ long: "Email Address",
+ },
+
+ // Incorporated Locations
+ "1.3.6.1.4.1.311.60.2.1.1": {
+ short: undefined,
+ long: "Inc. Locality",
+ },
+ "1.3.6.1.4.1.311.60.2.1.2": {
+ short: undefined,
+ long: "Inc. State / Province",
+ },
+ "1.3.6.1.4.1.311.60.2.1.3": {
+ short: undefined,
+ long: "Inc. Country",
+ },
+
+ // microsoft cryptographic extensions
+ "1.3.6.1.4.1.311.21.7": {
+ name: {
+ short: "Certificate Template",
+ long: "Microsoft Certificate Template",
+ },
+ },
+ "1.3.6.1.4.1.311.21.10": {
+ name: {
+ short: "Certificate Policies",
+ long: "Microsoft Certificate Policies",
+ },
+ },
+
+ // certificate extensions
+ "1.3.6.1.4.1.11129.2.4.2": {
+ name: {
+ short: "Embedded SCTs",
+ long: "Embedded Signed Certificate Timestamps",
+ },
+ },
+ "1.3.6.1.5.5.7.1.1": {
+ name: {
+ short: undefined,
+ long: "Authority Information Access",
+ },
+ },
+ "1.3.6.1.5.5.7.1.24": {
+ name: {
+ short: "OCSP Stapling",
+ long: "Online Certificate Status Protocol Stapling",
+ },
+ },
+
+ // X.500 attribute types
+ "2.5.4.1": {
+ short: undefined,
+ long: "Aliased Entry",
+ },
+ "2.5.4.2": {
+ short: undefined,
+ long: "Knowledge Information",
+ },
+ "2.5.4.3": {
+ short: "cn",
+ long: "Common Name",
+ },
+ "2.5.4.4": {
+ short: "sn",
+ long: "Surname",
+ },
+ "2.5.4.5": {
+ short: "serialNumber",
+ long: "Serial Number",
+ },
+ "2.5.4.6": {
+ short: "c",
+ long: "Country",
+ },
+ "2.5.4.7": {
+ short: "l",
+ long: "Locality",
+ },
+ "2.5.4.8": {
+ short: "s",
+ long: "State / Province",
+ },
+ "2.5.4.9": {
+ short: "street",
+ long: "Stress Address",
+ },
+ "2.5.4.10": {
+ short: "o",
+ long: "Organization",
+ },
+ "2.5.4.11": {
+ short: "ou",
+ long: "Organizational Unit",
+ },
+ "2.5.4.12": {
+ short: "t",
+ long: "Title",
+ },
+ "2.5.4.13": {
+ short: "description",
+ long: "Description",
+ },
+ "2.5.4.14": {
+ short: undefined,
+ long: "Search Guide",
+ },
+ "2.5.4.15": {
+ short: undefined,
+ long: "Business Category",
+ },
+ "2.5.4.16": {
+ short: undefined,
+ long: "Postal Address",
+ },
+ "2.5.4.17": {
+ short: "postalCode",
+ long: "Postal Code",
+ },
+ "2.5.4.18": {
+ short: "POBox",
+ long: "PO Box",
+ },
+ "2.5.4.19": {
+ short: undefined,
+ long: "Physical Delivery Office Name",
+ },
+ "2.5.4.20": {
+ short: "phone",
+ long: "Phone Number",
+ },
+ "2.5.4.21": {
+ short: undefined,
+ long: "Telex Number",
+ },
+ "2.5.4.22": {
+ short: undefined,
+ long: "Teletex Terminal Identifier",
+ },
+ "2.5.4.23": {
+ short: undefined,
+ long: "Fax Number",
+ },
+ "2.5.4.24": {
+ short: undefined,
+ long: "X.121 Address",
+ },
+ "2.5.4.25": {
+ short: undefined,
+ long: "International ISDN Number",
+ },
+ "2.5.4.26": {
+ short: undefined,
+ long: "Registered Address",
+ },
+ "2.5.4.27": {
+ short: undefined,
+ long: "Destination Indicator",
+ },
+ "2.5.4.28": {
+ short: undefined,
+ long: "Preferred Delivery Method",
+ },
+ "2.5.4.29": {
+ short: undefined,
+ long: "Presentation Address",
+ },
+ "2.5.4.30": {
+ short: undefined,
+ long: "Supported Application Context",
+ },
+ "2.5.4.31": {
+ short: undefined,
+ long: "Member",
+ },
+ "2.5.4.32": {
+ short: undefined,
+ long: "Owner",
+ },
+ "2.5.4.33": {
+ short: undefined,
+ long: "Role Occupant",
+ },
+ "2.5.4.34": {
+ short: undefined,
+ long: "See Also",
+ },
+ "2.5.4.35": {
+ short: undefined,
+ long: "User Password",
+ },
+ "2.5.4.36": {
+ short: undefined,
+ long: "User Certificate",
+ },
+ "2.5.4.37": {
+ short: undefined,
+ long: "CA Certificate",
+ },
+ "2.5.4.38": {
+ short: undefined,
+ long: "Authority Revocation List",
+ },
+ "2.5.4.39": {
+ short: undefined,
+ long: "Certificate Revocation List",
+ },
+ "2.5.4.40": {
+ short: undefined,
+ long: "Cross-certificate Pair",
+ },
+ "2.5.4.41": {
+ short: undefined,
+ long: "Name",
+ },
+ "2.5.4.42": {
+ short: "g",
+ long: "Given Name",
+ },
+ "2.5.4.43": {
+ short: "i",
+ long: "Initials",
+ },
+ "2.5.4.44": {
+ short: undefined,
+ long: "Generation Qualifier",
+ },
+ "2.5.4.45": {
+ short: undefined,
+ long: "Unique Identifier",
+ },
+ "2.5.4.46": {
+ short: undefined,
+ long: "DN Qualifier",
+ },
+ "2.5.4.47": {
+ short: undefined,
+ long: "Enhanced Search Guide",
+ },
+ "2.5.4.48": {
+ short: undefined,
+ long: "Protocol Information",
+ },
+ "2.5.4.49": {
+ short: "dn",
+ long: "Distinguished Name",
+ },
+ "2.5.4.50": {
+ short: undefined,
+ long: "Unique Member",
+ },
+ "2.5.4.51": {
+ short: undefined,
+ long: "House Identifier",
+ },
+ "2.5.4.52": {
+ short: undefined,
+ long: "Supported Algorithms",
+ },
+ "2.5.4.53": {
+ short: undefined,
+ long: "Delta Revocation List",
+ },
+ "2.5.4.58": {
+ short: undefined,
+ long: "Attribute Certificate Attribute", // huh
+ },
+ "2.5.4.65": {
+ short: undefined,
+ long: "Pseudonym",
+ },
+
+ // extensions
+ "2.5.29.14": {
+ name: {
+ short: "Subject Key ID",
+ long: "Subject Key Identifier",
+ },
+ },
+ "2.5.29.15": {
+ name: {
+ short: undefined,
+ long: "Key Usages",
+ },
+ },
+ "2.5.29.17": {
+ name: {
+ short: "Subject Alt Names",
+ long: "Subject Alternative Names",
+ },
+ },
+ "2.5.29.19": {
+ name: {
+ short: undefined,
+ long: "Basic Constraints",
+ },
+ },
+ "2.5.29.31": {
+ name: {
+ short: "CRL Endpoints",
+ long: "Certificate Revocation List Endpoints",
+ },
+ },
+ "2.5.29.32": {
+ name: {
+ short: undefined,
+ long: "Certificate Policies",
+ },
+ },
+ "2.5.29.35": {
+ name: {
+ short: "Authority Key ID",
+ long: "Authority Key Identifier",
+ },
+ },
+ "2.5.29.37": {
+ name: {
+ short: undefined,
+ long: "Extended Key Usages",
+ },
+ },
+ },
+
+ keyUsages: [
+ "CRL Signing",
+ "Certificate Signing",
+ "Key Agreement",
+ "Data Encipherment",
+ "Key Encipherment",
+ "Non-Repudiation",
+ "Digital Signature",
+ ],
+
+ san: [
+ "Other Name",
+ "RFC 822 Name",
+ "DNS Name",
+ "X.400 Address",
+ "Directory Name",
+ "EDI Party Name",
+ "URI",
+ "IP Address",
+ "Registered ID",
+ ],
+
+ eKU: {
+ "1.3.6.1.4.1.311.10.3.1": "Certificate Trust List (CTL) Signing",
+ "1.3.6.1.4.1.311.10.3.2": "Timestamp Signing",
+ "1.3.6.1.4.1.311.10.3.4": "EFS Encryption",
+ "1.3.6.1.4.1.311.10.3.4.1": "EFS Recovery",
+ "1.3.6.1.4.1.311.10.3.5":
+ "Windows Hardware Quality Labs (WHQL) Cryptography",
+ "1.3.6.1.4.1.311.10.3.7": "Windows NT 5 Cryptography",
+ "1.3.6.1.4.1.311.10.3.8": "Windows NT Embedded Cryptography",
+ "1.3.6.1.4.1.311.10.3.10": "Qualified Subordination",
+ "1.3.6.1.4.1.311.10.3.11": "Escrowed Key Recovery",
+ "1.3.6.1.4.1.311.10.3.12": "Document Signing",
+ "1.3.6.1.4.1.311.10.5.1": "Digital Rights Management",
+ "1.3.6.1.4.1.311.10.6.1": "Key Pack Licenses",
+ "1.3.6.1.4.1.311.10.6.2": "License Server",
+ "1.3.6.1.4.1.311.20.2.1": "Enrollment Agent",
+ "1.3.6.1.4.1.311.20.2.2": "Smartcard Login",
+ "1.3.6.1.4.1.311.21.5": "Certificate Authority Private Key Archival",
+ "1.3.6.1.4.1.311.21.6": "Key Recovery Agent",
+ "1.3.6.1.4.1.311.21.19": "Directory Service Email Replication",
+ "1.3.6.1.5.5.7.3.1": "Server Authentication",
+ "1.3.6.1.5.5.7.3.2": "Client Authentication",
+ "1.3.6.1.5.5.7.3.3": "Code Signing",
+ "1.3.6.1.5.5.7.3.4": "E-mail Protection",
+ "1.3.6.1.5.5.7.3.5": "IPsec End System",
+ "1.3.6.1.5.5.7.3.6": "IPsec Tunnel",
+ "1.3.6.1.5.5.7.3.7": "IPSec User",
+ "1.3.6.1.5.5.7.3.8": "Timestamping",
+ "1.3.6.1.5.5.7.3.9": "OCSP Signing",
+ "1.3.6.1.5.5.8.2.2": "Internet Key Exchange (IKE)",
+ },
+
+ signature: {
+ "1.2.840.113549.1.1.4": "MD5 with RSA Encryption",
+ "1.2.840.113549.1.1.5": "SHA-1 with RSA Encryption",
+ "1.2.840.113549.1.1.11": "SHA-256 with RSA Encryption",
+ "1.2.840.113549.1.1.12": "SHA-384 with RSA Encryption",
+ "1.2.840.113549.1.1.13": "SHA-512 with RSA Encryption",
+ "1.2.840.10040.4.3": "DSA with SHA-1",
+ "2.16.840.1.101.3.4.3.2": "DSA with SHA-256",
+ "1.2.840.10045.4.1": "ECDSA with SHA-1",
+ "1.2.840.10045.4.3.2": "ECDSA with SHA-256",
+ "1.2.840.10045.4.3.3": "ECDSA with SHA-384",
+ "1.2.840.10045.4.3.4": "ECDSA with SHA-512",
+ },
+
+ aia: {
+ "1.3.6.1.5.5.7.48.1": "Online Certificate Status Protocol (OCSP)",
+ "1.3.6.1.5.5.7.48.2": "CA Issuers",
+ },
+
+ // this includes qualifiers as well
+ cps: {
+ "1.3.6.1.4.1": {
+ name: "Statement Identifier",
+ value: undefined,
+ },
+ "1.3.6.1.5.5.7.2.1": {
+ name: "Practices Statement",
+ value: undefined,
+ },
+ "1.3.6.1.5.5.7.2.2": {
+ name: "User Notice",
+ value: undefined,
+ },
+ "2.16.840": {
+ name: "ANSI Organizational Identifier",
+ value: undefined,
+ },
+ "2.23.140.1.1": {
+ name: "Certificate Type",
+ value: "Extended Validation",
+ },
+ "2.23.140.1.2.1": {
+ name: "Certificate Type",
+ value: "Domain Validation",
+ },
+ "2.23.140.1.2.2": {
+ name: "Certificate Type",
+ value: "Organization Validation",
+ },
+ "2.23.140.1.2.3": {
+ name: "Certificate Type",
+ value: "Individual Validation",
+ },
+ "2.23.140.1.3": {
+ name: "Certificate Type",
+ value: "Extended Validation (Code Signing)",
+ },
+ "2.23.140.1.31": {
+ name: "Certificate Type",
+ value: ".onion Extended Validation",
+ },
+ "2.23.140.2.1": {
+ name: "Certificate Type",
+ value: "Test Certificate",
+ },
+ },
+
+ microsoftCertificateTypes: {
+ Administrator: "Administrator",
+ CA: "Root Certification Authority",
+ CAExchange: "CA Exchange",
+ CEPEncryption: "CEP Encryption",
+ CertificateRequestAgent: "Certificate Request Agent",
+ ClientAuth: "Authenticated Session",
+ CodeSigning: "Code Signing",
+ CrossCA: "Cross Certification Authority",
+ CTLSigning: "Trust List Signing",
+ DirectoryEmailReplication: "Directory Email Replication",
+ DomainController: "Domain Controller",
+ DomainControllerAuthentication: "Domain Controller Authentication",
+ EFS: "Basic EFS",
+ EFSRecovery: "EFS Recovery Agent",
+ EnrollmentAgent: "Enrollment Agent",
+ EnrollmentAgentOffline: "Exchange Enrollment Agent (Offline request)",
+ ExchangeUser: "Exchange User",
+ ExchangeUserSignature: "Exchange Signature Only",
+ IPSECIntermediateOffline: "IPSec (Offline request)",
+ IPSECIntermediateOnline: "IPSEC",
+ KerberosAuthentication: "Kerberos Authentication",
+ KeyRecoveryAgent: "Key Recovery Agent",
+ Machine: "Computer",
+ MachineEnrollmentAgent: "Enrollment Agent (Computer)",
+ OCSPResponseSigning: "OCSP Response Signing",
+ OfflineRouter: "Router (Offline request)",
+ RASAndIASServer: "RAS and IAS Server",
+ SmartcardLogon: "Smartcard Logon",
+ SmartcardUser: "Smartcard User",
+ SubCA: "Subordinate Certification Authority",
+ User: "User",
+ UserSignature: "User Signature Only",
+ WebServer: "Web Server",
+ Workstation: "Workstation Authentication",
+ },
+};
+
+function stringToArrayBuffer(string) {
+ let result = new Uint8Array(string.length);
+ for (let i = 0; i < string.length; i++) {
+ result[i] = string.charCodeAt(i);
+ }
+ return result;
+}
+
+// this particular prototype override makes it easy to chain down complex objects
+const getObjPath = (obj, path) => {
+ path = path.split(".");
+ for (let i = 0, len = path.length; i < len; i++) {
+ if (Array.isArray(obj[path[i]])) {
+ obj = obj[path[i]][path[i + 1]];
+ i++;
+ } else {
+ obj = obj[path[i]];
+ }
+ }
+ return obj;
+};
+
+const arrayBufferToHex = arrayBuffer => {
+ const array = Array.from(new Uint8Array(arrayBuffer));
+
+ return array
+ .map(b => ("00" + b.toString(16)).slice(-2))
+ .join(":")
+ .toUpperCase();
+};
+
+const hash = async (algo, buffer) => {
+ const hashBuffer = await crypto.subtle.digest(algo, buffer);
+ return arrayBufferToHex(hashBuffer);
+};
+
+const hashify = rawHash => {
+ if (typeof rawHash === "string") {
+ return rawHash.match(/.{2}/g).join(":").toUpperCase();
+ }
+ if (rawHash instanceof ArrayBuffer) {
+ return arrayBufferToHex(rawHash);
+ }
+ return rawHash.join(":").toUpperCase();
+};
+
+export const pemToDER = pem => {
+ return stringToArrayBuffer(atob(pem));
+};
diff --git a/toolkit/components/certviewer/content/certviewer.css b/toolkit/components/certviewer/content/certviewer.css
new file mode 100644
index 0000000000..1d5bd52917
--- /dev/null
+++ b/toolkit/components/certviewer/content/certviewer.css
@@ -0,0 +1,8 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+body {
+ max-width: 800px;
+ margin: 0 auto;
+}
diff --git a/toolkit/components/certviewer/content/certviewer.html b/toolkit/components/certviewer/content/certviewer.html
new file mode 100644
index 0000000000..661fa6b0d9
--- /dev/null
+++ b/toolkit/components/certviewer/content/certviewer.html
@@ -0,0 +1,113 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<!DOCTYPE html>
+
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width" />
+ <meta
+ http-equiv="Content-Security-Policy"
+ content="default-src chrome:; object-src 'none'"
+ />
+ <meta name="color-scheme" content="light dark" />
+ <link rel="localization" href="toolkit/about/certviewer.ftl" />
+ <link rel="localization" href="branding/brand.ftl" />
+ <script
+ type="module"
+ src="chrome://global/content/certviewer/certviewer.mjs"
+ ></script>
+ <script
+ type="module"
+ src="chrome://global/content/certviewer/components/certificate-section.mjs"
+ ></script>
+ <script
+ type="module"
+ src="chrome://global/content/certviewer/components/about-certificate-section.mjs"
+ ></script>
+ <link rel="stylesheet" href="chrome://global/skin/in-content/common.css" />
+ <link
+ rel="stylesheet"
+ href="chrome://global/content/certviewer/certviewer.css"
+ />
+ <title id="certTitle">about:certificate</title>
+ </head>
+ <body>
+ <template id="certificate-section-template" class="section">
+ <link
+ rel="stylesheet"
+ href="chrome://global/content/certviewer/components/certificate-section.css"
+ />
+ <h1 class="title"></h1>
+ </template>
+
+ <template id="certificate-tabs-template">
+ <div class="certificate-tabs" role="tablist"></div>
+ </template>
+
+ <template id="info-groups-template"> </template>
+
+ <template id="info-item-template">
+ <link
+ rel="stylesheet"
+ href="chrome://global/skin/in-content/common.css"
+ />
+ <link
+ rel="stylesheet"
+ href="chrome://global/content/certviewer/components/info-item.css"
+ />
+ <label></label>
+ <span class="info"></span>
+ </template>
+
+ <template id="info-group-template">
+ <link
+ rel="stylesheet"
+ href="chrome://global/content/certviewer/components/info-group.css"
+ />
+ <span class="extension">
+ <img
+ src="chrome://global/skin/icons/error.svg"
+ id="critical-info"
+ data-l10n-id="certificate-viewer-critical-extension"
+ />
+ <h2 class="info-group-title"></h2>
+ </span>
+ <span class="info-group-title-hr"></span>
+ </template>
+
+ <template id="error-section-template">
+ <link
+ rel="stylesheet"
+ href="chrome://global/content/certviewer/components/error-section.css"
+ />
+ <h1 class="title"></h1>
+ <span class="error"></span>
+ </template>
+
+ <template id="about-certificate-template" class="section">
+ <link
+ rel="stylesheet"
+ href="chrome://global/content/certviewer/components/certificate-section.css"
+ />
+ <h1 class="title"></h1>
+ </template>
+
+ <template id="about-certificate-items-template">
+ <link
+ rel="stylesheet"
+ href="chrome://global/content/certviewer/components/about-certificate-section.css"
+ />
+ </template>
+
+ <template id="list-item-template">
+ <link
+ rel="stylesheet"
+ href="chrome://global/content/certviewer/components/list-item.css"
+ />
+ <a class="cert-url"><span class="item-name"></span></a>
+ <button class="export"></button>
+ </template>
+ </body>
+</html>
diff --git a/toolkit/components/certviewer/content/certviewer.mjs b/toolkit/components/certviewer/content/certviewer.mjs
new file mode 100644
index 0000000000..3e48a069f5
--- /dev/null
+++ b/toolkit/components/certviewer/content/certviewer.mjs
@@ -0,0 +1,475 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* eslint-env mozilla/remote-page */
+
+import { normalizeToKebabCase } from "./components/utils.mjs";
+import {
+ parse,
+ pemToDER,
+} from "chrome://global/content/certviewer/certDecoder.mjs";
+
+document.addEventListener("DOMContentLoaded", async e => {
+ let url = new URL(document.URL);
+ let certInfo = url.searchParams.getAll("cert");
+ if (certInfo.length === 0) {
+ render({}, false, true);
+ return;
+ }
+ certInfo = certInfo.map(cert => decodeURIComponent(cert));
+ await buildChain(certInfo);
+});
+
+export const updateSelectedItem = (() => {
+ let state;
+ return selectedItem => {
+ let certificateSection =
+ document.querySelector("certificate-section") ||
+ document.querySelector("about-certificate-section");
+ if (selectedItem) {
+ if (state !== selectedItem) {
+ state = selectedItem;
+ certificateSection.updateCertificateSource(selectedItem);
+ certificateSection.updateSelectedTab(selectedItem);
+ }
+ }
+ return state;
+ };
+})();
+
+const createEntryItem = (labelId, info, isHex = false) => {
+ if (
+ labelId == null ||
+ info == null ||
+ (Array.isArray(info) && !info.length)
+ ) {
+ return null;
+ }
+ return {
+ labelId,
+ info,
+ isHex,
+ };
+};
+
+const addToResultUsing = (callback, certItems, sectionId, Critical) => {
+ let items = callback();
+ if (items.length) {
+ certItems.push({
+ sectionId,
+ sectionItems: items,
+ Critical,
+ });
+ }
+};
+
+const getElementByPathOrFalse = (obj, pathString) => {
+ let pathArray = pathString.split(".");
+ let result = obj;
+ for (let entry of pathArray) {
+ result = result[entry];
+ if (result == null) {
+ return false;
+ }
+ }
+ return result ? result : false;
+};
+
+export const adjustCertInformation = cert => {
+ let certItems = [];
+ let tabName = cert?.subject?.cn || "";
+ if (cert && !tabName) {
+ // No common name, use the value of the last item in the cert's entries.
+ tabName = cert.subject?.entries?.slice(-1)[0]?.[1] || "";
+ }
+
+ if (!cert) {
+ return {
+ certItems,
+ tabName,
+ };
+ }
+
+ addToResultUsing(
+ () => {
+ let items = [];
+ if (cert.subject && cert.subject.entries) {
+ items = cert.subject.entries
+ .map(entry =>
+ createEntryItem(normalizeToKebabCase(entry[0]), entry[1])
+ )
+ .filter(elem => elem != null);
+ }
+ return items;
+ },
+ certItems,
+ "subject-name",
+ false
+ );
+
+ addToResultUsing(
+ () => {
+ let items = [];
+ if (cert.issuer && cert.issuer.entries) {
+ items = cert.issuer.entries
+ .map(entry =>
+ createEntryItem(normalizeToKebabCase(entry[0]), entry[1])
+ )
+ .filter(elem => elem != null);
+ }
+ return items;
+ },
+ certItems,
+ "issuer-name",
+ false
+ );
+
+ addToResultUsing(
+ () => {
+ let items = [];
+ if (cert.notBefore && cert.notAfter) {
+ items = [
+ createEntryItem("not-before", {
+ local: cert.notBefore,
+ utc: cert.notBeforeUTC,
+ }),
+ createEntryItem("not-after", {
+ local: cert.notAfter,
+ utc: cert.notAfterUTC,
+ }),
+ ].filter(elem => elem != null);
+ }
+ return items;
+ },
+ certItems,
+ "validity",
+ false
+ );
+
+ addToResultUsing(
+ () => {
+ let items = [];
+ if (cert.ext && cert.ext.san && cert.ext.san.altNames) {
+ items = cert.ext.san.altNames
+ .map(entry =>
+ createEntryItem(normalizeToKebabCase(entry[0]), entry[1])
+ )
+ .filter(elem => elem != null);
+ }
+ return items;
+ },
+ certItems,
+ "subject-alt-names",
+ getElementByPathOrFalse(cert, "ext.san.critical")
+ );
+
+ addToResultUsing(
+ () => {
+ let items = [];
+ if (cert.subjectPublicKeyInfo) {
+ items = [
+ createEntryItem("algorithm", cert.subjectPublicKeyInfo.kty),
+ createEntryItem("key-size", cert.subjectPublicKeyInfo.keysize),
+ createEntryItem("curve", cert.subjectPublicKeyInfo.crv),
+ createEntryItem("public-value", cert.subjectPublicKeyInfo.xy, true),
+ createEntryItem("exponent", cert.subjectPublicKeyInfo.e),
+ createEntryItem("modulus", cert.subjectPublicKeyInfo.n, true),
+ ].filter(elem => elem != null);
+ }
+ return items;
+ },
+ certItems,
+ "public-key-info",
+ false
+ );
+
+ addToResultUsing(
+ () => {
+ let items = [
+ createEntryItem("serial-number", cert.serialNumber, true),
+ createEntryItem(
+ "signature-algorithm",
+ cert.signature ? cert.signature.name : null
+ ),
+ createEntryItem("version", cert.version),
+ createEntryItem("download", cert.files ? cert.files.pem : null),
+ ].filter(elem => elem != null);
+ return items;
+ },
+ certItems,
+ "miscellaneous",
+ false
+ );
+
+ addToResultUsing(
+ () => {
+ let items = [];
+ if (cert.fingerprint) {
+ items = [
+ createEntryItem("sha-256", cert.fingerprint.sha256, true),
+ createEntryItem("sha-1", cert.fingerprint.sha1, true),
+ ].filter(elem => elem != null);
+ }
+ return items;
+ },
+ certItems,
+ "fingerprints",
+ false
+ );
+
+ if (!cert.ext) {
+ return {
+ certItems,
+ tabName,
+ };
+ }
+
+ addToResultUsing(
+ () => {
+ let items = [];
+ if (cert.ext.basicConstraints) {
+ items = [
+ createEntryItem(
+ "certificate-authority",
+ cert.ext.basicConstraints.cA
+ ),
+ ].filter(elem => elem != null);
+ }
+ return items;
+ },
+ certItems,
+ "basic-constraints",
+ getElementByPathOrFalse(cert, "ext.basicConstraints.critical")
+ );
+
+ addToResultUsing(
+ () => {
+ let items = [];
+ if (cert.ext.keyUsages) {
+ items = [
+ createEntryItem("purposes", cert.ext.keyUsages.purposes),
+ ].filter(elem => elem != null);
+ }
+ return items;
+ },
+ certItems,
+ "key-usages",
+ getElementByPathOrFalse(cert, "ext.keyUsages.critical")
+ );
+
+ addToResultUsing(
+ () => {
+ let items = [];
+ if (cert.ext.eKeyUsages) {
+ items = [
+ createEntryItem("purposes", cert.ext.eKeyUsages.purposes),
+ ].filter(elem => elem != null);
+ }
+ return items;
+ },
+ certItems,
+ "extended-key-usages",
+ getElementByPathOrFalse(cert, "ext.eKeyUsages.critical")
+ );
+
+ addToResultUsing(
+ () => {
+ let items = [];
+ if (cert.ext.ocspStaple && cert.ext.ocspStaple.required) {
+ items = [createEntryItem("required", true)];
+ }
+ return items;
+ },
+ certItems,
+ "ocsp-stapling",
+ getElementByPathOrFalse(cert, "ext.ocspStaple.critical")
+ );
+
+ addToResultUsing(
+ () => {
+ let items = [];
+ if (cert.ext.sKID) {
+ items = [createEntryItem("key-id", cert.ext.sKID.id, true)].filter(
+ elem => elem != null
+ );
+ }
+ return items;
+ },
+ certItems,
+ "subject-key-id",
+ getElementByPathOrFalse(cert, "ext.sKID.critical")
+ );
+
+ addToResultUsing(
+ () => {
+ let items = [];
+ if (cert.ext.aKID) {
+ items = [createEntryItem("key-id", cert.ext.aKID.id, true)].filter(
+ elem => elem != null
+ );
+ }
+ return items;
+ },
+ certItems,
+ "authority-key-id",
+ getElementByPathOrFalse(cert, "ext.aKID.critical")
+ );
+
+ addToResultUsing(
+ () => {
+ let items = [];
+ if (cert.ext.crlPoints && cert.ext.crlPoints.points) {
+ items = cert.ext.crlPoints.points
+ .map(entry => {
+ let label = "distribution-point";
+ return createEntryItem(label, entry);
+ })
+ .filter(elem => elem != null);
+ }
+ return items;
+ },
+ certItems,
+ "crl-endpoints",
+ getElementByPathOrFalse(cert, "ext.crlPoints.critical")
+ );
+
+ addToResultUsing(
+ () => {
+ let items = [];
+ if (cert.ext.aia && cert.ext.aia.descriptions) {
+ cert.ext.aia.descriptions.forEach(entry => {
+ items.push(createEntryItem("location", entry.location));
+ items.push(createEntryItem("method", entry.method));
+ });
+ }
+ return items.filter(elem => elem != null);
+ },
+ certItems,
+ "authority-info-aia",
+ getElementByPathOrFalse(cert, "ext.aia.critical")
+ );
+
+ addToResultUsing(
+ () => {
+ let items = [];
+ if (cert.ext.cp && cert.ext.cp.policies) {
+ cert.ext.cp.policies.forEach(entry => {
+ if (entry.name && entry.id) {
+ items.push(
+ createEntryItem("policy", entry.name + " ( " + entry.id + " )")
+ );
+ }
+ items.push(createEntryItem("value", entry.value));
+ if (entry.qualifiers) {
+ entry.qualifiers.forEach(qualifier => {
+ if (qualifier.qualifierName && qualifier.qualifierId) {
+ items.push(
+ createEntryItem(
+ "qualifier",
+ qualifier.qualifierName +
+ " ( " +
+ qualifier.qualifierId +
+ " )"
+ )
+ );
+ }
+ items.push(createEntryItem("value", qualifier.qualifierValue));
+ });
+ }
+ });
+ }
+ return items.filter(elem => elem != null);
+ },
+ certItems,
+ "certificate-policies",
+ getElementByPathOrFalse(cert, "ext.cp.critical")
+ );
+
+ addToResultUsing(
+ () => {
+ let items = [];
+ if (cert.ext.scts && cert.ext.scts.timestamps) {
+ cert.ext.scts.timestamps.forEach(entry => {
+ let timestamps = {};
+ for (let key of Object.keys(entry)) {
+ if (key.includes("timestamp")) {
+ timestamps[key.includes("UTC") ? "utc" : "local"] = entry[key];
+ } else {
+ let isHex = false;
+ if (key == "logId") {
+ isHex = true;
+ }
+ items.push(
+ createEntryItem(normalizeToKebabCase(key), entry[key], isHex)
+ );
+ }
+ }
+ items.push(createEntryItem("timestamp", timestamps));
+ });
+ }
+ return items.filter(elem => elem != null);
+ },
+ certItems,
+ "embedded-scts",
+ getElementByPathOrFalse(cert, "ext.scts.critical")
+ );
+
+ return {
+ certItems,
+ tabName,
+ };
+};
+
+// isAboutCertificate means to the standalone page about:certificate, which
+// uses a different customElement than opening a certain certificate
+const render = async (certs, error, isAboutCertificate = false) => {
+ if (isAboutCertificate) {
+ await customElements.whenDefined("about-certificate-section");
+ const AboutCertificateSection = customElements.get(
+ "about-certificate-section"
+ );
+ document.querySelector("body").append(new AboutCertificateSection());
+ } else {
+ await customElements.whenDefined("certificate-section");
+ const CertificateSection = customElements.get("certificate-section");
+ document.querySelector("body").append(new CertificateSection(certs, error));
+ }
+ return Promise.resolve();
+};
+
+const buildChain = async chain => {
+ await Promise.all(
+ chain
+ .map(cert => {
+ try {
+ return pemToDER(cert);
+ } catch (err) {
+ return Promise.reject(err);
+ }
+ })
+ .map(cert => {
+ try {
+ return parse(cert);
+ } catch (err) {
+ return Promise.reject(err);
+ }
+ })
+ )
+ .then(certs => {
+ if (certs.length === 0) {
+ return Promise.reject();
+ }
+ let certTitle = document.querySelector("#certTitle");
+ let firstCertCommonName = certs[0].subject.cn;
+ document.l10n.setAttributes(certTitle, "certificate-viewer-tab-title", {
+ firstCertName: firstCertCommonName,
+ });
+
+ let adjustedCerts = certs.map(cert => adjustCertInformation(cert));
+ return render(adjustedCerts, false);
+ })
+ .catch(err => {
+ render(null, true);
+ });
+};
diff --git a/toolkit/components/certviewer/content/components/about-certificate-items.mjs b/toolkit/components/certviewer/content/components/about-certificate-items.mjs
new file mode 100644
index 0000000000..9fa856c61e
--- /dev/null
+++ b/toolkit/components/certviewer/content/components/about-certificate-items.mjs
@@ -0,0 +1,33 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* eslint-env mozilla/remote-page */
+
+import { ListItem } from "./list-item.mjs";
+
+export class AboutCertificateItems extends HTMLElement {
+ constructor(id, data) {
+ super();
+ this.id = id;
+ this.data = data;
+ }
+
+ connectedCallback() {
+ let template = document.getElementById("about-certificate-items-template");
+ let templateHtml = template.content.cloneNode(true);
+
+ this.attachShadow({ mode: "open" }).appendChild(templateHtml);
+
+ document.l10n.connectRoot(this.shadowRoot);
+
+ this.render();
+ }
+
+ render() {
+ for (let cert of this.data) {
+ this.shadowRoot.append(new ListItem(cert));
+ }
+ }
+}
+customElements.define("about-certificate-items", AboutCertificateItems);
diff --git a/toolkit/components/certviewer/content/components/about-certificate-section.css b/toolkit/components/certviewer/content/components/about-certificate-section.css
new file mode 100644
index 0000000000..4f472b57d5
--- /dev/null
+++ b/toolkit/components/certviewer/content/components/about-certificate-section.css
@@ -0,0 +1,7 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+:host {
+ margin: 2em;
+}
diff --git a/toolkit/components/certviewer/content/components/about-certificate-section.mjs b/toolkit/components/certviewer/content/components/about-certificate-section.mjs
new file mode 100644
index 0000000000..26c82a5c9a
--- /dev/null
+++ b/toolkit/components/certviewer/content/components/about-certificate-section.mjs
@@ -0,0 +1,114 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* eslint-env mozilla/remote-page */
+
+import { InfoGroupContainer } from "./info-group-container.mjs";
+import { CertificateTabsSection } from "./certificate-tabs-section.mjs";
+
+const TYPE_CA = 1;
+const TYPE_USER = 2;
+const TYPE_EMAIL = 4;
+const TYPE_SERVER = 8;
+
+export class AboutCertificateSection extends HTMLElement {
+ constructor() {
+ super();
+ }
+
+ connectedCallback() {
+ let template = document.getElementById("about-certificate-template");
+ let templateHtml = template.content.cloneNode(true);
+
+ this.attachShadow({ mode: "open" }).appendChild(templateHtml);
+
+ document.l10n.connectRoot(this.shadowRoot);
+
+ this.certificateTabsSection = new CertificateTabsSection(true);
+ this.shadowRoot.appendChild(this.certificateTabsSection.tabsElement);
+ this.infoGroupsContainers = new InfoGroupContainer(true);
+
+ this.render();
+ }
+
+ render() {
+ RPMSendQuery("getCertificates").then(this.filterCerts.bind(this));
+
+ let title = this.shadowRoot.querySelector(".title");
+ document.l10n.setAttributes(
+ title,
+ "certificate-viewer-certificate-section-title"
+ );
+ }
+
+ filterCerts(srcCerts) {
+ let certs = [];
+ if (srcCerts[TYPE_USER].length) {
+ certs.push({
+ name: "certificate-viewer-tab-mine",
+ data: srcCerts[TYPE_USER],
+ });
+ }
+ if (srcCerts[TYPE_EMAIL].length) {
+ certs.push({
+ name: "certificate-viewer-tab-people",
+ data: srcCerts[TYPE_EMAIL],
+ });
+ }
+ if (srcCerts[TYPE_SERVER].length) {
+ certs.push({
+ name: "certificate-viewer-tab-servers",
+ data: srcCerts[TYPE_SERVER],
+ });
+ }
+ if (srcCerts[TYPE_CA].length) {
+ certs.push({
+ name: "certificate-viewer-tab-ca",
+ data: srcCerts[TYPE_CA],
+ });
+ }
+
+ let i = 0;
+ for (let cert of certs) {
+ let final = i == certs.length - 1;
+ this.infoGroupsContainers.createInfoGroupsContainers({}, i, final, cert);
+ this.shadowRoot.appendChild(
+ this.infoGroupsContainers.infoGroupsContainers[i]
+ );
+ this.certificateTabsSection.createTabSection(cert.name, i);
+ this.infoGroupsContainers.addClass("selected", 0);
+ i++;
+ }
+ this.setAccessibilityEventListeners();
+ this.addClassForPadding();
+ }
+
+ // Adds class selector for items that need padding,
+ // as nth-child/parent-based selectors aren't supported
+ // due to the encapsulation of custom-element CSS.
+ addClassForPadding() {
+ let embeddedScts = this.shadowRoot.querySelector(".embedded-scts");
+ if (!embeddedScts) {
+ return;
+ }
+ let items = embeddedScts.shadowRoot.querySelectorAll(".timestamp");
+
+ for (let i = 0; i < items.length; i++) {
+ items[i].classList.add("padding");
+ }
+ }
+
+ setAccessibilityEventListeners() {
+ this.certificateTabsSection.setAccessibilityEventListeners();
+ }
+
+ updateSelectedTab(index) {
+ this.certificateTabsSection.updateSelectedTab(index);
+ }
+
+ updateCertificateSource(index) {
+ this.infoGroupsContainers.updateCertificateSource(index);
+ }
+}
+customElements.define("about-certificate-section", AboutCertificateSection);
diff --git a/toolkit/components/certviewer/content/components/certificate-section.css b/toolkit/components/certviewer/content/components/certificate-section.css
new file mode 100644
index 0000000000..1e57a65b4d
--- /dev/null
+++ b/toolkit/components/certviewer/content/components/certificate-section.css
@@ -0,0 +1,72 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+@import url("chrome://global/skin/design-system/text-and-typography.css");
+
+h1 {
+ margin: 3em 0 1em;
+}
+
+.certificate-tabs {
+ display: flex;
+ text-align: center;
+ border-bottom: 1px solid var(--in-content-border-color);
+ box-shadow: var(--card-shadow);
+}
+
+.info-groups {
+ display: none;
+ outline: none;
+ background-color: var(--in-content-box-background);
+ box-shadow: var(--card-shadow);
+ margin-bottom: 2em;
+ border-radius: 0 0 4px 4px;
+}
+
+.info-groups.selected {
+ display: block;
+}
+
+.tab {
+ margin: 0;
+ border-radius: 0;
+ padding: 18px;
+ padding-bottom: 15px; /* compensate for border-bottom below */
+ border: none;
+ border-bottom: 3px solid transparent;
+ background-color: var(--in-content-box-background);
+ color: var(--in-content-text-color);
+ flex: 1 1 auto;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ font-size: 1.1em;
+}
+
+/* .tab can be LTR (by `dir="auto"`) for `about:certificate?cert=`
+ pages, so set the border-radius according to the parent's direction. */
+.certificate-tabs:dir(rtl) > .tab:first-of-type,
+.certificate-tabs:dir(ltr) > .tab:last-of-type {
+ border-top-right-radius: 4px;
+}
+
+.certificate-tabs:dir(ltr) > .tab:first-of-type,
+.certificate-tabs:dir(rtl) > .tab:last-of-type {
+ border-top-left-radius: 4px;
+}
+
+.certificate-tab:focus-visible {
+ z-index: 1;
+ outline: 2px solid var(--in-content-focus-outline-color);
+}
+
+.tab:hover {
+ border-bottom-color: var(--in-content-border-color);
+}
+
+.tab.selected {
+ border-bottom-color: currentColor;
+ color: var(--in-content-accent-color);
+ text-overflow: unset;
+ overflow: visible;
+}
diff --git a/toolkit/components/certviewer/content/components/certificate-section.mjs b/toolkit/components/certviewer/content/components/certificate-section.mjs
new file mode 100644
index 0000000000..65e8741994
--- /dev/null
+++ b/toolkit/components/certviewer/content/components/certificate-section.mjs
@@ -0,0 +1,93 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import { ErrorSection } from "./error-section.mjs";
+import { InfoGroupContainer } from "./info-group-container.mjs";
+import { CertificateTabsSection } from "./certificate-tabs-section.mjs";
+
+class CertificateSection extends HTMLElement {
+ constructor(certs, error) {
+ super();
+ this.certs = certs;
+ this.error = error;
+ }
+
+ connectedCallback() {
+ // Attach and connect before adding the template, or fluent
+ // won't translate the template copy we insert into the
+ // shadowroot.
+ this.attachShadow({ mode: "open" });
+ document.l10n.connectRoot(this.shadowRoot);
+
+ let template = document.getElementById("certificate-section-template");
+ let templateHtml = template.content.cloneNode(true);
+ this.shadowRoot.appendChild(templateHtml);
+
+ this.certificateTabsSection = new CertificateTabsSection();
+ this.shadowRoot.appendChild(this.certificateTabsSection.tabsElement);
+ this.infoGroupsContainers = new InfoGroupContainer();
+
+ this.render();
+ }
+
+ render() {
+ let title = this.shadowRoot.querySelector(".title");
+ document.l10n.setAttributes(
+ title,
+ "certificate-viewer-certificate-section-title"
+ );
+
+ if (this.error) {
+ title.classList.add("error");
+ this.certificateTabsSection.appendChild(new ErrorSection());
+ return;
+ }
+ let final = false;
+ for (let i = 0; i < this.certs.length; i++) {
+ if (i === this.certs.length - 1) {
+ final = true;
+ }
+ this.infoGroupsContainers.createInfoGroupsContainers(
+ this.certs[i].certItems,
+ i,
+ final
+ );
+ this.shadowRoot.appendChild(
+ this.infoGroupsContainers.infoGroupsContainers[i]
+ );
+ this.certificateTabsSection.createTabSection(this.certs[i].tabName, i);
+ this.infoGroupsContainers.addClass("selected", 0);
+ }
+ this.setAccessibilityEventListeners();
+ this.addClassForPadding();
+ }
+
+ // Adds class selector for items that need padding,
+ // as nth-child/parent-based selectors aren't supported
+ // due to the encapsulation of custom-element CSS.
+ addClassForPadding() {
+ let embeddedScts = this.shadowRoot.querySelector(".embedded-scts");
+ if (!embeddedScts) {
+ return;
+ }
+ let items = embeddedScts.shadowRoot.querySelectorAll(".timestamp");
+
+ for (let i = 0; i < items.length; i++) {
+ items[i].classList.add("padding");
+ }
+ }
+
+ setAccessibilityEventListeners() {
+ this.certificateTabsSection.setAccessibilityEventListeners();
+ }
+
+ updateSelectedTab(index) {
+ this.certificateTabsSection.updateSelectedTab(index);
+ }
+
+ updateCertificateSource(index) {
+ this.infoGroupsContainers.updateCertificateSource(index);
+ }
+}
+customElements.define("certificate-section", CertificateSection);
diff --git a/toolkit/components/certviewer/content/components/certificate-tabs-section.mjs b/toolkit/components/certviewer/content/components/certificate-tabs-section.mjs
new file mode 100644
index 0000000000..f9837e3d3e
--- /dev/null
+++ b/toolkit/components/certviewer/content/components/certificate-tabs-section.mjs
@@ -0,0 +1,123 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import { normalizeToKebabCase } from "./utils.mjs";
+import { updateSelectedItem } from "../certviewer.mjs";
+
+export class CertificateTabsSection extends HTMLElement {
+ constructor(isAboutCertificate) {
+ super();
+ this.isAboutCertificate = isAboutCertificate || false;
+ this.connectedCallback();
+ }
+
+ connectedCallback() {
+ let certificateTabsTemplate = document.getElementById(
+ "certificate-tabs-template"
+ );
+ this.attachShadow({ mode: "open" }).appendChild(
+ certificateTabsTemplate.content.cloneNode(true)
+ );
+ this.render();
+ }
+
+ render() {
+ this.tabsElement = this.shadowRoot.querySelector(".certificate-tabs");
+ }
+
+ appendChild(child) {
+ this.tabsElement.appendChild(child);
+ }
+
+ createTabSection(tabName, i) {
+ let tab = document.createElement("button");
+ if (tabName) {
+ tab.textContent = tabName;
+ } else {
+ document.l10n.setAttributes(
+ tab,
+ "certificate-viewer-unknown-group-label"
+ );
+ }
+ tab.setAttribute("id", normalizeToKebabCase(tabName));
+ tab.setAttribute("aria-controls", "panel" + i);
+ tab.setAttribute("idnumber", i);
+ tab.setAttribute("role", "tab");
+ tab.classList.add("certificate-tab");
+ tab.classList.add("tab");
+ if (this.isAboutCertificate) {
+ document.l10n.setAttributes(tab, tabName);
+ } else {
+ // Display tabs on `about:certificate?cert=` pages as dir=auto
+ // to avoid text like `mozilla.org.*` in RTL.
+ // Not needed in the standalone version of about:certificate
+ // because the tab text there should be localized.
+ tab.dir = "auto";
+ }
+ this.tabsElement.appendChild(tab);
+
+ // If it is the first tab, allow it to be tabbable by the user.
+ // If it isn't the first tab, do not allow tab functionality,
+ // as arrow functionality is implemented in certviewer.mjs.
+ if (i === 0) {
+ tab.classList.add("selected");
+ tab.setAttribute("tabindex", 0);
+ } else {
+ tab.setAttribute("tabindex", -1);
+ }
+ }
+
+ updateSelectedTab(index) {
+ let tabs = this.tabsElement.querySelectorAll(".certificate-tab");
+
+ for (let tab of tabs) {
+ tab.classList.remove("selected");
+ }
+ tabs[index].classList.add("selected");
+ }
+
+ /* Information on setAccessibilityEventListeners() can be found
+ * at https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/Tab_Role */
+ setAccessibilityEventListeners() {
+ let tabs = this.tabsElement.querySelectorAll('[role="tab"]');
+
+ // Add a click event handler to each tab
+ for (let tab of tabs) {
+ tab.addEventListener("click", e =>
+ updateSelectedItem(e.target.getAttribute("idnumber"))
+ );
+ }
+
+ // Enable arrow navigation between tabs in the tab list
+ let tabFocus = 0;
+
+ this.tabsElement.addEventListener("keydown", e => {
+ // Move right
+ if (e.keyCode === 39 || e.keyCode === 37) {
+ // After navigating away from the current tab,
+ // prevent that tab from being tabbable -
+ // so as to only allow arrow navigation within the tablist.
+ tabs[tabFocus].setAttribute("tabindex", -1);
+ if (e.keyCode === 39) {
+ tabFocus++;
+ // If we're at the end, go to the start
+ if (tabFocus > tabs.length - 1) {
+ tabFocus = 0;
+ }
+ // Move left
+ } else if (e.keyCode === 37) {
+ tabFocus--;
+ // If we're at the start, move to the end
+ if (tabFocus < 0) {
+ tabFocus = tabs.length;
+ }
+ }
+ tabs[tabFocus].setAttribute("tabindex", 0);
+ tabs[tabFocus].focus();
+ }
+ });
+ }
+}
+
+customElements.define("certificate-tabs-section", CertificateTabsSection);
diff --git a/toolkit/components/certviewer/content/components/error-section.css b/toolkit/components/certviewer/content/components/error-section.css
new file mode 100644
index 0000000000..5a8e91be62
--- /dev/null
+++ b/toolkit/components/certviewer/content/components/error-section.css
@@ -0,0 +1,23 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+@import url("chrome://global/skin/design-system/text-and-typography.css");
+
+:host {
+ background-image: url("chrome://global/skin/illustrations/error-malformed-url.svg");
+ min-height: 300px;
+ background-repeat: no-repeat;
+ padding-inline-start: 30%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ margin: 0 auto;
+ max-width: 500px;
+ background-size: 30%;
+ background-position: left center;
+}
+
+:host(:dir(rtl)) {
+ background-position-x: right;
+}
diff --git a/toolkit/components/certviewer/content/components/error-section.mjs b/toolkit/components/certviewer/content/components/error-section.mjs
new file mode 100644
index 0000000000..1384518825
--- /dev/null
+++ b/toolkit/components/certviewer/content/components/error-section.mjs
@@ -0,0 +1,31 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+export class ErrorSection extends HTMLElement {
+ constructor() {
+ super();
+ }
+
+ connectedCallback() {
+ let template = document.getElementById("error-section-template");
+ let templateHtml = template.content.cloneNode(true);
+
+ this.attachShadow({ mode: "open" }).appendChild(templateHtml);
+
+ document.l10n.connectRoot(this.shadowRoot);
+ this.render();
+ }
+
+ render() {
+ let title = this.shadowRoot.querySelector(".title");
+ document.l10n.setAttributes(title, "certificate-viewer-error-title");
+
+ let errorMessage = this.shadowRoot.querySelector(".error");
+ document.l10n.setAttributes(
+ errorMessage,
+ "certificate-viewer-error-message"
+ );
+ }
+}
+customElements.define("error-section", ErrorSection);
diff --git a/toolkit/components/certviewer/content/components/info-group-container.mjs b/toolkit/components/certviewer/content/components/info-group-container.mjs
new file mode 100644
index 0000000000..feca2f905b
--- /dev/null
+++ b/toolkit/components/certviewer/content/components/info-group-container.mjs
@@ -0,0 +1,65 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import { InfoGroup } from "./info-group.mjs";
+import { AboutCertificateItems } from "./about-certificate-items.mjs";
+
+export class InfoGroupContainer extends HTMLElement {
+ constructor(isAboutCertificate = false) {
+ super();
+ this.infoGroupsContainers = [];
+ this.isAboutCertificate = isAboutCertificate;
+ }
+
+ connectedCallback() {
+ let infoGroupContainerTemplate = document.getElementById(
+ "info-groups-template"
+ );
+ this.attachShadow({ mode: "open" }).appendChild(
+ infoGroupContainerTemplate.content.cloneNode(true)
+ );
+ this.render();
+ }
+
+ render() {}
+
+ createInfoGroupsContainers(certArray, i, final, certData = []) {
+ this.infoGroupsContainers[i] = document.createElement("div");
+ this.infoGroupsContainers[i].setAttribute("id", "panel" + i);
+ this.infoGroupsContainers[i].setAttribute("role", "tabpanel");
+ this.infoGroupsContainers[i].setAttribute("tabindex", 0);
+ this.infoGroupsContainers[i].setAttribute("aria-labelledby", "tab" + i);
+ // Hiding all the certificzte contents except for the first tab that is
+ // selected and shown by default
+ if (i !== 0) {
+ this.infoGroupsContainers[i].hidden = true;
+ }
+ this.infoGroupsContainers[i].classList.add("info-groups");
+
+ if (this.isAboutCertificate) {
+ this.infoGroupsContainers[i].appendChild(
+ new AboutCertificateItems(certData.name, certData.data)
+ );
+ } else {
+ for (let j = 0; j < certArray.length; j++) {
+ this.infoGroupsContainers[i].appendChild(
+ new InfoGroup(certArray[j], final)
+ );
+ }
+ }
+ }
+
+ addClass(className, index) {
+ this.infoGroupsContainers[index].classList.add(className);
+ }
+
+ updateCertificateSource(index) {
+ for (let i = 0; i < this.infoGroupsContainers.length; i++) {
+ this.infoGroupsContainers[i].classList.remove("selected");
+ }
+ this.infoGroupsContainers[index].classList.add("selected");
+ }
+}
+
+customElements.define("info-group-container", InfoGroupContainer);
diff --git a/toolkit/components/certviewer/content/components/info-group.css b/toolkit/components/certviewer/content/components/info-group.css
new file mode 100644
index 0000000000..03e71d7723
--- /dev/null
+++ b/toolkit/components/certviewer/content/components/info-group.css
@@ -0,0 +1,38 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+:host {
+ display: grid;
+ grid-template-columns: minmax(8em, 25%) minmax(50%, 75%);
+ grid-gap: 0 2em;
+ padding: 1.75em 30px;
+ align-items: center;
+ border-top: 1px solid var(--in-content-border-color);
+}
+
+:host(:first-of-type) {
+ border-top: none;
+}
+
+.info-group-title {
+ margin: 0;
+ text-align: end;
+ font-weight: 700;
+ color: var(--in-content-text-color);
+ font-size: 1em;
+ vertical-align: middle;
+}
+
+#critical-info {
+ -moz-context-properties: fill;
+ fill: currentColor;
+ height: 16px;
+ width: 16px;
+ vertical-align: middle;
+}
+
+.extension {
+ text-align: end;
+ margin-block-end: 1em;
+}
diff --git a/toolkit/components/certviewer/content/components/info-group.mjs b/toolkit/components/certviewer/content/components/info-group.mjs
new file mode 100644
index 0000000000..0d0a6bc0bf
--- /dev/null
+++ b/toolkit/components/certviewer/content/components/info-group.mjs
@@ -0,0 +1,93 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import { InfoItem } from "./info-item.mjs";
+import { updateSelectedItem } from "../certviewer.mjs";
+import { normalizeToKebabCase } from "./utils.mjs";
+
+export class InfoGroup extends HTMLElement {
+ constructor(item, final) {
+ super();
+ this.item = item;
+ this.final = final;
+ }
+
+ connectedCallback() {
+ // Attach and connect before adding the template, or fluent
+ // won't translate the template copy we insert into the
+ // shadowroot.
+ this.attachShadow({ mode: "open" });
+ document.l10n.connectRoot(this.shadowRoot);
+
+ let infoGroupTemplate = document.getElementById("info-group-template");
+ this.shadowRoot.appendChild(infoGroupTemplate.content.cloneNode(true));
+ this.render();
+ }
+
+ render() {
+ let title = this.shadowRoot.querySelector(".info-group-title");
+ document.l10n.setAttributes(
+ title,
+ `certificate-viewer-${this.item.sectionId}`
+ );
+
+ // Adds a class with the section title's name, to make
+ // it easier to find when highlighting errors.
+ this.classList.add(this.item.sectionId);
+ for (let i = 0; i < this.item.sectionItems.length; i++) {
+ this.shadowRoot.append(new InfoItem(this.item.sectionItems[i]));
+ }
+
+ if (this.item.sectionId === "issuer-name") {
+ this.setLinkToTab();
+ }
+
+ let criticalIcon = this.shadowRoot.querySelector("#critical-info");
+ if (!this.item.Critical) {
+ criticalIcon.style.display = "none";
+ }
+ }
+
+ setLinkToTab() {
+ if (this.final) {
+ return;
+ }
+
+ let issuerLabelElement =
+ this.shadowRoot.querySelector(".common-name") ||
+ this.shadowRoot.querySelector(".organizational-unit");
+
+ issuerLabelElement = issuerLabelElement?.shadowRoot.querySelector(".info");
+
+ if (!issuerLabelElement) {
+ return;
+ }
+
+ let link = document.createElement("a");
+ link.textContent = issuerLabelElement.textContent;
+ if (!link.textContent) {
+ link.setAttribute(
+ "data-l10n-id",
+ "certificate-viewer-unknown-group-label"
+ );
+ }
+ link.setAttribute("href", "#");
+
+ issuerLabelElement.textContent = "";
+ issuerLabelElement.appendChild(link);
+
+ link.addEventListener("click", () => {
+ let id = normalizeToKebabCase(link.textContent);
+ let issuerTab = document
+ .querySelector("certificate-section")
+ .shadowRoot.getElementById(id);
+
+ let index = issuerTab.getAttribute("idnumber");
+
+ updateSelectedItem(index);
+ });
+ }
+}
+
+customElements.define("info-group", InfoGroup);
diff --git a/toolkit/components/certviewer/content/components/info-item.css b/toolkit/components/certviewer/content/components/info-item.css
new file mode 100644
index 0000000000..b63452152c
--- /dev/null
+++ b/toolkit/components/certviewer/content/components/info-item.css
@@ -0,0 +1,69 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+:host {
+ line-height: 22px;
+ display: contents;
+ word-break: break-word;
+}
+
+:host * {
+ padding: 1px 0;
+}
+
+label {
+ text-align: end;
+ margin-inline-end: 0;
+ color: var(--text-color-deemphasized);
+ font-weight: 600;
+ font-size: 1em;
+}
+
+.hex {
+ overflow: hidden;
+ word-break: break-all;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.download-link-chain {
+ margin: 0 5px;
+}
+
+.long-hex {
+ padding: 0;
+ border-block: 1px solid transparent;
+}
+
+.long-hex:hover {
+ border-block-color: var(--in-content-border-color);
+ background-color: var(--in-content-item-hover);
+ color: var(--in-content-item-hover-text);
+}
+
+.hex-open {
+ white-space: normal;
+}
+
+:host(.value) *,
+:host(.method) *,
+:host(.padding) * {
+ padding-bottom: 10px;
+}
+
+/* Elements that always need to be forced to LTR */
+.hex,
+:host(.dns-name) .info,
+.url {
+ direction: ltr;
+ text-align: match-parent;
+}
+
+/* Display some elements according to their text directionality */
+:host(.common-name) .info,
+:host(.name) .info,
+:host(.organization) .info {
+ unicode-bidi: plaintext;
+ text-align: match-parent;
+}
diff --git a/toolkit/components/certviewer/content/components/info-item.mjs b/toolkit/components/certviewer/content/components/info-item.mjs
new file mode 100644
index 0000000000..354bc2b8d4
--- /dev/null
+++ b/toolkit/components/certviewer/content/components/info-item.mjs
@@ -0,0 +1,173 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import { b64ToPEM, normalizeToKebabCase } from "./utils.mjs";
+
+export class InfoItem extends HTMLElement {
+ constructor(item) {
+ super();
+ this.item = item;
+ }
+
+ connectedCallback() {
+ // Attach and connect before adding the template, or fluent
+ // won't translate the template copy we insert into the
+ // shadowroot.
+ this.attachShadow({ mode: "open" });
+ document.l10n.connectRoot(this.shadowRoot);
+
+ let infoItemTemplate = document.getElementById("info-item-template");
+ this.shadowRoot.appendChild(infoItemTemplate.content.cloneNode(true));
+
+ this.render();
+ }
+
+ handleTimeZone(infoElement) {
+ let localTime = this.item.info.local;
+ let UTCTime = this.item.info.utc;
+ infoElement.textContent = UTCTime;
+ infoElement.setAttribute("title", localTime);
+ }
+
+ addLongHexOverflow(info) {
+ info.classList.add("hex");
+
+ // For visual appeal, we want to collapse large hex values into single
+ // line items that can be clicked to expand.
+ // This function measures the size of the info item relative to its
+ // container and adds the "long-hex" class if it's overflowing. Since the
+ // container size changes on window resize this function is hooked up to
+ // a resize event listener.
+ function resize() {
+ if (info.classList.contains("hex-open")) {
+ info.classList.toggle("long-hex", true);
+ return;
+ }
+
+ // If the item is not currently drawn and we can't measure its dimensions
+ // then attach an observer that will measure it once it appears.
+ if (info.clientWidth <= 0) {
+ let observer = new IntersectionObserver(function ([
+ { intersectionRatio },
+ ]) {
+ if (intersectionRatio > 0) {
+ info.classList.toggle(
+ "long-hex",
+ info.scrollWidth > info.clientWidth
+ );
+ observer.unobserve(info);
+ }
+ },
+ {});
+
+ observer.observe(info);
+ }
+ info.classList.toggle("long-hex", info.scrollWidth > info.clientWidth);
+ }
+ window.addEventListener("resize", resize);
+ window.requestAnimationFrame(resize);
+
+ this.addEventListener("mouseup", () => {
+ // If a range of text is selected, don't toggle the class that
+ // hides/shows additional text.
+ if (
+ info.classList.contains("long-hex") &&
+ window.getSelection().type !== "Range"
+ ) {
+ info.classList.toggle("hex-open");
+ }
+ });
+ }
+
+ render() {
+ let label = this.shadowRoot.querySelector("label");
+ let labelId = this.item.labelId;
+
+ // Map specific elements to a different message ID, to allow updates to
+ // existing labels and avoid duplicates.
+ let stringMapping = {
+ signaturealgorithm: "signature-algorithm",
+ "rfc-822-name": "email-address",
+ };
+ let fluentID = stringMapping[labelId] || labelId;
+
+ document.l10n.setAttributes(label, `certificate-viewer-${fluentID}`);
+
+ this.classList.add(labelId);
+
+ let info = this.shadowRoot.querySelector(".info");
+ if (this.item.info.hasOwnProperty("utc")) {
+ this.handleTimeZone(info);
+ return;
+ }
+ if (labelId === "other-name") {
+ document.l10n.setAttributes(info, "certificate-viewer-unsupported");
+ return;
+ }
+ if (typeof this.item.info === "boolean") {
+ document.l10n.setAttributes(info, "certificate-viewer-boolean", {
+ boolean: this.item.info,
+ });
+ } else {
+ info.textContent = Array.isArray(this.item.info)
+ ? this.item.info.join(", ")
+ : this.item.info;
+ }
+
+ this.classList.add(labelId);
+
+ if (this.item.isHex) {
+ this.addLongHexOverflow(info);
+ }
+
+ if (labelId === "download") {
+ this.setDownloadLinkInformation(info);
+ }
+ }
+
+ setDownloadLinkInformation(info) {
+ let link = document.createElement("a");
+ link.setAttribute("href", "data:," + this.item.info);
+ link.classList.add("download-link");
+
+ let url = new URL(document.URL);
+ let certArray = url.searchParams.getAll("cert");
+ let encodedCertArray = [];
+ for (let i = 0; i < certArray.length; i++) {
+ encodedCertArray.push(encodeURI(b64ToPEM(certArray[i])));
+ }
+ encodedCertArray = encodedCertArray.join("");
+
+ let chainLink = document.createElement("a");
+ chainLink.setAttribute("href", "data:," + encodedCertArray);
+ chainLink.classList.add("download-link");
+ chainLink.classList.add("download-link-chain");
+
+ info.textContent = "";
+ info.appendChild(link);
+ info.appendChild(chainLink);
+
+ let commonName = document
+ .querySelector("certificate-section")
+ .shadowRoot.querySelector(".subject-name")
+ .shadowRoot.querySelector(".common-name")
+ .shadowRoot.querySelector(".info");
+
+ let fileName = normalizeToKebabCase(commonName.textContent);
+
+ document.l10n.setAttributes(link, "certificate-viewer-download-pem", {
+ fileName,
+ });
+
+ document.l10n.setAttributes(
+ chainLink,
+ "certificate-viewer-download-pem-chain",
+ {
+ fileName,
+ }
+ );
+ }
+}
+
+customElements.define("info-item", InfoItem);
diff --git a/toolkit/components/certviewer/content/components/list-item.css b/toolkit/components/certviewer/content/components/list-item.css
new file mode 100644
index 0000000000..2d03edb63e
--- /dev/null
+++ b/toolkit/components/certviewer/content/components/list-item.css
@@ -0,0 +1,46 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+:host {
+ display: grid;
+ padding: 1em 0 1em;
+ border-block: 0.5px solid var(--in-content-border-color);
+ border-inline: 0.5px solid transparent;
+ position: relative;
+}
+
+:host(:hover) {
+ background-color: var(--in-content-item-hover);
+ color: var(--in-content-item-hover-text);
+ border-inline-color: var(--in-content-border-color);
+ cursor: pointer;
+}
+
+a {
+ text-decoration: none;
+ color: inherit;
+}
+
+.cert-url {
+ height: 100%;
+ width: 100%;
+ position: absolute;
+ align-items: center;
+ display: flex;
+}
+
+.cert-url > .item-name {
+ padding-inline-start: 0.8em;
+}
+
+.export {
+ position: absolute;
+ inset-inline-end: 2em;
+ align-self: center;
+ font-size: 1em;
+}
+
+.export a {
+ position: relative;
+}
diff --git a/toolkit/components/certviewer/content/components/list-item.mjs b/toolkit/components/certviewer/content/components/list-item.mjs
new file mode 100644
index 0000000000..723eed05ab
--- /dev/null
+++ b/toolkit/components/certviewer/content/components/list-item.mjs
@@ -0,0 +1,58 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import { normalizeToKebabCase } from "./utils.mjs";
+
+export class ListItem extends HTMLElement {
+ constructor(item) {
+ super();
+ this.item = item;
+ }
+
+ connectedCallback() {
+ // Attach and connect before adding the template, or fluent
+ // won't translate the template copy we insert into the
+ // shadowroot.
+ this.attachShadow({ mode: "open" });
+ document.l10n.connectRoot(this.shadowRoot);
+
+ let ListItemTemplate = document.getElementById("list-item-template");
+ this.shadowRoot.appendChild(ListItemTemplate.content.cloneNode(true));
+
+ this.render();
+ }
+
+ render() {
+ let label = this.shadowRoot.querySelector(".item-name");
+ label.textContent = this.item.displayName;
+
+ this.handleExport();
+
+ let link = this.shadowRoot.querySelector(".cert-url");
+ let derb64 = encodeURIComponent(this.item.derb64);
+ let url = `about:certificate?cert=${derb64}`;
+ link.setAttribute("href", url);
+ }
+
+ handleExport() {
+ let exportButton = this.shadowRoot.querySelector(".export");
+ // Wrap the Base64 string into lines of 64 characters,
+ // with CRLF line breaks (as specified in RFC 1421).
+ let wrapped = this.item.derb64.replace(/(\S{64}(?!$))/g, "$1\r\n");
+ let download =
+ "-----BEGIN CERTIFICATE-----\r\n" +
+ wrapped +
+ "\r\n-----END CERTIFICATE-----\r\n";
+
+ let element = document.createElement("a");
+ element.setAttribute("href", "data:," + encodeURI(download));
+ let fileName = normalizeToKebabCase(this.item.displayName);
+ document.l10n.setAttributes(element, "certificate-viewer-export", {
+ fileName,
+ });
+ exportButton.appendChild(element);
+ }
+}
+
+customElements.define("list-item", ListItem);
diff --git a/toolkit/components/certviewer/content/components/utils.mjs b/toolkit/components/certviewer/content/components/utils.mjs
new file mode 100644
index 0000000000..e7c5d258d0
--- /dev/null
+++ b/toolkit/components/certviewer/content/components/utils.mjs
@@ -0,0 +1,26 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+export const normalizeToKebabCase = string => {
+ let kebabString = string
+ // Turn all dots into dashes
+ .replace(/\./g, "-")
+ // Turn whitespace into dashes
+ .replace(/\s+/g, "-")
+ // Remove all non-characters or numbers
+ .replace(/[^a-z0-9\-]/gi, "")
+ // De-dupe dashes
+ .replace(/--/g, "-")
+ // Remove trailing and leading dashes
+ .replace(/^-/g, "")
+ .replace(/-$/g, "")
+ .toLowerCase();
+
+ return kebabString;
+};
+
+export const b64ToPEM = string => {
+ let wrapped = string.match(/.{1,64}/g).join("\r\n");
+ return `-----BEGIN CERTIFICATE-----\r\n${wrapped}\r\n-----END CERTIFICATE-----\r\n`;
+};
diff --git a/toolkit/components/certviewer/content/vendor/pkijs.js b/toolkit/components/certviewer/content/vendor/pkijs.js
new file mode 100644
index 0000000000..efee8d1e16
--- /dev/null
+++ b/toolkit/components/certviewer/content/vendor/pkijs.js
@@ -0,0 +1,24083 @@
+/*!
+ * Copyright (c) 2014, GlobalSign
+ * Copyright (c) 2015-2019, Peculiar Ventures
+ * All rights reserved.
+ *
+ * Author 2014-2019, Yury Strozhevsky
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * * Neither the name of the {organization} nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*!
+ * MIT License
+ *
+ * Copyright (c) 2017-2022 Peculiar Ventures, LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+const ARRAY_BUFFER_NAME = "[object ArrayBuffer]";
+class BufferSourceConverter {
+ static isArrayBuffer(data) {
+ return Object.prototype.toString.call(data) === ARRAY_BUFFER_NAME;
+ }
+ static toArrayBuffer(data) {
+ if (this.isArrayBuffer(data)) {
+ return data;
+ }
+ if (data.byteLength === data.buffer.byteLength) {
+ return data.buffer;
+ }
+ return this.toUint8Array(data).slice().buffer;
+ }
+ static toUint8Array(data) {
+ return this.toView(data, Uint8Array);
+ }
+ static toView(data, type) {
+ if (data.constructor === type) {
+ return data;
+ }
+ if (this.isArrayBuffer(data)) {
+ return new type(data);
+ }
+ if (this.isArrayBufferView(data)) {
+ return new type(data.buffer, data.byteOffset, data.byteLength);
+ }
+ throw new TypeError("The provided value is not of type '(ArrayBuffer or ArrayBufferView)'");
+ }
+ static isBufferSource(data) {
+ return this.isArrayBufferView(data)
+ || this.isArrayBuffer(data);
+ }
+ static isArrayBufferView(data) {
+ return ArrayBuffer.isView(data)
+ || (data && this.isArrayBuffer(data.buffer));
+ }
+ static isEqual(a, b) {
+ const aView = BufferSourceConverter.toUint8Array(a);
+ const bView = BufferSourceConverter.toUint8Array(b);
+ if (aView.length !== bView.byteLength) {
+ return false;
+ }
+ for (let i = 0; i < aView.length; i++) {
+ if (aView[i] !== bView[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+ static concat(...args) {
+ if (Array.isArray(args[0])) {
+ const buffers = args[0];
+ let size = 0;
+ for (const buffer of buffers) {
+ size += buffer.byteLength;
+ }
+ const res = new Uint8Array(size);
+ let offset = 0;
+ for (const buffer of buffers) {
+ const view = this.toUint8Array(buffer);
+ res.set(view, offset);
+ offset += view.length;
+ }
+ if (args[1]) {
+ return this.toView(res, args[1]);
+ }
+ return res.buffer;
+ }
+ else {
+ return this.concat(args);
+ }
+ }
+}
+
+class Utf8Converter {
+ static fromString(text) {
+ const s = unescape(encodeURIComponent(text));
+ const uintArray = new Uint8Array(s.length);
+ for (let i = 0; i < s.length; i++) {
+ uintArray[i] = s.charCodeAt(i);
+ }
+ return uintArray.buffer;
+ }
+ static toString(buffer) {
+ const buf = BufferSourceConverter.toUint8Array(buffer);
+ let encodedString = "";
+ for (let i = 0; i < buf.length; i++) {
+ encodedString += String.fromCharCode(buf[i]);
+ }
+ const decodedString = decodeURIComponent(escape(encodedString));
+ return decodedString;
+ }
+}
+class Utf16Converter {
+ static toString(buffer, littleEndian = false) {
+ const arrayBuffer = BufferSourceConverter.toArrayBuffer(buffer);
+ const dataView = new DataView(arrayBuffer);
+ let res = "";
+ for (let i = 0; i < arrayBuffer.byteLength; i += 2) {
+ const code = dataView.getUint16(i, littleEndian);
+ res += String.fromCharCode(code);
+ }
+ return res;
+ }
+ static fromString(text, littleEndian = false) {
+ const res = new ArrayBuffer(text.length * 2);
+ const dataView = new DataView(res);
+ for (let i = 0; i < text.length; i++) {
+ dataView.setUint16(i * 2, text.charCodeAt(i), littleEndian);
+ }
+ return res;
+ }
+}
+class Convert {
+ static isHex(data) {
+ return typeof data === "string"
+ && /^[a-z0-9]+$/i.test(data);
+ }
+ static isBase64(data) {
+ return typeof data === "string"
+ && /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(data);
+ }
+ static isBase64Url(data) {
+ return typeof data === "string"
+ && /^[a-zA-Z0-9-_]+$/i.test(data);
+ }
+ static ToString(buffer, enc = "utf8") {
+ const buf = BufferSourceConverter.toUint8Array(buffer);
+ switch (enc.toLowerCase()) {
+ case "utf8":
+ return this.ToUtf8String(buf);
+ case "binary":
+ return this.ToBinary(buf);
+ case "hex":
+ return this.ToHex(buf);
+ case "base64":
+ return this.ToBase64(buf);
+ case "base64url":
+ return this.ToBase64Url(buf);
+ case "utf16le":
+ return Utf16Converter.toString(buf, true);
+ case "utf16":
+ case "utf16be":
+ return Utf16Converter.toString(buf);
+ default:
+ throw new Error(`Unknown type of encoding '${enc}'`);
+ }
+ }
+ static FromString(str, enc = "utf8") {
+ if (!str) {
+ return new ArrayBuffer(0);
+ }
+ switch (enc.toLowerCase()) {
+ case "utf8":
+ return this.FromUtf8String(str);
+ case "binary":
+ return this.FromBinary(str);
+ case "hex":
+ return this.FromHex(str);
+ case "base64":
+ return this.FromBase64(str);
+ case "base64url":
+ return this.FromBase64Url(str);
+ case "utf16le":
+ return Utf16Converter.fromString(str, true);
+ case "utf16":
+ case "utf16be":
+ return Utf16Converter.fromString(str);
+ default:
+ throw new Error(`Unknown type of encoding '${enc}'`);
+ }
+ }
+ static ToBase64(buffer) {
+ const buf = BufferSourceConverter.toUint8Array(buffer);
+ if (typeof btoa !== "undefined") {
+ const binary = this.ToString(buf, "binary");
+ return btoa(binary);
+ }
+ else {
+ return Buffer.from(buf).toString("base64");
+ }
+ }
+ static FromBase64(base64) {
+ const formatted = this.formatString(base64);
+ if (!formatted) {
+ return new ArrayBuffer(0);
+ }
+ if (!Convert.isBase64(formatted)) {
+ throw new TypeError("Argument 'base64Text' is not Base64 encoded");
+ }
+ if (typeof atob !== "undefined") {
+ return this.FromBinary(atob(formatted));
+ }
+ else {
+ return new Uint8Array(Buffer.from(formatted, "base64")).buffer;
+ }
+ }
+ static FromBase64Url(base64url) {
+ const formatted = this.formatString(base64url);
+ if (!formatted) {
+ return new ArrayBuffer(0);
+ }
+ if (!Convert.isBase64Url(formatted)) {
+ throw new TypeError("Argument 'base64url' is not Base64Url encoded");
+ }
+ return this.FromBase64(this.Base64Padding(formatted.replace(/\-/g, "+").replace(/\_/g, "/")));
+ }
+ static ToBase64Url(data) {
+ return this.ToBase64(data).replace(/\+/g, "-").replace(/\//g, "_").replace(/\=/g, "");
+ }
+ static FromUtf8String(text, encoding = Convert.DEFAULT_UTF8_ENCODING) {
+ switch (encoding) {
+ case "ascii":
+ return this.FromBinary(text);
+ case "utf8":
+ return Utf8Converter.fromString(text);
+ case "utf16":
+ case "utf16be":
+ return Utf16Converter.fromString(text);
+ case "utf16le":
+ case "usc2":
+ return Utf16Converter.fromString(text, true);
+ default:
+ throw new Error(`Unknown type of encoding '${encoding}'`);
+ }
+ }
+ static ToUtf8String(buffer, encoding = Convert.DEFAULT_UTF8_ENCODING) {
+ switch (encoding) {
+ case "ascii":
+ return this.ToBinary(buffer);
+ case "utf8":
+ return Utf8Converter.toString(buffer);
+ case "utf16":
+ case "utf16be":
+ return Utf16Converter.toString(buffer);
+ case "utf16le":
+ case "usc2":
+ return Utf16Converter.toString(buffer, true);
+ default:
+ throw new Error(`Unknown type of encoding '${encoding}'`);
+ }
+ }
+ static FromBinary(text) {
+ const stringLength = text.length;
+ const resultView = new Uint8Array(stringLength);
+ for (let i = 0; i < stringLength; i++) {
+ resultView[i] = text.charCodeAt(i);
+ }
+ return resultView.buffer;
+ }
+ static ToBinary(buffer) {
+ const buf = BufferSourceConverter.toUint8Array(buffer);
+ let res = "";
+ for (let i = 0; i < buf.length; i++) {
+ res += String.fromCharCode(buf[i]);
+ }
+ return res;
+ }
+ static ToHex(buffer) {
+ const buf = BufferSourceConverter.toUint8Array(buffer);
+ const splitter = "";
+ const res = [];
+ const len = buf.length;
+ for (let i = 0; i < len; i++) {
+ const char = buf[i].toString(16).padStart(2, "0");
+ res.push(char);
+ }
+ return res.join(splitter);
+ }
+ static FromHex(hexString) {
+ let formatted = this.formatString(hexString);
+ if (!formatted) {
+ return new ArrayBuffer(0);
+ }
+ if (!Convert.isHex(formatted)) {
+ throw new TypeError("Argument 'hexString' is not HEX encoded");
+ }
+ if (formatted.length % 2) {
+ formatted = `0${formatted}`;
+ }
+ const res = new Uint8Array(formatted.length / 2);
+ for (let i = 0; i < formatted.length; i = i + 2) {
+ const c = formatted.slice(i, i + 2);
+ res[i / 2] = parseInt(c, 16);
+ }
+ return res.buffer;
+ }
+ static ToUtf16String(buffer, littleEndian = false) {
+ return Utf16Converter.toString(buffer, littleEndian);
+ }
+ static FromUtf16String(text, littleEndian = false) {
+ return Utf16Converter.fromString(text, littleEndian);
+ }
+ static Base64Padding(base64) {
+ const padCount = 4 - (base64.length % 4);
+ if (padCount < 4) {
+ for (let i = 0; i < padCount; i++) {
+ base64 += "=";
+ }
+ }
+ return base64;
+ }
+ static formatString(data) {
+ return (data === null || data === void 0 ? void 0 : data.replace(/[\n\r\t ]/g, "")) || "";
+ }
+}
+Convert.DEFAULT_UTF8_ENCODING = "utf8";
+
+/*!
+ Copyright (c) Peculiar Ventures, LLC
+*/
+function getParametersValue(parameters, name, defaultValue) {
+ var _a;
+ if ((parameters instanceof Object) === false) {
+ return defaultValue;
+ }
+ return (_a = parameters[name]) !== null && _a !== void 0 ? _a : defaultValue;
+}
+function bufferToHexCodes(inputBuffer, inputOffset = 0, inputLength = (inputBuffer.byteLength - inputOffset), insertSpace = false) {
+ let result = "";
+ for (const item of (new Uint8Array(inputBuffer, inputOffset, inputLength))) {
+ const str = item.toString(16).toUpperCase();
+ if (str.length === 1) {
+ result += "0";
+ }
+ result += str;
+ if (insertSpace) {
+ result += " ";
+ }
+ }
+ return result.trim();
+}
+function utilFromBase(inputBuffer, inputBase) {
+ let result = 0;
+ if (inputBuffer.length === 1) {
+ return inputBuffer[0];
+ }
+ for (let i = (inputBuffer.length - 1); i >= 0; i--) {
+ result += inputBuffer[(inputBuffer.length - 1) - i] * Math.pow(2, inputBase * i);
+ }
+ return result;
+}
+function utilToBase(value, base, reserved = (-1)) {
+ const internalReserved = reserved;
+ let internalValue = value;
+ let result = 0;
+ let biggest = Math.pow(2, base);
+ for (let i = 1; i < 8; i++) {
+ if (value < biggest) {
+ let retBuf;
+ if (internalReserved < 0) {
+ retBuf = new ArrayBuffer(i);
+ result = i;
+ }
+ else {
+ if (internalReserved < i) {
+ return (new ArrayBuffer(0));
+ }
+ retBuf = new ArrayBuffer(internalReserved);
+ result = internalReserved;
+ }
+ const retView = new Uint8Array(retBuf);
+ for (let j = (i - 1); j >= 0; j--) {
+ const basis = Math.pow(2, j * base);
+ retView[result - j - 1] = Math.floor(internalValue / basis);
+ internalValue -= (retView[result - j - 1]) * basis;
+ }
+ return retBuf;
+ }
+ biggest *= Math.pow(2, base);
+ }
+ return new ArrayBuffer(0);
+}
+function utilConcatBuf(...buffers) {
+ let outputLength = 0;
+ let prevLength = 0;
+ for (const buffer of buffers) {
+ outputLength += buffer.byteLength;
+ }
+ const retBuf = new ArrayBuffer(outputLength);
+ const retView = new Uint8Array(retBuf);
+ for (const buffer of buffers) {
+ retView.set(new Uint8Array(buffer), prevLength);
+ prevLength += buffer.byteLength;
+ }
+ return retBuf;
+}
+function utilConcatView(...views) {
+ let outputLength = 0;
+ let prevLength = 0;
+ for (const view of views) {
+ outputLength += view.length;
+ }
+ const retBuf = new ArrayBuffer(outputLength);
+ const retView = new Uint8Array(retBuf);
+ for (const view of views) {
+ retView.set(view, prevLength);
+ prevLength += view.length;
+ }
+ return retView;
+}
+function utilDecodeTC() {
+ const buf = new Uint8Array(this.valueHex);
+ if (this.valueHex.byteLength >= 2) {
+ const condition1 = (buf[0] === 0xFF) && (buf[1] & 0x80);
+ const condition2 = (buf[0] === 0x00) && ((buf[1] & 0x80) === 0x00);
+ if (condition1 || condition2) {
+ this.warnings.push("Needlessly long format");
+ }
+ }
+ const bigIntBuffer = new ArrayBuffer(this.valueHex.byteLength);
+ const bigIntView = new Uint8Array(bigIntBuffer);
+ for (let i = 0; i < this.valueHex.byteLength; i++) {
+ bigIntView[i] = 0;
+ }
+ bigIntView[0] = (buf[0] & 0x80);
+ const bigInt = utilFromBase(bigIntView, 8);
+ const smallIntBuffer = new ArrayBuffer(this.valueHex.byteLength);
+ const smallIntView = new Uint8Array(smallIntBuffer);
+ for (let j = 0; j < this.valueHex.byteLength; j++) {
+ smallIntView[j] = buf[j];
+ }
+ smallIntView[0] &= 0x7F;
+ const smallInt = utilFromBase(smallIntView, 8);
+ return (smallInt - bigInt);
+}
+function utilEncodeTC(value) {
+ const modValue = (value < 0) ? (value * (-1)) : value;
+ let bigInt = 128;
+ for (let i = 1; i < 8; i++) {
+ if (modValue <= bigInt) {
+ if (value < 0) {
+ const smallInt = bigInt - modValue;
+ const retBuf = utilToBase(smallInt, 8, i);
+ const retView = new Uint8Array(retBuf);
+ retView[0] |= 0x80;
+ return retBuf;
+ }
+ let retBuf = utilToBase(modValue, 8, i);
+ let retView = new Uint8Array(retBuf);
+ if (retView[0] & 0x80) {
+ const tempBuf = retBuf.slice(0);
+ const tempView = new Uint8Array(tempBuf);
+ retBuf = new ArrayBuffer(retBuf.byteLength + 1);
+ retView = new Uint8Array(retBuf);
+ for (let k = 0; k < tempBuf.byteLength; k++) {
+ retView[k + 1] = tempView[k];
+ }
+ retView[0] = 0x00;
+ }
+ return retBuf;
+ }
+ bigInt *= Math.pow(2, 8);
+ }
+ return (new ArrayBuffer(0));
+}
+function isEqualBuffer(inputBuffer1, inputBuffer2) {
+ if (inputBuffer1.byteLength !== inputBuffer2.byteLength) {
+ return false;
+ }
+ const view1 = new Uint8Array(inputBuffer1);
+ const view2 = new Uint8Array(inputBuffer2);
+ for (let i = 0; i < view1.length; i++) {
+ if (view1[i] !== view2[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+function padNumber(inputNumber, fullLength) {
+ const str = inputNumber.toString(10);
+ if (fullLength < str.length) {
+ return "";
+ }
+ const dif = fullLength - str.length;
+ const padding = new Array(dif);
+ for (let i = 0; i < dif; i++) {
+ padding[i] = "0";
+ }
+ const paddingString = padding.join("");
+ return paddingString.concat(str);
+}
+const base64Template = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+const base64UrlTemplate = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=";
+function toBase64(input, useUrlTemplate = false, skipPadding = false, skipLeadingZeros = false) {
+ let i = 0;
+ let flag1 = 0;
+ let flag2 = 0;
+ let output = "";
+ const template = (useUrlTemplate) ? base64UrlTemplate : base64Template;
+ if (skipLeadingZeros) {
+ let nonZeroPosition = 0;
+ for (let i = 0; i < input.length; i++) {
+ if (input.charCodeAt(i) !== 0) {
+ nonZeroPosition = i;
+ break;
+ }
+ }
+ input = input.slice(nonZeroPosition);
+ }
+ while (i < input.length) {
+ const chr1 = input.charCodeAt(i++);
+ if (i >= input.length) {
+ flag1 = 1;
+ }
+ const chr2 = input.charCodeAt(i++);
+ if (i >= input.length) {
+ flag2 = 1;
+ }
+ const chr3 = input.charCodeAt(i++);
+ const enc1 = chr1 >> 2;
+ const enc2 = ((chr1 & 0x03) << 4) | (chr2 >> 4);
+ let enc3 = ((chr2 & 0x0F) << 2) | (chr3 >> 6);
+ let enc4 = chr3 & 0x3F;
+ if (flag1 === 1) {
+ enc3 = enc4 = 64;
+ }
+ else {
+ if (flag2 === 1) {
+ enc4 = 64;
+ }
+ }
+ if (skipPadding) {
+ if (enc3 === 64) {
+ output += `${template.charAt(enc1)}${template.charAt(enc2)}`;
+ }
+ else {
+ if (enc4 === 64) {
+ output += `${template.charAt(enc1)}${template.charAt(enc2)}${template.charAt(enc3)}`;
+ }
+ else {
+ output += `${template.charAt(enc1)}${template.charAt(enc2)}${template.charAt(enc3)}${template.charAt(enc4)}`;
+ }
+ }
+ }
+ else {
+ output += `${template.charAt(enc1)}${template.charAt(enc2)}${template.charAt(enc3)}${template.charAt(enc4)}`;
+ }
+ }
+ return output;
+}
+function fromBase64(input, useUrlTemplate = false, cutTailZeros = false) {
+ const template = (useUrlTemplate) ? base64UrlTemplate : base64Template;
+ function indexOf(toSearch) {
+ for (let i = 0; i < 64; i++) {
+ if (template.charAt(i) === toSearch)
+ return i;
+ }
+ return 64;
+ }
+ function test(incoming) {
+ return ((incoming === 64) ? 0x00 : incoming);
+ }
+ let i = 0;
+ let output = "";
+ while (i < input.length) {
+ const enc1 = indexOf(input.charAt(i++));
+ const enc2 = (i >= input.length) ? 0x00 : indexOf(input.charAt(i++));
+ const enc3 = (i >= input.length) ? 0x00 : indexOf(input.charAt(i++));
+ const enc4 = (i >= input.length) ? 0x00 : indexOf(input.charAt(i++));
+ const chr1 = (test(enc1) << 2) | (test(enc2) >> 4);
+ const chr2 = ((test(enc2) & 0x0F) << 4) | (test(enc3) >> 2);
+ const chr3 = ((test(enc3) & 0x03) << 6) | test(enc4);
+ output += String.fromCharCode(chr1);
+ if (enc3 !== 64) {
+ output += String.fromCharCode(chr2);
+ }
+ if (enc4 !== 64) {
+ output += String.fromCharCode(chr3);
+ }
+ }
+ if (cutTailZeros) {
+ const outputLength = output.length;
+ let nonZeroStart = (-1);
+ for (let i = (outputLength - 1); i >= 0; i--) {
+ if (output.charCodeAt(i) !== 0) {
+ nonZeroStart = i;
+ break;
+ }
+ }
+ if (nonZeroStart !== (-1)) {
+ output = output.slice(0, nonZeroStart + 1);
+ }
+ else {
+ output = "";
+ }
+ }
+ return output;
+}
+function arrayBufferToString(buffer) {
+ let resultString = "";
+ const view = new Uint8Array(buffer);
+ for (const element of view) {
+ resultString += String.fromCharCode(element);
+ }
+ return resultString;
+}
+function stringToArrayBuffer(str) {
+ const stringLength = str.length;
+ const resultBuffer = new ArrayBuffer(stringLength);
+ const resultView = new Uint8Array(resultBuffer);
+ for (let i = 0; i < stringLength; i++) {
+ resultView[i] = str.charCodeAt(i);
+ }
+ return resultBuffer;
+}
+const log2 = Math.log(2);
+function nearestPowerOf2(length) {
+ const base = (Math.log(length) / log2);
+ const floor = Math.floor(base);
+ const round = Math.round(base);
+ return ((floor === round) ? floor : round);
+}
+function clearProps(object, propsArray) {
+ for (const prop of propsArray) {
+ delete object[prop];
+ }
+}
+
+/*!
+ * Copyright (c) 2014, GMO GlobalSign
+ * Copyright (c) 2015-2022, Peculiar Ventures
+ * All rights reserved.
+ *
+ * Author 2014-2019, Yury Strozhevsky
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * * Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+function assertBigInt() {
+ if (typeof BigInt === "undefined") {
+ throw new Error("BigInt is not defined. Your environment doesn't implement BigInt.");
+ }
+}
+function concat(buffers) {
+ let outputLength = 0;
+ let prevLength = 0;
+ for (let i = 0; i < buffers.length; i++) {
+ const buffer = buffers[i];
+ outputLength += buffer.byteLength;
+ }
+ const retView = new Uint8Array(outputLength);
+ for (let i = 0; i < buffers.length; i++) {
+ const buffer = buffers[i];
+ retView.set(new Uint8Array(buffer), prevLength);
+ prevLength += buffer.byteLength;
+ }
+ return retView.buffer;
+}
+function checkBufferParams(baseBlock, inputBuffer, inputOffset, inputLength) {
+ if (!(inputBuffer instanceof Uint8Array)) {
+ baseBlock.error = "Wrong parameter: inputBuffer must be 'Uint8Array'";
+ return false;
+ }
+ if (!inputBuffer.byteLength) {
+ baseBlock.error = "Wrong parameter: inputBuffer has zero length";
+ return false;
+ }
+ if (inputOffset < 0) {
+ baseBlock.error = "Wrong parameter: inputOffset less than zero";
+ return false;
+ }
+ if (inputLength < 0) {
+ baseBlock.error = "Wrong parameter: inputLength less than zero";
+ return false;
+ }
+ if ((inputBuffer.byteLength - inputOffset - inputLength) < 0) {
+ baseBlock.error = "End of input reached before message was fully decoded (inconsistent offset and length values)";
+ return false;
+ }
+ return true;
+}
+
+class ViewWriter {
+ constructor() {
+ this.items = [];
+ }
+ write(buf) {
+ this.items.push(buf);
+ }
+ final() {
+ return concat(this.items);
+ }
+}
+
+const powers2 = [new Uint8Array([1])];
+const digitsString = "0123456789";
+const NAME = "name";
+const VALUE_HEX_VIEW = "valueHexView";
+const IS_HEX_ONLY = "isHexOnly";
+const ID_BLOCK = "idBlock";
+const TAG_CLASS = "tagClass";
+const TAG_NUMBER = "tagNumber";
+const IS_CONSTRUCTED = "isConstructed";
+const FROM_BER = "fromBER";
+const TO_BER = "toBER";
+const LOCAL = "local";
+const EMPTY_STRING$1 = "";
+const EMPTY_BUFFER$1 = new ArrayBuffer(0);
+const EMPTY_VIEW = new Uint8Array(0);
+const END_OF_CONTENT_NAME = "EndOfContent";
+const OCTET_STRING_NAME = "OCTET STRING";
+const BIT_STRING_NAME = "BIT STRING";
+
+function HexBlock(BaseClass) {
+ var _a;
+ return _a = class Some extends BaseClass {
+ constructor(...args) {
+ var _a;
+ super(...args);
+ const params = args[0] || {};
+ this.isHexOnly = (_a = params.isHexOnly) !== null && _a !== void 0 ? _a : false;
+ this.valueHexView = params.valueHex ? BufferSourceConverter.toUint8Array(params.valueHex) : EMPTY_VIEW;
+ }
+ get valueHex() {
+ return this.valueHexView.slice().buffer;
+ }
+ set valueHex(value) {
+ this.valueHexView = new Uint8Array(value);
+ }
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ const view = inputBuffer instanceof ArrayBuffer ? new Uint8Array(inputBuffer) : inputBuffer;
+ if (!checkBufferParams(this, view, inputOffset, inputLength)) {
+ return -1;
+ }
+ const endLength = inputOffset + inputLength;
+ this.valueHexView = view.subarray(inputOffset, endLength);
+ if (!this.valueHexView.length) {
+ this.warnings.push("Zero buffer length");
+ return inputOffset;
+ }
+ this.blockLength = inputLength;
+ return endLength;
+ }
+ toBER(sizeOnly = false) {
+ if (!this.isHexOnly) {
+ this.error = "Flag 'isHexOnly' is not set, abort";
+ return EMPTY_BUFFER$1;
+ }
+ if (sizeOnly) {
+ return new ArrayBuffer(this.valueHexView.byteLength);
+ }
+ return (this.valueHexView.byteLength === this.valueHexView.buffer.byteLength)
+ ? this.valueHexView.buffer
+ : this.valueHexView.slice().buffer;
+ }
+ toJSON() {
+ return {
+ ...super.toJSON(),
+ isHexOnly: this.isHexOnly,
+ valueHex: Convert.ToHex(this.valueHexView),
+ };
+ }
+ },
+ _a.NAME = "hexBlock",
+ _a;
+}
+
+class LocalBaseBlock {
+ constructor({ blockLength = 0, error = EMPTY_STRING$1, warnings = [], valueBeforeDecode = EMPTY_VIEW, } = {}) {
+ this.blockLength = blockLength;
+ this.error = error;
+ this.warnings = warnings;
+ this.valueBeforeDecodeView = BufferSourceConverter.toUint8Array(valueBeforeDecode);
+ }
+ static blockName() {
+ return this.NAME;
+ }
+ get valueBeforeDecode() {
+ return this.valueBeforeDecodeView.slice().buffer;
+ }
+ set valueBeforeDecode(value) {
+ this.valueBeforeDecodeView = new Uint8Array(value);
+ }
+ toJSON() {
+ return {
+ blockName: this.constructor.NAME,
+ blockLength: this.blockLength,
+ error: this.error,
+ warnings: this.warnings,
+ valueBeforeDecode: Convert.ToHex(this.valueBeforeDecodeView),
+ };
+ }
+}
+LocalBaseBlock.NAME = "baseBlock";
+
+class ValueBlock extends LocalBaseBlock {
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ throw TypeError("User need to make a specific function in a class which extends 'ValueBlock'");
+ }
+ toBER(sizeOnly, writer) {
+ throw TypeError("User need to make a specific function in a class which extends 'ValueBlock'");
+ }
+}
+ValueBlock.NAME = "valueBlock";
+
+class LocalIdentificationBlock extends HexBlock(LocalBaseBlock) {
+ constructor({ idBlock = {}, } = {}) {
+ var _a, _b, _c, _d;
+ super();
+ if (idBlock) {
+ this.isHexOnly = (_a = idBlock.isHexOnly) !== null && _a !== void 0 ? _a : false;
+ this.valueHexView = idBlock.valueHex ? BufferSourceConverter.toUint8Array(idBlock.valueHex) : EMPTY_VIEW;
+ this.tagClass = (_b = idBlock.tagClass) !== null && _b !== void 0 ? _b : -1;
+ this.tagNumber = (_c = idBlock.tagNumber) !== null && _c !== void 0 ? _c : -1;
+ this.isConstructed = (_d = idBlock.isConstructed) !== null && _d !== void 0 ? _d : false;
+ }
+ else {
+ this.tagClass = -1;
+ this.tagNumber = -1;
+ this.isConstructed = false;
+ }
+ }
+ toBER(sizeOnly = false) {
+ let firstOctet = 0;
+ switch (this.tagClass) {
+ case 1:
+ firstOctet |= 0x00;
+ break;
+ case 2:
+ firstOctet |= 0x40;
+ break;
+ case 3:
+ firstOctet |= 0x80;
+ break;
+ case 4:
+ firstOctet |= 0xC0;
+ break;
+ default:
+ this.error = "Unknown tag class";
+ return EMPTY_BUFFER$1;
+ }
+ if (this.isConstructed)
+ firstOctet |= 0x20;
+ if (this.tagNumber < 31 && !this.isHexOnly) {
+ const retView = new Uint8Array(1);
+ if (!sizeOnly) {
+ let number = this.tagNumber;
+ number &= 0x1F;
+ firstOctet |= number;
+ retView[0] = firstOctet;
+ }
+ return retView.buffer;
+ }
+ if (!this.isHexOnly) {
+ const encodedBuf = utilToBase(this.tagNumber, 7);
+ const encodedView = new Uint8Array(encodedBuf);
+ const size = encodedBuf.byteLength;
+ const retView = new Uint8Array(size + 1);
+ retView[0] = (firstOctet | 0x1F);
+ if (!sizeOnly) {
+ for (let i = 0; i < (size - 1); i++)
+ retView[i + 1] = encodedView[i] | 0x80;
+ retView[size] = encodedView[size - 1];
+ }
+ return retView.buffer;
+ }
+ const retView = new Uint8Array(this.valueHexView.byteLength + 1);
+ retView[0] = (firstOctet | 0x1F);
+ if (!sizeOnly) {
+ const curView = this.valueHexView;
+ for (let i = 0; i < (curView.length - 1); i++)
+ retView[i + 1] = curView[i] | 0x80;
+ retView[this.valueHexView.byteLength] = curView[curView.length - 1];
+ }
+ return retView.buffer;
+ }
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ const inputView = BufferSourceConverter.toUint8Array(inputBuffer);
+ if (!checkBufferParams(this, inputView, inputOffset, inputLength)) {
+ return -1;
+ }
+ const intBuffer = inputView.subarray(inputOffset, inputOffset + inputLength);
+ if (intBuffer.length === 0) {
+ this.error = "Zero buffer length";
+ return -1;
+ }
+ const tagClassMask = intBuffer[0] & 0xC0;
+ switch (tagClassMask) {
+ case 0x00:
+ this.tagClass = (1);
+ break;
+ case 0x40:
+ this.tagClass = (2);
+ break;
+ case 0x80:
+ this.tagClass = (3);
+ break;
+ case 0xC0:
+ this.tagClass = (4);
+ break;
+ default:
+ this.error = "Unknown tag class";
+ return -1;
+ }
+ this.isConstructed = (intBuffer[0] & 0x20) === 0x20;
+ this.isHexOnly = false;
+ const tagNumberMask = intBuffer[0] & 0x1F;
+ if (tagNumberMask !== 0x1F) {
+ this.tagNumber = (tagNumberMask);
+ this.blockLength = 1;
+ }
+ else {
+ let count = 1;
+ let intTagNumberBuffer = this.valueHexView = new Uint8Array(255);
+ let tagNumberBufferMaxLength = 255;
+ while (intBuffer[count] & 0x80) {
+ intTagNumberBuffer[count - 1] = intBuffer[count] & 0x7F;
+ count++;
+ if (count >= intBuffer.length) {
+ this.error = "End of input reached before message was fully decoded";
+ return -1;
+ }
+ if (count === tagNumberBufferMaxLength) {
+ tagNumberBufferMaxLength += 255;
+ const tempBufferView = new Uint8Array(tagNumberBufferMaxLength);
+ for (let i = 0; i < intTagNumberBuffer.length; i++)
+ tempBufferView[i] = intTagNumberBuffer[i];
+ intTagNumberBuffer = this.valueHexView = new Uint8Array(tagNumberBufferMaxLength);
+ }
+ }
+ this.blockLength = (count + 1);
+ intTagNumberBuffer[count - 1] = intBuffer[count] & 0x7F;
+ const tempBufferView = new Uint8Array(count);
+ for (let i = 0; i < count; i++)
+ tempBufferView[i] = intTagNumberBuffer[i];
+ intTagNumberBuffer = this.valueHexView = new Uint8Array(count);
+ intTagNumberBuffer.set(tempBufferView);
+ if (this.blockLength <= 9)
+ this.tagNumber = utilFromBase(intTagNumberBuffer, 7);
+ else {
+ this.isHexOnly = true;
+ this.warnings.push("Tag too long, represented as hex-coded");
+ }
+ }
+ if (((this.tagClass === 1)) &&
+ (this.isConstructed)) {
+ switch (this.tagNumber) {
+ case 1:
+ case 2:
+ case 5:
+ case 6:
+ case 9:
+ case 13:
+ case 14:
+ case 23:
+ case 24:
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ this.error = "Constructed encoding used for primitive type";
+ return -1;
+ }
+ }
+ return (inputOffset + this.blockLength);
+ }
+ toJSON() {
+ return {
+ ...super.toJSON(),
+ tagClass: this.tagClass,
+ tagNumber: this.tagNumber,
+ isConstructed: this.isConstructed,
+ };
+ }
+}
+LocalIdentificationBlock.NAME = "identificationBlock";
+
+class LocalLengthBlock extends LocalBaseBlock {
+ constructor({ lenBlock = {}, } = {}) {
+ var _a, _b, _c;
+ super();
+ this.isIndefiniteForm = (_a = lenBlock.isIndefiniteForm) !== null && _a !== void 0 ? _a : false;
+ this.longFormUsed = (_b = lenBlock.longFormUsed) !== null && _b !== void 0 ? _b : false;
+ this.length = (_c = lenBlock.length) !== null && _c !== void 0 ? _c : 0;
+ }
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ const view = BufferSourceConverter.toUint8Array(inputBuffer);
+ if (!checkBufferParams(this, view, inputOffset, inputLength)) {
+ return -1;
+ }
+ const intBuffer = view.subarray(inputOffset, inputOffset + inputLength);
+ if (intBuffer.length === 0) {
+ this.error = "Zero buffer length";
+ return -1;
+ }
+ if (intBuffer[0] === 0xFF) {
+ this.error = "Length block 0xFF is reserved by standard";
+ return -1;
+ }
+ this.isIndefiniteForm = intBuffer[0] === 0x80;
+ if (this.isIndefiniteForm) {
+ this.blockLength = 1;
+ return (inputOffset + this.blockLength);
+ }
+ this.longFormUsed = !!(intBuffer[0] & 0x80);
+ if (this.longFormUsed === false) {
+ this.length = (intBuffer[0]);
+ this.blockLength = 1;
+ return (inputOffset + this.blockLength);
+ }
+ const count = intBuffer[0] & 0x7F;
+ if (count > 8) {
+ this.error = "Too big integer";
+ return -1;
+ }
+ if ((count + 1) > intBuffer.length) {
+ this.error = "End of input reached before message was fully decoded";
+ return -1;
+ }
+ const lenOffset = inputOffset + 1;
+ const lengthBufferView = view.subarray(lenOffset, lenOffset + count);
+ if (lengthBufferView[count - 1] === 0x00)
+ this.warnings.push("Needlessly long encoded length");
+ this.length = utilFromBase(lengthBufferView, 8);
+ if (this.longFormUsed && (this.length <= 127))
+ this.warnings.push("Unnecessary usage of long length form");
+ this.blockLength = count + 1;
+ return (inputOffset + this.blockLength);
+ }
+ toBER(sizeOnly = false) {
+ let retBuf;
+ let retView;
+ if (this.length > 127)
+ this.longFormUsed = true;
+ if (this.isIndefiniteForm) {
+ retBuf = new ArrayBuffer(1);
+ if (sizeOnly === false) {
+ retView = new Uint8Array(retBuf);
+ retView[0] = 0x80;
+ }
+ return retBuf;
+ }
+ if (this.longFormUsed) {
+ const encodedBuf = utilToBase(this.length, 8);
+ if (encodedBuf.byteLength > 127) {
+ this.error = "Too big length";
+ return (EMPTY_BUFFER$1);
+ }
+ retBuf = new ArrayBuffer(encodedBuf.byteLength + 1);
+ if (sizeOnly)
+ return retBuf;
+ const encodedView = new Uint8Array(encodedBuf);
+ retView = new Uint8Array(retBuf);
+ retView[0] = encodedBuf.byteLength | 0x80;
+ for (let i = 0; i < encodedBuf.byteLength; i++)
+ retView[i + 1] = encodedView[i];
+ return retBuf;
+ }
+ retBuf = new ArrayBuffer(1);
+ if (sizeOnly === false) {
+ retView = new Uint8Array(retBuf);
+ retView[0] = this.length;
+ }
+ return retBuf;
+ }
+ toJSON() {
+ return {
+ ...super.toJSON(),
+ isIndefiniteForm: this.isIndefiniteForm,
+ longFormUsed: this.longFormUsed,
+ length: this.length,
+ };
+ }
+}
+LocalLengthBlock.NAME = "lengthBlock";
+
+const typeStore = {};
+
+class BaseBlock extends LocalBaseBlock {
+ constructor({ name = EMPTY_STRING$1, optional = false, primitiveSchema, ...parameters } = {}, valueBlockType) {
+ super(parameters);
+ this.name = name;
+ this.optional = optional;
+ if (primitiveSchema) {
+ this.primitiveSchema = primitiveSchema;
+ }
+ this.idBlock = new LocalIdentificationBlock(parameters);
+ this.lenBlock = new LocalLengthBlock(parameters);
+ this.valueBlock = valueBlockType ? new valueBlockType(parameters) : new ValueBlock(parameters);
+ }
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, (this.lenBlock.isIndefiniteForm) ? inputLength : this.lenBlock.length);
+ if (resultOffset === -1) {
+ this.error = this.valueBlock.error;
+ return resultOffset;
+ }
+ if (!this.idBlock.error.length)
+ this.blockLength += this.idBlock.blockLength;
+ if (!this.lenBlock.error.length)
+ this.blockLength += this.lenBlock.blockLength;
+ if (!this.valueBlock.error.length)
+ this.blockLength += this.valueBlock.blockLength;
+ return resultOffset;
+ }
+ toBER(sizeOnly, writer) {
+ const _writer = writer || new ViewWriter();
+ if (!writer) {
+ prepareIndefiniteForm(this);
+ }
+ const idBlockBuf = this.idBlock.toBER(sizeOnly);
+ _writer.write(idBlockBuf);
+ if (this.lenBlock.isIndefiniteForm) {
+ _writer.write(new Uint8Array([0x80]).buffer);
+ this.valueBlock.toBER(sizeOnly, _writer);
+ _writer.write(new ArrayBuffer(2));
+ }
+ else {
+ const valueBlockBuf = this.valueBlock.toBER(sizeOnly);
+ this.lenBlock.length = valueBlockBuf.byteLength;
+ const lenBlockBuf = this.lenBlock.toBER(sizeOnly);
+ _writer.write(lenBlockBuf);
+ _writer.write(valueBlockBuf);
+ }
+ if (!writer) {
+ return _writer.final();
+ }
+ return EMPTY_BUFFER$1;
+ }
+ toJSON() {
+ const object = {
+ ...super.toJSON(),
+ idBlock: this.idBlock.toJSON(),
+ lenBlock: this.lenBlock.toJSON(),
+ valueBlock: this.valueBlock.toJSON(),
+ name: this.name,
+ optional: this.optional,
+ };
+ if (this.primitiveSchema)
+ object.primitiveSchema = this.primitiveSchema.toJSON();
+ return object;
+ }
+ toString(encoding = "ascii") {
+ if (encoding === "ascii") {
+ return this.onAsciiEncoding();
+ }
+ return Convert.ToHex(this.toBER());
+ }
+ onAsciiEncoding() {
+ return `${this.constructor.NAME} : ${Convert.ToHex(this.valueBlock.valueBeforeDecodeView)}`;
+ }
+ isEqual(other) {
+ if (this === other) {
+ return true;
+ }
+ if (!(other instanceof this.constructor)) {
+ return false;
+ }
+ const thisRaw = this.toBER();
+ const otherRaw = other.toBER();
+ return isEqualBuffer(thisRaw, otherRaw);
+ }
+}
+BaseBlock.NAME = "BaseBlock";
+function prepareIndefiniteForm(baseBlock) {
+ if (baseBlock instanceof typeStore.Constructed) {
+ for (const value of baseBlock.valueBlock.value) {
+ if (prepareIndefiniteForm(value)) {
+ baseBlock.lenBlock.isIndefiniteForm = true;
+ }
+ }
+ }
+ return !!baseBlock.lenBlock.isIndefiniteForm;
+}
+
+class BaseStringBlock extends BaseBlock {
+ constructor({ value = EMPTY_STRING$1, ...parameters } = {}, stringValueBlockType) {
+ super(parameters, stringValueBlockType);
+ if (value) {
+ this.fromString(value);
+ }
+ }
+ getValue() {
+ return this.valueBlock.value;
+ }
+ setValue(value) {
+ this.valueBlock.value = value;
+ }
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, (this.lenBlock.isIndefiniteForm) ? inputLength : this.lenBlock.length);
+ if (resultOffset === -1) {
+ this.error = this.valueBlock.error;
+ return resultOffset;
+ }
+ this.fromBuffer(this.valueBlock.valueHexView);
+ if (!this.idBlock.error.length)
+ this.blockLength += this.idBlock.blockLength;
+ if (!this.lenBlock.error.length)
+ this.blockLength += this.lenBlock.blockLength;
+ if (!this.valueBlock.error.length)
+ this.blockLength += this.valueBlock.blockLength;
+ return resultOffset;
+ }
+ onAsciiEncoding() {
+ return `${this.constructor.NAME} : '${this.valueBlock.value}'`;
+ }
+}
+BaseStringBlock.NAME = "BaseStringBlock";
+
+class LocalPrimitiveValueBlock extends HexBlock(ValueBlock) {
+ constructor({ isHexOnly = true, ...parameters } = {}) {
+ super(parameters);
+ this.isHexOnly = isHexOnly;
+ }
+}
+LocalPrimitiveValueBlock.NAME = "PrimitiveValueBlock";
+
+var _a$w;
+class Primitive extends BaseBlock {
+ constructor(parameters = {}) {
+ super(parameters, LocalPrimitiveValueBlock);
+ this.idBlock.isConstructed = false;
+ }
+}
+_a$w = Primitive;
+(() => {
+ typeStore.Primitive = _a$w;
+})();
+Primitive.NAME = "PRIMITIVE";
+
+function localChangeType(inputObject, newType) {
+ if (inputObject instanceof newType) {
+ return inputObject;
+ }
+ const newObject = new newType();
+ newObject.idBlock = inputObject.idBlock;
+ newObject.lenBlock = inputObject.lenBlock;
+ newObject.warnings = inputObject.warnings;
+ newObject.valueBeforeDecodeView = inputObject.valueBeforeDecodeView;
+ return newObject;
+}
+function localFromBER(inputBuffer, inputOffset = 0, inputLength = inputBuffer.length) {
+ const incomingOffset = inputOffset;
+ let returnObject = new BaseBlock({}, ValueBlock);
+ const baseBlock = new LocalBaseBlock();
+ if (!checkBufferParams(baseBlock, inputBuffer, inputOffset, inputLength)) {
+ returnObject.error = baseBlock.error;
+ return {
+ offset: -1,
+ result: returnObject
+ };
+ }
+ const intBuffer = inputBuffer.subarray(inputOffset, inputOffset + inputLength);
+ if (!intBuffer.length) {
+ returnObject.error = "Zero buffer length";
+ return {
+ offset: -1,
+ result: returnObject
+ };
+ }
+ let resultOffset = returnObject.idBlock.fromBER(inputBuffer, inputOffset, inputLength);
+ if (returnObject.idBlock.warnings.length) {
+ returnObject.warnings.concat(returnObject.idBlock.warnings);
+ }
+ if (resultOffset === -1) {
+ returnObject.error = returnObject.idBlock.error;
+ return {
+ offset: -1,
+ result: returnObject
+ };
+ }
+ inputOffset = resultOffset;
+ inputLength -= returnObject.idBlock.blockLength;
+ resultOffset = returnObject.lenBlock.fromBER(inputBuffer, inputOffset, inputLength);
+ if (returnObject.lenBlock.warnings.length) {
+ returnObject.warnings.concat(returnObject.lenBlock.warnings);
+ }
+ if (resultOffset === -1) {
+ returnObject.error = returnObject.lenBlock.error;
+ return {
+ offset: -1,
+ result: returnObject
+ };
+ }
+ inputOffset = resultOffset;
+ inputLength -= returnObject.lenBlock.blockLength;
+ if (!returnObject.idBlock.isConstructed &&
+ returnObject.lenBlock.isIndefiniteForm) {
+ returnObject.error = "Indefinite length form used for primitive encoding form";
+ return {
+ offset: -1,
+ result: returnObject
+ };
+ }
+ let newASN1Type = BaseBlock;
+ switch (returnObject.idBlock.tagClass) {
+ case 1:
+ if ((returnObject.idBlock.tagNumber >= 37) &&
+ (returnObject.idBlock.isHexOnly === false)) {
+ returnObject.error = "UNIVERSAL 37 and upper tags are reserved by ASN.1 standard";
+ return {
+ offset: -1,
+ result: returnObject
+ };
+ }
+ switch (returnObject.idBlock.tagNumber) {
+ case 0:
+ if ((returnObject.idBlock.isConstructed) &&
+ (returnObject.lenBlock.length > 0)) {
+ returnObject.error = "Type [UNIVERSAL 0] is reserved";
+ return {
+ offset: -1,
+ result: returnObject
+ };
+ }
+ newASN1Type = typeStore.EndOfContent;
+ break;
+ case 1:
+ newASN1Type = typeStore.Boolean;
+ break;
+ case 2:
+ newASN1Type = typeStore.Integer;
+ break;
+ case 3:
+ newASN1Type = typeStore.BitString;
+ break;
+ case 4:
+ newASN1Type = typeStore.OctetString;
+ break;
+ case 5:
+ newASN1Type = typeStore.Null;
+ break;
+ case 6:
+ newASN1Type = typeStore.ObjectIdentifier;
+ break;
+ case 10:
+ newASN1Type = typeStore.Enumerated;
+ break;
+ case 12:
+ newASN1Type = typeStore.Utf8String;
+ break;
+ case 13:
+ newASN1Type = typeStore.RelativeObjectIdentifier;
+ break;
+ case 14:
+ newASN1Type = typeStore.TIME;
+ break;
+ case 15:
+ returnObject.error = "[UNIVERSAL 15] is reserved by ASN.1 standard";
+ return {
+ offset: -1,
+ result: returnObject
+ };
+ case 16:
+ newASN1Type = typeStore.Sequence;
+ break;
+ case 17:
+ newASN1Type = typeStore.Set;
+ break;
+ case 18:
+ newASN1Type = typeStore.NumericString;
+ break;
+ case 19:
+ newASN1Type = typeStore.PrintableString;
+ break;
+ case 20:
+ newASN1Type = typeStore.TeletexString;
+ break;
+ case 21:
+ newASN1Type = typeStore.VideotexString;
+ break;
+ case 22:
+ newASN1Type = typeStore.IA5String;
+ break;
+ case 23:
+ newASN1Type = typeStore.UTCTime;
+ break;
+ case 24:
+ newASN1Type = typeStore.GeneralizedTime;
+ break;
+ case 25:
+ newASN1Type = typeStore.GraphicString;
+ break;
+ case 26:
+ newASN1Type = typeStore.VisibleString;
+ break;
+ case 27:
+ newASN1Type = typeStore.GeneralString;
+ break;
+ case 28:
+ newASN1Type = typeStore.UniversalString;
+ break;
+ case 29:
+ newASN1Type = typeStore.CharacterString;
+ break;
+ case 30:
+ newASN1Type = typeStore.BmpString;
+ break;
+ case 31:
+ newASN1Type = typeStore.DATE;
+ break;
+ case 32:
+ newASN1Type = typeStore.TimeOfDay;
+ break;
+ case 33:
+ newASN1Type = typeStore.DateTime;
+ break;
+ case 34:
+ newASN1Type = typeStore.Duration;
+ break;
+ default: {
+ const newObject = returnObject.idBlock.isConstructed
+ ? new typeStore.Constructed()
+ : new typeStore.Primitive();
+ newObject.idBlock = returnObject.idBlock;
+ newObject.lenBlock = returnObject.lenBlock;
+ newObject.warnings = returnObject.warnings;
+ returnObject = newObject;
+ }
+ }
+ break;
+ case 2:
+ case 3:
+ case 4:
+ default: {
+ newASN1Type = returnObject.idBlock.isConstructed
+ ? typeStore.Constructed
+ : typeStore.Primitive;
+ }
+ }
+ returnObject = localChangeType(returnObject, newASN1Type);
+ resultOffset = returnObject.fromBER(inputBuffer, inputOffset, returnObject.lenBlock.isIndefiniteForm ? inputLength : returnObject.lenBlock.length);
+ returnObject.valueBeforeDecodeView = inputBuffer.subarray(incomingOffset, incomingOffset + returnObject.blockLength);
+ return {
+ offset: resultOffset,
+ result: returnObject
+ };
+}
+function fromBER(inputBuffer) {
+ if (!inputBuffer.byteLength) {
+ const result = new BaseBlock({}, ValueBlock);
+ result.error = "Input buffer has zero length";
+ return {
+ offset: -1,
+ result
+ };
+ }
+ return localFromBER(BufferSourceConverter.toUint8Array(inputBuffer).slice(), 0, inputBuffer.byteLength);
+}
+
+function checkLen(indefiniteLength, length) {
+ if (indefiniteLength) {
+ return 1;
+ }
+ return length;
+}
+class LocalConstructedValueBlock extends ValueBlock {
+ constructor({ value = [], isIndefiniteForm = false, ...parameters } = {}) {
+ super(parameters);
+ this.value = value;
+ this.isIndefiniteForm = isIndefiniteForm;
+ }
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ const view = BufferSourceConverter.toUint8Array(inputBuffer);
+ if (!checkBufferParams(this, view, inputOffset, inputLength)) {
+ return -1;
+ }
+ this.valueBeforeDecodeView = view.subarray(inputOffset, inputOffset + inputLength);
+ if (this.valueBeforeDecodeView.length === 0) {
+ this.warnings.push("Zero buffer length");
+ return inputOffset;
+ }
+ let currentOffset = inputOffset;
+ while (checkLen(this.isIndefiniteForm, inputLength) > 0) {
+ const returnObject = localFromBER(view, currentOffset, inputLength);
+ if (returnObject.offset === -1) {
+ this.error = returnObject.result.error;
+ this.warnings.concat(returnObject.result.warnings);
+ return -1;
+ }
+ currentOffset = returnObject.offset;
+ this.blockLength += returnObject.result.blockLength;
+ inputLength -= returnObject.result.blockLength;
+ this.value.push(returnObject.result);
+ if (this.isIndefiniteForm && returnObject.result.constructor.NAME === END_OF_CONTENT_NAME) {
+ break;
+ }
+ }
+ if (this.isIndefiniteForm) {
+ if (this.value[this.value.length - 1].constructor.NAME === END_OF_CONTENT_NAME) {
+ this.value.pop();
+ }
+ else {
+ this.warnings.push("No EndOfContent block encoded");
+ }
+ }
+ return currentOffset;
+ }
+ toBER(sizeOnly, writer) {
+ const _writer = writer || new ViewWriter();
+ for (let i = 0; i < this.value.length; i++) {
+ this.value[i].toBER(sizeOnly, _writer);
+ }
+ if (!writer) {
+ return _writer.final();
+ }
+ return EMPTY_BUFFER$1;
+ }
+ toJSON() {
+ const object = {
+ ...super.toJSON(),
+ isIndefiniteForm: this.isIndefiniteForm,
+ value: [],
+ };
+ for (const value of this.value) {
+ object.value.push(value.toJSON());
+ }
+ return object;
+ }
+}
+LocalConstructedValueBlock.NAME = "ConstructedValueBlock";
+
+var _a$v;
+class Constructed extends BaseBlock {
+ constructor(parameters = {}) {
+ super(parameters, LocalConstructedValueBlock);
+ this.idBlock.isConstructed = true;
+ }
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm;
+ const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, (this.lenBlock.isIndefiniteForm) ? inputLength : this.lenBlock.length);
+ if (resultOffset === -1) {
+ this.error = this.valueBlock.error;
+ return resultOffset;
+ }
+ if (!this.idBlock.error.length)
+ this.blockLength += this.idBlock.blockLength;
+ if (!this.lenBlock.error.length)
+ this.blockLength += this.lenBlock.blockLength;
+ if (!this.valueBlock.error.length)
+ this.blockLength += this.valueBlock.blockLength;
+ return resultOffset;
+ }
+ onAsciiEncoding() {
+ const values = [];
+ for (const value of this.valueBlock.value) {
+ values.push(value.toString("ascii").split("\n").map(o => ` ${o}`).join("\n"));
+ }
+ const blockName = this.idBlock.tagClass === 3
+ ? `[${this.idBlock.tagNumber}]`
+ : this.constructor.NAME;
+ return values.length
+ ? `${blockName} :\n${values.join("\n")}`
+ : `${blockName} :`;
+ }
+}
+_a$v = Constructed;
+(() => {
+ typeStore.Constructed = _a$v;
+})();
+Constructed.NAME = "CONSTRUCTED";
+
+class LocalEndOfContentValueBlock extends ValueBlock {
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ return inputOffset;
+ }
+ toBER(sizeOnly) {
+ return EMPTY_BUFFER$1;
+ }
+}
+LocalEndOfContentValueBlock.override = "EndOfContentValueBlock";
+
+var _a$u;
+class EndOfContent extends BaseBlock {
+ constructor(parameters = {}) {
+ super(parameters, LocalEndOfContentValueBlock);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 0;
+ }
+}
+_a$u = EndOfContent;
+(() => {
+ typeStore.EndOfContent = _a$u;
+})();
+EndOfContent.NAME = END_OF_CONTENT_NAME;
+
+var _a$t;
+class Null extends BaseBlock {
+ constructor(parameters = {}) {
+ super(parameters, ValueBlock);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 5;
+ }
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ if (this.lenBlock.length > 0)
+ this.warnings.push("Non-zero length of value block for Null type");
+ if (!this.idBlock.error.length)
+ this.blockLength += this.idBlock.blockLength;
+ if (!this.lenBlock.error.length)
+ this.blockLength += this.lenBlock.blockLength;
+ this.blockLength += inputLength;
+ if ((inputOffset + inputLength) > inputBuffer.byteLength) {
+ this.error = "End of input reached before message was fully decoded (inconsistent offset and length values)";
+ return -1;
+ }
+ return (inputOffset + inputLength);
+ }
+ toBER(sizeOnly, writer) {
+ const retBuf = new ArrayBuffer(2);
+ if (!sizeOnly) {
+ const retView = new Uint8Array(retBuf);
+ retView[0] = 0x05;
+ retView[1] = 0x00;
+ }
+ if (writer) {
+ writer.write(retBuf);
+ }
+ return retBuf;
+ }
+ onAsciiEncoding() {
+ return `${this.constructor.NAME}`;
+ }
+}
+_a$t = Null;
+(() => {
+ typeStore.Null = _a$t;
+})();
+Null.NAME = "NULL";
+
+class LocalBooleanValueBlock extends HexBlock(ValueBlock) {
+ constructor({ value, ...parameters } = {}) {
+ super(parameters);
+ if (parameters.valueHex) {
+ this.valueHexView = BufferSourceConverter.toUint8Array(parameters.valueHex);
+ }
+ else {
+ this.valueHexView = new Uint8Array(1);
+ }
+ if (value) {
+ this.value = value;
+ }
+ }
+ get value() {
+ for (const octet of this.valueHexView) {
+ if (octet > 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+ set value(value) {
+ this.valueHexView[0] = value ? 0xFF : 0x00;
+ }
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ const inputView = BufferSourceConverter.toUint8Array(inputBuffer);
+ if (!checkBufferParams(this, inputView, inputOffset, inputLength)) {
+ return -1;
+ }
+ this.valueHexView = inputView.subarray(inputOffset, inputOffset + inputLength);
+ if (inputLength > 1)
+ this.warnings.push("Boolean value encoded in more then 1 octet");
+ this.isHexOnly = true;
+ utilDecodeTC.call(this);
+ this.blockLength = inputLength;
+ return (inputOffset + inputLength);
+ }
+ toBER() {
+ return this.valueHexView.slice();
+ }
+ toJSON() {
+ return {
+ ...super.toJSON(),
+ value: this.value,
+ };
+ }
+}
+LocalBooleanValueBlock.NAME = "BooleanValueBlock";
+
+var _a$s;
+class Boolean extends BaseBlock {
+ constructor(parameters = {}) {
+ super(parameters, LocalBooleanValueBlock);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 1;
+ }
+ getValue() {
+ return this.valueBlock.value;
+ }
+ setValue(value) {
+ this.valueBlock.value = value;
+ }
+ onAsciiEncoding() {
+ return `${this.constructor.NAME} : ${this.getValue}`;
+ }
+}
+_a$s = Boolean;
+(() => {
+ typeStore.Boolean = _a$s;
+})();
+Boolean.NAME = "BOOLEAN";
+
+class LocalOctetStringValueBlock extends HexBlock(LocalConstructedValueBlock) {
+ constructor({ isConstructed = false, ...parameters } = {}) {
+ super(parameters);
+ this.isConstructed = isConstructed;
+ }
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ let resultOffset = 0;
+ if (this.isConstructed) {
+ this.isHexOnly = false;
+ resultOffset = LocalConstructedValueBlock.prototype.fromBER.call(this, inputBuffer, inputOffset, inputLength);
+ if (resultOffset === -1)
+ return resultOffset;
+ for (let i = 0; i < this.value.length; i++) {
+ const currentBlockName = this.value[i].constructor.NAME;
+ if (currentBlockName === END_OF_CONTENT_NAME) {
+ if (this.isIndefiniteForm)
+ break;
+ else {
+ this.error = "EndOfContent is unexpected, OCTET STRING may consists of OCTET STRINGs only";
+ return -1;
+ }
+ }
+ if (currentBlockName !== OCTET_STRING_NAME) {
+ this.error = "OCTET STRING may consists of OCTET STRINGs only";
+ return -1;
+ }
+ }
+ }
+ else {
+ this.isHexOnly = true;
+ resultOffset = super.fromBER(inputBuffer, inputOffset, inputLength);
+ this.blockLength = inputLength;
+ }
+ return resultOffset;
+ }
+ toBER(sizeOnly, writer) {
+ if (this.isConstructed)
+ return LocalConstructedValueBlock.prototype.toBER.call(this, sizeOnly, writer);
+ return sizeOnly
+ ? new ArrayBuffer(this.valueHexView.byteLength)
+ : this.valueHexView.slice().buffer;
+ }
+ toJSON() {
+ return {
+ ...super.toJSON(),
+ isConstructed: this.isConstructed,
+ };
+ }
+}
+LocalOctetStringValueBlock.NAME = "OctetStringValueBlock";
+
+var _a$r;
+class OctetString extends BaseBlock {
+ constructor({ idBlock = {}, lenBlock = {}, ...parameters } = {}) {
+ var _b, _c;
+ (_b = parameters.isConstructed) !== null && _b !== void 0 ? _b : (parameters.isConstructed = !!((_c = parameters.value) === null || _c === void 0 ? void 0 : _c.length));
+ super({
+ idBlock: {
+ isConstructed: parameters.isConstructed,
+ ...idBlock,
+ },
+ lenBlock: {
+ ...lenBlock,
+ isIndefiniteForm: !!parameters.isIndefiniteForm,
+ },
+ ...parameters,
+ }, LocalOctetStringValueBlock);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 4;
+ }
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ this.valueBlock.isConstructed = this.idBlock.isConstructed;
+ this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm;
+ if (inputLength === 0) {
+ if (this.idBlock.error.length === 0)
+ this.blockLength += this.idBlock.blockLength;
+ if (this.lenBlock.error.length === 0)
+ this.blockLength += this.lenBlock.blockLength;
+ return inputOffset;
+ }
+ if (!this.valueBlock.isConstructed) {
+ const view = inputBuffer instanceof ArrayBuffer ? new Uint8Array(inputBuffer) : inputBuffer;
+ const buf = view.subarray(inputOffset, inputOffset + inputLength);
+ try {
+ if (buf.byteLength) {
+ const asn = localFromBER(buf, 0, buf.byteLength);
+ if (asn.offset !== -1 && asn.offset === inputLength) {
+ this.valueBlock.value = [asn.result];
+ }
+ }
+ }
+ catch (e) {
+ }
+ }
+ return super.fromBER(inputBuffer, inputOffset, inputLength);
+ }
+ onAsciiEncoding() {
+ if (this.valueBlock.isConstructed || (this.valueBlock.value && this.valueBlock.value.length)) {
+ return Constructed.prototype.onAsciiEncoding.call(this);
+ }
+ return `${this.constructor.NAME} : ${Convert.ToHex(this.valueBlock.valueHexView)}`;
+ }
+ getValue() {
+ if (!this.idBlock.isConstructed) {
+ return this.valueBlock.valueHexView.slice().buffer;
+ }
+ const array = [];
+ for (const content of this.valueBlock.value) {
+ if (content instanceof OctetString) {
+ array.push(content.valueBlock.valueHexView);
+ }
+ }
+ return BufferSourceConverter.concat(array);
+ }
+}
+_a$r = OctetString;
+(() => {
+ typeStore.OctetString = _a$r;
+})();
+OctetString.NAME = OCTET_STRING_NAME;
+
+class LocalBitStringValueBlock extends HexBlock(LocalConstructedValueBlock) {
+ constructor({ unusedBits = 0, isConstructed = false, ...parameters } = {}) {
+ super(parameters);
+ this.unusedBits = unusedBits;
+ this.isConstructed = isConstructed;
+ this.blockLength = this.valueHexView.byteLength;
+ }
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ if (!inputLength) {
+ return inputOffset;
+ }
+ let resultOffset = -1;
+ if (this.isConstructed) {
+ resultOffset = LocalConstructedValueBlock.prototype.fromBER.call(this, inputBuffer, inputOffset, inputLength);
+ if (resultOffset === -1)
+ return resultOffset;
+ for (const value of this.value) {
+ const currentBlockName = value.constructor.NAME;
+ if (currentBlockName === END_OF_CONTENT_NAME) {
+ if (this.isIndefiniteForm)
+ break;
+ else {
+ this.error = "EndOfContent is unexpected, BIT STRING may consists of BIT STRINGs only";
+ return -1;
+ }
+ }
+ if (currentBlockName !== BIT_STRING_NAME) {
+ this.error = "BIT STRING may consists of BIT STRINGs only";
+ return -1;
+ }
+ const valueBlock = value.valueBlock;
+ if ((this.unusedBits > 0) && (valueBlock.unusedBits > 0)) {
+ this.error = "Using of \"unused bits\" inside constructive BIT STRING allowed for least one only";
+ return -1;
+ }
+ this.unusedBits = valueBlock.unusedBits;
+ }
+ return resultOffset;
+ }
+ const inputView = BufferSourceConverter.toUint8Array(inputBuffer);
+ if (!checkBufferParams(this, inputView, inputOffset, inputLength)) {
+ return -1;
+ }
+ const intBuffer = inputView.subarray(inputOffset, inputOffset + inputLength);
+ this.unusedBits = intBuffer[0];
+ if (this.unusedBits > 7) {
+ this.error = "Unused bits for BitString must be in range 0-7";
+ return -1;
+ }
+ if (!this.unusedBits) {
+ const buf = intBuffer.subarray(1);
+ try {
+ if (buf.byteLength) {
+ const asn = localFromBER(buf, 0, buf.byteLength);
+ if (asn.offset !== -1 && asn.offset === (inputLength - 1)) {
+ this.value = [asn.result];
+ }
+ }
+ }
+ catch (e) {
+ }
+ }
+ this.valueHexView = intBuffer.subarray(1);
+ this.blockLength = intBuffer.length;
+ return (inputOffset + inputLength);
+ }
+ toBER(sizeOnly, writer) {
+ if (this.isConstructed) {
+ return LocalConstructedValueBlock.prototype.toBER.call(this, sizeOnly, writer);
+ }
+ if (sizeOnly) {
+ return new ArrayBuffer(this.valueHexView.byteLength + 1);
+ }
+ if (!this.valueHexView.byteLength) {
+ return EMPTY_BUFFER$1;
+ }
+ const retView = new Uint8Array(this.valueHexView.length + 1);
+ retView[0] = this.unusedBits;
+ retView.set(this.valueHexView, 1);
+ return retView.buffer;
+ }
+ toJSON() {
+ return {
+ ...super.toJSON(),
+ unusedBits: this.unusedBits,
+ isConstructed: this.isConstructed,
+ };
+ }
+}
+LocalBitStringValueBlock.NAME = "BitStringValueBlock";
+
+var _a$q;
+class BitString extends BaseBlock {
+ constructor({ idBlock = {}, lenBlock = {}, ...parameters } = {}) {
+ var _b, _c;
+ (_b = parameters.isConstructed) !== null && _b !== void 0 ? _b : (parameters.isConstructed = !!((_c = parameters.value) === null || _c === void 0 ? void 0 : _c.length));
+ super({
+ idBlock: {
+ isConstructed: parameters.isConstructed,
+ ...idBlock,
+ },
+ lenBlock: {
+ ...lenBlock,
+ isIndefiniteForm: !!parameters.isIndefiniteForm,
+ },
+ ...parameters,
+ }, LocalBitStringValueBlock);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 3;
+ }
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ this.valueBlock.isConstructed = this.idBlock.isConstructed;
+ this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm;
+ return super.fromBER(inputBuffer, inputOffset, inputLength);
+ }
+ onAsciiEncoding() {
+ if (this.valueBlock.isConstructed || (this.valueBlock.value && this.valueBlock.value.length)) {
+ return Constructed.prototype.onAsciiEncoding.call(this);
+ }
+ else {
+ const bits = [];
+ const valueHex = this.valueBlock.valueHexView;
+ for (const byte of valueHex) {
+ bits.push(byte.toString(2).padStart(8, "0"));
+ }
+ const bitsStr = bits.join("");
+ return `${this.constructor.NAME} : ${bitsStr.substring(0, bitsStr.length - this.valueBlock.unusedBits)}`;
+ }
+ }
+}
+_a$q = BitString;
+(() => {
+ typeStore.BitString = _a$q;
+})();
+BitString.NAME = BIT_STRING_NAME;
+
+var _a$p;
+function viewAdd(first, second) {
+ const c = new Uint8Array([0]);
+ const firstView = new Uint8Array(first);
+ const secondView = new Uint8Array(second);
+ let firstViewCopy = firstView.slice(0);
+ const firstViewCopyLength = firstViewCopy.length - 1;
+ const secondViewCopy = secondView.slice(0);
+ const secondViewCopyLength = secondViewCopy.length - 1;
+ let value = 0;
+ const max = (secondViewCopyLength < firstViewCopyLength) ? firstViewCopyLength : secondViewCopyLength;
+ let counter = 0;
+ for (let i = max; i >= 0; i--, counter++) {
+ switch (true) {
+ case (counter < secondViewCopy.length):
+ value = firstViewCopy[firstViewCopyLength - counter] + secondViewCopy[secondViewCopyLength - counter] + c[0];
+ break;
+ default:
+ value = firstViewCopy[firstViewCopyLength - counter] + c[0];
+ }
+ c[0] = value / 10;
+ switch (true) {
+ case (counter >= firstViewCopy.length):
+ firstViewCopy = utilConcatView(new Uint8Array([value % 10]), firstViewCopy);
+ break;
+ default:
+ firstViewCopy[firstViewCopyLength - counter] = value % 10;
+ }
+ }
+ if (c[0] > 0)
+ firstViewCopy = utilConcatView(c, firstViewCopy);
+ return firstViewCopy;
+}
+function power2(n) {
+ if (n >= powers2.length) {
+ for (let p = powers2.length; p <= n; p++) {
+ const c = new Uint8Array([0]);
+ let digits = (powers2[p - 1]).slice(0);
+ for (let i = (digits.length - 1); i >= 0; i--) {
+ const newValue = new Uint8Array([(digits[i] << 1) + c[0]]);
+ c[0] = newValue[0] / 10;
+ digits[i] = newValue[0] % 10;
+ }
+ if (c[0] > 0)
+ digits = utilConcatView(c, digits);
+ powers2.push(digits);
+ }
+ }
+ return powers2[n];
+}
+function viewSub(first, second) {
+ let b = 0;
+ const firstView = new Uint8Array(first);
+ const secondView = new Uint8Array(second);
+ const firstViewCopy = firstView.slice(0);
+ const firstViewCopyLength = firstViewCopy.length - 1;
+ const secondViewCopy = secondView.slice(0);
+ const secondViewCopyLength = secondViewCopy.length - 1;
+ let value;
+ let counter = 0;
+ for (let i = secondViewCopyLength; i >= 0; i--, counter++) {
+ value = firstViewCopy[firstViewCopyLength - counter] - secondViewCopy[secondViewCopyLength - counter] - b;
+ switch (true) {
+ case (value < 0):
+ b = 1;
+ firstViewCopy[firstViewCopyLength - counter] = value + 10;
+ break;
+ default:
+ b = 0;
+ firstViewCopy[firstViewCopyLength - counter] = value;
+ }
+ }
+ if (b > 0) {
+ for (let i = (firstViewCopyLength - secondViewCopyLength + 1); i >= 0; i--, counter++) {
+ value = firstViewCopy[firstViewCopyLength - counter] - b;
+ if (value < 0) {
+ b = 1;
+ firstViewCopy[firstViewCopyLength - counter] = value + 10;
+ }
+ else {
+ b = 0;
+ firstViewCopy[firstViewCopyLength - counter] = value;
+ break;
+ }
+ }
+ }
+ return firstViewCopy.slice();
+}
+class LocalIntegerValueBlock extends HexBlock(ValueBlock) {
+ constructor({ value, ...parameters } = {}) {
+ super(parameters);
+ this._valueDec = 0;
+ if (parameters.valueHex) {
+ this.setValueHex();
+ }
+ if (value !== undefined) {
+ this.valueDec = value;
+ }
+ }
+ setValueHex() {
+ if (this.valueHexView.length >= 4) {
+ this.warnings.push("Too big Integer for decoding, hex only");
+ this.isHexOnly = true;
+ this._valueDec = 0;
+ }
+ else {
+ this.isHexOnly = false;
+ if (this.valueHexView.length > 0) {
+ this._valueDec = utilDecodeTC.call(this);
+ }
+ }
+ }
+ set valueDec(v) {
+ this._valueDec = v;
+ this.isHexOnly = false;
+ this.valueHexView = new Uint8Array(utilEncodeTC(v));
+ }
+ get valueDec() {
+ return this._valueDec;
+ }
+ fromDER(inputBuffer, inputOffset, inputLength, expectedLength = 0) {
+ const offset = this.fromBER(inputBuffer, inputOffset, inputLength);
+ if (offset === -1)
+ return offset;
+ const view = this.valueHexView;
+ if ((view[0] === 0x00) && ((view[1] & 0x80) !== 0)) {
+ this.valueHexView = view.subarray(1);
+ }
+ else {
+ if (expectedLength !== 0) {
+ if (view.length < expectedLength) {
+ if ((expectedLength - view.length) > 1)
+ expectedLength = view.length + 1;
+ this.valueHexView = view.subarray(expectedLength - view.length);
+ }
+ }
+ }
+ return offset;
+ }
+ toDER(sizeOnly = false) {
+ const view = this.valueHexView;
+ switch (true) {
+ case ((view[0] & 0x80) !== 0):
+ {
+ const updatedView = new Uint8Array(this.valueHexView.length + 1);
+ updatedView[0] = 0x00;
+ updatedView.set(view, 1);
+ this.valueHexView = updatedView;
+ }
+ break;
+ case ((view[0] === 0x00) && ((view[1] & 0x80) === 0)):
+ {
+ this.valueHexView = this.valueHexView.subarray(1);
+ }
+ break;
+ }
+ return this.toBER(sizeOnly);
+ }
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ const resultOffset = super.fromBER(inputBuffer, inputOffset, inputLength);
+ if (resultOffset === -1) {
+ return resultOffset;
+ }
+ this.setValueHex();
+ return resultOffset;
+ }
+ toBER(sizeOnly) {
+ return sizeOnly
+ ? new ArrayBuffer(this.valueHexView.length)
+ : this.valueHexView.slice().buffer;
+ }
+ toJSON() {
+ return {
+ ...super.toJSON(),
+ valueDec: this.valueDec,
+ };
+ }
+ toString() {
+ const firstBit = (this.valueHexView.length * 8) - 1;
+ let digits = new Uint8Array((this.valueHexView.length * 8) / 3);
+ let bitNumber = 0;
+ let currentByte;
+ const asn1View = this.valueHexView;
+ let result = "";
+ let flag = false;
+ for (let byteNumber = (asn1View.byteLength - 1); byteNumber >= 0; byteNumber--) {
+ currentByte = asn1View[byteNumber];
+ for (let i = 0; i < 8; i++) {
+ if ((currentByte & 1) === 1) {
+ switch (bitNumber) {
+ case firstBit:
+ digits = viewSub(power2(bitNumber), digits);
+ result = "-";
+ break;
+ default:
+ digits = viewAdd(digits, power2(bitNumber));
+ }
+ }
+ bitNumber++;
+ currentByte >>= 1;
+ }
+ }
+ for (let i = 0; i < digits.length; i++) {
+ if (digits[i])
+ flag = true;
+ if (flag)
+ result += digitsString.charAt(digits[i]);
+ }
+ if (flag === false)
+ result += digitsString.charAt(0);
+ return result;
+ }
+}
+_a$p = LocalIntegerValueBlock;
+LocalIntegerValueBlock.NAME = "IntegerValueBlock";
+(() => {
+ Object.defineProperty(_a$p.prototype, "valueHex", {
+ set: function (v) {
+ this.valueHexView = new Uint8Array(v);
+ this.setValueHex();
+ },
+ get: function () {
+ return this.valueHexView.slice().buffer;
+ },
+ });
+})();
+
+var _a$o;
+class Integer extends BaseBlock {
+ constructor(parameters = {}) {
+ super(parameters, LocalIntegerValueBlock);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 2;
+ }
+ toBigInt() {
+ assertBigInt();
+ return BigInt(this.valueBlock.toString());
+ }
+ static fromBigInt(value) {
+ assertBigInt();
+ const bigIntValue = BigInt(value);
+ const writer = new ViewWriter();
+ const hex = bigIntValue.toString(16).replace(/^-/, "");
+ const view = new Uint8Array(Convert.FromHex(hex));
+ if (bigIntValue < 0) {
+ const first = new Uint8Array(view.length + (view[0] & 0x80 ? 1 : 0));
+ first[0] |= 0x80;
+ const firstInt = BigInt(`0x${Convert.ToHex(first)}`);
+ const secondInt = firstInt + bigIntValue;
+ const second = BufferSourceConverter.toUint8Array(Convert.FromHex(secondInt.toString(16)));
+ second[0] |= 0x80;
+ writer.write(second);
+ }
+ else {
+ if (view[0] & 0x80) {
+ writer.write(new Uint8Array([0]));
+ }
+ writer.write(view);
+ }
+ const res = new Integer({
+ valueHex: writer.final(),
+ });
+ return res;
+ }
+ convertToDER() {
+ const integer = new Integer({ valueHex: this.valueBlock.valueHexView });
+ integer.valueBlock.toDER();
+ return integer;
+ }
+ convertFromDER() {
+ return new Integer({
+ valueHex: this.valueBlock.valueHexView[0] === 0
+ ? this.valueBlock.valueHexView.subarray(1)
+ : this.valueBlock.valueHexView,
+ });
+ }
+ onAsciiEncoding() {
+ return `${this.constructor.NAME} : ${this.valueBlock.toString()}`;
+ }
+}
+_a$o = Integer;
+(() => {
+ typeStore.Integer = _a$o;
+})();
+Integer.NAME = "INTEGER";
+
+var _a$n;
+class Enumerated extends Integer {
+ constructor(parameters = {}) {
+ super(parameters);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 10;
+ }
+}
+_a$n = Enumerated;
+(() => {
+ typeStore.Enumerated = _a$n;
+})();
+Enumerated.NAME = "ENUMERATED";
+
+class LocalSidValueBlock extends HexBlock(ValueBlock) {
+ constructor({ valueDec = -1, isFirstSid = false, ...parameters } = {}) {
+ super(parameters);
+ this.valueDec = valueDec;
+ this.isFirstSid = isFirstSid;
+ }
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ if (!inputLength) {
+ return inputOffset;
+ }
+ const inputView = BufferSourceConverter.toUint8Array(inputBuffer);
+ if (!checkBufferParams(this, inputView, inputOffset, inputLength)) {
+ return -1;
+ }
+ const intBuffer = inputView.subarray(inputOffset, inputOffset + inputLength);
+ this.valueHexView = new Uint8Array(inputLength);
+ for (let i = 0; i < inputLength; i++) {
+ this.valueHexView[i] = intBuffer[i] & 0x7F;
+ this.blockLength++;
+ if ((intBuffer[i] & 0x80) === 0x00)
+ break;
+ }
+ const tempView = new Uint8Array(this.blockLength);
+ for (let i = 0; i < this.blockLength; i++) {
+ tempView[i] = this.valueHexView[i];
+ }
+ this.valueHexView = tempView;
+ if ((intBuffer[this.blockLength - 1] & 0x80) !== 0x00) {
+ this.error = "End of input reached before message was fully decoded";
+ return -1;
+ }
+ if (this.valueHexView[0] === 0x00)
+ this.warnings.push("Needlessly long format of SID encoding");
+ if (this.blockLength <= 8)
+ this.valueDec = utilFromBase(this.valueHexView, 7);
+ else {
+ this.isHexOnly = true;
+ this.warnings.push("Too big SID for decoding, hex only");
+ }
+ return (inputOffset + this.blockLength);
+ }
+ set valueBigInt(value) {
+ assertBigInt();
+ let bits = BigInt(value).toString(2);
+ while (bits.length % 7) {
+ bits = "0" + bits;
+ }
+ const bytes = new Uint8Array(bits.length / 7);
+ for (let i = 0; i < bytes.length; i++) {
+ bytes[i] = parseInt(bits.slice(i * 7, i * 7 + 7), 2) + (i + 1 < bytes.length ? 0x80 : 0);
+ }
+ this.fromBER(bytes.buffer, 0, bytes.length);
+ }
+ toBER(sizeOnly) {
+ if (this.isHexOnly) {
+ if (sizeOnly)
+ return (new ArrayBuffer(this.valueHexView.byteLength));
+ const curView = this.valueHexView;
+ const retView = new Uint8Array(this.blockLength);
+ for (let i = 0; i < (this.blockLength - 1); i++)
+ retView[i] = curView[i] | 0x80;
+ retView[this.blockLength - 1] = curView[this.blockLength - 1];
+ return retView.buffer;
+ }
+ const encodedBuf = utilToBase(this.valueDec, 7);
+ if (encodedBuf.byteLength === 0) {
+ this.error = "Error during encoding SID value";
+ return EMPTY_BUFFER$1;
+ }
+ const retView = new Uint8Array(encodedBuf.byteLength);
+ if (!sizeOnly) {
+ const encodedView = new Uint8Array(encodedBuf);
+ const len = encodedBuf.byteLength - 1;
+ for (let i = 0; i < len; i++)
+ retView[i] = encodedView[i] | 0x80;
+ retView[len] = encodedView[len];
+ }
+ return retView;
+ }
+ toString() {
+ let result = "";
+ if (this.isHexOnly)
+ result = Convert.ToHex(this.valueHexView);
+ else {
+ if (this.isFirstSid) {
+ let sidValue = this.valueDec;
+ if (this.valueDec <= 39)
+ result = "0.";
+ else {
+ if (this.valueDec <= 79) {
+ result = "1.";
+ sidValue -= 40;
+ }
+ else {
+ result = "2.";
+ sidValue -= 80;
+ }
+ }
+ result += sidValue.toString();
+ }
+ else
+ result = this.valueDec.toString();
+ }
+ return result;
+ }
+ toJSON() {
+ return {
+ ...super.toJSON(),
+ valueDec: this.valueDec,
+ isFirstSid: this.isFirstSid,
+ };
+ }
+}
+LocalSidValueBlock.NAME = "sidBlock";
+
+class LocalObjectIdentifierValueBlock extends ValueBlock {
+ constructor({ value = EMPTY_STRING$1, ...parameters } = {}) {
+ super(parameters);
+ this.value = [];
+ if (value) {
+ this.fromString(value);
+ }
+ }
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ let resultOffset = inputOffset;
+ while (inputLength > 0) {
+ const sidBlock = new LocalSidValueBlock();
+ resultOffset = sidBlock.fromBER(inputBuffer, resultOffset, inputLength);
+ if (resultOffset === -1) {
+ this.blockLength = 0;
+ this.error = sidBlock.error;
+ return resultOffset;
+ }
+ if (this.value.length === 0)
+ sidBlock.isFirstSid = true;
+ this.blockLength += sidBlock.blockLength;
+ inputLength -= sidBlock.blockLength;
+ this.value.push(sidBlock);
+ }
+ return resultOffset;
+ }
+ toBER(sizeOnly) {
+ const retBuffers = [];
+ for (let i = 0; i < this.value.length; i++) {
+ const valueBuf = this.value[i].toBER(sizeOnly);
+ if (valueBuf.byteLength === 0) {
+ this.error = this.value[i].error;
+ return EMPTY_BUFFER$1;
+ }
+ retBuffers.push(valueBuf);
+ }
+ return concat(retBuffers);
+ }
+ fromString(string) {
+ this.value = [];
+ let pos1 = 0;
+ let pos2 = 0;
+ let sid = "";
+ let flag = false;
+ do {
+ pos2 = string.indexOf(".", pos1);
+ if (pos2 === -1)
+ sid = string.substring(pos1);
+ else
+ sid = string.substring(pos1, pos2);
+ pos1 = pos2 + 1;
+ if (flag) {
+ const sidBlock = this.value[0];
+ let plus = 0;
+ switch (sidBlock.valueDec) {
+ case 0:
+ break;
+ case 1:
+ plus = 40;
+ break;
+ case 2:
+ plus = 80;
+ break;
+ default:
+ this.value = [];
+ return;
+ }
+ const parsedSID = parseInt(sid, 10);
+ if (isNaN(parsedSID))
+ return;
+ sidBlock.valueDec = parsedSID + plus;
+ flag = false;
+ }
+ else {
+ const sidBlock = new LocalSidValueBlock();
+ if (sid > Number.MAX_SAFE_INTEGER) {
+ assertBigInt();
+ const sidValue = BigInt(sid);
+ sidBlock.valueBigInt = sidValue;
+ }
+ else {
+ sidBlock.valueDec = parseInt(sid, 10);
+ if (isNaN(sidBlock.valueDec))
+ return;
+ }
+ if (!this.value.length) {
+ sidBlock.isFirstSid = true;
+ flag = true;
+ }
+ this.value.push(sidBlock);
+ }
+ } while (pos2 !== -1);
+ }
+ toString() {
+ let result = "";
+ let isHexOnly = false;
+ for (let i = 0; i < this.value.length; i++) {
+ isHexOnly = this.value[i].isHexOnly;
+ let sidStr = this.value[i].toString();
+ if (i !== 0)
+ result = `${result}.`;
+ if (isHexOnly) {
+ sidStr = `{${sidStr}}`;
+ if (this.value[i].isFirstSid)
+ result = `2.{${sidStr} - 80}`;
+ else
+ result += sidStr;
+ }
+ else
+ result += sidStr;
+ }
+ return result;
+ }
+ toJSON() {
+ const object = {
+ ...super.toJSON(),
+ value: this.toString(),
+ sidArray: [],
+ };
+ for (let i = 0; i < this.value.length; i++) {
+ object.sidArray.push(this.value[i].toJSON());
+ }
+ return object;
+ }
+}
+LocalObjectIdentifierValueBlock.NAME = "ObjectIdentifierValueBlock";
+
+var _a$m;
+class ObjectIdentifier extends BaseBlock {
+ constructor(parameters = {}) {
+ super(parameters, LocalObjectIdentifierValueBlock);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 6;
+ }
+ getValue() {
+ return this.valueBlock.toString();
+ }
+ setValue(value) {
+ this.valueBlock.fromString(value);
+ }
+ onAsciiEncoding() {
+ return `${this.constructor.NAME} : ${this.valueBlock.toString() || "empty"}`;
+ }
+ toJSON() {
+ return {
+ ...super.toJSON(),
+ value: this.getValue(),
+ };
+ }
+}
+_a$m = ObjectIdentifier;
+(() => {
+ typeStore.ObjectIdentifier = _a$m;
+})();
+ObjectIdentifier.NAME = "OBJECT IDENTIFIER";
+
+class LocalRelativeSidValueBlock extends HexBlock(LocalBaseBlock) {
+ constructor({ valueDec = 0, ...parameters } = {}) {
+ super(parameters);
+ this.valueDec = valueDec;
+ }
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ if (inputLength === 0)
+ return inputOffset;
+ const inputView = BufferSourceConverter.toUint8Array(inputBuffer);
+ if (!checkBufferParams(this, inputView, inputOffset, inputLength))
+ return -1;
+ const intBuffer = inputView.subarray(inputOffset, inputOffset + inputLength);
+ this.valueHexView = new Uint8Array(inputLength);
+ for (let i = 0; i < inputLength; i++) {
+ this.valueHexView[i] = intBuffer[i] & 0x7F;
+ this.blockLength++;
+ if ((intBuffer[i] & 0x80) === 0x00)
+ break;
+ }
+ const tempView = new Uint8Array(this.blockLength);
+ for (let i = 0; i < this.blockLength; i++)
+ tempView[i] = this.valueHexView[i];
+ this.valueHexView = tempView;
+ if ((intBuffer[this.blockLength - 1] & 0x80) !== 0x00) {
+ this.error = "End of input reached before message was fully decoded";
+ return -1;
+ }
+ if (this.valueHexView[0] === 0x00)
+ this.warnings.push("Needlessly long format of SID encoding");
+ if (this.blockLength <= 8)
+ this.valueDec = utilFromBase(this.valueHexView, 7);
+ else {
+ this.isHexOnly = true;
+ this.warnings.push("Too big SID for decoding, hex only");
+ }
+ return (inputOffset + this.blockLength);
+ }
+ toBER(sizeOnly) {
+ if (this.isHexOnly) {
+ if (sizeOnly)
+ return (new ArrayBuffer(this.valueHexView.byteLength));
+ const curView = this.valueHexView;
+ const retView = new Uint8Array(this.blockLength);
+ for (let i = 0; i < (this.blockLength - 1); i++)
+ retView[i] = curView[i] | 0x80;
+ retView[this.blockLength - 1] = curView[this.blockLength - 1];
+ return retView.buffer;
+ }
+ const encodedBuf = utilToBase(this.valueDec, 7);
+ if (encodedBuf.byteLength === 0) {
+ this.error = "Error during encoding SID value";
+ return EMPTY_BUFFER$1;
+ }
+ const retView = new Uint8Array(encodedBuf.byteLength);
+ if (!sizeOnly) {
+ const encodedView = new Uint8Array(encodedBuf);
+ const len = encodedBuf.byteLength - 1;
+ for (let i = 0; i < len; i++)
+ retView[i] = encodedView[i] | 0x80;
+ retView[len] = encodedView[len];
+ }
+ return retView.buffer;
+ }
+ toString() {
+ let result = "";
+ if (this.isHexOnly)
+ result = Convert.ToHex(this.valueHexView);
+ else {
+ result = this.valueDec.toString();
+ }
+ return result;
+ }
+ toJSON() {
+ return {
+ ...super.toJSON(),
+ valueDec: this.valueDec,
+ };
+ }
+}
+LocalRelativeSidValueBlock.NAME = "relativeSidBlock";
+
+class LocalRelativeObjectIdentifierValueBlock extends ValueBlock {
+ constructor({ value = EMPTY_STRING$1, ...parameters } = {}) {
+ super(parameters);
+ this.value = [];
+ if (value) {
+ this.fromString(value);
+ }
+ }
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ let resultOffset = inputOffset;
+ while (inputLength > 0) {
+ const sidBlock = new LocalRelativeSidValueBlock();
+ resultOffset = sidBlock.fromBER(inputBuffer, resultOffset, inputLength);
+ if (resultOffset === -1) {
+ this.blockLength = 0;
+ this.error = sidBlock.error;
+ return resultOffset;
+ }
+ this.blockLength += sidBlock.blockLength;
+ inputLength -= sidBlock.blockLength;
+ this.value.push(sidBlock);
+ }
+ return resultOffset;
+ }
+ toBER(sizeOnly, writer) {
+ const retBuffers = [];
+ for (let i = 0; i < this.value.length; i++) {
+ const valueBuf = this.value[i].toBER(sizeOnly);
+ if (valueBuf.byteLength === 0) {
+ this.error = this.value[i].error;
+ return EMPTY_BUFFER$1;
+ }
+ retBuffers.push(valueBuf);
+ }
+ return concat(retBuffers);
+ }
+ fromString(string) {
+ this.value = [];
+ let pos1 = 0;
+ let pos2 = 0;
+ let sid = "";
+ do {
+ pos2 = string.indexOf(".", pos1);
+ if (pos2 === -1)
+ sid = string.substring(pos1);
+ else
+ sid = string.substring(pos1, pos2);
+ pos1 = pos2 + 1;
+ const sidBlock = new LocalRelativeSidValueBlock();
+ sidBlock.valueDec = parseInt(sid, 10);
+ if (isNaN(sidBlock.valueDec))
+ return true;
+ this.value.push(sidBlock);
+ } while (pos2 !== -1);
+ return true;
+ }
+ toString() {
+ let result = "";
+ let isHexOnly = false;
+ for (let i = 0; i < this.value.length; i++) {
+ isHexOnly = this.value[i].isHexOnly;
+ let sidStr = this.value[i].toString();
+ if (i !== 0)
+ result = `${result}.`;
+ if (isHexOnly) {
+ sidStr = `{${sidStr}}`;
+ result += sidStr;
+ }
+ else
+ result += sidStr;
+ }
+ return result;
+ }
+ toJSON() {
+ const object = {
+ ...super.toJSON(),
+ value: this.toString(),
+ sidArray: [],
+ };
+ for (let i = 0; i < this.value.length; i++)
+ object.sidArray.push(this.value[i].toJSON());
+ return object;
+ }
+}
+LocalRelativeObjectIdentifierValueBlock.NAME = "RelativeObjectIdentifierValueBlock";
+
+var _a$l;
+class RelativeObjectIdentifier extends BaseBlock {
+ constructor(parameters = {}) {
+ super(parameters, LocalRelativeObjectIdentifierValueBlock);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 13;
+ }
+ getValue() {
+ return this.valueBlock.toString();
+ }
+ setValue(value) {
+ this.valueBlock.fromString(value);
+ }
+ onAsciiEncoding() {
+ return `${this.constructor.NAME} : ${this.valueBlock.toString() || "empty"}`;
+ }
+ toJSON() {
+ return {
+ ...super.toJSON(),
+ value: this.getValue(),
+ };
+ }
+}
+_a$l = RelativeObjectIdentifier;
+(() => {
+ typeStore.RelativeObjectIdentifier = _a$l;
+})();
+RelativeObjectIdentifier.NAME = "RelativeObjectIdentifier";
+
+var _a$k;
+class Sequence extends Constructed {
+ constructor(parameters = {}) {
+ super(parameters);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 16;
+ }
+}
+_a$k = Sequence;
+(() => {
+ typeStore.Sequence = _a$k;
+})();
+Sequence.NAME = "SEQUENCE";
+
+var _a$j;
+class Set extends Constructed {
+ constructor(parameters = {}) {
+ super(parameters);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 17;
+ }
+}
+_a$j = Set;
+(() => {
+ typeStore.Set = _a$j;
+})();
+Set.NAME = "SET";
+
+class LocalStringValueBlock extends HexBlock(ValueBlock) {
+ constructor({ ...parameters } = {}) {
+ super(parameters);
+ this.isHexOnly = true;
+ this.value = EMPTY_STRING$1;
+ }
+ toJSON() {
+ return {
+ ...super.toJSON(),
+ value: this.value,
+ };
+ }
+}
+LocalStringValueBlock.NAME = "StringValueBlock";
+
+class LocalSimpleStringValueBlock extends LocalStringValueBlock {
+}
+LocalSimpleStringValueBlock.NAME = "SimpleStringValueBlock";
+
+class LocalSimpleStringBlock extends BaseStringBlock {
+ constructor({ ...parameters } = {}) {
+ super(parameters, LocalSimpleStringValueBlock);
+ }
+ fromBuffer(inputBuffer) {
+ this.valueBlock.value = String.fromCharCode.apply(null, BufferSourceConverter.toUint8Array(inputBuffer));
+ }
+ fromString(inputString) {
+ const strLen = inputString.length;
+ const view = this.valueBlock.valueHexView = new Uint8Array(strLen);
+ for (let i = 0; i < strLen; i++)
+ view[i] = inputString.charCodeAt(i);
+ this.valueBlock.value = inputString;
+ }
+}
+LocalSimpleStringBlock.NAME = "SIMPLE STRING";
+
+class LocalUtf8StringValueBlock extends LocalSimpleStringBlock {
+ fromBuffer(inputBuffer) {
+ this.valueBlock.valueHexView = BufferSourceConverter.toUint8Array(inputBuffer);
+ try {
+ this.valueBlock.value = Convert.ToUtf8String(inputBuffer);
+ }
+ catch (ex) {
+ this.warnings.push(`Error during "decodeURIComponent": ${ex}, using raw string`);
+ this.valueBlock.value = Convert.ToBinary(inputBuffer);
+ }
+ }
+ fromString(inputString) {
+ this.valueBlock.valueHexView = new Uint8Array(Convert.FromUtf8String(inputString));
+ this.valueBlock.value = inputString;
+ }
+}
+LocalUtf8StringValueBlock.NAME = "Utf8StringValueBlock";
+
+var _a$i;
+class Utf8String extends LocalUtf8StringValueBlock {
+ constructor(parameters = {}) {
+ super(parameters);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 12;
+ }
+}
+_a$i = Utf8String;
+(() => {
+ typeStore.Utf8String = _a$i;
+})();
+Utf8String.NAME = "UTF8String";
+
+class LocalBmpStringValueBlock extends LocalSimpleStringBlock {
+ fromBuffer(inputBuffer) {
+ this.valueBlock.value = Convert.ToUtf16String(inputBuffer);
+ this.valueBlock.valueHexView = BufferSourceConverter.toUint8Array(inputBuffer);
+ }
+ fromString(inputString) {
+ this.valueBlock.value = inputString;
+ this.valueBlock.valueHexView = new Uint8Array(Convert.FromUtf16String(inputString));
+ }
+}
+LocalBmpStringValueBlock.NAME = "BmpStringValueBlock";
+
+var _a$h;
+class BmpString extends LocalBmpStringValueBlock {
+ constructor({ ...parameters } = {}) {
+ super(parameters);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 30;
+ }
+}
+_a$h = BmpString;
+(() => {
+ typeStore.BmpString = _a$h;
+})();
+BmpString.NAME = "BMPString";
+
+class LocalUniversalStringValueBlock extends LocalSimpleStringBlock {
+ fromBuffer(inputBuffer) {
+ const copyBuffer = ArrayBuffer.isView(inputBuffer) ? inputBuffer.slice().buffer : inputBuffer.slice(0);
+ const valueView = new Uint8Array(copyBuffer);
+ for (let i = 0; i < valueView.length; i += 4) {
+ valueView[i] = valueView[i + 3];
+ valueView[i + 1] = valueView[i + 2];
+ valueView[i + 2] = 0x00;
+ valueView[i + 3] = 0x00;
+ }
+ this.valueBlock.value = String.fromCharCode.apply(null, new Uint32Array(copyBuffer));
+ }
+ fromString(inputString) {
+ const strLength = inputString.length;
+ const valueHexView = this.valueBlock.valueHexView = new Uint8Array(strLength * 4);
+ for (let i = 0; i < strLength; i++) {
+ const codeBuf = utilToBase(inputString.charCodeAt(i), 8);
+ const codeView = new Uint8Array(codeBuf);
+ if (codeView.length > 4)
+ continue;
+ const dif = 4 - codeView.length;
+ for (let j = (codeView.length - 1); j >= 0; j--)
+ valueHexView[i * 4 + j + dif] = codeView[j];
+ }
+ this.valueBlock.value = inputString;
+ }
+}
+LocalUniversalStringValueBlock.NAME = "UniversalStringValueBlock";
+
+var _a$g;
+class UniversalString extends LocalUniversalStringValueBlock {
+ constructor({ ...parameters } = {}) {
+ super(parameters);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 28;
+ }
+}
+_a$g = UniversalString;
+(() => {
+ typeStore.UniversalString = _a$g;
+})();
+UniversalString.NAME = "UniversalString";
+
+var _a$f;
+class NumericString extends LocalSimpleStringBlock {
+ constructor(parameters = {}) {
+ super(parameters);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 18;
+ }
+}
+_a$f = NumericString;
+(() => {
+ typeStore.NumericString = _a$f;
+})();
+NumericString.NAME = "NumericString";
+
+var _a$e;
+class PrintableString extends LocalSimpleStringBlock {
+ constructor(parameters = {}) {
+ super(parameters);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 19;
+ }
+}
+_a$e = PrintableString;
+(() => {
+ typeStore.PrintableString = _a$e;
+})();
+PrintableString.NAME = "PrintableString";
+
+var _a$d;
+class TeletexString extends LocalSimpleStringBlock {
+ constructor(parameters = {}) {
+ super(parameters);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 20;
+ }
+}
+_a$d = TeletexString;
+(() => {
+ typeStore.TeletexString = _a$d;
+})();
+TeletexString.NAME = "TeletexString";
+
+var _a$c;
+class VideotexString extends LocalSimpleStringBlock {
+ constructor(parameters = {}) {
+ super(parameters);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 21;
+ }
+}
+_a$c = VideotexString;
+(() => {
+ typeStore.VideotexString = _a$c;
+})();
+VideotexString.NAME = "VideotexString";
+
+var _a$b;
+class IA5String extends LocalSimpleStringBlock {
+ constructor(parameters = {}) {
+ super(parameters);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 22;
+ }
+}
+_a$b = IA5String;
+(() => {
+ typeStore.IA5String = _a$b;
+})();
+IA5String.NAME = "IA5String";
+
+var _a$a;
+class GraphicString extends LocalSimpleStringBlock {
+ constructor(parameters = {}) {
+ super(parameters);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 25;
+ }
+}
+_a$a = GraphicString;
+(() => {
+ typeStore.GraphicString = _a$a;
+})();
+GraphicString.NAME = "GraphicString";
+
+var _a$9;
+class VisibleString extends LocalSimpleStringBlock {
+ constructor(parameters = {}) {
+ super(parameters);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 26;
+ }
+}
+_a$9 = VisibleString;
+(() => {
+ typeStore.VisibleString = _a$9;
+})();
+VisibleString.NAME = "VisibleString";
+
+var _a$8;
+class GeneralString extends LocalSimpleStringBlock {
+ constructor(parameters = {}) {
+ super(parameters);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 27;
+ }
+}
+_a$8 = GeneralString;
+(() => {
+ typeStore.GeneralString = _a$8;
+})();
+GeneralString.NAME = "GeneralString";
+
+var _a$7;
+class CharacterString extends LocalSimpleStringBlock {
+ constructor(parameters = {}) {
+ super(parameters);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 29;
+ }
+}
+_a$7 = CharacterString;
+(() => {
+ typeStore.CharacterString = _a$7;
+})();
+CharacterString.NAME = "CharacterString";
+
+var _a$6;
+class UTCTime extends VisibleString {
+ constructor({ value, valueDate, ...parameters } = {}) {
+ super(parameters);
+ this.year = 0;
+ this.month = 0;
+ this.day = 0;
+ this.hour = 0;
+ this.minute = 0;
+ this.second = 0;
+ if (value) {
+ this.fromString(value);
+ this.valueBlock.valueHexView = new Uint8Array(value.length);
+ for (let i = 0; i < value.length; i++)
+ this.valueBlock.valueHexView[i] = value.charCodeAt(i);
+ }
+ if (valueDate) {
+ this.fromDate(valueDate);
+ this.valueBlock.valueHexView = new Uint8Array(this.toBuffer());
+ }
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 23;
+ }
+ fromBuffer(inputBuffer) {
+ this.fromString(String.fromCharCode.apply(null, BufferSourceConverter.toUint8Array(inputBuffer)));
+ }
+ toBuffer() {
+ const str = this.toString();
+ const buffer = new ArrayBuffer(str.length);
+ const view = new Uint8Array(buffer);
+ for (let i = 0; i < str.length; i++)
+ view[i] = str.charCodeAt(i);
+ return buffer;
+ }
+ fromDate(inputDate) {
+ this.year = inputDate.getUTCFullYear();
+ this.month = inputDate.getUTCMonth() + 1;
+ this.day = inputDate.getUTCDate();
+ this.hour = inputDate.getUTCHours();
+ this.minute = inputDate.getUTCMinutes();
+ this.second = inputDate.getUTCSeconds();
+ }
+ toDate() {
+ return (new Date(Date.UTC(this.year, this.month - 1, this.day, this.hour, this.minute, this.second)));
+ }
+ fromString(inputString) {
+ const parser = /(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})Z/ig;
+ const parserArray = parser.exec(inputString);
+ if (parserArray === null) {
+ this.error = "Wrong input string for conversion";
+ return;
+ }
+ const year = parseInt(parserArray[1], 10);
+ if (year >= 50)
+ this.year = 1900 + year;
+ else
+ this.year = 2000 + year;
+ this.month = parseInt(parserArray[2], 10);
+ this.day = parseInt(parserArray[3], 10);
+ this.hour = parseInt(parserArray[4], 10);
+ this.minute = parseInt(parserArray[5], 10);
+ this.second = parseInt(parserArray[6], 10);
+ }
+ toString(encoding = "iso") {
+ if (encoding === "iso") {
+ const outputArray = new Array(7);
+ outputArray[0] = padNumber(((this.year < 2000) ? (this.year - 1900) : (this.year - 2000)), 2);
+ outputArray[1] = padNumber(this.month, 2);
+ outputArray[2] = padNumber(this.day, 2);
+ outputArray[3] = padNumber(this.hour, 2);
+ outputArray[4] = padNumber(this.minute, 2);
+ outputArray[5] = padNumber(this.second, 2);
+ outputArray[6] = "Z";
+ return outputArray.join("");
+ }
+ return super.toString(encoding);
+ }
+ onAsciiEncoding() {
+ return `${this.constructor.NAME} : ${this.toDate().toISOString()}`;
+ }
+ toJSON() {
+ return {
+ ...super.toJSON(),
+ year: this.year,
+ month: this.month,
+ day: this.day,
+ hour: this.hour,
+ minute: this.minute,
+ second: this.second,
+ };
+ }
+}
+_a$6 = UTCTime;
+(() => {
+ typeStore.UTCTime = _a$6;
+})();
+UTCTime.NAME = "UTCTime";
+
+var _a$5;
+class GeneralizedTime extends UTCTime {
+ constructor(parameters = {}) {
+ var _b;
+ super(parameters);
+ (_b = this.millisecond) !== null && _b !== void 0 ? _b : (this.millisecond = 0);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 24;
+ }
+ fromDate(inputDate) {
+ super.fromDate(inputDate);
+ this.millisecond = inputDate.getUTCMilliseconds();
+ }
+ toDate() {
+ return (new Date(Date.UTC(this.year, this.month - 1, this.day, this.hour, this.minute, this.second, this.millisecond)));
+ }
+ fromString(inputString) {
+ let isUTC = false;
+ let timeString = "";
+ let dateTimeString = "";
+ let fractionPart = 0;
+ let parser;
+ let hourDifference = 0;
+ let minuteDifference = 0;
+ if (inputString[inputString.length - 1] === "Z") {
+ timeString = inputString.substring(0, inputString.length - 1);
+ isUTC = true;
+ }
+ else {
+ const number = new Number(inputString[inputString.length - 1]);
+ if (isNaN(number.valueOf()))
+ throw new Error("Wrong input string for conversion");
+ timeString = inputString;
+ }
+ if (isUTC) {
+ if (timeString.indexOf("+") !== -1)
+ throw new Error("Wrong input string for conversion");
+ if (timeString.indexOf("-") !== -1)
+ throw new Error("Wrong input string for conversion");
+ }
+ else {
+ let multiplier = 1;
+ let differencePosition = timeString.indexOf("+");
+ let differenceString = "";
+ if (differencePosition === -1) {
+ differencePosition = timeString.indexOf("-");
+ multiplier = -1;
+ }
+ if (differencePosition !== -1) {
+ differenceString = timeString.substring(differencePosition + 1);
+ timeString = timeString.substring(0, differencePosition);
+ if ((differenceString.length !== 2) && (differenceString.length !== 4))
+ throw new Error("Wrong input string for conversion");
+ let number = parseInt(differenceString.substring(0, 2), 10);
+ if (isNaN(number.valueOf()))
+ throw new Error("Wrong input string for conversion");
+ hourDifference = multiplier * number;
+ if (differenceString.length === 4) {
+ number = parseInt(differenceString.substring(2, 4), 10);
+ if (isNaN(number.valueOf()))
+ throw new Error("Wrong input string for conversion");
+ minuteDifference = multiplier * number;
+ }
+ }
+ }
+ let fractionPointPosition = timeString.indexOf(".");
+ if (fractionPointPosition === -1)
+ fractionPointPosition = timeString.indexOf(",");
+ if (fractionPointPosition !== -1) {
+ const fractionPartCheck = new Number(`0${timeString.substring(fractionPointPosition)}`);
+ if (isNaN(fractionPartCheck.valueOf()))
+ throw new Error("Wrong input string for conversion");
+ fractionPart = fractionPartCheck.valueOf();
+ dateTimeString = timeString.substring(0, fractionPointPosition);
+ }
+ else
+ dateTimeString = timeString;
+ switch (true) {
+ case (dateTimeString.length === 8):
+ parser = /(\d{4})(\d{2})(\d{2})/ig;
+ if (fractionPointPosition !== -1)
+ throw new Error("Wrong input string for conversion");
+ break;
+ case (dateTimeString.length === 10):
+ parser = /(\d{4})(\d{2})(\d{2})(\d{2})/ig;
+ if (fractionPointPosition !== -1) {
+ let fractionResult = 60 * fractionPart;
+ this.minute = Math.floor(fractionResult);
+ fractionResult = 60 * (fractionResult - this.minute);
+ this.second = Math.floor(fractionResult);
+ fractionResult = 1000 * (fractionResult - this.second);
+ this.millisecond = Math.floor(fractionResult);
+ }
+ break;
+ case (dateTimeString.length === 12):
+ parser = /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})/ig;
+ if (fractionPointPosition !== -1) {
+ let fractionResult = 60 * fractionPart;
+ this.second = Math.floor(fractionResult);
+ fractionResult = 1000 * (fractionResult - this.second);
+ this.millisecond = Math.floor(fractionResult);
+ }
+ break;
+ case (dateTimeString.length === 14):
+ parser = /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/ig;
+ if (fractionPointPosition !== -1) {
+ const fractionResult = 1000 * fractionPart;
+ this.millisecond = Math.floor(fractionResult);
+ }
+ break;
+ default:
+ throw new Error("Wrong input string for conversion");
+ }
+ const parserArray = parser.exec(dateTimeString);
+ if (parserArray === null)
+ throw new Error("Wrong input string for conversion");
+ for (let j = 1; j < parserArray.length; j++) {
+ switch (j) {
+ case 1:
+ this.year = parseInt(parserArray[j], 10);
+ break;
+ case 2:
+ this.month = parseInt(parserArray[j], 10);
+ break;
+ case 3:
+ this.day = parseInt(parserArray[j], 10);
+ break;
+ case 4:
+ this.hour = parseInt(parserArray[j], 10) + hourDifference;
+ break;
+ case 5:
+ this.minute = parseInt(parserArray[j], 10) + minuteDifference;
+ break;
+ case 6:
+ this.second = parseInt(parserArray[j], 10);
+ break;
+ default:
+ throw new Error("Wrong input string for conversion");
+ }
+ }
+ if (isUTC === false) {
+ const tempDate = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+ this.year = tempDate.getUTCFullYear();
+ this.month = tempDate.getUTCMonth();
+ this.day = tempDate.getUTCDay();
+ this.hour = tempDate.getUTCHours();
+ this.minute = tempDate.getUTCMinutes();
+ this.second = tempDate.getUTCSeconds();
+ this.millisecond = tempDate.getUTCMilliseconds();
+ }
+ }
+ toString(encoding = "iso") {
+ if (encoding === "iso") {
+ const outputArray = [];
+ outputArray.push(padNumber(this.year, 4));
+ outputArray.push(padNumber(this.month, 2));
+ outputArray.push(padNumber(this.day, 2));
+ outputArray.push(padNumber(this.hour, 2));
+ outputArray.push(padNumber(this.minute, 2));
+ outputArray.push(padNumber(this.second, 2));
+ if (this.millisecond !== 0) {
+ outputArray.push(".");
+ outputArray.push(padNumber(this.millisecond, 3));
+ }
+ outputArray.push("Z");
+ return outputArray.join("");
+ }
+ return super.toString(encoding);
+ }
+ toJSON() {
+ return {
+ ...super.toJSON(),
+ millisecond: this.millisecond,
+ };
+ }
+}
+_a$5 = GeneralizedTime;
+(() => {
+ typeStore.GeneralizedTime = _a$5;
+})();
+GeneralizedTime.NAME = "GeneralizedTime";
+
+var _a$4;
+class DATE$2 extends Utf8String {
+ constructor(parameters = {}) {
+ super(parameters);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 31;
+ }
+}
+_a$4 = DATE$2;
+(() => {
+ typeStore.DATE = _a$4;
+})();
+DATE$2.NAME = "DATE";
+
+var _a$3;
+class TimeOfDay extends Utf8String {
+ constructor(parameters = {}) {
+ super(parameters);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 32;
+ }
+}
+_a$3 = TimeOfDay;
+(() => {
+ typeStore.TimeOfDay = _a$3;
+})();
+TimeOfDay.NAME = "TimeOfDay";
+
+var _a$2;
+class DateTime extends Utf8String {
+ constructor(parameters = {}) {
+ super(parameters);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 33;
+ }
+}
+_a$2 = DateTime;
+(() => {
+ typeStore.DateTime = _a$2;
+})();
+DateTime.NAME = "DateTime";
+
+var _a$1;
+class Duration extends Utf8String {
+ constructor(parameters = {}) {
+ super(parameters);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 34;
+ }
+}
+_a$1 = Duration;
+(() => {
+ typeStore.Duration = _a$1;
+})();
+Duration.NAME = "Duration";
+
+var _a$x;
+class TIME extends Utf8String {
+ constructor(parameters = {}) {
+ super(parameters);
+ this.idBlock.tagClass = 1;
+ this.idBlock.tagNumber = 14;
+ }
+}
+_a$x = TIME;
+(() => {
+ typeStore.TIME = _a$x;
+})();
+TIME.NAME = "TIME";
+
+class Any {
+ constructor({ name = EMPTY_STRING$1, optional = false, } = {}) {
+ this.name = name;
+ this.optional = optional;
+ }
+}
+
+class Choice extends Any {
+ constructor({ value = [], ...parameters } = {}) {
+ super(parameters);
+ this.value = value;
+ }
+}
+
+class Repeated extends Any {
+ constructor({ value = new Any(), local = false, ...parameters } = {}) {
+ super(parameters);
+ this.value = value;
+ this.local = local;
+ }
+}
+
+class RawData {
+ constructor({ data = EMPTY_VIEW } = {}) {
+ this.dataView = BufferSourceConverter.toUint8Array(data);
+ }
+ get data() {
+ return this.dataView.slice().buffer;
+ }
+ set data(value) {
+ this.dataView = BufferSourceConverter.toUint8Array(value);
+ }
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ const endLength = inputOffset + inputLength;
+ this.dataView = BufferSourceConverter.toUint8Array(inputBuffer).subarray(inputOffset, endLength);
+ return endLength;
+ }
+ toBER(sizeOnly) {
+ return this.dataView.slice().buffer;
+ }
+}
+
+function compareSchema(root, inputData, inputSchema) {
+ if (inputSchema instanceof Choice) {
+ for (let j = 0; j < inputSchema.value.length; j++) {
+ const result = compareSchema(root, inputData, inputSchema.value[j]);
+ if (result.verified) {
+ return {
+ verified: true,
+ result: root
+ };
+ }
+ }
+ {
+ const _result = {
+ verified: false,
+ result: {
+ error: "Wrong values for Choice type"
+ },
+ };
+ if (inputSchema.hasOwnProperty(NAME))
+ _result.name = inputSchema.name;
+ return _result;
+ }
+ }
+ if (inputSchema instanceof Any) {
+ if (inputSchema.hasOwnProperty(NAME))
+ root[inputSchema.name] = inputData;
+ return {
+ verified: true,
+ result: root
+ };
+ }
+ if ((root instanceof Object) === false) {
+ return {
+ verified: false,
+ result: { error: "Wrong root object" }
+ };
+ }
+ if ((inputData instanceof Object) === false) {
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 data" }
+ };
+ }
+ if ((inputSchema instanceof Object) === false) {
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+ }
+ if ((ID_BLOCK in inputSchema) === false) {
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+ }
+ if ((FROM_BER in inputSchema.idBlock) === false) {
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+ }
+ if ((TO_BER in inputSchema.idBlock) === false) {
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+ }
+ const encodedId = inputSchema.idBlock.toBER(false);
+ if (encodedId.byteLength === 0) {
+ return {
+ verified: false,
+ result: { error: "Error encoding idBlock for ASN.1 schema" }
+ };
+ }
+ const decodedOffset = inputSchema.idBlock.fromBER(encodedId, 0, encodedId.byteLength);
+ if (decodedOffset === -1) {
+ return {
+ verified: false,
+ result: { error: "Error decoding idBlock for ASN.1 schema" }
+ };
+ }
+ if (inputSchema.idBlock.hasOwnProperty(TAG_CLASS) === false) {
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+ }
+ if (inputSchema.idBlock.tagClass !== inputData.idBlock.tagClass) {
+ return {
+ verified: false,
+ result: root
+ };
+ }
+ if (inputSchema.idBlock.hasOwnProperty(TAG_NUMBER) === false) {
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+ }
+ if (inputSchema.idBlock.tagNumber !== inputData.idBlock.tagNumber) {
+ return {
+ verified: false,
+ result: root
+ };
+ }
+ if (inputSchema.idBlock.hasOwnProperty(IS_CONSTRUCTED) === false) {
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+ }
+ if (inputSchema.idBlock.isConstructed !== inputData.idBlock.isConstructed) {
+ return {
+ verified: false,
+ result: root
+ };
+ }
+ if (!(IS_HEX_ONLY in inputSchema.idBlock)) {
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+ }
+ if (inputSchema.idBlock.isHexOnly !== inputData.idBlock.isHexOnly) {
+ return {
+ verified: false,
+ result: root
+ };
+ }
+ if (inputSchema.idBlock.isHexOnly) {
+ if ((VALUE_HEX_VIEW in inputSchema.idBlock) === false) {
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+ }
+ const schemaView = inputSchema.idBlock.valueHexView;
+ const asn1View = inputData.idBlock.valueHexView;
+ if (schemaView.length !== asn1View.length) {
+ return {
+ verified: false,
+ result: root
+ };
+ }
+ for (let i = 0; i < schemaView.length; i++) {
+ if (schemaView[i] !== asn1View[1]) {
+ return {
+ verified: false,
+ result: root
+ };
+ }
+ }
+ }
+ if (inputSchema.name) {
+ inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING$1);
+ if (inputSchema.name)
+ root[inputSchema.name] = inputData;
+ }
+ if (inputSchema instanceof typeStore.Constructed) {
+ let admission = 0;
+ let result = {
+ verified: false,
+ result: {
+ error: "Unknown error",
+ }
+ };
+ let maxLength = inputSchema.valueBlock.value.length;
+ if (maxLength > 0) {
+ if (inputSchema.valueBlock.value[0] instanceof Repeated) {
+ maxLength = inputData.valueBlock.value.length;
+ }
+ }
+ if (maxLength === 0) {
+ return {
+ verified: true,
+ result: root
+ };
+ }
+ if ((inputData.valueBlock.value.length === 0) &&
+ (inputSchema.valueBlock.value.length !== 0)) {
+ let _optional = true;
+ for (let i = 0; i < inputSchema.valueBlock.value.length; i++)
+ _optional = _optional && (inputSchema.valueBlock.value[i].optional || false);
+ if (_optional) {
+ return {
+ verified: true,
+ result: root
+ };
+ }
+ if (inputSchema.name) {
+ inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING$1);
+ if (inputSchema.name)
+ delete root[inputSchema.name];
+ }
+ root.error = "Inconsistent object length";
+ return {
+ verified: false,
+ result: root
+ };
+ }
+ for (let i = 0; i < maxLength; i++) {
+ if ((i - admission) >= inputData.valueBlock.value.length) {
+ if (inputSchema.valueBlock.value[i].optional === false) {
+ const _result = {
+ verified: false,
+ result: root
+ };
+ root.error = "Inconsistent length between ASN.1 data and schema";
+ if (inputSchema.name) {
+ inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING$1);
+ if (inputSchema.name) {
+ delete root[inputSchema.name];
+ _result.name = inputSchema.name;
+ }
+ }
+ return _result;
+ }
+ }
+ else {
+ if (inputSchema.valueBlock.value[0] instanceof Repeated) {
+ result = compareSchema(root, inputData.valueBlock.value[i], inputSchema.valueBlock.value[0].value);
+ if (result.verified === false) {
+ if (inputSchema.valueBlock.value[0].optional)
+ admission++;
+ else {
+ if (inputSchema.name) {
+ inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING$1);
+ if (inputSchema.name)
+ delete root[inputSchema.name];
+ }
+ return result;
+ }
+ }
+ if ((NAME in inputSchema.valueBlock.value[0]) && (inputSchema.valueBlock.value[0].name.length > 0)) {
+ let arrayRoot = {};
+ if ((LOCAL in inputSchema.valueBlock.value[0]) && (inputSchema.valueBlock.value[0].local))
+ arrayRoot = inputData;
+ else
+ arrayRoot = root;
+ if (typeof arrayRoot[inputSchema.valueBlock.value[0].name] === "undefined")
+ arrayRoot[inputSchema.valueBlock.value[0].name] = [];
+ arrayRoot[inputSchema.valueBlock.value[0].name].push(inputData.valueBlock.value[i]);
+ }
+ }
+ else {
+ result = compareSchema(root, inputData.valueBlock.value[i - admission], inputSchema.valueBlock.value[i]);
+ if (result.verified === false) {
+ if (inputSchema.valueBlock.value[i].optional)
+ admission++;
+ else {
+ if (inputSchema.name) {
+ inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING$1);
+ if (inputSchema.name)
+ delete root[inputSchema.name];
+ }
+ return result;
+ }
+ }
+ }
+ }
+ }
+ if (result.verified === false) {
+ const _result = {
+ verified: false,
+ result: root
+ };
+ if (inputSchema.name) {
+ inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING$1);
+ if (inputSchema.name) {
+ delete root[inputSchema.name];
+ _result.name = inputSchema.name;
+ }
+ }
+ return _result;
+ }
+ return {
+ verified: true,
+ result: root
+ };
+ }
+ if (inputSchema.primitiveSchema &&
+ (VALUE_HEX_VIEW in inputData.valueBlock)) {
+ const asn1 = localFromBER(inputData.valueBlock.valueHexView);
+ if (asn1.offset === -1) {
+ const _result = {
+ verified: false,
+ result: asn1.result
+ };
+ if (inputSchema.name) {
+ inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING$1);
+ if (inputSchema.name) {
+ delete root[inputSchema.name];
+ _result.name = inputSchema.name;
+ }
+ }
+ return _result;
+ }
+ return compareSchema(root, asn1.result, inputSchema.primitiveSchema);
+ }
+ return {
+ verified: true,
+ result: root
+ };
+}
+
+const EMPTY_BUFFER = new ArrayBuffer(0);
+const EMPTY_STRING = "";
+
+class ArgumentError extends TypeError {
+ constructor() {
+ super(...arguments);
+ this.name = ArgumentError.NAME;
+ }
+ static isType(value, type) {
+ if (typeof type === "string") {
+ if (type === "Array" && Array.isArray(value)) {
+ return true;
+ }
+ else if (type === "ArrayBuffer" && value instanceof ArrayBuffer) {
+ return true;
+ }
+ else if (type === "ArrayBufferView" && ArrayBuffer.isView(value)) {
+ return true;
+ }
+ else if (typeof value === type) {
+ return true;
+ }
+ }
+ else if (value instanceof type) {
+ return true;
+ }
+ return false;
+ }
+ static assert(value, name, ...types) {
+ for (const type of types) {
+ if (this.isType(value, type)) {
+ return;
+ }
+ }
+ const typeNames = types.map(o => o instanceof Function && "name" in o ? o.name : `${o}`);
+ throw new ArgumentError(`Parameter '${name}' is not of type ${typeNames.length > 1 ? `(${typeNames.join(" or ")})` : typeNames[0]}`);
+ }
+}
+ArgumentError.NAME = "ArgumentError";
+
+class ParameterError extends TypeError {
+ constructor(field, target = null, message) {
+ super();
+ this.name = ParameterError.NAME;
+ this.field = field;
+ if (target) {
+ this.target = target;
+ }
+ if (message) {
+ this.message = message;
+ }
+ else {
+ this.message = `Absent mandatory parameter '${field}' ${target ? ` in '${target}'` : EMPTY_STRING}`;
+ }
+ }
+ static assert(...args) {
+ let target = null;
+ let params;
+ let fields;
+ if (typeof args[0] === "string") {
+ target = args[0];
+ params = args[1];
+ fields = args.slice(2);
+ }
+ else {
+ params = args[0];
+ fields = args.slice(1);
+ }
+ ArgumentError.assert(params, "parameters", "object");
+ for (const field of fields) {
+ const value = params[field];
+ if (value === undefined || value === null) {
+ throw new ParameterError(field, target);
+ }
+ }
+ }
+ static assertEmpty(value, name, target) {
+ if (value === undefined || value === null) {
+ throw new ParameterError(name, target);
+ }
+ }
+}
+ParameterError.NAME = "ParameterError";
+
+class AsnError extends Error {
+ static assertSchema(asn1, target) {
+ if (!asn1.verified) {
+ throw new Error(`Object's schema was not verified against input data for ${target}`);
+ }
+ }
+ static assert(asn, target) {
+ if (asn.offset === -1) {
+ throw new AsnError(`Error during parsing of ASN.1 data. Data is not correct for '${target}'.`);
+ }
+ }
+ constructor(message) {
+ super(message);
+ this.name = "AsnError";
+ }
+}
+
+class PkiObject {
+ static blockName() {
+ return this.CLASS_NAME;
+ }
+ static fromBER(raw) {
+ const asn1 = fromBER(raw);
+ AsnError.assert(asn1, this.name);
+ try {
+ return new this({ schema: asn1.result });
+ }
+ catch (e) {
+ throw new AsnError(`Cannot create '${this.CLASS_NAME}' from ASN.1 object`);
+ }
+ }
+ static defaultValues(memberName) {
+ throw new Error(`Invalid member name for ${this.CLASS_NAME} class: ${memberName}`);
+ }
+ static schema(parameters = {}) {
+ throw new Error(`Method '${this.CLASS_NAME}.schema' should be overridden`);
+ }
+ get className() {
+ return this.constructor.CLASS_NAME;
+ }
+ toString(encoding = "hex") {
+ let schema;
+ try {
+ schema = this.toSchema();
+ }
+ catch (_a) {
+ schema = this.toSchema(true);
+ }
+ return Convert.ToString(schema.toBER(), encoding);
+ }
+}
+PkiObject.CLASS_NAME = "PkiObject";
+
+function stringPrep(inputString) {
+ let isSpace = false;
+ let cutResult = EMPTY_STRING;
+ const result = inputString.trim();
+ for (let i = 0; i < result.length; i++) {
+ if (result.charCodeAt(i) === 32) {
+ if (isSpace === false)
+ isSpace = true;
+ }
+ else {
+ if (isSpace) {
+ cutResult += " ";
+ isSpace = false;
+ }
+ cutResult += result[i];
+ }
+ }
+ return cutResult.toLowerCase();
+}
+
+const TYPE$5 = "type";
+const VALUE$6 = "value";
+class AttributeTypeAndValue extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.type = getParametersValue(parameters, TYPE$5, AttributeTypeAndValue.defaultValues(TYPE$5));
+ this.value = getParametersValue(parameters, VALUE$6, AttributeTypeAndValue.defaultValues(VALUE$6));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case TYPE$5:
+ return EMPTY_STRING;
+ case VALUE$6:
+ return {};
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new ObjectIdentifier({ name: (names.type || EMPTY_STRING) }),
+ new Any({ name: (names.value || EMPTY_STRING) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, [
+ TYPE$5,
+ "typeValue"
+ ]);
+ const asn1 = compareSchema(schema, schema, AttributeTypeAndValue.schema({
+ names: {
+ type: TYPE$5,
+ value: "typeValue"
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.type = asn1.result.type.valueBlock.toString();
+ this.value = asn1.result.typeValue;
+ }
+ toSchema() {
+ return (new Sequence({
+ value: [
+ new ObjectIdentifier({ value: this.type }),
+ this.value
+ ]
+ }));
+ }
+ toJSON() {
+ const _object = {
+ type: this.type
+ };
+ if (Object.keys(this.value).length !== 0) {
+ _object.value = (this.value).toJSON();
+ }
+ else {
+ _object.value = this.value;
+ }
+ return _object;
+ }
+ isEqual(compareTo) {
+ const stringBlockNames = [
+ Utf8String.blockName(),
+ BmpString.blockName(),
+ UniversalString.blockName(),
+ NumericString.blockName(),
+ PrintableString.blockName(),
+ TeletexString.blockName(),
+ VideotexString.blockName(),
+ IA5String.blockName(),
+ GraphicString.blockName(),
+ VisibleString.blockName(),
+ GeneralString.blockName(),
+ CharacterString.blockName()
+ ];
+ if (compareTo instanceof ArrayBuffer) {
+ return BufferSourceConverter.isEqual(this.value.valueBeforeDecodeView, compareTo);
+ }
+ if (compareTo.constructor.blockName() === AttributeTypeAndValue.blockName()) {
+ if (this.type !== compareTo.type)
+ return false;
+ const isStringPair = [false, false];
+ const thisName = this.value.constructor.blockName();
+ for (const name of stringBlockNames) {
+ if (thisName === name) {
+ isStringPair[0] = true;
+ }
+ if (compareTo.value.constructor.blockName() === name) {
+ isStringPair[1] = true;
+ }
+ }
+ if (isStringPair[0] !== isStringPair[1]) {
+ return false;
+ }
+ const isString = (isStringPair[0] && isStringPair[1]);
+ if (isString) {
+ const value1 = stringPrep(this.value.valueBlock.value);
+ const value2 = stringPrep(compareTo.value.valueBlock.value);
+ if (value1.localeCompare(value2) !== 0)
+ return false;
+ }
+ else {
+ if (!BufferSourceConverter.isEqual(this.value.valueBeforeDecodeView, compareTo.value.valueBeforeDecodeView))
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+}
+AttributeTypeAndValue.CLASS_NAME = "AttributeTypeAndValue";
+
+const TYPE_AND_VALUES = "typesAndValues";
+const VALUE_BEFORE_DECODE = "valueBeforeDecode";
+const RDN = "RDN";
+class RelativeDistinguishedNames extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.typesAndValues = getParametersValue(parameters, TYPE_AND_VALUES, RelativeDistinguishedNames.defaultValues(TYPE_AND_VALUES));
+ this.valueBeforeDecode = getParametersValue(parameters, VALUE_BEFORE_DECODE, RelativeDistinguishedNames.defaultValues(VALUE_BEFORE_DECODE));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case TYPE_AND_VALUES:
+ return [];
+ case VALUE_BEFORE_DECODE:
+ return EMPTY_BUFFER;
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case TYPE_AND_VALUES:
+ return (memberValue.length === 0);
+ case VALUE_BEFORE_DECODE:
+ return (memberValue.byteLength === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Repeated({
+ name: (names.repeatedSequence || EMPTY_STRING),
+ value: new Set({
+ value: [
+ new Repeated({
+ name: (names.repeatedSet || EMPTY_STRING),
+ value: AttributeTypeAndValue.schema(names.typeAndValue || {})
+ })
+ ]
+ })
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, [
+ RDN,
+ TYPE_AND_VALUES
+ ]);
+ const asn1 = compareSchema(schema, schema, RelativeDistinguishedNames.schema({
+ names: {
+ blockName: RDN,
+ repeatedSet: TYPE_AND_VALUES
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ if (TYPE_AND_VALUES in asn1.result) {
+ this.typesAndValues = Array.from(asn1.result.typesAndValues, element => new AttributeTypeAndValue({ schema: element }));
+ }
+ this.valueBeforeDecode = asn1.result.RDN.valueBeforeDecodeView.slice().buffer;
+ }
+ toSchema() {
+ if (this.valueBeforeDecode.byteLength === 0) {
+ return (new Sequence({
+ value: [new Set({
+ value: Array.from(this.typesAndValues, o => o.toSchema())
+ })]
+ }));
+ }
+ const asn1 = fromBER(this.valueBeforeDecode);
+ AsnError.assert(asn1, "RelativeDistinguishedNames");
+ if (!(asn1.result instanceof Sequence)) {
+ throw new Error("ASN.1 result should be SEQUENCE");
+ }
+ return asn1.result;
+ }
+ toJSON() {
+ return {
+ typesAndValues: Array.from(this.typesAndValues, o => o.toJSON())
+ };
+ }
+ isEqual(compareTo) {
+ if (compareTo instanceof RelativeDistinguishedNames) {
+ if (this.typesAndValues.length !== compareTo.typesAndValues.length)
+ return false;
+ for (const [index, typeAndValue] of this.typesAndValues.entries()) {
+ if (typeAndValue.isEqual(compareTo.typesAndValues[index]) === false)
+ return false;
+ }
+ return true;
+ }
+ if (compareTo instanceof ArrayBuffer) {
+ return isEqualBuffer(this.valueBeforeDecode, compareTo);
+ }
+ return false;
+ }
+}
+RelativeDistinguishedNames.CLASS_NAME = "RelativeDistinguishedNames";
+
+const TYPE$4 = "type";
+const VALUE$5 = "value";
+function builtInStandardAttributes(parameters = {}, optional = false) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ optional,
+ value: [
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 2,
+ tagNumber: 1
+ },
+ name: (names.country_name || EMPTY_STRING),
+ value: [
+ new Choice({
+ value: [
+ new NumericString(),
+ new PrintableString()
+ ]
+ })
+ ]
+ }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 2,
+ tagNumber: 2
+ },
+ name: (names.administration_domain_name || EMPTY_STRING),
+ value: [
+ new Choice({
+ value: [
+ new NumericString(),
+ new PrintableString()
+ ]
+ })
+ ]
+ }),
+ new Primitive({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ name: (names.network_address || EMPTY_STRING),
+ isHexOnly: true
+ }),
+ new Primitive({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ name: (names.terminal_identifier || EMPTY_STRING),
+ isHexOnly: true
+ }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ },
+ name: (names.private_domain_name || EMPTY_STRING),
+ value: [
+ new Choice({
+ value: [
+ new NumericString(),
+ new PrintableString()
+ ]
+ })
+ ]
+ }),
+ new Primitive({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 3
+ },
+ name: (names.organization_name || EMPTY_STRING),
+ isHexOnly: true
+ }),
+ new Primitive({
+ optional: true,
+ name: (names.numeric_user_identifier || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 4
+ },
+ isHexOnly: true
+ }),
+ new Constructed({
+ optional: true,
+ name: (names.personal_name || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 5
+ },
+ value: [
+ new Primitive({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ isHexOnly: true
+ }),
+ new Primitive({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ isHexOnly: true
+ }),
+ new Primitive({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ },
+ isHexOnly: true
+ }),
+ new Primitive({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 3
+ },
+ isHexOnly: true
+ })
+ ]
+ }),
+ new Constructed({
+ optional: true,
+ name: (names.organizational_unit_names || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 6
+ },
+ value: [
+ new Repeated({
+ value: new PrintableString()
+ })
+ ]
+ })
+ ]
+ }));
+}
+function builtInDomainDefinedAttributes(optional = false) {
+ return (new Sequence({
+ optional,
+ value: [
+ new PrintableString(),
+ new PrintableString()
+ ]
+ }));
+}
+function extensionAttributes(optional = false) {
+ return (new Set({
+ optional,
+ value: [
+ new Primitive({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ isHexOnly: true
+ }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: [new Any()]
+ })
+ ]
+ }));
+}
+class GeneralName extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.type = getParametersValue(parameters, TYPE$4, GeneralName.defaultValues(TYPE$4));
+ this.value = getParametersValue(parameters, VALUE$5, GeneralName.defaultValues(VALUE$5));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case TYPE$4:
+ return 9;
+ case VALUE$5:
+ return {};
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case TYPE$4:
+ return (memberValue === GeneralName.defaultValues(memberName));
+ case VALUE$5:
+ return (Object.keys(memberValue).length === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Choice({
+ value: [
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new ObjectIdentifier(),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [new Any()]
+ })
+ ]
+ }),
+ new Primitive({
+ name: (names.blockName || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ }
+ }),
+ new Primitive({
+ name: (names.blockName || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ }
+ }),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 3
+ },
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ builtInStandardAttributes((names.builtInStandardAttributes || {}), false),
+ builtInDomainDefinedAttributes(true),
+ extensionAttributes(true)
+ ]
+ }),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 4
+ },
+ name: (names.blockName || EMPTY_STRING),
+ value: [RelativeDistinguishedNames.schema(names.directoryName || {})]
+ }),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 5
+ },
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [
+ new Choice({
+ value: [
+ new TeletexString(),
+ new PrintableString(),
+ new UniversalString(),
+ new Utf8String(),
+ new BmpString()
+ ]
+ })
+ ]
+ }),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: [
+ new Choice({
+ value: [
+ new TeletexString(),
+ new PrintableString(),
+ new UniversalString(),
+ new Utf8String(),
+ new BmpString()
+ ]
+ })
+ ]
+ })
+ ]
+ }),
+ new Primitive({
+ name: (names.blockName || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 6
+ }
+ }),
+ new Primitive({
+ name: (names.blockName || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 7
+ }
+ }),
+ new Primitive({
+ name: (names.blockName || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 8
+ }
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, [
+ "blockName",
+ "otherName",
+ "rfc822Name",
+ "dNSName",
+ "x400Address",
+ "directoryName",
+ "ediPartyName",
+ "uniformResourceIdentifier",
+ "iPAddress",
+ "registeredID"
+ ]);
+ const asn1 = compareSchema(schema, schema, GeneralName.schema({
+ names: {
+ blockName: "blockName",
+ otherName: "otherName",
+ rfc822Name: "rfc822Name",
+ dNSName: "dNSName",
+ x400Address: "x400Address",
+ directoryName: {
+ names: {
+ blockName: "directoryName"
+ }
+ },
+ ediPartyName: "ediPartyName",
+ uniformResourceIdentifier: "uniformResourceIdentifier",
+ iPAddress: "iPAddress",
+ registeredID: "registeredID"
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.type = asn1.result.blockName.idBlock.tagNumber;
+ switch (this.type) {
+ case 0:
+ this.value = asn1.result.blockName;
+ break;
+ case 1:
+ case 2:
+ case 6:
+ {
+ const value = asn1.result.blockName;
+ value.idBlock.tagClass = 1;
+ value.idBlock.tagNumber = 22;
+ const valueBER = value.toBER(false);
+ const asnValue = fromBER(valueBER);
+ AsnError.assert(asnValue, "GeneralName value");
+ this.value = asnValue.result.valueBlock.value;
+ }
+ break;
+ case 3:
+ this.value = asn1.result.blockName;
+ break;
+ case 4:
+ this.value = new RelativeDistinguishedNames({ schema: asn1.result.directoryName });
+ break;
+ case 5:
+ this.value = asn1.result.ediPartyName;
+ break;
+ case 7:
+ this.value = new OctetString({ valueHex: asn1.result.blockName.valueBlock.valueHex });
+ break;
+ case 8:
+ {
+ const value = asn1.result.blockName;
+ value.idBlock.tagClass = 1;
+ value.idBlock.tagNumber = 6;
+ const valueBER = value.toBER(false);
+ const asnValue = fromBER(valueBER);
+ AsnError.assert(asnValue, "GeneralName registeredID");
+ this.value = asnValue.result.valueBlock.toString();
+ }
+ break;
+ }
+ }
+ toSchema() {
+ switch (this.type) {
+ case 0:
+ case 3:
+ case 5:
+ return new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: this.type
+ },
+ value: [
+ this.value
+ ]
+ });
+ case 1:
+ case 2:
+ case 6:
+ {
+ const value = new IA5String({ value: this.value });
+ value.idBlock.tagClass = 3;
+ value.idBlock.tagNumber = this.type;
+ return value;
+ }
+ case 4:
+ return new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 4
+ },
+ value: [this.value.toSchema()]
+ });
+ case 7:
+ {
+ const value = this.value;
+ value.idBlock.tagClass = 3;
+ value.idBlock.tagNumber = this.type;
+ return value;
+ }
+ case 8:
+ {
+ const value = new ObjectIdentifier({ value: this.value });
+ value.idBlock.tagClass = 3;
+ value.idBlock.tagNumber = this.type;
+ return value;
+ }
+ default:
+ return GeneralName.schema();
+ }
+ }
+ toJSON() {
+ const _object = {
+ type: this.type,
+ value: EMPTY_STRING
+ };
+ if ((typeof this.value) === "string")
+ _object.value = this.value;
+ else {
+ try {
+ _object.value = this.value.toJSON();
+ }
+ catch (ex) {
+ }
+ }
+ return _object;
+ }
+}
+GeneralName.CLASS_NAME = "GeneralName";
+
+const ACCESS_METHOD = "accessMethod";
+const ACCESS_LOCATION = "accessLocation";
+const CLEAR_PROPS$1v = [
+ ACCESS_METHOD,
+ ACCESS_LOCATION,
+];
+class AccessDescription extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.accessMethod = getParametersValue(parameters, ACCESS_METHOD, AccessDescription.defaultValues(ACCESS_METHOD));
+ this.accessLocation = getParametersValue(parameters, ACCESS_LOCATION, AccessDescription.defaultValues(ACCESS_LOCATION));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case ACCESS_METHOD:
+ return EMPTY_STRING;
+ case ACCESS_LOCATION:
+ return new GeneralName();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new ObjectIdentifier({ name: (names.accessMethod || EMPTY_STRING) }),
+ GeneralName.schema(names.accessLocation || {})
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$1v);
+ const asn1 = compareSchema(schema, schema, AccessDescription.schema({
+ names: {
+ accessMethod: ACCESS_METHOD,
+ accessLocation: {
+ names: {
+ blockName: ACCESS_LOCATION
+ }
+ }
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.accessMethod = asn1.result.accessMethod.valueBlock.toString();
+ this.accessLocation = new GeneralName({ schema: asn1.result.accessLocation });
+ }
+ toSchema() {
+ return (new Sequence({
+ value: [
+ new ObjectIdentifier({ value: this.accessMethod }),
+ this.accessLocation.toSchema()
+ ]
+ }));
+ }
+ toJSON() {
+ return {
+ accessMethod: this.accessMethod,
+ accessLocation: this.accessLocation.toJSON()
+ };
+ }
+}
+AccessDescription.CLASS_NAME = "AccessDescription";
+
+const SECONDS = "seconds";
+const MILLIS = "millis";
+const MICROS = "micros";
+class Accuracy extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ if (SECONDS in parameters) {
+ this.seconds = getParametersValue(parameters, SECONDS, Accuracy.defaultValues(SECONDS));
+ }
+ if (MILLIS in parameters) {
+ this.millis = getParametersValue(parameters, MILLIS, Accuracy.defaultValues(MILLIS));
+ }
+ if (MICROS in parameters) {
+ this.micros = getParametersValue(parameters, MICROS, Accuracy.defaultValues(MICROS));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case SECONDS:
+ case MILLIS:
+ case MICROS:
+ return 0;
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case SECONDS:
+ case MILLIS:
+ case MICROS:
+ return (memberValue === Accuracy.defaultValues(memberName));
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ optional: true,
+ value: [
+ new Integer({
+ optional: true,
+ name: (names.seconds || EMPTY_STRING)
+ }),
+ new Primitive({
+ name: (names.millis || EMPTY_STRING),
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ }
+ }),
+ new Primitive({
+ name: (names.micros || EMPTY_STRING),
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ }
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, [
+ SECONDS,
+ MILLIS,
+ MICROS,
+ ]);
+ const asn1 = compareSchema(schema, schema, Accuracy.schema({
+ names: {
+ seconds: SECONDS,
+ millis: MILLIS,
+ micros: MICROS,
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ if ("seconds" in asn1.result) {
+ this.seconds = asn1.result.seconds.valueBlock.valueDec;
+ }
+ if ("millis" in asn1.result) {
+ const intMillis = new Integer({ valueHex: asn1.result.millis.valueBlock.valueHex });
+ this.millis = intMillis.valueBlock.valueDec;
+ }
+ if ("micros" in asn1.result) {
+ const intMicros = new Integer({ valueHex: asn1.result.micros.valueBlock.valueHex });
+ this.micros = intMicros.valueBlock.valueDec;
+ }
+ }
+ toSchema() {
+ const outputArray = [];
+ if (this.seconds !== undefined)
+ outputArray.push(new Integer({ value: this.seconds }));
+ if (this.millis !== undefined) {
+ const intMillis = new Integer({ value: this.millis });
+ outputArray.push(new Primitive({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ valueHex: intMillis.valueBlock.valueHexView
+ }));
+ }
+ if (this.micros !== undefined) {
+ const intMicros = new Integer({ value: this.micros });
+ outputArray.push(new Primitive({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ valueHex: intMicros.valueBlock.valueHexView
+ }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const _object = {};
+ if (this.seconds !== undefined)
+ _object.seconds = this.seconds;
+ if (this.millis !== undefined)
+ _object.millis = this.millis;
+ if (this.micros !== undefined)
+ _object.micros = this.micros;
+ return _object;
+ }
+}
+Accuracy.CLASS_NAME = "Accuracy";
+
+const ALGORITHM_ID = "algorithmId";
+const ALGORITHM_PARAMS = "algorithmParams";
+const ALGORITHM$2 = "algorithm";
+const PARAMS = "params";
+const CLEAR_PROPS$1u = [
+ ALGORITHM$2,
+ PARAMS
+];
+class AlgorithmIdentifier extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.algorithmId = getParametersValue(parameters, ALGORITHM_ID, AlgorithmIdentifier.defaultValues(ALGORITHM_ID));
+ if (ALGORITHM_PARAMS in parameters) {
+ this.algorithmParams = getParametersValue(parameters, ALGORITHM_PARAMS, AlgorithmIdentifier.defaultValues(ALGORITHM_PARAMS));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case ALGORITHM_ID:
+ return EMPTY_STRING;
+ case ALGORITHM_PARAMS:
+ return new Any();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case ALGORITHM_ID:
+ return (memberValue === EMPTY_STRING);
+ case ALGORITHM_PARAMS:
+ return (memberValue instanceof Any);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ optional: (names.optional || false),
+ value: [
+ new ObjectIdentifier({ name: (names.algorithmIdentifier || EMPTY_STRING) }),
+ new Any({ name: (names.algorithmParams || EMPTY_STRING), optional: true })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$1u);
+ const asn1 = compareSchema(schema, schema, AlgorithmIdentifier.schema({
+ names: {
+ algorithmIdentifier: ALGORITHM$2,
+ algorithmParams: PARAMS
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.algorithmId = asn1.result.algorithm.valueBlock.toString();
+ if (PARAMS in asn1.result) {
+ this.algorithmParams = asn1.result.params;
+ }
+ }
+ toSchema() {
+ const outputArray = [];
+ outputArray.push(new ObjectIdentifier({ value: this.algorithmId }));
+ if (this.algorithmParams && !(this.algorithmParams instanceof Any)) {
+ outputArray.push(this.algorithmParams);
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const object = {
+ algorithmId: this.algorithmId
+ };
+ if (this.algorithmParams && !(this.algorithmParams instanceof Any)) {
+ object.algorithmParams = this.algorithmParams.toJSON();
+ }
+ return object;
+ }
+ isEqual(algorithmIdentifier) {
+ if (!(algorithmIdentifier instanceof AlgorithmIdentifier)) {
+ return false;
+ }
+ if (this.algorithmId !== algorithmIdentifier.algorithmId) {
+ return false;
+ }
+ if (this.algorithmParams) {
+ if (algorithmIdentifier.algorithmParams) {
+ return JSON.stringify(this.algorithmParams) === JSON.stringify(algorithmIdentifier.algorithmParams);
+ }
+ return false;
+ }
+ if (algorithmIdentifier.algorithmParams) {
+ return false;
+ }
+ return true;
+ }
+}
+AlgorithmIdentifier.CLASS_NAME = "AlgorithmIdentifier";
+
+const ALT_NAMES = "altNames";
+const CLEAR_PROPS$1t = [
+ ALT_NAMES
+];
+class AltName extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.altNames = getParametersValue(parameters, ALT_NAMES, AltName.defaultValues(ALT_NAMES));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case ALT_NAMES:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Repeated({
+ name: (names.altNames || EMPTY_STRING),
+ value: GeneralName.schema()
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$1t);
+ const asn1 = compareSchema(schema, schema, AltName.schema({
+ names: {
+ altNames: ALT_NAMES
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ if (ALT_NAMES in asn1.result) {
+ this.altNames = Array.from(asn1.result.altNames, element => new GeneralName({ schema: element }));
+ }
+ }
+ toSchema() {
+ return (new Sequence({
+ value: Array.from(this.altNames, o => o.toSchema())
+ }));
+ }
+ toJSON() {
+ return {
+ altNames: Array.from(this.altNames, o => o.toJSON())
+ };
+ }
+}
+AltName.CLASS_NAME = "AltName";
+
+const TYPE$3 = "type";
+const VALUES$1 = "values";
+const CLEAR_PROPS$1s = [
+ TYPE$3,
+ VALUES$1
+];
+class Attribute extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.type = getParametersValue(parameters, TYPE$3, Attribute.defaultValues(TYPE$3));
+ this.values = getParametersValue(parameters, VALUES$1, Attribute.defaultValues(VALUES$1));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case TYPE$3:
+ return EMPTY_STRING;
+ case VALUES$1:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case TYPE$3:
+ return (memberValue === EMPTY_STRING);
+ case VALUES$1:
+ return (memberValue.length === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new ObjectIdentifier({ name: (names.type || EMPTY_STRING) }),
+ new Set({
+ name: (names.setName || EMPTY_STRING),
+ value: [
+ new Repeated({
+ name: (names.values || EMPTY_STRING),
+ value: new Any()
+ })
+ ]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$1s);
+ const asn1 = compareSchema(schema, schema, Attribute.schema({
+ names: {
+ type: TYPE$3,
+ values: VALUES$1
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.type = asn1.result.type.valueBlock.toString();
+ this.values = asn1.result.values;
+ }
+ toSchema() {
+ return (new Sequence({
+ value: [
+ new ObjectIdentifier({ value: this.type }),
+ new Set({
+ value: this.values
+ })
+ ]
+ }));
+ }
+ toJSON() {
+ return {
+ type: this.type,
+ values: Array.from(this.values, o => o.toJSON())
+ };
+ }
+}
+Attribute.CLASS_NAME = "Attribute";
+
+const NOT_BEFORE_TIME = "notBeforeTime";
+const NOT_AFTER_TIME = "notAfterTime";
+const CLEAR_PROPS$1r = [
+ NOT_BEFORE_TIME,
+ NOT_AFTER_TIME,
+];
+class AttCertValidityPeriod extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.notBeforeTime = getParametersValue(parameters, NOT_BEFORE_TIME, AttCertValidityPeriod.defaultValues(NOT_BEFORE_TIME));
+ this.notAfterTime = getParametersValue(parameters, NOT_AFTER_TIME, AttCertValidityPeriod.defaultValues(NOT_AFTER_TIME));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case NOT_BEFORE_TIME:
+ case NOT_AFTER_TIME:
+ return new Date(0, 0, 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new GeneralizedTime({ name: (names.notBeforeTime || EMPTY_STRING) }),
+ new GeneralizedTime({ name: (names.notAfterTime || EMPTY_STRING) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$1r);
+ const asn1 = compareSchema(schema, schema, AttCertValidityPeriod.schema({
+ names: {
+ notBeforeTime: NOT_BEFORE_TIME,
+ notAfterTime: NOT_AFTER_TIME
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.notBeforeTime = asn1.result.notBeforeTime.toDate();
+ this.notAfterTime = asn1.result.notAfterTime.toDate();
+ }
+ toSchema() {
+ return (new Sequence({
+ value: [
+ new GeneralizedTime({ valueDate: this.notBeforeTime }),
+ new GeneralizedTime({ valueDate: this.notAfterTime }),
+ ]
+ }));
+ }
+ toJSON() {
+ return {
+ notBeforeTime: this.notBeforeTime,
+ notAfterTime: this.notAfterTime
+ };
+ }
+}
+AttCertValidityPeriod.CLASS_NAME = "AttCertValidityPeriod";
+
+const NAMES = "names";
+const GENERAL_NAMES = "generalNames";
+class GeneralNames extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.names = getParametersValue(parameters, NAMES, GeneralNames.defaultValues(NAMES));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case "names":
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}, optional = false) {
+ const names = getParametersValue(parameters, NAMES, {});
+ return (new Sequence({
+ optional,
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Repeated({
+ name: (names.generalNames || EMPTY_STRING),
+ value: GeneralName.schema()
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, [
+ NAMES,
+ GENERAL_NAMES
+ ]);
+ const asn1 = compareSchema(schema, schema, GeneralNames.schema({
+ names: {
+ blockName: NAMES,
+ generalNames: GENERAL_NAMES
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.names = Array.from(asn1.result.generalNames, element => new GeneralName({ schema: element }));
+ }
+ toSchema() {
+ return (new Sequence({
+ value: Array.from(this.names, o => o.toSchema())
+ }));
+ }
+ toJSON() {
+ return {
+ names: Array.from(this.names, o => o.toJSON())
+ };
+ }
+}
+GeneralNames.CLASS_NAME = "GeneralNames";
+
+const id_SubjectDirectoryAttributes = "2.5.29.9";
+const id_SubjectKeyIdentifier = "2.5.29.14";
+const id_KeyUsage = "2.5.29.15";
+const id_PrivateKeyUsagePeriod = "2.5.29.16";
+const id_SubjectAltName = "2.5.29.17";
+const id_IssuerAltName = "2.5.29.18";
+const id_BasicConstraints = "2.5.29.19";
+const id_CRLNumber = "2.5.29.20";
+const id_BaseCRLNumber = "2.5.29.27";
+const id_CRLReason = "2.5.29.21";
+const id_InvalidityDate = "2.5.29.24";
+const id_IssuingDistributionPoint = "2.5.29.28";
+const id_CertificateIssuer = "2.5.29.29";
+const id_NameConstraints = "2.5.29.30";
+const id_CRLDistributionPoints = "2.5.29.31";
+const id_FreshestCRL = "2.5.29.46";
+const id_CertificatePolicies = "2.5.29.32";
+const id_AnyPolicy = "2.5.29.32.0";
+const id_MicrosoftAppPolicies = "1.3.6.1.4.1.311.21.10";
+const id_PolicyMappings = "2.5.29.33";
+const id_AuthorityKeyIdentifier = "2.5.29.35";
+const id_PolicyConstraints = "2.5.29.36";
+const id_ExtKeyUsage = "2.5.29.37";
+const id_InhibitAnyPolicy = "2.5.29.54";
+const id_AuthorityInfoAccess = "1.3.6.1.5.5.7.1.1";
+const id_SubjectInfoAccess = "1.3.6.1.5.5.7.1.11";
+const id_SignedCertificateTimestampList = "1.3.6.1.4.1.11129.2.4.2";
+const id_MicrosoftCertTemplateV1 = "1.3.6.1.4.1.311.20.2";
+const id_MicrosoftPrevCaCertHash = "1.3.6.1.4.1.311.21.2";
+const id_MicrosoftCertTemplateV2 = "1.3.6.1.4.1.311.21.7";
+const id_MicrosoftCaVersion = "1.3.6.1.4.1.311.21.1";
+const id_QCStatements = "1.3.6.1.5.5.7.1.3";
+const id_ContentType_Data = "1.2.840.113549.1.7.1";
+const id_ContentType_SignedData = "1.2.840.113549.1.7.2";
+const id_ContentType_EnvelopedData = "1.2.840.113549.1.7.3";
+const id_ContentType_EncryptedData = "1.2.840.113549.1.7.6";
+const id_eContentType_TSTInfo = "1.2.840.113549.1.9.16.1.4";
+const id_CertBag_X509Certificate = "1.2.840.113549.1.9.22.1";
+const id_CertBag_SDSICertificate = "1.2.840.113549.1.9.22.2";
+const id_CertBag_AttributeCertificate = "1.2.840.113549.1.9.22.3";
+const id_CRLBag_X509CRL = "1.2.840.113549.1.9.23.1";
+const id_pkix = "1.3.6.1.5.5.7";
+const id_ad = `${id_pkix}.48`;
+const id_PKIX_OCSP_Basic = `${id_ad}.1.1`;
+const id_ad_caIssuers = `${id_ad}.2`;
+const id_ad_ocsp = `${id_ad}.1`;
+const id_sha1 = "1.3.14.3.2.26";
+const id_sha256 = "2.16.840.1.101.3.4.2.1";
+const id_sha384 = "2.16.840.1.101.3.4.2.2";
+const id_sha512 = "2.16.840.1.101.3.4.2.3";
+
+const KEY_IDENTIFIER$1 = "keyIdentifier";
+const AUTHORITY_CERT_ISSUER = "authorityCertIssuer";
+const AUTHORITY_CERT_SERIAL_NUMBER = "authorityCertSerialNumber";
+const CLEAR_PROPS$1q = [
+ KEY_IDENTIFIER$1,
+ AUTHORITY_CERT_ISSUER,
+ AUTHORITY_CERT_SERIAL_NUMBER,
+];
+class AuthorityKeyIdentifier extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ if (KEY_IDENTIFIER$1 in parameters) {
+ this.keyIdentifier = getParametersValue(parameters, KEY_IDENTIFIER$1, AuthorityKeyIdentifier.defaultValues(KEY_IDENTIFIER$1));
+ }
+ if (AUTHORITY_CERT_ISSUER in parameters) {
+ this.authorityCertIssuer = getParametersValue(parameters, AUTHORITY_CERT_ISSUER, AuthorityKeyIdentifier.defaultValues(AUTHORITY_CERT_ISSUER));
+ }
+ if (AUTHORITY_CERT_SERIAL_NUMBER in parameters) {
+ this.authorityCertSerialNumber = getParametersValue(parameters, AUTHORITY_CERT_SERIAL_NUMBER, AuthorityKeyIdentifier.defaultValues(AUTHORITY_CERT_SERIAL_NUMBER));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case KEY_IDENTIFIER$1:
+ return new OctetString();
+ case AUTHORITY_CERT_ISSUER:
+ return [];
+ case AUTHORITY_CERT_SERIAL_NUMBER:
+ return new Integer();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Primitive({
+ name: (names.keyIdentifier || EMPTY_STRING),
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ }
+ }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: [
+ new Repeated({
+ name: (names.authorityCertIssuer || EMPTY_STRING),
+ value: GeneralName.schema()
+ })
+ ]
+ }),
+ new Primitive({
+ name: (names.authorityCertSerialNumber || EMPTY_STRING),
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ }
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$1q);
+ const asn1 = compareSchema(schema, schema, AuthorityKeyIdentifier.schema({
+ names: {
+ keyIdentifier: KEY_IDENTIFIER$1,
+ authorityCertIssuer: AUTHORITY_CERT_ISSUER,
+ authorityCertSerialNumber: AUTHORITY_CERT_SERIAL_NUMBER
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ if (KEY_IDENTIFIER$1 in asn1.result)
+ this.keyIdentifier = new OctetString({ valueHex: asn1.result.keyIdentifier.valueBlock.valueHex });
+ if (AUTHORITY_CERT_ISSUER in asn1.result)
+ this.authorityCertIssuer = Array.from(asn1.result.authorityCertIssuer, o => new GeneralName({ schema: o }));
+ if (AUTHORITY_CERT_SERIAL_NUMBER in asn1.result)
+ this.authorityCertSerialNumber = new Integer({ valueHex: asn1.result.authorityCertSerialNumber.valueBlock.valueHex });
+ }
+ toSchema() {
+ const outputArray = [];
+ if (this.keyIdentifier) {
+ outputArray.push(new Primitive({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ valueHex: this.keyIdentifier.valueBlock.valueHexView
+ }));
+ }
+ if (this.authorityCertIssuer) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: Array.from(this.authorityCertIssuer, o => o.toSchema())
+ }));
+ }
+ if (this.authorityCertSerialNumber) {
+ outputArray.push(new Primitive({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ },
+ valueHex: this.authorityCertSerialNumber.valueBlock.valueHexView
+ }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const object = {};
+ if (this.keyIdentifier) {
+ object.keyIdentifier = this.keyIdentifier.toJSON();
+ }
+ if (this.authorityCertIssuer) {
+ object.authorityCertIssuer = Array.from(this.authorityCertIssuer, o => o.toJSON());
+ }
+ if (this.authorityCertSerialNumber) {
+ object.authorityCertSerialNumber = this.authorityCertSerialNumber.toJSON();
+ }
+ return object;
+ }
+}
+AuthorityKeyIdentifier.CLASS_NAME = "AuthorityKeyIdentifier";
+
+const PATH_LENGTH_CONSTRAINT = "pathLenConstraint";
+const CA = "cA";
+class BasicConstraints extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.cA = getParametersValue(parameters, CA, false);
+ if (PATH_LENGTH_CONSTRAINT in parameters) {
+ this.pathLenConstraint = getParametersValue(parameters, PATH_LENGTH_CONSTRAINT, 0);
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case CA:
+ return false;
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Boolean({
+ optional: true,
+ name: (names.cA || EMPTY_STRING)
+ }),
+ new Integer({
+ optional: true,
+ name: (names.pathLenConstraint || EMPTY_STRING)
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, [
+ CA,
+ PATH_LENGTH_CONSTRAINT
+ ]);
+ const asn1 = compareSchema(schema, schema, BasicConstraints.schema({
+ names: {
+ cA: CA,
+ pathLenConstraint: PATH_LENGTH_CONSTRAINT
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ if (CA in asn1.result) {
+ this.cA = asn1.result.cA.valueBlock.value;
+ }
+ if (PATH_LENGTH_CONSTRAINT in asn1.result) {
+ if (asn1.result.pathLenConstraint.valueBlock.isHexOnly) {
+ this.pathLenConstraint = asn1.result.pathLenConstraint;
+ }
+ else {
+ this.pathLenConstraint = asn1.result.pathLenConstraint.valueBlock.valueDec;
+ }
+ }
+ }
+ toSchema() {
+ const outputArray = [];
+ if (this.cA !== BasicConstraints.defaultValues(CA))
+ outputArray.push(new Boolean({ value: this.cA }));
+ if (PATH_LENGTH_CONSTRAINT in this) {
+ if (this.pathLenConstraint instanceof Integer) {
+ outputArray.push(this.pathLenConstraint);
+ }
+ else {
+ outputArray.push(new Integer({ value: this.pathLenConstraint }));
+ }
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const object = {};
+ if (this.cA !== BasicConstraints.defaultValues(CA)) {
+ object.cA = this.cA;
+ }
+ if (PATH_LENGTH_CONSTRAINT in this) {
+ if (this.pathLenConstraint instanceof Integer) {
+ object.pathLenConstraint = this.pathLenConstraint.toJSON();
+ }
+ else {
+ object.pathLenConstraint = this.pathLenConstraint;
+ }
+ }
+ return object;
+ }
+}
+BasicConstraints.CLASS_NAME = "BasicConstraints";
+
+const CERTIFICATE_INDEX = "certificateIndex";
+const KEY_INDEX = "keyIndex";
+class CAVersion extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.certificateIndex = getParametersValue(parameters, CERTIFICATE_INDEX, CAVersion.defaultValues(CERTIFICATE_INDEX));
+ this.keyIndex = getParametersValue(parameters, KEY_INDEX, CAVersion.defaultValues(KEY_INDEX));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case CERTIFICATE_INDEX:
+ case KEY_INDEX:
+ return 0;
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema() {
+ return (new Integer());
+ }
+ fromSchema(schema) {
+ if (schema.constructor.blockName() !== Integer.blockName()) {
+ throw new Error("Object's schema was not verified against input data for CAVersion");
+ }
+ let value = schema.valueBlock.valueHex.slice(0);
+ const valueView = new Uint8Array(value);
+ switch (true) {
+ case (value.byteLength < 4):
+ {
+ const tempValue = new ArrayBuffer(4);
+ const tempValueView = new Uint8Array(tempValue);
+ tempValueView.set(valueView, 4 - value.byteLength);
+ value = tempValue.slice(0);
+ }
+ break;
+ case (value.byteLength > 4):
+ {
+ const tempValue = new ArrayBuffer(4);
+ const tempValueView = new Uint8Array(tempValue);
+ tempValueView.set(valueView.slice(0, 4));
+ value = tempValue.slice(0);
+ }
+ break;
+ }
+ const keyIndexBuffer = value.slice(0, 2);
+ const keyIndexView8 = new Uint8Array(keyIndexBuffer);
+ let temp = keyIndexView8[0];
+ keyIndexView8[0] = keyIndexView8[1];
+ keyIndexView8[1] = temp;
+ const keyIndexView16 = new Uint16Array(keyIndexBuffer);
+ this.keyIndex = keyIndexView16[0];
+ const certificateIndexBuffer = value.slice(2);
+ const certificateIndexView8 = new Uint8Array(certificateIndexBuffer);
+ temp = certificateIndexView8[0];
+ certificateIndexView8[0] = certificateIndexView8[1];
+ certificateIndexView8[1] = temp;
+ const certificateIndexView16 = new Uint16Array(certificateIndexBuffer);
+ this.certificateIndex = certificateIndexView16[0];
+ }
+ toSchema() {
+ const certificateIndexBuffer = new ArrayBuffer(2);
+ const certificateIndexView = new Uint16Array(certificateIndexBuffer);
+ certificateIndexView[0] = this.certificateIndex;
+ const certificateIndexView8 = new Uint8Array(certificateIndexBuffer);
+ let temp = certificateIndexView8[0];
+ certificateIndexView8[0] = certificateIndexView8[1];
+ certificateIndexView8[1] = temp;
+ const keyIndexBuffer = new ArrayBuffer(2);
+ const keyIndexView = new Uint16Array(keyIndexBuffer);
+ keyIndexView[0] = this.keyIndex;
+ const keyIndexView8 = new Uint8Array(keyIndexBuffer);
+ temp = keyIndexView8[0];
+ keyIndexView8[0] = keyIndexView8[1];
+ keyIndexView8[1] = temp;
+ return (new Integer({
+ valueHex: utilConcatBuf(keyIndexBuffer, certificateIndexBuffer)
+ }));
+ }
+ toJSON() {
+ return {
+ certificateIndex: this.certificateIndex,
+ keyIndex: this.keyIndex
+ };
+ }
+}
+CAVersion.CLASS_NAME = "CAVersion";
+
+const POLICY_QUALIFIER_ID = "policyQualifierId";
+const QUALIFIER = "qualifier";
+const CLEAR_PROPS$1p = [
+ POLICY_QUALIFIER_ID,
+ QUALIFIER
+];
+class PolicyQualifierInfo extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.policyQualifierId = getParametersValue(parameters, POLICY_QUALIFIER_ID, PolicyQualifierInfo.defaultValues(POLICY_QUALIFIER_ID));
+ this.qualifier = getParametersValue(parameters, QUALIFIER, PolicyQualifierInfo.defaultValues(QUALIFIER));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case POLICY_QUALIFIER_ID:
+ return EMPTY_STRING;
+ case QUALIFIER:
+ return new Any();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new ObjectIdentifier({ name: (names.policyQualifierId || EMPTY_STRING) }),
+ new Any({ name: (names.qualifier || EMPTY_STRING) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$1p);
+ const asn1 = compareSchema(schema, schema, PolicyQualifierInfo.schema({
+ names: {
+ policyQualifierId: POLICY_QUALIFIER_ID,
+ qualifier: QUALIFIER
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.policyQualifierId = asn1.result.policyQualifierId.valueBlock.toString();
+ this.qualifier = asn1.result.qualifier;
+ }
+ toSchema() {
+ return (new Sequence({
+ value: [
+ new ObjectIdentifier({ value: this.policyQualifierId }),
+ this.qualifier
+ ]
+ }));
+ }
+ toJSON() {
+ return {
+ policyQualifierId: this.policyQualifierId,
+ qualifier: this.qualifier.toJSON()
+ };
+ }
+}
+PolicyQualifierInfo.CLASS_NAME = "PolicyQualifierInfo";
+
+const POLICY_IDENTIFIER = "policyIdentifier";
+const POLICY_QUALIFIERS = "policyQualifiers";
+const CLEAR_PROPS$1o = [
+ POLICY_IDENTIFIER,
+ POLICY_QUALIFIERS
+];
+class PolicyInformation extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.policyIdentifier = getParametersValue(parameters, POLICY_IDENTIFIER, PolicyInformation.defaultValues(POLICY_IDENTIFIER));
+ if (POLICY_QUALIFIERS in parameters) {
+ this.policyQualifiers = getParametersValue(parameters, POLICY_QUALIFIERS, PolicyInformation.defaultValues(POLICY_QUALIFIERS));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case POLICY_IDENTIFIER:
+ return EMPTY_STRING;
+ case POLICY_QUALIFIERS:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new ObjectIdentifier({ name: (names.policyIdentifier || EMPTY_STRING) }),
+ new Sequence({
+ optional: true,
+ value: [
+ new Repeated({
+ name: (names.policyQualifiers || EMPTY_STRING),
+ value: PolicyQualifierInfo.schema()
+ })
+ ]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$1o);
+ const asn1 = compareSchema(schema, schema, PolicyInformation.schema({
+ names: {
+ policyIdentifier: POLICY_IDENTIFIER,
+ policyQualifiers: POLICY_QUALIFIERS
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.policyIdentifier = asn1.result.policyIdentifier.valueBlock.toString();
+ if (POLICY_QUALIFIERS in asn1.result) {
+ this.policyQualifiers = Array.from(asn1.result.policyQualifiers, element => new PolicyQualifierInfo({ schema: element }));
+ }
+ }
+ toSchema() {
+ const outputArray = [];
+ outputArray.push(new ObjectIdentifier({ value: this.policyIdentifier }));
+ if (this.policyQualifiers) {
+ outputArray.push(new Sequence({
+ value: Array.from(this.policyQualifiers, o => o.toSchema())
+ }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {
+ policyIdentifier: this.policyIdentifier
+ };
+ if (this.policyQualifiers)
+ res.policyQualifiers = Array.from(this.policyQualifiers, o => o.toJSON());
+ return res;
+ }
+}
+PolicyInformation.CLASS_NAME = "PolicyInformation";
+
+const CERTIFICATE_POLICIES = "certificatePolicies";
+const CLEAR_PROPS$1n = [
+ CERTIFICATE_POLICIES,
+];
+class CertificatePolicies extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.certificatePolicies = getParametersValue(parameters, CERTIFICATE_POLICIES, CertificatePolicies.defaultValues(CERTIFICATE_POLICIES));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case CERTIFICATE_POLICIES:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Repeated({
+ name: (names.certificatePolicies || EMPTY_STRING),
+ value: PolicyInformation.schema()
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$1n);
+ const asn1 = compareSchema(schema, schema, CertificatePolicies.schema({
+ names: {
+ certificatePolicies: CERTIFICATE_POLICIES
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.certificatePolicies = Array.from(asn1.result.certificatePolicies, element => new PolicyInformation({ schema: element }));
+ }
+ toSchema() {
+ return (new Sequence({
+ value: Array.from(this.certificatePolicies, o => o.toSchema())
+ }));
+ }
+ toJSON() {
+ return {
+ certificatePolicies: Array.from(this.certificatePolicies, o => o.toJSON())
+ };
+ }
+}
+CertificatePolicies.CLASS_NAME = "CertificatePolicies";
+
+const TEMPLATE_ID = "templateID";
+const TEMPLATE_MAJOR_VERSION = "templateMajorVersion";
+const TEMPLATE_MINOR_VERSION = "templateMinorVersion";
+const CLEAR_PROPS$1m = [
+ TEMPLATE_ID,
+ TEMPLATE_MAJOR_VERSION,
+ TEMPLATE_MINOR_VERSION
+];
+class CertificateTemplate extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.templateID = getParametersValue(parameters, TEMPLATE_ID, CertificateTemplate.defaultValues(TEMPLATE_ID));
+ if (TEMPLATE_MAJOR_VERSION in parameters) {
+ this.templateMajorVersion = getParametersValue(parameters, TEMPLATE_MAJOR_VERSION, CertificateTemplate.defaultValues(TEMPLATE_MAJOR_VERSION));
+ }
+ if (TEMPLATE_MINOR_VERSION in parameters) {
+ this.templateMinorVersion = getParametersValue(parameters, TEMPLATE_MINOR_VERSION, CertificateTemplate.defaultValues(TEMPLATE_MINOR_VERSION));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case TEMPLATE_ID:
+ return EMPTY_STRING;
+ case TEMPLATE_MAJOR_VERSION:
+ case TEMPLATE_MINOR_VERSION:
+ return 0;
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new ObjectIdentifier({ name: (names.templateID || EMPTY_STRING) }),
+ new Integer({
+ name: (names.templateMajorVersion || EMPTY_STRING),
+ optional: true
+ }),
+ new Integer({
+ name: (names.templateMinorVersion || EMPTY_STRING),
+ optional: true
+ }),
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$1m);
+ const asn1 = compareSchema(schema, schema, CertificateTemplate.schema({
+ names: {
+ templateID: TEMPLATE_ID,
+ templateMajorVersion: TEMPLATE_MAJOR_VERSION,
+ templateMinorVersion: TEMPLATE_MINOR_VERSION
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.templateID = asn1.result.templateID.valueBlock.toString();
+ if (TEMPLATE_MAJOR_VERSION in asn1.result) {
+ this.templateMajorVersion = asn1.result.templateMajorVersion.valueBlock.valueDec;
+ }
+ if (TEMPLATE_MINOR_VERSION in asn1.result) {
+ this.templateMinorVersion = asn1.result.templateMinorVersion.valueBlock.valueDec;
+ }
+ }
+ toSchema() {
+ const outputArray = [];
+ outputArray.push(new ObjectIdentifier({ value: this.templateID }));
+ if (TEMPLATE_MAJOR_VERSION in this) {
+ outputArray.push(new Integer({ value: this.templateMajorVersion }));
+ }
+ if (TEMPLATE_MINOR_VERSION in this) {
+ outputArray.push(new Integer({ value: this.templateMinorVersion }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {
+ templateID: this.templateID
+ };
+ if (TEMPLATE_MAJOR_VERSION in this)
+ res.templateMajorVersion = this.templateMajorVersion;
+ if (TEMPLATE_MINOR_VERSION in this)
+ res.templateMinorVersion = this.templateMinorVersion;
+ return res;
+ }
+}
+
+const DISTRIBUTION_POINT$1 = "distributionPoint";
+const DISTRIBUTION_POINT_NAMES$1 = "distributionPointNames";
+const REASONS = "reasons";
+const CRL_ISSUER = "cRLIssuer";
+const CRL_ISSUER_NAMES = "cRLIssuerNames";
+const CLEAR_PROPS$1l = [
+ DISTRIBUTION_POINT$1,
+ DISTRIBUTION_POINT_NAMES$1,
+ REASONS,
+ CRL_ISSUER,
+ CRL_ISSUER_NAMES,
+];
+class DistributionPoint extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ if (DISTRIBUTION_POINT$1 in parameters) {
+ this.distributionPoint = getParametersValue(parameters, DISTRIBUTION_POINT$1, DistributionPoint.defaultValues(DISTRIBUTION_POINT$1));
+ }
+ if (REASONS in parameters) {
+ this.reasons = getParametersValue(parameters, REASONS, DistributionPoint.defaultValues(REASONS));
+ }
+ if (CRL_ISSUER in parameters) {
+ this.cRLIssuer = getParametersValue(parameters, CRL_ISSUER, DistributionPoint.defaultValues(CRL_ISSUER));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case DISTRIBUTION_POINT$1:
+ return [];
+ case REASONS:
+ return new BitString();
+ case CRL_ISSUER:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [
+ new Choice({
+ value: [
+ new Constructed({
+ name: (names.distributionPoint || EMPTY_STRING),
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [
+ new Repeated({
+ name: (names.distributionPointNames || EMPTY_STRING),
+ value: GeneralName.schema()
+ })
+ ]
+ }),
+ new Constructed({
+ name: (names.distributionPoint || EMPTY_STRING),
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: RelativeDistinguishedNames.schema().valueBlock.value
+ })
+ ]
+ })
+ ]
+ }),
+ new Primitive({
+ name: (names.reasons || EMPTY_STRING),
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ }
+ }),
+ new Constructed({
+ name: (names.cRLIssuer || EMPTY_STRING),
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ },
+ value: [
+ new Repeated({
+ name: (names.cRLIssuerNames || EMPTY_STRING),
+ value: GeneralName.schema()
+ })
+ ]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$1l);
+ const asn1 = compareSchema(schema, schema, DistributionPoint.schema({
+ names: {
+ distributionPoint: DISTRIBUTION_POINT$1,
+ distributionPointNames: DISTRIBUTION_POINT_NAMES$1,
+ reasons: REASONS,
+ cRLIssuer: CRL_ISSUER,
+ cRLIssuerNames: CRL_ISSUER_NAMES
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ if (DISTRIBUTION_POINT$1 in asn1.result) {
+ if (asn1.result.distributionPoint.idBlock.tagNumber === 0) {
+ this.distributionPoint = Array.from(asn1.result.distributionPointNames, element => new GeneralName({ schema: element }));
+ }
+ if (asn1.result.distributionPoint.idBlock.tagNumber === 1) {
+ this.distributionPoint = new RelativeDistinguishedNames({
+ schema: new Sequence({
+ value: asn1.result.distributionPoint.valueBlock.value
+ })
+ });
+ }
+ }
+ if (REASONS in asn1.result) {
+ this.reasons = new BitString({ valueHex: asn1.result.reasons.valueBlock.valueHex });
+ }
+ if (CRL_ISSUER in asn1.result) {
+ this.cRLIssuer = Array.from(asn1.result.cRLIssuerNames, element => new GeneralName({ schema: element }));
+ }
+ }
+ toSchema() {
+ const outputArray = [];
+ if (this.distributionPoint) {
+ let internalValue;
+ if (this.distributionPoint instanceof Array) {
+ internalValue = new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: Array.from(this.distributionPoint, o => o.toSchema())
+ });
+ }
+ else {
+ internalValue = new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: [this.distributionPoint.toSchema()]
+ });
+ }
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [internalValue]
+ }));
+ }
+ if (this.reasons) {
+ outputArray.push(new Primitive({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ valueHex: this.reasons.valueBlock.valueHexView
+ }));
+ }
+ if (this.cRLIssuer) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ },
+ value: Array.from(this.cRLIssuer, o => o.toSchema())
+ }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const object = {};
+ if (this.distributionPoint) {
+ if (this.distributionPoint instanceof Array) {
+ object.distributionPoint = Array.from(this.distributionPoint, o => o.toJSON());
+ }
+ else {
+ object.distributionPoint = this.distributionPoint.toJSON();
+ }
+ }
+ if (this.reasons) {
+ object.reasons = this.reasons.toJSON();
+ }
+ if (this.cRLIssuer) {
+ object.cRLIssuer = Array.from(this.cRLIssuer, o => o.toJSON());
+ }
+ return object;
+ }
+}
+DistributionPoint.CLASS_NAME = "DistributionPoint";
+
+const DISTRIBUTION_POINTS = "distributionPoints";
+const CLEAR_PROPS$1k = [
+ DISTRIBUTION_POINTS
+];
+class CRLDistributionPoints extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.distributionPoints = getParametersValue(parameters, DISTRIBUTION_POINTS, CRLDistributionPoints.defaultValues(DISTRIBUTION_POINTS));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case DISTRIBUTION_POINTS:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Repeated({
+ name: (names.distributionPoints || EMPTY_STRING),
+ value: DistributionPoint.schema()
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$1k);
+ const asn1 = compareSchema(schema, schema, CRLDistributionPoints.schema({
+ names: {
+ distributionPoints: DISTRIBUTION_POINTS
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.distributionPoints = Array.from(asn1.result.distributionPoints, element => new DistributionPoint({ schema: element }));
+ }
+ toSchema() {
+ return (new Sequence({
+ value: Array.from(this.distributionPoints, o => o.toSchema())
+ }));
+ }
+ toJSON() {
+ return {
+ distributionPoints: Array.from(this.distributionPoints, o => o.toJSON())
+ };
+ }
+}
+CRLDistributionPoints.CLASS_NAME = "CRLDistributionPoints";
+
+const KEY_PURPOSES = "keyPurposes";
+const CLEAR_PROPS$1j = [
+ KEY_PURPOSES,
+];
+class ExtKeyUsage extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.keyPurposes = getParametersValue(parameters, KEY_PURPOSES, ExtKeyUsage.defaultValues(KEY_PURPOSES));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case KEY_PURPOSES:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Repeated({
+ name: (names.keyPurposes || EMPTY_STRING),
+ value: new ObjectIdentifier()
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$1j);
+ const asn1 = compareSchema(schema, schema, ExtKeyUsage.schema({
+ names: {
+ keyPurposes: KEY_PURPOSES
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.keyPurposes = Array.from(asn1.result.keyPurposes, (element) => element.valueBlock.toString());
+ }
+ toSchema() {
+ return (new Sequence({
+ value: Array.from(this.keyPurposes, element => new ObjectIdentifier({ value: element }))
+ }));
+ }
+ toJSON() {
+ return {
+ keyPurposes: Array.from(this.keyPurposes)
+ };
+ }
+}
+ExtKeyUsage.CLASS_NAME = "ExtKeyUsage";
+
+const ACCESS_DESCRIPTIONS = "accessDescriptions";
+class InfoAccess extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.accessDescriptions = getParametersValue(parameters, ACCESS_DESCRIPTIONS, InfoAccess.defaultValues(ACCESS_DESCRIPTIONS));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case ACCESS_DESCRIPTIONS:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Repeated({
+ name: (names.accessDescriptions || EMPTY_STRING),
+ value: AccessDescription.schema()
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, [
+ ACCESS_DESCRIPTIONS
+ ]);
+ const asn1 = compareSchema(schema, schema, InfoAccess.schema({
+ names: {
+ accessDescriptions: ACCESS_DESCRIPTIONS
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.accessDescriptions = Array.from(asn1.result.accessDescriptions, element => new AccessDescription({ schema: element }));
+ }
+ toSchema() {
+ return (new Sequence({
+ value: Array.from(this.accessDescriptions, o => o.toSchema())
+ }));
+ }
+ toJSON() {
+ return {
+ accessDescriptions: Array.from(this.accessDescriptions, o => o.toJSON())
+ };
+ }
+}
+InfoAccess.CLASS_NAME = "InfoAccess";
+
+const DISTRIBUTION_POINT = "distributionPoint";
+const DISTRIBUTION_POINT_NAMES = "distributionPointNames";
+const ONLY_CONTAINS_USER_CERTS = "onlyContainsUserCerts";
+const ONLY_CONTAINS_CA_CERTS = "onlyContainsCACerts";
+const ONLY_SOME_REASON = "onlySomeReasons";
+const INDIRECT_CRL = "indirectCRL";
+const ONLY_CONTAINS_ATTRIBUTE_CERTS = "onlyContainsAttributeCerts";
+const CLEAR_PROPS$1i = [
+ DISTRIBUTION_POINT,
+ DISTRIBUTION_POINT_NAMES,
+ ONLY_CONTAINS_USER_CERTS,
+ ONLY_CONTAINS_CA_CERTS,
+ ONLY_SOME_REASON,
+ INDIRECT_CRL,
+ ONLY_CONTAINS_ATTRIBUTE_CERTS,
+];
+class IssuingDistributionPoint extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ if (DISTRIBUTION_POINT in parameters) {
+ this.distributionPoint = getParametersValue(parameters, DISTRIBUTION_POINT, IssuingDistributionPoint.defaultValues(DISTRIBUTION_POINT));
+ }
+ this.onlyContainsUserCerts = getParametersValue(parameters, ONLY_CONTAINS_USER_CERTS, IssuingDistributionPoint.defaultValues(ONLY_CONTAINS_USER_CERTS));
+ this.onlyContainsCACerts = getParametersValue(parameters, ONLY_CONTAINS_CA_CERTS, IssuingDistributionPoint.defaultValues(ONLY_CONTAINS_CA_CERTS));
+ if (ONLY_SOME_REASON in parameters) {
+ this.onlySomeReasons = getParametersValue(parameters, ONLY_SOME_REASON, IssuingDistributionPoint.defaultValues(ONLY_SOME_REASON));
+ }
+ this.indirectCRL = getParametersValue(parameters, INDIRECT_CRL, IssuingDistributionPoint.defaultValues(INDIRECT_CRL));
+ this.onlyContainsAttributeCerts = getParametersValue(parameters, ONLY_CONTAINS_ATTRIBUTE_CERTS, IssuingDistributionPoint.defaultValues(ONLY_CONTAINS_ATTRIBUTE_CERTS));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case DISTRIBUTION_POINT:
+ return [];
+ case ONLY_CONTAINS_USER_CERTS:
+ return false;
+ case ONLY_CONTAINS_CA_CERTS:
+ return false;
+ case ONLY_SOME_REASON:
+ return 0;
+ case INDIRECT_CRL:
+ return false;
+ case ONLY_CONTAINS_ATTRIBUTE_CERTS:
+ return false;
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [
+ new Choice({
+ value: [
+ new Constructed({
+ name: (names.distributionPoint || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [
+ new Repeated({
+ name: (names.distributionPointNames || EMPTY_STRING),
+ value: GeneralName.schema()
+ })
+ ]
+ }),
+ new Constructed({
+ name: (names.distributionPoint || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: RelativeDistinguishedNames.schema().valueBlock.value
+ })
+ ]
+ })
+ ]
+ }),
+ new Primitive({
+ name: (names.onlyContainsUserCerts || EMPTY_STRING),
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ }
+ }),
+ new Primitive({
+ name: (names.onlyContainsCACerts || EMPTY_STRING),
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ }
+ }),
+ new Primitive({
+ name: (names.onlySomeReasons || EMPTY_STRING),
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 3
+ }
+ }),
+ new Primitive({
+ name: (names.indirectCRL || EMPTY_STRING),
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 4
+ }
+ }),
+ new Primitive({
+ name: (names.onlyContainsAttributeCerts || EMPTY_STRING),
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 5
+ }
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$1i);
+ const asn1 = compareSchema(schema, schema, IssuingDistributionPoint.schema({
+ names: {
+ distributionPoint: DISTRIBUTION_POINT,
+ distributionPointNames: DISTRIBUTION_POINT_NAMES,
+ onlyContainsUserCerts: ONLY_CONTAINS_USER_CERTS,
+ onlyContainsCACerts: ONLY_CONTAINS_CA_CERTS,
+ onlySomeReasons: ONLY_SOME_REASON,
+ indirectCRL: INDIRECT_CRL,
+ onlyContainsAttributeCerts: ONLY_CONTAINS_ATTRIBUTE_CERTS
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ if (DISTRIBUTION_POINT in asn1.result) {
+ switch (true) {
+ case (asn1.result.distributionPoint.idBlock.tagNumber === 0):
+ this.distributionPoint = Array.from(asn1.result.distributionPointNames, element => new GeneralName({ schema: element }));
+ break;
+ case (asn1.result.distributionPoint.idBlock.tagNumber === 1):
+ {
+ this.distributionPoint = new RelativeDistinguishedNames({
+ schema: new Sequence({
+ value: asn1.result.distributionPoint.valueBlock.value
+ })
+ });
+ }
+ break;
+ default:
+ throw new Error("Unknown tagNumber for distributionPoint: {$asn1.result.distributionPoint.idBlock.tagNumber}");
+ }
+ }
+ if (ONLY_CONTAINS_USER_CERTS in asn1.result) {
+ const view = new Uint8Array(asn1.result.onlyContainsUserCerts.valueBlock.valueHex);
+ this.onlyContainsUserCerts = (view[0] !== 0x00);
+ }
+ if (ONLY_CONTAINS_CA_CERTS in asn1.result) {
+ const view = new Uint8Array(asn1.result.onlyContainsCACerts.valueBlock.valueHex);
+ this.onlyContainsCACerts = (view[0] !== 0x00);
+ }
+ if (ONLY_SOME_REASON in asn1.result) {
+ const view = new Uint8Array(asn1.result.onlySomeReasons.valueBlock.valueHex);
+ this.onlySomeReasons = view[0];
+ }
+ if (INDIRECT_CRL in asn1.result) {
+ const view = new Uint8Array(asn1.result.indirectCRL.valueBlock.valueHex);
+ this.indirectCRL = (view[0] !== 0x00);
+ }
+ if (ONLY_CONTAINS_ATTRIBUTE_CERTS in asn1.result) {
+ const view = new Uint8Array(asn1.result.onlyContainsAttributeCerts.valueBlock.valueHex);
+ this.onlyContainsAttributeCerts = (view[0] !== 0x00);
+ }
+ }
+ toSchema() {
+ const outputArray = [];
+ if (this.distributionPoint) {
+ let value;
+ if (this.distributionPoint instanceof Array) {
+ value = new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: Array.from(this.distributionPoint, o => o.toSchema())
+ });
+ }
+ else {
+ value = this.distributionPoint.toSchema();
+ value.idBlock.tagClass = 3;
+ value.idBlock.tagNumber = 1;
+ }
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [value]
+ }));
+ }
+ if (this.onlyContainsUserCerts !== IssuingDistributionPoint.defaultValues(ONLY_CONTAINS_USER_CERTS)) {
+ outputArray.push(new Primitive({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ valueHex: (new Uint8Array([0xFF])).buffer
+ }));
+ }
+ if (this.onlyContainsCACerts !== IssuingDistributionPoint.defaultValues(ONLY_CONTAINS_CA_CERTS)) {
+ outputArray.push(new Primitive({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ },
+ valueHex: (new Uint8Array([0xFF])).buffer
+ }));
+ }
+ if (this.onlySomeReasons !== undefined) {
+ const buffer = new ArrayBuffer(1);
+ const view = new Uint8Array(buffer);
+ view[0] = this.onlySomeReasons;
+ outputArray.push(new Primitive({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 3
+ },
+ valueHex: buffer
+ }));
+ }
+ if (this.indirectCRL !== IssuingDistributionPoint.defaultValues(INDIRECT_CRL)) {
+ outputArray.push(new Primitive({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 4
+ },
+ valueHex: (new Uint8Array([0xFF])).buffer
+ }));
+ }
+ if (this.onlyContainsAttributeCerts !== IssuingDistributionPoint.defaultValues(ONLY_CONTAINS_ATTRIBUTE_CERTS)) {
+ outputArray.push(new Primitive({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 5
+ },
+ valueHex: (new Uint8Array([0xFF])).buffer
+ }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const obj = {};
+ if (this.distributionPoint) {
+ if (this.distributionPoint instanceof Array) {
+ obj.distributionPoint = Array.from(this.distributionPoint, o => o.toJSON());
+ }
+ else {
+ obj.distributionPoint = this.distributionPoint.toJSON();
+ }
+ }
+ if (this.onlyContainsUserCerts !== IssuingDistributionPoint.defaultValues(ONLY_CONTAINS_USER_CERTS)) {
+ obj.onlyContainsUserCerts = this.onlyContainsUserCerts;
+ }
+ if (this.onlyContainsCACerts !== IssuingDistributionPoint.defaultValues(ONLY_CONTAINS_CA_CERTS)) {
+ obj.onlyContainsCACerts = this.onlyContainsCACerts;
+ }
+ if (ONLY_SOME_REASON in this) {
+ obj.onlySomeReasons = this.onlySomeReasons;
+ }
+ if (this.indirectCRL !== IssuingDistributionPoint.defaultValues(INDIRECT_CRL)) {
+ obj.indirectCRL = this.indirectCRL;
+ }
+ if (this.onlyContainsAttributeCerts !== IssuingDistributionPoint.defaultValues(ONLY_CONTAINS_ATTRIBUTE_CERTS)) {
+ obj.onlyContainsAttributeCerts = this.onlyContainsAttributeCerts;
+ }
+ return obj;
+ }
+}
+IssuingDistributionPoint.CLASS_NAME = "IssuingDistributionPoint";
+
+const BASE = "base";
+const MINIMUM = "minimum";
+const MAXIMUM = "maximum";
+const CLEAR_PROPS$1h = [
+ BASE,
+ MINIMUM,
+ MAXIMUM
+];
+class GeneralSubtree extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.base = getParametersValue(parameters, BASE, GeneralSubtree.defaultValues(BASE));
+ this.minimum = getParametersValue(parameters, MINIMUM, GeneralSubtree.defaultValues(MINIMUM));
+ if (MAXIMUM in parameters) {
+ this.maximum = getParametersValue(parameters, MAXIMUM, GeneralSubtree.defaultValues(MAXIMUM));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case BASE:
+ return new GeneralName();
+ case MINIMUM:
+ return 0;
+ case MAXIMUM:
+ return 0;
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ GeneralName.schema(names.base || {}),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [new Integer({ name: (names.minimum || EMPTY_STRING) })]
+ }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: [new Integer({ name: (names.maximum || EMPTY_STRING) })]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$1h);
+ const asn1 = compareSchema(schema, schema, GeneralSubtree.schema({
+ names: {
+ base: {
+ names: {
+ blockName: BASE
+ }
+ },
+ minimum: MINIMUM,
+ maximum: MAXIMUM
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.base = new GeneralName({ schema: asn1.result.base });
+ if (MINIMUM in asn1.result) {
+ if (asn1.result.minimum.valueBlock.isHexOnly)
+ this.minimum = asn1.result.minimum;
+ else
+ this.minimum = asn1.result.minimum.valueBlock.valueDec;
+ }
+ if (MAXIMUM in asn1.result) {
+ if (asn1.result.maximum.valueBlock.isHexOnly)
+ this.maximum = asn1.result.maximum;
+ else
+ this.maximum = asn1.result.maximum.valueBlock.valueDec;
+ }
+ }
+ toSchema() {
+ const outputArray = [];
+ outputArray.push(this.base.toSchema());
+ if (this.minimum !== 0) {
+ let valueMinimum = 0;
+ if (this.minimum instanceof Integer) {
+ valueMinimum = this.minimum;
+ }
+ else {
+ valueMinimum = new Integer({ value: this.minimum });
+ }
+ outputArray.push(new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [valueMinimum]
+ }));
+ }
+ if (MAXIMUM in this) {
+ let valueMaximum = 0;
+ if (this.maximum instanceof Integer) {
+ valueMaximum = this.maximum;
+ }
+ else {
+ valueMaximum = new Integer({ value: this.maximum });
+ }
+ outputArray.push(new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: [valueMaximum]
+ }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {
+ base: this.base.toJSON()
+ };
+ if (this.minimum !== 0) {
+ if (typeof this.minimum === "number") {
+ res.minimum = this.minimum;
+ }
+ else {
+ res.minimum = this.minimum.toJSON();
+ }
+ }
+ if (this.maximum !== undefined) {
+ if (typeof this.maximum === "number") {
+ res.maximum = this.maximum;
+ }
+ else {
+ res.maximum = this.maximum.toJSON();
+ }
+ }
+ return res;
+ }
+}
+GeneralSubtree.CLASS_NAME = "GeneralSubtree";
+
+const PERMITTED_SUBTREES = "permittedSubtrees";
+const EXCLUDED_SUBTREES = "excludedSubtrees";
+const CLEAR_PROPS$1g = [
+ PERMITTED_SUBTREES,
+ EXCLUDED_SUBTREES
+];
+class NameConstraints extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ if (PERMITTED_SUBTREES in parameters) {
+ this.permittedSubtrees = getParametersValue(parameters, PERMITTED_SUBTREES, NameConstraints.defaultValues(PERMITTED_SUBTREES));
+ }
+ if (EXCLUDED_SUBTREES in parameters) {
+ this.excludedSubtrees = getParametersValue(parameters, EXCLUDED_SUBTREES, NameConstraints.defaultValues(EXCLUDED_SUBTREES));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case PERMITTED_SUBTREES:
+ case EXCLUDED_SUBTREES:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [
+ new Repeated({
+ name: (names.permittedSubtrees || EMPTY_STRING),
+ value: GeneralSubtree.schema()
+ })
+ ]
+ }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: [
+ new Repeated({
+ name: (names.excludedSubtrees || EMPTY_STRING),
+ value: GeneralSubtree.schema()
+ })
+ ]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$1g);
+ const asn1 = compareSchema(schema, schema, NameConstraints.schema({
+ names: {
+ permittedSubtrees: PERMITTED_SUBTREES,
+ excludedSubtrees: EXCLUDED_SUBTREES
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ if (PERMITTED_SUBTREES in asn1.result)
+ this.permittedSubtrees = Array.from(asn1.result.permittedSubtrees, element => new GeneralSubtree({ schema: element }));
+ if (EXCLUDED_SUBTREES in asn1.result)
+ this.excludedSubtrees = Array.from(asn1.result.excludedSubtrees, element => new GeneralSubtree({ schema: element }));
+ }
+ toSchema() {
+ const outputArray = [];
+ if (this.permittedSubtrees) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: Array.from(this.permittedSubtrees, o => o.toSchema())
+ }));
+ }
+ if (this.excludedSubtrees) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: Array.from(this.excludedSubtrees, o => o.toSchema())
+ }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const object = {};
+ if (this.permittedSubtrees) {
+ object.permittedSubtrees = Array.from(this.permittedSubtrees, o => o.toJSON());
+ }
+ if (this.excludedSubtrees) {
+ object.excludedSubtrees = Array.from(this.excludedSubtrees, o => o.toJSON());
+ }
+ return object;
+ }
+}
+NameConstraints.CLASS_NAME = "NameConstraints";
+
+const REQUIRE_EXPLICIT_POLICY = "requireExplicitPolicy";
+const INHIBIT_POLICY_MAPPING = "inhibitPolicyMapping";
+const CLEAR_PROPS$1f = [
+ REQUIRE_EXPLICIT_POLICY,
+ INHIBIT_POLICY_MAPPING,
+];
+class PolicyConstraints extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ if (REQUIRE_EXPLICIT_POLICY in parameters) {
+ this.requireExplicitPolicy = getParametersValue(parameters, REQUIRE_EXPLICIT_POLICY, PolicyConstraints.defaultValues(REQUIRE_EXPLICIT_POLICY));
+ }
+ if (INHIBIT_POLICY_MAPPING in parameters) {
+ this.inhibitPolicyMapping = getParametersValue(parameters, INHIBIT_POLICY_MAPPING, PolicyConstraints.defaultValues(INHIBIT_POLICY_MAPPING));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case REQUIRE_EXPLICIT_POLICY:
+ return 0;
+ case INHIBIT_POLICY_MAPPING:
+ return 0;
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Primitive({
+ name: (names.requireExplicitPolicy || EMPTY_STRING),
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ }
+ }),
+ new Primitive({
+ name: (names.inhibitPolicyMapping || EMPTY_STRING),
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ }
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$1f);
+ const asn1 = compareSchema(schema, schema, PolicyConstraints.schema({
+ names: {
+ requireExplicitPolicy: REQUIRE_EXPLICIT_POLICY,
+ inhibitPolicyMapping: INHIBIT_POLICY_MAPPING
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ if (REQUIRE_EXPLICIT_POLICY in asn1.result) {
+ const field1 = asn1.result.requireExplicitPolicy;
+ field1.idBlock.tagClass = 1;
+ field1.idBlock.tagNumber = 2;
+ const ber1 = field1.toBER(false);
+ const int1 = fromBER(ber1);
+ AsnError.assert(int1, "Integer");
+ this.requireExplicitPolicy = int1.result.valueBlock.valueDec;
+ }
+ if (INHIBIT_POLICY_MAPPING in asn1.result) {
+ const field2 = asn1.result.inhibitPolicyMapping;
+ field2.idBlock.tagClass = 1;
+ field2.idBlock.tagNumber = 2;
+ const ber2 = field2.toBER(false);
+ const int2 = fromBER(ber2);
+ AsnError.assert(int2, "Integer");
+ this.inhibitPolicyMapping = int2.result.valueBlock.valueDec;
+ }
+ }
+ toSchema() {
+ const outputArray = [];
+ if (REQUIRE_EXPLICIT_POLICY in this) {
+ const int1 = new Integer({ value: this.requireExplicitPolicy });
+ int1.idBlock.tagClass = 3;
+ int1.idBlock.tagNumber = 0;
+ outputArray.push(int1);
+ }
+ if (INHIBIT_POLICY_MAPPING in this) {
+ const int2 = new Integer({ value: this.inhibitPolicyMapping });
+ int2.idBlock.tagClass = 3;
+ int2.idBlock.tagNumber = 1;
+ outputArray.push(int2);
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {};
+ if (REQUIRE_EXPLICIT_POLICY in this) {
+ res.requireExplicitPolicy = this.requireExplicitPolicy;
+ }
+ if (INHIBIT_POLICY_MAPPING in this) {
+ res.inhibitPolicyMapping = this.inhibitPolicyMapping;
+ }
+ return res;
+ }
+}
+PolicyConstraints.CLASS_NAME = "PolicyConstraints";
+
+const ISSUER_DOMAIN_POLICY = "issuerDomainPolicy";
+const SUBJECT_DOMAIN_POLICY = "subjectDomainPolicy";
+const CLEAR_PROPS$1e = [
+ ISSUER_DOMAIN_POLICY,
+ SUBJECT_DOMAIN_POLICY
+];
+class PolicyMapping extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.issuerDomainPolicy = getParametersValue(parameters, ISSUER_DOMAIN_POLICY, PolicyMapping.defaultValues(ISSUER_DOMAIN_POLICY));
+ this.subjectDomainPolicy = getParametersValue(parameters, SUBJECT_DOMAIN_POLICY, PolicyMapping.defaultValues(SUBJECT_DOMAIN_POLICY));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case ISSUER_DOMAIN_POLICY:
+ return EMPTY_STRING;
+ case SUBJECT_DOMAIN_POLICY:
+ return EMPTY_STRING;
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new ObjectIdentifier({ name: (names.issuerDomainPolicy || EMPTY_STRING) }),
+ new ObjectIdentifier({ name: (names.subjectDomainPolicy || EMPTY_STRING) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$1e);
+ const asn1 = compareSchema(schema, schema, PolicyMapping.schema({
+ names: {
+ issuerDomainPolicy: ISSUER_DOMAIN_POLICY,
+ subjectDomainPolicy: SUBJECT_DOMAIN_POLICY
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.issuerDomainPolicy = asn1.result.issuerDomainPolicy.valueBlock.toString();
+ this.subjectDomainPolicy = asn1.result.subjectDomainPolicy.valueBlock.toString();
+ }
+ toSchema() {
+ return (new Sequence({
+ value: [
+ new ObjectIdentifier({ value: this.issuerDomainPolicy }),
+ new ObjectIdentifier({ value: this.subjectDomainPolicy })
+ ]
+ }));
+ }
+ toJSON() {
+ return {
+ issuerDomainPolicy: this.issuerDomainPolicy,
+ subjectDomainPolicy: this.subjectDomainPolicy
+ };
+ }
+}
+PolicyMapping.CLASS_NAME = "PolicyMapping";
+
+const MAPPINGS = "mappings";
+const CLEAR_PROPS$1d = [
+ MAPPINGS,
+];
+class PolicyMappings extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.mappings = getParametersValue(parameters, MAPPINGS, PolicyMappings.defaultValues(MAPPINGS));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case MAPPINGS:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Repeated({
+ name: (names.mappings || EMPTY_STRING),
+ value: PolicyMapping.schema()
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$1d);
+ const asn1 = compareSchema(schema, schema, PolicyMappings.schema({
+ names: {
+ mappings: MAPPINGS
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.mappings = Array.from(asn1.result.mappings, element => new PolicyMapping({ schema: element }));
+ }
+ toSchema() {
+ return (new Sequence({
+ value: Array.from(this.mappings, o => o.toSchema())
+ }));
+ }
+ toJSON() {
+ return {
+ mappings: Array.from(this.mappings, o => o.toJSON())
+ };
+ }
+}
+PolicyMappings.CLASS_NAME = "PolicyMappings";
+
+const NOT_BEFORE$1 = "notBefore";
+const NOT_AFTER$1 = "notAfter";
+const CLEAR_PROPS$1c = [
+ NOT_BEFORE$1,
+ NOT_AFTER$1
+];
+class PrivateKeyUsagePeriod extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ if (NOT_BEFORE$1 in parameters) {
+ this.notBefore = getParametersValue(parameters, NOT_BEFORE$1, PrivateKeyUsagePeriod.defaultValues(NOT_BEFORE$1));
+ }
+ if (NOT_AFTER$1 in parameters) {
+ this.notAfter = getParametersValue(parameters, NOT_AFTER$1, PrivateKeyUsagePeriod.defaultValues(NOT_AFTER$1));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case NOT_BEFORE$1:
+ return new Date();
+ case NOT_AFTER$1:
+ return new Date();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Primitive({
+ name: (names.notBefore || EMPTY_STRING),
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ }
+ }),
+ new Primitive({
+ name: (names.notAfter || EMPTY_STRING),
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ }
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$1c);
+ const asn1 = compareSchema(schema, schema, PrivateKeyUsagePeriod.schema({
+ names: {
+ notBefore: NOT_BEFORE$1,
+ notAfter: NOT_AFTER$1
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ if (NOT_BEFORE$1 in asn1.result) {
+ const localNotBefore = new GeneralizedTime();
+ localNotBefore.fromBuffer(asn1.result.notBefore.valueBlock.valueHex);
+ this.notBefore = localNotBefore.toDate();
+ }
+ if (NOT_AFTER$1 in asn1.result) {
+ const localNotAfter = new GeneralizedTime({ valueHex: asn1.result.notAfter.valueBlock.valueHex });
+ localNotAfter.fromBuffer(asn1.result.notAfter.valueBlock.valueHex);
+ this.notAfter = localNotAfter.toDate();
+ }
+ }
+ toSchema() {
+ const outputArray = [];
+ if (NOT_BEFORE$1 in this) {
+ outputArray.push(new Primitive({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ valueHex: (new GeneralizedTime({ valueDate: this.notBefore })).valueBlock.valueHexView
+ }));
+ }
+ if (NOT_AFTER$1 in this) {
+ outputArray.push(new Primitive({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ valueHex: (new GeneralizedTime({ valueDate: this.notAfter })).valueBlock.valueHexView
+ }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {};
+ if (this.notBefore) {
+ res.notBefore = this.notBefore;
+ }
+ if (this.notAfter) {
+ res.notAfter = this.notAfter;
+ }
+ return res;
+ }
+}
+PrivateKeyUsagePeriod.CLASS_NAME = "PrivateKeyUsagePeriod";
+
+const ID = "id";
+const TYPE$2 = "type";
+const VALUES = "values";
+const QC_STATEMENT_CLEAR_PROPS = [
+ ID,
+ TYPE$2
+];
+const QC_STATEMENTS_CLEAR_PROPS = [
+ VALUES
+];
+class QCStatement extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.id = getParametersValue(parameters, ID, QCStatement.defaultValues(ID));
+ if (TYPE$2 in parameters) {
+ this.type = getParametersValue(parameters, TYPE$2, QCStatement.defaultValues(TYPE$2));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case ID:
+ return EMPTY_STRING;
+ case TYPE$2:
+ return new Null();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case ID:
+ return (memberValue === EMPTY_STRING);
+ case TYPE$2:
+ return (memberValue instanceof Null);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new ObjectIdentifier({ name: (names.id || EMPTY_STRING) }),
+ new Any({
+ name: (names.type || EMPTY_STRING),
+ optional: true
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, QC_STATEMENT_CLEAR_PROPS);
+ const asn1 = compareSchema(schema, schema, QCStatement.schema({
+ names: {
+ id: ID,
+ type: TYPE$2
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.id = asn1.result.id.valueBlock.toString();
+ if (TYPE$2 in asn1.result)
+ this.type = asn1.result.type;
+ }
+ toSchema() {
+ const value = [
+ new ObjectIdentifier({ value: this.id })
+ ];
+ if (TYPE$2 in this)
+ value.push(this.type);
+ return (new Sequence({
+ value,
+ }));
+ }
+ toJSON() {
+ const object = {
+ id: this.id
+ };
+ if (this.type) {
+ object.type = this.type.toJSON();
+ }
+ return object;
+ }
+}
+QCStatement.CLASS_NAME = "QCStatement";
+class QCStatements extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.values = getParametersValue(parameters, VALUES, QCStatements.defaultValues(VALUES));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case VALUES:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case VALUES:
+ return (memberValue.length === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Repeated({
+ name: (names.values || EMPTY_STRING),
+ value: QCStatement.schema(names.value || {})
+ }),
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, QC_STATEMENTS_CLEAR_PROPS);
+ const asn1 = compareSchema(schema, schema, QCStatements.schema({
+ names: {
+ values: VALUES
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.values = Array.from(asn1.result.values, element => new QCStatement({ schema: element }));
+ }
+ toSchema() {
+ return (new Sequence({
+ value: Array.from(this.values, o => o.toSchema())
+ }));
+ }
+ toJSON() {
+ return {
+ values: Array.from(this.values, o => o.toJSON())
+ };
+ }
+}
+QCStatements.CLASS_NAME = "QCStatements";
+
+class ByteStream {
+ constructor(parameters = {}) {
+ if ("view" in parameters) {
+ this.fromUint8Array(parameters.view);
+ }
+ else if ("buffer" in parameters) {
+ this.fromArrayBuffer(parameters.buffer);
+ }
+ else if ("string" in parameters) {
+ this.fromString(parameters.string);
+ }
+ else if ("hexstring" in parameters) {
+ this.fromHexString(parameters.hexstring);
+ }
+ else {
+ if ("length" in parameters && parameters.length > 0) {
+ this.length = parameters.length;
+ if (parameters.stub) {
+ for (let i = 0; i < this._view.length; i++) {
+ this._view[i] = parameters.stub;
+ }
+ }
+ }
+ else {
+ this.length = 0;
+ }
+ }
+ }
+ set buffer(value) {
+ this._buffer = value;
+ this._view = new Uint8Array(this._buffer);
+ }
+ get buffer() {
+ return this._buffer;
+ }
+ set view(value) {
+ this._buffer = new ArrayBuffer(value.length);
+ this._view = new Uint8Array(this._buffer);
+ this._view.set(value);
+ }
+ get view() {
+ return this._view;
+ }
+ get length() {
+ return this.view.byteLength;
+ }
+ set length(value) {
+ this._buffer = new ArrayBuffer(value);
+ this._view = new Uint8Array(this._buffer);
+ }
+ clear() {
+ this._buffer = new ArrayBuffer(0);
+ this._view = new Uint8Array(this._buffer);
+ }
+ fromArrayBuffer(array) {
+ this._buffer = array;
+ this._view = new Uint8Array(this._buffer);
+ }
+ fromUint8Array(array) {
+ this.fromArrayBuffer(new Uint8Array(array).buffer);
+ }
+ fromString(string) {
+ const stringLength = string.length;
+ this.length = stringLength;
+ for (let i = 0; i < stringLength; i++)
+ this.view[i] = string.charCodeAt(i);
+ }
+ toString(start = 0, length = (this.view.length - start)) {
+ let result = "";
+ if ((start >= this.view.length) || (start < 0)) {
+ start = 0;
+ }
+ if ((length >= this.view.length) || (length < 0)) {
+ length = this.view.length - start;
+ }
+ for (let i = start; i < (start + length); i++)
+ result += String.fromCharCode(this.view[i]);
+ return result;
+ }
+ fromHexString(hexString) {
+ const stringLength = hexString.length;
+ this.buffer = new ArrayBuffer(stringLength >> 1);
+ this.view = new Uint8Array(this.buffer);
+ const hexMap = new Map();
+ hexMap.set("0", 0x00);
+ hexMap.set("1", 0x01);
+ hexMap.set("2", 0x02);
+ hexMap.set("3", 0x03);
+ hexMap.set("4", 0x04);
+ hexMap.set("5", 0x05);
+ hexMap.set("6", 0x06);
+ hexMap.set("7", 0x07);
+ hexMap.set("8", 0x08);
+ hexMap.set("9", 0x09);
+ hexMap.set("A", 0x0A);
+ hexMap.set("a", 0x0A);
+ hexMap.set("B", 0x0B);
+ hexMap.set("b", 0x0B);
+ hexMap.set("C", 0x0C);
+ hexMap.set("c", 0x0C);
+ hexMap.set("D", 0x0D);
+ hexMap.set("d", 0x0D);
+ hexMap.set("E", 0x0E);
+ hexMap.set("e", 0x0E);
+ hexMap.set("F", 0x0F);
+ hexMap.set("f", 0x0F);
+ let j = 0;
+ let temp = 0x00;
+ for (let i = 0; i < stringLength; i++) {
+ if (!(i % 2)) {
+ temp = hexMap.get(hexString.charAt(i)) << 4;
+ }
+ else {
+ temp |= hexMap.get(hexString.charAt(i));
+ this.view[j] = temp;
+ j++;
+ }
+ }
+ }
+ toHexString(start = 0, length = (this.view.length - start)) {
+ let result = "";
+ if ((start >= this.view.length) || (start < 0)) {
+ start = 0;
+ }
+ if ((length >= this.view.length) || (length < 0)) {
+ length = this.view.length - start;
+ }
+ for (let i = start; i < (start + length); i++) {
+ const str = this.view[i].toString(16).toUpperCase();
+ result = result + ((str.length == 1) ? "0" : "") + str;
+ }
+ return result;
+ }
+ copy(start = 0, length = (this.length - start)) {
+ if (!start && !this.length) {
+ return new ByteStream();
+ }
+ if ((start < 0) || (start > (this.length - 1))) {
+ throw new Error(`Wrong start position: ${start}`);
+ }
+ const stream = new ByteStream({
+ buffer: this._buffer.slice(start, start + length)
+ });
+ return stream;
+ }
+ slice(start = 0, end = this.length) {
+ if (!start && !this.length) {
+ return new ByteStream();
+ }
+ if ((start < 0) || (start > (this.length - 1))) {
+ throw new Error(`Wrong start position: ${start}`);
+ }
+ const stream = new ByteStream({
+ buffer: this._buffer.slice(start, end),
+ });
+ return stream;
+ }
+ realloc(size) {
+ const buffer = new ArrayBuffer(size);
+ const view = new Uint8Array(buffer);
+ if (size > this._view.length)
+ view.set(this._view);
+ else {
+ view.set(new Uint8Array(this._buffer, 0, size));
+ }
+ this._buffer = buffer;
+ this._view = new Uint8Array(this._buffer);
+ }
+ append(stream) {
+ const initialSize = this.length;
+ const streamViewLength = stream.length;
+ const subarrayView = stream._view.subarray();
+ this.realloc(initialSize + streamViewLength);
+ this._view.set(subarrayView, initialSize);
+ }
+ insert(stream, start = 0, length = (this.length - start)) {
+ if (start > (this.length - 1))
+ return false;
+ if (length > (this.length - start)) {
+ length = this.length - start;
+ }
+ if (length > stream.length) {
+ length = stream.length;
+ }
+ if (length == stream.length)
+ this._view.set(stream._view, start);
+ else {
+ this._view.set(stream._view.subarray(0, length), start);
+ }
+ return true;
+ }
+ isEqual(stream) {
+ if (this.length != stream.length)
+ return false;
+ for (let i = 0; i < stream.length; i++) {
+ if (this.view[i] != stream.view[i])
+ return false;
+ }
+ return true;
+ }
+ isEqualView(view) {
+ if (view.length != this.view.length)
+ return false;
+ for (let i = 0; i < view.length; i++) {
+ if (this.view[i] != view[i])
+ return false;
+ }
+ return true;
+ }
+ findPattern(pattern, start_, length_, backward_) {
+ const { start, length, backward } = this.prepareFindParameters(start_, length_, backward_);
+ const patternLength = pattern.length;
+ if (patternLength > length) {
+ return (-1);
+ }
+ const patternArray = [];
+ for (let i = 0; i < patternLength; i++)
+ patternArray.push(pattern.view[i]);
+ for (let i = 0; i <= (length - patternLength); i++) {
+ let equal = true;
+ const equalStart = (backward) ? (start - patternLength - i) : (start + i);
+ for (let j = 0; j < patternLength; j++) {
+ if (this.view[j + equalStart] != patternArray[j]) {
+ equal = false;
+ break;
+ }
+ }
+ if (equal) {
+ return (backward) ? (start - patternLength - i) : (start + patternLength + i);
+ }
+ }
+ return (-1);
+ }
+ findFirstIn(patterns, start_, length_, backward_) {
+ const { start, length, backward } = this.prepareFindParameters(start_, length_, backward_);
+ const result = {
+ id: (-1),
+ position: (backward) ? 0 : (start + length),
+ length: 0
+ };
+ for (let i = 0; i < patterns.length; i++) {
+ const position = this.findPattern(patterns[i], start, length, backward);
+ if (position != (-1)) {
+ let valid = false;
+ const patternLength = patterns[i].length;
+ if (backward) {
+ if ((position - patternLength) >= (result.position - result.length))
+ valid = true;
+ }
+ else {
+ if ((position - patternLength) <= (result.position - result.length))
+ valid = true;
+ }
+ if (valid) {
+ result.position = position;
+ result.id = i;
+ result.length = patternLength;
+ }
+ }
+ }
+ return result;
+ }
+ findAllIn(patterns, start_, length_) {
+ let { start, length } = this.prepareFindParameters(start_, length_);
+ const result = [];
+ let patternFound = {
+ id: (-1),
+ position: start
+ };
+ do {
+ const position = patternFound.position;
+ patternFound = this.findFirstIn(patterns, patternFound.position, length);
+ if (patternFound.id == (-1)) {
+ break;
+ }
+ length -= (patternFound.position - position);
+ result.push({
+ id: patternFound.id,
+ position: patternFound.position
+ });
+ } while (true);
+ return result;
+ }
+ findAllPatternIn(pattern, start_, length_) {
+ const { start, length } = this.prepareFindParameters(start_, length_);
+ const result = [];
+ const patternLength = pattern.length;
+ if (patternLength > length) {
+ return (-1);
+ }
+ const patternArray = Array.from(pattern.view);
+ for (let i = 0; i <= (length - patternLength); i++) {
+ let equal = true;
+ const equalStart = start + i;
+ for (let j = 0; j < patternLength; j++) {
+ if (this.view[j + equalStart] != patternArray[j]) {
+ equal = false;
+ break;
+ }
+ }
+ if (equal) {
+ result.push(start + patternLength + i);
+ i += (patternLength - 1);
+ }
+ }
+ return result;
+ }
+ findFirstNotIn(patterns, start_, length_, backward_) {
+ let { start, length, backward } = this.prepareFindParameters(start_, length_, backward_);
+ const result = {
+ left: {
+ id: (-1),
+ position: start
+ },
+ right: {
+ id: (-1),
+ position: 0
+ },
+ value: new ByteStream()
+ };
+ let currentLength = length;
+ while (currentLength > 0) {
+ result.right = this.findFirstIn(patterns, (backward) ? (start - length + currentLength) : (start + length - currentLength), currentLength, backward);
+ if (result.right.id == (-1)) {
+ length = currentLength;
+ if (backward) {
+ start -= length;
+ }
+ else {
+ start = result.left.position;
+ }
+ result.value = new ByteStream({
+ buffer: this._buffer.slice(start, start + length),
+ });
+ break;
+ }
+ if (result.right.position != ((backward) ? (result.left.position - patterns[result.right.id].length) : (result.left.position + patterns[result.right.id].length))) {
+ if (backward) {
+ start = result.right.position + patterns[result.right.id].length;
+ length = result.left.position - result.right.position - patterns[result.right.id].length;
+ }
+ else {
+ start = result.left.position;
+ length = result.right.position - result.left.position - patterns[result.right.id].length;
+ }
+ result.value = new ByteStream({
+ buffer: this._buffer.slice(start, start + length),
+ });
+ break;
+ }
+ result.left = result.right;
+ currentLength -= patterns[result.right.id].length;
+ }
+ if (backward) {
+ const temp = result.right;
+ result.right = result.left;
+ result.left = temp;
+ }
+ return result;
+ }
+ findAllNotIn(patterns, start_, length_) {
+ let { start, length } = this.prepareFindParameters(start_, length_);
+ const result = [];
+ let patternFound = {
+ left: {
+ id: (-1),
+ position: start
+ },
+ right: {
+ id: (-1),
+ position: start
+ },
+ value: new ByteStream()
+ };
+ do {
+ const position = patternFound.right.position;
+ patternFound = this.findFirstNotIn(patterns, patternFound.right.position, length);
+ length -= (patternFound.right.position - position);
+ result.push({
+ left: {
+ id: patternFound.left.id,
+ position: patternFound.left.position
+ },
+ right: {
+ id: patternFound.right.id,
+ position: patternFound.right.position
+ },
+ value: patternFound.value
+ });
+ } while (patternFound.right.id != (-1));
+ return result;
+ }
+ findFirstSequence(patterns, start_, length_, backward_) {
+ let { start, length, backward } = this.prepareFindParameters(start_, length_, backward_);
+ const firstIn = this.skipNotPatterns(patterns, start, length, backward);
+ if (firstIn == (-1)) {
+ return {
+ position: (-1),
+ value: new ByteStream()
+ };
+ }
+ const firstNotIn = this.skipPatterns(patterns, firstIn, length - ((backward) ? (start - firstIn) : (firstIn - start)), backward);
+ if (backward) {
+ start = firstNotIn;
+ length = (firstIn - firstNotIn);
+ }
+ else {
+ start = firstIn;
+ length = (firstNotIn - firstIn);
+ }
+ const value = new ByteStream({
+ buffer: this._buffer.slice(start, start + length),
+ });
+ return {
+ position: firstNotIn,
+ value
+ };
+ }
+ findAllSequences(patterns, start_, length_) {
+ let { start, length } = this.prepareFindParameters(start_, length_);
+ const result = [];
+ let patternFound = {
+ position: start,
+ value: new ByteStream()
+ };
+ do {
+ const position = patternFound.position;
+ patternFound = this.findFirstSequence(patterns, patternFound.position, length);
+ if (patternFound.position != (-1)) {
+ length -= (patternFound.position - position);
+ result.push({
+ position: patternFound.position,
+ value: patternFound.value,
+ });
+ }
+ } while (patternFound.position != (-1));
+ return result;
+ }
+ findPairedPatterns(leftPattern, rightPattern, start_, length_) {
+ const result = [];
+ if (leftPattern.isEqual(rightPattern))
+ return result;
+ const { start, length } = this.prepareFindParameters(start_, length_);
+ let currentPositionLeft = 0;
+ const leftPatterns = this.findAllPatternIn(leftPattern, start, length);
+ if (!Array.isArray(leftPatterns) || leftPatterns.length == 0) {
+ return result;
+ }
+ const rightPatterns = this.findAllPatternIn(rightPattern, start, length);
+ if (!Array.isArray(rightPatterns) || rightPatterns.length == 0) {
+ return result;
+ }
+ while (currentPositionLeft < leftPatterns.length) {
+ if (rightPatterns.length == 0) {
+ break;
+ }
+ if (leftPatterns[0] == rightPatterns[0]) {
+ result.push({
+ left: leftPatterns[0],
+ right: rightPatterns[0]
+ });
+ leftPatterns.splice(0, 1);
+ rightPatterns.splice(0, 1);
+ continue;
+ }
+ if (leftPatterns[currentPositionLeft] > rightPatterns[0]) {
+ break;
+ }
+ while (leftPatterns[currentPositionLeft] < rightPatterns[0]) {
+ currentPositionLeft++;
+ if (currentPositionLeft >= leftPatterns.length) {
+ break;
+ }
+ }
+ result.push({
+ left: leftPatterns[currentPositionLeft - 1],
+ right: rightPatterns[0]
+ });
+ leftPatterns.splice(currentPositionLeft - 1, 1);
+ rightPatterns.splice(0, 1);
+ currentPositionLeft = 0;
+ }
+ result.sort((a, b) => (a.left - b.left));
+ return result;
+ }
+ findPairedArrays(inputLeftPatterns, inputRightPatterns, start_, length_) {
+ const { start, length } = this.prepareFindParameters(start_, length_);
+ const result = [];
+ let currentPositionLeft = 0;
+ const leftPatterns = this.findAllIn(inputLeftPatterns, start, length);
+ if (leftPatterns.length == 0)
+ return result;
+ const rightPatterns = this.findAllIn(inputRightPatterns, start, length);
+ if (rightPatterns.length == 0)
+ return result;
+ while (currentPositionLeft < leftPatterns.length) {
+ if (rightPatterns.length == 0) {
+ break;
+ }
+ if (leftPatterns[0].position == rightPatterns[0].position) {
+ result.push({
+ left: leftPatterns[0],
+ right: rightPatterns[0]
+ });
+ leftPatterns.splice(0, 1);
+ rightPatterns.splice(0, 1);
+ continue;
+ }
+ if (leftPatterns[currentPositionLeft].position > rightPatterns[0].position) {
+ break;
+ }
+ while (leftPatterns[currentPositionLeft].position < rightPatterns[0].position) {
+ currentPositionLeft++;
+ if (currentPositionLeft >= leftPatterns.length) {
+ break;
+ }
+ }
+ result.push({
+ left: leftPatterns[currentPositionLeft - 1],
+ right: rightPatterns[0]
+ });
+ leftPatterns.splice(currentPositionLeft - 1, 1);
+ rightPatterns.splice(0, 1);
+ currentPositionLeft = 0;
+ }
+ result.sort((a, b) => (a.left.position - b.left.position));
+ return result;
+ }
+ replacePattern(searchPattern, replacePattern, start_, length_, findAllResult = null) {
+ let result = [];
+ let i;
+ const output = {
+ status: (-1),
+ searchPatternPositions: [],
+ replacePatternPositions: []
+ };
+ const { start, length } = this.prepareFindParameters(start_, length_);
+ if (findAllResult == null) {
+ result = this.findAllIn([searchPattern], start, length);
+ if (result.length == 0) {
+ return output;
+ }
+ }
+ else {
+ result = findAllResult;
+ }
+ output.searchPatternPositions.push(...Array.from(result, element => element.position));
+ const patternDifference = searchPattern.length - replacePattern.length;
+ const changedBuffer = new ArrayBuffer(this.view.length - (result.length * patternDifference));
+ const changedView = new Uint8Array(changedBuffer);
+ changedView.set(new Uint8Array(this.buffer, 0, start));
+ for (i = 0; i < result.length; i++) {
+ const currentPosition = (i == 0) ? start : result[i - 1].position;
+ changedView.set(new Uint8Array(this.buffer, currentPosition, result[i].position - searchPattern.length - currentPosition), currentPosition - i * patternDifference);
+ changedView.set(replacePattern.view, result[i].position - searchPattern.length - i * patternDifference);
+ output.replacePatternPositions.push(result[i].position - searchPattern.length - i * patternDifference);
+ }
+ i--;
+ changedView.set(new Uint8Array(this.buffer, result[i].position, this.length - result[i].position), result[i].position - searchPattern.length + replacePattern.length - i * patternDifference);
+ this.buffer = changedBuffer;
+ this.view = new Uint8Array(this.buffer);
+ output.status = 1;
+ return output;
+ }
+ skipPatterns(patterns, start_, length_, backward_) {
+ const { start, length, backward } = this.prepareFindParameters(start_, length_, backward_);
+ let result = start;
+ for (let k = 0; k < patterns.length; k++) {
+ const patternLength = patterns[k].length;
+ const equalStart = (backward) ? (result - patternLength) : (result);
+ let equal = true;
+ for (let j = 0; j < patternLength; j++) {
+ if (this.view[j + equalStart] != patterns[k].view[j]) {
+ equal = false;
+ break;
+ }
+ }
+ if (equal) {
+ k = (-1);
+ if (backward) {
+ result -= patternLength;
+ if (result <= 0)
+ return result;
+ }
+ else {
+ result += patternLength;
+ if (result >= (start + length))
+ return result;
+ }
+ }
+ }
+ return result;
+ }
+ skipNotPatterns(patterns, start_, length_, backward_) {
+ const { start, length, backward } = this.prepareFindParameters(start_, length_, backward_);
+ let result = (-1);
+ for (let i = 0; i < length; i++) {
+ for (let k = 0; k < patterns.length; k++) {
+ const patternLength = patterns[k].length;
+ const equalStart = (backward) ? (start - i - patternLength) : (start + i);
+ let equal = true;
+ for (let j = 0; j < patternLength; j++) {
+ if (this.view[j + equalStart] != patterns[k].view[j]) {
+ equal = false;
+ break;
+ }
+ }
+ if (equal) {
+ result = (backward) ? (start - i) : (start + i);
+ break;
+ }
+ }
+ if (result != (-1)) {
+ break;
+ }
+ }
+ return result;
+ }
+ prepareFindParameters(start = null, length = null, backward = false) {
+ if (start === null) {
+ start = (backward) ? this.length : 0;
+ }
+ if (start > this.length) {
+ start = this.length;
+ }
+ if (backward) {
+ if (length === null) {
+ length = start;
+ }
+ if (length > start) {
+ length = start;
+ }
+ }
+ else {
+ if (length === null) {
+ length = this.length - start;
+ }
+ if (length > (this.length - start)) {
+ length = this.length - start;
+ }
+ }
+ return { start, length, backward };
+ }
+}
+
+class SeqStream {
+ constructor(parameters = {}) {
+ this._stream = new ByteStream();
+ this._length = 0;
+ this._start = 0;
+ this.backward = false;
+ this.appendBlock = 0;
+ this.prevLength = 0;
+ this.prevStart = 0;
+ if ("view" in parameters) {
+ this.stream = new ByteStream({ view: parameters.view });
+ }
+ else if ("buffer" in parameters) {
+ this.stream = new ByteStream({ buffer: parameters.buffer });
+ }
+ else if ("string" in parameters) {
+ this.stream = new ByteStream({ string: parameters.string });
+ }
+ else if ("hexstring" in parameters) {
+ this.stream = new ByteStream({ hexstring: parameters.hexstring });
+ }
+ else if ("stream" in parameters) {
+ this.stream = parameters.stream.slice();
+ }
+ else {
+ this.stream = new ByteStream();
+ }
+ if ("backward" in parameters && parameters.backward) {
+ this.backward = parameters.backward;
+ this._start = this.stream.length;
+ }
+ if ("length" in parameters && parameters.length > 0) {
+ this._length = parameters.length;
+ }
+ if ("start" in parameters && parameters.start && parameters.start > 0) {
+ this._start = parameters.start;
+ }
+ if ("appendBlock" in parameters && parameters.appendBlock && parameters.appendBlock > 0) {
+ this.appendBlock = parameters.appendBlock;
+ }
+ }
+ set stream(value) {
+ this._stream = value;
+ this.prevLength = this._length;
+ this._length = value.length;
+ this.prevStart = this._start;
+ this._start = 0;
+ }
+ get stream() {
+ return this._stream;
+ }
+ set length(value) {
+ this.prevLength = this._length;
+ this._length = value;
+ }
+ get length() {
+ if (this.appendBlock) {
+ return this.start;
+ }
+ return this._length;
+ }
+ set start(value) {
+ if (value > this.stream.length)
+ return;
+ this.prevStart = this._start;
+ this.prevLength = this._length;
+ this._length -= (this.backward) ? (this._start - value) : (value - this._start);
+ this._start = value;
+ }
+ get start() {
+ return this._start;
+ }
+ get buffer() {
+ return this._stream.buffer.slice(0, this._length);
+ }
+ resetPosition() {
+ this._start = this.prevStart;
+ this._length = this.prevLength;
+ }
+ findPattern(pattern, gap = null) {
+ if ((gap == null) || (gap > this.length)) {
+ gap = this.length;
+ }
+ const result = this.stream.findPattern(pattern, this.start, this.length, this.backward);
+ if (result == (-1))
+ return result;
+ if (this.backward) {
+ if (result < (this.start - pattern.length - gap)) {
+ return (-1);
+ }
+ }
+ else {
+ if (result > (this.start + pattern.length + gap)) {
+ return (-1);
+ }
+ }
+ this.start = result;
+ return result;
+ }
+ findFirstIn(patterns, gap = null) {
+ if ((gap == null) || (gap > this.length)) {
+ gap = this.length;
+ }
+ const result = this.stream.findFirstIn(patterns, this.start, this.length, this.backward);
+ if (result.id == (-1))
+ return result;
+ if (this.backward) {
+ if (result.position < (this.start - patterns[result.id].length - gap)) {
+ return {
+ id: (-1),
+ position: (this.backward) ? 0 : (this.start + this.length)
+ };
+ }
+ }
+ else {
+ if (result.position > (this.start + patterns[result.id].length + gap)) {
+ return {
+ id: (-1),
+ position: (this.backward) ? 0 : (this.start + this.length)
+ };
+ }
+ }
+ this.start = result.position;
+ return result;
+ }
+ findAllIn(patterns) {
+ const start = (this.backward) ? (this.start - this.length) : this.start;
+ return this.stream.findAllIn(patterns, start, this.length);
+ }
+ findFirstNotIn(patterns, gap = null) {
+ if ((gap == null) || (gap > this._length)) {
+ gap = this._length;
+ }
+ const result = this._stream.findFirstNotIn(patterns, this._start, this._length, this.backward);
+ if ((result.left.id == (-1)) && (result.right.id == (-1))) {
+ return result;
+ }
+ if (this.backward) {
+ if (result.right.id != (-1)) {
+ if (result.right.position < (this._start - patterns[result.right.id].length - gap)) {
+ return {
+ left: {
+ id: (-1),
+ position: this._start
+ },
+ right: {
+ id: (-1),
+ position: 0
+ },
+ value: new ByteStream()
+ };
+ }
+ }
+ }
+ else {
+ if (result.left.id != (-1)) {
+ if (result.left.position > (this._start + patterns[result.left.id].length + gap)) {
+ return {
+ left: {
+ id: (-1),
+ position: this._start
+ },
+ right: {
+ id: (-1),
+ position: 0
+ },
+ value: new ByteStream()
+ };
+ }
+ }
+ }
+ if (this.backward) {
+ if (result.left.id == (-1)) {
+ this.start = 0;
+ }
+ else {
+ this.start = result.left.position;
+ }
+ }
+ else {
+ if (result.right.id == (-1)) {
+ this.start = (this._start + this._length);
+ }
+ else {
+ this.start = result.right.position;
+ }
+ }
+ return result;
+ }
+ findAllNotIn(patterns) {
+ const start = (this.backward) ? (this._start - this._length) : this._start;
+ return this._stream.findAllNotIn(patterns, start, this._length);
+ }
+ findFirstSequence(patterns, length = null, gap = null) {
+ if ((length == null) || (length > this._length)) {
+ length = this._length;
+ }
+ if ((gap == null) || (gap > length)) {
+ gap = length;
+ }
+ const result = this._stream.findFirstSequence(patterns, this._start, length, this.backward);
+ if (result.value.length == 0) {
+ return result;
+ }
+ if (this.backward) {
+ if (result.position < (this._start - result.value.length - gap)) {
+ return {
+ position: (-1),
+ value: new ByteStream()
+ };
+ }
+ }
+ else {
+ if (result.position > (this._start + result.value.length + gap)) {
+ return {
+ position: (-1),
+ value: new ByteStream()
+ };
+ }
+ }
+ this.start = result.position;
+ return result;
+ }
+ findAllSequences(patterns) {
+ const start = (this.backward) ? (this.start - this.length) : this.start;
+ return this.stream.findAllSequences(patterns, start, this.length);
+ }
+ findPairedPatterns(leftPattern, rightPattern, gap = null) {
+ if ((gap == null) || (gap > this.length)) {
+ gap = this.length;
+ }
+ const start = (this.backward) ? (this.start - this.length) : this.start;
+ const result = this.stream.findPairedPatterns(leftPattern, rightPattern, start, this.length);
+ if (result.length) {
+ if (this.backward) {
+ if (result[0].right < (this.start - rightPattern.length - gap)) {
+ return [];
+ }
+ }
+ else {
+ if (result[0].left > (this.start + leftPattern.length + gap)) {
+ return [];
+ }
+ }
+ }
+ return result;
+ }
+ findPairedArrays(leftPatterns, rightPatterns, gap = null) {
+ if ((gap == null) || (gap > this.length)) {
+ gap = this.length;
+ }
+ const start = (this.backward) ? (this.start - this.length) : this.start;
+ const result = this.stream.findPairedArrays(leftPatterns, rightPatterns, start, this.length);
+ if (result.length) {
+ if (this.backward) {
+ if (result[0].right.position < (this.start - rightPatterns[result[0].right.id].length - gap)) {
+ return [];
+ }
+ }
+ else {
+ if (result[0].left.position > (this.start + leftPatterns[result[0].left.id].length + gap)) {
+ return [];
+ }
+ }
+ }
+ return result;
+ }
+ replacePattern(searchPattern, replacePattern) {
+ const start = (this.backward) ? (this.start - this.length) : this.start;
+ return this.stream.replacePattern(searchPattern, replacePattern, start, this.length);
+ }
+ skipPatterns(patterns) {
+ const result = this.stream.skipPatterns(patterns, this.start, this.length, this.backward);
+ this.start = result;
+ return result;
+ }
+ skipNotPatterns(patterns) {
+ const result = this.stream.skipNotPatterns(patterns, this.start, this.length, this.backward);
+ if (result == (-1))
+ return (-1);
+ this.start = result;
+ return result;
+ }
+ append(stream) {
+ this.beforeAppend(stream.length);
+ this._stream.view.set(stream.view, this._start);
+ this._length += (stream.length * 2);
+ this.start = (this._start + stream.length);
+ this.prevLength -= (stream.length * 2);
+ }
+ appendView(view) {
+ this.beforeAppend(view.length);
+ this._stream.view.set(view, this._start);
+ this._length += (view.length * 2);
+ this.start = (this._start + view.length);
+ this.prevLength -= (view.length * 2);
+ }
+ appendChar(char) {
+ this.beforeAppend(1);
+ this._stream.view[this._start] = char;
+ this._length += 2;
+ this.start = (this._start + 1);
+ this.prevLength -= 2;
+ }
+ appendUint16(number) {
+ this.beforeAppend(2);
+ const value = new Uint16Array([number]);
+ const view = new Uint8Array(value.buffer);
+ this.stream.view[this._start] = view[1];
+ this._stream.view[this._start + 1] = view[0];
+ this._length += 4;
+ this.start = this._start + 2;
+ this.prevLength -= 4;
+ }
+ appendUint24(number) {
+ this.beforeAppend(3);
+ const value = new Uint32Array([number]);
+ const view = new Uint8Array(value.buffer);
+ this._stream.view[this._start] = view[2];
+ this._stream.view[this._start + 1] = view[1];
+ this._stream.view[this._start + 2] = view[0];
+ this._length += 6;
+ this.start = (this._start + 3);
+ this.prevLength -= 6;
+ }
+ appendUint32(number) {
+ this.beforeAppend(4);
+ const value = new Uint32Array([number]);
+ const view = new Uint8Array(value.buffer);
+ this._stream.view[this._start] = view[3];
+ this._stream.view[this._start + 1] = view[2];
+ this._stream.view[this._start + 2] = view[1];
+ this._stream.view[this._start + 3] = view[0];
+ this._length += 8;
+ this.start = (this._start + 4);
+ this.prevLength -= 8;
+ }
+ appendInt16(number) {
+ this.beforeAppend(2);
+ const value = new Int16Array([number]);
+ const view = new Uint8Array(value.buffer);
+ this._stream.view[this._start] = view[1];
+ this._stream.view[this._start + 1] = view[0];
+ this._length += 4;
+ this.start = (this._start + 2);
+ this.prevLength -= 4;
+ }
+ appendInt32(number) {
+ this.beforeAppend(4);
+ const value = new Int32Array([number]);
+ const view = new Uint8Array(value.buffer);
+ this._stream.view[this._start] = view[3];
+ this._stream.view[this._start + 1] = view[2];
+ this._stream.view[this._start + 2] = view[1];
+ this._stream.view[this._start + 3] = view[0];
+ this._length += 8;
+ this.start = (this._start + 4);
+ this.prevLength -= 8;
+ }
+ getBlock(size, changeLength = true) {
+ if (this._length <= 0) {
+ return new Uint8Array(0);
+ }
+ if (this._length < size) {
+ size = this._length;
+ }
+ let result;
+ if (this.backward) {
+ const view = this._stream.view.subarray(this._length - size, this._length);
+ result = new Uint8Array(size);
+ for (let i = 0; i < size; i++) {
+ result[size - 1 - i] = view[i];
+ }
+ }
+ else {
+ result = this._stream.view.subarray(this._start, this._start + size);
+ }
+ if (changeLength) {
+ this.start += ((this.backward) ? ((-1) * size) : size);
+ }
+ return result;
+ }
+ getUint16(changeLength = true) {
+ const block = this.getBlock(2, changeLength);
+ if (block.length < 2)
+ return 0;
+ const value = new Uint16Array(1);
+ const view = new Uint8Array(value.buffer);
+ view[0] = block[1];
+ view[1] = block[0];
+ return value[0];
+ }
+ getInt16(changeLength = true) {
+ const block = this.getBlock(2, changeLength);
+ if (block.length < 2)
+ return 0;
+ const value = new Int16Array(1);
+ const view = new Uint8Array(value.buffer);
+ view[0] = block[1];
+ view[1] = block[0];
+ return value[0];
+ }
+ getUint24(changeLength = true) {
+ const block = this.getBlock(3, changeLength);
+ if (block.length < 3)
+ return 0;
+ const value = new Uint32Array(1);
+ const view = new Uint8Array(value.buffer);
+ for (let i = 3; i >= 1; i--) {
+ view[3 - i] = block[i - 1];
+ }
+ return value[0];
+ }
+ getUint32(changeLength = true) {
+ const block = this.getBlock(4, changeLength);
+ if (block.length < 4) {
+ return 0;
+ }
+ const value = new Uint32Array(1);
+ const view = new Uint8Array(value.buffer);
+ for (let i = 3; i >= 0; i--) {
+ view[3 - i] = block[i];
+ }
+ return value[0];
+ }
+ getInt32(changeLength = true) {
+ const block = this.getBlock(4, changeLength);
+ if (block.length < 4)
+ return 0;
+ const value = new Int32Array(1);
+ const view = new Uint8Array(value.buffer);
+ for (let i = 3; i >= 0; i--) {
+ view[3 - i] = block[i];
+ }
+ return value[0];
+ }
+ beforeAppend(size) {
+ if ((this._start + size) > this._stream.length) {
+ if (size > this.appendBlock) {
+ this.appendBlock = size + SeqStream.APPEND_BLOCK;
+ }
+ this._stream.realloc(this._stream.length + this.appendBlock);
+ }
+ }
+}
+SeqStream.APPEND_BLOCK = 1000;
+
+/******************************************************************************
+Copyright (c) Microsoft Corporation.
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+***************************************************************************** */
+
+function __awaiter(thisArg, _arguments, P, generator) {
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+}
+
+var _a;
+class ECNamedCurves {
+ static register(name, id, size) {
+ this.namedCurves[name.toLowerCase()] = this.namedCurves[id] = { name, id, size };
+ }
+ static find(nameOrId) {
+ return this.namedCurves[nameOrId.toLowerCase()] || null;
+ }
+}
+_a = ECNamedCurves;
+ECNamedCurves.namedCurves = {};
+(() => {
+ _a.register("P-256", "1.2.840.10045.3.1.7", 32);
+ _a.register("P-384", "1.3.132.0.34", 48);
+ _a.register("P-521", "1.3.132.0.35", 66);
+ _a.register("brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7", 32);
+ _a.register("brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11", 48);
+ _a.register("brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13", 64);
+})();
+
+const X = "x";
+const Y = "y";
+const NAMED_CURVE$1 = "namedCurve";
+class ECPublicKey extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.x = getParametersValue(parameters, X, ECPublicKey.defaultValues(X));
+ this.y = getParametersValue(parameters, Y, ECPublicKey.defaultValues(Y));
+ this.namedCurve = getParametersValue(parameters, NAMED_CURVE$1, ECPublicKey.defaultValues(NAMED_CURVE$1));
+ if (parameters.json) {
+ this.fromJSON(parameters.json);
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case X:
+ case Y:
+ return EMPTY_BUFFER;
+ case NAMED_CURVE$1:
+ return EMPTY_STRING;
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case X:
+ case Y:
+ return memberValue instanceof ArrayBuffer &&
+ (isEqualBuffer(memberValue, ECPublicKey.defaultValues(memberName)));
+ case NAMED_CURVE$1:
+ return typeof memberValue === "string" &&
+ memberValue === ECPublicKey.defaultValues(memberName);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema() {
+ return new RawData();
+ }
+ fromSchema(schema1) {
+ const view = BufferSourceConverter.toUint8Array(schema1);
+ if (view[0] !== 0x04) {
+ throw new Error("Object's schema was not verified against input data for ECPublicKey");
+ }
+ const namedCurve = ECNamedCurves.find(this.namedCurve);
+ if (!namedCurve) {
+ throw new Error(`Incorrect curve OID: ${this.namedCurve}`);
+ }
+ const coordinateLength = namedCurve.size;
+ if (view.byteLength !== (coordinateLength * 2 + 1)) {
+ throw new Error("Object's schema was not verified against input data for ECPublicKey");
+ }
+ this.namedCurve = namedCurve.name;
+ this.x = view.slice(1, coordinateLength + 1).buffer;
+ this.y = view.slice(1 + coordinateLength, coordinateLength * 2 + 1).buffer;
+ }
+ toSchema() {
+ return new RawData({
+ data: utilConcatBuf((new Uint8Array([0x04])).buffer, this.x, this.y)
+ });
+ }
+ toJSON() {
+ const namedCurve = ECNamedCurves.find(this.namedCurve);
+ return {
+ crv: namedCurve ? namedCurve.name : this.namedCurve,
+ x: toBase64(arrayBufferToString(this.x), true, true, false),
+ y: toBase64(arrayBufferToString(this.y), true, true, false)
+ };
+ }
+ fromJSON(json) {
+ ParameterError.assert("json", json, "crv", "x", "y");
+ let coordinateLength = 0;
+ const namedCurve = ECNamedCurves.find(json.crv);
+ if (namedCurve) {
+ this.namedCurve = namedCurve.id;
+ coordinateLength = namedCurve.size;
+ }
+ const xConvertBuffer = stringToArrayBuffer(fromBase64(json.x, true));
+ if (xConvertBuffer.byteLength < coordinateLength) {
+ this.x = new ArrayBuffer(coordinateLength);
+ const view = new Uint8Array(this.x);
+ const convertBufferView = new Uint8Array(xConvertBuffer);
+ view.set(convertBufferView, 1);
+ }
+ else {
+ this.x = xConvertBuffer.slice(0, coordinateLength);
+ }
+ const yConvertBuffer = stringToArrayBuffer(fromBase64(json.y, true));
+ if (yConvertBuffer.byteLength < coordinateLength) {
+ this.y = new ArrayBuffer(coordinateLength);
+ const view = new Uint8Array(this.y);
+ const convertBufferView = new Uint8Array(yConvertBuffer);
+ view.set(convertBufferView, 1);
+ }
+ else {
+ this.y = yConvertBuffer.slice(0, coordinateLength);
+ }
+ }
+}
+ECPublicKey.CLASS_NAME = "ECPublicKey";
+
+const MODULUS$1 = "modulus";
+const PUBLIC_EXPONENT$1 = "publicExponent";
+const CLEAR_PROPS$1b = [MODULUS$1, PUBLIC_EXPONENT$1];
+class RSAPublicKey extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.modulus = getParametersValue(parameters, MODULUS$1, RSAPublicKey.defaultValues(MODULUS$1));
+ this.publicExponent = getParametersValue(parameters, PUBLIC_EXPONENT$1, RSAPublicKey.defaultValues(PUBLIC_EXPONENT$1));
+ if (parameters.json) {
+ this.fromJSON(parameters.json);
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case MODULUS$1:
+ return new Integer();
+ case PUBLIC_EXPONENT$1:
+ return new Integer();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Integer({ name: (names.modulus || EMPTY_STRING) }),
+ new Integer({ name: (names.publicExponent || EMPTY_STRING) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$1b);
+ const asn1 = compareSchema(schema, schema, RSAPublicKey.schema({
+ names: {
+ modulus: MODULUS$1,
+ publicExponent: PUBLIC_EXPONENT$1
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.modulus = asn1.result.modulus.convertFromDER(256);
+ this.publicExponent = asn1.result.publicExponent;
+ }
+ toSchema() {
+ return (new Sequence({
+ value: [
+ this.modulus.convertToDER(),
+ this.publicExponent
+ ]
+ }));
+ }
+ toJSON() {
+ return {
+ n: Convert.ToBase64Url(this.modulus.valueBlock.valueHexView),
+ e: Convert.ToBase64Url(this.publicExponent.valueBlock.valueHexView),
+ };
+ }
+ fromJSON(json) {
+ ParameterError.assert("json", json, "n", "e");
+ const array = stringToArrayBuffer(fromBase64(json.n, true));
+ this.modulus = new Integer({ valueHex: array.slice(0, Math.pow(2, nearestPowerOf2(array.byteLength))) });
+ this.publicExponent = new Integer({ valueHex: stringToArrayBuffer(fromBase64(json.e, true)).slice(0, 3) });
+ }
+}
+RSAPublicKey.CLASS_NAME = "RSAPublicKey";
+
+const ALGORITHM$1 = "algorithm";
+const SUBJECT_PUBLIC_KEY = "subjectPublicKey";
+const CLEAR_PROPS$1a = [ALGORITHM$1, SUBJECT_PUBLIC_KEY];
+class PublicKeyInfo extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.algorithm = getParametersValue(parameters, ALGORITHM$1, PublicKeyInfo.defaultValues(ALGORITHM$1));
+ this.subjectPublicKey = getParametersValue(parameters, SUBJECT_PUBLIC_KEY, PublicKeyInfo.defaultValues(SUBJECT_PUBLIC_KEY));
+ const parsedKey = getParametersValue(parameters, "parsedKey", null);
+ if (parsedKey) {
+ this.parsedKey = parsedKey;
+ }
+ if (parameters.json) {
+ this.fromJSON(parameters.json);
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ get parsedKey() {
+ if (this._parsedKey === undefined) {
+ switch (this.algorithm.algorithmId) {
+ case "1.2.840.10045.2.1":
+ if ("algorithmParams" in this.algorithm) {
+ if (this.algorithm.algorithmParams.constructor.blockName() === ObjectIdentifier.blockName()) {
+ try {
+ this._parsedKey = new ECPublicKey({
+ namedCurve: this.algorithm.algorithmParams.valueBlock.toString(),
+ schema: this.subjectPublicKey.valueBlock.valueHexView
+ });
+ }
+ catch (ex) {
+ }
+ }
+ }
+ break;
+ case "1.2.840.113549.1.1.1":
+ {
+ const publicKeyASN1 = fromBER(this.subjectPublicKey.valueBlock.valueHexView);
+ if (publicKeyASN1.offset !== -1) {
+ try {
+ this._parsedKey = new RSAPublicKey({ schema: publicKeyASN1.result });
+ }
+ catch (ex) {
+ }
+ }
+ }
+ break;
+ }
+ this._parsedKey || (this._parsedKey = null);
+ }
+ return this._parsedKey || undefined;
+ }
+ set parsedKey(value) {
+ this._parsedKey = value;
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case ALGORITHM$1:
+ return new AlgorithmIdentifier();
+ case SUBJECT_PUBLIC_KEY:
+ return new BitString();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ AlgorithmIdentifier.schema(names.algorithm || {}),
+ new BitString({ name: (names.subjectPublicKey || EMPTY_STRING) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$1a);
+ const asn1 = compareSchema(schema, schema, PublicKeyInfo.schema({
+ names: {
+ algorithm: {
+ names: {
+ blockName: ALGORITHM$1
+ }
+ },
+ subjectPublicKey: SUBJECT_PUBLIC_KEY
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.algorithm = new AlgorithmIdentifier({ schema: asn1.result.algorithm });
+ this.subjectPublicKey = asn1.result.subjectPublicKey;
+ }
+ toSchema() {
+ return (new Sequence({
+ value: [
+ this.algorithm.toSchema(),
+ this.subjectPublicKey
+ ]
+ }));
+ }
+ toJSON() {
+ if (!this.parsedKey) {
+ return {
+ algorithm: this.algorithm.toJSON(),
+ subjectPublicKey: this.subjectPublicKey.toJSON(),
+ };
+ }
+ const jwk = {};
+ switch (this.algorithm.algorithmId) {
+ case "1.2.840.10045.2.1":
+ jwk.kty = "EC";
+ break;
+ case "1.2.840.113549.1.1.1":
+ jwk.kty = "RSA";
+ break;
+ }
+ const publicKeyJWK = this.parsedKey.toJSON();
+ Object.assign(jwk, publicKeyJWK);
+ return jwk;
+ }
+ fromJSON(json) {
+ if ("kty" in json) {
+ switch (json.kty.toUpperCase()) {
+ case "EC":
+ this.parsedKey = new ECPublicKey({ json });
+ this.algorithm = new AlgorithmIdentifier({
+ algorithmId: "1.2.840.10045.2.1",
+ algorithmParams: new ObjectIdentifier({ value: this.parsedKey.namedCurve })
+ });
+ break;
+ case "RSA":
+ this.parsedKey = new RSAPublicKey({ json });
+ this.algorithm = new AlgorithmIdentifier({
+ algorithmId: "1.2.840.113549.1.1.1",
+ algorithmParams: new Null()
+ });
+ break;
+ default:
+ throw new Error(`Invalid value for "kty" parameter: ${json.kty}`);
+ }
+ this.subjectPublicKey = new BitString({ valueHex: this.parsedKey.toSchema().toBER(false) });
+ }
+ }
+ importKey(publicKey, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ try {
+ if (!publicKey) {
+ throw new Error("Need to provide publicKey input parameter");
+ }
+ const exportedKey = yield crypto.exportKey("spki", publicKey);
+ const asn1 = fromBER(exportedKey);
+ try {
+ this.fromSchema(asn1.result);
+ }
+ catch (exception) {
+ throw new Error("Error during initializing object from schema");
+ }
+ }
+ catch (e) {
+ const message = e instanceof Error ? e.message : `${e}`;
+ throw new Error(`Error during exporting public key: ${message}`);
+ }
+ });
+ }
+}
+PublicKeyInfo.CLASS_NAME = "PublicKeyInfo";
+
+const VERSION$l = "version";
+const PRIVATE_KEY$1 = "privateKey";
+const NAMED_CURVE = "namedCurve";
+const PUBLIC_KEY$1 = "publicKey";
+const CLEAR_PROPS$19 = [
+ VERSION$l,
+ PRIVATE_KEY$1,
+ NAMED_CURVE,
+ PUBLIC_KEY$1
+];
+class ECPrivateKey extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.version = getParametersValue(parameters, VERSION$l, ECPrivateKey.defaultValues(VERSION$l));
+ this.privateKey = getParametersValue(parameters, PRIVATE_KEY$1, ECPrivateKey.defaultValues(PRIVATE_KEY$1));
+ if (NAMED_CURVE in parameters) {
+ this.namedCurve = getParametersValue(parameters, NAMED_CURVE, ECPrivateKey.defaultValues(NAMED_CURVE));
+ }
+ if (PUBLIC_KEY$1 in parameters) {
+ this.publicKey = getParametersValue(parameters, PUBLIC_KEY$1, ECPrivateKey.defaultValues(PUBLIC_KEY$1));
+ }
+ if (parameters.json) {
+ this.fromJSON(parameters.json);
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case VERSION$l:
+ return 1;
+ case PRIVATE_KEY$1:
+ return new OctetString();
+ case NAMED_CURVE:
+ return EMPTY_STRING;
+ case PUBLIC_KEY$1:
+ return new ECPublicKey();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case VERSION$l:
+ return (memberValue === ECPrivateKey.defaultValues(memberName));
+ case PRIVATE_KEY$1:
+ return (memberValue.isEqual(ECPrivateKey.defaultValues(memberName)));
+ case NAMED_CURVE:
+ return (memberValue === EMPTY_STRING);
+ case PUBLIC_KEY$1:
+ return ((ECPublicKey.compareWithDefault(NAMED_CURVE, memberValue.namedCurve)) &&
+ (ECPublicKey.compareWithDefault("x", memberValue.x)) &&
+ (ECPublicKey.compareWithDefault("y", memberValue.y)));
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Integer({ name: (names.version || EMPTY_STRING) }),
+ new OctetString({ name: (names.privateKey || EMPTY_STRING) }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [
+ new ObjectIdentifier({ name: (names.namedCurve || EMPTY_STRING) })
+ ]
+ }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: [
+ new BitString({ name: (names.publicKey || EMPTY_STRING) })
+ ]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$19);
+ const asn1 = compareSchema(schema, schema, ECPrivateKey.schema({
+ names: {
+ version: VERSION$l,
+ privateKey: PRIVATE_KEY$1,
+ namedCurve: NAMED_CURVE,
+ publicKey: PUBLIC_KEY$1
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.version = asn1.result.version.valueBlock.valueDec;
+ this.privateKey = asn1.result.privateKey;
+ if (NAMED_CURVE in asn1.result) {
+ this.namedCurve = asn1.result.namedCurve.valueBlock.toString();
+ }
+ if (PUBLIC_KEY$1 in asn1.result) {
+ const publicKeyData = { schema: asn1.result.publicKey.valueBlock.valueHex };
+ if (NAMED_CURVE in this) {
+ publicKeyData.namedCurve = this.namedCurve;
+ }
+ this.publicKey = new ECPublicKey(publicKeyData);
+ }
+ }
+ toSchema() {
+ const outputArray = [
+ new Integer({ value: this.version }),
+ this.privateKey
+ ];
+ if (this.namedCurve) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [
+ new ObjectIdentifier({ value: this.namedCurve })
+ ]
+ }));
+ }
+ if (this.publicKey) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: [
+ new BitString({ valueHex: this.publicKey.toSchema().toBER(false) })
+ ]
+ }));
+ }
+ return new Sequence({
+ value: outputArray
+ });
+ }
+ toJSON() {
+ if (!this.namedCurve || ECPrivateKey.compareWithDefault(NAMED_CURVE, this.namedCurve)) {
+ throw new Error("Not enough information for making JSON: absent \"namedCurve\" value");
+ }
+ const curve = ECNamedCurves.find(this.namedCurve);
+ const privateKeyJSON = {
+ crv: curve ? curve.name : this.namedCurve,
+ d: Convert.ToBase64Url(this.privateKey.valueBlock.valueHexView),
+ };
+ if (this.publicKey) {
+ const publicKeyJSON = this.publicKey.toJSON();
+ privateKeyJSON.x = publicKeyJSON.x;
+ privateKeyJSON.y = publicKeyJSON.y;
+ }
+ return privateKeyJSON;
+ }
+ fromJSON(json) {
+ ParameterError.assert("json", json, "crv", "d");
+ let coordinateLength = 0;
+ const curve = ECNamedCurves.find(json.crv);
+ if (curve) {
+ this.namedCurve = curve.id;
+ coordinateLength = curve.size;
+ }
+ const convertBuffer = Convert.FromBase64Url(json.d);
+ if (convertBuffer.byteLength < coordinateLength) {
+ const buffer = new ArrayBuffer(coordinateLength);
+ const view = new Uint8Array(buffer);
+ const convertBufferView = new Uint8Array(convertBuffer);
+ view.set(convertBufferView, 1);
+ this.privateKey = new OctetString({ valueHex: buffer });
+ }
+ else {
+ this.privateKey = new OctetString({ valueHex: convertBuffer.slice(0, coordinateLength) });
+ }
+ if (json.x && json.y) {
+ this.publicKey = new ECPublicKey({ json });
+ }
+ }
+}
+ECPrivateKey.CLASS_NAME = "ECPrivateKey";
+
+const PRIME = "prime";
+const EXPONENT = "exponent";
+const COEFFICIENT$1 = "coefficient";
+const CLEAR_PROPS$18 = [
+ PRIME,
+ EXPONENT,
+ COEFFICIENT$1,
+];
+class OtherPrimeInfo extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.prime = getParametersValue(parameters, PRIME, OtherPrimeInfo.defaultValues(PRIME));
+ this.exponent = getParametersValue(parameters, EXPONENT, OtherPrimeInfo.defaultValues(EXPONENT));
+ this.coefficient = getParametersValue(parameters, COEFFICIENT$1, OtherPrimeInfo.defaultValues(COEFFICIENT$1));
+ if (parameters.json) {
+ this.fromJSON(parameters.json);
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case PRIME:
+ return new Integer();
+ case EXPONENT:
+ return new Integer();
+ case COEFFICIENT$1:
+ return new Integer();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Integer({ name: (names.prime || EMPTY_STRING) }),
+ new Integer({ name: (names.exponent || EMPTY_STRING) }),
+ new Integer({ name: (names.coefficient || EMPTY_STRING) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$18);
+ const asn1 = compareSchema(schema, schema, OtherPrimeInfo.schema({
+ names: {
+ prime: PRIME,
+ exponent: EXPONENT,
+ coefficient: COEFFICIENT$1
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.prime = asn1.result.prime.convertFromDER();
+ this.exponent = asn1.result.exponent.convertFromDER();
+ this.coefficient = asn1.result.coefficient.convertFromDER();
+ }
+ toSchema() {
+ return (new Sequence({
+ value: [
+ this.prime.convertToDER(),
+ this.exponent.convertToDER(),
+ this.coefficient.convertToDER()
+ ]
+ }));
+ }
+ toJSON() {
+ return {
+ r: Convert.ToBase64Url(this.prime.valueBlock.valueHexView),
+ d: Convert.ToBase64Url(this.exponent.valueBlock.valueHexView),
+ t: Convert.ToBase64Url(this.coefficient.valueBlock.valueHexView),
+ };
+ }
+ fromJSON(json) {
+ ParameterError.assert("json", json, "r", "d", "r");
+ this.prime = new Integer({ valueHex: Convert.FromBase64Url(json.r) });
+ this.exponent = new Integer({ valueHex: Convert.FromBase64Url(json.d) });
+ this.coefficient = new Integer({ valueHex: Convert.FromBase64Url(json.t) });
+ }
+}
+OtherPrimeInfo.CLASS_NAME = "OtherPrimeInfo";
+
+const VERSION$k = "version";
+const MODULUS = "modulus";
+const PUBLIC_EXPONENT = "publicExponent";
+const PRIVATE_EXPONENT = "privateExponent";
+const PRIME1 = "prime1";
+const PRIME2 = "prime2";
+const EXPONENT1 = "exponent1";
+const EXPONENT2 = "exponent2";
+const COEFFICIENT = "coefficient";
+const OTHER_PRIME_INFOS = "otherPrimeInfos";
+const CLEAR_PROPS$17 = [
+ VERSION$k,
+ MODULUS,
+ PUBLIC_EXPONENT,
+ PRIVATE_EXPONENT,
+ PRIME1,
+ PRIME2,
+ EXPONENT1,
+ EXPONENT2,
+ COEFFICIENT,
+ OTHER_PRIME_INFOS
+];
+class RSAPrivateKey extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.version = getParametersValue(parameters, VERSION$k, RSAPrivateKey.defaultValues(VERSION$k));
+ this.modulus = getParametersValue(parameters, MODULUS, RSAPrivateKey.defaultValues(MODULUS));
+ this.publicExponent = getParametersValue(parameters, PUBLIC_EXPONENT, RSAPrivateKey.defaultValues(PUBLIC_EXPONENT));
+ this.privateExponent = getParametersValue(parameters, PRIVATE_EXPONENT, RSAPrivateKey.defaultValues(PRIVATE_EXPONENT));
+ this.prime1 = getParametersValue(parameters, PRIME1, RSAPrivateKey.defaultValues(PRIME1));
+ this.prime2 = getParametersValue(parameters, PRIME2, RSAPrivateKey.defaultValues(PRIME2));
+ this.exponent1 = getParametersValue(parameters, EXPONENT1, RSAPrivateKey.defaultValues(EXPONENT1));
+ this.exponent2 = getParametersValue(parameters, EXPONENT2, RSAPrivateKey.defaultValues(EXPONENT2));
+ this.coefficient = getParametersValue(parameters, COEFFICIENT, RSAPrivateKey.defaultValues(COEFFICIENT));
+ if (OTHER_PRIME_INFOS in parameters) {
+ this.otherPrimeInfos = getParametersValue(parameters, OTHER_PRIME_INFOS, RSAPrivateKey.defaultValues(OTHER_PRIME_INFOS));
+ }
+ if (parameters.json) {
+ this.fromJSON(parameters.json);
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case VERSION$k:
+ return 0;
+ case MODULUS:
+ return new Integer();
+ case PUBLIC_EXPONENT:
+ return new Integer();
+ case PRIVATE_EXPONENT:
+ return new Integer();
+ case PRIME1:
+ return new Integer();
+ case PRIME2:
+ return new Integer();
+ case EXPONENT1:
+ return new Integer();
+ case EXPONENT2:
+ return new Integer();
+ case COEFFICIENT:
+ return new Integer();
+ case OTHER_PRIME_INFOS:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Integer({ name: (names.version || EMPTY_STRING) }),
+ new Integer({ name: (names.modulus || EMPTY_STRING) }),
+ new Integer({ name: (names.publicExponent || EMPTY_STRING) }),
+ new Integer({ name: (names.privateExponent || EMPTY_STRING) }),
+ new Integer({ name: (names.prime1 || EMPTY_STRING) }),
+ new Integer({ name: (names.prime2 || EMPTY_STRING) }),
+ new Integer({ name: (names.exponent1 || EMPTY_STRING) }),
+ new Integer({ name: (names.exponent2 || EMPTY_STRING) }),
+ new Integer({ name: (names.coefficient || EMPTY_STRING) }),
+ new Sequence({
+ optional: true,
+ value: [
+ new Repeated({
+ name: (names.otherPrimeInfosName || EMPTY_STRING),
+ value: OtherPrimeInfo.schema(names.otherPrimeInfo || {})
+ })
+ ]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$17);
+ const asn1 = compareSchema(schema, schema, RSAPrivateKey.schema({
+ names: {
+ version: VERSION$k,
+ modulus: MODULUS,
+ publicExponent: PUBLIC_EXPONENT,
+ privateExponent: PRIVATE_EXPONENT,
+ prime1: PRIME1,
+ prime2: PRIME2,
+ exponent1: EXPONENT1,
+ exponent2: EXPONENT2,
+ coefficient: COEFFICIENT,
+ otherPrimeInfo: {
+ names: {
+ blockName: OTHER_PRIME_INFOS
+ }
+ }
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.version = asn1.result.version.valueBlock.valueDec;
+ this.modulus = asn1.result.modulus.convertFromDER(256);
+ this.publicExponent = asn1.result.publicExponent;
+ this.privateExponent = asn1.result.privateExponent.convertFromDER(256);
+ this.prime1 = asn1.result.prime1.convertFromDER(128);
+ this.prime2 = asn1.result.prime2.convertFromDER(128);
+ this.exponent1 = asn1.result.exponent1.convertFromDER(128);
+ this.exponent2 = asn1.result.exponent2.convertFromDER(128);
+ this.coefficient = asn1.result.coefficient.convertFromDER(128);
+ if (OTHER_PRIME_INFOS in asn1.result)
+ this.otherPrimeInfos = Array.from(asn1.result.otherPrimeInfos, element => new OtherPrimeInfo({ schema: element }));
+ }
+ toSchema() {
+ const outputArray = [];
+ outputArray.push(new Integer({ value: this.version }));
+ outputArray.push(this.modulus.convertToDER());
+ outputArray.push(this.publicExponent);
+ outputArray.push(this.privateExponent.convertToDER());
+ outputArray.push(this.prime1.convertToDER());
+ outputArray.push(this.prime2.convertToDER());
+ outputArray.push(this.exponent1.convertToDER());
+ outputArray.push(this.exponent2.convertToDER());
+ outputArray.push(this.coefficient.convertToDER());
+ if (this.otherPrimeInfos) {
+ outputArray.push(new Sequence({
+ value: Array.from(this.otherPrimeInfos, o => o.toSchema())
+ }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const jwk = {
+ n: Convert.ToBase64Url(this.modulus.valueBlock.valueHexView),
+ e: Convert.ToBase64Url(this.publicExponent.valueBlock.valueHexView),
+ d: Convert.ToBase64Url(this.privateExponent.valueBlock.valueHexView),
+ p: Convert.ToBase64Url(this.prime1.valueBlock.valueHexView),
+ q: Convert.ToBase64Url(this.prime2.valueBlock.valueHexView),
+ dp: Convert.ToBase64Url(this.exponent1.valueBlock.valueHexView),
+ dq: Convert.ToBase64Url(this.exponent2.valueBlock.valueHexView),
+ qi: Convert.ToBase64Url(this.coefficient.valueBlock.valueHexView),
+ };
+ if (this.otherPrimeInfos) {
+ jwk.oth = Array.from(this.otherPrimeInfos, o => o.toJSON());
+ }
+ return jwk;
+ }
+ fromJSON(json) {
+ ParameterError.assert("json", json, "n", "e", "d", "p", "q", "dp", "dq", "qi");
+ this.modulus = new Integer({ valueHex: Convert.FromBase64Url(json.n) });
+ this.publicExponent = new Integer({ valueHex: Convert.FromBase64Url(json.e) });
+ this.privateExponent = new Integer({ valueHex: Convert.FromBase64Url(json.d) });
+ this.prime1 = new Integer({ valueHex: Convert.FromBase64Url(json.p) });
+ this.prime2 = new Integer({ valueHex: Convert.FromBase64Url(json.q) });
+ this.exponent1 = new Integer({ valueHex: Convert.FromBase64Url(json.dp) });
+ this.exponent2 = new Integer({ valueHex: Convert.FromBase64Url(json.dq) });
+ this.coefficient = new Integer({ valueHex: Convert.FromBase64Url(json.qi) });
+ if (json.oth) {
+ this.otherPrimeInfos = Array.from(json.oth, (element) => new OtherPrimeInfo({ json: element }));
+ }
+ }
+}
+RSAPrivateKey.CLASS_NAME = "RSAPrivateKey";
+
+const VERSION$j = "version";
+const PRIVATE_KEY_ALGORITHM = "privateKeyAlgorithm";
+const PRIVATE_KEY = "privateKey";
+const ATTRIBUTES$5 = "attributes";
+const PARSED_KEY = "parsedKey";
+const CLEAR_PROPS$16 = [
+ VERSION$j,
+ PRIVATE_KEY_ALGORITHM,
+ PRIVATE_KEY,
+ ATTRIBUTES$5
+];
+class PrivateKeyInfo extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.version = getParametersValue(parameters, VERSION$j, PrivateKeyInfo.defaultValues(VERSION$j));
+ this.privateKeyAlgorithm = getParametersValue(parameters, PRIVATE_KEY_ALGORITHM, PrivateKeyInfo.defaultValues(PRIVATE_KEY_ALGORITHM));
+ this.privateKey = getParametersValue(parameters, PRIVATE_KEY, PrivateKeyInfo.defaultValues(PRIVATE_KEY));
+ if (ATTRIBUTES$5 in parameters) {
+ this.attributes = getParametersValue(parameters, ATTRIBUTES$5, PrivateKeyInfo.defaultValues(ATTRIBUTES$5));
+ }
+ if (PARSED_KEY in parameters) {
+ this.parsedKey = getParametersValue(parameters, PARSED_KEY, PrivateKeyInfo.defaultValues(PARSED_KEY));
+ }
+ if (parameters.json) {
+ this.fromJSON(parameters.json);
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case VERSION$j:
+ return 0;
+ case PRIVATE_KEY_ALGORITHM:
+ return new AlgorithmIdentifier();
+ case PRIVATE_KEY:
+ return new OctetString();
+ case ATTRIBUTES$5:
+ return [];
+ case PARSED_KEY:
+ return {};
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Integer({ name: (names.version || EMPTY_STRING) }),
+ AlgorithmIdentifier.schema(names.privateKeyAlgorithm || {}),
+ new OctetString({ name: (names.privateKey || EMPTY_STRING) }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [
+ new Repeated({
+ name: (names.attributes || EMPTY_STRING),
+ value: Attribute.schema()
+ })
+ ]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$16);
+ const asn1 = compareSchema(schema, schema, PrivateKeyInfo.schema({
+ names: {
+ version: VERSION$j,
+ privateKeyAlgorithm: {
+ names: {
+ blockName: PRIVATE_KEY_ALGORITHM
+ }
+ },
+ privateKey: PRIVATE_KEY,
+ attributes: ATTRIBUTES$5
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.version = asn1.result.version.valueBlock.valueDec;
+ this.privateKeyAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.privateKeyAlgorithm });
+ this.privateKey = asn1.result.privateKey;
+ if (ATTRIBUTES$5 in asn1.result)
+ this.attributes = Array.from(asn1.result.attributes, element => new Attribute({ schema: element }));
+ switch (this.privateKeyAlgorithm.algorithmId) {
+ case "1.2.840.113549.1.1.1":
+ {
+ const privateKeyASN1 = fromBER(this.privateKey.valueBlock.valueHexView);
+ if (privateKeyASN1.offset !== -1)
+ this.parsedKey = new RSAPrivateKey({ schema: privateKeyASN1.result });
+ }
+ break;
+ case "1.2.840.10045.2.1":
+ if ("algorithmParams" in this.privateKeyAlgorithm) {
+ if (this.privateKeyAlgorithm.algorithmParams instanceof ObjectIdentifier) {
+ const privateKeyASN1 = fromBER(this.privateKey.valueBlock.valueHexView);
+ if (privateKeyASN1.offset !== -1) {
+ this.parsedKey = new ECPrivateKey({
+ namedCurve: this.privateKeyAlgorithm.algorithmParams.valueBlock.toString(),
+ schema: privateKeyASN1.result
+ });
+ }
+ }
+ }
+ break;
+ }
+ }
+ toSchema() {
+ const outputArray = [
+ new Integer({ value: this.version }),
+ this.privateKeyAlgorithm.toSchema(),
+ this.privateKey
+ ];
+ if (this.attributes) {
+ outputArray.push(new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: Array.from(this.attributes, o => o.toSchema())
+ }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ if (!this.parsedKey) {
+ const object = {
+ version: this.version,
+ privateKeyAlgorithm: this.privateKeyAlgorithm.toJSON(),
+ privateKey: this.privateKey.toJSON(),
+ };
+ if (this.attributes) {
+ object.attributes = Array.from(this.attributes, o => o.toJSON());
+ }
+ return object;
+ }
+ const jwk = {};
+ switch (this.privateKeyAlgorithm.algorithmId) {
+ case "1.2.840.10045.2.1":
+ jwk.kty = "EC";
+ break;
+ case "1.2.840.113549.1.1.1":
+ jwk.kty = "RSA";
+ break;
+ }
+ const publicKeyJWK = this.parsedKey.toJSON();
+ Object.assign(jwk, publicKeyJWK);
+ return jwk;
+ }
+ fromJSON(json) {
+ if ("kty" in json) {
+ switch (json.kty.toUpperCase()) {
+ case "EC":
+ this.parsedKey = new ECPrivateKey({ json });
+ this.privateKeyAlgorithm = new AlgorithmIdentifier({
+ algorithmId: "1.2.840.10045.2.1",
+ algorithmParams: new ObjectIdentifier({ value: this.parsedKey.namedCurve })
+ });
+ break;
+ case "RSA":
+ this.parsedKey = new RSAPrivateKey({ json });
+ this.privateKeyAlgorithm = new AlgorithmIdentifier({
+ algorithmId: "1.2.840.113549.1.1.1",
+ algorithmParams: new Null()
+ });
+ break;
+ default:
+ throw new Error(`Invalid value for "kty" parameter: ${json.kty}`);
+ }
+ this.privateKey = new OctetString({ valueHex: this.parsedKey.toSchema().toBER(false) });
+ }
+ }
+}
+PrivateKeyInfo.CLASS_NAME = "PrivateKeyInfo";
+
+const CONTENT_TYPE$1 = "contentType";
+const CONTENT_ENCRYPTION_ALGORITHM = "contentEncryptionAlgorithm";
+const ENCRYPTED_CONTENT = "encryptedContent";
+const CLEAR_PROPS$15 = [
+ CONTENT_TYPE$1,
+ CONTENT_ENCRYPTION_ALGORITHM,
+ ENCRYPTED_CONTENT,
+];
+class EncryptedContentInfo extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.contentType = getParametersValue(parameters, CONTENT_TYPE$1, EncryptedContentInfo.defaultValues(CONTENT_TYPE$1));
+ this.contentEncryptionAlgorithm = getParametersValue(parameters, CONTENT_ENCRYPTION_ALGORITHM, EncryptedContentInfo.defaultValues(CONTENT_ENCRYPTION_ALGORITHM));
+ if (ENCRYPTED_CONTENT in parameters && parameters.encryptedContent) {
+ this.encryptedContent = parameters.encryptedContent;
+ if ((this.encryptedContent.idBlock.tagClass === 1) &&
+ (this.encryptedContent.idBlock.tagNumber === 4)) {
+ if (this.encryptedContent.idBlock.isConstructed === false) {
+ const constrString = new OctetString({
+ idBlock: { isConstructed: true },
+ isConstructed: true
+ });
+ let offset = 0;
+ const valueHex = this.encryptedContent.valueBlock.valueHexView.slice().buffer;
+ let length = valueHex.byteLength;
+ const pieceSize = 1024;
+ while (length > 0) {
+ const pieceView = new Uint8Array(valueHex, offset, ((offset + pieceSize) > valueHex.byteLength) ? (valueHex.byteLength - offset) : pieceSize);
+ const _array = new ArrayBuffer(pieceView.length);
+ const _view = new Uint8Array(_array);
+ for (let i = 0; i < _view.length; i++)
+ _view[i] = pieceView[i];
+ constrString.valueBlock.value.push(new OctetString({ valueHex: _array }));
+ length -= pieceView.length;
+ offset += pieceView.length;
+ }
+ this.encryptedContent = constrString;
+ }
+ }
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case CONTENT_TYPE$1:
+ return EMPTY_STRING;
+ case CONTENT_ENCRYPTION_ALGORITHM:
+ return new AlgorithmIdentifier();
+ case ENCRYPTED_CONTENT:
+ return new OctetString();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case CONTENT_TYPE$1:
+ return (memberValue === EMPTY_STRING);
+ case CONTENT_ENCRYPTION_ALGORITHM:
+ return ((memberValue.algorithmId === EMPTY_STRING) && (("algorithmParams" in memberValue) === false));
+ case ENCRYPTED_CONTENT:
+ return (memberValue.isEqual(EncryptedContentInfo.defaultValues(ENCRYPTED_CONTENT)));
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new ObjectIdentifier({ name: (names.contentType || EMPTY_STRING) }),
+ AlgorithmIdentifier.schema(names.contentEncryptionAlgorithm || {}),
+ new Choice({
+ value: [
+ new Constructed({
+ name: (names.encryptedContent || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [
+ new Repeated({
+ value: new OctetString()
+ })
+ ]
+ }),
+ new Primitive({
+ name: (names.encryptedContent || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ }
+ })
+ ]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$15);
+ const asn1 = compareSchema(schema, schema, EncryptedContentInfo.schema({
+ names: {
+ contentType: CONTENT_TYPE$1,
+ contentEncryptionAlgorithm: {
+ names: {
+ blockName: CONTENT_ENCRYPTION_ALGORITHM
+ }
+ },
+ encryptedContent: ENCRYPTED_CONTENT
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.contentType = asn1.result.contentType.valueBlock.toString();
+ this.contentEncryptionAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.contentEncryptionAlgorithm });
+ if (ENCRYPTED_CONTENT in asn1.result) {
+ this.encryptedContent = asn1.result.encryptedContent;
+ this.encryptedContent.idBlock.tagClass = 1;
+ this.encryptedContent.idBlock.tagNumber = 4;
+ }
+ }
+ toSchema() {
+ const sequenceLengthBlock = {
+ isIndefiniteForm: false
+ };
+ const outputArray = [];
+ outputArray.push(new ObjectIdentifier({ value: this.contentType }));
+ outputArray.push(this.contentEncryptionAlgorithm.toSchema());
+ if (this.encryptedContent) {
+ sequenceLengthBlock.isIndefiniteForm = this.encryptedContent.idBlock.isConstructed;
+ const encryptedValue = this.encryptedContent;
+ encryptedValue.idBlock.tagClass = 3;
+ encryptedValue.idBlock.tagNumber = 0;
+ encryptedValue.lenBlock.isIndefiniteForm = this.encryptedContent.idBlock.isConstructed;
+ outputArray.push(encryptedValue);
+ }
+ return (new Sequence({
+ lenBlock: sequenceLengthBlock,
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {
+ contentType: this.contentType,
+ contentEncryptionAlgorithm: this.contentEncryptionAlgorithm.toJSON()
+ };
+ if (this.encryptedContent) {
+ res.encryptedContent = this.encryptedContent.toJSON();
+ }
+ return res;
+ }
+ getEncryptedContent() {
+ if (!this.encryptedContent) {
+ throw new Error("Parameter 'encryptedContent' is undefined");
+ }
+ return OctetString.prototype.getValue.call(this.encryptedContent);
+ }
+}
+EncryptedContentInfo.CLASS_NAME = "EncryptedContentInfo";
+
+const HASH_ALGORITHM$4 = "hashAlgorithm";
+const MASK_GEN_ALGORITHM$1 = "maskGenAlgorithm";
+const SALT_LENGTH = "saltLength";
+const TRAILER_FIELD = "trailerField";
+const CLEAR_PROPS$14 = [
+ HASH_ALGORITHM$4,
+ MASK_GEN_ALGORITHM$1,
+ SALT_LENGTH,
+ TRAILER_FIELD
+];
+class RSASSAPSSParams extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.hashAlgorithm = getParametersValue(parameters, HASH_ALGORITHM$4, RSASSAPSSParams.defaultValues(HASH_ALGORITHM$4));
+ this.maskGenAlgorithm = getParametersValue(parameters, MASK_GEN_ALGORITHM$1, RSASSAPSSParams.defaultValues(MASK_GEN_ALGORITHM$1));
+ this.saltLength = getParametersValue(parameters, SALT_LENGTH, RSASSAPSSParams.defaultValues(SALT_LENGTH));
+ this.trailerField = getParametersValue(parameters, TRAILER_FIELD, RSASSAPSSParams.defaultValues(TRAILER_FIELD));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case HASH_ALGORITHM$4:
+ return new AlgorithmIdentifier({
+ algorithmId: "1.3.14.3.2.26",
+ algorithmParams: new Null()
+ });
+ case MASK_GEN_ALGORITHM$1:
+ return new AlgorithmIdentifier({
+ algorithmId: "1.2.840.113549.1.1.8",
+ algorithmParams: (new AlgorithmIdentifier({
+ algorithmId: "1.3.14.3.2.26",
+ algorithmParams: new Null()
+ })).toSchema()
+ });
+ case SALT_LENGTH:
+ return 20;
+ case TRAILER_FIELD:
+ return 1;
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ optional: true,
+ value: [AlgorithmIdentifier.schema(names.hashAlgorithm || {})]
+ }),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ optional: true,
+ value: [AlgorithmIdentifier.schema(names.maskGenAlgorithm || {})]
+ }),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ },
+ optional: true,
+ value: [new Integer({ name: (names.saltLength || EMPTY_STRING) })]
+ }),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 3
+ },
+ optional: true,
+ value: [new Integer({ name: (names.trailerField || EMPTY_STRING) })]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$14);
+ const asn1 = compareSchema(schema, schema, RSASSAPSSParams.schema({
+ names: {
+ hashAlgorithm: {
+ names: {
+ blockName: HASH_ALGORITHM$4
+ }
+ },
+ maskGenAlgorithm: {
+ names: {
+ blockName: MASK_GEN_ALGORITHM$1
+ }
+ },
+ saltLength: SALT_LENGTH,
+ trailerField: TRAILER_FIELD
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ if (HASH_ALGORITHM$4 in asn1.result)
+ this.hashAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.hashAlgorithm });
+ if (MASK_GEN_ALGORITHM$1 in asn1.result)
+ this.maskGenAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.maskGenAlgorithm });
+ if (SALT_LENGTH in asn1.result)
+ this.saltLength = asn1.result.saltLength.valueBlock.valueDec;
+ if (TRAILER_FIELD in asn1.result)
+ this.trailerField = asn1.result.trailerField.valueBlock.valueDec;
+ }
+ toSchema() {
+ const outputArray = [];
+ if (!this.hashAlgorithm.isEqual(RSASSAPSSParams.defaultValues(HASH_ALGORITHM$4))) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [this.hashAlgorithm.toSchema()]
+ }));
+ }
+ if (!this.maskGenAlgorithm.isEqual(RSASSAPSSParams.defaultValues(MASK_GEN_ALGORITHM$1))) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: [this.maskGenAlgorithm.toSchema()]
+ }));
+ }
+ if (this.saltLength !== RSASSAPSSParams.defaultValues(SALT_LENGTH)) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ },
+ value: [new Integer({ value: this.saltLength })]
+ }));
+ }
+ if (this.trailerField !== RSASSAPSSParams.defaultValues(TRAILER_FIELD)) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 3
+ },
+ value: [new Integer({ value: this.trailerField })]
+ }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {};
+ if (!this.hashAlgorithm.isEqual(RSASSAPSSParams.defaultValues(HASH_ALGORITHM$4))) {
+ res.hashAlgorithm = this.hashAlgorithm.toJSON();
+ }
+ if (!this.maskGenAlgorithm.isEqual(RSASSAPSSParams.defaultValues(MASK_GEN_ALGORITHM$1))) {
+ res.maskGenAlgorithm = this.maskGenAlgorithm.toJSON();
+ }
+ if (this.saltLength !== RSASSAPSSParams.defaultValues(SALT_LENGTH)) {
+ res.saltLength = this.saltLength;
+ }
+ if (this.trailerField !== RSASSAPSSParams.defaultValues(TRAILER_FIELD)) {
+ res.trailerField = this.trailerField;
+ }
+ return res;
+ }
+}
+RSASSAPSSParams.CLASS_NAME = "RSASSAPSSParams";
+
+const SALT = "salt";
+const ITERATION_COUNT = "iterationCount";
+const KEY_LENGTH = "keyLength";
+const PRF = "prf";
+const CLEAR_PROPS$13 = [
+ SALT,
+ ITERATION_COUNT,
+ KEY_LENGTH,
+ PRF
+];
+class PBKDF2Params extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.salt = getParametersValue(parameters, SALT, PBKDF2Params.defaultValues(SALT));
+ this.iterationCount = getParametersValue(parameters, ITERATION_COUNT, PBKDF2Params.defaultValues(ITERATION_COUNT));
+ if (KEY_LENGTH in parameters) {
+ this.keyLength = getParametersValue(parameters, KEY_LENGTH, PBKDF2Params.defaultValues(KEY_LENGTH));
+ }
+ if (PRF in parameters) {
+ this.prf = getParametersValue(parameters, PRF, PBKDF2Params.defaultValues(PRF));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case SALT:
+ return {};
+ case ITERATION_COUNT:
+ return (-1);
+ case KEY_LENGTH:
+ return 0;
+ case PRF:
+ return new AlgorithmIdentifier({
+ algorithmId: "1.3.14.3.2.26",
+ algorithmParams: new Null()
+ });
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Choice({
+ value: [
+ new OctetString({ name: (names.saltPrimitive || EMPTY_STRING) }),
+ AlgorithmIdentifier.schema(names.saltConstructed || {})
+ ]
+ }),
+ new Integer({ name: (names.iterationCount || EMPTY_STRING) }),
+ new Integer({
+ name: (names.keyLength || EMPTY_STRING),
+ optional: true
+ }),
+ AlgorithmIdentifier.schema(names.prf || {
+ names: {
+ optional: true
+ }
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$13);
+ const asn1 = compareSchema(schema, schema, PBKDF2Params.schema({
+ names: {
+ saltPrimitive: SALT,
+ saltConstructed: {
+ names: {
+ blockName: SALT
+ }
+ },
+ iterationCount: ITERATION_COUNT,
+ keyLength: KEY_LENGTH,
+ prf: {
+ names: {
+ blockName: PRF,
+ optional: true
+ }
+ }
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.salt = asn1.result.salt;
+ this.iterationCount = asn1.result.iterationCount.valueBlock.valueDec;
+ if (KEY_LENGTH in asn1.result)
+ this.keyLength = asn1.result.keyLength.valueBlock.valueDec;
+ if (PRF in asn1.result)
+ this.prf = new AlgorithmIdentifier({ schema: asn1.result.prf });
+ }
+ toSchema() {
+ const outputArray = [];
+ outputArray.push(this.salt);
+ outputArray.push(new Integer({ value: this.iterationCount }));
+ if (KEY_LENGTH in this) {
+ if (PBKDF2Params.defaultValues(KEY_LENGTH) !== this.keyLength)
+ outputArray.push(new Integer({ value: this.keyLength }));
+ }
+ if (this.prf) {
+ if (PBKDF2Params.defaultValues(PRF).isEqual(this.prf) === false)
+ outputArray.push(this.prf.toSchema());
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {
+ salt: this.salt.toJSON(),
+ iterationCount: this.iterationCount
+ };
+ if (KEY_LENGTH in this) {
+ if (PBKDF2Params.defaultValues(KEY_LENGTH) !== this.keyLength)
+ res.keyLength = this.keyLength;
+ }
+ if (this.prf) {
+ if (PBKDF2Params.defaultValues(PRF).isEqual(this.prf) === false)
+ res.prf = this.prf.toJSON();
+ }
+ return res;
+ }
+}
+PBKDF2Params.CLASS_NAME = "PBKDF2Params";
+
+const KEY_DERIVATION_FUNC = "keyDerivationFunc";
+const ENCRYPTION_SCHEME = "encryptionScheme";
+const CLEAR_PROPS$12 = [
+ KEY_DERIVATION_FUNC,
+ ENCRYPTION_SCHEME
+];
+class PBES2Params extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.keyDerivationFunc = getParametersValue(parameters, KEY_DERIVATION_FUNC, PBES2Params.defaultValues(KEY_DERIVATION_FUNC));
+ this.encryptionScheme = getParametersValue(parameters, ENCRYPTION_SCHEME, PBES2Params.defaultValues(ENCRYPTION_SCHEME));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case KEY_DERIVATION_FUNC:
+ return new AlgorithmIdentifier();
+ case ENCRYPTION_SCHEME:
+ return new AlgorithmIdentifier();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ AlgorithmIdentifier.schema(names.keyDerivationFunc || {}),
+ AlgorithmIdentifier.schema(names.encryptionScheme || {})
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$12);
+ const asn1 = compareSchema(schema, schema, PBES2Params.schema({
+ names: {
+ keyDerivationFunc: {
+ names: {
+ blockName: KEY_DERIVATION_FUNC
+ }
+ },
+ encryptionScheme: {
+ names: {
+ blockName: ENCRYPTION_SCHEME
+ }
+ }
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.keyDerivationFunc = new AlgorithmIdentifier({ schema: asn1.result.keyDerivationFunc });
+ this.encryptionScheme = new AlgorithmIdentifier({ schema: asn1.result.encryptionScheme });
+ }
+ toSchema() {
+ return (new Sequence({
+ value: [
+ this.keyDerivationFunc.toSchema(),
+ this.encryptionScheme.toSchema()
+ ]
+ }));
+ }
+ toJSON() {
+ return {
+ keyDerivationFunc: this.keyDerivationFunc.toJSON(),
+ encryptionScheme: this.encryptionScheme.toJSON()
+ };
+ }
+}
+PBES2Params.CLASS_NAME = "PBES2Params";
+
+class AbstractCryptoEngine {
+ constructor(parameters) {
+ this.crypto = parameters.crypto;
+ this.subtle = "webkitSubtle" in parameters.crypto
+ ? parameters.crypto.webkitSubtle
+ : parameters.crypto.subtle;
+ this.name = getParametersValue(parameters, "name", EMPTY_STRING);
+ }
+ encrypt(...args) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.subtle.encrypt(...args);
+ });
+ }
+ decrypt(...args) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.subtle.decrypt(...args);
+ });
+ }
+ sign(...args) {
+ return this.subtle.sign(...args);
+ }
+ verify(...args) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.subtle.verify(...args);
+ });
+ }
+ digest(...args) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.subtle.digest(...args);
+ });
+ }
+ generateKey(...args) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.subtle.generateKey(...args);
+ });
+ }
+ deriveKey(...args) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.subtle.deriveKey(...args);
+ });
+ }
+ deriveBits(...args) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.subtle.deriveBits(...args);
+ });
+ }
+ wrapKey(...args) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.subtle.wrapKey(...args);
+ });
+ }
+ unwrapKey(...args) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return this.subtle.unwrapKey(...args);
+ });
+ }
+ exportKey(...args) {
+ return this.subtle.exportKey(...args);
+ }
+ importKey(...args) {
+ return this.subtle.importKey(...args);
+ }
+ getRandomValues(array) {
+ return this.crypto.getRandomValues(array);
+ }
+}
+
+function makePKCS12B2Key(cryptoEngine, hashAlgorithm, keyLength, password, salt, iterationCount) {
+ return __awaiter(this, void 0, void 0, function* () {
+ let u;
+ let v;
+ const result = [];
+ switch (hashAlgorithm.toUpperCase()) {
+ case "SHA-1":
+ u = 20;
+ v = 64;
+ break;
+ case "SHA-256":
+ u = 32;
+ v = 64;
+ break;
+ case "SHA-384":
+ u = 48;
+ v = 128;
+ break;
+ case "SHA-512":
+ u = 64;
+ v = 128;
+ break;
+ default:
+ throw new Error("Unsupported hashing algorithm");
+ }
+ const passwordViewInitial = new Uint8Array(password);
+ const passwordTransformed = new ArrayBuffer((password.byteLength * 2) + 2);
+ const passwordTransformedView = new Uint8Array(passwordTransformed);
+ for (let i = 0; i < passwordViewInitial.length; i++) {
+ passwordTransformedView[i * 2] = 0x00;
+ passwordTransformedView[i * 2 + 1] = passwordViewInitial[i];
+ }
+ passwordTransformedView[passwordTransformedView.length - 2] = 0x00;
+ passwordTransformedView[passwordTransformedView.length - 1] = 0x00;
+ password = passwordTransformed.slice(0);
+ const D = new ArrayBuffer(v);
+ const dView = new Uint8Array(D);
+ for (let i = 0; i < D.byteLength; i++)
+ dView[i] = 3;
+ const saltLength = salt.byteLength;
+ const sLen = v * Math.ceil(saltLength / v);
+ const S = new ArrayBuffer(sLen);
+ const sView = new Uint8Array(S);
+ const saltView = new Uint8Array(salt);
+ for (let i = 0; i < sLen; i++)
+ sView[i] = saltView[i % saltLength];
+ const passwordLength = password.byteLength;
+ const pLen = v * Math.ceil(passwordLength / v);
+ const P = new ArrayBuffer(pLen);
+ const pView = new Uint8Array(P);
+ const passwordView = new Uint8Array(password);
+ for (let i = 0; i < pLen; i++)
+ pView[i] = passwordView[i % passwordLength];
+ const sPlusPLength = S.byteLength + P.byteLength;
+ let I = new ArrayBuffer(sPlusPLength);
+ let iView = new Uint8Array(I);
+ iView.set(sView);
+ iView.set(pView, sView.length);
+ const c = Math.ceil((keyLength >> 3) / u);
+ let internalSequence = Promise.resolve(I);
+ for (let i = 0; i <= c; i++) {
+ internalSequence = internalSequence.then(_I => {
+ const dAndI = new ArrayBuffer(D.byteLength + _I.byteLength);
+ const dAndIView = new Uint8Array(dAndI);
+ dAndIView.set(dView);
+ dAndIView.set(iView, dView.length);
+ return dAndI;
+ });
+ for (let j = 0; j < iterationCount; j++)
+ internalSequence = internalSequence.then(roundBuffer => cryptoEngine.digest({ name: hashAlgorithm }, new Uint8Array(roundBuffer)));
+ internalSequence = internalSequence.then(roundBuffer => {
+ const B = new ArrayBuffer(v);
+ const bView = new Uint8Array(B);
+ for (let j = 0; j < B.byteLength; j++)
+ bView[j] = roundBuffer[j % roundBuffer.byteLength];
+ const k = Math.ceil(saltLength / v) + Math.ceil(passwordLength / v);
+ const iRound = [];
+ let sliceStart = 0;
+ let sliceLength = v;
+ for (let j = 0; j < k; j++) {
+ const chunk = Array.from(new Uint8Array(I.slice(sliceStart, sliceStart + sliceLength)));
+ sliceStart += v;
+ if ((sliceStart + v) > I.byteLength)
+ sliceLength = I.byteLength - sliceStart;
+ let x = 0x1ff;
+ for (let l = (B.byteLength - 1); l >= 0; l--) {
+ x >>= 8;
+ x += bView[l] + chunk[l];
+ chunk[l] = (x & 0xff);
+ }
+ iRound.push(...chunk);
+ }
+ I = new ArrayBuffer(iRound.length);
+ iView = new Uint8Array(I);
+ iView.set(iRound);
+ result.push(...(new Uint8Array(roundBuffer)));
+ return I;
+ });
+ }
+ internalSequence = internalSequence.then(() => {
+ const resultBuffer = new ArrayBuffer(keyLength >> 3);
+ const resultView = new Uint8Array(resultBuffer);
+ resultView.set((new Uint8Array(result)).slice(0, keyLength >> 3));
+ return resultBuffer;
+ });
+ return internalSequence;
+ });
+}
+function prepareAlgorithm(data) {
+ const res = typeof data === "string"
+ ? { name: data }
+ : data;
+ if ("hash" in res) {
+ return Object.assign(Object.assign({}, res), { hash: prepareAlgorithm(res.hash) });
+ }
+ return res;
+}
+class CryptoEngine extends AbstractCryptoEngine {
+ importKey(format, keyData, algorithm, extractable, keyUsages) {
+ var _a, _b, _c, _d, _e, _f;
+ return __awaiter(this, void 0, void 0, function* () {
+ let jwk = {};
+ const alg = prepareAlgorithm(algorithm);
+ switch (format.toLowerCase()) {
+ case "raw":
+ return this.subtle.importKey("raw", keyData, algorithm, extractable, keyUsages);
+ case "spki":
+ {
+ const asn1 = fromBER(BufferSourceConverter.toArrayBuffer(keyData));
+ AsnError.assert(asn1, "keyData");
+ const publicKeyInfo = new PublicKeyInfo();
+ try {
+ publicKeyInfo.fromSchema(asn1.result);
+ }
+ catch (_g) {
+ throw new ArgumentError("Incorrect keyData");
+ }
+ switch (alg.name.toUpperCase()) {
+ case "RSA-PSS":
+ {
+ if (!alg.hash) {
+ throw new ParameterError("hash", "algorithm.hash", "Incorrect hash algorithm: Hash algorithm is missed");
+ }
+ switch (alg.hash.name.toUpperCase()) {
+ case "SHA-1":
+ jwk.alg = "PS1";
+ break;
+ case "SHA-256":
+ jwk.alg = "PS256";
+ break;
+ case "SHA-384":
+ jwk.alg = "PS384";
+ break;
+ case "SHA-512":
+ jwk.alg = "PS512";
+ break;
+ default:
+ throw new Error(`Incorrect hash algorithm: ${alg.hash.name.toUpperCase()}`);
+ }
+ }
+ case "RSASSA-PKCS1-V1_5":
+ {
+ keyUsages = ["verify"];
+ jwk.kty = "RSA";
+ jwk.ext = extractable;
+ jwk.key_ops = keyUsages;
+ if (publicKeyInfo.algorithm.algorithmId !== "1.2.840.113549.1.1.1")
+ throw new Error(`Incorrect public key algorithm: ${publicKeyInfo.algorithm.algorithmId}`);
+ if (!jwk.alg) {
+ if (!alg.hash) {
+ throw new ParameterError("hash", "algorithm.hash", "Incorrect hash algorithm: Hash algorithm is missed");
+ }
+ switch (alg.hash.name.toUpperCase()) {
+ case "SHA-1":
+ jwk.alg = "RS1";
+ break;
+ case "SHA-256":
+ jwk.alg = "RS256";
+ break;
+ case "SHA-384":
+ jwk.alg = "RS384";
+ break;
+ case "SHA-512":
+ jwk.alg = "RS512";
+ break;
+ default:
+ throw new Error(`Incorrect hash algorithm: ${alg.hash.name.toUpperCase()}`);
+ }
+ }
+ const publicKeyJSON = publicKeyInfo.toJSON();
+ Object.assign(jwk, publicKeyJSON);
+ }
+ break;
+ case "ECDSA":
+ keyUsages = ["verify"];
+ case "ECDH":
+ {
+ jwk = {
+ kty: "EC",
+ ext: extractable,
+ key_ops: keyUsages
+ };
+ if (publicKeyInfo.algorithm.algorithmId !== "1.2.840.10045.2.1") {
+ throw new Error(`Incorrect public key algorithm: ${publicKeyInfo.algorithm.algorithmId}`);
+ }
+ const publicKeyJSON = publicKeyInfo.toJSON();
+ Object.assign(jwk, publicKeyJSON);
+ }
+ break;
+ case "RSA-OAEP":
+ {
+ jwk.kty = "RSA";
+ jwk.ext = extractable;
+ jwk.key_ops = keyUsages;
+ if (this.name.toLowerCase() === "safari")
+ jwk.alg = "RSA-OAEP";
+ else {
+ if (!alg.hash) {
+ throw new ParameterError("hash", "algorithm.hash", "Incorrect hash algorithm: Hash algorithm is missed");
+ }
+ switch (alg.hash.name.toUpperCase()) {
+ case "SHA-1":
+ jwk.alg = "RSA-OAEP";
+ break;
+ case "SHA-256":
+ jwk.alg = "RSA-OAEP-256";
+ break;
+ case "SHA-384":
+ jwk.alg = "RSA-OAEP-384";
+ break;
+ case "SHA-512":
+ jwk.alg = "RSA-OAEP-512";
+ break;
+ default:
+ throw new Error(`Incorrect hash algorithm: ${alg.hash.name.toUpperCase()}`);
+ }
+ }
+ const publicKeyJSON = publicKeyInfo.toJSON();
+ Object.assign(jwk, publicKeyJSON);
+ }
+ break;
+ case "RSAES-PKCS1-V1_5":
+ {
+ jwk.kty = "RSA";
+ jwk.ext = extractable;
+ jwk.key_ops = keyUsages;
+ jwk.alg = "PS1";
+ const publicKeyJSON = publicKeyInfo.toJSON();
+ Object.assign(jwk, publicKeyJSON);
+ }
+ break;
+ default:
+ throw new Error(`Incorrect algorithm name: ${alg.name.toUpperCase()}`);
+ }
+ }
+ break;
+ case "pkcs8":
+ {
+ const privateKeyInfo = new PrivateKeyInfo();
+ const asn1 = fromBER(BufferSourceConverter.toArrayBuffer(keyData));
+ AsnError.assert(asn1, "keyData");
+ try {
+ privateKeyInfo.fromSchema(asn1.result);
+ }
+ catch (ex) {
+ throw new Error("Incorrect keyData");
+ }
+ if (!privateKeyInfo.parsedKey)
+ throw new Error("Incorrect keyData");
+ switch (alg.name.toUpperCase()) {
+ case "RSA-PSS":
+ {
+ switch ((_a = alg.hash) === null || _a === void 0 ? void 0 : _a.name.toUpperCase()) {
+ case "SHA-1":
+ jwk.alg = "PS1";
+ break;
+ case "SHA-256":
+ jwk.alg = "PS256";
+ break;
+ case "SHA-384":
+ jwk.alg = "PS384";
+ break;
+ case "SHA-512":
+ jwk.alg = "PS512";
+ break;
+ default:
+ throw new Error(`Incorrect hash algorithm: ${(_b = alg.hash) === null || _b === void 0 ? void 0 : _b.name.toUpperCase()}`);
+ }
+ }
+ case "RSASSA-PKCS1-V1_5":
+ {
+ keyUsages = ["sign"];
+ jwk.kty = "RSA";
+ jwk.ext = extractable;
+ jwk.key_ops = keyUsages;
+ if (privateKeyInfo.privateKeyAlgorithm.algorithmId !== "1.2.840.113549.1.1.1")
+ throw new Error(`Incorrect private key algorithm: ${privateKeyInfo.privateKeyAlgorithm.algorithmId}`);
+ if (("alg" in jwk) === false) {
+ switch ((_c = alg.hash) === null || _c === void 0 ? void 0 : _c.name.toUpperCase()) {
+ case "SHA-1":
+ jwk.alg = "RS1";
+ break;
+ case "SHA-256":
+ jwk.alg = "RS256";
+ break;
+ case "SHA-384":
+ jwk.alg = "RS384";
+ break;
+ case "SHA-512":
+ jwk.alg = "RS512";
+ break;
+ default:
+ throw new Error(`Incorrect hash algorithm: ${(_d = alg.hash) === null || _d === void 0 ? void 0 : _d.name.toUpperCase()}`);
+ }
+ }
+ const privateKeyJSON = privateKeyInfo.toJSON();
+ Object.assign(jwk, privateKeyJSON);
+ }
+ break;
+ case "ECDSA":
+ keyUsages = ["sign"];
+ case "ECDH":
+ {
+ jwk = {
+ kty: "EC",
+ ext: extractable,
+ key_ops: keyUsages
+ };
+ if (privateKeyInfo.privateKeyAlgorithm.algorithmId !== "1.2.840.10045.2.1")
+ throw new Error(`Incorrect algorithm: ${privateKeyInfo.privateKeyAlgorithm.algorithmId}`);
+ const privateKeyJSON = privateKeyInfo.toJSON();
+ Object.assign(jwk, privateKeyJSON);
+ }
+ break;
+ case "RSA-OAEP":
+ {
+ jwk.kty = "RSA";
+ jwk.ext = extractable;
+ jwk.key_ops = keyUsages;
+ if (this.name.toLowerCase() === "safari")
+ jwk.alg = "RSA-OAEP";
+ else {
+ switch ((_e = alg.hash) === null || _e === void 0 ? void 0 : _e.name.toUpperCase()) {
+ case "SHA-1":
+ jwk.alg = "RSA-OAEP";
+ break;
+ case "SHA-256":
+ jwk.alg = "RSA-OAEP-256";
+ break;
+ case "SHA-384":
+ jwk.alg = "RSA-OAEP-384";
+ break;
+ case "SHA-512":
+ jwk.alg = "RSA-OAEP-512";
+ break;
+ default:
+ throw new Error(`Incorrect hash algorithm: ${(_f = alg.hash) === null || _f === void 0 ? void 0 : _f.name.toUpperCase()}`);
+ }
+ }
+ const privateKeyJSON = privateKeyInfo.toJSON();
+ Object.assign(jwk, privateKeyJSON);
+ }
+ break;
+ case "RSAES-PKCS1-V1_5":
+ {
+ keyUsages = ["decrypt"];
+ jwk.kty = "RSA";
+ jwk.ext = extractable;
+ jwk.key_ops = keyUsages;
+ jwk.alg = "PS1";
+ const privateKeyJSON = privateKeyInfo.toJSON();
+ Object.assign(jwk, privateKeyJSON);
+ }
+ break;
+ default:
+ throw new Error(`Incorrect algorithm name: ${alg.name.toUpperCase()}`);
+ }
+ }
+ break;
+ case "jwk":
+ jwk = keyData;
+ break;
+ default:
+ throw new Error(`Incorrect format: ${format}`);
+ }
+ if (this.name.toLowerCase() === "safari") {
+ try {
+ return this.subtle.importKey("jwk", stringToArrayBuffer(JSON.stringify(jwk)), algorithm, extractable, keyUsages);
+ }
+ catch (_h) {
+ return this.subtle.importKey("jwk", jwk, algorithm, extractable, keyUsages);
+ }
+ }
+ return this.subtle.importKey("jwk", jwk, algorithm, extractable, keyUsages);
+ });
+ }
+ exportKey(format, key) {
+ return __awaiter(this, void 0, void 0, function* () {
+ let jwk = yield this.subtle.exportKey("jwk", key);
+ if (this.name.toLowerCase() === "safari") {
+ if (jwk instanceof ArrayBuffer) {
+ jwk = JSON.parse(arrayBufferToString(jwk));
+ }
+ }
+ switch (format.toLowerCase()) {
+ case "raw":
+ return this.subtle.exportKey("raw", key);
+ case "spki": {
+ const publicKeyInfo = new PublicKeyInfo();
+ try {
+ publicKeyInfo.fromJSON(jwk);
+ }
+ catch (ex) {
+ throw new Error("Incorrect key data");
+ }
+ return publicKeyInfo.toSchema().toBER(false);
+ }
+ case "pkcs8": {
+ const privateKeyInfo = new PrivateKeyInfo();
+ try {
+ privateKeyInfo.fromJSON(jwk);
+ }
+ catch (ex) {
+ throw new Error("Incorrect key data");
+ }
+ return privateKeyInfo.toSchema().toBER(false);
+ }
+ case "jwk":
+ return jwk;
+ default:
+ throw new Error(`Incorrect format: ${format}`);
+ }
+ });
+ }
+ convert(inputFormat, outputFormat, keyData, algorithm, extractable, keyUsages) {
+ return __awaiter(this, void 0, void 0, function* () {
+ if (inputFormat.toLowerCase() === outputFormat.toLowerCase()) {
+ return keyData;
+ }
+ const key = yield this.importKey(inputFormat, keyData, algorithm, extractable, keyUsages);
+ return this.exportKey(outputFormat, key);
+ });
+ }
+ getAlgorithmByOID(oid, safety = false, target) {
+ switch (oid) {
+ case "1.2.840.113549.1.1.1":
+ return {
+ name: "RSAES-PKCS1-v1_5"
+ };
+ case "1.2.840.113549.1.1.5":
+ return {
+ name: "RSASSA-PKCS1-v1_5",
+ hash: {
+ name: "SHA-1"
+ }
+ };
+ case "1.2.840.113549.1.1.11":
+ return {
+ name: "RSASSA-PKCS1-v1_5",
+ hash: {
+ name: "SHA-256"
+ }
+ };
+ case "1.2.840.113549.1.1.12":
+ return {
+ name: "RSASSA-PKCS1-v1_5",
+ hash: {
+ name: "SHA-384"
+ }
+ };
+ case "1.2.840.113549.1.1.13":
+ return {
+ name: "RSASSA-PKCS1-v1_5",
+ hash: {
+ name: "SHA-512"
+ }
+ };
+ case "1.2.840.113549.1.1.10":
+ return {
+ name: "RSA-PSS"
+ };
+ case "1.2.840.113549.1.1.7":
+ return {
+ name: "RSA-OAEP"
+ };
+ case "1.2.840.10045.2.1":
+ case "1.2.840.10045.4.1":
+ return {
+ name: "ECDSA",
+ hash: {
+ name: "SHA-1"
+ }
+ };
+ case "1.2.840.10045.4.3.2":
+ return {
+ name: "ECDSA",
+ hash: {
+ name: "SHA-256"
+ }
+ };
+ case "1.2.840.10045.4.3.3":
+ return {
+ name: "ECDSA",
+ hash: {
+ name: "SHA-384"
+ }
+ };
+ case "1.2.840.10045.4.3.4":
+ return {
+ name: "ECDSA",
+ hash: {
+ name: "SHA-512"
+ }
+ };
+ case "1.3.133.16.840.63.0.2":
+ return {
+ name: "ECDH",
+ kdf: "SHA-1"
+ };
+ case "1.3.132.1.11.1":
+ return {
+ name: "ECDH",
+ kdf: "SHA-256"
+ };
+ case "1.3.132.1.11.2":
+ return {
+ name: "ECDH",
+ kdf: "SHA-384"
+ };
+ case "1.3.132.1.11.3":
+ return {
+ name: "ECDH",
+ kdf: "SHA-512"
+ };
+ case "2.16.840.1.101.3.4.1.2":
+ return {
+ name: "AES-CBC",
+ length: 128
+ };
+ case "2.16.840.1.101.3.4.1.22":
+ return {
+ name: "AES-CBC",
+ length: 192
+ };
+ case "2.16.840.1.101.3.4.1.42":
+ return {
+ name: "AES-CBC",
+ length: 256
+ };
+ case "2.16.840.1.101.3.4.1.6":
+ return {
+ name: "AES-GCM",
+ length: 128
+ };
+ case "2.16.840.1.101.3.4.1.26":
+ return {
+ name: "AES-GCM",
+ length: 192
+ };
+ case "2.16.840.1.101.3.4.1.46":
+ return {
+ name: "AES-GCM",
+ length: 256
+ };
+ case "2.16.840.1.101.3.4.1.4":
+ return {
+ name: "AES-CFB",
+ length: 128
+ };
+ case "2.16.840.1.101.3.4.1.24":
+ return {
+ name: "AES-CFB",
+ length: 192
+ };
+ case "2.16.840.1.101.3.4.1.44":
+ return {
+ name: "AES-CFB",
+ length: 256
+ };
+ case "2.16.840.1.101.3.4.1.5":
+ return {
+ name: "AES-KW",
+ length: 128
+ };
+ case "2.16.840.1.101.3.4.1.25":
+ return {
+ name: "AES-KW",
+ length: 192
+ };
+ case "2.16.840.1.101.3.4.1.45":
+ return {
+ name: "AES-KW",
+ length: 256
+ };
+ case "1.2.840.113549.2.7":
+ return {
+ name: "HMAC",
+ hash: {
+ name: "SHA-1"
+ }
+ };
+ case "1.2.840.113549.2.9":
+ return {
+ name: "HMAC",
+ hash: {
+ name: "SHA-256"
+ }
+ };
+ case "1.2.840.113549.2.10":
+ return {
+ name: "HMAC",
+ hash: {
+ name: "SHA-384"
+ }
+ };
+ case "1.2.840.113549.2.11":
+ return {
+ name: "HMAC",
+ hash: {
+ name: "SHA-512"
+ }
+ };
+ case "1.2.840.113549.1.9.16.3.5":
+ return {
+ name: "DH"
+ };
+ case "1.3.14.3.2.26":
+ return {
+ name: "SHA-1"
+ };
+ case "2.16.840.1.101.3.4.2.1":
+ return {
+ name: "SHA-256"
+ };
+ case "2.16.840.1.101.3.4.2.2":
+ return {
+ name: "SHA-384"
+ };
+ case "2.16.840.1.101.3.4.2.3":
+ return {
+ name: "SHA-512"
+ };
+ case "1.2.840.113549.1.5.12":
+ return {
+ name: "PBKDF2"
+ };
+ case "1.2.840.10045.3.1.7":
+ return {
+ name: "P-256"
+ };
+ case "1.3.132.0.34":
+ return {
+ name: "P-384"
+ };
+ case "1.3.132.0.35":
+ return {
+ name: "P-521"
+ };
+ }
+ if (safety) {
+ throw new Error(`Unsupported algorithm identifier ${target ? `for ${target} ` : EMPTY_STRING}: ${oid}`);
+ }
+ return {};
+ }
+ getOIDByAlgorithm(algorithm, safety = false, target) {
+ let result = EMPTY_STRING;
+ switch (algorithm.name.toUpperCase()) {
+ case "RSAES-PKCS1-V1_5":
+ result = "1.2.840.113549.1.1.1";
+ break;
+ case "RSASSA-PKCS1-V1_5":
+ switch (algorithm.hash.name.toUpperCase()) {
+ case "SHA-1":
+ result = "1.2.840.113549.1.1.5";
+ break;
+ case "SHA-256":
+ result = "1.2.840.113549.1.1.11";
+ break;
+ case "SHA-384":
+ result = "1.2.840.113549.1.1.12";
+ break;
+ case "SHA-512":
+ result = "1.2.840.113549.1.1.13";
+ break;
+ }
+ break;
+ case "RSA-PSS":
+ result = "1.2.840.113549.1.1.10";
+ break;
+ case "RSA-OAEP":
+ result = "1.2.840.113549.1.1.7";
+ break;
+ case "ECDSA":
+ switch (algorithm.hash.name.toUpperCase()) {
+ case "SHA-1":
+ result = "1.2.840.10045.4.1";
+ break;
+ case "SHA-256":
+ result = "1.2.840.10045.4.3.2";
+ break;
+ case "SHA-384":
+ result = "1.2.840.10045.4.3.3";
+ break;
+ case "SHA-512":
+ result = "1.2.840.10045.4.3.4";
+ break;
+ }
+ break;
+ case "ECDH":
+ switch (algorithm.kdf.toUpperCase()) {
+ case "SHA-1":
+ result = "1.3.133.16.840.63.0.2";
+ break;
+ case "SHA-256":
+ result = "1.3.132.1.11.1";
+ break;
+ case "SHA-384":
+ result = "1.3.132.1.11.2";
+ break;
+ case "SHA-512":
+ result = "1.3.132.1.11.3";
+ break;
+ }
+ break;
+ case "AES-CTR":
+ break;
+ case "AES-CBC":
+ switch (algorithm.length) {
+ case 128:
+ result = "2.16.840.1.101.3.4.1.2";
+ break;
+ case 192:
+ result = "2.16.840.1.101.3.4.1.22";
+ break;
+ case 256:
+ result = "2.16.840.1.101.3.4.1.42";
+ break;
+ }
+ break;
+ case "AES-CMAC":
+ break;
+ case "AES-GCM":
+ switch (algorithm.length) {
+ case 128:
+ result = "2.16.840.1.101.3.4.1.6";
+ break;
+ case 192:
+ result = "2.16.840.1.101.3.4.1.26";
+ break;
+ case 256:
+ result = "2.16.840.1.101.3.4.1.46";
+ break;
+ }
+ break;
+ case "AES-CFB":
+ switch (algorithm.length) {
+ case 128:
+ result = "2.16.840.1.101.3.4.1.4";
+ break;
+ case 192:
+ result = "2.16.840.1.101.3.4.1.24";
+ break;
+ case 256:
+ result = "2.16.840.1.101.3.4.1.44";
+ break;
+ }
+ break;
+ case "AES-KW":
+ switch (algorithm.length) {
+ case 128:
+ result = "2.16.840.1.101.3.4.1.5";
+ break;
+ case 192:
+ result = "2.16.840.1.101.3.4.1.25";
+ break;
+ case 256:
+ result = "2.16.840.1.101.3.4.1.45";
+ break;
+ }
+ break;
+ case "HMAC":
+ switch (algorithm.hash.name.toUpperCase()) {
+ case "SHA-1":
+ result = "1.2.840.113549.2.7";
+ break;
+ case "SHA-256":
+ result = "1.2.840.113549.2.9";
+ break;
+ case "SHA-384":
+ result = "1.2.840.113549.2.10";
+ break;
+ case "SHA-512":
+ result = "1.2.840.113549.2.11";
+ break;
+ }
+ break;
+ case "DH":
+ result = "1.2.840.113549.1.9.16.3.5";
+ break;
+ case "SHA-1":
+ result = "1.3.14.3.2.26";
+ break;
+ case "SHA-256":
+ result = "2.16.840.1.101.3.4.2.1";
+ break;
+ case "SHA-384":
+ result = "2.16.840.1.101.3.4.2.2";
+ break;
+ case "SHA-512":
+ result = "2.16.840.1.101.3.4.2.3";
+ break;
+ case "CONCAT":
+ break;
+ case "HKDF":
+ break;
+ case "PBKDF2":
+ result = "1.2.840.113549.1.5.12";
+ break;
+ case "P-256":
+ result = "1.2.840.10045.3.1.7";
+ break;
+ case "P-384":
+ result = "1.3.132.0.34";
+ break;
+ case "P-521":
+ result = "1.3.132.0.35";
+ break;
+ }
+ if (!result && safety) {
+ throw new Error(`Unsupported algorithm ${target ? `for ${target} ` : EMPTY_STRING}: ${algorithm.name}`);
+ }
+ return result;
+ }
+ getAlgorithmParameters(algorithmName, operation) {
+ let result = {
+ algorithm: {},
+ usages: []
+ };
+ switch (algorithmName.toUpperCase()) {
+ case "RSAES-PKCS1-V1_5":
+ case "RSASSA-PKCS1-V1_5":
+ switch (operation.toLowerCase()) {
+ case "generatekey":
+ result = {
+ algorithm: {
+ name: "RSASSA-PKCS1-v1_5",
+ modulusLength: 2048,
+ publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
+ hash: {
+ name: "SHA-256"
+ }
+ },
+ usages: ["sign", "verify"]
+ };
+ break;
+ case "verify":
+ case "sign":
+ case "importkey":
+ result = {
+ algorithm: {
+ name: "RSASSA-PKCS1-v1_5",
+ hash: {
+ name: "SHA-256"
+ }
+ },
+ usages: ["verify"]
+ };
+ break;
+ case "exportkey":
+ default:
+ return {
+ algorithm: {
+ name: "RSASSA-PKCS1-v1_5"
+ },
+ usages: []
+ };
+ }
+ break;
+ case "RSA-PSS":
+ switch (operation.toLowerCase()) {
+ case "sign":
+ case "verify":
+ result = {
+ algorithm: {
+ name: "RSA-PSS",
+ hash: {
+ name: "SHA-1"
+ },
+ saltLength: 20
+ },
+ usages: ["sign", "verify"]
+ };
+ break;
+ case "generatekey":
+ result = {
+ algorithm: {
+ name: "RSA-PSS",
+ modulusLength: 2048,
+ publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
+ hash: {
+ name: "SHA-1"
+ }
+ },
+ usages: ["sign", "verify"]
+ };
+ break;
+ case "importkey":
+ result = {
+ algorithm: {
+ name: "RSA-PSS",
+ hash: {
+ name: "SHA-1"
+ }
+ },
+ usages: ["verify"]
+ };
+ break;
+ case "exportkey":
+ default:
+ return {
+ algorithm: {
+ name: "RSA-PSS"
+ },
+ usages: []
+ };
+ }
+ break;
+ case "RSA-OAEP":
+ switch (operation.toLowerCase()) {
+ case "encrypt":
+ case "decrypt":
+ result = {
+ algorithm: {
+ name: "RSA-OAEP"
+ },
+ usages: ["encrypt", "decrypt"]
+ };
+ break;
+ case "generatekey":
+ result = {
+ algorithm: {
+ name: "RSA-OAEP",
+ modulusLength: 2048,
+ publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
+ hash: {
+ name: "SHA-256"
+ }
+ },
+ usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"]
+ };
+ break;
+ case "importkey":
+ result = {
+ algorithm: {
+ name: "RSA-OAEP",
+ hash: {
+ name: "SHA-256"
+ }
+ },
+ usages: ["encrypt"]
+ };
+ break;
+ case "exportkey":
+ default:
+ return {
+ algorithm: {
+ name: "RSA-OAEP"
+ },
+ usages: []
+ };
+ }
+ break;
+ case "ECDSA":
+ switch (operation.toLowerCase()) {
+ case "generatekey":
+ result = {
+ algorithm: {
+ name: "ECDSA",
+ namedCurve: "P-256"
+ },
+ usages: ["sign", "verify"]
+ };
+ break;
+ case "importkey":
+ result = {
+ algorithm: {
+ name: "ECDSA",
+ namedCurve: "P-256"
+ },
+ usages: ["verify"]
+ };
+ break;
+ case "verify":
+ case "sign":
+ result = {
+ algorithm: {
+ name: "ECDSA",
+ hash: {
+ name: "SHA-256"
+ }
+ },
+ usages: ["sign"]
+ };
+ break;
+ default:
+ return {
+ algorithm: {
+ name: "ECDSA"
+ },
+ usages: []
+ };
+ }
+ break;
+ case "ECDH":
+ switch (operation.toLowerCase()) {
+ case "exportkey":
+ case "importkey":
+ case "generatekey":
+ result = {
+ algorithm: {
+ name: "ECDH",
+ namedCurve: "P-256"
+ },
+ usages: ["deriveKey", "deriveBits"]
+ };
+ break;
+ case "derivekey":
+ case "derivebits":
+ result = {
+ algorithm: {
+ name: "ECDH",
+ namedCurve: "P-256",
+ public: []
+ },
+ usages: ["encrypt", "decrypt"]
+ };
+ break;
+ default:
+ return {
+ algorithm: {
+ name: "ECDH"
+ },
+ usages: []
+ };
+ }
+ break;
+ case "AES-CTR":
+ switch (operation.toLowerCase()) {
+ case "importkey":
+ case "exportkey":
+ case "generatekey":
+ result = {
+ algorithm: {
+ name: "AES-CTR",
+ length: 256
+ },
+ usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"]
+ };
+ break;
+ case "decrypt":
+ case "encrypt":
+ result = {
+ algorithm: {
+ name: "AES-CTR",
+ counter: new Uint8Array(16),
+ length: 10
+ },
+ usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"]
+ };
+ break;
+ default:
+ return {
+ algorithm: {
+ name: "AES-CTR"
+ },
+ usages: []
+ };
+ }
+ break;
+ case "AES-CBC":
+ switch (operation.toLowerCase()) {
+ case "importkey":
+ case "exportkey":
+ case "generatekey":
+ result = {
+ algorithm: {
+ name: "AES-CBC",
+ length: 256
+ },
+ usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"]
+ };
+ break;
+ case "decrypt":
+ case "encrypt":
+ result = {
+ algorithm: {
+ name: "AES-CBC",
+ iv: this.getRandomValues(new Uint8Array(16))
+ },
+ usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"]
+ };
+ break;
+ default:
+ return {
+ algorithm: {
+ name: "AES-CBC"
+ },
+ usages: []
+ };
+ }
+ break;
+ case "AES-GCM":
+ switch (operation.toLowerCase()) {
+ case "importkey":
+ case "exportkey":
+ case "generatekey":
+ result = {
+ algorithm: {
+ name: "AES-GCM",
+ length: 256
+ },
+ usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"]
+ };
+ break;
+ case "decrypt":
+ case "encrypt":
+ result = {
+ algorithm: {
+ name: "AES-GCM",
+ iv: this.getRandomValues(new Uint8Array(16))
+ },
+ usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"]
+ };
+ break;
+ default:
+ return {
+ algorithm: {
+ name: "AES-GCM"
+ },
+ usages: []
+ };
+ }
+ break;
+ case "AES-KW":
+ switch (operation.toLowerCase()) {
+ case "importkey":
+ case "exportkey":
+ case "generatekey":
+ case "wrapkey":
+ case "unwrapkey":
+ result = {
+ algorithm: {
+ name: "AES-KW",
+ length: 256
+ },
+ usages: ["wrapKey", "unwrapKey"]
+ };
+ break;
+ default:
+ return {
+ algorithm: {
+ name: "AES-KW"
+ },
+ usages: []
+ };
+ }
+ break;
+ case "HMAC":
+ switch (operation.toLowerCase()) {
+ case "sign":
+ case "verify":
+ result = {
+ algorithm: {
+ name: "HMAC"
+ },
+ usages: ["sign", "verify"]
+ };
+ break;
+ case "importkey":
+ case "exportkey":
+ case "generatekey":
+ result = {
+ algorithm: {
+ name: "HMAC",
+ length: 32,
+ hash: {
+ name: "SHA-256"
+ }
+ },
+ usages: ["sign", "verify"]
+ };
+ break;
+ default:
+ return {
+ algorithm: {
+ name: "HMAC"
+ },
+ usages: []
+ };
+ }
+ break;
+ case "HKDF":
+ switch (operation.toLowerCase()) {
+ case "derivekey":
+ result = {
+ algorithm: {
+ name: "HKDF",
+ hash: "SHA-256",
+ salt: new Uint8Array([]),
+ info: new Uint8Array([])
+ },
+ usages: ["encrypt", "decrypt"]
+ };
+ break;
+ default:
+ return {
+ algorithm: {
+ name: "HKDF"
+ },
+ usages: []
+ };
+ }
+ break;
+ case "PBKDF2":
+ switch (operation.toLowerCase()) {
+ case "derivekey":
+ result = {
+ algorithm: {
+ name: "PBKDF2",
+ hash: { name: "SHA-256" },
+ salt: new Uint8Array([]),
+ iterations: 10000
+ },
+ usages: ["encrypt", "decrypt"]
+ };
+ break;
+ default:
+ return {
+ algorithm: {
+ name: "PBKDF2"
+ },
+ usages: []
+ };
+ }
+ break;
+ }
+ return result;
+ }
+ getHashAlgorithm(signatureAlgorithm) {
+ let result = EMPTY_STRING;
+ switch (signatureAlgorithm.algorithmId) {
+ case "1.2.840.10045.4.1":
+ case "1.2.840.113549.1.1.5":
+ result = "SHA-1";
+ break;
+ case "1.2.840.10045.4.3.2":
+ case "1.2.840.113549.1.1.11":
+ result = "SHA-256";
+ break;
+ case "1.2.840.10045.4.3.3":
+ case "1.2.840.113549.1.1.12":
+ result = "SHA-384";
+ break;
+ case "1.2.840.10045.4.3.4":
+ case "1.2.840.113549.1.1.13":
+ result = "SHA-512";
+ break;
+ case "1.2.840.113549.1.1.10":
+ {
+ try {
+ const params = new RSASSAPSSParams({ schema: signatureAlgorithm.algorithmParams });
+ if (params.hashAlgorithm) {
+ const algorithm = this.getAlgorithmByOID(params.hashAlgorithm.algorithmId);
+ if ("name" in algorithm) {
+ result = algorithm.name;
+ }
+ else {
+ return EMPTY_STRING;
+ }
+ }
+ else
+ result = "SHA-1";
+ }
+ catch (_a) {
+ }
+ }
+ break;
+ }
+ return result;
+ }
+ encryptEncryptedContentInfo(parameters) {
+ return __awaiter(this, void 0, void 0, function* () {
+ ParameterError.assert(parameters, "password", "contentEncryptionAlgorithm", "hmacHashAlgorithm", "iterationCount", "contentToEncrypt", "contentToEncrypt", "contentType");
+ const contentEncryptionOID = this.getOIDByAlgorithm(parameters.contentEncryptionAlgorithm, true, "contentEncryptionAlgorithm");
+ const pbkdf2OID = this.getOIDByAlgorithm({
+ name: "PBKDF2"
+ }, true, "PBKDF2");
+ const hmacOID = this.getOIDByAlgorithm({
+ name: "HMAC",
+ hash: {
+ name: parameters.hmacHashAlgorithm
+ }
+ }, true, "hmacHashAlgorithm");
+ const ivBuffer = new ArrayBuffer(16);
+ const ivView = new Uint8Array(ivBuffer);
+ this.getRandomValues(ivView);
+ const saltBuffer = new ArrayBuffer(64);
+ const saltView = new Uint8Array(saltBuffer);
+ this.getRandomValues(saltView);
+ const contentView = new Uint8Array(parameters.contentToEncrypt);
+ const pbkdf2Params = new PBKDF2Params({
+ salt: new OctetString({ valueHex: saltBuffer }),
+ iterationCount: parameters.iterationCount,
+ prf: new AlgorithmIdentifier({
+ algorithmId: hmacOID,
+ algorithmParams: new Null()
+ })
+ });
+ const passwordView = new Uint8Array(parameters.password);
+ const pbkdfKey = yield this.importKey("raw", passwordView, "PBKDF2", false, ["deriveKey"]);
+ const derivedKey = yield this.deriveKey({
+ name: "PBKDF2",
+ hash: {
+ name: parameters.hmacHashAlgorithm
+ },
+ salt: saltView,
+ iterations: parameters.iterationCount
+ }, pbkdfKey, parameters.contentEncryptionAlgorithm, false, ["encrypt"]);
+ const encryptedData = yield this.encrypt({
+ name: parameters.contentEncryptionAlgorithm.name,
+ iv: ivView
+ }, derivedKey, contentView);
+ const pbes2Parameters = new PBES2Params({
+ keyDerivationFunc: new AlgorithmIdentifier({
+ algorithmId: pbkdf2OID,
+ algorithmParams: pbkdf2Params.toSchema()
+ }),
+ encryptionScheme: new AlgorithmIdentifier({
+ algorithmId: contentEncryptionOID,
+ algorithmParams: new OctetString({ valueHex: ivBuffer })
+ })
+ });
+ return new EncryptedContentInfo({
+ contentType: parameters.contentType,
+ contentEncryptionAlgorithm: new AlgorithmIdentifier({
+ algorithmId: "1.2.840.113549.1.5.13",
+ algorithmParams: pbes2Parameters.toSchema()
+ }),
+ encryptedContent: new OctetString({ valueHex: encryptedData })
+ });
+ });
+ }
+ decryptEncryptedContentInfo(parameters) {
+ return __awaiter(this, void 0, void 0, function* () {
+ ParameterError.assert(parameters, "password", "encryptedContentInfo");
+ if (parameters.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId !== "1.2.840.113549.1.5.13")
+ throw new Error(`Unknown "contentEncryptionAlgorithm": ${parameters.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId}`);
+ let pbes2Parameters;
+ try {
+ pbes2Parameters = new PBES2Params({ schema: parameters.encryptedContentInfo.contentEncryptionAlgorithm.algorithmParams });
+ }
+ catch (ex) {
+ throw new Error("Incorrectly encoded \"pbes2Parameters\"");
+ }
+ let pbkdf2Params;
+ try {
+ pbkdf2Params = new PBKDF2Params({ schema: pbes2Parameters.keyDerivationFunc.algorithmParams });
+ }
+ catch (ex) {
+ throw new Error("Incorrectly encoded \"pbkdf2Params\"");
+ }
+ const contentEncryptionAlgorithm = this.getAlgorithmByOID(pbes2Parameters.encryptionScheme.algorithmId, true);
+ const ivBuffer = pbes2Parameters.encryptionScheme.algorithmParams.valueBlock.valueHex;
+ const ivView = new Uint8Array(ivBuffer);
+ const saltBuffer = pbkdf2Params.salt.valueBlock.valueHex;
+ const saltView = new Uint8Array(saltBuffer);
+ const iterationCount = pbkdf2Params.iterationCount;
+ let hmacHashAlgorithm = "SHA-1";
+ if (pbkdf2Params.prf) {
+ const algorithm = this.getAlgorithmByOID(pbkdf2Params.prf.algorithmId, true);
+ hmacHashAlgorithm = algorithm.hash.name;
+ }
+ const pbkdfKey = yield this.importKey("raw", parameters.password, "PBKDF2", false, ["deriveKey"]);
+ const result = yield this.deriveKey({
+ name: "PBKDF2",
+ hash: {
+ name: hmacHashAlgorithm
+ },
+ salt: saltView,
+ iterations: iterationCount
+ }, pbkdfKey, contentEncryptionAlgorithm, false, ["decrypt"]);
+ const dataBuffer = parameters.encryptedContentInfo.getEncryptedContent();
+ return this.decrypt({
+ name: contentEncryptionAlgorithm.name,
+ iv: ivView
+ }, result, dataBuffer);
+ });
+ }
+ stampDataWithPassword(parameters) {
+ return __awaiter(this, void 0, void 0, function* () {
+ if ((parameters instanceof Object) === false)
+ throw new Error("Parameters must have type \"Object\"");
+ ParameterError.assert(parameters, "password", "hashAlgorithm", "iterationCount", "salt", "contentToStamp");
+ let length;
+ switch (parameters.hashAlgorithm.toLowerCase()) {
+ case "sha-1":
+ length = 160;
+ break;
+ case "sha-256":
+ length = 256;
+ break;
+ case "sha-384":
+ length = 384;
+ break;
+ case "sha-512":
+ length = 512;
+ break;
+ default:
+ throw new Error(`Incorrect "parameters.hashAlgorithm" parameter: ${parameters.hashAlgorithm}`);
+ }
+ const hmacAlgorithm = {
+ name: "HMAC",
+ length,
+ hash: {
+ name: parameters.hashAlgorithm
+ }
+ };
+ const pkcsKey = yield makePKCS12B2Key(this, parameters.hashAlgorithm, length, parameters.password, parameters.salt, parameters.iterationCount);
+ const hmacKey = yield this.importKey("raw", new Uint8Array(pkcsKey), hmacAlgorithm, false, ["sign"]);
+ return this.sign(hmacAlgorithm, hmacKey, new Uint8Array(parameters.contentToStamp));
+ });
+ }
+ verifyDataStampedWithPassword(parameters) {
+ return __awaiter(this, void 0, void 0, function* () {
+ ParameterError.assert(parameters, "password", "hashAlgorithm", "salt", "iterationCount", "contentToVerify", "signatureToVerify");
+ let length = 0;
+ switch (parameters.hashAlgorithm.toLowerCase()) {
+ case "sha-1":
+ length = 160;
+ break;
+ case "sha-256":
+ length = 256;
+ break;
+ case "sha-384":
+ length = 384;
+ break;
+ case "sha-512":
+ length = 512;
+ break;
+ default:
+ throw new Error(`Incorrect "parameters.hashAlgorithm" parameter: ${parameters.hashAlgorithm}`);
+ }
+ const hmacAlgorithm = {
+ name: "HMAC",
+ length,
+ hash: {
+ name: parameters.hashAlgorithm
+ }
+ };
+ const pkcsKey = yield makePKCS12B2Key(this, parameters.hashAlgorithm, length, parameters.password, parameters.salt, parameters.iterationCount);
+ const hmacKey = yield this.importKey("raw", new Uint8Array(pkcsKey), hmacAlgorithm, false, ["verify"]);
+ return this.verify(hmacAlgorithm, hmacKey, new Uint8Array(parameters.signatureToVerify), new Uint8Array(parameters.contentToVerify));
+ });
+ }
+ getSignatureParameters(privateKey, hashAlgorithm = "SHA-1") {
+ return __awaiter(this, void 0, void 0, function* () {
+ this.getOIDByAlgorithm({ name: hashAlgorithm }, true, "hashAlgorithm");
+ const signatureAlgorithm = new AlgorithmIdentifier();
+ const parameters = this.getAlgorithmParameters(privateKey.algorithm.name, "sign");
+ if (!Object.keys(parameters.algorithm).length) {
+ throw new Error("Parameter 'algorithm' is empty");
+ }
+ const algorithm = parameters.algorithm;
+ algorithm.hash.name = hashAlgorithm;
+ switch (privateKey.algorithm.name.toUpperCase()) {
+ case "RSASSA-PKCS1-V1_5":
+ case "ECDSA":
+ signatureAlgorithm.algorithmId = this.getOIDByAlgorithm(algorithm, true);
+ break;
+ case "RSA-PSS":
+ {
+ switch (hashAlgorithm.toUpperCase()) {
+ case "SHA-256":
+ algorithm.saltLength = 32;
+ break;
+ case "SHA-384":
+ algorithm.saltLength = 48;
+ break;
+ case "SHA-512":
+ algorithm.saltLength = 64;
+ break;
+ }
+ const paramsObject = {};
+ if (hashAlgorithm.toUpperCase() !== "SHA-1") {
+ const hashAlgorithmOID = this.getOIDByAlgorithm({ name: hashAlgorithm }, true, "hashAlgorithm");
+ paramsObject.hashAlgorithm = new AlgorithmIdentifier({
+ algorithmId: hashAlgorithmOID,
+ algorithmParams: new Null()
+ });
+ paramsObject.maskGenAlgorithm = new AlgorithmIdentifier({
+ algorithmId: "1.2.840.113549.1.1.8",
+ algorithmParams: paramsObject.hashAlgorithm.toSchema()
+ });
+ }
+ if (algorithm.saltLength !== 20)
+ paramsObject.saltLength = algorithm.saltLength;
+ const pssParameters = new RSASSAPSSParams(paramsObject);
+ signatureAlgorithm.algorithmId = "1.2.840.113549.1.1.10";
+ signatureAlgorithm.algorithmParams = pssParameters.toSchema();
+ }
+ break;
+ default:
+ throw new Error(`Unsupported signature algorithm: ${privateKey.algorithm.name}`);
+ }
+ return {
+ signatureAlgorithm,
+ parameters
+ };
+ });
+ }
+ signWithPrivateKey(data, privateKey, parameters) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const signature = yield this.sign(parameters.algorithm, privateKey, data);
+ if (parameters.algorithm.name === "ECDSA") {
+ return createCMSECDSASignature(signature);
+ }
+ return signature;
+ });
+ }
+ fillPublicKeyParameters(publicKeyInfo, signatureAlgorithm) {
+ const parameters = {};
+ const shaAlgorithm = this.getHashAlgorithm(signatureAlgorithm);
+ if (shaAlgorithm === EMPTY_STRING)
+ throw new Error(`Unsupported signature algorithm: ${signatureAlgorithm.algorithmId}`);
+ let algorithmId;
+ if (signatureAlgorithm.algorithmId === "1.2.840.113549.1.1.10")
+ algorithmId = signatureAlgorithm.algorithmId;
+ else
+ algorithmId = publicKeyInfo.algorithm.algorithmId;
+ const algorithmObject = this.getAlgorithmByOID(algorithmId, true);
+ parameters.algorithm = this.getAlgorithmParameters(algorithmObject.name, "importKey");
+ if ("hash" in parameters.algorithm.algorithm)
+ parameters.algorithm.algorithm.hash.name = shaAlgorithm;
+ if (algorithmObject.name === "ECDSA") {
+ const publicKeyAlgorithm = publicKeyInfo.algorithm;
+ if (!publicKeyAlgorithm.algorithmParams) {
+ throw new Error("Algorithm parameters for ECDSA public key are missed");
+ }
+ const publicKeyAlgorithmParams = publicKeyAlgorithm.algorithmParams;
+ if ("idBlock" in publicKeyAlgorithm.algorithmParams) {
+ if (!((publicKeyAlgorithmParams.idBlock.tagClass === 1) && (publicKeyAlgorithmParams.idBlock.tagNumber === 6))) {
+ throw new Error("Incorrect type for ECDSA public key parameters");
+ }
+ }
+ const curveObject = this.getAlgorithmByOID(publicKeyAlgorithmParams.valueBlock.toString(), true);
+ parameters.algorithm.algorithm.namedCurve = curveObject.name;
+ }
+ return parameters;
+ }
+ getPublicKey(publicKeyInfo, signatureAlgorithm, parameters) {
+ return __awaiter(this, void 0, void 0, function* () {
+ if (!parameters) {
+ parameters = this.fillPublicKeyParameters(publicKeyInfo, signatureAlgorithm);
+ }
+ const publicKeyInfoBuffer = publicKeyInfo.toSchema().toBER(false);
+ return this.importKey("spki", publicKeyInfoBuffer, parameters.algorithm.algorithm, true, parameters.algorithm.usages);
+ });
+ }
+ verifyWithPublicKey(data, signature, publicKeyInfo, signatureAlgorithm, shaAlgorithm) {
+ return __awaiter(this, void 0, void 0, function* () {
+ let publicKey;
+ if (!shaAlgorithm) {
+ shaAlgorithm = this.getHashAlgorithm(signatureAlgorithm);
+ if (!shaAlgorithm)
+ throw new Error(`Unsupported signature algorithm: ${signatureAlgorithm.algorithmId}`);
+ publicKey = yield this.getPublicKey(publicKeyInfo, signatureAlgorithm);
+ }
+ else {
+ const parameters = {};
+ let algorithmId;
+ if (signatureAlgorithm.algorithmId === "1.2.840.113549.1.1.10")
+ algorithmId = signatureAlgorithm.algorithmId;
+ else
+ algorithmId = publicKeyInfo.algorithm.algorithmId;
+ const algorithmObject = this.getAlgorithmByOID(algorithmId, true);
+ parameters.algorithm = this.getAlgorithmParameters(algorithmObject.name, "importKey");
+ if ("hash" in parameters.algorithm.algorithm)
+ parameters.algorithm.algorithm.hash.name = shaAlgorithm;
+ if (algorithmObject.name === "ECDSA") {
+ let algorithmParamsChecked = false;
+ if (("algorithmParams" in publicKeyInfo.algorithm) === true) {
+ if ("idBlock" in publicKeyInfo.algorithm.algorithmParams) {
+ if ((publicKeyInfo.algorithm.algorithmParams.idBlock.tagClass === 1) && (publicKeyInfo.algorithm.algorithmParams.idBlock.tagNumber === 6))
+ algorithmParamsChecked = true;
+ }
+ }
+ if (algorithmParamsChecked === false) {
+ throw new Error("Incorrect type for ECDSA public key parameters");
+ }
+ const curveObject = this.getAlgorithmByOID(publicKeyInfo.algorithm.algorithmParams.valueBlock.toString(), true);
+ parameters.algorithm.algorithm.namedCurve = curveObject.name;
+ }
+ publicKey = yield this.getPublicKey(publicKeyInfo, null, parameters);
+ }
+ const algorithm = this.getAlgorithmParameters(publicKey.algorithm.name, "verify");
+ if ("hash" in algorithm.algorithm)
+ algorithm.algorithm.hash.name = shaAlgorithm;
+ let signatureValue = signature.valueBlock.valueHexView;
+ if (publicKey.algorithm.name === "ECDSA") {
+ const namedCurve = ECNamedCurves.find(publicKey.algorithm.namedCurve);
+ if (!namedCurve) {
+ throw new Error("Unsupported named curve in use");
+ }
+ const asn1 = fromBER(signatureValue);
+ AsnError.assert(asn1, "Signature value");
+ signatureValue = createECDSASignatureFromCMS(asn1.result, namedCurve.size);
+ }
+ if (publicKey.algorithm.name === "RSA-PSS") {
+ const pssParameters = new RSASSAPSSParams({ schema: signatureAlgorithm.algorithmParams });
+ if ("saltLength" in pssParameters)
+ algorithm.algorithm.saltLength = pssParameters.saltLength;
+ else
+ algorithm.algorithm.saltLength = 20;
+ let hashAlgo = "SHA-1";
+ if ("hashAlgorithm" in pssParameters) {
+ const hashAlgorithm = this.getAlgorithmByOID(pssParameters.hashAlgorithm.algorithmId, true);
+ hashAlgo = hashAlgorithm.name;
+ }
+ algorithm.algorithm.hash.name = hashAlgo;
+ }
+ return this.verify(algorithm.algorithm, publicKey, signatureValue, data);
+ });
+ }
+}
+
+let engine = {
+ name: "none",
+ crypto: null,
+};
+function isCryptoEngine(engine) {
+ return engine
+ && typeof engine === "object"
+ && "crypto" in engine
+ ? true
+ : false;
+}
+function setEngine(name, ...args) {
+ let crypto = null;
+ if (args.length < 2) {
+ if (args.length) {
+ crypto = args[0];
+ }
+ else {
+ crypto = typeof self !== "undefined" && self.crypto ? new CryptoEngine({ name: "browser", crypto: self.crypto }) : null;
+ }
+ }
+ else {
+ const cryptoArg = args[0];
+ const subtleArg = args[1];
+ if (isCryptoEngine(subtleArg)) {
+ crypto = subtleArg;
+ }
+ else if (isCryptoEngine(cryptoArg)) {
+ crypto = cryptoArg;
+ }
+ else if ("subtle" in cryptoArg && "getRandomValues" in cryptoArg) {
+ crypto = new CryptoEngine({
+ crypto: cryptoArg,
+ });
+ }
+ }
+ if ((typeof process !== "undefined") && ("pid" in process) && (typeof global !== "undefined") && (typeof window === "undefined")) {
+ if (typeof global[process.pid] === "undefined") {
+ global[process.pid] = {};
+ }
+ else {
+ if (typeof global[process.pid] !== "object") {
+ throw new Error(`Name global.${process.pid} already exists and it is not an object`);
+ }
+ }
+ if (typeof global[process.pid].pkijs === "undefined") {
+ global[process.pid].pkijs = {};
+ }
+ else {
+ if (typeof global[process.pid].pkijs !== "object") {
+ throw new Error(`Name global.${process.pid}.pkijs already exists and it is not an object`);
+ }
+ }
+ global[process.pid].pkijs.engine = {
+ name: name,
+ crypto,
+ };
+ }
+ else {
+ engine = {
+ name: name,
+ crypto,
+ };
+ }
+}
+function getEngine() {
+ if ((typeof process !== "undefined") && ("pid" in process) && (typeof global !== "undefined") && (typeof window === "undefined")) {
+ let _engine;
+ try {
+ _engine = global[process.pid].pkijs.engine;
+ }
+ catch (ex) {
+ throw new Error("Please call 'setEngine' before call to 'getEngine'");
+ }
+ return _engine;
+ }
+ return engine;
+}
+function getCrypto(safety = false) {
+ const _engine = getEngine();
+ if (!_engine.crypto && safety) {
+ throw new Error("Unable to create WebCrypto object");
+ }
+ return _engine.crypto;
+}
+function getRandomValues(view) {
+ return getCrypto(true).getRandomValues(view);
+}
+function getOIDByAlgorithm(algorithm, safety, target) {
+ return getCrypto(true).getOIDByAlgorithm(algorithm, safety, target);
+}
+function getAlgorithmParameters(algorithmName, operation) {
+ return getCrypto(true).getAlgorithmParameters(algorithmName, operation);
+}
+function createCMSECDSASignature(signatureBuffer) {
+ if ((signatureBuffer.byteLength % 2) !== 0)
+ return EMPTY_BUFFER;
+ const length = signatureBuffer.byteLength / 2;
+ const rBuffer = new ArrayBuffer(length);
+ const rView = new Uint8Array(rBuffer);
+ rView.set(new Uint8Array(signatureBuffer, 0, length));
+ const rInteger = new Integer({ valueHex: rBuffer });
+ const sBuffer = new ArrayBuffer(length);
+ const sView = new Uint8Array(sBuffer);
+ sView.set(new Uint8Array(signatureBuffer, length, length));
+ const sInteger = new Integer({ valueHex: sBuffer });
+ return (new Sequence({
+ value: [
+ rInteger.convertToDER(),
+ sInteger.convertToDER()
+ ]
+ })).toBER(false);
+}
+function createECDSASignatureFromCMS(cmsSignature, pointSize) {
+ if (!(cmsSignature instanceof Sequence
+ && cmsSignature.valueBlock.value.length === 2
+ && cmsSignature.valueBlock.value[0] instanceof Integer
+ && cmsSignature.valueBlock.value[1] instanceof Integer))
+ return EMPTY_BUFFER;
+ const rValueView = cmsSignature.valueBlock.value[0].convertFromDER().valueBlock.valueHexView;
+ const sValueView = cmsSignature.valueBlock.value[1].convertFromDER().valueBlock.valueHexView;
+ const res = new Uint8Array(pointSize * 2);
+ res.set(rValueView, pointSize - rValueView.byteLength);
+ res.set(sValueView, (2 * pointSize) - sValueView.byteLength);
+ return res.buffer;
+}
+function getAlgorithmByOID(oid, safety = false, target) {
+ return getCrypto(true).getAlgorithmByOID(oid, safety, target);
+}
+function getHashAlgorithm(signatureAlgorithm) {
+ return getCrypto(true).getHashAlgorithm(signatureAlgorithm);
+}
+function kdfWithCounter(hashFunction, zBuffer, Counter, SharedInfo, crypto) {
+ return __awaiter(this, void 0, void 0, function* () {
+ switch (hashFunction.toUpperCase()) {
+ case "SHA-1":
+ case "SHA-256":
+ case "SHA-384":
+ case "SHA-512":
+ break;
+ default:
+ throw new ArgumentError(`Unknown hash function: ${hashFunction}`);
+ }
+ ArgumentError.assert(zBuffer, "zBuffer", "ArrayBuffer");
+ if (zBuffer.byteLength === 0)
+ throw new ArgumentError("'zBuffer' has zero length, error");
+ ArgumentError.assert(SharedInfo, "SharedInfo", "ArrayBuffer");
+ if (Counter > 255)
+ throw new ArgumentError("Please set 'Counter' argument to value less or equal to 255");
+ const counterBuffer = new ArrayBuffer(4);
+ const counterView = new Uint8Array(counterBuffer);
+ counterView[0] = 0x00;
+ counterView[1] = 0x00;
+ counterView[2] = 0x00;
+ counterView[3] = Counter;
+ let combinedBuffer = EMPTY_BUFFER;
+ combinedBuffer = utilConcatBuf(combinedBuffer, zBuffer);
+ combinedBuffer = utilConcatBuf(combinedBuffer, counterBuffer);
+ combinedBuffer = utilConcatBuf(combinedBuffer, SharedInfo);
+ const result = yield crypto.digest({ name: hashFunction }, combinedBuffer);
+ return {
+ counter: Counter,
+ result
+ };
+ });
+}
+function kdf(hashFunction, Zbuffer, keydatalen, SharedInfo, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ let hashLength = 0;
+ let maxCounter = 1;
+ switch (hashFunction.toUpperCase()) {
+ case "SHA-1":
+ hashLength = 160;
+ break;
+ case "SHA-256":
+ hashLength = 256;
+ break;
+ case "SHA-384":
+ hashLength = 384;
+ break;
+ case "SHA-512":
+ hashLength = 512;
+ break;
+ default:
+ throw new ArgumentError(`Unknown hash function: ${hashFunction}`);
+ }
+ ArgumentError.assert(Zbuffer, "Zbuffer", "ArrayBuffer");
+ if (Zbuffer.byteLength === 0)
+ throw new ArgumentError("'Zbuffer' has zero length, error");
+ ArgumentError.assert(SharedInfo, "SharedInfo", "ArrayBuffer");
+ const quotient = keydatalen / hashLength;
+ if (Math.floor(quotient) > 0) {
+ maxCounter = Math.floor(quotient);
+ if ((quotient - maxCounter) > 0)
+ maxCounter++;
+ }
+ const incomingResult = [];
+ for (let i = 1; i <= maxCounter; i++)
+ incomingResult.push(yield kdfWithCounter(hashFunction, Zbuffer, i, SharedInfo, crypto));
+ let combinedBuffer = EMPTY_BUFFER;
+ let currentCounter = 1;
+ let found = true;
+ while (found) {
+ found = false;
+ for (const result of incomingResult) {
+ if (result.counter === currentCounter) {
+ combinedBuffer = utilConcatBuf(combinedBuffer, result.result);
+ found = true;
+ break;
+ }
+ }
+ currentCounter++;
+ }
+ keydatalen >>= 3;
+ if (combinedBuffer.byteLength > keydatalen) {
+ const newBuffer = new ArrayBuffer(keydatalen);
+ const newView = new Uint8Array(newBuffer);
+ const combinedView = new Uint8Array(combinedBuffer);
+ for (let i = 0; i < keydatalen; i++)
+ newView[i] = combinedView[i];
+ return newBuffer;
+ }
+ return combinedBuffer;
+ });
+}
+
+const VERSION$i = "version";
+const LOG_ID = "logID";
+const EXTENSIONS$6 = "extensions";
+const TIMESTAMP = "timestamp";
+const HASH_ALGORITHM$3 = "hashAlgorithm";
+const SIGNATURE_ALGORITHM$8 = "signatureAlgorithm";
+const SIGNATURE$7 = "signature";
+const NONE = "none";
+const MD5 = "md5";
+const SHA1 = "sha1";
+const SHA224 = "sha224";
+const SHA256 = "sha256";
+const SHA384 = "sha384";
+const SHA512 = "sha512";
+const ANONYMOUS = "anonymous";
+const RSA = "rsa";
+const DSA = "dsa";
+const ECDSA = "ecdsa";
+class SignedCertificateTimestamp extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.version = getParametersValue(parameters, VERSION$i, SignedCertificateTimestamp.defaultValues(VERSION$i));
+ this.logID = getParametersValue(parameters, LOG_ID, SignedCertificateTimestamp.defaultValues(LOG_ID));
+ this.timestamp = getParametersValue(parameters, TIMESTAMP, SignedCertificateTimestamp.defaultValues(TIMESTAMP));
+ this.extensions = getParametersValue(parameters, EXTENSIONS$6, SignedCertificateTimestamp.defaultValues(EXTENSIONS$6));
+ this.hashAlgorithm = getParametersValue(parameters, HASH_ALGORITHM$3, SignedCertificateTimestamp.defaultValues(HASH_ALGORITHM$3));
+ this.signatureAlgorithm = getParametersValue(parameters, SIGNATURE_ALGORITHM$8, SignedCertificateTimestamp.defaultValues(SIGNATURE_ALGORITHM$8));
+ this.signature = getParametersValue(parameters, SIGNATURE$7, SignedCertificateTimestamp.defaultValues(SIGNATURE$7));
+ if ("stream" in parameters && parameters.stream) {
+ this.fromStream(parameters.stream);
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case VERSION$i:
+ return 0;
+ case LOG_ID:
+ case EXTENSIONS$6:
+ return EMPTY_BUFFER;
+ case TIMESTAMP:
+ return new Date(0);
+ case HASH_ALGORITHM$3:
+ case SIGNATURE_ALGORITHM$8:
+ return EMPTY_STRING;
+ case SIGNATURE$7:
+ return new Any();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ fromSchema(schema) {
+ if ((schema instanceof RawData) === false)
+ throw new Error("Object's schema was not verified against input data for SignedCertificateTimestamp");
+ const seqStream = new SeqStream({
+ stream: new ByteStream({
+ buffer: schema.data
+ })
+ });
+ this.fromStream(seqStream);
+ }
+ fromStream(stream) {
+ const blockLength = stream.getUint16();
+ this.version = (stream.getBlock(1))[0];
+ if (this.version === 0) {
+ this.logID = (new Uint8Array(stream.getBlock(32))).buffer.slice(0);
+ this.timestamp = new Date(utilFromBase(new Uint8Array(stream.getBlock(8)), 8));
+ const extensionsLength = stream.getUint16();
+ this.extensions = (new Uint8Array(stream.getBlock(extensionsLength))).buffer.slice(0);
+ switch ((stream.getBlock(1))[0]) {
+ case 0:
+ this.hashAlgorithm = NONE;
+ break;
+ case 1:
+ this.hashAlgorithm = MD5;
+ break;
+ case 2:
+ this.hashAlgorithm = SHA1;
+ break;
+ case 3:
+ this.hashAlgorithm = SHA224;
+ break;
+ case 4:
+ this.hashAlgorithm = SHA256;
+ break;
+ case 5:
+ this.hashAlgorithm = SHA384;
+ break;
+ case 6:
+ this.hashAlgorithm = SHA512;
+ break;
+ default:
+ throw new Error("Object's stream was not correct for SignedCertificateTimestamp");
+ }
+ switch ((stream.getBlock(1))[0]) {
+ case 0:
+ this.signatureAlgorithm = ANONYMOUS;
+ break;
+ case 1:
+ this.signatureAlgorithm = RSA;
+ break;
+ case 2:
+ this.signatureAlgorithm = DSA;
+ break;
+ case 3:
+ this.signatureAlgorithm = ECDSA;
+ break;
+ default:
+ throw new Error("Object's stream was not correct for SignedCertificateTimestamp");
+ }
+ const signatureLength = stream.getUint16();
+ const signatureData = new Uint8Array(stream.getBlock(signatureLength)).buffer.slice(0);
+ const asn1 = fromBER(signatureData);
+ AsnError.assert(asn1, "SignedCertificateTimestamp");
+ this.signature = asn1.result;
+ if (blockLength !== (47 + extensionsLength + signatureLength)) {
+ throw new Error("Object's stream was not correct for SignedCertificateTimestamp");
+ }
+ }
+ }
+ toSchema() {
+ const stream = this.toStream();
+ return new RawData({ data: stream.stream.buffer });
+ }
+ toStream() {
+ const stream = new SeqStream();
+ stream.appendUint16(47 + this.extensions.byteLength + this.signature.valueBeforeDecodeView.byteLength);
+ stream.appendChar(this.version);
+ stream.appendView(new Uint8Array(this.logID));
+ const timeBuffer = new ArrayBuffer(8);
+ const timeView = new Uint8Array(timeBuffer);
+ const baseArray = utilToBase(this.timestamp.valueOf(), 8);
+ timeView.set(new Uint8Array(baseArray), 8 - baseArray.byteLength);
+ stream.appendView(timeView);
+ stream.appendUint16(this.extensions.byteLength);
+ if (this.extensions.byteLength)
+ stream.appendView(new Uint8Array(this.extensions));
+ let _hashAlgorithm;
+ switch (this.hashAlgorithm.toLowerCase()) {
+ case NONE:
+ _hashAlgorithm = 0;
+ break;
+ case MD5:
+ _hashAlgorithm = 1;
+ break;
+ case SHA1:
+ _hashAlgorithm = 2;
+ break;
+ case SHA224:
+ _hashAlgorithm = 3;
+ break;
+ case SHA256:
+ _hashAlgorithm = 4;
+ break;
+ case SHA384:
+ _hashAlgorithm = 5;
+ break;
+ case SHA512:
+ _hashAlgorithm = 6;
+ break;
+ default:
+ throw new Error(`Incorrect data for hashAlgorithm: ${this.hashAlgorithm}`);
+ }
+ stream.appendChar(_hashAlgorithm);
+ let _signatureAlgorithm;
+ switch (this.signatureAlgorithm.toLowerCase()) {
+ case ANONYMOUS:
+ _signatureAlgorithm = 0;
+ break;
+ case RSA:
+ _signatureAlgorithm = 1;
+ break;
+ case DSA:
+ _signatureAlgorithm = 2;
+ break;
+ case ECDSA:
+ _signatureAlgorithm = 3;
+ break;
+ default:
+ throw new Error(`Incorrect data for signatureAlgorithm: ${this.signatureAlgorithm}`);
+ }
+ stream.appendChar(_signatureAlgorithm);
+ const _signature = this.signature.toBER(false);
+ stream.appendUint16(_signature.byteLength);
+ stream.appendView(new Uint8Array(_signature));
+ return stream;
+ }
+ toJSON() {
+ return {
+ version: this.version,
+ logID: bufferToHexCodes(this.logID),
+ timestamp: this.timestamp,
+ extensions: bufferToHexCodes(this.extensions),
+ hashAlgorithm: this.hashAlgorithm,
+ signatureAlgorithm: this.signatureAlgorithm,
+ signature: this.signature.toJSON()
+ };
+ }
+ verify(logs, data, dataType = 0, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const logId = toBase64(arrayBufferToString(this.logID));
+ let publicKeyBase64 = null;
+ const stream = new SeqStream();
+ for (const log of logs) {
+ if (log.log_id === logId) {
+ publicKeyBase64 = log.key;
+ break;
+ }
+ }
+ if (!publicKeyBase64) {
+ throw new Error(`Public key not found for CT with logId: ${logId}`);
+ }
+ const pki = stringToArrayBuffer(fromBase64(publicKeyBase64));
+ const publicKeyInfo = PublicKeyInfo.fromBER(pki);
+ stream.appendChar(0x00);
+ stream.appendChar(0x00);
+ const timeBuffer = new ArrayBuffer(8);
+ const timeView = new Uint8Array(timeBuffer);
+ const baseArray = utilToBase(this.timestamp.valueOf(), 8);
+ timeView.set(new Uint8Array(baseArray), 8 - baseArray.byteLength);
+ stream.appendView(timeView);
+ stream.appendUint16(dataType);
+ if (dataType === 0)
+ stream.appendUint24(data.byteLength);
+ stream.appendView(new Uint8Array(data));
+ stream.appendUint16(this.extensions.byteLength);
+ if (this.extensions.byteLength !== 0)
+ stream.appendView(new Uint8Array(this.extensions));
+ return crypto.verifyWithPublicKey(stream.buffer.slice(0, stream.length), new OctetString({ valueHex: this.signature.toBER(false) }), publicKeyInfo, { algorithmId: EMPTY_STRING }, "SHA-256");
+ });
+ }
+}
+SignedCertificateTimestamp.CLASS_NAME = "SignedCertificateTimestamp";
+function verifySCTsForCertificate(certificate, issuerCertificate, logs, index = (-1), crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ let parsedValue = null;
+ const stream = new SeqStream();
+ for (let i = 0; certificate.extensions && i < certificate.extensions.length; i++) {
+ switch (certificate.extensions[i].extnID) {
+ case id_SignedCertificateTimestampList:
+ {
+ parsedValue = certificate.extensions[i].parsedValue;
+ if (!parsedValue || parsedValue.timestamps.length === 0)
+ throw new Error("Nothing to verify in the certificate");
+ certificate.extensions.splice(i, 1);
+ }
+ break;
+ }
+ }
+ if (parsedValue === null)
+ throw new Error("No SignedCertificateTimestampList extension in the specified certificate");
+ const tbs = certificate.encodeTBS().toBER();
+ const issuerId = yield crypto.digest({ name: "SHA-256" }, new Uint8Array(issuerCertificate.subjectPublicKeyInfo.toSchema().toBER(false)));
+ stream.appendView(new Uint8Array(issuerId));
+ stream.appendUint24(tbs.byteLength);
+ stream.appendView(new Uint8Array(tbs));
+ const preCert = stream.stream.slice(0, stream.length);
+ if (index === (-1)) {
+ const verifyArray = [];
+ for (const timestamp of parsedValue.timestamps) {
+ const verifyResult = yield timestamp.verify(logs, preCert.buffer, 1, crypto);
+ verifyArray.push(verifyResult);
+ }
+ return verifyArray;
+ }
+ if (index >= parsedValue.timestamps.length)
+ index = (parsedValue.timestamps.length - 1);
+ return [yield parsedValue.timestamps[index].verify(logs, preCert.buffer, 1, crypto)];
+ });
+}
+
+const TIMESTAMPS = "timestamps";
+class SignedCertificateTimestampList extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.timestamps = getParametersValue(parameters, TIMESTAMPS, SignedCertificateTimestampList.defaultValues(TIMESTAMPS));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case TIMESTAMPS:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case TIMESTAMPS:
+ return (memberValue.length === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ var _a;
+ const names = getParametersValue(parameters, "names", {});
+ (_a = names.optional) !== null && _a !== void 0 ? _a : (names.optional = false);
+ return (new OctetString({
+ name: (names.blockName || "SignedCertificateTimestampList"),
+ optional: names.optional
+ }));
+ }
+ fromSchema(schema) {
+ if ((schema instanceof OctetString) === false) {
+ throw new Error("Object's schema was not verified against input data for SignedCertificateTimestampList");
+ }
+ const seqStream = new SeqStream({
+ stream: new ByteStream({
+ buffer: schema.valueBlock.valueHex
+ })
+ });
+ const dataLength = seqStream.getUint16();
+ if (dataLength !== seqStream.length) {
+ throw new Error("Object's schema was not verified against input data for SignedCertificateTimestampList");
+ }
+ while (seqStream.length) {
+ this.timestamps.push(new SignedCertificateTimestamp({ stream: seqStream }));
+ }
+ }
+ toSchema() {
+ const stream = new SeqStream();
+ let overallLength = 0;
+ const timestampsData = [];
+ for (const timestamp of this.timestamps) {
+ const timestampStream = timestamp.toStream();
+ timestampsData.push(timestampStream);
+ overallLength += timestampStream.stream.buffer.byteLength;
+ }
+ stream.appendUint16(overallLength);
+ for (const timestamp of timestampsData) {
+ stream.appendView(timestamp.stream.view);
+ }
+ return new OctetString({ valueHex: stream.stream.buffer.slice(0) });
+ }
+ toJSON() {
+ return {
+ timestamps: Array.from(this.timestamps, o => o.toJSON())
+ };
+ }
+}
+SignedCertificateTimestampList.CLASS_NAME = "SignedCertificateTimestampList";
+
+const ATTRIBUTES$4 = "attributes";
+const CLEAR_PROPS$11 = [
+ ATTRIBUTES$4
+];
+class SubjectDirectoryAttributes extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.attributes = getParametersValue(parameters, ATTRIBUTES$4, SubjectDirectoryAttributes.defaultValues(ATTRIBUTES$4));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case ATTRIBUTES$4:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Repeated({
+ name: (names.attributes || EMPTY_STRING),
+ value: Attribute.schema()
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$11);
+ const asn1 = compareSchema(schema, schema, SubjectDirectoryAttributes.schema({
+ names: {
+ attributes: ATTRIBUTES$4
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.attributes = Array.from(asn1.result.attributes, element => new Attribute({ schema: element }));
+ }
+ toSchema() {
+ return (new Sequence({
+ value: Array.from(this.attributes, o => o.toSchema())
+ }));
+ }
+ toJSON() {
+ return {
+ attributes: Array.from(this.attributes, o => o.toJSON())
+ };
+ }
+}
+SubjectDirectoryAttributes.CLASS_NAME = "SubjectDirectoryAttributes";
+
+class ExtensionValueFactory {
+ static getItems() {
+ if (!this.types) {
+ this.types = {};
+ ExtensionValueFactory.register(id_SubjectAltName, "SubjectAltName", AltName);
+ ExtensionValueFactory.register(id_IssuerAltName, "IssuerAltName", AltName);
+ ExtensionValueFactory.register(id_AuthorityKeyIdentifier, "AuthorityKeyIdentifier", AuthorityKeyIdentifier);
+ ExtensionValueFactory.register(id_BasicConstraints, "BasicConstraints", BasicConstraints);
+ ExtensionValueFactory.register(id_MicrosoftCaVersion, "MicrosoftCaVersion", CAVersion);
+ ExtensionValueFactory.register(id_CertificatePolicies, "CertificatePolicies", CertificatePolicies);
+ ExtensionValueFactory.register(id_MicrosoftAppPolicies, "CertificatePoliciesMicrosoft", CertificatePolicies);
+ ExtensionValueFactory.register(id_MicrosoftCertTemplateV2, "MicrosoftCertTemplateV2", CertificateTemplate);
+ ExtensionValueFactory.register(id_CRLDistributionPoints, "CRLDistributionPoints", CRLDistributionPoints);
+ ExtensionValueFactory.register(id_FreshestCRL, "FreshestCRL", CRLDistributionPoints);
+ ExtensionValueFactory.register(id_ExtKeyUsage, "ExtKeyUsage", ExtKeyUsage);
+ ExtensionValueFactory.register(id_CertificateIssuer, "CertificateIssuer", GeneralNames);
+ ExtensionValueFactory.register(id_AuthorityInfoAccess, "AuthorityInfoAccess", InfoAccess);
+ ExtensionValueFactory.register(id_SubjectInfoAccess, "SubjectInfoAccess", InfoAccess);
+ ExtensionValueFactory.register(id_IssuingDistributionPoint, "IssuingDistributionPoint", IssuingDistributionPoint);
+ ExtensionValueFactory.register(id_NameConstraints, "NameConstraints", NameConstraints);
+ ExtensionValueFactory.register(id_PolicyConstraints, "PolicyConstraints", PolicyConstraints);
+ ExtensionValueFactory.register(id_PolicyMappings, "PolicyMappings", PolicyMappings);
+ ExtensionValueFactory.register(id_PrivateKeyUsagePeriod, "PrivateKeyUsagePeriod", PrivateKeyUsagePeriod);
+ ExtensionValueFactory.register(id_QCStatements, "QCStatements", QCStatements);
+ ExtensionValueFactory.register(id_SignedCertificateTimestampList, "SignedCertificateTimestampList", SignedCertificateTimestampList);
+ ExtensionValueFactory.register(id_SubjectDirectoryAttributes, "SubjectDirectoryAttributes", SubjectDirectoryAttributes);
+ }
+ return this.types;
+ }
+ static fromBER(id, raw) {
+ const asn1 = fromBER(raw);
+ if (asn1.offset === -1) {
+ return null;
+ }
+ const item = this.find(id);
+ if (item) {
+ try {
+ return new item.type({ schema: asn1.result });
+ }
+ catch (ex) {
+ const res = new item.type();
+ res.parsingError = `Incorrectly formatted value of extension ${item.name} (${id})`;
+ return res;
+ }
+ }
+ return asn1.result;
+ }
+ static find(id) {
+ const types = this.getItems();
+ return types[id] || null;
+ }
+ static register(id, name, type) {
+ this.getItems()[id] = { name, type };
+ }
+}
+
+const EXTN_ID = "extnID";
+const CRITICAL = "critical";
+const EXTN_VALUE = "extnValue";
+const PARSED_VALUE$5 = "parsedValue";
+const CLEAR_PROPS$10 = [
+ EXTN_ID,
+ CRITICAL,
+ EXTN_VALUE
+];
+class Extension extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.extnID = getParametersValue(parameters, EXTN_ID, Extension.defaultValues(EXTN_ID));
+ this.critical = getParametersValue(parameters, CRITICAL, Extension.defaultValues(CRITICAL));
+ if (EXTN_VALUE in parameters) {
+ this.extnValue = new OctetString({ valueHex: parameters.extnValue });
+ }
+ else {
+ this.extnValue = Extension.defaultValues(EXTN_VALUE);
+ }
+ if (PARSED_VALUE$5 in parameters) {
+ this.parsedValue = getParametersValue(parameters, PARSED_VALUE$5, Extension.defaultValues(PARSED_VALUE$5));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ get parsedValue() {
+ if (this._parsedValue === undefined) {
+ const parsedValue = ExtensionValueFactory.fromBER(this.extnID, this.extnValue.valueBlock.valueHexView);
+ this._parsedValue = parsedValue;
+ }
+ return this._parsedValue || undefined;
+ }
+ set parsedValue(value) {
+ this._parsedValue = value;
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case EXTN_ID:
+ return EMPTY_STRING;
+ case CRITICAL:
+ return false;
+ case EXTN_VALUE:
+ return new OctetString();
+ case PARSED_VALUE$5:
+ return {};
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new ObjectIdentifier({ name: (names.extnID || EMPTY_STRING) }),
+ new Boolean({
+ name: (names.critical || EMPTY_STRING),
+ optional: true
+ }),
+ new OctetString({ name: (names.extnValue || EMPTY_STRING) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$10);
+ const asn1 = compareSchema(schema, schema, Extension.schema({
+ names: {
+ extnID: EXTN_ID,
+ critical: CRITICAL,
+ extnValue: EXTN_VALUE
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.extnID = asn1.result.extnID.valueBlock.toString();
+ if (CRITICAL in asn1.result) {
+ this.critical = asn1.result.critical.valueBlock.value;
+ }
+ this.extnValue = asn1.result.extnValue;
+ }
+ toSchema() {
+ const outputArray = [];
+ outputArray.push(new ObjectIdentifier({ value: this.extnID }));
+ if (this.critical !== Extension.defaultValues(CRITICAL)) {
+ outputArray.push(new Boolean({ value: this.critical }));
+ }
+ outputArray.push(this.extnValue);
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const object = {
+ extnID: this.extnID,
+ extnValue: this.extnValue.toJSON(),
+ };
+ if (this.critical !== Extension.defaultValues(CRITICAL)) {
+ object.critical = this.critical;
+ }
+ if (this.parsedValue && this.parsedValue.toJSON) {
+ object.parsedValue = this.parsedValue.toJSON();
+ }
+ return object;
+ }
+}
+Extension.CLASS_NAME = "Extension";
+
+const EXTENSIONS$5 = "extensions";
+const CLEAR_PROPS$$ = [
+ EXTENSIONS$5,
+];
+class Extensions extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.extensions = getParametersValue(parameters, EXTENSIONS$5, Extensions.defaultValues(EXTENSIONS$5));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case EXTENSIONS$5:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}, optional = false) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ optional,
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Repeated({
+ name: (names.extensions || EMPTY_STRING),
+ value: Extension.schema(names.extension || {})
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$$);
+ const asn1 = compareSchema(schema, schema, Extensions.schema({
+ names: {
+ extensions: EXTENSIONS$5
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.extensions = Array.from(asn1.result.extensions, element => new Extension({ schema: element }));
+ }
+ toSchema() {
+ return (new Sequence({
+ value: Array.from(this.extensions, o => o.toSchema())
+ }));
+ }
+ toJSON() {
+ return {
+ extensions: this.extensions.map(o => o.toJSON())
+ };
+ }
+}
+Extensions.CLASS_NAME = "Extensions";
+
+const ISSUER$5 = "issuer";
+const SERIAL_NUMBER$6 = "serialNumber";
+const ISSUER_UID = "issuerUID";
+const CLEAR_PROPS$_ = [
+ ISSUER$5,
+ SERIAL_NUMBER$6,
+ ISSUER_UID,
+];
+class IssuerSerial extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.issuer = getParametersValue(parameters, ISSUER$5, IssuerSerial.defaultValues(ISSUER$5));
+ this.serialNumber = getParametersValue(parameters, SERIAL_NUMBER$6, IssuerSerial.defaultValues(SERIAL_NUMBER$6));
+ if (ISSUER_UID in parameters) {
+ this.issuerUID = getParametersValue(parameters, ISSUER_UID, IssuerSerial.defaultValues(ISSUER_UID));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case ISSUER$5:
+ return new GeneralNames();
+ case SERIAL_NUMBER$6:
+ return new Integer();
+ case ISSUER_UID:
+ return new BitString();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ GeneralNames.schema(names.issuer || {}),
+ new Integer({ name: (names.serialNumber || EMPTY_STRING) }),
+ new BitString({
+ optional: true,
+ name: (names.issuerUID || EMPTY_STRING)
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$_);
+ const asn1 = compareSchema(schema, schema, IssuerSerial.schema({
+ names: {
+ issuer: {
+ names: {
+ blockName: ISSUER$5
+ }
+ },
+ serialNumber: SERIAL_NUMBER$6,
+ issuerUID: ISSUER_UID
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.issuer = new GeneralNames({ schema: asn1.result.issuer });
+ this.serialNumber = asn1.result.serialNumber;
+ if (ISSUER_UID in asn1.result)
+ this.issuerUID = asn1.result.issuerUID;
+ }
+ toSchema() {
+ const result = new Sequence({
+ value: [
+ this.issuer.toSchema(),
+ this.serialNumber
+ ]
+ });
+ if (this.issuerUID) {
+ result.valueBlock.value.push(this.issuerUID);
+ }
+ return result;
+ }
+ toJSON() {
+ const result = {
+ issuer: this.issuer.toJSON(),
+ serialNumber: this.serialNumber.toJSON()
+ };
+ if (this.issuerUID) {
+ result.issuerUID = this.issuerUID.toJSON();
+ }
+ return result;
+ }
+}
+IssuerSerial.CLASS_NAME = "IssuerSerial";
+
+const VERSION$h = "version";
+const BASE_CERTIFICATE_ID$2 = "baseCertificateID";
+const SUBJECT_NAME = "subjectName";
+const ISSUER$4 = "issuer";
+const SIGNATURE$6 = "signature";
+const SERIAL_NUMBER$5 = "serialNumber";
+const ATTR_CERT_VALIDITY_PERIOD$1 = "attrCertValidityPeriod";
+const ATTRIBUTES$3 = "attributes";
+const ISSUER_UNIQUE_ID$2 = "issuerUniqueID";
+const EXTENSIONS$4 = "extensions";
+const CLEAR_PROPS$Z = [
+ VERSION$h,
+ BASE_CERTIFICATE_ID$2,
+ SUBJECT_NAME,
+ ISSUER$4,
+ SIGNATURE$6,
+ SERIAL_NUMBER$5,
+ ATTR_CERT_VALIDITY_PERIOD$1,
+ ATTRIBUTES$3,
+ ISSUER_UNIQUE_ID$2,
+ EXTENSIONS$4,
+];
+class AttributeCertificateInfoV1 extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.version = getParametersValue(parameters, VERSION$h, AttributeCertificateInfoV1.defaultValues(VERSION$h));
+ if (BASE_CERTIFICATE_ID$2 in parameters) {
+ this.baseCertificateID = getParametersValue(parameters, BASE_CERTIFICATE_ID$2, AttributeCertificateInfoV1.defaultValues(BASE_CERTIFICATE_ID$2));
+ }
+ if (SUBJECT_NAME in parameters) {
+ this.subjectName = getParametersValue(parameters, SUBJECT_NAME, AttributeCertificateInfoV1.defaultValues(SUBJECT_NAME));
+ }
+ this.issuer = getParametersValue(parameters, ISSUER$4, AttributeCertificateInfoV1.defaultValues(ISSUER$4));
+ this.signature = getParametersValue(parameters, SIGNATURE$6, AttributeCertificateInfoV1.defaultValues(SIGNATURE$6));
+ this.serialNumber = getParametersValue(parameters, SERIAL_NUMBER$5, AttributeCertificateInfoV1.defaultValues(SERIAL_NUMBER$5));
+ this.attrCertValidityPeriod = getParametersValue(parameters, ATTR_CERT_VALIDITY_PERIOD$1, AttributeCertificateInfoV1.defaultValues(ATTR_CERT_VALIDITY_PERIOD$1));
+ this.attributes = getParametersValue(parameters, ATTRIBUTES$3, AttributeCertificateInfoV1.defaultValues(ATTRIBUTES$3));
+ if (ISSUER_UNIQUE_ID$2 in parameters)
+ this.issuerUniqueID = getParametersValue(parameters, ISSUER_UNIQUE_ID$2, AttributeCertificateInfoV1.defaultValues(ISSUER_UNIQUE_ID$2));
+ if (EXTENSIONS$4 in parameters) {
+ this.extensions = getParametersValue(parameters, EXTENSIONS$4, AttributeCertificateInfoV1.defaultValues(EXTENSIONS$4));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case VERSION$h:
+ return 0;
+ case BASE_CERTIFICATE_ID$2:
+ return new IssuerSerial();
+ case SUBJECT_NAME:
+ return new GeneralNames();
+ case ISSUER$4:
+ return new GeneralNames();
+ case SIGNATURE$6:
+ return new AlgorithmIdentifier();
+ case SERIAL_NUMBER$5:
+ return new Integer();
+ case ATTR_CERT_VALIDITY_PERIOD$1:
+ return new AttCertValidityPeriod();
+ case ATTRIBUTES$3:
+ return [];
+ case ISSUER_UNIQUE_ID$2:
+ return new BitString();
+ case EXTENSIONS$4:
+ return new Extensions();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Integer({ name: (names.version || EMPTY_STRING) }),
+ new Choice({
+ value: [
+ new Constructed({
+ name: (names.baseCertificateID || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: IssuerSerial.schema().valueBlock.value
+ }),
+ new Constructed({
+ name: (names.subjectName || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: GeneralNames.schema().valueBlock.value
+ }),
+ ]
+ }),
+ GeneralNames.schema({
+ names: {
+ blockName: (names.issuer || EMPTY_STRING)
+ }
+ }),
+ AlgorithmIdentifier.schema(names.signature || {}),
+ new Integer({ name: (names.serialNumber || EMPTY_STRING) }),
+ AttCertValidityPeriod.schema(names.attrCertValidityPeriod || {}),
+ new Sequence({
+ name: (names.attributes || EMPTY_STRING),
+ value: [
+ new Repeated({
+ value: Attribute.schema()
+ })
+ ]
+ }),
+ new BitString({
+ optional: true,
+ name: (names.issuerUniqueID || EMPTY_STRING)
+ }),
+ Extensions.schema(names.extensions || {}, true)
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$Z);
+ const asn1 = compareSchema(schema, schema, AttributeCertificateInfoV1.schema({
+ names: {
+ version: VERSION$h,
+ baseCertificateID: BASE_CERTIFICATE_ID$2,
+ subjectName: SUBJECT_NAME,
+ issuer: ISSUER$4,
+ signature: {
+ names: {
+ blockName: SIGNATURE$6
+ }
+ },
+ serialNumber: SERIAL_NUMBER$5,
+ attrCertValidityPeriod: {
+ names: {
+ blockName: ATTR_CERT_VALIDITY_PERIOD$1
+ }
+ },
+ attributes: ATTRIBUTES$3,
+ issuerUniqueID: ISSUER_UNIQUE_ID$2,
+ extensions: {
+ names: {
+ blockName: EXTENSIONS$4
+ }
+ }
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.version = asn1.result.version.valueBlock.valueDec;
+ if (BASE_CERTIFICATE_ID$2 in asn1.result) {
+ this.baseCertificateID = new IssuerSerial({
+ schema: new Sequence({
+ value: asn1.result.baseCertificateID.valueBlock.value
+ })
+ });
+ }
+ if (SUBJECT_NAME in asn1.result) {
+ this.subjectName = new GeneralNames({
+ schema: new Sequence({
+ value: asn1.result.subjectName.valueBlock.value
+ })
+ });
+ }
+ this.issuer = asn1.result.issuer;
+ this.signature = new AlgorithmIdentifier({ schema: asn1.result.signature });
+ this.serialNumber = asn1.result.serialNumber;
+ this.attrCertValidityPeriod = new AttCertValidityPeriod({ schema: asn1.result.attrCertValidityPeriod });
+ this.attributes = Array.from(asn1.result.attributes.valueBlock.value, element => new Attribute({ schema: element }));
+ if (ISSUER_UNIQUE_ID$2 in asn1.result) {
+ this.issuerUniqueID = asn1.result.issuerUniqueID;
+ }
+ if (EXTENSIONS$4 in asn1.result) {
+ this.extensions = new Extensions({ schema: asn1.result.extensions });
+ }
+ }
+ toSchema() {
+ const result = new Sequence({
+ value: [new Integer({ value: this.version })]
+ });
+ if (this.baseCertificateID) {
+ result.valueBlock.value.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: this.baseCertificateID.toSchema().valueBlock.value
+ }));
+ }
+ if (this.subjectName) {
+ result.valueBlock.value.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: this.subjectName.toSchema().valueBlock.value
+ }));
+ }
+ result.valueBlock.value.push(this.issuer.toSchema());
+ result.valueBlock.value.push(this.signature.toSchema());
+ result.valueBlock.value.push(this.serialNumber);
+ result.valueBlock.value.push(this.attrCertValidityPeriod.toSchema());
+ result.valueBlock.value.push(new Sequence({
+ value: Array.from(this.attributes, o => o.toSchema())
+ }));
+ if (this.issuerUniqueID) {
+ result.valueBlock.value.push(this.issuerUniqueID);
+ }
+ if (this.extensions) {
+ result.valueBlock.value.push(this.extensions.toSchema());
+ }
+ return result;
+ }
+ toJSON() {
+ const result = {
+ version: this.version
+ };
+ if (this.baseCertificateID) {
+ result.baseCertificateID = this.baseCertificateID.toJSON();
+ }
+ if (this.subjectName) {
+ result.subjectName = this.subjectName.toJSON();
+ }
+ result.issuer = this.issuer.toJSON();
+ result.signature = this.signature.toJSON();
+ result.serialNumber = this.serialNumber.toJSON();
+ result.attrCertValidityPeriod = this.attrCertValidityPeriod.toJSON();
+ result.attributes = Array.from(this.attributes, o => o.toJSON());
+ if (this.issuerUniqueID) {
+ result.issuerUniqueID = this.issuerUniqueID.toJSON();
+ }
+ if (this.extensions) {
+ result.extensions = this.extensions.toJSON();
+ }
+ return result;
+ }
+}
+AttributeCertificateInfoV1.CLASS_NAME = "AttributeCertificateInfoV1";
+
+const ACINFO$1 = "acinfo";
+const SIGNATURE_ALGORITHM$7 = "signatureAlgorithm";
+const SIGNATURE_VALUE$4 = "signatureValue";
+const CLEAR_PROPS$Y = [
+ ACINFO$1,
+ SIGNATURE_VALUE$4,
+ SIGNATURE_ALGORITHM$7
+];
+class AttributeCertificateV1 extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.acinfo = getParametersValue(parameters, ACINFO$1, AttributeCertificateV1.defaultValues(ACINFO$1));
+ this.signatureAlgorithm = getParametersValue(parameters, SIGNATURE_ALGORITHM$7, AttributeCertificateV1.defaultValues(SIGNATURE_ALGORITHM$7));
+ this.signatureValue = getParametersValue(parameters, SIGNATURE_VALUE$4, AttributeCertificateV1.defaultValues(SIGNATURE_VALUE$4));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case ACINFO$1:
+ return new AttributeCertificateInfoV1();
+ case SIGNATURE_ALGORITHM$7:
+ return new AlgorithmIdentifier();
+ case SIGNATURE_VALUE$4:
+ return new BitString();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ AttributeCertificateInfoV1.schema(names.acinfo || {}),
+ AlgorithmIdentifier.schema(names.signatureAlgorithm || {}),
+ new BitString({ name: (names.signatureValue || EMPTY_STRING) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$Y);
+ const asn1 = compareSchema(schema, schema, AttributeCertificateV1.schema({
+ names: {
+ acinfo: {
+ names: {
+ blockName: ACINFO$1
+ }
+ },
+ signatureAlgorithm: {
+ names: {
+ blockName: SIGNATURE_ALGORITHM$7
+ }
+ },
+ signatureValue: SIGNATURE_VALUE$4
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.acinfo = new AttributeCertificateInfoV1({ schema: asn1.result.acinfo });
+ this.signatureAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.signatureAlgorithm });
+ this.signatureValue = asn1.result.signatureValue;
+ }
+ toSchema() {
+ return (new Sequence({
+ value: [
+ this.acinfo.toSchema(),
+ this.signatureAlgorithm.toSchema(),
+ this.signatureValue
+ ]
+ }));
+ }
+ toJSON() {
+ return {
+ acinfo: this.acinfo.toJSON(),
+ signatureAlgorithm: this.signatureAlgorithm.toJSON(),
+ signatureValue: this.signatureValue.toJSON(),
+ };
+ }
+}
+AttributeCertificateV1.CLASS_NAME = "AttributeCertificateV1";
+
+const DIGESTED_OBJECT_TYPE = "digestedObjectType";
+const OTHER_OBJECT_TYPE_ID = "otherObjectTypeID";
+const DIGEST_ALGORITHM$2 = "digestAlgorithm";
+const OBJECT_DIGEST = "objectDigest";
+const CLEAR_PROPS$X = [
+ DIGESTED_OBJECT_TYPE,
+ OTHER_OBJECT_TYPE_ID,
+ DIGEST_ALGORITHM$2,
+ OBJECT_DIGEST,
+];
+class ObjectDigestInfo extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.digestedObjectType = getParametersValue(parameters, DIGESTED_OBJECT_TYPE, ObjectDigestInfo.defaultValues(DIGESTED_OBJECT_TYPE));
+ if (OTHER_OBJECT_TYPE_ID in parameters) {
+ this.otherObjectTypeID = getParametersValue(parameters, OTHER_OBJECT_TYPE_ID, ObjectDigestInfo.defaultValues(OTHER_OBJECT_TYPE_ID));
+ }
+ this.digestAlgorithm = getParametersValue(parameters, DIGEST_ALGORITHM$2, ObjectDigestInfo.defaultValues(DIGEST_ALGORITHM$2));
+ this.objectDigest = getParametersValue(parameters, OBJECT_DIGEST, ObjectDigestInfo.defaultValues(OBJECT_DIGEST));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case DIGESTED_OBJECT_TYPE:
+ return new Enumerated();
+ case OTHER_OBJECT_TYPE_ID:
+ return new ObjectIdentifier();
+ case DIGEST_ALGORITHM$2:
+ return new AlgorithmIdentifier();
+ case OBJECT_DIGEST:
+ return new BitString();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Enumerated({ name: (names.digestedObjectType || EMPTY_STRING) }),
+ new ObjectIdentifier({
+ optional: true,
+ name: (names.otherObjectTypeID || EMPTY_STRING)
+ }),
+ AlgorithmIdentifier.schema(names.digestAlgorithm || {}),
+ new BitString({ name: (names.objectDigest || EMPTY_STRING) }),
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$X);
+ const asn1 = compareSchema(schema, schema, ObjectDigestInfo.schema({
+ names: {
+ digestedObjectType: DIGESTED_OBJECT_TYPE,
+ otherObjectTypeID: OTHER_OBJECT_TYPE_ID,
+ digestAlgorithm: {
+ names: {
+ blockName: DIGEST_ALGORITHM$2
+ }
+ },
+ objectDigest: OBJECT_DIGEST
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.digestedObjectType = asn1.result.digestedObjectType;
+ if (OTHER_OBJECT_TYPE_ID in asn1.result) {
+ this.otherObjectTypeID = asn1.result.otherObjectTypeID;
+ }
+ this.digestAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.digestAlgorithm });
+ this.objectDigest = asn1.result.objectDigest;
+ }
+ toSchema() {
+ const result = new Sequence({
+ value: [this.digestedObjectType]
+ });
+ if (this.otherObjectTypeID) {
+ result.valueBlock.value.push(this.otherObjectTypeID);
+ }
+ result.valueBlock.value.push(this.digestAlgorithm.toSchema());
+ result.valueBlock.value.push(this.objectDigest);
+ return result;
+ }
+ toJSON() {
+ const result = {
+ digestedObjectType: this.digestedObjectType.toJSON(),
+ digestAlgorithm: this.digestAlgorithm.toJSON(),
+ objectDigest: this.objectDigest.toJSON(),
+ };
+ if (this.otherObjectTypeID) {
+ result.otherObjectTypeID = this.otherObjectTypeID.toJSON();
+ }
+ return result;
+ }
+}
+ObjectDigestInfo.CLASS_NAME = "ObjectDigestInfo";
+
+const ISSUER_NAME = "issuerName";
+const BASE_CERTIFICATE_ID$1 = "baseCertificateID";
+const OBJECT_DIGEST_INFO$1 = "objectDigestInfo";
+const CLEAR_PROPS$W = [
+ ISSUER_NAME,
+ BASE_CERTIFICATE_ID$1,
+ OBJECT_DIGEST_INFO$1
+];
+class V2Form extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ if (ISSUER_NAME in parameters) {
+ this.issuerName = getParametersValue(parameters, ISSUER_NAME, V2Form.defaultValues(ISSUER_NAME));
+ }
+ if (BASE_CERTIFICATE_ID$1 in parameters) {
+ this.baseCertificateID = getParametersValue(parameters, BASE_CERTIFICATE_ID$1, V2Form.defaultValues(BASE_CERTIFICATE_ID$1));
+ }
+ if (OBJECT_DIGEST_INFO$1 in parameters) {
+ this.objectDigestInfo = getParametersValue(parameters, OBJECT_DIGEST_INFO$1, V2Form.defaultValues(OBJECT_DIGEST_INFO$1));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case ISSUER_NAME:
+ return new GeneralNames();
+ case BASE_CERTIFICATE_ID$1:
+ return new IssuerSerial();
+ case OBJECT_DIGEST_INFO$1:
+ return new ObjectDigestInfo();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ GeneralNames.schema({
+ names: {
+ blockName: names.issuerName
+ }
+ }, true),
+ new Constructed({
+ optional: true,
+ name: (names.baseCertificateID || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: IssuerSerial.schema().valueBlock.value
+ }),
+ new Constructed({
+ optional: true,
+ name: (names.objectDigestInfo || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: ObjectDigestInfo.schema().valueBlock.value
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$W);
+ const asn1 = compareSchema(schema, schema, V2Form.schema({
+ names: {
+ issuerName: ISSUER_NAME,
+ baseCertificateID: BASE_CERTIFICATE_ID$1,
+ objectDigestInfo: OBJECT_DIGEST_INFO$1
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ if (ISSUER_NAME in asn1.result)
+ this.issuerName = new GeneralNames({ schema: asn1.result.issuerName });
+ if (BASE_CERTIFICATE_ID$1 in asn1.result) {
+ this.baseCertificateID = new IssuerSerial({
+ schema: new Sequence({
+ value: asn1.result.baseCertificateID.valueBlock.value
+ })
+ });
+ }
+ if (OBJECT_DIGEST_INFO$1 in asn1.result) {
+ this.objectDigestInfo = new ObjectDigestInfo({
+ schema: new Sequence({
+ value: asn1.result.objectDigestInfo.valueBlock.value
+ })
+ });
+ }
+ }
+ toSchema() {
+ const result = new Sequence();
+ if (this.issuerName)
+ result.valueBlock.value.push(this.issuerName.toSchema());
+ if (this.baseCertificateID) {
+ result.valueBlock.value.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: this.baseCertificateID.toSchema().valueBlock.value
+ }));
+ }
+ if (this.objectDigestInfo) {
+ result.valueBlock.value.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: this.objectDigestInfo.toSchema().valueBlock.value
+ }));
+ }
+ return result;
+ }
+ toJSON() {
+ const result = {};
+ if (this.issuerName) {
+ result.issuerName = this.issuerName.toJSON();
+ }
+ if (this.baseCertificateID) {
+ result.baseCertificateID = this.baseCertificateID.toJSON();
+ }
+ if (this.objectDigestInfo) {
+ result.objectDigestInfo = this.objectDigestInfo.toJSON();
+ }
+ return result;
+ }
+}
+V2Form.CLASS_NAME = "V2Form";
+
+const BASE_CERTIFICATE_ID = "baseCertificateID";
+const ENTITY_NAME = "entityName";
+const OBJECT_DIGEST_INFO = "objectDigestInfo";
+const CLEAR_PROPS$V = [
+ BASE_CERTIFICATE_ID,
+ ENTITY_NAME,
+ OBJECT_DIGEST_INFO
+];
+class Holder extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ if (BASE_CERTIFICATE_ID in parameters) {
+ this.baseCertificateID = getParametersValue(parameters, BASE_CERTIFICATE_ID, Holder.defaultValues(BASE_CERTIFICATE_ID));
+ }
+ if (ENTITY_NAME in parameters) {
+ this.entityName = getParametersValue(parameters, ENTITY_NAME, Holder.defaultValues(ENTITY_NAME));
+ }
+ if (OBJECT_DIGEST_INFO in parameters) {
+ this.objectDigestInfo = getParametersValue(parameters, OBJECT_DIGEST_INFO, Holder.defaultValues(OBJECT_DIGEST_INFO));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case BASE_CERTIFICATE_ID:
+ return new IssuerSerial();
+ case ENTITY_NAME:
+ return new GeneralNames();
+ case OBJECT_DIGEST_INFO:
+ return new ObjectDigestInfo();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Constructed({
+ optional: true,
+ name: (names.baseCertificateID || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: IssuerSerial.schema().valueBlock.value
+ }),
+ new Constructed({
+ optional: true,
+ name: (names.entityName || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: GeneralNames.schema().valueBlock.value
+ }),
+ new Constructed({
+ optional: true,
+ name: (names.objectDigestInfo || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ },
+ value: ObjectDigestInfo.schema().valueBlock.value
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$V);
+ const asn1 = compareSchema(schema, schema, Holder.schema({
+ names: {
+ baseCertificateID: BASE_CERTIFICATE_ID,
+ entityName: ENTITY_NAME,
+ objectDigestInfo: OBJECT_DIGEST_INFO
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ if (BASE_CERTIFICATE_ID in asn1.result) {
+ this.baseCertificateID = new IssuerSerial({
+ schema: new Sequence({
+ value: asn1.result.baseCertificateID.valueBlock.value
+ })
+ });
+ }
+ if (ENTITY_NAME in asn1.result) {
+ this.entityName = new GeneralNames({
+ schema: new Sequence({
+ value: asn1.result.entityName.valueBlock.value
+ })
+ });
+ }
+ if (OBJECT_DIGEST_INFO in asn1.result) {
+ this.objectDigestInfo = new ObjectDigestInfo({
+ schema: new Sequence({
+ value: asn1.result.objectDigestInfo.valueBlock.value
+ })
+ });
+ }
+ }
+ toSchema() {
+ const result = new Sequence();
+ if (this.baseCertificateID) {
+ result.valueBlock.value.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: this.baseCertificateID.toSchema().valueBlock.value
+ }));
+ }
+ if (this.entityName) {
+ result.valueBlock.value.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: this.entityName.toSchema().valueBlock.value
+ }));
+ }
+ if (this.objectDigestInfo) {
+ result.valueBlock.value.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ },
+ value: this.objectDigestInfo.toSchema().valueBlock.value
+ }));
+ }
+ return result;
+ }
+ toJSON() {
+ const result = {};
+ if (this.baseCertificateID) {
+ result.baseCertificateID = this.baseCertificateID.toJSON();
+ }
+ if (this.entityName) {
+ result.entityName = this.entityName.toJSON();
+ }
+ if (this.objectDigestInfo) {
+ result.objectDigestInfo = this.objectDigestInfo.toJSON();
+ }
+ return result;
+ }
+}
+Holder.CLASS_NAME = "Holder";
+
+const VERSION$g = "version";
+const HOLDER = "holder";
+const ISSUER$3 = "issuer";
+const SIGNATURE$5 = "signature";
+const SERIAL_NUMBER$4 = "serialNumber";
+const ATTR_CERT_VALIDITY_PERIOD = "attrCertValidityPeriod";
+const ATTRIBUTES$2 = "attributes";
+const ISSUER_UNIQUE_ID$1 = "issuerUniqueID";
+const EXTENSIONS$3 = "extensions";
+const CLEAR_PROPS$U = [
+ VERSION$g,
+ HOLDER,
+ ISSUER$3,
+ SIGNATURE$5,
+ SERIAL_NUMBER$4,
+ ATTR_CERT_VALIDITY_PERIOD,
+ ATTRIBUTES$2,
+ ISSUER_UNIQUE_ID$1,
+ EXTENSIONS$3
+];
+class AttributeCertificateInfoV2 extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.version = getParametersValue(parameters, VERSION$g, AttributeCertificateInfoV2.defaultValues(VERSION$g));
+ this.holder = getParametersValue(parameters, HOLDER, AttributeCertificateInfoV2.defaultValues(HOLDER));
+ this.issuer = getParametersValue(parameters, ISSUER$3, AttributeCertificateInfoV2.defaultValues(ISSUER$3));
+ this.signature = getParametersValue(parameters, SIGNATURE$5, AttributeCertificateInfoV2.defaultValues(SIGNATURE$5));
+ this.serialNumber = getParametersValue(parameters, SERIAL_NUMBER$4, AttributeCertificateInfoV2.defaultValues(SERIAL_NUMBER$4));
+ this.attrCertValidityPeriod = getParametersValue(parameters, ATTR_CERT_VALIDITY_PERIOD, AttributeCertificateInfoV2.defaultValues(ATTR_CERT_VALIDITY_PERIOD));
+ this.attributes = getParametersValue(parameters, ATTRIBUTES$2, AttributeCertificateInfoV2.defaultValues(ATTRIBUTES$2));
+ if (ISSUER_UNIQUE_ID$1 in parameters) {
+ this.issuerUniqueID = getParametersValue(parameters, ISSUER_UNIQUE_ID$1, AttributeCertificateInfoV2.defaultValues(ISSUER_UNIQUE_ID$1));
+ }
+ if (EXTENSIONS$3 in parameters) {
+ this.extensions = getParametersValue(parameters, EXTENSIONS$3, AttributeCertificateInfoV2.defaultValues(EXTENSIONS$3));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case VERSION$g:
+ return 1;
+ case HOLDER:
+ return new Holder();
+ case ISSUER$3:
+ return {};
+ case SIGNATURE$5:
+ return new AlgorithmIdentifier();
+ case SERIAL_NUMBER$4:
+ return new Integer();
+ case ATTR_CERT_VALIDITY_PERIOD:
+ return new AttCertValidityPeriod();
+ case ATTRIBUTES$2:
+ return [];
+ case ISSUER_UNIQUE_ID$1:
+ return new BitString();
+ case EXTENSIONS$3:
+ return new Extensions();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Integer({ name: (names.version || EMPTY_STRING) }),
+ Holder.schema(names.holder || {}),
+ new Choice({
+ value: [
+ GeneralNames.schema({
+ names: {
+ blockName: (names.issuer || EMPTY_STRING)
+ }
+ }),
+ new Constructed({
+ name: (names.issuer || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: V2Form.schema().valueBlock.value
+ })
+ ]
+ }),
+ AlgorithmIdentifier.schema(names.signature || {}),
+ new Integer({ name: (names.serialNumber || EMPTY_STRING) }),
+ AttCertValidityPeriod.schema(names.attrCertValidityPeriod || {}),
+ new Sequence({
+ name: (names.attributes || EMPTY_STRING),
+ value: [
+ new Repeated({
+ value: Attribute.schema()
+ })
+ ]
+ }),
+ new BitString({
+ optional: true,
+ name: (names.issuerUniqueID || EMPTY_STRING)
+ }),
+ Extensions.schema(names.extensions || {}, true)
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$U);
+ const asn1 = compareSchema(schema, schema, AttributeCertificateInfoV2.schema({
+ names: {
+ version: VERSION$g,
+ holder: {
+ names: {
+ blockName: HOLDER
+ }
+ },
+ issuer: ISSUER$3,
+ signature: {
+ names: {
+ blockName: SIGNATURE$5
+ }
+ },
+ serialNumber: SERIAL_NUMBER$4,
+ attrCertValidityPeriod: {
+ names: {
+ blockName: ATTR_CERT_VALIDITY_PERIOD
+ }
+ },
+ attributes: ATTRIBUTES$2,
+ issuerUniqueID: ISSUER_UNIQUE_ID$1,
+ extensions: {
+ names: {
+ blockName: EXTENSIONS$3
+ }
+ }
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.version = asn1.result.version.valueBlock.valueDec;
+ this.holder = new Holder({ schema: asn1.result.holder });
+ switch (asn1.result.issuer.idBlock.tagClass) {
+ case 3:
+ this.issuer = new V2Form({
+ schema: new Sequence({
+ value: asn1.result.issuer.valueBlock.value
+ })
+ });
+ break;
+ case 1:
+ default:
+ throw new Error("Incorrect value for 'issuer' in AttributeCertificateInfoV2");
+ }
+ this.signature = new AlgorithmIdentifier({ schema: asn1.result.signature });
+ this.serialNumber = asn1.result.serialNumber;
+ this.attrCertValidityPeriod = new AttCertValidityPeriod({ schema: asn1.result.attrCertValidityPeriod });
+ this.attributes = Array.from(asn1.result.attributes.valueBlock.value, element => new Attribute({ schema: element }));
+ if (ISSUER_UNIQUE_ID$1 in asn1.result) {
+ this.issuerUniqueID = asn1.result.issuerUniqueID;
+ }
+ if (EXTENSIONS$3 in asn1.result) {
+ this.extensions = new Extensions({ schema: asn1.result.extensions });
+ }
+ }
+ toSchema() {
+ const result = new Sequence({
+ value: [
+ new Integer({ value: this.version }),
+ this.holder.toSchema(),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: this.issuer.toSchema().valueBlock.value
+ }),
+ this.signature.toSchema(),
+ this.serialNumber,
+ this.attrCertValidityPeriod.toSchema(),
+ new Sequence({
+ value: Array.from(this.attributes, o => o.toSchema())
+ })
+ ]
+ });
+ if (this.issuerUniqueID) {
+ result.valueBlock.value.push(this.issuerUniqueID);
+ }
+ if (this.extensions) {
+ result.valueBlock.value.push(this.extensions.toSchema());
+ }
+ return result;
+ }
+ toJSON() {
+ const result = {
+ version: this.version,
+ holder: this.holder.toJSON(),
+ issuer: this.issuer.toJSON(),
+ signature: this.signature.toJSON(),
+ serialNumber: this.serialNumber.toJSON(),
+ attrCertValidityPeriod: this.attrCertValidityPeriod.toJSON(),
+ attributes: Array.from(this.attributes, o => o.toJSON())
+ };
+ if (this.issuerUniqueID) {
+ result.issuerUniqueID = this.issuerUniqueID.toJSON();
+ }
+ if (this.extensions) {
+ result.extensions = this.extensions.toJSON();
+ }
+ return result;
+ }
+}
+AttributeCertificateInfoV2.CLASS_NAME = "AttributeCertificateInfoV2";
+
+const ACINFO = "acinfo";
+const SIGNATURE_ALGORITHM$6 = "signatureAlgorithm";
+const SIGNATURE_VALUE$3 = "signatureValue";
+const CLEAR_PROPS$T = [
+ ACINFO,
+ SIGNATURE_ALGORITHM$6,
+ SIGNATURE_VALUE$3,
+];
+class AttributeCertificateV2 extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.acinfo = getParametersValue(parameters, ACINFO, AttributeCertificateV2.defaultValues(ACINFO));
+ this.signatureAlgorithm = getParametersValue(parameters, SIGNATURE_ALGORITHM$6, AttributeCertificateV2.defaultValues(SIGNATURE_ALGORITHM$6));
+ this.signatureValue = getParametersValue(parameters, SIGNATURE_VALUE$3, AttributeCertificateV2.defaultValues(SIGNATURE_VALUE$3));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case ACINFO:
+ return new AttributeCertificateInfoV2();
+ case SIGNATURE_ALGORITHM$6:
+ return new AlgorithmIdentifier();
+ case SIGNATURE_VALUE$3:
+ return new BitString();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ AttributeCertificateInfoV2.schema(names.acinfo || {}),
+ AlgorithmIdentifier.schema(names.signatureAlgorithm || {}),
+ new BitString({ name: (names.signatureValue || EMPTY_STRING) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$T);
+ const asn1 = compareSchema(schema, schema, AttributeCertificateV2.schema({
+ names: {
+ acinfo: {
+ names: {
+ blockName: ACINFO
+ }
+ },
+ signatureAlgorithm: {
+ names: {
+ blockName: SIGNATURE_ALGORITHM$6
+ }
+ },
+ signatureValue: SIGNATURE_VALUE$3
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.acinfo = new AttributeCertificateInfoV2({ schema: asn1.result.acinfo });
+ this.signatureAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.signatureAlgorithm });
+ this.signatureValue = asn1.result.signatureValue;
+ }
+ toSchema() {
+ return (new Sequence({
+ value: [
+ this.acinfo.toSchema(),
+ this.signatureAlgorithm.toSchema(),
+ this.signatureValue
+ ]
+ }));
+ }
+ toJSON() {
+ return {
+ acinfo: this.acinfo.toJSON(),
+ signatureAlgorithm: this.signatureAlgorithm.toJSON(),
+ signatureValue: this.signatureValue.toJSON(),
+ };
+ }
+}
+AttributeCertificateV2.CLASS_NAME = "AttributeCertificateV2";
+
+const CONTENT_TYPE = "contentType";
+const CONTENT = "content";
+const CLEAR_PROPS$S = [CONTENT_TYPE, CONTENT];
+class ContentInfo extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.contentType = getParametersValue(parameters, CONTENT_TYPE, ContentInfo.defaultValues(CONTENT_TYPE));
+ this.content = getParametersValue(parameters, CONTENT, ContentInfo.defaultValues(CONTENT));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case CONTENT_TYPE:
+ return EMPTY_STRING;
+ case CONTENT:
+ return new Any();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case CONTENT_TYPE:
+ return (typeof memberValue === "string" &&
+ memberValue === this.defaultValues(CONTENT_TYPE));
+ case CONTENT:
+ return (memberValue instanceof Any);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ if (("optional" in names) === false) {
+ names.optional = false;
+ }
+ return (new Sequence({
+ name: (names.blockName || "ContentInfo"),
+ optional: names.optional,
+ value: [
+ new ObjectIdentifier({ name: (names.contentType || CONTENT_TYPE) }),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [new Any({ name: (names.content || CONTENT) })]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$S);
+ const asn1 = compareSchema(schema, schema, ContentInfo.schema());
+ AsnError.assertSchema(asn1, this.className);
+ this.contentType = asn1.result.contentType.valueBlock.toString();
+ this.content = asn1.result.content;
+ }
+ toSchema() {
+ return (new Sequence({
+ value: [
+ new ObjectIdentifier({ value: this.contentType }),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [this.content]
+ })
+ ]
+ }));
+ }
+ toJSON() {
+ const object = {
+ contentType: this.contentType
+ };
+ if (!(this.content instanceof Any)) {
+ object.content = this.content.toJSON();
+ }
+ return object;
+ }
+}
+ContentInfo.CLASS_NAME = "ContentInfo";
+ContentInfo.DATA = id_ContentType_Data;
+ContentInfo.SIGNED_DATA = id_ContentType_SignedData;
+ContentInfo.ENVELOPED_DATA = id_ContentType_EnvelopedData;
+ContentInfo.ENCRYPTED_DATA = id_ContentType_EncryptedData;
+
+const TYPE$1 = "type";
+const VALUE$4 = "value";
+const UTC_TIME_NAME = "utcTimeName";
+const GENERAL_TIME_NAME = "generalTimeName";
+const CLEAR_PROPS$R = [UTC_TIME_NAME, GENERAL_TIME_NAME];
+var TimeType;
+(function (TimeType) {
+ TimeType[TimeType["UTCTime"] = 0] = "UTCTime";
+ TimeType[TimeType["GeneralizedTime"] = 1] = "GeneralizedTime";
+ TimeType[TimeType["empty"] = 2] = "empty";
+})(TimeType || (TimeType = {}));
+class Time extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.type = getParametersValue(parameters, TYPE$1, Time.defaultValues(TYPE$1));
+ this.value = getParametersValue(parameters, VALUE$4, Time.defaultValues(VALUE$4));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case TYPE$1:
+ return 0;
+ case VALUE$4:
+ return new Date(0, 0, 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}, optional = false) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Choice({
+ optional,
+ value: [
+ new UTCTime({ name: (names.utcTimeName || EMPTY_STRING) }),
+ new GeneralizedTime({ name: (names.generalTimeName || EMPTY_STRING) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$R);
+ const asn1 = compareSchema(schema, schema, Time.schema({
+ names: {
+ utcTimeName: UTC_TIME_NAME,
+ generalTimeName: GENERAL_TIME_NAME
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ if (UTC_TIME_NAME in asn1.result) {
+ this.type = 0;
+ this.value = asn1.result.utcTimeName.toDate();
+ }
+ if (GENERAL_TIME_NAME in asn1.result) {
+ this.type = 1;
+ this.value = asn1.result.generalTimeName.toDate();
+ }
+ }
+ toSchema() {
+ if (this.type === 0) {
+ return new UTCTime({ valueDate: this.value });
+ }
+ else if (this.type === 1) {
+ return new GeneralizedTime({ valueDate: this.value });
+ }
+ return {};
+ }
+ toJSON() {
+ return {
+ type: this.type,
+ value: this.value
+ };
+ }
+}
+Time.CLASS_NAME = "Time";
+
+const TBS$4 = "tbs";
+const VERSION$f = "version";
+const SERIAL_NUMBER$3 = "serialNumber";
+const SIGNATURE$4 = "signature";
+const ISSUER$2 = "issuer";
+const NOT_BEFORE = "notBefore";
+const NOT_AFTER = "notAfter";
+const SUBJECT$1 = "subject";
+const SUBJECT_PUBLIC_KEY_INFO = "subjectPublicKeyInfo";
+const ISSUER_UNIQUE_ID = "issuerUniqueID";
+const SUBJECT_UNIQUE_ID = "subjectUniqueID";
+const EXTENSIONS$2 = "extensions";
+const SIGNATURE_ALGORITHM$5 = "signatureAlgorithm";
+const SIGNATURE_VALUE$2 = "signatureValue";
+const TBS_CERTIFICATE = "tbsCertificate";
+const TBS_CERTIFICATE_VERSION = `${TBS_CERTIFICATE}.${VERSION$f}`;
+const TBS_CERTIFICATE_SERIAL_NUMBER = `${TBS_CERTIFICATE}.${SERIAL_NUMBER$3}`;
+const TBS_CERTIFICATE_SIGNATURE = `${TBS_CERTIFICATE}.${SIGNATURE$4}`;
+const TBS_CERTIFICATE_ISSUER = `${TBS_CERTIFICATE}.${ISSUER$2}`;
+const TBS_CERTIFICATE_NOT_BEFORE = `${TBS_CERTIFICATE}.${NOT_BEFORE}`;
+const TBS_CERTIFICATE_NOT_AFTER = `${TBS_CERTIFICATE}.${NOT_AFTER}`;
+const TBS_CERTIFICATE_SUBJECT = `${TBS_CERTIFICATE}.${SUBJECT$1}`;
+const TBS_CERTIFICATE_SUBJECT_PUBLIC_KEY = `${TBS_CERTIFICATE}.${SUBJECT_PUBLIC_KEY_INFO}`;
+const TBS_CERTIFICATE_ISSUER_UNIQUE_ID = `${TBS_CERTIFICATE}.${ISSUER_UNIQUE_ID}`;
+const TBS_CERTIFICATE_SUBJECT_UNIQUE_ID = `${TBS_CERTIFICATE}.${SUBJECT_UNIQUE_ID}`;
+const TBS_CERTIFICATE_EXTENSIONS = `${TBS_CERTIFICATE}.${EXTENSIONS$2}`;
+const CLEAR_PROPS$Q = [
+ TBS_CERTIFICATE,
+ TBS_CERTIFICATE_VERSION,
+ TBS_CERTIFICATE_SERIAL_NUMBER,
+ TBS_CERTIFICATE_SIGNATURE,
+ TBS_CERTIFICATE_ISSUER,
+ TBS_CERTIFICATE_NOT_BEFORE,
+ TBS_CERTIFICATE_NOT_AFTER,
+ TBS_CERTIFICATE_SUBJECT,
+ TBS_CERTIFICATE_SUBJECT_PUBLIC_KEY,
+ TBS_CERTIFICATE_ISSUER_UNIQUE_ID,
+ TBS_CERTIFICATE_SUBJECT_UNIQUE_ID,
+ TBS_CERTIFICATE_EXTENSIONS,
+ SIGNATURE_ALGORITHM$5,
+ SIGNATURE_VALUE$2
+];
+function tbsCertificate(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || TBS_CERTIFICATE),
+ value: [
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [
+ new Integer({ name: (names.tbsCertificateVersion || TBS_CERTIFICATE_VERSION) })
+ ]
+ }),
+ new Integer({ name: (names.tbsCertificateSerialNumber || TBS_CERTIFICATE_SERIAL_NUMBER) }),
+ AlgorithmIdentifier.schema(names.signature || {
+ names: {
+ blockName: TBS_CERTIFICATE_SIGNATURE
+ }
+ }),
+ RelativeDistinguishedNames.schema(names.issuer || {
+ names: {
+ blockName: TBS_CERTIFICATE_ISSUER
+ }
+ }),
+ new Sequence({
+ name: (names.tbsCertificateValidity || "tbsCertificate.validity"),
+ value: [
+ Time.schema(names.notBefore || {
+ names: {
+ utcTimeName: TBS_CERTIFICATE_NOT_BEFORE,
+ generalTimeName: TBS_CERTIFICATE_NOT_BEFORE
+ }
+ }),
+ Time.schema(names.notAfter || {
+ names: {
+ utcTimeName: TBS_CERTIFICATE_NOT_AFTER,
+ generalTimeName: TBS_CERTIFICATE_NOT_AFTER
+ }
+ })
+ ]
+ }),
+ RelativeDistinguishedNames.schema(names.subject || {
+ names: {
+ blockName: TBS_CERTIFICATE_SUBJECT
+ }
+ }),
+ PublicKeyInfo.schema(names.subjectPublicKeyInfo || {
+ names: {
+ blockName: TBS_CERTIFICATE_SUBJECT_PUBLIC_KEY
+ }
+ }),
+ new Primitive({
+ name: (names.tbsCertificateIssuerUniqueID || TBS_CERTIFICATE_ISSUER_UNIQUE_ID),
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ }
+ }),
+ new Primitive({
+ name: (names.tbsCertificateSubjectUniqueID || TBS_CERTIFICATE_SUBJECT_UNIQUE_ID),
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ }
+ }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 3
+ },
+ value: [Extensions.schema(names.extensions || {
+ names: {
+ blockName: TBS_CERTIFICATE_EXTENSIONS
+ }
+ })]
+ })
+ ]
+ }));
+}
+class Certificate extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.tbsView = new Uint8Array(getParametersValue(parameters, TBS$4, Certificate.defaultValues(TBS$4)));
+ this.version = getParametersValue(parameters, VERSION$f, Certificate.defaultValues(VERSION$f));
+ this.serialNumber = getParametersValue(parameters, SERIAL_NUMBER$3, Certificate.defaultValues(SERIAL_NUMBER$3));
+ this.signature = getParametersValue(parameters, SIGNATURE$4, Certificate.defaultValues(SIGNATURE$4));
+ this.issuer = getParametersValue(parameters, ISSUER$2, Certificate.defaultValues(ISSUER$2));
+ this.notBefore = getParametersValue(parameters, NOT_BEFORE, Certificate.defaultValues(NOT_BEFORE));
+ this.notAfter = getParametersValue(parameters, NOT_AFTER, Certificate.defaultValues(NOT_AFTER));
+ this.subject = getParametersValue(parameters, SUBJECT$1, Certificate.defaultValues(SUBJECT$1));
+ this.subjectPublicKeyInfo = getParametersValue(parameters, SUBJECT_PUBLIC_KEY_INFO, Certificate.defaultValues(SUBJECT_PUBLIC_KEY_INFO));
+ if (ISSUER_UNIQUE_ID in parameters) {
+ this.issuerUniqueID = getParametersValue(parameters, ISSUER_UNIQUE_ID, Certificate.defaultValues(ISSUER_UNIQUE_ID));
+ }
+ if (SUBJECT_UNIQUE_ID in parameters) {
+ this.subjectUniqueID = getParametersValue(parameters, SUBJECT_UNIQUE_ID, Certificate.defaultValues(SUBJECT_UNIQUE_ID));
+ }
+ if (EXTENSIONS$2 in parameters) {
+ this.extensions = getParametersValue(parameters, EXTENSIONS$2, Certificate.defaultValues(EXTENSIONS$2));
+ }
+ this.signatureAlgorithm = getParametersValue(parameters, SIGNATURE_ALGORITHM$5, Certificate.defaultValues(SIGNATURE_ALGORITHM$5));
+ this.signatureValue = getParametersValue(parameters, SIGNATURE_VALUE$2, Certificate.defaultValues(SIGNATURE_VALUE$2));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ get tbs() {
+ return BufferSourceConverter.toArrayBuffer(this.tbsView);
+ }
+ set tbs(value) {
+ this.tbsView = new Uint8Array(value);
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case TBS$4:
+ return EMPTY_BUFFER;
+ case VERSION$f:
+ return 0;
+ case SERIAL_NUMBER$3:
+ return new Integer();
+ case SIGNATURE$4:
+ return new AlgorithmIdentifier();
+ case ISSUER$2:
+ return new RelativeDistinguishedNames();
+ case NOT_BEFORE:
+ return new Time();
+ case NOT_AFTER:
+ return new Time();
+ case SUBJECT$1:
+ return new RelativeDistinguishedNames();
+ case SUBJECT_PUBLIC_KEY_INFO:
+ return new PublicKeyInfo();
+ case ISSUER_UNIQUE_ID:
+ return EMPTY_BUFFER;
+ case SUBJECT_UNIQUE_ID:
+ return EMPTY_BUFFER;
+ case EXTENSIONS$2:
+ return [];
+ case SIGNATURE_ALGORITHM$5:
+ return new AlgorithmIdentifier();
+ case SIGNATURE_VALUE$2:
+ return new BitString();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ tbsCertificate(names.tbsCertificate),
+ AlgorithmIdentifier.schema(names.signatureAlgorithm || {
+ names: {
+ blockName: SIGNATURE_ALGORITHM$5
+ }
+ }),
+ new BitString({ name: (names.signatureValue || SIGNATURE_VALUE$2) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$Q);
+ const asn1 = compareSchema(schema, schema, Certificate.schema({
+ names: {
+ tbsCertificate: {
+ names: {
+ extensions: {
+ names: {
+ extensions: TBS_CERTIFICATE_EXTENSIONS
+ }
+ }
+ }
+ }
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.tbsView = asn1.result.tbsCertificate.valueBeforeDecodeView;
+ if (TBS_CERTIFICATE_VERSION in asn1.result)
+ this.version = asn1.result[TBS_CERTIFICATE_VERSION].valueBlock.valueDec;
+ this.serialNumber = asn1.result[TBS_CERTIFICATE_SERIAL_NUMBER];
+ this.signature = new AlgorithmIdentifier({ schema: asn1.result[TBS_CERTIFICATE_SIGNATURE] });
+ this.issuer = new RelativeDistinguishedNames({ schema: asn1.result[TBS_CERTIFICATE_ISSUER] });
+ this.notBefore = new Time({ schema: asn1.result[TBS_CERTIFICATE_NOT_BEFORE] });
+ this.notAfter = new Time({ schema: asn1.result[TBS_CERTIFICATE_NOT_AFTER] });
+ this.subject = new RelativeDistinguishedNames({ schema: asn1.result[TBS_CERTIFICATE_SUBJECT] });
+ this.subjectPublicKeyInfo = new PublicKeyInfo({ schema: asn1.result[TBS_CERTIFICATE_SUBJECT_PUBLIC_KEY] });
+ if (TBS_CERTIFICATE_ISSUER_UNIQUE_ID in asn1.result)
+ this.issuerUniqueID = asn1.result[TBS_CERTIFICATE_ISSUER_UNIQUE_ID].valueBlock.valueHex;
+ if (TBS_CERTIFICATE_SUBJECT_UNIQUE_ID in asn1.result)
+ this.subjectUniqueID = asn1.result[TBS_CERTIFICATE_SUBJECT_UNIQUE_ID].valueBlock.valueHex;
+ if (TBS_CERTIFICATE_EXTENSIONS in asn1.result)
+ this.extensions = Array.from(asn1.result[TBS_CERTIFICATE_EXTENSIONS], element => new Extension({ schema: element }));
+ this.signatureAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.signatureAlgorithm });
+ this.signatureValue = asn1.result.signatureValue;
+ }
+ encodeTBS() {
+ const outputArray = [];
+ if ((VERSION$f in this) && (this.version !== Certificate.defaultValues(VERSION$f))) {
+ outputArray.push(new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [
+ new Integer({ value: this.version })
+ ]
+ }));
+ }
+ outputArray.push(this.serialNumber);
+ outputArray.push(this.signature.toSchema());
+ outputArray.push(this.issuer.toSchema());
+ outputArray.push(new Sequence({
+ value: [
+ this.notBefore.toSchema(),
+ this.notAfter.toSchema()
+ ]
+ }));
+ outputArray.push(this.subject.toSchema());
+ outputArray.push(this.subjectPublicKeyInfo.toSchema());
+ if (this.issuerUniqueID) {
+ outputArray.push(new Primitive({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ valueHex: this.issuerUniqueID
+ }));
+ }
+ if (this.subjectUniqueID) {
+ outputArray.push(new Primitive({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ },
+ valueHex: this.subjectUniqueID
+ }));
+ }
+ if (this.extensions) {
+ outputArray.push(new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 3
+ },
+ value: [new Sequence({
+ value: Array.from(this.extensions, o => o.toSchema())
+ })]
+ }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toSchema(encodeFlag = false) {
+ let tbsSchema;
+ if (encodeFlag === false) {
+ if (!this.tbsView.byteLength) {
+ return Certificate.schema().value[0];
+ }
+ const asn1 = fromBER(this.tbsView);
+ AsnError.assert(asn1, "TBS Certificate");
+ tbsSchema = asn1.result;
+ }
+ else {
+ tbsSchema = this.encodeTBS();
+ }
+ return (new Sequence({
+ value: [
+ tbsSchema,
+ this.signatureAlgorithm.toSchema(),
+ this.signatureValue
+ ]
+ }));
+ }
+ toJSON() {
+ const res = {
+ tbs: Convert.ToHex(this.tbsView),
+ version: this.version,
+ serialNumber: this.serialNumber.toJSON(),
+ signature: this.signature.toJSON(),
+ issuer: this.issuer.toJSON(),
+ notBefore: this.notBefore.toJSON(),
+ notAfter: this.notAfter.toJSON(),
+ subject: this.subject.toJSON(),
+ subjectPublicKeyInfo: this.subjectPublicKeyInfo.toJSON(),
+ signatureAlgorithm: this.signatureAlgorithm.toJSON(),
+ signatureValue: this.signatureValue.toJSON(),
+ };
+ if ((VERSION$f in this) && (this.version !== Certificate.defaultValues(VERSION$f))) {
+ res.version = this.version;
+ }
+ if (this.issuerUniqueID) {
+ res.issuerUniqueID = Convert.ToHex(this.issuerUniqueID);
+ }
+ if (this.subjectUniqueID) {
+ res.subjectUniqueID = Convert.ToHex(this.subjectUniqueID);
+ }
+ if (this.extensions) {
+ res.extensions = Array.from(this.extensions, o => o.toJSON());
+ }
+ return res;
+ }
+ getPublicKey(parameters, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return crypto.getPublicKey(this.subjectPublicKeyInfo, this.signatureAlgorithm, parameters);
+ });
+ }
+ getKeyHash(hashAlgorithm = "SHA-1", crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return crypto.digest({ name: hashAlgorithm }, this.subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHexView);
+ });
+ }
+ sign(privateKey, hashAlgorithm = "SHA-1", crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ if (!privateKey) {
+ throw new Error("Need to provide a private key for signing");
+ }
+ const signatureParameters = yield crypto.getSignatureParameters(privateKey, hashAlgorithm);
+ const parameters = signatureParameters.parameters;
+ this.signature = signatureParameters.signatureAlgorithm;
+ this.signatureAlgorithm = signatureParameters.signatureAlgorithm;
+ this.tbsView = new Uint8Array(this.encodeTBS().toBER());
+ const signature = yield crypto.signWithPrivateKey(this.tbsView, privateKey, parameters);
+ this.signatureValue = new BitString({ valueHex: signature });
+ });
+ }
+ verify(issuerCertificate, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ let subjectPublicKeyInfo;
+ if (issuerCertificate) {
+ subjectPublicKeyInfo = issuerCertificate.subjectPublicKeyInfo;
+ }
+ else if (this.issuer.isEqual(this.subject)) {
+ subjectPublicKeyInfo = this.subjectPublicKeyInfo;
+ }
+ if (!(subjectPublicKeyInfo instanceof PublicKeyInfo)) {
+ throw new Error("Please provide issuer certificate as a parameter");
+ }
+ return crypto.verifyWithPublicKey(this.tbsView, this.signatureValue, subjectPublicKeyInfo, this.signatureAlgorithm);
+ });
+ }
+}
+Certificate.CLASS_NAME = "Certificate";
+function checkCA(cert, signerCert = null) {
+ if (signerCert && cert.issuer.isEqual(signerCert.issuer) && cert.serialNumber.isEqual(signerCert.serialNumber)) {
+ return null;
+ }
+ let isCA = false;
+ if (cert.extensions) {
+ for (const extension of cert.extensions) {
+ if (extension.extnID === id_BasicConstraints && extension.parsedValue instanceof BasicConstraints) {
+ if (extension.parsedValue.cA) {
+ isCA = true;
+ break;
+ }
+ }
+ }
+ }
+ if (isCA) {
+ return cert;
+ }
+ return null;
+}
+
+const CERT_ID$1 = "certId";
+const CERT_VALUE = "certValue";
+const PARSED_VALUE$4 = "parsedValue";
+const CLEAR_PROPS$P = [
+ CERT_ID$1,
+ CERT_VALUE
+];
+class CertBag extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.certId = getParametersValue(parameters, CERT_ID$1, CertBag.defaultValues(CERT_ID$1));
+ this.certValue = getParametersValue(parameters, CERT_VALUE, CertBag.defaultValues(CERT_VALUE));
+ if (PARSED_VALUE$4 in parameters) {
+ this.parsedValue = getParametersValue(parameters, PARSED_VALUE$4, CertBag.defaultValues(PARSED_VALUE$4));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case CERT_ID$1:
+ return EMPTY_STRING;
+ case CERT_VALUE:
+ return (new Any());
+ case PARSED_VALUE$4:
+ return {};
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case CERT_ID$1:
+ return (memberValue === EMPTY_STRING);
+ case CERT_VALUE:
+ return (memberValue instanceof Any);
+ case PARSED_VALUE$4:
+ return ((memberValue instanceof Object) && (Object.keys(memberValue).length === 0));
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new ObjectIdentifier({ name: (names.id || "id") }),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [new Any({ name: (names.value || "value") })]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$P);
+ const asn1 = compareSchema(schema, schema, CertBag.schema({
+ names: {
+ id: CERT_ID$1,
+ value: CERT_VALUE
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.certId = asn1.result.certId.valueBlock.toString();
+ this.certValue = asn1.result.certValue;
+ const certValueHex = this.certValue.valueBlock.valueHexView;
+ switch (this.certId) {
+ case id_CertBag_X509Certificate:
+ {
+ try {
+ this.parsedValue = Certificate.fromBER(certValueHex);
+ }
+ catch (ex) {
+ AttributeCertificateV2.fromBER(certValueHex);
+ }
+ }
+ break;
+ case id_CertBag_AttributeCertificate:
+ {
+ this.parsedValue = AttributeCertificateV2.fromBER(certValueHex);
+ }
+ break;
+ case id_CertBag_SDSICertificate:
+ default:
+ throw new Error(`Incorrect CERT_ID value in CertBag: ${this.certId}`);
+ }
+ }
+ toSchema() {
+ if (PARSED_VALUE$4 in this) {
+ if ("acinfo" in this.parsedValue) {
+ this.certId = id_CertBag_AttributeCertificate;
+ }
+ else {
+ this.certId = id_CertBag_X509Certificate;
+ }
+ this.certValue = new OctetString({ valueHex: this.parsedValue.toSchema().toBER(false) });
+ }
+ return (new Sequence({
+ value: [
+ new ObjectIdentifier({ value: this.certId }),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [(("toSchema" in this.certValue) ? this.certValue.toSchema() : this.certValue)]
+ })
+ ]
+ }));
+ }
+ toJSON() {
+ return {
+ certId: this.certId,
+ certValue: this.certValue.toJSON()
+ };
+ }
+}
+CertBag.CLASS_NAME = "CertBag";
+
+const USER_CERTIFICATE = "userCertificate";
+const REVOCATION_DATE = "revocationDate";
+const CRL_ENTRY_EXTENSIONS = "crlEntryExtensions";
+const CLEAR_PROPS$O = [
+ USER_CERTIFICATE,
+ REVOCATION_DATE,
+ CRL_ENTRY_EXTENSIONS
+];
+class RevokedCertificate extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.userCertificate = getParametersValue(parameters, USER_CERTIFICATE, RevokedCertificate.defaultValues(USER_CERTIFICATE));
+ this.revocationDate = getParametersValue(parameters, REVOCATION_DATE, RevokedCertificate.defaultValues(REVOCATION_DATE));
+ if (CRL_ENTRY_EXTENSIONS in parameters) {
+ this.crlEntryExtensions = getParametersValue(parameters, CRL_ENTRY_EXTENSIONS, RevokedCertificate.defaultValues(CRL_ENTRY_EXTENSIONS));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case USER_CERTIFICATE:
+ return new Integer();
+ case REVOCATION_DATE:
+ return new Time();
+ case CRL_ENTRY_EXTENSIONS:
+ return new Extensions();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Integer({ name: (names.userCertificate || USER_CERTIFICATE) }),
+ Time.schema({
+ names: {
+ utcTimeName: (names.revocationDate || REVOCATION_DATE),
+ generalTimeName: (names.revocationDate || REVOCATION_DATE)
+ }
+ }),
+ Extensions.schema({
+ names: {
+ blockName: (names.crlEntryExtensions || CRL_ENTRY_EXTENSIONS)
+ }
+ }, true)
+ ]
+ });
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$O);
+ const asn1 = compareSchema(schema, schema, RevokedCertificate.schema());
+ AsnError.assertSchema(asn1, this.className);
+ this.userCertificate = asn1.result.userCertificate;
+ this.revocationDate = new Time({ schema: asn1.result.revocationDate });
+ if (CRL_ENTRY_EXTENSIONS in asn1.result) {
+ this.crlEntryExtensions = new Extensions({ schema: asn1.result.crlEntryExtensions });
+ }
+ }
+ toSchema() {
+ const outputArray = [
+ this.userCertificate,
+ this.revocationDate.toSchema()
+ ];
+ if (this.crlEntryExtensions) {
+ outputArray.push(this.crlEntryExtensions.toSchema());
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {
+ userCertificate: this.userCertificate.toJSON(),
+ revocationDate: this.revocationDate.toJSON(),
+ };
+ if (this.crlEntryExtensions) {
+ res.crlEntryExtensions = this.crlEntryExtensions.toJSON();
+ }
+ return res;
+ }
+}
+RevokedCertificate.CLASS_NAME = "RevokedCertificate";
+
+const TBS$3 = "tbs";
+const VERSION$e = "version";
+const SIGNATURE$3 = "signature";
+const ISSUER$1 = "issuer";
+const THIS_UPDATE$1 = "thisUpdate";
+const NEXT_UPDATE$1 = "nextUpdate";
+const REVOKED_CERTIFICATES = "revokedCertificates";
+const CRL_EXTENSIONS = "crlExtensions";
+const SIGNATURE_ALGORITHM$4 = "signatureAlgorithm";
+const SIGNATURE_VALUE$1 = "signatureValue";
+const TBS_CERT_LIST = "tbsCertList";
+const TBS_CERT_LIST_VERSION = `${TBS_CERT_LIST}.version`;
+const TBS_CERT_LIST_SIGNATURE = `${TBS_CERT_LIST}.signature`;
+const TBS_CERT_LIST_ISSUER = `${TBS_CERT_LIST}.issuer`;
+const TBS_CERT_LIST_THIS_UPDATE = `${TBS_CERT_LIST}.thisUpdate`;
+const TBS_CERT_LIST_NEXT_UPDATE = `${TBS_CERT_LIST}.nextUpdate`;
+const TBS_CERT_LIST_REVOKED_CERTIFICATES = `${TBS_CERT_LIST}.revokedCertificates`;
+const TBS_CERT_LIST_EXTENSIONS = `${TBS_CERT_LIST}.extensions`;
+const CLEAR_PROPS$N = [
+ TBS_CERT_LIST,
+ TBS_CERT_LIST_VERSION,
+ TBS_CERT_LIST_SIGNATURE,
+ TBS_CERT_LIST_ISSUER,
+ TBS_CERT_LIST_THIS_UPDATE,
+ TBS_CERT_LIST_NEXT_UPDATE,
+ TBS_CERT_LIST_REVOKED_CERTIFICATES,
+ TBS_CERT_LIST_EXTENSIONS,
+ SIGNATURE_ALGORITHM$4,
+ SIGNATURE_VALUE$1
+];
+function tbsCertList(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || TBS_CERT_LIST),
+ value: [
+ new Integer({
+ optional: true,
+ name: (names.tbsCertListVersion || TBS_CERT_LIST_VERSION),
+ value: 2
+ }),
+ AlgorithmIdentifier.schema(names.signature || {
+ names: {
+ blockName: TBS_CERT_LIST_SIGNATURE
+ }
+ }),
+ RelativeDistinguishedNames.schema(names.issuer || {
+ names: {
+ blockName: TBS_CERT_LIST_ISSUER
+ }
+ }),
+ Time.schema(names.tbsCertListThisUpdate || {
+ names: {
+ utcTimeName: TBS_CERT_LIST_THIS_UPDATE,
+ generalTimeName: TBS_CERT_LIST_THIS_UPDATE
+ }
+ }),
+ Time.schema(names.tbsCertListNextUpdate || {
+ names: {
+ utcTimeName: TBS_CERT_LIST_NEXT_UPDATE,
+ generalTimeName: TBS_CERT_LIST_NEXT_UPDATE
+ }
+ }, true),
+ new Sequence({
+ optional: true,
+ value: [
+ new Repeated({
+ name: (names.tbsCertListRevokedCertificates || TBS_CERT_LIST_REVOKED_CERTIFICATES),
+ value: new Sequence({
+ value: [
+ new Integer(),
+ Time.schema(),
+ Extensions.schema({}, true)
+ ]
+ })
+ })
+ ]
+ }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [Extensions.schema(names.crlExtensions || {
+ names: {
+ blockName: TBS_CERT_LIST_EXTENSIONS
+ }
+ })]
+ })
+ ]
+ }));
+}
+const WELL_KNOWN_EXTENSIONS = [
+ id_AuthorityKeyIdentifier,
+ id_IssuerAltName,
+ id_CRLNumber,
+ id_BaseCRLNumber,
+ id_IssuingDistributionPoint,
+ id_FreshestCRL,
+ id_AuthorityInfoAccess,
+ id_CRLReason,
+ id_InvalidityDate,
+ id_CertificateIssuer,
+];
+class CertificateRevocationList extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.tbsView = new Uint8Array(getParametersValue(parameters, TBS$3, CertificateRevocationList.defaultValues(TBS$3)));
+ this.version = getParametersValue(parameters, VERSION$e, CertificateRevocationList.defaultValues(VERSION$e));
+ this.signature = getParametersValue(parameters, SIGNATURE$3, CertificateRevocationList.defaultValues(SIGNATURE$3));
+ this.issuer = getParametersValue(parameters, ISSUER$1, CertificateRevocationList.defaultValues(ISSUER$1));
+ this.thisUpdate = getParametersValue(parameters, THIS_UPDATE$1, CertificateRevocationList.defaultValues(THIS_UPDATE$1));
+ if (NEXT_UPDATE$1 in parameters) {
+ this.nextUpdate = getParametersValue(parameters, NEXT_UPDATE$1, CertificateRevocationList.defaultValues(NEXT_UPDATE$1));
+ }
+ if (REVOKED_CERTIFICATES in parameters) {
+ this.revokedCertificates = getParametersValue(parameters, REVOKED_CERTIFICATES, CertificateRevocationList.defaultValues(REVOKED_CERTIFICATES));
+ }
+ if (CRL_EXTENSIONS in parameters) {
+ this.crlExtensions = getParametersValue(parameters, CRL_EXTENSIONS, CertificateRevocationList.defaultValues(CRL_EXTENSIONS));
+ }
+ this.signatureAlgorithm = getParametersValue(parameters, SIGNATURE_ALGORITHM$4, CertificateRevocationList.defaultValues(SIGNATURE_ALGORITHM$4));
+ this.signatureValue = getParametersValue(parameters, SIGNATURE_VALUE$1, CertificateRevocationList.defaultValues(SIGNATURE_VALUE$1));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ get tbs() {
+ return BufferSourceConverter.toArrayBuffer(this.tbsView);
+ }
+ set tbs(value) {
+ this.tbsView = new Uint8Array(value);
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case TBS$3:
+ return EMPTY_BUFFER;
+ case VERSION$e:
+ return 0;
+ case SIGNATURE$3:
+ return new AlgorithmIdentifier();
+ case ISSUER$1:
+ return new RelativeDistinguishedNames();
+ case THIS_UPDATE$1:
+ return new Time();
+ case NEXT_UPDATE$1:
+ return new Time();
+ case REVOKED_CERTIFICATES:
+ return [];
+ case CRL_EXTENSIONS:
+ return new Extensions();
+ case SIGNATURE_ALGORITHM$4:
+ return new AlgorithmIdentifier();
+ case SIGNATURE_VALUE$1:
+ return new BitString();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || "CertificateList"),
+ value: [
+ tbsCertList(parameters),
+ AlgorithmIdentifier.schema(names.signatureAlgorithm || {
+ names: {
+ blockName: SIGNATURE_ALGORITHM$4
+ }
+ }),
+ new BitString({ name: (names.signatureValue || SIGNATURE_VALUE$1) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$N);
+ const asn1 = compareSchema(schema, schema, CertificateRevocationList.schema());
+ AsnError.assertSchema(asn1, this.className);
+ this.tbsView = asn1.result.tbsCertList.valueBeforeDecodeView;
+ if (TBS_CERT_LIST_VERSION in asn1.result) {
+ this.version = asn1.result[TBS_CERT_LIST_VERSION].valueBlock.valueDec;
+ }
+ this.signature = new AlgorithmIdentifier({ schema: asn1.result[TBS_CERT_LIST_SIGNATURE] });
+ this.issuer = new RelativeDistinguishedNames({ schema: asn1.result[TBS_CERT_LIST_ISSUER] });
+ this.thisUpdate = new Time({ schema: asn1.result[TBS_CERT_LIST_THIS_UPDATE] });
+ if (TBS_CERT_LIST_NEXT_UPDATE in asn1.result) {
+ this.nextUpdate = new Time({ schema: asn1.result[TBS_CERT_LIST_NEXT_UPDATE] });
+ }
+ if (TBS_CERT_LIST_REVOKED_CERTIFICATES in asn1.result) {
+ this.revokedCertificates = Array.from(asn1.result[TBS_CERT_LIST_REVOKED_CERTIFICATES], element => new RevokedCertificate({ schema: element }));
+ }
+ if (TBS_CERT_LIST_EXTENSIONS in asn1.result) {
+ this.crlExtensions = new Extensions({ schema: asn1.result[TBS_CERT_LIST_EXTENSIONS] });
+ }
+ this.signatureAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.signatureAlgorithm });
+ this.signatureValue = asn1.result.signatureValue;
+ }
+ encodeTBS() {
+ const outputArray = [];
+ if (this.version !== CertificateRevocationList.defaultValues(VERSION$e)) {
+ outputArray.push(new Integer({ value: this.version }));
+ }
+ outputArray.push(this.signature.toSchema());
+ outputArray.push(this.issuer.toSchema());
+ outputArray.push(this.thisUpdate.toSchema());
+ if (this.nextUpdate) {
+ outputArray.push(this.nextUpdate.toSchema());
+ }
+ if (this.revokedCertificates) {
+ outputArray.push(new Sequence({
+ value: Array.from(this.revokedCertificates, o => o.toSchema())
+ }));
+ }
+ if (this.crlExtensions) {
+ outputArray.push(new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [
+ this.crlExtensions.toSchema()
+ ]
+ }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toSchema(encodeFlag = false) {
+ let tbsSchema;
+ if (!encodeFlag) {
+ if (!this.tbsView.byteLength) {
+ return CertificateRevocationList.schema();
+ }
+ const asn1 = fromBER(this.tbsView);
+ AsnError.assert(asn1, "TBS Certificate Revocation List");
+ tbsSchema = asn1.result;
+ }
+ else {
+ tbsSchema = this.encodeTBS();
+ }
+ return (new Sequence({
+ value: [
+ tbsSchema,
+ this.signatureAlgorithm.toSchema(),
+ this.signatureValue
+ ]
+ }));
+ }
+ toJSON() {
+ const res = {
+ tbs: Convert.ToHex(this.tbsView),
+ version: this.version,
+ signature: this.signature.toJSON(),
+ issuer: this.issuer.toJSON(),
+ thisUpdate: this.thisUpdate.toJSON(),
+ signatureAlgorithm: this.signatureAlgorithm.toJSON(),
+ signatureValue: this.signatureValue.toJSON()
+ };
+ if (this.version !== CertificateRevocationList.defaultValues(VERSION$e))
+ res.version = this.version;
+ if (this.nextUpdate) {
+ res.nextUpdate = this.nextUpdate.toJSON();
+ }
+ if (this.revokedCertificates) {
+ res.revokedCertificates = Array.from(this.revokedCertificates, o => o.toJSON());
+ }
+ if (this.crlExtensions) {
+ res.crlExtensions = this.crlExtensions.toJSON();
+ }
+ return res;
+ }
+ isCertificateRevoked(certificate) {
+ if (!this.issuer.isEqual(certificate.issuer)) {
+ return false;
+ }
+ if (!this.revokedCertificates) {
+ return false;
+ }
+ for (const revokedCertificate of this.revokedCertificates) {
+ if (revokedCertificate.userCertificate.isEqual(certificate.serialNumber)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ sign(privateKey, hashAlgorithm = "SHA-1", crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ if (!privateKey) {
+ throw new Error("Need to provide a private key for signing");
+ }
+ const signatureParameters = yield crypto.getSignatureParameters(privateKey, hashAlgorithm);
+ const { parameters } = signatureParameters;
+ this.signature = signatureParameters.signatureAlgorithm;
+ this.signatureAlgorithm = signatureParameters.signatureAlgorithm;
+ this.tbsView = new Uint8Array(this.encodeTBS().toBER());
+ const signature = yield crypto.signWithPrivateKey(this.tbsView, privateKey, parameters);
+ this.signatureValue = new BitString({ valueHex: signature });
+ });
+ }
+ verify(parameters = {}, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ let subjectPublicKeyInfo;
+ if (parameters.issuerCertificate) {
+ subjectPublicKeyInfo = parameters.issuerCertificate.subjectPublicKeyInfo;
+ if (!this.issuer.isEqual(parameters.issuerCertificate.subject)) {
+ return false;
+ }
+ }
+ if (parameters.publicKeyInfo) {
+ subjectPublicKeyInfo = parameters.publicKeyInfo;
+ }
+ if (!subjectPublicKeyInfo) {
+ throw new Error("Issuer's certificate must be provided as an input parameter");
+ }
+ if (this.crlExtensions) {
+ for (const extension of this.crlExtensions.extensions) {
+ if (extension.critical) {
+ if (!WELL_KNOWN_EXTENSIONS.includes(extension.extnID))
+ return false;
+ }
+ }
+ }
+ return crypto.verifyWithPublicKey(this.tbsView, this.signatureValue, subjectPublicKeyInfo, this.signatureAlgorithm);
+ });
+ }
+}
+CertificateRevocationList.CLASS_NAME = "CertificateRevocationList";
+
+const CRL_ID = "crlId";
+const CRL_VALUE = "crlValue";
+const PARSED_VALUE$3 = "parsedValue";
+const CLEAR_PROPS$M = [
+ CRL_ID,
+ CRL_VALUE,
+];
+class CRLBag extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.crlId = getParametersValue(parameters, CRL_ID, CRLBag.defaultValues(CRL_ID));
+ this.crlValue = getParametersValue(parameters, CRL_VALUE, CRLBag.defaultValues(CRL_VALUE));
+ if (PARSED_VALUE$3 in parameters) {
+ this.parsedValue = getParametersValue(parameters, PARSED_VALUE$3, CRLBag.defaultValues(PARSED_VALUE$3));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case CRL_ID:
+ return EMPTY_STRING;
+ case CRL_VALUE:
+ return (new Any());
+ case PARSED_VALUE$3:
+ return {};
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case CRL_ID:
+ return (memberValue === EMPTY_STRING);
+ case CRL_VALUE:
+ return (memberValue instanceof Any);
+ case PARSED_VALUE$3:
+ return ((memberValue instanceof Object) && (Object.keys(memberValue).length === 0));
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new ObjectIdentifier({ name: (names.id || "id") }),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [new Any({ name: (names.value || "value") })]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$M);
+ const asn1 = compareSchema(schema, schema, CRLBag.schema({
+ names: {
+ id: CRL_ID,
+ value: CRL_VALUE
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.crlId = asn1.result.crlId.valueBlock.toString();
+ this.crlValue = asn1.result.crlValue;
+ switch (this.crlId) {
+ case id_CRLBag_X509CRL:
+ {
+ this.parsedValue = CertificateRevocationList.fromBER(this.certValue.valueBlock.valueHex);
+ }
+ break;
+ default:
+ throw new Error(`Incorrect CRL_ID value in CRLBag: ${this.crlId}`);
+ }
+ }
+ toSchema() {
+ if (this.parsedValue) {
+ this.crlId = id_CRLBag_X509CRL;
+ this.crlValue = new OctetString({ valueHex: this.parsedValue.toSchema().toBER(false) });
+ }
+ return (new Sequence({
+ value: [
+ new ObjectIdentifier({ value: this.crlId }),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [this.crlValue.toSchema()]
+ })
+ ]
+ }));
+ }
+ toJSON() {
+ return {
+ crlId: this.crlId,
+ crlValue: this.crlValue.toJSON()
+ };
+ }
+}
+CRLBag.CLASS_NAME = "CRLBag";
+
+const VERSION$d = "version";
+const ENCRYPTED_CONTENT_INFO$1 = "encryptedContentInfo";
+const UNPROTECTED_ATTRS$1 = "unprotectedAttrs";
+const CLEAR_PROPS$L = [
+ VERSION$d,
+ ENCRYPTED_CONTENT_INFO$1,
+ UNPROTECTED_ATTRS$1,
+];
+class EncryptedData extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.version = getParametersValue(parameters, VERSION$d, EncryptedData.defaultValues(VERSION$d));
+ this.encryptedContentInfo = getParametersValue(parameters, ENCRYPTED_CONTENT_INFO$1, EncryptedData.defaultValues(ENCRYPTED_CONTENT_INFO$1));
+ if (UNPROTECTED_ATTRS$1 in parameters) {
+ this.unprotectedAttrs = getParametersValue(parameters, UNPROTECTED_ATTRS$1, EncryptedData.defaultValues(UNPROTECTED_ATTRS$1));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case VERSION$d:
+ return 0;
+ case ENCRYPTED_CONTENT_INFO$1:
+ return new EncryptedContentInfo();
+ case UNPROTECTED_ATTRS$1:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case VERSION$d:
+ return (memberValue === 0);
+ case ENCRYPTED_CONTENT_INFO$1:
+ return ((EncryptedContentInfo.compareWithDefault("contentType", memberValue.contentType)) &&
+ (EncryptedContentInfo.compareWithDefault("contentEncryptionAlgorithm", memberValue.contentEncryptionAlgorithm)) &&
+ (EncryptedContentInfo.compareWithDefault("encryptedContent", memberValue.encryptedContent)));
+ case UNPROTECTED_ATTRS$1:
+ return (memberValue.length === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Integer({ name: (names.version || EMPTY_STRING) }),
+ EncryptedContentInfo.schema(names.encryptedContentInfo || {}),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: [
+ new Repeated({
+ name: (names.unprotectedAttrs || EMPTY_STRING),
+ value: Attribute.schema()
+ })
+ ]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$L);
+ const asn1 = compareSchema(schema, schema, EncryptedData.schema({
+ names: {
+ version: VERSION$d,
+ encryptedContentInfo: {
+ names: {
+ blockName: ENCRYPTED_CONTENT_INFO$1
+ }
+ },
+ unprotectedAttrs: UNPROTECTED_ATTRS$1
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.version = asn1.result.version.valueBlock.valueDec;
+ this.encryptedContentInfo = new EncryptedContentInfo({ schema: asn1.result.encryptedContentInfo });
+ if (UNPROTECTED_ATTRS$1 in asn1.result)
+ this.unprotectedAttrs = Array.from(asn1.result.unprotectedAttrs, element => new Attribute({ schema: element }));
+ }
+ toSchema() {
+ const outputArray = [];
+ outputArray.push(new Integer({ value: this.version }));
+ outputArray.push(this.encryptedContentInfo.toSchema());
+ if (this.unprotectedAttrs) {
+ outputArray.push(new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: Array.from(this.unprotectedAttrs, o => o.toSchema())
+ }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {
+ version: this.version,
+ encryptedContentInfo: this.encryptedContentInfo.toJSON()
+ };
+ if (this.unprotectedAttrs)
+ res.unprotectedAttrs = Array.from(this.unprotectedAttrs, o => o.toJSON());
+ return res;
+ }
+ encrypt(parameters) {
+ return __awaiter(this, void 0, void 0, function* () {
+ ArgumentError.assert(parameters, "parameters", "object");
+ const encryptParams = Object.assign(Object.assign({}, parameters), { contentType: "1.2.840.113549.1.7.1" });
+ this.encryptedContentInfo = yield getCrypto(true).encryptEncryptedContentInfo(encryptParams);
+ });
+ }
+ decrypt(parameters, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ ArgumentError.assert(parameters, "parameters", "object");
+ const decryptParams = Object.assign(Object.assign({}, parameters), { encryptedContentInfo: this.encryptedContentInfo });
+ return crypto.decryptEncryptedContentInfo(decryptParams);
+ });
+ }
+}
+EncryptedData.CLASS_NAME = "EncryptedData";
+
+const ENCRYPTION_ALGORITHM = "encryptionAlgorithm";
+const ENCRYPTED_DATA = "encryptedData";
+const PARSED_VALUE$2 = "parsedValue";
+const CLEAR_PROPS$K = [
+ ENCRYPTION_ALGORITHM,
+ ENCRYPTED_DATA,
+];
+class PKCS8ShroudedKeyBag extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.encryptionAlgorithm = getParametersValue(parameters, ENCRYPTION_ALGORITHM, PKCS8ShroudedKeyBag.defaultValues(ENCRYPTION_ALGORITHM));
+ this.encryptedData = getParametersValue(parameters, ENCRYPTED_DATA, PKCS8ShroudedKeyBag.defaultValues(ENCRYPTED_DATA));
+ if (PARSED_VALUE$2 in parameters) {
+ this.parsedValue = getParametersValue(parameters, PARSED_VALUE$2, PKCS8ShroudedKeyBag.defaultValues(PARSED_VALUE$2));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case ENCRYPTION_ALGORITHM:
+ return (new AlgorithmIdentifier());
+ case ENCRYPTED_DATA:
+ return (new OctetString());
+ case PARSED_VALUE$2:
+ return {};
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case ENCRYPTION_ALGORITHM:
+ return ((AlgorithmIdentifier.compareWithDefault("algorithmId", memberValue.algorithmId)) &&
+ (("algorithmParams" in memberValue) === false));
+ case ENCRYPTED_DATA:
+ return (memberValue.isEqual(PKCS8ShroudedKeyBag.defaultValues(memberName)));
+ case PARSED_VALUE$2:
+ return ((memberValue instanceof Object) && (Object.keys(memberValue).length === 0));
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ AlgorithmIdentifier.schema(names.encryptionAlgorithm || {
+ names: {
+ blockName: ENCRYPTION_ALGORITHM
+ }
+ }),
+ new Choice({
+ value: [
+ new OctetString({ name: (names.encryptedData || ENCRYPTED_DATA) }),
+ new OctetString({
+ idBlock: {
+ isConstructed: true
+ },
+ name: (names.encryptedData || ENCRYPTED_DATA)
+ })
+ ]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$K);
+ const asn1 = compareSchema(schema, schema, PKCS8ShroudedKeyBag.schema({
+ names: {
+ encryptionAlgorithm: {
+ names: {
+ blockName: ENCRYPTION_ALGORITHM
+ }
+ },
+ encryptedData: ENCRYPTED_DATA
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.encryptionAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.encryptionAlgorithm });
+ this.encryptedData = asn1.result.encryptedData;
+ }
+ toSchema() {
+ return (new Sequence({
+ value: [
+ this.encryptionAlgorithm.toSchema(),
+ this.encryptedData
+ ]
+ }));
+ }
+ toJSON() {
+ return {
+ encryptionAlgorithm: this.encryptionAlgorithm.toJSON(),
+ encryptedData: this.encryptedData.toJSON(),
+ };
+ }
+ parseInternalValues(parameters, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const cmsEncrypted = new EncryptedData({
+ encryptedContentInfo: new EncryptedContentInfo({
+ contentEncryptionAlgorithm: this.encryptionAlgorithm,
+ encryptedContent: this.encryptedData
+ })
+ });
+ const decryptedData = yield cmsEncrypted.decrypt(parameters, crypto);
+ this.parsedValue = PrivateKeyInfo.fromBER(decryptedData);
+ });
+ }
+ makeInternalValues(parameters) {
+ return __awaiter(this, void 0, void 0, function* () {
+ if (!this.parsedValue) {
+ throw new Error("Please initialize \"parsedValue\" first");
+ }
+ const cmsEncrypted = new EncryptedData();
+ const encryptParams = Object.assign(Object.assign({}, parameters), { contentToEncrypt: this.parsedValue.toSchema().toBER(false) });
+ yield cmsEncrypted.encrypt(encryptParams);
+ if (!cmsEncrypted.encryptedContentInfo.encryptedContent) {
+ throw new Error("The filed `encryptedContent` in EncryptedContentInfo is empty");
+ }
+ this.encryptionAlgorithm = cmsEncrypted.encryptedContentInfo.contentEncryptionAlgorithm;
+ this.encryptedData = cmsEncrypted.encryptedContentInfo.encryptedContent;
+ });
+ }
+}
+PKCS8ShroudedKeyBag.CLASS_NAME = "PKCS8ShroudedKeyBag";
+
+const SECRET_TYPE_ID = "secretTypeId";
+const SECRET_VALUE = "secretValue";
+const CLEAR_PROPS$J = [
+ SECRET_TYPE_ID,
+ SECRET_VALUE,
+];
+class SecretBag extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.secretTypeId = getParametersValue(parameters, SECRET_TYPE_ID, SecretBag.defaultValues(SECRET_TYPE_ID));
+ this.secretValue = getParametersValue(parameters, SECRET_VALUE, SecretBag.defaultValues(SECRET_VALUE));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case SECRET_TYPE_ID:
+ return EMPTY_STRING;
+ case SECRET_VALUE:
+ return (new Any());
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case SECRET_TYPE_ID:
+ return (memberValue === EMPTY_STRING);
+ case SECRET_VALUE:
+ return (memberValue instanceof Any);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new ObjectIdentifier({ name: (names.id || "id") }),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [new Any({ name: (names.value || "value") })]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$J);
+ const asn1 = compareSchema(schema, schema, SecretBag.schema({
+ names: {
+ id: SECRET_TYPE_ID,
+ value: SECRET_VALUE
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.secretTypeId = asn1.result.secretTypeId.valueBlock.toString();
+ this.secretValue = asn1.result.secretValue;
+ }
+ toSchema() {
+ return (new Sequence({
+ value: [
+ new ObjectIdentifier({ value: this.secretTypeId }),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [this.secretValue.toSchema()]
+ })
+ ]
+ }));
+ }
+ toJSON() {
+ return {
+ secretTypeId: this.secretTypeId,
+ secretValue: this.secretValue.toJSON()
+ };
+ }
+}
+SecretBag.CLASS_NAME = "SecretBag";
+
+class SafeBagValueFactory {
+ static getItems() {
+ if (!this.items) {
+ this.items = {};
+ SafeBagValueFactory.register("1.2.840.113549.1.12.10.1.1", PrivateKeyInfo);
+ SafeBagValueFactory.register("1.2.840.113549.1.12.10.1.2", PKCS8ShroudedKeyBag);
+ SafeBagValueFactory.register("1.2.840.113549.1.12.10.1.3", CertBag);
+ SafeBagValueFactory.register("1.2.840.113549.1.12.10.1.4", CRLBag);
+ SafeBagValueFactory.register("1.2.840.113549.1.12.10.1.5", SecretBag);
+ SafeBagValueFactory.register("1.2.840.113549.1.12.10.1.6", SafeContents);
+ }
+ return this.items;
+ }
+ static register(id, type) {
+ this.getItems()[id] = type;
+ }
+ static find(id) {
+ return this.getItems()[id] || null;
+ }
+}
+
+const BAG_ID = "bagId";
+const BAG_VALUE = "bagValue";
+const BAG_ATTRIBUTES = "bagAttributes";
+const CLEAR_PROPS$I = [
+ BAG_ID,
+ BAG_VALUE,
+ BAG_ATTRIBUTES
+];
+class SafeBag extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.bagId = getParametersValue(parameters, BAG_ID, SafeBag.defaultValues(BAG_ID));
+ this.bagValue = getParametersValue(parameters, BAG_VALUE, SafeBag.defaultValues(BAG_VALUE));
+ if (BAG_ATTRIBUTES in parameters) {
+ this.bagAttributes = getParametersValue(parameters, BAG_ATTRIBUTES, SafeBag.defaultValues(BAG_ATTRIBUTES));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case BAG_ID:
+ return EMPTY_STRING;
+ case BAG_VALUE:
+ return (new Any());
+ case BAG_ATTRIBUTES:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case BAG_ID:
+ return (memberValue === EMPTY_STRING);
+ case BAG_VALUE:
+ return (memberValue instanceof Any);
+ case BAG_ATTRIBUTES:
+ return (memberValue.length === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new ObjectIdentifier({ name: (names.bagId || BAG_ID) }),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [new Any({ name: (names.bagValue || BAG_VALUE) })]
+ }),
+ new Set({
+ optional: true,
+ value: [
+ new Repeated({
+ name: (names.bagAttributes || BAG_ATTRIBUTES),
+ value: Attribute.schema()
+ })
+ ]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$I);
+ const asn1 = compareSchema(schema, schema, SafeBag.schema({
+ names: {
+ bagId: BAG_ID,
+ bagValue: BAG_VALUE,
+ bagAttributes: BAG_ATTRIBUTES
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.bagId = asn1.result.bagId.valueBlock.toString();
+ const bagType = SafeBagValueFactory.find(this.bagId);
+ if (!bagType) {
+ throw new Error(`Invalid BAG_ID for SafeBag: ${this.bagId}`);
+ }
+ this.bagValue = new bagType({ schema: asn1.result.bagValue });
+ if (BAG_ATTRIBUTES in asn1.result) {
+ this.bagAttributes = Array.from(asn1.result.bagAttributes, element => new Attribute({ schema: element }));
+ }
+ }
+ toSchema() {
+ const outputArray = [
+ new ObjectIdentifier({ value: this.bagId }),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [this.bagValue.toSchema()]
+ })
+ ];
+ if (this.bagAttributes) {
+ outputArray.push(new Set({
+ value: Array.from(this.bagAttributes, o => o.toSchema())
+ }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const output = {
+ bagId: this.bagId,
+ bagValue: this.bagValue.toJSON()
+ };
+ if (this.bagAttributes) {
+ output.bagAttributes = Array.from(this.bagAttributes, o => o.toJSON());
+ }
+ return output;
+ }
+}
+SafeBag.CLASS_NAME = "SafeBag";
+
+const SAFE_BUGS = "safeBags";
+class SafeContents extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.safeBags = getParametersValue(parameters, SAFE_BUGS, SafeContents.defaultValues(SAFE_BUGS));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case SAFE_BUGS:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case SAFE_BUGS:
+ return (memberValue.length === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Repeated({
+ name: (names.safeBags || EMPTY_STRING),
+ value: SafeBag.schema()
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, [
+ SAFE_BUGS
+ ]);
+ const asn1 = compareSchema(schema, schema, SafeContents.schema({
+ names: {
+ safeBags: SAFE_BUGS
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.safeBags = Array.from(asn1.result.safeBags, element => new SafeBag({ schema: element }));
+ }
+ toSchema() {
+ return (new Sequence({
+ value: Array.from(this.safeBags, o => o.toSchema())
+ }));
+ }
+ toJSON() {
+ return {
+ safeBags: Array.from(this.safeBags, o => o.toJSON())
+ };
+ }
+}
+SafeContents.CLASS_NAME = "SafeContents";
+
+const OTHER_CERT_FORMAT = "otherCertFormat";
+const OTHER_CERT = "otherCert";
+const CLEAR_PROPS$H = [
+ OTHER_CERT_FORMAT,
+ OTHER_CERT
+];
+class OtherCertificateFormat extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.otherCertFormat = getParametersValue(parameters, OTHER_CERT_FORMAT, OtherCertificateFormat.defaultValues(OTHER_CERT_FORMAT));
+ this.otherCert = getParametersValue(parameters, OTHER_CERT, OtherCertificateFormat.defaultValues(OTHER_CERT));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case OTHER_CERT_FORMAT:
+ return EMPTY_STRING;
+ case OTHER_CERT:
+ return new Any();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new ObjectIdentifier({ name: (names.otherCertFormat || OTHER_CERT_FORMAT) }),
+ new Any({ name: (names.otherCert || OTHER_CERT) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$H);
+ const asn1 = compareSchema(schema, schema, OtherCertificateFormat.schema());
+ AsnError.assertSchema(asn1, this.className);
+ this.otherCertFormat = asn1.result.otherCertFormat.valueBlock.toString();
+ this.otherCert = asn1.result.otherCert;
+ }
+ toSchema() {
+ return (new Sequence({
+ value: [
+ new ObjectIdentifier({ value: this.otherCertFormat }),
+ this.otherCert
+ ]
+ }));
+ }
+ toJSON() {
+ const res = {
+ otherCertFormat: this.otherCertFormat
+ };
+ if (!(this.otherCert instanceof Any)) {
+ res.otherCert = this.otherCert.toJSON();
+ }
+ return res;
+ }
+}
+
+const CERTIFICATES$1 = "certificates";
+const CLEAR_PROPS$G = [
+ CERTIFICATES$1,
+];
+class CertificateSet extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.certificates = getParametersValue(parameters, CERTIFICATES$1, CertificateSet.defaultValues(CERTIFICATES$1));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case CERTIFICATES$1:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Set({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Repeated({
+ name: (names.certificates || CERTIFICATES$1),
+ value: new Choice({
+ value: [
+ Certificate.schema(),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [
+ new Any()
+ ]
+ }),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: [
+ new Sequence
+ ]
+ }),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ },
+ value: AttributeCertificateV2.schema().valueBlock.value
+ }),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 3
+ },
+ value: OtherCertificateFormat.schema().valueBlock.value
+ })
+ ]
+ })
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$G);
+ const asn1 = compareSchema(schema, schema, CertificateSet.schema());
+ AsnError.assertSchema(asn1, this.className);
+ this.certificates = Array.from(asn1.result.certificates || [], (element) => {
+ const initialTagNumber = element.idBlock.tagNumber;
+ if (element.idBlock.tagClass === 1)
+ return new Certificate({ schema: element });
+ const elementSequence = new Sequence({
+ value: element.valueBlock.value
+ });
+ switch (initialTagNumber) {
+ case 1:
+ if (elementSequence.valueBlock.value[0].valueBlock.value[0].valueBlock.valueDec === 1) {
+ return new AttributeCertificateV2({ schema: elementSequence });
+ }
+ else {
+ return new AttributeCertificateV1({ schema: elementSequence });
+ }
+ case 2:
+ return new AttributeCertificateV2({ schema: elementSequence });
+ case 3:
+ return new OtherCertificateFormat({ schema: elementSequence });
+ }
+ return element;
+ });
+ }
+ toSchema() {
+ return (new Set({
+ value: Array.from(this.certificates, element => {
+ switch (true) {
+ case (element instanceof Certificate):
+ return element.toSchema();
+ case (element instanceof AttributeCertificateV1):
+ return new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: element.toSchema().valueBlock.value
+ });
+ case (element instanceof AttributeCertificateV2):
+ return new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ },
+ value: element.toSchema().valueBlock.value
+ });
+ case (element instanceof OtherCertificateFormat):
+ return new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 3
+ },
+ value: element.toSchema().valueBlock.value
+ });
+ }
+ return element.toSchema();
+ })
+ }));
+ }
+ toJSON() {
+ return {
+ certificates: Array.from(this.certificates, o => o.toJSON())
+ };
+ }
+}
+CertificateSet.CLASS_NAME = "CertificateSet";
+
+const OTHER_REV_INFO_FORMAT = "otherRevInfoFormat";
+const OTHER_REV_INFO = "otherRevInfo";
+const CLEAR_PROPS$F = [
+ OTHER_REV_INFO_FORMAT,
+ OTHER_REV_INFO
+];
+class OtherRevocationInfoFormat extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.otherRevInfoFormat = getParametersValue(parameters, OTHER_REV_INFO_FORMAT, OtherRevocationInfoFormat.defaultValues(OTHER_REV_INFO_FORMAT));
+ this.otherRevInfo = getParametersValue(parameters, OTHER_REV_INFO, OtherRevocationInfoFormat.defaultValues(OTHER_REV_INFO));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case OTHER_REV_INFO_FORMAT:
+ return EMPTY_STRING;
+ case OTHER_REV_INFO:
+ return new Any();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new ObjectIdentifier({ name: (names.otherRevInfoFormat || OTHER_REV_INFO_FORMAT) }),
+ new Any({ name: (names.otherRevInfo || OTHER_REV_INFO) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$F);
+ const asn1 = compareSchema(schema, schema, OtherRevocationInfoFormat.schema());
+ AsnError.assertSchema(asn1, this.className);
+ this.otherRevInfoFormat = asn1.result.otherRevInfoFormat.valueBlock.toString();
+ this.otherRevInfo = asn1.result.otherRevInfo;
+ }
+ toSchema() {
+ return (new Sequence({
+ value: [
+ new ObjectIdentifier({ value: this.otherRevInfoFormat }),
+ this.otherRevInfo
+ ]
+ }));
+ }
+ toJSON() {
+ const res = {
+ otherRevInfoFormat: this.otherRevInfoFormat
+ };
+ if (!(this.otherRevInfo instanceof Any)) {
+ res.otherRevInfo = this.otherRevInfo.toJSON();
+ }
+ return res;
+ }
+}
+OtherRevocationInfoFormat.CLASS_NAME = "OtherRevocationInfoFormat";
+
+const CRLS$3 = "crls";
+const OTHER_REVOCATION_INFOS = "otherRevocationInfos";
+const CLEAR_PROPS$E = [
+ CRLS$3
+];
+class RevocationInfoChoices extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.crls = getParametersValue(parameters, CRLS$3, RevocationInfoChoices.defaultValues(CRLS$3));
+ this.otherRevocationInfos = getParametersValue(parameters, OTHER_REVOCATION_INFOS, RevocationInfoChoices.defaultValues(OTHER_REVOCATION_INFOS));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case CRLS$3:
+ return [];
+ case OTHER_REVOCATION_INFOS:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Set({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Repeated({
+ name: (names.crls || EMPTY_STRING),
+ value: new Choice({
+ value: [
+ CertificateRevocationList.schema(),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: [
+ new ObjectIdentifier(),
+ new Any()
+ ]
+ })
+ ]
+ })
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$E);
+ const asn1 = compareSchema(schema, schema, RevocationInfoChoices.schema({
+ names: {
+ crls: CRLS$3
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ if (asn1.result.crls) {
+ for (const element of asn1.result.crls) {
+ if (element.idBlock.tagClass === 1)
+ this.crls.push(new CertificateRevocationList({ schema: element }));
+ else
+ this.otherRevocationInfos.push(new OtherRevocationInfoFormat({ schema: element }));
+ }
+ }
+ }
+ toSchema() {
+ const outputArray = [];
+ outputArray.push(...Array.from(this.crls, o => o.toSchema()));
+ outputArray.push(...Array.from(this.otherRevocationInfos, element => {
+ const schema = element.toSchema();
+ schema.idBlock.tagClass = 3;
+ schema.idBlock.tagNumber = 1;
+ return schema;
+ }));
+ return (new Set({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ return {
+ crls: Array.from(this.crls, o => o.toJSON()),
+ otherRevocationInfos: Array.from(this.otherRevocationInfos, o => o.toJSON())
+ };
+ }
+}
+RevocationInfoChoices.CLASS_NAME = "RevocationInfoChoices";
+
+const CERTS$3 = "certs";
+const CRLS$2 = "crls";
+const CLEAR_PROPS$D = [
+ CERTS$3,
+ CRLS$2,
+];
+class OriginatorInfo extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.crls = getParametersValue(parameters, CRLS$2, OriginatorInfo.defaultValues(CRLS$2));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case CERTS$3:
+ return new CertificateSet();
+ case CRLS$2:
+ return new RevocationInfoChoices();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case CERTS$3:
+ return (memberValue.certificates.length === 0);
+ case CRLS$2:
+ return ((memberValue.crls.length === 0) && (memberValue.otherRevocationInfos.length === 0));
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Constructed({
+ name: (names.certs || EMPTY_STRING),
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: CertificateSet.schema().valueBlock.value
+ }),
+ new Constructed({
+ name: (names.crls || EMPTY_STRING),
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: RevocationInfoChoices.schema().valueBlock.value
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$D);
+ const asn1 = compareSchema(schema, schema, OriginatorInfo.schema({
+ names: {
+ certs: CERTS$3,
+ crls: CRLS$2
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ if (CERTS$3 in asn1.result) {
+ this.certs = new CertificateSet({
+ schema: new Set({
+ value: asn1.result.certs.valueBlock.value
+ })
+ });
+ }
+ if (CRLS$2 in asn1.result) {
+ this.crls = new RevocationInfoChoices({
+ schema: new Set({
+ value: asn1.result.crls.valueBlock.value
+ })
+ });
+ }
+ }
+ toSchema() {
+ const sequenceValue = [];
+ if (this.certs) {
+ sequenceValue.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: this.certs.toSchema().valueBlock.value
+ }));
+ }
+ if (this.crls) {
+ sequenceValue.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: this.crls.toSchema().valueBlock.value
+ }));
+ }
+ return (new Sequence({
+ value: sequenceValue
+ }));
+ }
+ toJSON() {
+ const res = {};
+ if (this.certs) {
+ res.certs = this.certs.toJSON();
+ }
+ if (this.crls) {
+ res.crls = this.crls.toJSON();
+ }
+ return res;
+ }
+}
+OriginatorInfo.CLASS_NAME = "OriginatorInfo";
+
+const ISSUER = "issuer";
+const SERIAL_NUMBER$2 = "serialNumber";
+const CLEAR_PROPS$C = [
+ ISSUER,
+ SERIAL_NUMBER$2,
+];
+class IssuerAndSerialNumber extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.issuer = getParametersValue(parameters, ISSUER, IssuerAndSerialNumber.defaultValues(ISSUER));
+ this.serialNumber = getParametersValue(parameters, SERIAL_NUMBER$2, IssuerAndSerialNumber.defaultValues(SERIAL_NUMBER$2));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case ISSUER:
+ return new RelativeDistinguishedNames();
+ case SERIAL_NUMBER$2:
+ return new Integer();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ RelativeDistinguishedNames.schema(names.issuer || {}),
+ new Integer({ name: (names.serialNumber || EMPTY_STRING) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$C);
+ const asn1 = compareSchema(schema, schema, IssuerAndSerialNumber.schema({
+ names: {
+ issuer: {
+ names: {
+ blockName: ISSUER
+ }
+ },
+ serialNumber: SERIAL_NUMBER$2
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.issuer = new RelativeDistinguishedNames({ schema: asn1.result.issuer });
+ this.serialNumber = asn1.result.serialNumber;
+ }
+ toSchema() {
+ return (new Sequence({
+ value: [
+ this.issuer.toSchema(),
+ this.serialNumber
+ ]
+ }));
+ }
+ toJSON() {
+ return {
+ issuer: this.issuer.toJSON(),
+ serialNumber: this.serialNumber.toJSON(),
+ };
+ }
+}
+IssuerAndSerialNumber.CLASS_NAME = "IssuerAndSerialNumber";
+
+const VARIANT$3 = "variant";
+const VALUE$3 = "value";
+const CLEAR_PROPS$B = [
+ "blockName"
+];
+class RecipientIdentifier extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.variant = getParametersValue(parameters, VARIANT$3, RecipientIdentifier.defaultValues(VARIANT$3));
+ if (VALUE$3 in parameters) {
+ this.value = getParametersValue(parameters, VALUE$3, RecipientIdentifier.defaultValues(VALUE$3));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case VARIANT$3:
+ return (-1);
+ case VALUE$3:
+ return {};
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case VARIANT$3:
+ return (memberValue === (-1));
+ case VALUE$3:
+ return (Object.keys(memberValue).length === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Choice({
+ value: [
+ IssuerAndSerialNumber.schema({
+ names: {
+ blockName: (names.blockName || EMPTY_STRING)
+ }
+ }),
+ new Primitive({
+ name: (names.blockName || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ }
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$B);
+ const asn1 = compareSchema(schema, schema, RecipientIdentifier.schema({
+ names: {
+ blockName: "blockName"
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ if (asn1.result.blockName.idBlock.tagClass === 1) {
+ this.variant = 1;
+ this.value = new IssuerAndSerialNumber({ schema: asn1.result.blockName });
+ }
+ else {
+ this.variant = 2;
+ this.value = new OctetString({ valueHex: asn1.result.blockName.valueBlock.valueHex });
+ }
+ }
+ toSchema() {
+ switch (this.variant) {
+ case 1:
+ if (!(this.value instanceof IssuerAndSerialNumber)) {
+ throw new Error("Incorrect type of RecipientIdentifier.value. It should be IssuerAndSerialNumber.");
+ }
+ return this.value.toSchema();
+ case 2:
+ if (!(this.value instanceof OctetString)) {
+ throw new Error("Incorrect type of RecipientIdentifier.value. It should be ASN.1 OctetString.");
+ }
+ return new Primitive({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ valueHex: this.value.valueBlock.valueHexView
+ });
+ default:
+ return new Any();
+ }
+ }
+ toJSON() {
+ const res = {
+ variant: this.variant
+ };
+ if ((this.variant === 1 || this.variant === 2) && this.value) {
+ res.value = this.value.toJSON();
+ }
+ return res;
+ }
+}
+RecipientIdentifier.CLASS_NAME = "RecipientIdentifier";
+
+const VERSION$c = "version";
+const RID$1 = "rid";
+const KEY_ENCRYPTION_ALGORITHM$3 = "keyEncryptionAlgorithm";
+const ENCRYPTED_KEY$3 = "encryptedKey";
+const RECIPIENT_CERTIFICATE$1 = "recipientCertificate";
+const CLEAR_PROPS$A = [
+ VERSION$c,
+ RID$1,
+ KEY_ENCRYPTION_ALGORITHM$3,
+ ENCRYPTED_KEY$3,
+];
+class KeyTransRecipientInfo extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.version = getParametersValue(parameters, VERSION$c, KeyTransRecipientInfo.defaultValues(VERSION$c));
+ this.rid = getParametersValue(parameters, RID$1, KeyTransRecipientInfo.defaultValues(RID$1));
+ this.keyEncryptionAlgorithm = getParametersValue(parameters, KEY_ENCRYPTION_ALGORITHM$3, KeyTransRecipientInfo.defaultValues(KEY_ENCRYPTION_ALGORITHM$3));
+ this.encryptedKey = getParametersValue(parameters, ENCRYPTED_KEY$3, KeyTransRecipientInfo.defaultValues(ENCRYPTED_KEY$3));
+ this.recipientCertificate = getParametersValue(parameters, RECIPIENT_CERTIFICATE$1, KeyTransRecipientInfo.defaultValues(RECIPIENT_CERTIFICATE$1));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case VERSION$c:
+ return (-1);
+ case RID$1:
+ return {};
+ case KEY_ENCRYPTION_ALGORITHM$3:
+ return new AlgorithmIdentifier();
+ case ENCRYPTED_KEY$3:
+ return new OctetString();
+ case RECIPIENT_CERTIFICATE$1:
+ return new Certificate();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case VERSION$c:
+ return (memberValue === KeyTransRecipientInfo.defaultValues(VERSION$c));
+ case RID$1:
+ return (Object.keys(memberValue).length === 0);
+ case KEY_ENCRYPTION_ALGORITHM$3:
+ case ENCRYPTED_KEY$3:
+ return memberValue.isEqual(KeyTransRecipientInfo.defaultValues(memberName));
+ case RECIPIENT_CERTIFICATE$1:
+ return false;
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Integer({ name: (names.version || EMPTY_STRING) }),
+ RecipientIdentifier.schema(names.rid || {}),
+ AlgorithmIdentifier.schema(names.keyEncryptionAlgorithm || {}),
+ new OctetString({ name: (names.encryptedKey || EMPTY_STRING) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$A);
+ const asn1 = compareSchema(schema, schema, KeyTransRecipientInfo.schema({
+ names: {
+ version: VERSION$c,
+ rid: {
+ names: {
+ blockName: RID$1
+ }
+ },
+ keyEncryptionAlgorithm: {
+ names: {
+ blockName: KEY_ENCRYPTION_ALGORITHM$3
+ }
+ },
+ encryptedKey: ENCRYPTED_KEY$3
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.version = asn1.result.version.valueBlock.valueDec;
+ if (asn1.result.rid.idBlock.tagClass === 3) {
+ this.rid = new OctetString({ valueHex: asn1.result.rid.valueBlock.valueHex });
+ }
+ else {
+ this.rid = new IssuerAndSerialNumber({ schema: asn1.result.rid });
+ }
+ this.keyEncryptionAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.keyEncryptionAlgorithm });
+ this.encryptedKey = asn1.result.encryptedKey;
+ }
+ toSchema() {
+ const outputArray = [];
+ if (this.rid instanceof IssuerAndSerialNumber) {
+ this.version = 0;
+ outputArray.push(new Integer({ value: this.version }));
+ outputArray.push(this.rid.toSchema());
+ }
+ else {
+ this.version = 2;
+ outputArray.push(new Integer({ value: this.version }));
+ outputArray.push(new Primitive({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ valueHex: this.rid.valueBlock.valueHexView
+ }));
+ }
+ outputArray.push(this.keyEncryptionAlgorithm.toSchema());
+ outputArray.push(this.encryptedKey);
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ return {
+ version: this.version,
+ rid: this.rid.toJSON(),
+ keyEncryptionAlgorithm: this.keyEncryptionAlgorithm.toJSON(),
+ encryptedKey: this.encryptedKey.toJSON(),
+ };
+ }
+}
+KeyTransRecipientInfo.CLASS_NAME = "KeyTransRecipientInfo";
+
+const ALGORITHM = "algorithm";
+const PUBLIC_KEY = "publicKey";
+const CLEAR_PROPS$z = [
+ ALGORITHM,
+ PUBLIC_KEY
+];
+class OriginatorPublicKey extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.algorithm = getParametersValue(parameters, ALGORITHM, OriginatorPublicKey.defaultValues(ALGORITHM));
+ this.publicKey = getParametersValue(parameters, PUBLIC_KEY, OriginatorPublicKey.defaultValues(PUBLIC_KEY));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case ALGORITHM:
+ return new AlgorithmIdentifier();
+ case PUBLIC_KEY:
+ return new BitString();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case ALGORITHM:
+ case PUBLIC_KEY:
+ return (memberValue.isEqual(OriginatorPublicKey.defaultValues(memberName)));
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ AlgorithmIdentifier.schema(names.algorithm || {}),
+ new BitString({ name: (names.publicKey || EMPTY_STRING) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$z);
+ const asn1 = compareSchema(schema, schema, OriginatorPublicKey.schema({
+ names: {
+ algorithm: {
+ names: {
+ blockName: ALGORITHM
+ }
+ },
+ publicKey: PUBLIC_KEY
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.algorithm = new AlgorithmIdentifier({ schema: asn1.result.algorithm });
+ this.publicKey = asn1.result.publicKey;
+ }
+ toSchema() {
+ return (new Sequence({
+ value: [
+ this.algorithm.toSchema(),
+ this.publicKey
+ ]
+ }));
+ }
+ toJSON() {
+ return {
+ algorithm: this.algorithm.toJSON(),
+ publicKey: this.publicKey.toJSON(),
+ };
+ }
+}
+OriginatorPublicKey.CLASS_NAME = "OriginatorPublicKey";
+
+const VARIANT$2 = "variant";
+const VALUE$2 = "value";
+const CLEAR_PROPS$y = [
+ "blockName",
+];
+class OriginatorIdentifierOrKey extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.variant = getParametersValue(parameters, VARIANT$2, OriginatorIdentifierOrKey.defaultValues(VARIANT$2));
+ if (VALUE$2 in parameters) {
+ this.value = getParametersValue(parameters, VALUE$2, OriginatorIdentifierOrKey.defaultValues(VALUE$2));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case VARIANT$2:
+ return (-1);
+ case VALUE$2:
+ return {};
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case VARIANT$2:
+ return (memberValue === (-1));
+ case VALUE$2:
+ return (Object.keys(memberValue).length === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Choice({
+ value: [
+ IssuerAndSerialNumber.schema({
+ names: {
+ blockName: (names.blockName || EMPTY_STRING)
+ }
+ }),
+ new Primitive({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ name: (names.blockName || EMPTY_STRING)
+ }),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ name: (names.blockName || EMPTY_STRING),
+ value: OriginatorPublicKey.schema().valueBlock.value
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$y);
+ const asn1 = compareSchema(schema, schema, OriginatorIdentifierOrKey.schema({
+ names: {
+ blockName: "blockName"
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ if (asn1.result.blockName.idBlock.tagClass === 1) {
+ this.variant = 1;
+ this.value = new IssuerAndSerialNumber({ schema: asn1.result.blockName });
+ }
+ else {
+ if (asn1.result.blockName.idBlock.tagNumber === 0) {
+ asn1.result.blockName.idBlock.tagClass = 1;
+ asn1.result.blockName.idBlock.tagNumber = 4;
+ this.variant = 2;
+ this.value = asn1.result.blockName;
+ }
+ else {
+ this.variant = 3;
+ this.value = new OriginatorPublicKey({
+ schema: new Sequence({
+ value: asn1.result.blockName.valueBlock.value
+ })
+ });
+ }
+ }
+ }
+ toSchema() {
+ switch (this.variant) {
+ case 1:
+ return this.value.toSchema();
+ case 2:
+ this.value.idBlock.tagClass = 3;
+ this.value.idBlock.tagNumber = 0;
+ return this.value;
+ case 3:
+ {
+ const _schema = this.value.toSchema();
+ _schema.idBlock.tagClass = 3;
+ _schema.idBlock.tagNumber = 1;
+ return _schema;
+ }
+ default:
+ return new Any();
+ }
+ }
+ toJSON() {
+ const res = {
+ variant: this.variant
+ };
+ if ((this.variant === 1) || (this.variant === 2) || (this.variant === 3)) {
+ res.value = this.value.toJSON();
+ }
+ return res;
+ }
+}
+OriginatorIdentifierOrKey.CLASS_NAME = "OriginatorIdentifierOrKey";
+
+const KEY_ATTR_ID = "keyAttrId";
+const KEY_ATTR = "keyAttr";
+const CLEAR_PROPS$x = [
+ KEY_ATTR_ID,
+ KEY_ATTR,
+];
+class OtherKeyAttribute extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.keyAttrId = getParametersValue(parameters, KEY_ATTR_ID, OtherKeyAttribute.defaultValues(KEY_ATTR_ID));
+ if (KEY_ATTR in parameters) {
+ this.keyAttr = getParametersValue(parameters, KEY_ATTR, OtherKeyAttribute.defaultValues(KEY_ATTR));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case KEY_ATTR_ID:
+ return EMPTY_STRING;
+ case KEY_ATTR:
+ return {};
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case KEY_ATTR_ID:
+ return (typeof memberValue === "string" && memberValue === EMPTY_STRING);
+ case KEY_ATTR:
+ return (Object.keys(memberValue).length === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ optional: (names.optional || true),
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new ObjectIdentifier({ name: (names.keyAttrId || EMPTY_STRING) }),
+ new Any({
+ optional: true,
+ name: (names.keyAttr || EMPTY_STRING)
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$x);
+ const asn1 = compareSchema(schema, schema, OtherKeyAttribute.schema({
+ names: {
+ keyAttrId: KEY_ATTR_ID,
+ keyAttr: KEY_ATTR
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.keyAttrId = asn1.result.keyAttrId.valueBlock.toString();
+ if (KEY_ATTR in asn1.result) {
+ this.keyAttr = asn1.result.keyAttr;
+ }
+ }
+ toSchema() {
+ const outputArray = [];
+ outputArray.push(new ObjectIdentifier({ value: this.keyAttrId }));
+ if (KEY_ATTR in this) {
+ outputArray.push(this.keyAttr);
+ }
+ return (new Sequence({
+ value: outputArray,
+ }));
+ }
+ toJSON() {
+ const res = {
+ keyAttrId: this.keyAttrId
+ };
+ if (KEY_ATTR in this) {
+ res.keyAttr = this.keyAttr.toJSON();
+ }
+ return res;
+ }
+}
+OtherKeyAttribute.CLASS_NAME = "OtherKeyAttribute";
+
+const SUBJECT_KEY_IDENTIFIER = "subjectKeyIdentifier";
+const DATE$1 = "date";
+const OTHER$1 = "other";
+const CLEAR_PROPS$w = [
+ SUBJECT_KEY_IDENTIFIER,
+ DATE$1,
+ OTHER$1,
+];
+class RecipientKeyIdentifier extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.subjectKeyIdentifier = getParametersValue(parameters, SUBJECT_KEY_IDENTIFIER, RecipientKeyIdentifier.defaultValues(SUBJECT_KEY_IDENTIFIER));
+ if (DATE$1 in parameters) {
+ this.date = getParametersValue(parameters, DATE$1, RecipientKeyIdentifier.defaultValues(DATE$1));
+ }
+ if (OTHER$1 in parameters) {
+ this.other = getParametersValue(parameters, OTHER$1, RecipientKeyIdentifier.defaultValues(OTHER$1));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case SUBJECT_KEY_IDENTIFIER:
+ return new OctetString();
+ case DATE$1:
+ return new GeneralizedTime();
+ case OTHER$1:
+ return new OtherKeyAttribute();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case SUBJECT_KEY_IDENTIFIER:
+ return (memberValue.isEqual(RecipientKeyIdentifier.defaultValues(SUBJECT_KEY_IDENTIFIER)));
+ case DATE$1:
+ return ((memberValue.year === 0) &&
+ (memberValue.month === 0) &&
+ (memberValue.day === 0) &&
+ (memberValue.hour === 0) &&
+ (memberValue.minute === 0) &&
+ (memberValue.second === 0) &&
+ (memberValue.millisecond === 0));
+ case OTHER$1:
+ return ((memberValue.keyAttrId === EMPTY_STRING) && (("keyAttr" in memberValue) === false));
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new OctetString({ name: (names.subjectKeyIdentifier || EMPTY_STRING) }),
+ new GeneralizedTime({
+ optional: true,
+ name: (names.date || EMPTY_STRING)
+ }),
+ OtherKeyAttribute.schema(names.other || {})
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$w);
+ const asn1 = compareSchema(schema, schema, RecipientKeyIdentifier.schema({
+ names: {
+ subjectKeyIdentifier: SUBJECT_KEY_IDENTIFIER,
+ date: DATE$1,
+ other: {
+ names: {
+ blockName: OTHER$1
+ }
+ }
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.subjectKeyIdentifier = asn1.result.subjectKeyIdentifier;
+ if (DATE$1 in asn1.result)
+ this.date = asn1.result.date;
+ if (OTHER$1 in asn1.result)
+ this.other = new OtherKeyAttribute({ schema: asn1.result.other });
+ }
+ toSchema() {
+ const outputArray = [];
+ outputArray.push(this.subjectKeyIdentifier);
+ if (this.date) {
+ outputArray.push(this.date);
+ }
+ if (this.other) {
+ outputArray.push(this.other.toSchema());
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {
+ subjectKeyIdentifier: this.subjectKeyIdentifier.toJSON()
+ };
+ if (this.date) {
+ res.date = this.date.toJSON();
+ }
+ if (this.other) {
+ res.other = this.other.toJSON();
+ }
+ return res;
+ }
+}
+RecipientKeyIdentifier.CLASS_NAME = "RecipientKeyIdentifier";
+
+const VARIANT$1 = "variant";
+const VALUE$1 = "value";
+const CLEAR_PROPS$v = [
+ "blockName",
+];
+class KeyAgreeRecipientIdentifier extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.variant = getParametersValue(parameters, VARIANT$1, KeyAgreeRecipientIdentifier.defaultValues(VARIANT$1));
+ this.value = getParametersValue(parameters, VALUE$1, KeyAgreeRecipientIdentifier.defaultValues(VALUE$1));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case VARIANT$1:
+ return (-1);
+ case VALUE$1:
+ return {};
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case VARIANT$1:
+ return (memberValue === (-1));
+ case VALUE$1:
+ return (Object.keys(memberValue).length === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Choice({
+ value: [
+ IssuerAndSerialNumber.schema(names.issuerAndSerialNumber || {
+ names: {
+ blockName: (names.blockName || EMPTY_STRING)
+ }
+ }),
+ new Constructed({
+ name: (names.blockName || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: RecipientKeyIdentifier.schema(names.rKeyId || {
+ names: {
+ blockName: (names.blockName || EMPTY_STRING)
+ }
+ }).valueBlock.value
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$v);
+ const asn1 = compareSchema(schema, schema, KeyAgreeRecipientIdentifier.schema({
+ names: {
+ blockName: "blockName"
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ if (asn1.result.blockName.idBlock.tagClass === 1) {
+ this.variant = 1;
+ this.value = new IssuerAndSerialNumber({ schema: asn1.result.blockName });
+ }
+ else {
+ this.variant = 2;
+ this.value = new RecipientKeyIdentifier({
+ schema: new Sequence({
+ value: asn1.result.blockName.valueBlock.value
+ })
+ });
+ }
+ }
+ toSchema() {
+ switch (this.variant) {
+ case 1:
+ return this.value.toSchema();
+ case 2:
+ return new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: this.value.toSchema().valueBlock.value
+ });
+ default:
+ return new Any();
+ }
+ }
+ toJSON() {
+ const res = {
+ variant: this.variant,
+ };
+ if ((this.variant === 1) || (this.variant === 2)) {
+ res.value = this.value.toJSON();
+ }
+ return res;
+ }
+}
+KeyAgreeRecipientIdentifier.CLASS_NAME = "KeyAgreeRecipientIdentifier";
+
+const RID = "rid";
+const ENCRYPTED_KEY$2 = "encryptedKey";
+const CLEAR_PROPS$u = [
+ RID,
+ ENCRYPTED_KEY$2,
+];
+class RecipientEncryptedKey extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.rid = getParametersValue(parameters, RID, RecipientEncryptedKey.defaultValues(RID));
+ this.encryptedKey = getParametersValue(parameters, ENCRYPTED_KEY$2, RecipientEncryptedKey.defaultValues(ENCRYPTED_KEY$2));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case RID:
+ return new KeyAgreeRecipientIdentifier();
+ case ENCRYPTED_KEY$2:
+ return new OctetString();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case RID:
+ return ((memberValue.variant === (-1)) && (("value" in memberValue) === false));
+ case ENCRYPTED_KEY$2:
+ return (memberValue.isEqual(RecipientEncryptedKey.defaultValues(ENCRYPTED_KEY$2)));
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ KeyAgreeRecipientIdentifier.schema(names.rid || {}),
+ new OctetString({ name: (names.encryptedKey || EMPTY_STRING) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$u);
+ const asn1 = compareSchema(schema, schema, RecipientEncryptedKey.schema({
+ names: {
+ rid: {
+ names: {
+ blockName: RID
+ }
+ },
+ encryptedKey: ENCRYPTED_KEY$2
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.rid = new KeyAgreeRecipientIdentifier({ schema: asn1.result.rid });
+ this.encryptedKey = asn1.result.encryptedKey;
+ }
+ toSchema() {
+ return (new Sequence({
+ value: [
+ this.rid.toSchema(),
+ this.encryptedKey
+ ]
+ }));
+ }
+ toJSON() {
+ return {
+ rid: this.rid.toJSON(),
+ encryptedKey: this.encryptedKey.toJSON(),
+ };
+ }
+}
+RecipientEncryptedKey.CLASS_NAME = "RecipientEncryptedKey";
+
+const ENCRYPTED_KEYS = "encryptedKeys";
+const RECIPIENT_ENCRYPTED_KEYS = "RecipientEncryptedKeys";
+const CLEAR_PROPS$t = [
+ RECIPIENT_ENCRYPTED_KEYS,
+];
+class RecipientEncryptedKeys extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.encryptedKeys = getParametersValue(parameters, ENCRYPTED_KEYS, RecipientEncryptedKeys.defaultValues(ENCRYPTED_KEYS));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case ENCRYPTED_KEYS:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case ENCRYPTED_KEYS:
+ return (memberValue.length === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Repeated({
+ name: (names.RecipientEncryptedKeys || EMPTY_STRING),
+ value: RecipientEncryptedKey.schema()
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$t);
+ const asn1 = compareSchema(schema, schema, RecipientEncryptedKeys.schema({
+ names: {
+ RecipientEncryptedKeys: RECIPIENT_ENCRYPTED_KEYS
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.encryptedKeys = Array.from(asn1.result.RecipientEncryptedKeys, element => new RecipientEncryptedKey({ schema: element }));
+ }
+ toSchema() {
+ return (new Sequence({
+ value: Array.from(this.encryptedKeys, o => o.toSchema())
+ }));
+ }
+ toJSON() {
+ return {
+ encryptedKeys: Array.from(this.encryptedKeys, o => o.toJSON())
+ };
+ }
+}
+RecipientEncryptedKeys.CLASS_NAME = "RecipientEncryptedKeys";
+
+const VERSION$b = "version";
+const ORIGINATOR = "originator";
+const UKM = "ukm";
+const KEY_ENCRYPTION_ALGORITHM$2 = "keyEncryptionAlgorithm";
+const RECIPIENT_ENCRYPTED_KEY = "recipientEncryptedKeys";
+const RECIPIENT_CERTIFICATE = "recipientCertificate";
+const RECIPIENT_PUBLIC_KEY = "recipientPublicKey";
+const CLEAR_PROPS$s = [
+ VERSION$b,
+ ORIGINATOR,
+ UKM,
+ KEY_ENCRYPTION_ALGORITHM$2,
+ RECIPIENT_ENCRYPTED_KEY,
+];
+class KeyAgreeRecipientInfo extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.version = getParametersValue(parameters, VERSION$b, KeyAgreeRecipientInfo.defaultValues(VERSION$b));
+ this.originator = getParametersValue(parameters, ORIGINATOR, KeyAgreeRecipientInfo.defaultValues(ORIGINATOR));
+ if (UKM in parameters) {
+ this.ukm = getParametersValue(parameters, UKM, KeyAgreeRecipientInfo.defaultValues(UKM));
+ }
+ this.keyEncryptionAlgorithm = getParametersValue(parameters, KEY_ENCRYPTION_ALGORITHM$2, KeyAgreeRecipientInfo.defaultValues(KEY_ENCRYPTION_ALGORITHM$2));
+ this.recipientEncryptedKeys = getParametersValue(parameters, RECIPIENT_ENCRYPTED_KEY, KeyAgreeRecipientInfo.defaultValues(RECIPIENT_ENCRYPTED_KEY));
+ this.recipientCertificate = getParametersValue(parameters, RECIPIENT_CERTIFICATE, KeyAgreeRecipientInfo.defaultValues(RECIPIENT_CERTIFICATE));
+ this.recipientPublicKey = getParametersValue(parameters, RECIPIENT_PUBLIC_KEY, KeyAgreeRecipientInfo.defaultValues(RECIPIENT_PUBLIC_KEY));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case VERSION$b:
+ return 0;
+ case ORIGINATOR:
+ return new OriginatorIdentifierOrKey();
+ case UKM:
+ return new OctetString();
+ case KEY_ENCRYPTION_ALGORITHM$2:
+ return new AlgorithmIdentifier();
+ case RECIPIENT_ENCRYPTED_KEY:
+ return new RecipientEncryptedKeys();
+ case RECIPIENT_CERTIFICATE:
+ return new Certificate();
+ case RECIPIENT_PUBLIC_KEY:
+ return null;
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case VERSION$b:
+ return (memberValue === 0);
+ case ORIGINATOR:
+ return ((memberValue.variant === (-1)) && (("value" in memberValue) === false));
+ case UKM:
+ return (memberValue.isEqual(KeyAgreeRecipientInfo.defaultValues(UKM)));
+ case KEY_ENCRYPTION_ALGORITHM$2:
+ return ((memberValue.algorithmId === EMPTY_STRING) && (("algorithmParams" in memberValue) === false));
+ case RECIPIENT_ENCRYPTED_KEY:
+ return (memberValue.encryptedKeys.length === 0);
+ case RECIPIENT_CERTIFICATE:
+ return false;
+ case RECIPIENT_PUBLIC_KEY:
+ return false;
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: names.blockName || EMPTY_STRING,
+ value: [
+ new Integer({ name: names.version || EMPTY_STRING }),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [
+ OriginatorIdentifierOrKey.schema(names.originator || {})
+ ]
+ }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: [new OctetString({ name: names.ukm || EMPTY_STRING })]
+ }),
+ AlgorithmIdentifier.schema(names.keyEncryptionAlgorithm || {}),
+ RecipientEncryptedKeys.schema(names.recipientEncryptedKeys || {})
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$s);
+ const asn1 = compareSchema(schema, schema, KeyAgreeRecipientInfo.schema({
+ names: {
+ version: VERSION$b,
+ originator: {
+ names: {
+ blockName: ORIGINATOR
+ }
+ },
+ ukm: UKM,
+ keyEncryptionAlgorithm: {
+ names: {
+ blockName: KEY_ENCRYPTION_ALGORITHM$2
+ }
+ },
+ recipientEncryptedKeys: {
+ names: {
+ blockName: RECIPIENT_ENCRYPTED_KEY
+ }
+ }
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.version = asn1.result.version.valueBlock.valueDec;
+ this.originator = new OriginatorIdentifierOrKey({ schema: asn1.result.originator });
+ if (UKM in asn1.result)
+ this.ukm = asn1.result.ukm;
+ this.keyEncryptionAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.keyEncryptionAlgorithm });
+ this.recipientEncryptedKeys = new RecipientEncryptedKeys({ schema: asn1.result.recipientEncryptedKeys });
+ }
+ toSchema() {
+ const outputArray = [];
+ outputArray.push(new Integer({ value: this.version }));
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [this.originator.toSchema()]
+ }));
+ if (this.ukm) {
+ outputArray.push(new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: [this.ukm]
+ }));
+ }
+ outputArray.push(this.keyEncryptionAlgorithm.toSchema());
+ outputArray.push(this.recipientEncryptedKeys.toSchema());
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {
+ version: this.version,
+ originator: this.originator.toJSON(),
+ keyEncryptionAlgorithm: this.keyEncryptionAlgorithm.toJSON(),
+ recipientEncryptedKeys: this.recipientEncryptedKeys.toJSON(),
+ };
+ if (this.ukm) {
+ res.ukm = this.ukm.toJSON();
+ }
+ return res;
+ }
+}
+KeyAgreeRecipientInfo.CLASS_NAME = "KeyAgreeRecipientInfo";
+
+const KEY_IDENTIFIER = "keyIdentifier";
+const DATE = "date";
+const OTHER = "other";
+const CLEAR_PROPS$r = [
+ KEY_IDENTIFIER,
+ DATE,
+ OTHER,
+];
+class KEKIdentifier extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.keyIdentifier = getParametersValue(parameters, KEY_IDENTIFIER, KEKIdentifier.defaultValues(KEY_IDENTIFIER));
+ if (DATE in parameters) {
+ this.date = getParametersValue(parameters, DATE, KEKIdentifier.defaultValues(DATE));
+ }
+ if (OTHER in parameters) {
+ this.other = getParametersValue(parameters, OTHER, KEKIdentifier.defaultValues(OTHER));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case KEY_IDENTIFIER:
+ return new OctetString();
+ case DATE:
+ return new GeneralizedTime();
+ case OTHER:
+ return new OtherKeyAttribute();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case KEY_IDENTIFIER:
+ return (memberValue.isEqual(KEKIdentifier.defaultValues(KEY_IDENTIFIER)));
+ case DATE:
+ return ((memberValue.year === 0) &&
+ (memberValue.month === 0) &&
+ (memberValue.day === 0) &&
+ (memberValue.hour === 0) &&
+ (memberValue.minute === 0) &&
+ (memberValue.second === 0) &&
+ (memberValue.millisecond === 0));
+ case OTHER:
+ return ((memberValue.compareWithDefault("keyAttrId", memberValue.keyAttrId)) &&
+ (("keyAttr" in memberValue) === false));
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new OctetString({ name: (names.keyIdentifier || EMPTY_STRING) }),
+ new GeneralizedTime({
+ optional: true,
+ name: (names.date || EMPTY_STRING)
+ }),
+ OtherKeyAttribute.schema(names.other || {})
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$r);
+ const asn1 = compareSchema(schema, schema, KEKIdentifier.schema({
+ names: {
+ keyIdentifier: KEY_IDENTIFIER,
+ date: DATE,
+ other: {
+ names: {
+ blockName: OTHER
+ }
+ }
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.keyIdentifier = asn1.result.keyIdentifier;
+ if (DATE in asn1.result)
+ this.date = asn1.result.date;
+ if (OTHER in asn1.result)
+ this.other = new OtherKeyAttribute({ schema: asn1.result.other });
+ }
+ toSchema() {
+ const outputArray = [];
+ outputArray.push(this.keyIdentifier);
+ if (this.date) {
+ outputArray.push(this.date);
+ }
+ if (this.other) {
+ outputArray.push(this.other.toSchema());
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {
+ keyIdentifier: this.keyIdentifier.toJSON()
+ };
+ if (this.date) {
+ res.date = this.date;
+ }
+ if (this.other) {
+ res.other = this.other.toJSON();
+ }
+ return res;
+ }
+}
+KEKIdentifier.CLASS_NAME = "KEKIdentifier";
+
+const VERSION$a = "version";
+const KEK_ID = "kekid";
+const KEY_ENCRYPTION_ALGORITHM$1 = "keyEncryptionAlgorithm";
+const ENCRYPTED_KEY$1 = "encryptedKey";
+const PER_DEFINED_KEK = "preDefinedKEK";
+const CLEAR_PROPS$q = [
+ VERSION$a,
+ KEK_ID,
+ KEY_ENCRYPTION_ALGORITHM$1,
+ ENCRYPTED_KEY$1,
+];
+class KEKRecipientInfo extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.version = getParametersValue(parameters, VERSION$a, KEKRecipientInfo.defaultValues(VERSION$a));
+ this.kekid = getParametersValue(parameters, KEK_ID, KEKRecipientInfo.defaultValues(KEK_ID));
+ this.keyEncryptionAlgorithm = getParametersValue(parameters, KEY_ENCRYPTION_ALGORITHM$1, KEKRecipientInfo.defaultValues(KEY_ENCRYPTION_ALGORITHM$1));
+ this.encryptedKey = getParametersValue(parameters, ENCRYPTED_KEY$1, KEKRecipientInfo.defaultValues(ENCRYPTED_KEY$1));
+ this.preDefinedKEK = getParametersValue(parameters, PER_DEFINED_KEK, KEKRecipientInfo.defaultValues(PER_DEFINED_KEK));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case VERSION$a:
+ return 0;
+ case KEK_ID:
+ return new KEKIdentifier();
+ case KEY_ENCRYPTION_ALGORITHM$1:
+ return new AlgorithmIdentifier();
+ case ENCRYPTED_KEY$1:
+ return new OctetString();
+ case PER_DEFINED_KEK:
+ return EMPTY_BUFFER;
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case "KEKRecipientInfo":
+ return (memberValue === KEKRecipientInfo.defaultValues(VERSION$a));
+ case KEK_ID:
+ return ((memberValue.compareWithDefault("keyIdentifier", memberValue.keyIdentifier)) &&
+ (("date" in memberValue) === false) &&
+ (("other" in memberValue) === false));
+ case KEY_ENCRYPTION_ALGORITHM$1:
+ return ((memberValue.algorithmId === EMPTY_STRING) && (("algorithmParams" in memberValue) === false));
+ case ENCRYPTED_KEY$1:
+ return (memberValue.isEqual(KEKRecipientInfo.defaultValues(ENCRYPTED_KEY$1)));
+ case PER_DEFINED_KEK:
+ return (memberValue.byteLength === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Integer({ name: (names.version || EMPTY_STRING) }),
+ KEKIdentifier.schema(names.kekid || {}),
+ AlgorithmIdentifier.schema(names.keyEncryptionAlgorithm || {}),
+ new OctetString({ name: (names.encryptedKey || EMPTY_STRING) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$q);
+ const asn1 = compareSchema(schema, schema, KEKRecipientInfo.schema({
+ names: {
+ version: VERSION$a,
+ kekid: {
+ names: {
+ blockName: KEK_ID
+ }
+ },
+ keyEncryptionAlgorithm: {
+ names: {
+ blockName: KEY_ENCRYPTION_ALGORITHM$1
+ }
+ },
+ encryptedKey: ENCRYPTED_KEY$1
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.version = asn1.result.version.valueBlock.valueDec;
+ this.kekid = new KEKIdentifier({ schema: asn1.result.kekid });
+ this.keyEncryptionAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.keyEncryptionAlgorithm });
+ this.encryptedKey = asn1.result.encryptedKey;
+ }
+ toSchema() {
+ return (new Sequence({
+ value: [
+ new Integer({ value: this.version }),
+ this.kekid.toSchema(),
+ this.keyEncryptionAlgorithm.toSchema(),
+ this.encryptedKey
+ ]
+ }));
+ }
+ toJSON() {
+ return {
+ version: this.version,
+ kekid: this.kekid.toJSON(),
+ keyEncryptionAlgorithm: this.keyEncryptionAlgorithm.toJSON(),
+ encryptedKey: this.encryptedKey.toJSON(),
+ };
+ }
+}
+KEKRecipientInfo.CLASS_NAME = "KEKRecipientInfo";
+
+const VERSION$9 = "version";
+const KEY_DERIVATION_ALGORITHM = "keyDerivationAlgorithm";
+const KEY_ENCRYPTION_ALGORITHM = "keyEncryptionAlgorithm";
+const ENCRYPTED_KEY = "encryptedKey";
+const PASSWORD = "password";
+const CLEAR_PROPS$p = [
+ VERSION$9,
+ KEY_DERIVATION_ALGORITHM,
+ KEY_ENCRYPTION_ALGORITHM,
+ ENCRYPTED_KEY
+];
+class PasswordRecipientinfo extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.version = getParametersValue(parameters, VERSION$9, PasswordRecipientinfo.defaultValues(VERSION$9));
+ if (KEY_DERIVATION_ALGORITHM in parameters) {
+ this.keyDerivationAlgorithm = getParametersValue(parameters, KEY_DERIVATION_ALGORITHM, PasswordRecipientinfo.defaultValues(KEY_DERIVATION_ALGORITHM));
+ }
+ this.keyEncryptionAlgorithm = getParametersValue(parameters, KEY_ENCRYPTION_ALGORITHM, PasswordRecipientinfo.defaultValues(KEY_ENCRYPTION_ALGORITHM));
+ this.encryptedKey = getParametersValue(parameters, ENCRYPTED_KEY, PasswordRecipientinfo.defaultValues(ENCRYPTED_KEY));
+ this.password = getParametersValue(parameters, PASSWORD, PasswordRecipientinfo.defaultValues(PASSWORD));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case VERSION$9:
+ return (-1);
+ case KEY_DERIVATION_ALGORITHM:
+ return new AlgorithmIdentifier();
+ case KEY_ENCRYPTION_ALGORITHM:
+ return new AlgorithmIdentifier();
+ case ENCRYPTED_KEY:
+ return new OctetString();
+ case PASSWORD:
+ return EMPTY_BUFFER;
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case VERSION$9:
+ return (memberValue === (-1));
+ case KEY_DERIVATION_ALGORITHM:
+ case KEY_ENCRYPTION_ALGORITHM:
+ return ((memberValue.algorithmId === EMPTY_STRING) && (("algorithmParams" in memberValue) === false));
+ case ENCRYPTED_KEY:
+ return (memberValue.isEqual(PasswordRecipientinfo.defaultValues(ENCRYPTED_KEY)));
+ case PASSWORD:
+ return (memberValue.byteLength === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Integer({ name: (names.version || EMPTY_STRING) }),
+ new Constructed({
+ name: (names.keyDerivationAlgorithm || EMPTY_STRING),
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: AlgorithmIdentifier.schema().valueBlock.value
+ }),
+ AlgorithmIdentifier.schema(names.keyEncryptionAlgorithm || {}),
+ new OctetString({ name: (names.encryptedKey || EMPTY_STRING) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$p);
+ const asn1 = compareSchema(schema, schema, PasswordRecipientinfo.schema({
+ names: {
+ version: VERSION$9,
+ keyDerivationAlgorithm: KEY_DERIVATION_ALGORITHM,
+ keyEncryptionAlgorithm: {
+ names: {
+ blockName: KEY_ENCRYPTION_ALGORITHM
+ }
+ },
+ encryptedKey: ENCRYPTED_KEY
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.version = asn1.result.version.valueBlock.valueDec;
+ if (KEY_DERIVATION_ALGORITHM in asn1.result) {
+ this.keyDerivationAlgorithm = new AlgorithmIdentifier({
+ schema: new Sequence({
+ value: asn1.result.keyDerivationAlgorithm.valueBlock.value
+ })
+ });
+ }
+ this.keyEncryptionAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.keyEncryptionAlgorithm });
+ this.encryptedKey = asn1.result.encryptedKey;
+ }
+ toSchema() {
+ const outputArray = [];
+ outputArray.push(new Integer({ value: this.version }));
+ if (this.keyDerivationAlgorithm) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: this.keyDerivationAlgorithm.toSchema().valueBlock.value
+ }));
+ }
+ outputArray.push(this.keyEncryptionAlgorithm.toSchema());
+ outputArray.push(this.encryptedKey);
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {
+ version: this.version,
+ keyEncryptionAlgorithm: this.keyEncryptionAlgorithm.toJSON(),
+ encryptedKey: this.encryptedKey.toJSON(),
+ };
+ if (this.keyDerivationAlgorithm) {
+ res.keyDerivationAlgorithm = this.keyDerivationAlgorithm.toJSON();
+ }
+ return res;
+ }
+}
+PasswordRecipientinfo.CLASS_NAME = "PasswordRecipientInfo";
+
+const ORI_TYPE = "oriType";
+const ORI_VALUE = "oriValue";
+const CLEAR_PROPS$o = [
+ ORI_TYPE,
+ ORI_VALUE
+];
+class OtherRecipientInfo extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.oriType = getParametersValue(parameters, ORI_TYPE, OtherRecipientInfo.defaultValues(ORI_TYPE));
+ this.oriValue = getParametersValue(parameters, ORI_VALUE, OtherRecipientInfo.defaultValues(ORI_VALUE));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case ORI_TYPE:
+ return EMPTY_STRING;
+ case ORI_VALUE:
+ return {};
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case ORI_TYPE:
+ return (memberValue === EMPTY_STRING);
+ case ORI_VALUE:
+ return (Object.keys(memberValue).length === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new ObjectIdentifier({ name: (names.oriType || EMPTY_STRING) }),
+ new Any({ name: (names.oriValue || EMPTY_STRING) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$o);
+ const asn1 = compareSchema(schema, schema, OtherRecipientInfo.schema({
+ names: {
+ oriType: ORI_TYPE,
+ oriValue: ORI_VALUE
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.oriType = asn1.result.oriType.valueBlock.toString();
+ this.oriValue = asn1.result.oriValue;
+ }
+ toSchema() {
+ return (new Sequence({
+ value: [
+ new ObjectIdentifier({ value: this.oriType }),
+ this.oriValue
+ ]
+ }));
+ }
+ toJSON() {
+ const res = {
+ oriType: this.oriType
+ };
+ if (!OtherRecipientInfo.compareWithDefault(ORI_VALUE, this.oriValue)) {
+ res.oriValue = this.oriValue.toJSON();
+ }
+ return res;
+ }
+}
+OtherRecipientInfo.CLASS_NAME = "OtherRecipientInfo";
+
+const VARIANT = "variant";
+const VALUE = "value";
+const CLEAR_PROPS$n = [
+ "blockName"
+];
+class RecipientInfo extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.variant = getParametersValue(parameters, VARIANT, RecipientInfo.defaultValues(VARIANT));
+ if (VALUE in parameters) {
+ this.value = getParametersValue(parameters, VALUE, RecipientInfo.defaultValues(VALUE));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case VARIANT:
+ return (-1);
+ case VALUE:
+ return {};
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case VARIANT:
+ return (memberValue === RecipientInfo.defaultValues(memberName));
+ case VALUE:
+ return (Object.keys(memberValue).length === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Choice({
+ value: [
+ KeyTransRecipientInfo.schema({
+ names: {
+ blockName: (names.blockName || EMPTY_STRING)
+ }
+ }),
+ new Constructed({
+ name: (names.blockName || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: KeyAgreeRecipientInfo.schema().valueBlock.value
+ }),
+ new Constructed({
+ name: (names.blockName || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ },
+ value: KEKRecipientInfo.schema().valueBlock.value
+ }),
+ new Constructed({
+ name: (names.blockName || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 3
+ },
+ value: PasswordRecipientinfo.schema().valueBlock.value
+ }),
+ new Constructed({
+ name: (names.blockName || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 4
+ },
+ value: OtherRecipientInfo.schema().valueBlock.value
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$n);
+ const asn1 = compareSchema(schema, schema, RecipientInfo.schema({
+ names: {
+ blockName: "blockName"
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ if (asn1.result.blockName.idBlock.tagClass === 1) {
+ this.variant = 1;
+ this.value = new KeyTransRecipientInfo({ schema: asn1.result.blockName });
+ }
+ else {
+ const blockSequence = new Sequence({
+ value: asn1.result.blockName.valueBlock.value
+ });
+ switch (asn1.result.blockName.idBlock.tagNumber) {
+ case 1:
+ this.variant = 2;
+ this.value = new KeyAgreeRecipientInfo({ schema: blockSequence });
+ break;
+ case 2:
+ this.variant = 3;
+ this.value = new KEKRecipientInfo({ schema: blockSequence });
+ break;
+ case 3:
+ this.variant = 4;
+ this.value = new PasswordRecipientinfo({ schema: blockSequence });
+ break;
+ case 4:
+ this.variant = 5;
+ this.value = new OtherRecipientInfo({ schema: blockSequence });
+ break;
+ default:
+ throw new Error("Incorrect structure of RecipientInfo block");
+ }
+ }
+ }
+ toSchema() {
+ ParameterError.assertEmpty(this.value, "value", "RecipientInfo");
+ const _schema = this.value.toSchema();
+ switch (this.variant) {
+ case 1:
+ return _schema;
+ case 2:
+ case 3:
+ case 4:
+ _schema.idBlock.tagClass = 3;
+ _schema.idBlock.tagNumber = (this.variant - 1);
+ return _schema;
+ default:
+ return new Any();
+ }
+ }
+ toJSON() {
+ const res = {
+ variant: this.variant
+ };
+ if (this.value && (this.variant >= 1) && (this.variant <= 4)) {
+ res.value = this.value.toJSON();
+ }
+ return res;
+ }
+}
+RecipientInfo.CLASS_NAME = "RecipientInfo";
+
+const HASH_ALGORITHM$2 = "hashAlgorithm";
+const MASK_GEN_ALGORITHM = "maskGenAlgorithm";
+const P_SOURCE_ALGORITHM = "pSourceAlgorithm";
+const CLEAR_PROPS$m = [
+ HASH_ALGORITHM$2,
+ MASK_GEN_ALGORITHM,
+ P_SOURCE_ALGORITHM
+];
+class RSAESOAEPParams extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.hashAlgorithm = getParametersValue(parameters, HASH_ALGORITHM$2, RSAESOAEPParams.defaultValues(HASH_ALGORITHM$2));
+ this.maskGenAlgorithm = getParametersValue(parameters, MASK_GEN_ALGORITHM, RSAESOAEPParams.defaultValues(MASK_GEN_ALGORITHM));
+ this.pSourceAlgorithm = getParametersValue(parameters, P_SOURCE_ALGORITHM, RSAESOAEPParams.defaultValues(P_SOURCE_ALGORITHM));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case HASH_ALGORITHM$2:
+ return new AlgorithmIdentifier({
+ algorithmId: "1.3.14.3.2.26",
+ algorithmParams: new Null()
+ });
+ case MASK_GEN_ALGORITHM:
+ return new AlgorithmIdentifier({
+ algorithmId: "1.2.840.113549.1.1.8",
+ algorithmParams: (new AlgorithmIdentifier({
+ algorithmId: "1.3.14.3.2.26",
+ algorithmParams: new Null()
+ })).toSchema()
+ });
+ case P_SOURCE_ALGORITHM:
+ return new AlgorithmIdentifier({
+ algorithmId: "1.2.840.113549.1.1.9",
+ algorithmParams: new OctetString({ valueHex: (new Uint8Array([0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09])).buffer })
+ });
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ optional: true,
+ value: [AlgorithmIdentifier.schema(names.hashAlgorithm || {})]
+ }),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ optional: true,
+ value: [AlgorithmIdentifier.schema(names.maskGenAlgorithm || {})]
+ }),
+ new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ },
+ optional: true,
+ value: [AlgorithmIdentifier.schema(names.pSourceAlgorithm || {})]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$m);
+ const asn1 = compareSchema(schema, schema, RSAESOAEPParams.schema({
+ names: {
+ hashAlgorithm: {
+ names: {
+ blockName: HASH_ALGORITHM$2
+ }
+ },
+ maskGenAlgorithm: {
+ names: {
+ blockName: MASK_GEN_ALGORITHM
+ }
+ },
+ pSourceAlgorithm: {
+ names: {
+ blockName: P_SOURCE_ALGORITHM
+ }
+ }
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ if (HASH_ALGORITHM$2 in asn1.result)
+ this.hashAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.hashAlgorithm });
+ if (MASK_GEN_ALGORITHM in asn1.result)
+ this.maskGenAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.maskGenAlgorithm });
+ if (P_SOURCE_ALGORITHM in asn1.result)
+ this.pSourceAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.pSourceAlgorithm });
+ }
+ toSchema() {
+ const outputArray = [];
+ if (!this.hashAlgorithm.isEqual(RSAESOAEPParams.defaultValues(HASH_ALGORITHM$2))) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [this.hashAlgorithm.toSchema()]
+ }));
+ }
+ if (!this.maskGenAlgorithm.isEqual(RSAESOAEPParams.defaultValues(MASK_GEN_ALGORITHM))) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: [this.maskGenAlgorithm.toSchema()]
+ }));
+ }
+ if (!this.pSourceAlgorithm.isEqual(RSAESOAEPParams.defaultValues(P_SOURCE_ALGORITHM))) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ },
+ value: [this.pSourceAlgorithm.toSchema()]
+ }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {};
+ if (!this.hashAlgorithm.isEqual(RSAESOAEPParams.defaultValues(HASH_ALGORITHM$2))) {
+ res.hashAlgorithm = this.hashAlgorithm.toJSON();
+ }
+ if (!this.maskGenAlgorithm.isEqual(RSAESOAEPParams.defaultValues(MASK_GEN_ALGORITHM))) {
+ res.maskGenAlgorithm = this.maskGenAlgorithm.toJSON();
+ }
+ if (!this.pSourceAlgorithm.isEqual(RSAESOAEPParams.defaultValues(P_SOURCE_ALGORITHM))) {
+ res.pSourceAlgorithm = this.pSourceAlgorithm.toJSON();
+ }
+ return res;
+ }
+}
+RSAESOAEPParams.CLASS_NAME = "RSAESOAEPParams";
+
+const KEY_INFO = "keyInfo";
+const ENTITY_U_INFO = "entityUInfo";
+const SUPP_PUB_INFO = "suppPubInfo";
+const CLEAR_PROPS$l = [
+ KEY_INFO,
+ ENTITY_U_INFO,
+ SUPP_PUB_INFO
+];
+class ECCCMSSharedInfo extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.keyInfo = getParametersValue(parameters, KEY_INFO, ECCCMSSharedInfo.defaultValues(KEY_INFO));
+ if (ENTITY_U_INFO in parameters) {
+ this.entityUInfo = getParametersValue(parameters, ENTITY_U_INFO, ECCCMSSharedInfo.defaultValues(ENTITY_U_INFO));
+ }
+ this.suppPubInfo = getParametersValue(parameters, SUPP_PUB_INFO, ECCCMSSharedInfo.defaultValues(SUPP_PUB_INFO));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case KEY_INFO:
+ return new AlgorithmIdentifier();
+ case ENTITY_U_INFO:
+ return new OctetString();
+ case SUPP_PUB_INFO:
+ return new OctetString();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case KEY_INFO:
+ case ENTITY_U_INFO:
+ case SUPP_PUB_INFO:
+ return (memberValue.isEqual(ECCCMSSharedInfo.defaultValues(memberName)));
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ AlgorithmIdentifier.schema(names.keyInfo || {}),
+ new Constructed({
+ name: (names.entityUInfo || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ optional: true,
+ value: [new OctetString()]
+ }),
+ new Constructed({
+ name: (names.suppPubInfo || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ },
+ value: [new OctetString()]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$l);
+ const asn1 = compareSchema(schema, schema, ECCCMSSharedInfo.schema({
+ names: {
+ keyInfo: {
+ names: {
+ blockName: KEY_INFO
+ }
+ },
+ entityUInfo: ENTITY_U_INFO,
+ suppPubInfo: SUPP_PUB_INFO
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.keyInfo = new AlgorithmIdentifier({ schema: asn1.result.keyInfo });
+ if (ENTITY_U_INFO in asn1.result)
+ this.entityUInfo = asn1.result.entityUInfo.valueBlock.value[0];
+ this.suppPubInfo = asn1.result.suppPubInfo.valueBlock.value[0];
+ }
+ toSchema() {
+ const outputArray = [];
+ outputArray.push(this.keyInfo.toSchema());
+ if (this.entityUInfo) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [this.entityUInfo]
+ }));
+ }
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ },
+ value: [this.suppPubInfo]
+ }));
+ return new Sequence({
+ value: outputArray
+ });
+ }
+ toJSON() {
+ const res = {
+ keyInfo: this.keyInfo.toJSON(),
+ suppPubInfo: this.suppPubInfo.toJSON(),
+ };
+ if (this.entityUInfo) {
+ res.entityUInfo = this.entityUInfo.toJSON();
+ }
+ return res;
+ }
+}
+ECCCMSSharedInfo.CLASS_NAME = "ECCCMSSharedInfo";
+
+const VERSION$8 = "version";
+const ORIGINATOR_INFO = "originatorInfo";
+const RECIPIENT_INFOS = "recipientInfos";
+const ENCRYPTED_CONTENT_INFO = "encryptedContentInfo";
+const UNPROTECTED_ATTRS = "unprotectedAttrs";
+const CLEAR_PROPS$k = [
+ VERSION$8,
+ ORIGINATOR_INFO,
+ RECIPIENT_INFOS,
+ ENCRYPTED_CONTENT_INFO,
+ UNPROTECTED_ATTRS
+];
+const defaultEncryptionParams = {
+ kdfAlgorithm: "SHA-512",
+ kekEncryptionLength: 256
+};
+const curveLengthByName = {
+ "P-256": 256,
+ "P-384": 384,
+ "P-521": 528
+};
+class EnvelopedData extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.version = getParametersValue(parameters, VERSION$8, EnvelopedData.defaultValues(VERSION$8));
+ if (ORIGINATOR_INFO in parameters) {
+ this.originatorInfo = getParametersValue(parameters, ORIGINATOR_INFO, EnvelopedData.defaultValues(ORIGINATOR_INFO));
+ }
+ this.recipientInfos = getParametersValue(parameters, RECIPIENT_INFOS, EnvelopedData.defaultValues(RECIPIENT_INFOS));
+ this.encryptedContentInfo = getParametersValue(parameters, ENCRYPTED_CONTENT_INFO, EnvelopedData.defaultValues(ENCRYPTED_CONTENT_INFO));
+ if (UNPROTECTED_ATTRS in parameters) {
+ this.unprotectedAttrs = getParametersValue(parameters, UNPROTECTED_ATTRS, EnvelopedData.defaultValues(UNPROTECTED_ATTRS));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case VERSION$8:
+ return 0;
+ case ORIGINATOR_INFO:
+ return new OriginatorInfo();
+ case RECIPIENT_INFOS:
+ return [];
+ case ENCRYPTED_CONTENT_INFO:
+ return new EncryptedContentInfo();
+ case UNPROTECTED_ATTRS:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case VERSION$8:
+ return (memberValue === EnvelopedData.defaultValues(memberName));
+ case ORIGINATOR_INFO:
+ return ((memberValue.certs.certificates.length === 0) && (memberValue.crls.crls.length === 0));
+ case RECIPIENT_INFOS:
+ case UNPROTECTED_ATTRS:
+ return (memberValue.length === 0);
+ case ENCRYPTED_CONTENT_INFO:
+ return ((EncryptedContentInfo.compareWithDefault("contentType", memberValue.contentType)) &&
+ (EncryptedContentInfo.compareWithDefault("contentEncryptionAlgorithm", memberValue.contentEncryptionAlgorithm) &&
+ (EncryptedContentInfo.compareWithDefault("encryptedContent", memberValue.encryptedContent))));
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Integer({ name: (names.version || EMPTY_STRING) }),
+ new Constructed({
+ name: (names.originatorInfo || EMPTY_STRING),
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: OriginatorInfo.schema().valueBlock.value
+ }),
+ new Set({
+ value: [
+ new Repeated({
+ name: (names.recipientInfos || EMPTY_STRING),
+ value: RecipientInfo.schema()
+ })
+ ]
+ }),
+ EncryptedContentInfo.schema(names.encryptedContentInfo || {}),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: [
+ new Repeated({
+ name: (names.unprotectedAttrs || EMPTY_STRING),
+ value: Attribute.schema()
+ })
+ ]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$k);
+ const asn1 = compareSchema(schema, schema, EnvelopedData.schema({
+ names: {
+ version: VERSION$8,
+ originatorInfo: ORIGINATOR_INFO,
+ recipientInfos: RECIPIENT_INFOS,
+ encryptedContentInfo: {
+ names: {
+ blockName: ENCRYPTED_CONTENT_INFO
+ }
+ },
+ unprotectedAttrs: UNPROTECTED_ATTRS
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.version = asn1.result.version.valueBlock.valueDec;
+ if (ORIGINATOR_INFO in asn1.result) {
+ this.originatorInfo = new OriginatorInfo({
+ schema: new Sequence({
+ value: asn1.result.originatorInfo.valueBlock.value
+ })
+ });
+ }
+ this.recipientInfos = Array.from(asn1.result.recipientInfos, o => new RecipientInfo({ schema: o }));
+ this.encryptedContentInfo = new EncryptedContentInfo({ schema: asn1.result.encryptedContentInfo });
+ if (UNPROTECTED_ATTRS in asn1.result)
+ this.unprotectedAttrs = Array.from(asn1.result.unprotectedAttrs, o => new Attribute({ schema: o }));
+ }
+ toSchema() {
+ const outputArray = [];
+ outputArray.push(new Integer({ value: this.version }));
+ if (this.originatorInfo) {
+ outputArray.push(new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: this.originatorInfo.toSchema().valueBlock.value
+ }));
+ }
+ outputArray.push(new Set({
+ value: Array.from(this.recipientInfos, o => o.toSchema())
+ }));
+ outputArray.push(this.encryptedContentInfo.toSchema());
+ if (this.unprotectedAttrs) {
+ outputArray.push(new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: Array.from(this.unprotectedAttrs, o => o.toSchema())
+ }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {
+ version: this.version,
+ recipientInfos: Array.from(this.recipientInfos, o => o.toJSON()),
+ encryptedContentInfo: this.encryptedContentInfo.toJSON(),
+ };
+ if (this.originatorInfo)
+ res.originatorInfo = this.originatorInfo.toJSON();
+ if (this.unprotectedAttrs)
+ res.unprotectedAttrs = Array.from(this.unprotectedAttrs, o => o.toJSON());
+ return res;
+ }
+ addRecipientByCertificate(certificate, parameters, variant, crypto = getCrypto(true)) {
+ const encryptionParameters = Object.assign({ useOAEP: true, oaepHashAlgorithm: "SHA-512" }, defaultEncryptionParams, parameters || {});
+ if (certificate.subjectPublicKeyInfo.algorithm.algorithmId.indexOf("1.2.840.113549") !== (-1))
+ variant = 1;
+ else {
+ if (certificate.subjectPublicKeyInfo.algorithm.algorithmId.indexOf("1.2.840.10045") !== (-1))
+ variant = 2;
+ else
+ throw new Error(`Unknown type of certificate's public key: ${certificate.subjectPublicKeyInfo.algorithm.algorithmId}`);
+ }
+ switch (variant) {
+ case 1:
+ {
+ let algorithmId;
+ let algorithmParams;
+ if (encryptionParameters.useOAEP === true) {
+ algorithmId = crypto.getOIDByAlgorithm({
+ name: "RSA-OAEP"
+ }, true, "keyEncryptionAlgorithm");
+ const hashOID = crypto.getOIDByAlgorithm({
+ name: encryptionParameters.oaepHashAlgorithm
+ }, true, "RSAES-OAEP-params");
+ const hashAlgorithm = new AlgorithmIdentifier({
+ algorithmId: hashOID,
+ algorithmParams: new Null()
+ });
+ const rsaOAEPParams = new RSAESOAEPParams({
+ hashAlgorithm,
+ maskGenAlgorithm: new AlgorithmIdentifier({
+ algorithmId: "1.2.840.113549.1.1.8",
+ algorithmParams: hashAlgorithm.toSchema()
+ })
+ });
+ algorithmParams = rsaOAEPParams.toSchema();
+ }
+ else {
+ algorithmId = crypto.getOIDByAlgorithm({
+ name: "RSAES-PKCS1-v1_5"
+ });
+ if (algorithmId === EMPTY_STRING)
+ throw new Error("Can not find OID for RSAES-PKCS1-v1_5");
+ algorithmParams = new Null();
+ }
+ const keyInfo = new KeyTransRecipientInfo({
+ version: 0,
+ rid: new IssuerAndSerialNumber({
+ issuer: certificate.issuer,
+ serialNumber: certificate.serialNumber
+ }),
+ keyEncryptionAlgorithm: new AlgorithmIdentifier({
+ algorithmId,
+ algorithmParams
+ }),
+ recipientCertificate: certificate,
+ });
+ this.recipientInfos.push(new RecipientInfo({
+ variant: 1,
+ value: keyInfo
+ }));
+ }
+ break;
+ case 2:
+ {
+ const recipientIdentifier = new KeyAgreeRecipientIdentifier({
+ variant: 1,
+ value: new IssuerAndSerialNumber({
+ issuer: certificate.issuer,
+ serialNumber: certificate.serialNumber
+ })
+ });
+ this._addKeyAgreeRecipientInfo(recipientIdentifier, encryptionParameters, { recipientCertificate: certificate }, crypto);
+ }
+ break;
+ default:
+ throw new Error(`Unknown "variant" value: ${variant}`);
+ }
+ return true;
+ }
+ addRecipientByPreDefinedData(preDefinedData, parameters = {}, variant, crypto = getCrypto(true)) {
+ ArgumentError.assert(preDefinedData, "preDefinedData", "ArrayBuffer");
+ if (!preDefinedData.byteLength) {
+ throw new Error("Pre-defined data could have zero length");
+ }
+ if (!parameters.keyIdentifier) {
+ const keyIdentifierBuffer = new ArrayBuffer(16);
+ const keyIdentifierView = new Uint8Array(keyIdentifierBuffer);
+ crypto.getRandomValues(keyIdentifierView);
+ parameters.keyIdentifier = keyIdentifierBuffer;
+ }
+ if (!parameters.hmacHashAlgorithm)
+ parameters.hmacHashAlgorithm = "SHA-512";
+ if (parameters.iterationCount === undefined) {
+ parameters.iterationCount = 2048;
+ }
+ if (!parameters.keyEncryptionAlgorithm) {
+ parameters.keyEncryptionAlgorithm = {
+ name: "AES-KW",
+ length: 256
+ };
+ }
+ if (!parameters.keyEncryptionAlgorithmParams)
+ parameters.keyEncryptionAlgorithmParams = new Null();
+ switch (variant) {
+ case 1:
+ {
+ const kekOID = crypto.getOIDByAlgorithm(parameters.keyEncryptionAlgorithm, true, "keyEncryptionAlgorithm");
+ const keyInfo = new KEKRecipientInfo({
+ version: 4,
+ kekid: new KEKIdentifier({
+ keyIdentifier: new OctetString({ valueHex: parameters.keyIdentifier })
+ }),
+ keyEncryptionAlgorithm: new AlgorithmIdentifier({
+ algorithmId: kekOID,
+ algorithmParams: parameters.keyEncryptionAlgorithmParams
+ }),
+ preDefinedKEK: preDefinedData
+ });
+ this.recipientInfos.push(new RecipientInfo({
+ variant: 3,
+ value: keyInfo
+ }));
+ }
+ break;
+ case 2:
+ {
+ const pbkdf2OID = crypto.getOIDByAlgorithm({ name: "PBKDF2" }, true, "keyDerivationAlgorithm");
+ const saltBuffer = new ArrayBuffer(64);
+ const saltView = new Uint8Array(saltBuffer);
+ crypto.getRandomValues(saltView);
+ const hmacOID = crypto.getOIDByAlgorithm({
+ name: "HMAC",
+ hash: {
+ name: parameters.hmacHashAlgorithm
+ }
+ }, true, "hmacHashAlgorithm");
+ const pbkdf2Params = new PBKDF2Params({
+ salt: new OctetString({ valueHex: saltBuffer }),
+ iterationCount: parameters.iterationCount,
+ prf: new AlgorithmIdentifier({
+ algorithmId: hmacOID,
+ algorithmParams: new Null()
+ })
+ });
+ const kekOID = crypto.getOIDByAlgorithm(parameters.keyEncryptionAlgorithm, true, "keyEncryptionAlgorithm");
+ const keyInfo = new PasswordRecipientinfo({
+ version: 0,
+ keyDerivationAlgorithm: new AlgorithmIdentifier({
+ algorithmId: pbkdf2OID,
+ algorithmParams: pbkdf2Params.toSchema()
+ }),
+ keyEncryptionAlgorithm: new AlgorithmIdentifier({
+ algorithmId: kekOID,
+ algorithmParams: parameters.keyEncryptionAlgorithmParams
+ }),
+ password: preDefinedData
+ });
+ this.recipientInfos.push(new RecipientInfo({
+ variant: 4,
+ value: keyInfo
+ }));
+ }
+ break;
+ default:
+ throw new Error(`Unknown value for "variant": ${variant}`);
+ }
+ }
+ addRecipientByKeyIdentifier(key, keyId, parameters, crypto = getCrypto(true)) {
+ const encryptionParameters = Object.assign({}, defaultEncryptionParams, parameters || {});
+ const recipientIdentifier = new KeyAgreeRecipientIdentifier({
+ variant: 2,
+ value: new RecipientKeyIdentifier({
+ subjectKeyIdentifier: new OctetString({ valueHex: keyId }),
+ })
+ });
+ this._addKeyAgreeRecipientInfo(recipientIdentifier, encryptionParameters, { recipientPublicKey: key }, crypto);
+ }
+ _addKeyAgreeRecipientInfo(recipientIdentifier, encryptionParameters, extraRecipientInfoParams, crypto = getCrypto(true)) {
+ const encryptedKey = new RecipientEncryptedKey({
+ rid: recipientIdentifier
+ });
+ const aesKWoid = crypto.getOIDByAlgorithm({
+ name: "AES-KW",
+ length: encryptionParameters.kekEncryptionLength
+ }, true, "keyEncryptionAlgorithm");
+ const aesKW = new AlgorithmIdentifier({
+ algorithmId: aesKWoid,
+ });
+ const ecdhOID = crypto.getOIDByAlgorithm({
+ name: "ECDH",
+ kdf: encryptionParameters.kdfAlgorithm
+ }, true, "KeyAgreeRecipientInfo");
+ const ukmBuffer = new ArrayBuffer(64);
+ const ukmView = new Uint8Array(ukmBuffer);
+ crypto.getRandomValues(ukmView);
+ const recipientInfoParams = {
+ version: 3,
+ ukm: new OctetString({ valueHex: ukmBuffer }),
+ keyEncryptionAlgorithm: new AlgorithmIdentifier({
+ algorithmId: ecdhOID,
+ algorithmParams: aesKW.toSchema()
+ }),
+ recipientEncryptedKeys: new RecipientEncryptedKeys({
+ encryptedKeys: [encryptedKey]
+ })
+ };
+ const keyInfo = new KeyAgreeRecipientInfo(Object.assign(recipientInfoParams, extraRecipientInfoParams));
+ this.recipientInfos.push(new RecipientInfo({
+ variant: 2,
+ value: keyInfo
+ }));
+ }
+ encrypt(contentEncryptionAlgorithm, contentToEncrypt, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const ivBuffer = new ArrayBuffer(16);
+ const ivView = new Uint8Array(ivBuffer);
+ crypto.getRandomValues(ivView);
+ const contentView = new Uint8Array(contentToEncrypt);
+ const contentEncryptionOID = crypto.getOIDByAlgorithm(contentEncryptionAlgorithm, true, "contentEncryptionAlgorithm");
+ const sessionKey = yield crypto.generateKey(contentEncryptionAlgorithm, true, ["encrypt"]);
+ const encryptedContent = yield crypto.encrypt({
+ name: contentEncryptionAlgorithm.name,
+ iv: ivView
+ }, sessionKey, contentView);
+ const exportedSessionKey = yield crypto.exportKey("raw", sessionKey);
+ this.version = 2;
+ this.encryptedContentInfo = new EncryptedContentInfo({
+ contentType: "1.2.840.113549.1.7.1",
+ contentEncryptionAlgorithm: new AlgorithmIdentifier({
+ algorithmId: contentEncryptionOID,
+ algorithmParams: new OctetString({ valueHex: ivBuffer })
+ }),
+ encryptedContent: new OctetString({ valueHex: encryptedContent })
+ });
+ const SubKeyAgreeRecipientInfo = (index) => __awaiter(this, void 0, void 0, function* () {
+ const recipientInfo = this.recipientInfos[index].value;
+ let recipientCurve;
+ let recipientPublicKey;
+ if (recipientInfo.recipientPublicKey) {
+ recipientCurve = recipientInfo.recipientPublicKey.algorithm.namedCurve;
+ recipientPublicKey = recipientInfo.recipientPublicKey;
+ }
+ else if (recipientInfo.recipientCertificate) {
+ const curveObject = recipientInfo.recipientCertificate.subjectPublicKeyInfo.algorithm.algorithmParams;
+ if (curveObject.constructor.blockName() !== ObjectIdentifier.blockName())
+ throw new Error(`Incorrect "recipientCertificate" for index ${index}`);
+ const curveOID = curveObject.valueBlock.toString();
+ switch (curveOID) {
+ case "1.2.840.10045.3.1.7":
+ recipientCurve = "P-256";
+ break;
+ case "1.3.132.0.34":
+ recipientCurve = "P-384";
+ break;
+ case "1.3.132.0.35":
+ recipientCurve = "P-521";
+ break;
+ default:
+ throw new Error(`Incorrect curve OID for index ${index}`);
+ }
+ recipientPublicKey = yield recipientInfo.recipientCertificate.getPublicKey({
+ algorithm: {
+ algorithm: {
+ name: "ECDH",
+ namedCurve: recipientCurve
+ },
+ usages: []
+ }
+ }, crypto);
+ }
+ else {
+ throw new Error("Unsupported RecipientInfo");
+ }
+ const recipientCurveLength = curveLengthByName[recipientCurve];
+ const ecdhKeys = yield crypto.generateKey({ name: "ECDH", namedCurve: recipientCurve }, true, ["deriveBits"]);
+ const exportedECDHPublicKey = yield crypto.exportKey("spki", ecdhKeys.publicKey);
+ const derivedBits = yield crypto.deriveBits({
+ name: "ECDH",
+ public: recipientPublicKey
+ }, ecdhKeys.privateKey, recipientCurveLength);
+ const aesKWAlgorithm = new AlgorithmIdentifier({ schema: recipientInfo.keyEncryptionAlgorithm.algorithmParams });
+ const kwAlgorithm = crypto.getAlgorithmByOID(aesKWAlgorithm.algorithmId, true, "aesKWAlgorithm");
+ let kwLength = kwAlgorithm.length;
+ const kwLengthBuffer = new ArrayBuffer(4);
+ const kwLengthView = new Uint8Array(kwLengthBuffer);
+ for (let j = 3; j >= 0; j--) {
+ kwLengthView[j] = kwLength;
+ kwLength >>= 8;
+ }
+ const eccInfo = new ECCCMSSharedInfo({
+ keyInfo: new AlgorithmIdentifier({
+ algorithmId: aesKWAlgorithm.algorithmId
+ }),
+ entityUInfo: recipientInfo.ukm,
+ suppPubInfo: new OctetString({ valueHex: kwLengthBuffer })
+ });
+ const encodedInfo = eccInfo.toSchema().toBER(false);
+ const ecdhAlgorithm = crypto.getAlgorithmByOID(recipientInfo.keyEncryptionAlgorithm.algorithmId, true, "ecdhAlgorithm");
+ const derivedKeyRaw = yield kdf(ecdhAlgorithm.kdf, derivedBits, kwAlgorithm.length, encodedInfo, crypto);
+ const awsKW = yield crypto.importKey("raw", derivedKeyRaw, { name: "AES-KW" }, true, ["wrapKey"]);
+ const wrappedKey = yield crypto.wrapKey("raw", sessionKey, awsKW, { name: "AES-KW" });
+ const originator = new OriginatorIdentifierOrKey();
+ originator.variant = 3;
+ originator.value = OriginatorPublicKey.fromBER(exportedECDHPublicKey);
+ recipientInfo.originator = originator;
+ recipientInfo.recipientEncryptedKeys.encryptedKeys[0].encryptedKey = new OctetString({ valueHex: wrappedKey });
+ return { ecdhPrivateKey: ecdhKeys.privateKey };
+ });
+ const SubKeyTransRecipientInfo = (index) => __awaiter(this, void 0, void 0, function* () {
+ const recipientInfo = this.recipientInfos[index].value;
+ const algorithmParameters = crypto.getAlgorithmByOID(recipientInfo.keyEncryptionAlgorithm.algorithmId, true, "keyEncryptionAlgorithm");
+ if (algorithmParameters.name === "RSA-OAEP") {
+ const schema = recipientInfo.keyEncryptionAlgorithm.algorithmParams;
+ const rsaOAEPParams = new RSAESOAEPParams({ schema });
+ algorithmParameters.hash = crypto.getAlgorithmByOID(rsaOAEPParams.hashAlgorithm.algorithmId);
+ if (("name" in algorithmParameters.hash) === false)
+ throw new Error(`Incorrect OID for hash algorithm: ${rsaOAEPParams.hashAlgorithm.algorithmId}`);
+ }
+ try {
+ const publicKey = yield recipientInfo.recipientCertificate.getPublicKey({
+ algorithm: {
+ algorithm: algorithmParameters,
+ usages: ["encrypt", "wrapKey"]
+ }
+ }, crypto);
+ const encryptedKey = yield crypto.encrypt(publicKey.algorithm, publicKey, exportedSessionKey);
+ recipientInfo.encryptedKey = new OctetString({ valueHex: encryptedKey });
+ }
+ catch (_a) {
+ }
+ });
+ const SubKEKRecipientInfo = (index) => __awaiter(this, void 0, void 0, function* () {
+ const recipientInfo = this.recipientInfos[index].value;
+ const kekAlgorithm = crypto.getAlgorithmByOID(recipientInfo.keyEncryptionAlgorithm.algorithmId, true, "kekAlgorithm");
+ const kekKey = yield crypto.importKey("raw", new Uint8Array(recipientInfo.preDefinedKEK), kekAlgorithm, true, ["wrapKey"]);
+ const wrappedKey = yield crypto.wrapKey("raw", sessionKey, kekKey, kekAlgorithm);
+ recipientInfo.encryptedKey = new OctetString({ valueHex: wrappedKey });
+ });
+ const SubPasswordRecipientinfo = (index) => __awaiter(this, void 0, void 0, function* () {
+ const recipientInfo = this.recipientInfos[index].value;
+ let pbkdf2Params;
+ if (!recipientInfo.keyDerivationAlgorithm)
+ throw new Error("Please append encoded \"keyDerivationAlgorithm\"");
+ if (!recipientInfo.keyDerivationAlgorithm.algorithmParams)
+ throw new Error("Incorrectly encoded \"keyDerivationAlgorithm\"");
+ try {
+ pbkdf2Params = new PBKDF2Params({ schema: recipientInfo.keyDerivationAlgorithm.algorithmParams });
+ }
+ catch (ex) {
+ throw new Error("Incorrectly encoded \"keyDerivationAlgorithm\"");
+ }
+ const passwordView = new Uint8Array(recipientInfo.password);
+ const derivationKey = yield crypto.importKey("raw", passwordView, "PBKDF2", false, ["deriveKey"]);
+ const kekAlgorithm = crypto.getAlgorithmByOID(recipientInfo.keyEncryptionAlgorithm.algorithmId, true, "kekAlgorithm");
+ let hmacHashAlgorithm = "SHA-1";
+ if (pbkdf2Params.prf) {
+ const prfAlgorithm = crypto.getAlgorithmByOID(pbkdf2Params.prf.algorithmId, true, "prfAlgorithm");
+ hmacHashAlgorithm = prfAlgorithm.hash.name;
+ }
+ const saltView = new Uint8Array(pbkdf2Params.salt.valueBlock.valueHex);
+ const iterations = pbkdf2Params.iterationCount;
+ const derivedKey = yield crypto.deriveKey({
+ name: "PBKDF2",
+ hash: {
+ name: hmacHashAlgorithm
+ },
+ salt: saltView,
+ iterations
+ }, derivationKey, kekAlgorithm, true, ["wrapKey"]);
+ const wrappedKey = yield crypto.wrapKey("raw", sessionKey, derivedKey, kekAlgorithm);
+ recipientInfo.encryptedKey = new OctetString({ valueHex: wrappedKey });
+ });
+ const res = [];
+ for (let i = 0; i < this.recipientInfos.length; i++) {
+ switch (this.recipientInfos[i].variant) {
+ case 1:
+ res.push(yield SubKeyTransRecipientInfo(i));
+ break;
+ case 2:
+ res.push(yield SubKeyAgreeRecipientInfo(i));
+ break;
+ case 3:
+ res.push(yield SubKEKRecipientInfo(i));
+ break;
+ case 4:
+ res.push(yield SubPasswordRecipientinfo(i));
+ break;
+ default:
+ throw new Error(`Unknown recipient type in array with index ${i}`);
+ }
+ }
+ return res;
+ });
+ }
+ decrypt(recipientIndex, parameters, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const decryptionParameters = parameters || {};
+ if ((recipientIndex + 1) > this.recipientInfos.length) {
+ throw new Error(`Maximum value for "index" is: ${this.recipientInfos.length - 1}`);
+ }
+ const SubKeyAgreeRecipientInfo = (index) => __awaiter(this, void 0, void 0, function* () {
+ const recipientInfo = this.recipientInfos[index].value;
+ let curveOID;
+ let recipientCurve;
+ let recipientCurveLength;
+ const originator = recipientInfo.originator;
+ if (decryptionParameters.recipientCertificate) {
+ const curveObject = decryptionParameters.recipientCertificate.subjectPublicKeyInfo.algorithm.algorithmParams;
+ if (curveObject.constructor.blockName() !== ObjectIdentifier.blockName()) {
+ throw new Error(`Incorrect "recipientCertificate" for index ${index}`);
+ }
+ curveOID = curveObject.valueBlock.toString();
+ }
+ else if (originator.value.algorithm.algorithmParams) {
+ const curveObject = originator.value.algorithm.algorithmParams;
+ if (curveObject.constructor.blockName() !== ObjectIdentifier.blockName()) {
+ throw new Error(`Incorrect originator for index ${index}`);
+ }
+ curveOID = curveObject.valueBlock.toString();
+ }
+ else {
+ throw new Error("Parameter \"recipientCertificate\" is mandatory for \"KeyAgreeRecipientInfo\" if algorithm params are missing from originator");
+ }
+ if (!decryptionParameters.recipientPrivateKey)
+ throw new Error("Parameter \"recipientPrivateKey\" is mandatory for \"KeyAgreeRecipientInfo\"");
+ switch (curveOID) {
+ case "1.2.840.10045.3.1.7":
+ recipientCurve = "P-256";
+ recipientCurveLength = 256;
+ break;
+ case "1.3.132.0.34":
+ recipientCurve = "P-384";
+ recipientCurveLength = 384;
+ break;
+ case "1.3.132.0.35":
+ recipientCurve = "P-521";
+ recipientCurveLength = 528;
+ break;
+ default:
+ throw new Error(`Incorrect curve OID for index ${index}`);
+ }
+ const ecdhPrivateKey = yield crypto.importKey("pkcs8", decryptionParameters.recipientPrivateKey, {
+ name: "ECDH",
+ namedCurve: recipientCurve
+ }, true, ["deriveBits"]);
+ if (("algorithmParams" in originator.value.algorithm) === false)
+ originator.value.algorithm.algorithmParams = new ObjectIdentifier({ value: curveOID });
+ const buffer = originator.value.toSchema().toBER(false);
+ const ecdhPublicKey = yield crypto.importKey("spki", buffer, {
+ name: "ECDH",
+ namedCurve: recipientCurve
+ }, true, []);
+ const sharedSecret = yield crypto.deriveBits({
+ name: "ECDH",
+ public: ecdhPublicKey
+ }, ecdhPrivateKey, recipientCurveLength);
+ function applyKDF(includeAlgorithmParams) {
+ return __awaiter(this, void 0, void 0, function* () {
+ includeAlgorithmParams = includeAlgorithmParams || false;
+ const aesKWAlgorithm = new AlgorithmIdentifier({ schema: recipientInfo.keyEncryptionAlgorithm.algorithmParams });
+ const kwAlgorithm = crypto.getAlgorithmByOID(aesKWAlgorithm.algorithmId, true, "kwAlgorithm");
+ let kwLength = kwAlgorithm.length;
+ const kwLengthBuffer = new ArrayBuffer(4);
+ const kwLengthView = new Uint8Array(kwLengthBuffer);
+ for (let j = 3; j >= 0; j--) {
+ kwLengthView[j] = kwLength;
+ kwLength >>= 8;
+ }
+ const keyInfoAlgorithm = {
+ algorithmId: aesKWAlgorithm.algorithmId
+ };
+ if (includeAlgorithmParams) {
+ keyInfoAlgorithm.algorithmParams = new Null();
+ }
+ const eccInfo = new ECCCMSSharedInfo({
+ keyInfo: new AlgorithmIdentifier(keyInfoAlgorithm),
+ entityUInfo: recipientInfo.ukm,
+ suppPubInfo: new OctetString({ valueHex: kwLengthBuffer })
+ });
+ const encodedInfo = eccInfo.toSchema().toBER(false);
+ const ecdhAlgorithm = crypto.getAlgorithmByOID(recipientInfo.keyEncryptionAlgorithm.algorithmId, true, "ecdhAlgorithm");
+ if (!ecdhAlgorithm.name) {
+ throw new Error(`Incorrect OID for key encryption algorithm: ${recipientInfo.keyEncryptionAlgorithm.algorithmId}`);
+ }
+ return kdf(ecdhAlgorithm.kdf, sharedSecret, kwAlgorithm.length, encodedInfo, crypto);
+ });
+ }
+ const kdfResult = yield applyKDF();
+ const importAesKwKey = (kdfResult) => __awaiter(this, void 0, void 0, function* () {
+ return crypto.importKey("raw", kdfResult, { name: "AES-KW" }, true, ["unwrapKey"]);
+ });
+ const aesKwKey = yield importAesKwKey(kdfResult);
+ const unwrapSessionKey = (aesKwKey) => __awaiter(this, void 0, void 0, function* () {
+ const algorithmId = this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId;
+ const contentEncryptionAlgorithm = crypto.getAlgorithmByOID(algorithmId, true, "contentEncryptionAlgorithm");
+ return crypto.unwrapKey("raw", recipientInfo.recipientEncryptedKeys.encryptedKeys[0].encryptedKey.valueBlock.valueHexView, aesKwKey, { name: "AES-KW" }, contentEncryptionAlgorithm, true, ["decrypt"]);
+ });
+ try {
+ return yield unwrapSessionKey(aesKwKey);
+ }
+ catch (_a) {
+ const kdfResult = yield applyKDF(true);
+ const aesKwKey = yield importAesKwKey(kdfResult);
+ return unwrapSessionKey(aesKwKey);
+ }
+ });
+ const SubKeyTransRecipientInfo = (index) => __awaiter(this, void 0, void 0, function* () {
+ const recipientInfo = this.recipientInfos[index].value;
+ if (!decryptionParameters.recipientPrivateKey) {
+ throw new Error("Parameter \"recipientPrivateKey\" is mandatory for \"KeyTransRecipientInfo\"");
+ }
+ const algorithmParameters = crypto.getAlgorithmByOID(recipientInfo.keyEncryptionAlgorithm.algorithmId, true, "keyEncryptionAlgorithm");
+ if (algorithmParameters.name === "RSA-OAEP") {
+ const schema = recipientInfo.keyEncryptionAlgorithm.algorithmParams;
+ const rsaOAEPParams = new RSAESOAEPParams({ schema });
+ algorithmParameters.hash = crypto.getAlgorithmByOID(rsaOAEPParams.hashAlgorithm.algorithmId);
+ if (("name" in algorithmParameters.hash) === false)
+ throw new Error(`Incorrect OID for hash algorithm: ${rsaOAEPParams.hashAlgorithm.algorithmId}`);
+ }
+ const privateKey = yield crypto.importKey("pkcs8", decryptionParameters.recipientPrivateKey, algorithmParameters, true, ["decrypt"]);
+ const sessionKey = yield crypto.decrypt(privateKey.algorithm, privateKey, recipientInfo.encryptedKey.valueBlock.valueHexView);
+ const algorithmId = this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId;
+ const contentEncryptionAlgorithm = crypto.getAlgorithmByOID(algorithmId, true, "contentEncryptionAlgorithm");
+ if (("name" in contentEncryptionAlgorithm) === false)
+ throw new Error(`Incorrect "contentEncryptionAlgorithm": ${algorithmId}`);
+ return crypto.importKey("raw", sessionKey, contentEncryptionAlgorithm, true, ["decrypt"]);
+ });
+ const SubKEKRecipientInfo = (index) => __awaiter(this, void 0, void 0, function* () {
+ const recipientInfo = this.recipientInfos[index].value;
+ if (!decryptionParameters.preDefinedData)
+ throw new Error("Parameter \"preDefinedData\" is mandatory for \"KEKRecipientInfo\"");
+ const kekAlgorithm = crypto.getAlgorithmByOID(recipientInfo.keyEncryptionAlgorithm.algorithmId, true, "kekAlgorithm");
+ const importedKey = yield crypto.importKey("raw", decryptionParameters.preDefinedData, kekAlgorithm, true, ["unwrapKey"]);
+ const algorithmId = this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId;
+ const contentEncryptionAlgorithm = crypto.getAlgorithmByOID(algorithmId, true, "contentEncryptionAlgorithm");
+ if (!contentEncryptionAlgorithm.name) {
+ throw new Error(`Incorrect "contentEncryptionAlgorithm": ${algorithmId}`);
+ }
+ return crypto.unwrapKey("raw", recipientInfo.encryptedKey.valueBlock.valueHexView, importedKey, kekAlgorithm, contentEncryptionAlgorithm, true, ["decrypt"]);
+ });
+ const SubPasswordRecipientinfo = (index) => __awaiter(this, void 0, void 0, function* () {
+ const recipientInfo = this.recipientInfos[index].value;
+ let pbkdf2Params;
+ if (!decryptionParameters.preDefinedData) {
+ throw new Error("Parameter \"preDefinedData\" is mandatory for \"KEKRecipientInfo\"");
+ }
+ if (!recipientInfo.keyDerivationAlgorithm) {
+ throw new Error("Please append encoded \"keyDerivationAlgorithm\"");
+ }
+ if (!recipientInfo.keyDerivationAlgorithm.algorithmParams) {
+ throw new Error("Incorrectly encoded \"keyDerivationAlgorithm\"");
+ }
+ try {
+ pbkdf2Params = new PBKDF2Params({ schema: recipientInfo.keyDerivationAlgorithm.algorithmParams });
+ }
+ catch (ex) {
+ throw new Error("Incorrectly encoded \"keyDerivationAlgorithm\"");
+ }
+ const pbkdf2Key = yield crypto.importKey("raw", decryptionParameters.preDefinedData, "PBKDF2", false, ["deriveKey"]);
+ const kekAlgorithm = crypto.getAlgorithmByOID(recipientInfo.keyEncryptionAlgorithm.algorithmId, true, "keyEncryptionAlgorithm");
+ const hmacHashAlgorithm = pbkdf2Params.prf
+ ? crypto.getAlgorithmByOID(pbkdf2Params.prf.algorithmId, true, "prfAlgorithm").hash.name
+ : "SHA-1";
+ const saltView = new Uint8Array(pbkdf2Params.salt.valueBlock.valueHex);
+ const iterations = pbkdf2Params.iterationCount;
+ const kekKey = yield crypto.deriveKey({
+ name: "PBKDF2",
+ hash: {
+ name: hmacHashAlgorithm
+ },
+ salt: saltView,
+ iterations
+ }, pbkdf2Key, kekAlgorithm, true, ["unwrapKey"]);
+ const algorithmId = this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId;
+ const contentEncryptionAlgorithm = crypto.getAlgorithmByOID(algorithmId, true, "contentEncryptionAlgorithm");
+ return crypto.unwrapKey("raw", recipientInfo.encryptedKey.valueBlock.valueHexView, kekKey, kekAlgorithm, contentEncryptionAlgorithm, true, ["decrypt"]);
+ });
+ let unwrappedKey;
+ switch (this.recipientInfos[recipientIndex].variant) {
+ case 1:
+ unwrappedKey = yield SubKeyTransRecipientInfo(recipientIndex);
+ break;
+ case 2:
+ unwrappedKey = yield SubKeyAgreeRecipientInfo(recipientIndex);
+ break;
+ case 3:
+ unwrappedKey = yield SubKEKRecipientInfo(recipientIndex);
+ break;
+ case 4:
+ unwrappedKey = yield SubPasswordRecipientinfo(recipientIndex);
+ break;
+ default:
+ throw new Error(`Unknown recipient type in array with index ${recipientIndex}`);
+ }
+ const algorithmId = this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmId;
+ const contentEncryptionAlgorithm = crypto.getAlgorithmByOID(algorithmId, true, "contentEncryptionAlgorithm");
+ const ivBuffer = this.encryptedContentInfo.contentEncryptionAlgorithm.algorithmParams.valueBlock.valueHex;
+ const ivView = new Uint8Array(ivBuffer);
+ if (!this.encryptedContentInfo.encryptedContent) {
+ throw new Error("Required property `encryptedContent` is empty");
+ }
+ const dataBuffer = this.encryptedContentInfo.getEncryptedContent();
+ return crypto.decrypt({
+ name: contentEncryptionAlgorithm.name,
+ iv: ivView
+ }, unwrappedKey, dataBuffer);
+ });
+ }
+}
+EnvelopedData.CLASS_NAME = "EnvelopedData";
+
+const SAFE_CONTENTS = "safeContents";
+const PARSED_VALUE$1 = "parsedValue";
+const CONTENT_INFOS = "contentInfos";
+class AuthenticatedSafe extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.safeContents = getParametersValue(parameters, SAFE_CONTENTS, AuthenticatedSafe.defaultValues(SAFE_CONTENTS));
+ if (PARSED_VALUE$1 in parameters) {
+ this.parsedValue = getParametersValue(parameters, PARSED_VALUE$1, AuthenticatedSafe.defaultValues(PARSED_VALUE$1));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case SAFE_CONTENTS:
+ return [];
+ case PARSED_VALUE$1:
+ return {};
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case SAFE_CONTENTS:
+ return (memberValue.length === 0);
+ case PARSED_VALUE$1:
+ return ((memberValue instanceof Object) && (Object.keys(memberValue).length === 0));
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Repeated({
+ name: (names.contentInfos || EMPTY_STRING),
+ value: ContentInfo.schema()
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, [
+ CONTENT_INFOS
+ ]);
+ const asn1 = compareSchema(schema, schema, AuthenticatedSafe.schema({
+ names: {
+ contentInfos: CONTENT_INFOS
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.safeContents = Array.from(asn1.result.contentInfos, element => new ContentInfo({ schema: element }));
+ }
+ toSchema() {
+ return (new Sequence({
+ value: Array.from(this.safeContents, o => o.toSchema())
+ }));
+ }
+ toJSON() {
+ return {
+ safeContents: Array.from(this.safeContents, o => o.toJSON())
+ };
+ }
+ parseInternalValues(parameters, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ ParameterError.assert(parameters, SAFE_CONTENTS);
+ ArgumentError.assert(parameters.safeContents, SAFE_CONTENTS, "Array");
+ if (parameters.safeContents.length !== this.safeContents.length) {
+ throw new ArgumentError("Length of \"parameters.safeContents\" must be equal to \"this.safeContents.length\"");
+ }
+ this.parsedValue = {
+ safeContents: [],
+ };
+ for (const [index, content] of this.safeContents.entries()) {
+ const safeContent = parameters.safeContents[index];
+ const errorTarget = `parameters.safeContents[${index}]`;
+ switch (content.contentType) {
+ case id_ContentType_Data:
+ {
+ ArgumentError.assert(content.content, "this.safeContents[j].content", OctetString);
+ const authSafeContent = content.content.getValue();
+ this.parsedValue.safeContents.push({
+ privacyMode: 0,
+ value: SafeContents.fromBER(authSafeContent)
+ });
+ }
+ break;
+ case id_ContentType_EnvelopedData:
+ {
+ const cmsEnveloped = new EnvelopedData({ schema: content.content });
+ ParameterError.assert(errorTarget, safeContent, "recipientCertificate", "recipientKey");
+ const envelopedData = safeContent;
+ const recipientCertificate = envelopedData.recipientCertificate;
+ const recipientKey = envelopedData.recipientKey;
+ const decrypted = yield cmsEnveloped.decrypt(0, {
+ recipientCertificate,
+ recipientPrivateKey: recipientKey
+ }, crypto);
+ this.parsedValue.safeContents.push({
+ privacyMode: 2,
+ value: SafeContents.fromBER(decrypted),
+ });
+ }
+ break;
+ case id_ContentType_EncryptedData:
+ {
+ const cmsEncrypted = new EncryptedData({ schema: content.content });
+ ParameterError.assert(errorTarget, safeContent, "password");
+ const password = safeContent.password;
+ const decrypted = yield cmsEncrypted.decrypt({
+ password
+ }, crypto);
+ this.parsedValue.safeContents.push({
+ privacyMode: 1,
+ value: SafeContents.fromBER(decrypted),
+ });
+ }
+ break;
+ default:
+ throw new Error(`Unknown "contentType" for AuthenticatedSafe: " ${content.contentType}`);
+ }
+ }
+ });
+ }
+ makeInternalValues(parameters, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ if (!(this.parsedValue)) {
+ throw new Error("Please run \"parseValues\" first or add \"parsedValue\" manually");
+ }
+ ArgumentError.assert(this.parsedValue, "this.parsedValue", "object");
+ ArgumentError.assert(this.parsedValue.safeContents, "this.parsedValue.safeContents", "Array");
+ ArgumentError.assert(parameters, "parameters", "object");
+ ParameterError.assert(parameters, "safeContents");
+ ArgumentError.assert(parameters.safeContents, "parameters.safeContents", "Array");
+ if (parameters.safeContents.length !== this.parsedValue.safeContents.length) {
+ throw new ArgumentError("Length of \"parameters.safeContents\" must be equal to \"this.parsedValue.safeContents\"");
+ }
+ this.safeContents = [];
+ for (const [index, content] of this.parsedValue.safeContents.entries()) {
+ ParameterError.assert("content", content, "privacyMode", "value");
+ ArgumentError.assert(content.value, "content.value", SafeContents);
+ switch (content.privacyMode) {
+ case 0:
+ {
+ const contentBuffer = content.value.toSchema().toBER(false);
+ this.safeContents.push(new ContentInfo({
+ contentType: "1.2.840.113549.1.7.1",
+ content: new OctetString({ valueHex: contentBuffer })
+ }));
+ }
+ break;
+ case 1:
+ {
+ const cmsEncrypted = new EncryptedData();
+ const currentParameters = parameters.safeContents[index];
+ currentParameters.contentToEncrypt = content.value.toSchema().toBER(false);
+ yield cmsEncrypted.encrypt(currentParameters);
+ this.safeContents.push(new ContentInfo({
+ contentType: "1.2.840.113549.1.7.6",
+ content: cmsEncrypted.toSchema()
+ }));
+ }
+ break;
+ case 2:
+ {
+ const cmsEnveloped = new EnvelopedData();
+ const contentToEncrypt = content.value.toSchema().toBER(false);
+ const safeContent = parameters.safeContents[index];
+ ParameterError.assert(`parameters.safeContents[${index}]`, safeContent, "encryptingCertificate", "encryptionAlgorithm");
+ switch (true) {
+ case (safeContent.encryptionAlgorithm.name.toLowerCase() === "aes-cbc"):
+ case (safeContent.encryptionAlgorithm.name.toLowerCase() === "aes-gcm"):
+ break;
+ default:
+ throw new Error(`Incorrect parameter "encryptionAlgorithm" in "parameters.safeContents[i]": ${safeContent.encryptionAlgorithm}`);
+ }
+ switch (true) {
+ case (safeContent.encryptionAlgorithm.length === 128):
+ case (safeContent.encryptionAlgorithm.length === 192):
+ case (safeContent.encryptionAlgorithm.length === 256):
+ break;
+ default:
+ throw new Error(`Incorrect parameter "encryptionAlgorithm.length" in "parameters.safeContents[i]": ${safeContent.encryptionAlgorithm.length}`);
+ }
+ const encryptionAlgorithm = safeContent.encryptionAlgorithm;
+ cmsEnveloped.addRecipientByCertificate(safeContent.encryptingCertificate, {}, undefined, crypto);
+ yield cmsEnveloped.encrypt(encryptionAlgorithm, contentToEncrypt, crypto);
+ this.safeContents.push(new ContentInfo({
+ contentType: "1.2.840.113549.1.7.3",
+ content: cmsEnveloped.toSchema()
+ }));
+ }
+ break;
+ default:
+ throw new Error(`Incorrect value for "content.privacyMode": ${content.privacyMode}`);
+ }
+ }
+ return this;
+ });
+ }
+}
+AuthenticatedSafe.CLASS_NAME = "AuthenticatedSafe";
+
+const HASH_ALGORITHM$1 = "hashAlgorithm";
+const ISSUER_NAME_HASH = "issuerNameHash";
+const ISSUER_KEY_HASH = "issuerKeyHash";
+const SERIAL_NUMBER$1 = "serialNumber";
+const CLEAR_PROPS$j = [
+ HASH_ALGORITHM$1,
+ ISSUER_NAME_HASH,
+ ISSUER_KEY_HASH,
+ SERIAL_NUMBER$1,
+];
+class CertID extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.hashAlgorithm = getParametersValue(parameters, HASH_ALGORITHM$1, CertID.defaultValues(HASH_ALGORITHM$1));
+ this.issuerNameHash = getParametersValue(parameters, ISSUER_NAME_HASH, CertID.defaultValues(ISSUER_NAME_HASH));
+ this.issuerKeyHash = getParametersValue(parameters, ISSUER_KEY_HASH, CertID.defaultValues(ISSUER_KEY_HASH));
+ this.serialNumber = getParametersValue(parameters, SERIAL_NUMBER$1, CertID.defaultValues(SERIAL_NUMBER$1));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static create(certificate, parameters, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const certID = new CertID();
+ yield certID.createForCertificate(certificate, parameters, crypto);
+ return certID;
+ });
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case HASH_ALGORITHM$1:
+ return new AlgorithmIdentifier();
+ case ISSUER_NAME_HASH:
+ case ISSUER_KEY_HASH:
+ return new OctetString();
+ case SERIAL_NUMBER$1:
+ return new Integer();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case HASH_ALGORITHM$1:
+ return ((memberValue.algorithmId === EMPTY_STRING) && (("algorithmParams" in memberValue) === false));
+ case ISSUER_NAME_HASH:
+ case ISSUER_KEY_HASH:
+ case SERIAL_NUMBER$1:
+ return (memberValue.isEqual(CertID.defaultValues(SERIAL_NUMBER$1)));
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ AlgorithmIdentifier.schema(names.hashAlgorithmObject || {
+ names: {
+ blockName: (names.hashAlgorithm || EMPTY_STRING)
+ }
+ }),
+ new OctetString({ name: (names.issuerNameHash || EMPTY_STRING) }),
+ new OctetString({ name: (names.issuerKeyHash || EMPTY_STRING) }),
+ new Integer({ name: (names.serialNumber || EMPTY_STRING) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$j);
+ const asn1 = compareSchema(schema, schema, CertID.schema({
+ names: {
+ hashAlgorithm: HASH_ALGORITHM$1,
+ issuerNameHash: ISSUER_NAME_HASH,
+ issuerKeyHash: ISSUER_KEY_HASH,
+ serialNumber: SERIAL_NUMBER$1
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.hashAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.hashAlgorithm });
+ this.issuerNameHash = asn1.result.issuerNameHash;
+ this.issuerKeyHash = asn1.result.issuerKeyHash;
+ this.serialNumber = asn1.result.serialNumber;
+ }
+ toSchema() {
+ return (new Sequence({
+ value: [
+ this.hashAlgorithm.toSchema(),
+ this.issuerNameHash,
+ this.issuerKeyHash,
+ this.serialNumber
+ ]
+ }));
+ }
+ toJSON() {
+ return {
+ hashAlgorithm: this.hashAlgorithm.toJSON(),
+ issuerNameHash: this.issuerNameHash.toJSON(),
+ issuerKeyHash: this.issuerKeyHash.toJSON(),
+ serialNumber: this.serialNumber.toJSON(),
+ };
+ }
+ isEqual(certificateID) {
+ if (this.hashAlgorithm.algorithmId !== certificateID.hashAlgorithm.algorithmId) {
+ return false;
+ }
+ if (!BufferSourceConverter.isEqual(this.issuerNameHash.valueBlock.valueHexView, certificateID.issuerNameHash.valueBlock.valueHexView)) {
+ return false;
+ }
+ if (!BufferSourceConverter.isEqual(this.issuerKeyHash.valueBlock.valueHexView, certificateID.issuerKeyHash.valueBlock.valueHexView)) {
+ return false;
+ }
+ if (!this.serialNumber.isEqual(certificateID.serialNumber)) {
+ return false;
+ }
+ return true;
+ }
+ createForCertificate(certificate, parameters, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ ParameterError.assert(parameters, HASH_ALGORITHM$1, "issuerCertificate");
+ const hashOID = crypto.getOIDByAlgorithm({ name: parameters.hashAlgorithm }, true, "hashAlgorithm");
+ this.hashAlgorithm = new AlgorithmIdentifier({
+ algorithmId: hashOID,
+ algorithmParams: new Null()
+ });
+ const issuerCertificate = parameters.issuerCertificate;
+ this.serialNumber = certificate.serialNumber;
+ const hashIssuerName = yield crypto.digest({ name: parameters.hashAlgorithm }, issuerCertificate.subject.toSchema().toBER(false));
+ this.issuerNameHash = new OctetString({ valueHex: hashIssuerName });
+ const issuerKeyBuffer = issuerCertificate.subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHexView;
+ const hashIssuerKey = yield crypto.digest({ name: parameters.hashAlgorithm }, issuerKeyBuffer);
+ this.issuerKeyHash = new OctetString({ valueHex: hashIssuerKey });
+ });
+ }
+}
+CertID.CLASS_NAME = "CertID";
+
+const CERT_ID = "certID";
+const CERT_STATUS = "certStatus";
+const THIS_UPDATE = "thisUpdate";
+const NEXT_UPDATE = "nextUpdate";
+const SINGLE_EXTENSIONS = "singleExtensions";
+const CLEAR_PROPS$i = [
+ CERT_ID,
+ CERT_STATUS,
+ THIS_UPDATE,
+ NEXT_UPDATE,
+ SINGLE_EXTENSIONS,
+];
+class SingleResponse extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.certID = getParametersValue(parameters, CERT_ID, SingleResponse.defaultValues(CERT_ID));
+ this.certStatus = getParametersValue(parameters, CERT_STATUS, SingleResponse.defaultValues(CERT_STATUS));
+ this.thisUpdate = getParametersValue(parameters, THIS_UPDATE, SingleResponse.defaultValues(THIS_UPDATE));
+ if (NEXT_UPDATE in parameters) {
+ this.nextUpdate = getParametersValue(parameters, NEXT_UPDATE, SingleResponse.defaultValues(NEXT_UPDATE));
+ }
+ if (SINGLE_EXTENSIONS in parameters) {
+ this.singleExtensions = getParametersValue(parameters, SINGLE_EXTENSIONS, SingleResponse.defaultValues(SINGLE_EXTENSIONS));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case CERT_ID:
+ return new CertID();
+ case CERT_STATUS:
+ return {};
+ case THIS_UPDATE:
+ case NEXT_UPDATE:
+ return new Date(0, 0, 0);
+ case SINGLE_EXTENSIONS:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case CERT_ID:
+ return ((CertID.compareWithDefault("hashAlgorithm", memberValue.hashAlgorithm)) &&
+ (CertID.compareWithDefault("issuerNameHash", memberValue.issuerNameHash)) &&
+ (CertID.compareWithDefault("issuerKeyHash", memberValue.issuerKeyHash)) &&
+ (CertID.compareWithDefault("serialNumber", memberValue.serialNumber)));
+ case CERT_STATUS:
+ return (Object.keys(memberValue).length === 0);
+ case THIS_UPDATE:
+ case NEXT_UPDATE:
+ return (memberValue === SingleResponse.defaultValues(memberName));
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ CertID.schema(names.certID || {}),
+ new Choice({
+ value: [
+ new Primitive({
+ name: (names.certStatus || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ }),
+ new Constructed({
+ name: (names.certStatus || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: [
+ new GeneralizedTime(),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [new Enumerated()]
+ })
+ ]
+ }),
+ new Primitive({
+ name: (names.certStatus || EMPTY_STRING),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ },
+ lenBlock: { length: 1 }
+ })
+ ]
+ }),
+ new GeneralizedTime({ name: (names.thisUpdate || EMPTY_STRING) }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [new GeneralizedTime({ name: (names.nextUpdate || EMPTY_STRING) })]
+ }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: [Extensions.schema(names.singleExtensions || {})]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$i);
+ const asn1 = compareSchema(schema, schema, SingleResponse.schema({
+ names: {
+ certID: {
+ names: {
+ blockName: CERT_ID
+ }
+ },
+ certStatus: CERT_STATUS,
+ thisUpdate: THIS_UPDATE,
+ nextUpdate: NEXT_UPDATE,
+ singleExtensions: {
+ names: {
+ blockName: SINGLE_EXTENSIONS
+ }
+ }
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.certID = new CertID({ schema: asn1.result.certID });
+ this.certStatus = asn1.result.certStatus;
+ this.thisUpdate = asn1.result.thisUpdate.toDate();
+ if (NEXT_UPDATE in asn1.result)
+ this.nextUpdate = asn1.result.nextUpdate.toDate();
+ if (SINGLE_EXTENSIONS in asn1.result)
+ this.singleExtensions = Array.from(asn1.result.singleExtensions.valueBlock.value, element => new Extension({ schema: element }));
+ }
+ toSchema() {
+ const outputArray = [];
+ outputArray.push(this.certID.toSchema());
+ outputArray.push(this.certStatus);
+ outputArray.push(new GeneralizedTime({ valueDate: this.thisUpdate }));
+ if (this.nextUpdate) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [new GeneralizedTime({ valueDate: this.nextUpdate })]
+ }));
+ }
+ if (this.singleExtensions) {
+ outputArray.push(new Sequence({
+ value: Array.from(this.singleExtensions, o => o.toSchema())
+ }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {
+ certID: this.certID.toJSON(),
+ certStatus: this.certStatus.toJSON(),
+ thisUpdate: this.thisUpdate
+ };
+ if (this.nextUpdate) {
+ res.nextUpdate = this.nextUpdate;
+ }
+ if (this.singleExtensions) {
+ res.singleExtensions = Array.from(this.singleExtensions, o => o.toJSON());
+ }
+ return res;
+ }
+}
+SingleResponse.CLASS_NAME = "SingleResponse";
+
+const TBS$2 = "tbs";
+const VERSION$7 = "version";
+const RESPONDER_ID = "responderID";
+const PRODUCED_AT = "producedAt";
+const RESPONSES = "responses";
+const RESPONSE_EXTENSIONS = "responseExtensions";
+const RESPONSE_DATA = "ResponseData";
+const RESPONSE_DATA_VERSION = `${RESPONSE_DATA}.${VERSION$7}`;
+const RESPONSE_DATA_RESPONDER_ID = `${RESPONSE_DATA}.${RESPONDER_ID}`;
+const RESPONSE_DATA_PRODUCED_AT = `${RESPONSE_DATA}.${PRODUCED_AT}`;
+const RESPONSE_DATA_RESPONSES = `${RESPONSE_DATA}.${RESPONSES}`;
+const RESPONSE_DATA_RESPONSE_EXTENSIONS = `${RESPONSE_DATA}.${RESPONSE_EXTENSIONS}`;
+const CLEAR_PROPS$h = [
+ RESPONSE_DATA,
+ RESPONSE_DATA_VERSION,
+ RESPONSE_DATA_RESPONDER_ID,
+ RESPONSE_DATA_PRODUCED_AT,
+ RESPONSE_DATA_RESPONSES,
+ RESPONSE_DATA_RESPONSE_EXTENSIONS
+];
+class ResponseData extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.tbsView = new Uint8Array(getParametersValue(parameters, TBS$2, ResponseData.defaultValues(TBS$2)));
+ if (VERSION$7 in parameters) {
+ this.version = getParametersValue(parameters, VERSION$7, ResponseData.defaultValues(VERSION$7));
+ }
+ this.responderID = getParametersValue(parameters, RESPONDER_ID, ResponseData.defaultValues(RESPONDER_ID));
+ this.producedAt = getParametersValue(parameters, PRODUCED_AT, ResponseData.defaultValues(PRODUCED_AT));
+ this.responses = getParametersValue(parameters, RESPONSES, ResponseData.defaultValues(RESPONSES));
+ if (RESPONSE_EXTENSIONS in parameters) {
+ this.responseExtensions = getParametersValue(parameters, RESPONSE_EXTENSIONS, ResponseData.defaultValues(RESPONSE_EXTENSIONS));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ get tbs() {
+ return BufferSourceConverter.toArrayBuffer(this.tbsView);
+ }
+ set tbs(value) {
+ this.tbsView = new Uint8Array(value);
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case VERSION$7:
+ return 0;
+ case TBS$2:
+ return EMPTY_BUFFER;
+ case RESPONDER_ID:
+ return {};
+ case PRODUCED_AT:
+ return new Date(0, 0, 0);
+ case RESPONSES:
+ case RESPONSE_EXTENSIONS:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case TBS$2:
+ return (memberValue.byteLength === 0);
+ case RESPONDER_ID:
+ return (Object.keys(memberValue).length === 0);
+ case PRODUCED_AT:
+ return (memberValue === ResponseData.defaultValues(memberName));
+ case RESPONSES:
+ case RESPONSE_EXTENSIONS:
+ return (memberValue.length === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || RESPONSE_DATA),
+ value: [
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [new Integer({ name: (names.version || RESPONSE_DATA_VERSION) })]
+ }),
+ new Choice({
+ value: [
+ new Constructed({
+ name: (names.responderID || RESPONSE_DATA_RESPONDER_ID),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: [RelativeDistinguishedNames.schema(names.ResponseDataByName || {
+ names: {
+ blockName: "ResponseData.byName"
+ }
+ })]
+ }),
+ new Constructed({
+ name: (names.responderID || RESPONSE_DATA_RESPONDER_ID),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ },
+ value: [new OctetString({ name: (names.ResponseDataByKey || "ResponseData.byKey") })]
+ })
+ ]
+ }),
+ new GeneralizedTime({ name: (names.producedAt || RESPONSE_DATA_PRODUCED_AT) }),
+ new Sequence({
+ value: [
+ new Repeated({
+ name: RESPONSE_DATA_RESPONSES,
+ value: SingleResponse.schema(names.response || {})
+ })
+ ]
+ }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: [Extensions.schema(names.extensions || {
+ names: {
+ blockName: RESPONSE_DATA_RESPONSE_EXTENSIONS
+ }
+ })]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$h);
+ const asn1 = compareSchema(schema, schema, ResponseData.schema());
+ AsnError.assertSchema(asn1, this.className);
+ this.tbsView = asn1.result.ResponseData.valueBeforeDecodeView;
+ if (RESPONSE_DATA_VERSION in asn1.result)
+ this.version = asn1.result[RESPONSE_DATA_VERSION].valueBlock.valueDec;
+ if (asn1.result[RESPONSE_DATA_RESPONDER_ID].idBlock.tagNumber === 1)
+ this.responderID = new RelativeDistinguishedNames({ schema: asn1.result[RESPONSE_DATA_RESPONDER_ID].valueBlock.value[0] });
+ else
+ this.responderID = asn1.result[RESPONSE_DATA_RESPONDER_ID].valueBlock.value[0];
+ this.producedAt = asn1.result[RESPONSE_DATA_PRODUCED_AT].toDate();
+ this.responses = Array.from(asn1.result[RESPONSE_DATA_RESPONSES], element => new SingleResponse({ schema: element }));
+ if (RESPONSE_DATA_RESPONSE_EXTENSIONS in asn1.result)
+ this.responseExtensions = Array.from(asn1.result[RESPONSE_DATA_RESPONSE_EXTENSIONS].valueBlock.value, element => new Extension({ schema: element }));
+ }
+ toSchema(encodeFlag = false) {
+ let tbsSchema;
+ if (encodeFlag === false) {
+ if (!this.tbsView.byteLength) {
+ return ResponseData.schema();
+ }
+ const asn1 = fromBER(this.tbsView);
+ AsnError.assert(asn1, "TBS Response Data");
+ tbsSchema = asn1.result;
+ }
+ else {
+ const outputArray = [];
+ if (VERSION$7 in this) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [new Integer({ value: this.version })]
+ }));
+ }
+ if (this.responderID instanceof RelativeDistinguishedNames) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: [this.responderID.toSchema()]
+ }));
+ }
+ else {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ },
+ value: [this.responderID]
+ }));
+ }
+ outputArray.push(new GeneralizedTime({ valueDate: this.producedAt }));
+ outputArray.push(new Sequence({
+ value: Array.from(this.responses, o => o.toSchema())
+ }));
+ if (this.responseExtensions) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: [new Sequence({
+ value: Array.from(this.responseExtensions, o => o.toSchema())
+ })]
+ }));
+ }
+ tbsSchema = new Sequence({
+ value: outputArray
+ });
+ }
+ return tbsSchema;
+ }
+ toJSON() {
+ const res = {};
+ if (VERSION$7 in this) {
+ res.version = this.version;
+ }
+ if (this.responderID) {
+ res.responderID = this.responderID;
+ }
+ if (this.producedAt) {
+ res.producedAt = this.producedAt;
+ }
+ if (this.responses) {
+ res.responses = Array.from(this.responses, o => o.toJSON());
+ }
+ if (this.responseExtensions) {
+ res.responseExtensions = Array.from(this.responseExtensions, o => o.toJSON());
+ }
+ return res;
+ }
+}
+ResponseData.CLASS_NAME = "ResponseData";
+
+const TRUSTED_CERTS = "trustedCerts";
+const CERTS$2 = "certs";
+const CRLS$1 = "crls";
+const OCSPS$1 = "ocsps";
+const CHECK_DATE = "checkDate";
+const FIND_ORIGIN = "findOrigin";
+const FIND_ISSUER = "findIssuer";
+var ChainValidationCode;
+(function (ChainValidationCode) {
+ ChainValidationCode[ChainValidationCode["unknown"] = -1] = "unknown";
+ ChainValidationCode[ChainValidationCode["success"] = 0] = "success";
+ ChainValidationCode[ChainValidationCode["noRevocation"] = 11] = "noRevocation";
+ ChainValidationCode[ChainValidationCode["noPath"] = 60] = "noPath";
+ ChainValidationCode[ChainValidationCode["noValidPath"] = 97] = "noValidPath";
+})(ChainValidationCode || (ChainValidationCode = {}));
+class ChainValidationError extends Error {
+ constructor(code, message) {
+ super(message);
+ this.name = ChainValidationError.NAME;
+ this.code = code;
+ this.message = message;
+ }
+}
+ChainValidationError.NAME = "ChainValidationError";
+function isTrusted(cert, trustedList) {
+ for (let i = 0; i < trustedList.length; i++) {
+ if (BufferSourceConverter.isEqual(cert.tbsView, trustedList[i].tbsView)) {
+ return true;
+ }
+ }
+ return false;
+}
+class CertificateChainValidationEngine {
+ constructor(parameters = {}) {
+ this.trustedCerts = getParametersValue(parameters, TRUSTED_CERTS, this.defaultValues(TRUSTED_CERTS));
+ this.certs = getParametersValue(parameters, CERTS$2, this.defaultValues(CERTS$2));
+ this.crls = getParametersValue(parameters, CRLS$1, this.defaultValues(CRLS$1));
+ this.ocsps = getParametersValue(parameters, OCSPS$1, this.defaultValues(OCSPS$1));
+ this.checkDate = getParametersValue(parameters, CHECK_DATE, this.defaultValues(CHECK_DATE));
+ this.findOrigin = getParametersValue(parameters, FIND_ORIGIN, this.defaultValues(FIND_ORIGIN));
+ this.findIssuer = getParametersValue(parameters, FIND_ISSUER, this.defaultValues(FIND_ISSUER));
+ }
+ static defaultFindOrigin(certificate, validationEngine) {
+ if (certificate.tbsView.byteLength === 0) {
+ certificate.tbsView = new Uint8Array(certificate.encodeTBS().toBER());
+ }
+ for (const localCert of validationEngine.certs) {
+ if (localCert.tbsView.byteLength === 0) {
+ localCert.tbsView = new Uint8Array(localCert.encodeTBS().toBER());
+ }
+ if (BufferSourceConverter.isEqual(certificate.tbsView, localCert.tbsView))
+ return "Intermediate Certificates";
+ }
+ for (const trustedCert of validationEngine.trustedCerts) {
+ if (trustedCert.tbsView.byteLength === 0)
+ trustedCert.tbsView = new Uint8Array(trustedCert.encodeTBS().toBER());
+ if (BufferSourceConverter.isEqual(certificate.tbsView, trustedCert.tbsView))
+ return "Trusted Certificates";
+ }
+ return "Unknown";
+ }
+ defaultFindIssuer(certificate, validationEngine, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const result = [];
+ let keyIdentifier = null;
+ let authorityCertIssuer = null;
+ let authorityCertSerialNumber = null;
+ if (certificate.subject.isEqual(certificate.issuer)) {
+ try {
+ const verificationResult = yield certificate.verify(undefined, crypto);
+ if (verificationResult) {
+ return [certificate];
+ }
+ }
+ catch (ex) {
+ }
+ }
+ if (certificate.extensions) {
+ for (const extension of certificate.extensions) {
+ if (extension.extnID === id_AuthorityKeyIdentifier && extension.parsedValue instanceof AuthorityKeyIdentifier) {
+ if (extension.parsedValue.keyIdentifier) {
+ keyIdentifier = extension.parsedValue.keyIdentifier;
+ }
+ else {
+ if (extension.parsedValue.authorityCertIssuer) {
+ authorityCertIssuer = extension.parsedValue.authorityCertIssuer;
+ }
+ if (extension.parsedValue.authorityCertSerialNumber) {
+ authorityCertSerialNumber = extension.parsedValue.authorityCertSerialNumber;
+ }
+ }
+ break;
+ }
+ }
+ }
+ function checkCertificate(possibleIssuer) {
+ if (keyIdentifier !== null) {
+ if (possibleIssuer.extensions) {
+ let extensionFound = false;
+ for (const extension of possibleIssuer.extensions) {
+ if (extension.extnID === id_SubjectKeyIdentifier && extension.parsedValue) {
+ extensionFound = true;
+ if (BufferSourceConverter.isEqual(extension.parsedValue.valueBlock.valueHex, keyIdentifier.valueBlock.valueHexView)) {
+ result.push(possibleIssuer);
+ }
+ break;
+ }
+ }
+ if (extensionFound) {
+ return;
+ }
+ }
+ }
+ let authorityCertSerialNumberEqual = false;
+ if (authorityCertSerialNumber !== null)
+ authorityCertSerialNumberEqual = possibleIssuer.serialNumber.isEqual(authorityCertSerialNumber);
+ if (authorityCertIssuer !== null) {
+ if (possibleIssuer.subject.isEqual(authorityCertIssuer)) {
+ if (authorityCertSerialNumberEqual)
+ result.push(possibleIssuer);
+ }
+ }
+ else {
+ if (certificate.issuer.isEqual(possibleIssuer.subject))
+ result.push(possibleIssuer);
+ }
+ }
+ for (const trustedCert of validationEngine.trustedCerts) {
+ checkCertificate(trustedCert);
+ }
+ for (const intermediateCert of validationEngine.certs) {
+ checkCertificate(intermediateCert);
+ }
+ for (let i = 0; i < result.length; i++) {
+ try {
+ const verificationResult = yield certificate.verify(result[i], crypto);
+ if (verificationResult === false)
+ result.splice(i, 1);
+ }
+ catch (ex) {
+ result.splice(i, 1);
+ }
+ }
+ return result;
+ });
+ }
+ defaultValues(memberName) {
+ switch (memberName) {
+ case TRUSTED_CERTS:
+ return [];
+ case CERTS$2:
+ return [];
+ case CRLS$1:
+ return [];
+ case OCSPS$1:
+ return [];
+ case CHECK_DATE:
+ return new Date();
+ case FIND_ORIGIN:
+ return CertificateChainValidationEngine.defaultFindOrigin;
+ case FIND_ISSUER:
+ return this.defaultFindIssuer;
+ default:
+ throw new Error(`Invalid member name for CertificateChainValidationEngine class: ${memberName}`);
+ }
+ }
+ sort(passedWhenNotRevValues = false, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const localCerts = [];
+ const buildPath = (certificate, crypto) => __awaiter(this, void 0, void 0, function* () {
+ const result = [];
+ function checkUnique(array) {
+ let unique = true;
+ for (let i = 0; i < array.length; i++) {
+ for (let j = 0; j < array.length; j++) {
+ if (j === i)
+ continue;
+ if (array[i] === array[j]) {
+ unique = false;
+ break;
+ }
+ }
+ if (!unique)
+ break;
+ }
+ return unique;
+ }
+ if (isTrusted(certificate, this.trustedCerts)) {
+ return [[certificate]];
+ }
+ const findIssuerResult = yield this.findIssuer(certificate, this, crypto);
+ if (findIssuerResult.length === 0) {
+ throw new Error("No valid certificate paths found");
+ }
+ for (let i = 0; i < findIssuerResult.length; i++) {
+ if (BufferSourceConverter.isEqual(findIssuerResult[i].tbsView, certificate.tbsView)) {
+ result.push([findIssuerResult[i]]);
+ continue;
+ }
+ const buildPathResult = yield buildPath(findIssuerResult[i], crypto);
+ for (let j = 0; j < buildPathResult.length; j++) {
+ const copy = buildPathResult[j].slice();
+ copy.splice(0, 0, findIssuerResult[i]);
+ if (checkUnique(copy))
+ result.push(copy);
+ else
+ result.push(buildPathResult[j]);
+ }
+ }
+ return result;
+ });
+ const findCRL = (certificate) => __awaiter(this, void 0, void 0, function* () {
+ const issuerCertificates = [];
+ const crls = [];
+ const crlsAndCertificates = [];
+ issuerCertificates.push(...localCerts.filter(element => certificate.issuer.isEqual(element.subject)));
+ if (issuerCertificates.length === 0) {
+ return {
+ status: 1,
+ statusMessage: "No certificate's issuers"
+ };
+ }
+ crls.push(...this.crls.filter(o => o.issuer.isEqual(certificate.issuer)));
+ if (crls.length === 0) {
+ return {
+ status: 2,
+ statusMessage: "No CRLs for specific certificate issuer"
+ };
+ }
+ for (let i = 0; i < crls.length; i++) {
+ const crl = crls[i];
+ if (crl.nextUpdate && crl.nextUpdate.value < this.checkDate) {
+ continue;
+ }
+ for (let j = 0; j < issuerCertificates.length; j++) {
+ try {
+ const result = yield crls[i].verify({ issuerCertificate: issuerCertificates[j] }, crypto);
+ if (result) {
+ crlsAndCertificates.push({
+ crl: crls[i],
+ certificate: issuerCertificates[j]
+ });
+ break;
+ }
+ }
+ catch (ex) {
+ }
+ }
+ }
+ if (crlsAndCertificates.length) {
+ return {
+ status: 0,
+ statusMessage: EMPTY_STRING,
+ result: crlsAndCertificates
+ };
+ }
+ return {
+ status: 3,
+ statusMessage: "No valid CRLs found"
+ };
+ });
+ const findOCSP = (certificate, issuerCertificate) => __awaiter(this, void 0, void 0, function* () {
+ const hashAlgorithm = crypto.getAlgorithmByOID(certificate.signatureAlgorithm.algorithmId);
+ if (!hashAlgorithm.name) {
+ return 1;
+ }
+ if (!hashAlgorithm.hash) {
+ return 1;
+ }
+ for (let i = 0; i < this.ocsps.length; i++) {
+ const ocsp = this.ocsps[i];
+ const result = yield ocsp.getCertificateStatus(certificate, issuerCertificate, crypto);
+ if (result.isForCertificate) {
+ if (result.status === 0)
+ return 0;
+ return 1;
+ }
+ }
+ return 2;
+ });
+ function checkForCA(certificate, needToCheckCRL = false) {
+ return __awaiter(this, void 0, void 0, function* () {
+ let isCA = false;
+ let mustBeCA = false;
+ let keyUsagePresent = false;
+ let cRLSign = false;
+ if (certificate.extensions) {
+ for (let j = 0; j < certificate.extensions.length; j++) {
+ const extension = certificate.extensions[j];
+ if (extension.critical && !extension.parsedValue) {
+ return {
+ result: false,
+ resultCode: 6,
+ resultMessage: `Unable to parse critical certificate extension: ${extension.extnID}`
+ };
+ }
+ if (extension.extnID === id_KeyUsage) {
+ keyUsagePresent = true;
+ const view = new Uint8Array(extension.parsedValue.valueBlock.valueHex);
+ if ((view[0] & 0x04) === 0x04)
+ mustBeCA = true;
+ if ((view[0] & 0x02) === 0x02)
+ cRLSign = true;
+ }
+ if (extension.extnID === id_BasicConstraints) {
+ if ("cA" in extension.parsedValue) {
+ if (extension.parsedValue.cA === true)
+ isCA = true;
+ }
+ }
+ }
+ if ((mustBeCA === true) && (isCA === false)) {
+ return {
+ result: false,
+ resultCode: 3,
+ resultMessage: "Unable to build certificate chain - using \"keyCertSign\" flag set without BasicConstraints"
+ };
+ }
+ if ((keyUsagePresent === true) && (isCA === true) && (mustBeCA === false)) {
+ return {
+ result: false,
+ resultCode: 4,
+ resultMessage: "Unable to build certificate chain - \"keyCertSign\" flag was not set"
+ };
+ }
+ if ((isCA === true) && (keyUsagePresent === true) && ((needToCheckCRL) && (cRLSign === false))) {
+ return {
+ result: false,
+ resultCode: 5,
+ resultMessage: "Unable to build certificate chain - intermediate certificate must have \"cRLSign\" key usage flag"
+ };
+ }
+ }
+ if (isCA === false) {
+ return {
+ result: false,
+ resultCode: 7,
+ resultMessage: "Unable to build certificate chain - more than one possible end-user certificate"
+ };
+ }
+ return {
+ result: true,
+ resultCode: 0,
+ resultMessage: EMPTY_STRING
+ };
+ });
+ }
+ const basicCheck = (path, checkDate) => __awaiter(this, void 0, void 0, function* () {
+ for (let i = 0; i < path.length; i++) {
+ if ((path[i].notBefore.value > checkDate) ||
+ (path[i].notAfter.value < checkDate)) {
+ return {
+ result: false,
+ resultCode: 8,
+ resultMessage: "The certificate is either not yet valid or expired"
+ };
+ }
+ }
+ if (path.length < 2) {
+ return {
+ result: false,
+ resultCode: 9,
+ resultMessage: "Too short certificate path"
+ };
+ }
+ for (let i = (path.length - 2); i >= 0; i--) {
+ if (path[i].issuer.isEqual(path[i].subject) === false) {
+ if (path[i].issuer.isEqual(path[i + 1].subject) === false) {
+ return {
+ result: false,
+ resultCode: 10,
+ resultMessage: "Incorrect name chaining"
+ };
+ }
+ }
+ }
+ if ((this.crls.length !== 0) || (this.ocsps.length !== 0)) {
+ for (let i = 0; i < (path.length - 1); i++) {
+ let ocspResult = 2;
+ let crlResult = {
+ status: 0,
+ statusMessage: EMPTY_STRING
+ };
+ if (this.ocsps.length !== 0) {
+ ocspResult = yield findOCSP(path[i], path[i + 1]);
+ switch (ocspResult) {
+ case 0:
+ continue;
+ case 1:
+ return {
+ result: false,
+ resultCode: 12,
+ resultMessage: "One of certificates was revoked via OCSP response"
+ };
+ }
+ }
+ if (this.crls.length !== 0) {
+ crlResult = yield findCRL(path[i]);
+ if (crlResult.status === 0 && crlResult.result) {
+ for (let j = 0; j < crlResult.result.length; j++) {
+ const isCertificateRevoked = crlResult.result[j].crl.isCertificateRevoked(path[i]);
+ if (isCertificateRevoked) {
+ return {
+ result: false,
+ resultCode: 12,
+ resultMessage: "One of certificates had been revoked"
+ };
+ }
+ const isCertificateCA = yield checkForCA(crlResult.result[j].certificate, true);
+ if (isCertificateCA.result === false) {
+ return {
+ result: false,
+ resultCode: 13,
+ resultMessage: "CRL issuer certificate is not a CA certificate or does not have crlSign flag"
+ };
+ }
+ }
+ }
+ else {
+ if (passedWhenNotRevValues === false) {
+ throw new ChainValidationError(ChainValidationCode.noRevocation, `No revocation values found for one of certificates: ${crlResult.statusMessage}`);
+ }
+ }
+ }
+ else {
+ if (ocspResult === 2) {
+ return {
+ result: false,
+ resultCode: 11,
+ resultMessage: "No revocation values found for one of certificates"
+ };
+ }
+ }
+ if ((ocspResult === 2) && (crlResult.status === 2) && passedWhenNotRevValues) {
+ const issuerCertificate = path[i + 1];
+ let extensionFound = false;
+ if (issuerCertificate.extensions) {
+ for (const extension of issuerCertificate.extensions) {
+ switch (extension.extnID) {
+ case id_CRLDistributionPoints:
+ case id_FreshestCRL:
+ case id_AuthorityInfoAccess:
+ extensionFound = true;
+ break;
+ }
+ }
+ }
+ if (extensionFound) {
+ throw new ChainValidationError(ChainValidationCode.noRevocation, `No revocation values found for one of certificates: ${crlResult.statusMessage}`);
+ }
+ }
+ }
+ }
+ for (const [i, cert] of path.entries()) {
+ if (!i) {
+ continue;
+ }
+ const result = yield checkForCA(cert);
+ if (!result.result) {
+ return {
+ result: false,
+ resultCode: 14,
+ resultMessage: "One of intermediate certificates is not a CA certificate"
+ };
+ }
+ }
+ return {
+ result: true
+ };
+ });
+ localCerts.push(...this.trustedCerts);
+ localCerts.push(...this.certs);
+ for (let i = 0; i < localCerts.length; i++) {
+ for (let j = 0; j < localCerts.length; j++) {
+ if (i === j)
+ continue;
+ if (BufferSourceConverter.isEqual(localCerts[i].tbsView, localCerts[j].tbsView)) {
+ localCerts.splice(j, 1);
+ i = 0;
+ break;
+ }
+ }
+ }
+ const leafCert = localCerts[localCerts.length - 1];
+ let result;
+ const certificatePath = [leafCert];
+ result = yield buildPath(leafCert, crypto);
+ if (result.length === 0) {
+ throw new ChainValidationError(ChainValidationCode.noPath, "Unable to find certificate path");
+ }
+ for (let i = 0; i < result.length; i++) {
+ let found = false;
+ for (let j = 0; j < (result[i]).length; j++) {
+ const certificate = (result[i])[j];
+ for (let k = 0; k < this.trustedCerts.length; k++) {
+ if (BufferSourceConverter.isEqual(certificate.tbsView, this.trustedCerts[k].tbsView)) {
+ found = true;
+ break;
+ }
+ }
+ if (found)
+ break;
+ }
+ if (!found) {
+ result.splice(i, 1);
+ i = 0;
+ }
+ }
+ if (result.length === 0) {
+ throw new ChainValidationError(ChainValidationCode.noValidPath, "No valid certificate paths found");
+ }
+ let shortestLength = result[0].length;
+ let shortestIndex = 0;
+ for (let i = 0; i < result.length; i++) {
+ if (result[i].length < shortestLength) {
+ shortestLength = result[i].length;
+ shortestIndex = i;
+ }
+ }
+ for (let i = 0; i < result[shortestIndex].length; i++)
+ certificatePath.push((result[shortestIndex])[i]);
+ result = yield basicCheck(certificatePath, this.checkDate);
+ if (result.result === false)
+ throw result;
+ return certificatePath;
+ });
+ }
+ verify(parameters = {}, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ function compareDNSName(name, constraint) {
+ const namePrepared = stringPrep(name);
+ const constraintPrepared = stringPrep(constraint);
+ const nameSplitted = namePrepared.split(".");
+ const constraintSplitted = constraintPrepared.split(".");
+ const nameLen = nameSplitted.length;
+ const constrLen = constraintSplitted.length;
+ if ((nameLen === 0) || (constrLen === 0) || (nameLen < constrLen)) {
+ return false;
+ }
+ for (let i = 0; i < nameLen; i++) {
+ if (nameSplitted[i].length === 0) {
+ return false;
+ }
+ }
+ for (let i = 0; i < constrLen; i++) {
+ if (constraintSplitted[i].length === 0) {
+ if (i === 0) {
+ if (constrLen === 1) {
+ return false;
+ }
+ continue;
+ }
+ return false;
+ }
+ }
+ for (let i = 0; i < constrLen; i++) {
+ if (constraintSplitted[constrLen - 1 - i].length === 0) {
+ continue;
+ }
+ if (nameSplitted[nameLen - 1 - i].localeCompare(constraintSplitted[constrLen - 1 - i]) !== 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+ function compareRFC822Name(name, constraint) {
+ const namePrepared = stringPrep(name);
+ const constraintPrepared = stringPrep(constraint);
+ const nameSplitted = namePrepared.split("@");
+ const constraintSplitted = constraintPrepared.split("@");
+ if ((nameSplitted.length === 0) || (constraintSplitted.length === 0) || (nameSplitted.length < constraintSplitted.length))
+ return false;
+ if (constraintSplitted.length === 1) {
+ const result = compareDNSName(nameSplitted[1], constraintSplitted[0]);
+ if (result) {
+ const ns = nameSplitted[1].split(".");
+ const cs = constraintSplitted[0].split(".");
+ if (cs[0].length === 0)
+ return true;
+ return ns.length === cs.length;
+ }
+ return false;
+ }
+ return (namePrepared.localeCompare(constraintPrepared) === 0);
+ }
+ function compareUniformResourceIdentifier(name, constraint) {
+ let namePrepared = stringPrep(name);
+ const constraintPrepared = stringPrep(constraint);
+ const ns = namePrepared.split("/");
+ const cs = constraintPrepared.split("/");
+ if (cs.length > 1)
+ return false;
+ if (ns.length > 1) {
+ for (let i = 0; i < ns.length; i++) {
+ if ((ns[i].length > 0) && (ns[i].charAt(ns[i].length - 1) !== ":")) {
+ const nsPort = ns[i].split(":");
+ namePrepared = nsPort[0];
+ break;
+ }
+ }
+ }
+ const result = compareDNSName(namePrepared, constraintPrepared);
+ if (result) {
+ const nameSplitted = namePrepared.split(".");
+ const constraintSplitted = constraintPrepared.split(".");
+ if (constraintSplitted[0].length === 0)
+ return true;
+ return nameSplitted.length === constraintSplitted.length;
+ }
+ return false;
+ }
+ function compareIPAddress(name, constraint) {
+ const nameView = name.valueBlock.valueHexView;
+ const constraintView = constraint.valueBlock.valueHexView;
+ if ((nameView.length === 4) && (constraintView.length === 8)) {
+ for (let i = 0; i < 4; i++) {
+ if ((nameView[i] ^ constraintView[i]) & constraintView[i + 4])
+ return false;
+ }
+ return true;
+ }
+ if ((nameView.length === 16) && (constraintView.length === 32)) {
+ for (let i = 0; i < 16; i++) {
+ if ((nameView[i] ^ constraintView[i]) & constraintView[i + 16])
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+ function compareDirectoryName(name, constraint) {
+ if ((name.typesAndValues.length === 0) || (constraint.typesAndValues.length === 0))
+ return true;
+ if (name.typesAndValues.length < constraint.typesAndValues.length)
+ return false;
+ let result = true;
+ let nameStart = 0;
+ for (let i = 0; i < constraint.typesAndValues.length; i++) {
+ let localResult = false;
+ for (let j = nameStart; j < name.typesAndValues.length; j++) {
+ localResult = name.typesAndValues[j].isEqual(constraint.typesAndValues[i]);
+ if (name.typesAndValues[j].type === constraint.typesAndValues[i].type)
+ result = result && localResult;
+ if (localResult === true) {
+ if ((nameStart === 0) || (nameStart === j)) {
+ nameStart = j + 1;
+ break;
+ }
+ else
+ return false;
+ }
+ }
+ if (localResult === false)
+ return false;
+ }
+ return (nameStart === 0) ? false : result;
+ }
+ try {
+ if (this.certs.length === 0)
+ throw new Error("Empty certificate array");
+ const passedWhenNotRevValues = parameters.passedWhenNotRevValues || false;
+ const initialPolicySet = parameters.initialPolicySet || [id_AnyPolicy];
+ const initialExplicitPolicy = parameters.initialExplicitPolicy || false;
+ const initialPolicyMappingInhibit = parameters.initialPolicyMappingInhibit || false;
+ const initialInhibitPolicy = parameters.initialInhibitPolicy || false;
+ const initialPermittedSubtreesSet = parameters.initialPermittedSubtreesSet || [];
+ const initialExcludedSubtreesSet = parameters.initialExcludedSubtreesSet || [];
+ const initialRequiredNameForms = parameters.initialRequiredNameForms || [];
+ let explicitPolicyIndicator = initialExplicitPolicy;
+ let policyMappingInhibitIndicator = initialPolicyMappingInhibit;
+ let inhibitAnyPolicyIndicator = initialInhibitPolicy;
+ const pendingConstraints = [
+ false,
+ false,
+ false,
+ ];
+ let explicitPolicyPending = 0;
+ let policyMappingInhibitPending = 0;
+ let inhibitAnyPolicyPending = 0;
+ let permittedSubtrees = initialPermittedSubtreesSet;
+ let excludedSubtrees = initialExcludedSubtreesSet;
+ const requiredNameForms = initialRequiredNameForms;
+ let pathDepth = 1;
+ this.certs = yield this.sort(passedWhenNotRevValues, crypto);
+ const allPolicies = [];
+ allPolicies.push(id_AnyPolicy);
+ const policiesAndCerts = [];
+ const anyPolicyArray = new Array(this.certs.length - 1);
+ for (let ii = 0; ii < (this.certs.length - 1); ii++)
+ anyPolicyArray[ii] = true;
+ policiesAndCerts.push(anyPolicyArray);
+ const policyMappings = new Array(this.certs.length - 1);
+ const certPolicies = new Array(this.certs.length - 1);
+ let explicitPolicyStart = (explicitPolicyIndicator) ? (this.certs.length - 1) : (-1);
+ for (let i = (this.certs.length - 2); i >= 0; i--, pathDepth++) {
+ const cert = this.certs[i];
+ if (cert.extensions) {
+ for (let j = 0; j < cert.extensions.length; j++) {
+ const extension = cert.extensions[j];
+ if (extension.extnID === id_CertificatePolicies) {
+ certPolicies[i] = extension.parsedValue;
+ for (let s = 0; s < allPolicies.length; s++) {
+ if (allPolicies[s] === id_AnyPolicy) {
+ delete (policiesAndCerts[s])[i];
+ break;
+ }
+ }
+ for (let k = 0; k < extension.parsedValue.certificatePolicies.length; k++) {
+ let policyIndex = (-1);
+ const policyId = extension.parsedValue.certificatePolicies[k].policyIdentifier;
+ for (let s = 0; s < allPolicies.length; s++) {
+ if (policyId === allPolicies[s]) {
+ policyIndex = s;
+ break;
+ }
+ }
+ if (policyIndex === (-1)) {
+ allPolicies.push(policyId);
+ const certArray = new Array(this.certs.length - 1);
+ certArray[i] = true;
+ policiesAndCerts.push(certArray);
+ }
+ else
+ (policiesAndCerts[policyIndex])[i] = true;
+ }
+ }
+ if (extension.extnID === id_PolicyMappings) {
+ if (policyMappingInhibitIndicator) {
+ return {
+ result: false,
+ resultCode: 98,
+ resultMessage: "Policy mapping prohibited"
+ };
+ }
+ policyMappings[i] = extension.parsedValue;
+ }
+ if (extension.extnID === id_PolicyConstraints) {
+ if (explicitPolicyIndicator === false) {
+ if (extension.parsedValue.requireExplicitPolicy === 0) {
+ explicitPolicyIndicator = true;
+ explicitPolicyStart = i;
+ }
+ else {
+ if (pendingConstraints[0] === false) {
+ pendingConstraints[0] = true;
+ explicitPolicyPending = extension.parsedValue.requireExplicitPolicy;
+ }
+ else
+ explicitPolicyPending = (explicitPolicyPending > extension.parsedValue.requireExplicitPolicy) ? extension.parsedValue.requireExplicitPolicy : explicitPolicyPending;
+ }
+ if (extension.parsedValue.inhibitPolicyMapping === 0)
+ policyMappingInhibitIndicator = true;
+ else {
+ if (pendingConstraints[1] === false) {
+ pendingConstraints[1] = true;
+ policyMappingInhibitPending = extension.parsedValue.inhibitPolicyMapping + 1;
+ }
+ else
+ policyMappingInhibitPending = (policyMappingInhibitPending > (extension.parsedValue.inhibitPolicyMapping + 1)) ? (extension.parsedValue.inhibitPolicyMapping + 1) : policyMappingInhibitPending;
+ }
+ }
+ }
+ if (extension.extnID === id_InhibitAnyPolicy) {
+ if (inhibitAnyPolicyIndicator === false) {
+ if (extension.parsedValue.valueBlock.valueDec === 0)
+ inhibitAnyPolicyIndicator = true;
+ else {
+ if (pendingConstraints[2] === false) {
+ pendingConstraints[2] = true;
+ inhibitAnyPolicyPending = extension.parsedValue.valueBlock.valueDec;
+ }
+ else
+ inhibitAnyPolicyPending = (inhibitAnyPolicyPending > extension.parsedValue.valueBlock.valueDec) ? extension.parsedValue.valueBlock.valueDec : inhibitAnyPolicyPending;
+ }
+ }
+ }
+ }
+ if (inhibitAnyPolicyIndicator === true) {
+ let policyIndex = (-1);
+ for (let searchAnyPolicy = 0; searchAnyPolicy < allPolicies.length; searchAnyPolicy++) {
+ if (allPolicies[searchAnyPolicy] === id_AnyPolicy) {
+ policyIndex = searchAnyPolicy;
+ break;
+ }
+ }
+ if (policyIndex !== (-1))
+ delete (policiesAndCerts[0])[i];
+ }
+ if (explicitPolicyIndicator === false) {
+ if (pendingConstraints[0] === true) {
+ explicitPolicyPending--;
+ if (explicitPolicyPending === 0) {
+ explicitPolicyIndicator = true;
+ explicitPolicyStart = i;
+ pendingConstraints[0] = false;
+ }
+ }
+ }
+ if (policyMappingInhibitIndicator === false) {
+ if (pendingConstraints[1] === true) {
+ policyMappingInhibitPending--;
+ if (policyMappingInhibitPending === 0) {
+ policyMappingInhibitIndicator = true;
+ pendingConstraints[1] = false;
+ }
+ }
+ }
+ if (inhibitAnyPolicyIndicator === false) {
+ if (pendingConstraints[2] === true) {
+ inhibitAnyPolicyPending--;
+ if (inhibitAnyPolicyPending === 0) {
+ inhibitAnyPolicyIndicator = true;
+ pendingConstraints[2] = false;
+ }
+ }
+ }
+ }
+ }
+ for (let i = 0; i < (this.certs.length - 1); i++) {
+ if ((i < (this.certs.length - 2)) && (typeof policyMappings[i + 1] !== "undefined")) {
+ for (let k = 0; k < policyMappings[i + 1].mappings.length; k++) {
+ if ((policyMappings[i + 1].mappings[k].issuerDomainPolicy === id_AnyPolicy) || (policyMappings[i + 1].mappings[k].subjectDomainPolicy === id_AnyPolicy)) {
+ return {
+ result: false,
+ resultCode: 99,
+ resultMessage: "The \"anyPolicy\" should not be a part of policy mapping scheme"
+ };
+ }
+ let issuerDomainPolicyIndex = (-1);
+ let subjectDomainPolicyIndex = (-1);
+ for (let n = 0; n < allPolicies.length; n++) {
+ if (allPolicies[n] === policyMappings[i + 1].mappings[k].issuerDomainPolicy)
+ issuerDomainPolicyIndex = n;
+ if (allPolicies[n] === policyMappings[i + 1].mappings[k].subjectDomainPolicy)
+ subjectDomainPolicyIndex = n;
+ }
+ if (typeof (policiesAndCerts[issuerDomainPolicyIndex])[i] !== "undefined")
+ delete (policiesAndCerts[issuerDomainPolicyIndex])[i];
+ for (let j = 0; j < certPolicies[i].certificatePolicies.length; j++) {
+ if (policyMappings[i + 1].mappings[k].subjectDomainPolicy === certPolicies[i].certificatePolicies[j].policyIdentifier) {
+ if ((issuerDomainPolicyIndex !== (-1)) && (subjectDomainPolicyIndex !== (-1))) {
+ for (let m = 0; m <= i; m++) {
+ if (typeof (policiesAndCerts[subjectDomainPolicyIndex])[m] !== "undefined") {
+ (policiesAndCerts[issuerDomainPolicyIndex])[m] = true;
+ delete (policiesAndCerts[subjectDomainPolicyIndex])[m];
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ for (let i = 0; i < allPolicies.length; i++) {
+ if (allPolicies[i] === id_AnyPolicy) {
+ for (let j = 0; j < explicitPolicyStart; j++)
+ delete (policiesAndCerts[i])[j];
+ }
+ }
+ const authConstrPolicies = [];
+ for (let i = 0; i < policiesAndCerts.length; i++) {
+ let found = true;
+ for (let j = 0; j < (this.certs.length - 1); j++) {
+ let anyPolicyFound = false;
+ if ((j < explicitPolicyStart) && (allPolicies[i] === id_AnyPolicy) && (allPolicies.length > 1)) {
+ found = false;
+ break;
+ }
+ if (typeof (policiesAndCerts[i])[j] === "undefined") {
+ if (j >= explicitPolicyStart) {
+ for (let k = 0; k < allPolicies.length; k++) {
+ if (allPolicies[k] === id_AnyPolicy) {
+ if ((policiesAndCerts[k])[j] === true)
+ anyPolicyFound = true;
+ break;
+ }
+ }
+ }
+ if (!anyPolicyFound) {
+ found = false;
+ break;
+ }
+ }
+ }
+ if (found === true)
+ authConstrPolicies.push(allPolicies[i]);
+ }
+ let userConstrPolicies = [];
+ if ((initialPolicySet.length === 1) && (initialPolicySet[0] === id_AnyPolicy) && (explicitPolicyIndicator === false))
+ userConstrPolicies = initialPolicySet;
+ else {
+ if ((authConstrPolicies.length === 1) && (authConstrPolicies[0] === id_AnyPolicy))
+ userConstrPolicies = initialPolicySet;
+ else {
+ for (let i = 0; i < authConstrPolicies.length; i++) {
+ for (let j = 0; j < initialPolicySet.length; j++) {
+ if ((initialPolicySet[j] === authConstrPolicies[i]) || (initialPolicySet[j] === id_AnyPolicy)) {
+ userConstrPolicies.push(authConstrPolicies[i]);
+ break;
+ }
+ }
+ }
+ }
+ }
+ const policyResult = {
+ result: (userConstrPolicies.length > 0),
+ resultCode: 0,
+ resultMessage: (userConstrPolicies.length > 0) ? EMPTY_STRING : "Zero \"userConstrPolicies\" array, no intersections with \"authConstrPolicies\"",
+ authConstrPolicies,
+ userConstrPolicies,
+ explicitPolicyIndicator,
+ policyMappings,
+ certificatePath: this.certs
+ };
+ if (userConstrPolicies.length === 0)
+ return policyResult;
+ if (policyResult.result === false)
+ return policyResult;
+ pathDepth = 1;
+ for (let i = (this.certs.length - 2); i >= 0; i--, pathDepth++) {
+ const cert = this.certs[i];
+ let subjectAltNames = [];
+ let certPermittedSubtrees = [];
+ let certExcludedSubtrees = [];
+ if (cert.extensions) {
+ for (let j = 0; j < cert.extensions.length; j++) {
+ const extension = cert.extensions[j];
+ if (extension.extnID === id_NameConstraints) {
+ if ("permittedSubtrees" in extension.parsedValue)
+ certPermittedSubtrees = certPermittedSubtrees.concat(extension.parsedValue.permittedSubtrees);
+ if ("excludedSubtrees" in extension.parsedValue)
+ certExcludedSubtrees = certExcludedSubtrees.concat(extension.parsedValue.excludedSubtrees);
+ }
+ if (extension.extnID === id_SubjectAltName)
+ subjectAltNames = subjectAltNames.concat(extension.parsedValue.altNames);
+ }
+ }
+ let formFound = (requiredNameForms.length <= 0);
+ for (let j = 0; j < requiredNameForms.length; j++) {
+ switch (requiredNameForms[j].base.type) {
+ case 4:
+ {
+ if (requiredNameForms[j].base.value.typesAndValues.length !== cert.subject.typesAndValues.length)
+ continue;
+ formFound = true;
+ for (let k = 0; k < cert.subject.typesAndValues.length; k++) {
+ if (cert.subject.typesAndValues[k].type !== requiredNameForms[j].base.value.typesAndValues[k].type) {
+ formFound = false;
+ break;
+ }
+ }
+ if (formFound === true)
+ break;
+ }
+ break;
+ default:
+ }
+ }
+ if (formFound === false) {
+ policyResult.result = false;
+ policyResult.resultCode = 21;
+ policyResult.resultMessage = "No necessary name form found";
+ throw policyResult;
+ }
+ const constrGroups = [
+ [],
+ [],
+ [],
+ [],
+ [],
+ ];
+ for (let j = 0; j < permittedSubtrees.length; j++) {
+ switch (permittedSubtrees[j].base.type) {
+ case 1:
+ constrGroups[0].push(permittedSubtrees[j]);
+ break;
+ case 2:
+ constrGroups[1].push(permittedSubtrees[j]);
+ break;
+ case 4:
+ constrGroups[2].push(permittedSubtrees[j]);
+ break;
+ case 6:
+ constrGroups[3].push(permittedSubtrees[j]);
+ break;
+ case 7:
+ constrGroups[4].push(permittedSubtrees[j]);
+ break;
+ default:
+ }
+ }
+ for (let p = 0; p < 5; p++) {
+ let groupPermitted = false;
+ let valueExists = false;
+ const group = constrGroups[p];
+ for (let j = 0; j < group.length; j++) {
+ switch (p) {
+ case 0:
+ if (subjectAltNames.length > 0) {
+ for (let k = 0; k < subjectAltNames.length; k++) {
+ if (subjectAltNames[k].type === 1) {
+ valueExists = true;
+ groupPermitted = groupPermitted || compareRFC822Name(subjectAltNames[k].value, group[j].base.value);
+ }
+ }
+ }
+ else {
+ for (let k = 0; k < cert.subject.typesAndValues.length; k++) {
+ if ((cert.subject.typesAndValues[k].type === "1.2.840.113549.1.9.1") ||
+ (cert.subject.typesAndValues[k].type === "0.9.2342.19200300.100.1.3")) {
+ valueExists = true;
+ groupPermitted = groupPermitted || compareRFC822Name(cert.subject.typesAndValues[k].value.valueBlock.value, group[j].base.value);
+ }
+ }
+ }
+ break;
+ case 1:
+ if (subjectAltNames.length > 0) {
+ for (let k = 0; k < subjectAltNames.length; k++) {
+ if (subjectAltNames[k].type === 2) {
+ valueExists = true;
+ groupPermitted = groupPermitted || compareDNSName(subjectAltNames[k].value, group[j].base.value);
+ }
+ }
+ }
+ break;
+ case 2:
+ valueExists = true;
+ groupPermitted = compareDirectoryName(cert.subject, group[j].base.value);
+ break;
+ case 3:
+ if (subjectAltNames.length > 0) {
+ for (let k = 0; k < subjectAltNames.length; k++) {
+ if (subjectAltNames[k].type === 6) {
+ valueExists = true;
+ groupPermitted = groupPermitted || compareUniformResourceIdentifier(subjectAltNames[k].value, group[j].base.value);
+ }
+ }
+ }
+ break;
+ case 4:
+ if (subjectAltNames.length > 0) {
+ for (let k = 0; k < subjectAltNames.length; k++) {
+ if (subjectAltNames[k].type === 7) {
+ valueExists = true;
+ groupPermitted = groupPermitted || compareIPAddress(subjectAltNames[k].value, group[j].base.value);
+ }
+ }
+ }
+ break;
+ default:
+ }
+ if (groupPermitted)
+ break;
+ }
+ if ((groupPermitted === false) && (group.length > 0) && valueExists) {
+ policyResult.result = false;
+ policyResult.resultCode = 41;
+ policyResult.resultMessage = "Failed to meet \"permitted sub-trees\" name constraint";
+ throw policyResult;
+ }
+ }
+ let excluded = false;
+ for (let j = 0; j < excludedSubtrees.length; j++) {
+ switch (excludedSubtrees[j].base.type) {
+ case 1:
+ if (subjectAltNames.length >= 0) {
+ for (let k = 0; k < subjectAltNames.length; k++) {
+ if (subjectAltNames[k].type === 1)
+ excluded = excluded || compareRFC822Name(subjectAltNames[k].value, excludedSubtrees[j].base.value);
+ }
+ }
+ else {
+ for (let k = 0; k < cert.subject.typesAndValues.length; k++) {
+ if ((cert.subject.typesAndValues[k].type === "1.2.840.113549.1.9.1") ||
+ (cert.subject.typesAndValues[k].type === "0.9.2342.19200300.100.1.3"))
+ excluded = excluded || compareRFC822Name(cert.subject.typesAndValues[k].value.valueBlock.value, excludedSubtrees[j].base.value);
+ }
+ }
+ break;
+ case 2:
+ if (subjectAltNames.length > 0) {
+ for (let k = 0; k < subjectAltNames.length; k++) {
+ if (subjectAltNames[k].type === 2)
+ excluded = excluded || compareDNSName(subjectAltNames[k].value, excludedSubtrees[j].base.value);
+ }
+ }
+ break;
+ case 4:
+ excluded = excluded || compareDirectoryName(cert.subject, excludedSubtrees[j].base.value);
+ break;
+ case 6:
+ if (subjectAltNames.length > 0) {
+ for (let k = 0; k < subjectAltNames.length; k++) {
+ if (subjectAltNames[k].type === 6)
+ excluded = excluded || compareUniformResourceIdentifier(subjectAltNames[k].value, excludedSubtrees[j].base.value);
+ }
+ }
+ break;
+ case 7:
+ if (subjectAltNames.length > 0) {
+ for (let k = 0; k < subjectAltNames.length; k++) {
+ if (subjectAltNames[k].type === 7)
+ excluded = excluded || compareIPAddress(subjectAltNames[k].value, excludedSubtrees[j].base.value);
+ }
+ }
+ break;
+ default:
+ }
+ if (excluded)
+ break;
+ }
+ if (excluded === true) {
+ policyResult.result = false;
+ policyResult.resultCode = 42;
+ policyResult.resultMessage = "Failed to meet \"excluded sub-trees\" name constraint";
+ throw policyResult;
+ }
+ permittedSubtrees = permittedSubtrees.concat(certPermittedSubtrees);
+ excludedSubtrees = excludedSubtrees.concat(certExcludedSubtrees);
+ }
+ return policyResult;
+ }
+ catch (error) {
+ if (error instanceof Error) {
+ if (error instanceof ChainValidationError) {
+ return {
+ result: false,
+ resultCode: error.code,
+ resultMessage: error.message,
+ error: error,
+ };
+ }
+ return {
+ result: false,
+ resultCode: ChainValidationCode.unknown,
+ resultMessage: error.message,
+ error: error,
+ };
+ }
+ if (error && typeof error === "object" && "resultMessage" in error) {
+ return error;
+ }
+ return {
+ result: false,
+ resultCode: -1,
+ resultMessage: `${error}`,
+ };
+ }
+ });
+ }
+}
+
+const TBS_RESPONSE_DATA = "tbsResponseData";
+const SIGNATURE_ALGORITHM$3 = "signatureAlgorithm";
+const SIGNATURE$2 = "signature";
+const CERTS$1 = "certs";
+const BASIC_OCSP_RESPONSE = "BasicOCSPResponse";
+const BASIC_OCSP_RESPONSE_TBS_RESPONSE_DATA = `${BASIC_OCSP_RESPONSE}.${TBS_RESPONSE_DATA}`;
+const BASIC_OCSP_RESPONSE_SIGNATURE_ALGORITHM = `${BASIC_OCSP_RESPONSE}.${SIGNATURE_ALGORITHM$3}`;
+const BASIC_OCSP_RESPONSE_SIGNATURE = `${BASIC_OCSP_RESPONSE}.${SIGNATURE$2}`;
+const BASIC_OCSP_RESPONSE_CERTS = `${BASIC_OCSP_RESPONSE}.${CERTS$1}`;
+const CLEAR_PROPS$g = [
+ BASIC_OCSP_RESPONSE_TBS_RESPONSE_DATA,
+ BASIC_OCSP_RESPONSE_SIGNATURE_ALGORITHM,
+ BASIC_OCSP_RESPONSE_SIGNATURE,
+ BASIC_OCSP_RESPONSE_CERTS
+];
+class BasicOCSPResponse extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.tbsResponseData = getParametersValue(parameters, TBS_RESPONSE_DATA, BasicOCSPResponse.defaultValues(TBS_RESPONSE_DATA));
+ this.signatureAlgorithm = getParametersValue(parameters, SIGNATURE_ALGORITHM$3, BasicOCSPResponse.defaultValues(SIGNATURE_ALGORITHM$3));
+ this.signature = getParametersValue(parameters, SIGNATURE$2, BasicOCSPResponse.defaultValues(SIGNATURE$2));
+ if (CERTS$1 in parameters) {
+ this.certs = getParametersValue(parameters, CERTS$1, BasicOCSPResponse.defaultValues(CERTS$1));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case TBS_RESPONSE_DATA:
+ return new ResponseData();
+ case SIGNATURE_ALGORITHM$3:
+ return new AlgorithmIdentifier();
+ case SIGNATURE$2:
+ return new BitString();
+ case CERTS$1:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case "type":
+ {
+ let comparisonResult = ((ResponseData.compareWithDefault("tbs", memberValue.tbs)) &&
+ (ResponseData.compareWithDefault("responderID", memberValue.responderID)) &&
+ (ResponseData.compareWithDefault("producedAt", memberValue.producedAt)) &&
+ (ResponseData.compareWithDefault("responses", memberValue.responses)));
+ if ("responseExtensions" in memberValue)
+ comparisonResult = comparisonResult && (ResponseData.compareWithDefault("responseExtensions", memberValue.responseExtensions));
+ return comparisonResult;
+ }
+ case SIGNATURE_ALGORITHM$3:
+ return ((memberValue.algorithmId === EMPTY_STRING) && (("algorithmParams" in memberValue) === false));
+ case SIGNATURE$2:
+ return (memberValue.isEqual(BasicOCSPResponse.defaultValues(memberName)));
+ case CERTS$1:
+ return (memberValue.length === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || BASIC_OCSP_RESPONSE),
+ value: [
+ ResponseData.schema(names.tbsResponseData || {
+ names: {
+ blockName: BASIC_OCSP_RESPONSE_TBS_RESPONSE_DATA
+ }
+ }),
+ AlgorithmIdentifier.schema(names.signatureAlgorithm || {
+ names: {
+ blockName: BASIC_OCSP_RESPONSE_SIGNATURE_ALGORITHM
+ }
+ }),
+ new BitString({ name: (names.signature || BASIC_OCSP_RESPONSE_SIGNATURE) }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [
+ new Sequence({
+ value: [new Repeated({
+ name: BASIC_OCSP_RESPONSE_CERTS,
+ value: Certificate.schema(names.certs || {})
+ })]
+ })
+ ]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$g);
+ const asn1 = compareSchema(schema, schema, BasicOCSPResponse.schema());
+ AsnError.assertSchema(asn1, this.className);
+ this.tbsResponseData = new ResponseData({ schema: asn1.result[BASIC_OCSP_RESPONSE_TBS_RESPONSE_DATA] });
+ this.signatureAlgorithm = new AlgorithmIdentifier({ schema: asn1.result[BASIC_OCSP_RESPONSE_SIGNATURE_ALGORITHM] });
+ this.signature = asn1.result[BASIC_OCSP_RESPONSE_SIGNATURE];
+ if (BASIC_OCSP_RESPONSE_CERTS in asn1.result) {
+ this.certs = Array.from(asn1.result[BASIC_OCSP_RESPONSE_CERTS], element => new Certificate({ schema: element }));
+ }
+ }
+ toSchema() {
+ const outputArray = [];
+ outputArray.push(this.tbsResponseData.toSchema());
+ outputArray.push(this.signatureAlgorithm.toSchema());
+ outputArray.push(this.signature);
+ if (this.certs) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [
+ new Sequence({
+ value: Array.from(this.certs, o => o.toSchema())
+ })
+ ]
+ }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {
+ tbsResponseData: this.tbsResponseData.toJSON(),
+ signatureAlgorithm: this.signatureAlgorithm.toJSON(),
+ signature: this.signature.toJSON(),
+ };
+ if (this.certs) {
+ res.certs = Array.from(this.certs, o => o.toJSON());
+ }
+ return res;
+ }
+ getCertificateStatus(certificate, issuerCertificate, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const result = {
+ isForCertificate: false,
+ status: 2
+ };
+ const hashesObject = {};
+ const certIDs = [];
+ for (const response of this.tbsResponseData.responses) {
+ const hashAlgorithm = crypto.getAlgorithmByOID(response.certID.hashAlgorithm.algorithmId, true, "CertID.hashAlgorithm");
+ if (!hashesObject[hashAlgorithm.name]) {
+ hashesObject[hashAlgorithm.name] = 1;
+ const certID = new CertID();
+ certIDs.push(certID);
+ yield certID.createForCertificate(certificate, {
+ hashAlgorithm: hashAlgorithm.name,
+ issuerCertificate
+ }, crypto);
+ }
+ }
+ for (const response of this.tbsResponseData.responses) {
+ for (const id of certIDs) {
+ if (response.certID.isEqual(id)) {
+ result.isForCertificate = true;
+ try {
+ switch (response.certStatus.idBlock.isConstructed) {
+ case true:
+ if (response.certStatus.idBlock.tagNumber === 1)
+ result.status = 1;
+ break;
+ case false:
+ switch (response.certStatus.idBlock.tagNumber) {
+ case 0:
+ result.status = 0;
+ break;
+ case 2:
+ result.status = 2;
+ break;
+ default:
+ }
+ break;
+ default:
+ }
+ }
+ catch (ex) {
+ }
+ return result;
+ }
+ }
+ }
+ return result;
+ });
+ }
+ sign(privateKey, hashAlgorithm = "SHA-1", crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ if (!privateKey) {
+ throw new Error("Need to provide a private key for signing");
+ }
+ const signatureParams = yield crypto.getSignatureParameters(privateKey, hashAlgorithm);
+ const algorithm = signatureParams.parameters.algorithm;
+ if (!("name" in algorithm)) {
+ throw new Error("Empty algorithm");
+ }
+ this.signatureAlgorithm = signatureParams.signatureAlgorithm;
+ this.tbsResponseData.tbsView = new Uint8Array(this.tbsResponseData.toSchema(true).toBER());
+ const signature = yield crypto.signWithPrivateKey(this.tbsResponseData.tbsView, privateKey, { algorithm });
+ this.signature = new BitString({ valueHex: signature });
+ });
+ }
+ verify(params = {}, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ let signerCert = null;
+ let certIndex = -1;
+ const trustedCerts = params.trustedCerts || [];
+ if (!this.certs) {
+ throw new Error("No certificates attached to the BasicOCSPResponse");
+ }
+ switch (true) {
+ case (this.tbsResponseData.responderID instanceof RelativeDistinguishedNames):
+ for (const [index, certificate] of this.certs.entries()) {
+ if (certificate.subject.isEqual(this.tbsResponseData.responderID)) {
+ certIndex = index;
+ break;
+ }
+ }
+ break;
+ case (this.tbsResponseData.responderID instanceof OctetString):
+ for (const [index, cert] of this.certs.entries()) {
+ const hash = yield crypto.digest({ name: "sha-1" }, cert.subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHexView);
+ if (isEqualBuffer(hash, this.tbsResponseData.responderID.valueBlock.valueHex)) {
+ certIndex = index;
+ break;
+ }
+ }
+ break;
+ default:
+ throw new Error("Wrong value for responderID");
+ }
+ if (certIndex === (-1))
+ throw new Error("Correct certificate was not found in OCSP response");
+ signerCert = this.certs[certIndex];
+ const additionalCerts = [signerCert];
+ for (const cert of this.certs) {
+ const caCert = yield checkCA(cert, signerCert);
+ if (caCert) {
+ additionalCerts.push(caCert);
+ }
+ }
+ const certChain = new CertificateChainValidationEngine({
+ certs: additionalCerts,
+ trustedCerts,
+ });
+ const verificationResult = yield certChain.verify({}, crypto);
+ if (!verificationResult.result) {
+ throw new Error("Validation of signer's certificate failed");
+ }
+ return crypto.verifyWithPublicKey(this.tbsResponseData.tbsView, this.signature, this.certs[certIndex].subjectPublicKeyInfo, this.signatureAlgorithm);
+ });
+ }
+}
+BasicOCSPResponse.CLASS_NAME = "BasicOCSPResponse";
+
+const TBS$1 = "tbs";
+const VERSION$6 = "version";
+const SUBJECT = "subject";
+const SPKI = "subjectPublicKeyInfo";
+const ATTRIBUTES$1 = "attributes";
+const SIGNATURE_ALGORITHM$2 = "signatureAlgorithm";
+const SIGNATURE_VALUE = "signatureValue";
+const CSR_INFO = "CertificationRequestInfo";
+const CSR_INFO_VERSION = `${CSR_INFO}.version`;
+const CSR_INFO_SUBJECT = `${CSR_INFO}.subject`;
+const CSR_INFO_SPKI = `${CSR_INFO}.subjectPublicKeyInfo`;
+const CSR_INFO_ATTRS = `${CSR_INFO}.attributes`;
+const CLEAR_PROPS$f = [
+ CSR_INFO,
+ CSR_INFO_VERSION,
+ CSR_INFO_SUBJECT,
+ CSR_INFO_SPKI,
+ CSR_INFO_ATTRS,
+ SIGNATURE_ALGORITHM$2,
+ SIGNATURE_VALUE
+];
+function CertificationRequestInfo(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.CertificationRequestInfo || CSR_INFO),
+ value: [
+ new Integer({ name: (names.CertificationRequestInfoVersion || CSR_INFO_VERSION) }),
+ RelativeDistinguishedNames.schema(names.subject || {
+ names: {
+ blockName: CSR_INFO_SUBJECT
+ }
+ }),
+ PublicKeyInfo.schema({
+ names: {
+ blockName: CSR_INFO_SPKI
+ }
+ }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [
+ new Repeated({
+ optional: true,
+ name: (names.CertificationRequestInfoAttributes || CSR_INFO_ATTRS),
+ value: Attribute.schema(names.attributes || {})
+ })
+ ]
+ })
+ ]
+ }));
+}
+class CertificationRequest extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.tbsView = new Uint8Array(getParametersValue(parameters, TBS$1, CertificationRequest.defaultValues(TBS$1)));
+ this.version = getParametersValue(parameters, VERSION$6, CertificationRequest.defaultValues(VERSION$6));
+ this.subject = getParametersValue(parameters, SUBJECT, CertificationRequest.defaultValues(SUBJECT));
+ this.subjectPublicKeyInfo = getParametersValue(parameters, SPKI, CertificationRequest.defaultValues(SPKI));
+ if (ATTRIBUTES$1 in parameters) {
+ this.attributes = getParametersValue(parameters, ATTRIBUTES$1, CertificationRequest.defaultValues(ATTRIBUTES$1));
+ }
+ this.signatureAlgorithm = getParametersValue(parameters, SIGNATURE_ALGORITHM$2, CertificationRequest.defaultValues(SIGNATURE_ALGORITHM$2));
+ this.signatureValue = getParametersValue(parameters, SIGNATURE_VALUE, CertificationRequest.defaultValues(SIGNATURE_VALUE));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ get tbs() {
+ return BufferSourceConverter.toArrayBuffer(this.tbsView);
+ }
+ set tbs(value) {
+ this.tbsView = new Uint8Array(value);
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case TBS$1:
+ return EMPTY_BUFFER;
+ case VERSION$6:
+ return 0;
+ case SUBJECT:
+ return new RelativeDistinguishedNames();
+ case SPKI:
+ return new PublicKeyInfo();
+ case ATTRIBUTES$1:
+ return [];
+ case SIGNATURE_ALGORITHM$2:
+ return new AlgorithmIdentifier();
+ case SIGNATURE_VALUE:
+ return new BitString();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ value: [
+ CertificationRequestInfo(names.certificationRequestInfo || {}),
+ new Sequence({
+ name: (names.signatureAlgorithm || SIGNATURE_ALGORITHM$2),
+ value: [
+ new ObjectIdentifier(),
+ new Any({ optional: true })
+ ]
+ }),
+ new BitString({ name: (names.signatureValue || SIGNATURE_VALUE) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$f);
+ const asn1 = compareSchema(schema, schema, CertificationRequest.schema());
+ AsnError.assertSchema(asn1, this.className);
+ this.tbsView = asn1.result.CertificationRequestInfo.valueBeforeDecodeView;
+ this.version = asn1.result[CSR_INFO_VERSION].valueBlock.valueDec;
+ this.subject = new RelativeDistinguishedNames({ schema: asn1.result[CSR_INFO_SUBJECT] });
+ this.subjectPublicKeyInfo = new PublicKeyInfo({ schema: asn1.result[CSR_INFO_SPKI] });
+ if (CSR_INFO_ATTRS in asn1.result) {
+ this.attributes = Array.from(asn1.result[CSR_INFO_ATTRS], element => new Attribute({ schema: element }));
+ }
+ this.signatureAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.signatureAlgorithm });
+ this.signatureValue = asn1.result.signatureValue;
+ }
+ encodeTBS() {
+ const outputArray = [
+ new Integer({ value: this.version }),
+ this.subject.toSchema(),
+ this.subjectPublicKeyInfo.toSchema()
+ ];
+ if (ATTRIBUTES$1 in this) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: Array.from(this.attributes || [], o => o.toSchema())
+ }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toSchema(encodeFlag = false) {
+ let tbsSchema;
+ if (encodeFlag === false) {
+ if (this.tbsView.byteLength === 0) {
+ return CertificationRequest.schema();
+ }
+ const asn1 = fromBER(this.tbsView);
+ AsnError.assert(asn1, "PKCS#10 Certificate Request");
+ tbsSchema = asn1.result;
+ }
+ else {
+ tbsSchema = this.encodeTBS();
+ }
+ return (new Sequence({
+ value: [
+ tbsSchema,
+ this.signatureAlgorithm.toSchema(),
+ this.signatureValue
+ ]
+ }));
+ }
+ toJSON() {
+ const object = {
+ tbs: Convert.ToHex(this.tbsView),
+ version: this.version,
+ subject: this.subject.toJSON(),
+ subjectPublicKeyInfo: this.subjectPublicKeyInfo.toJSON(),
+ signatureAlgorithm: this.signatureAlgorithm.toJSON(),
+ signatureValue: this.signatureValue.toJSON(),
+ };
+ if (ATTRIBUTES$1 in this) {
+ object.attributes = Array.from(this.attributes || [], o => o.toJSON());
+ }
+ return object;
+ }
+ sign(privateKey, hashAlgorithm = "SHA-1", crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ if (!privateKey) {
+ throw new Error("Need to provide a private key for signing");
+ }
+ const signatureParams = yield crypto.getSignatureParameters(privateKey, hashAlgorithm);
+ const parameters = signatureParams.parameters;
+ this.signatureAlgorithm = signatureParams.signatureAlgorithm;
+ this.tbsView = new Uint8Array(this.encodeTBS().toBER());
+ const signature = yield crypto.signWithPrivateKey(this.tbsView, privateKey, parameters);
+ this.signatureValue = new BitString({ valueHex: signature });
+ });
+ }
+ verify(crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return crypto.verifyWithPublicKey(this.tbsView, this.signatureValue, this.subjectPublicKeyInfo, this.signatureAlgorithm);
+ });
+ }
+ getPublicKey(parameters, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ return crypto.getPublicKey(this.subjectPublicKeyInfo, this.signatureAlgorithm, parameters);
+ });
+ }
+}
+CertificationRequest.CLASS_NAME = "CertificationRequest";
+
+const DIGEST_ALGORITHM$1 = "digestAlgorithm";
+const DIGEST = "digest";
+const CLEAR_PROPS$e = [
+ DIGEST_ALGORITHM$1,
+ DIGEST
+];
+class DigestInfo extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.digestAlgorithm = getParametersValue(parameters, DIGEST_ALGORITHM$1, DigestInfo.defaultValues(DIGEST_ALGORITHM$1));
+ this.digest = getParametersValue(parameters, DIGEST, DigestInfo.defaultValues(DIGEST));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case DIGEST_ALGORITHM$1:
+ return new AlgorithmIdentifier();
+ case DIGEST:
+ return new OctetString();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case DIGEST_ALGORITHM$1:
+ return ((AlgorithmIdentifier.compareWithDefault("algorithmId", memberValue.algorithmId)) &&
+ (("algorithmParams" in memberValue) === false));
+ case DIGEST:
+ return (memberValue.isEqual(DigestInfo.defaultValues(memberName)));
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ AlgorithmIdentifier.schema(names.digestAlgorithm || {
+ names: {
+ blockName: DIGEST_ALGORITHM$1
+ }
+ }),
+ new OctetString({ name: (names.digest || DIGEST) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$e);
+ const asn1 = compareSchema(schema, schema, DigestInfo.schema({
+ names: {
+ digestAlgorithm: {
+ names: {
+ blockName: DIGEST_ALGORITHM$1
+ }
+ },
+ digest: DIGEST
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.digestAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.digestAlgorithm });
+ this.digest = asn1.result.digest;
+ }
+ toSchema() {
+ return (new Sequence({
+ value: [
+ this.digestAlgorithm.toSchema(),
+ this.digest
+ ]
+ }));
+ }
+ toJSON() {
+ return {
+ digestAlgorithm: this.digestAlgorithm.toJSON(),
+ digest: this.digest.toJSON(),
+ };
+ }
+}
+DigestInfo.CLASS_NAME = "DigestInfo";
+
+const E_CONTENT_TYPE = "eContentType";
+const E_CONTENT = "eContent";
+const CLEAR_PROPS$d = [
+ E_CONTENT_TYPE,
+ E_CONTENT,
+];
+class EncapsulatedContentInfo extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.eContentType = getParametersValue(parameters, E_CONTENT_TYPE, EncapsulatedContentInfo.defaultValues(E_CONTENT_TYPE));
+ if (E_CONTENT in parameters) {
+ this.eContent = getParametersValue(parameters, E_CONTENT, EncapsulatedContentInfo.defaultValues(E_CONTENT));
+ if ((this.eContent.idBlock.tagClass === 1) &&
+ (this.eContent.idBlock.tagNumber === 4)) {
+ if (this.eContent.idBlock.isConstructed === false) {
+ const constrString = new OctetString({
+ idBlock: { isConstructed: true },
+ isConstructed: true
+ });
+ let offset = 0;
+ const viewHex = this.eContent.valueBlock.valueHexView.slice().buffer;
+ let length = viewHex.byteLength;
+ while (length > 0) {
+ const pieceView = new Uint8Array(viewHex, offset, ((offset + 65536) > viewHex.byteLength) ? (viewHex.byteLength - offset) : 65536);
+ const _array = new ArrayBuffer(pieceView.length);
+ const _view = new Uint8Array(_array);
+ for (let i = 0; i < _view.length; i++) {
+ _view[i] = pieceView[i];
+ }
+ constrString.valueBlock.value.push(new OctetString({ valueHex: _array }));
+ length -= pieceView.length;
+ offset += pieceView.length;
+ }
+ this.eContent = constrString;
+ }
+ }
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case E_CONTENT_TYPE:
+ return EMPTY_STRING;
+ case E_CONTENT:
+ return new OctetString();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case E_CONTENT_TYPE:
+ return (memberValue === EMPTY_STRING);
+ case E_CONTENT:
+ {
+ if ((memberValue.idBlock.tagClass === 1) && (memberValue.idBlock.tagNumber === 4))
+ return (memberValue.isEqual(EncapsulatedContentInfo.defaultValues(E_CONTENT)));
+ return false;
+ }
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new ObjectIdentifier({ name: (names.eContentType || EMPTY_STRING) }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [
+ new Any({ name: (names.eContent || EMPTY_STRING) })
+ ]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$d);
+ const asn1 = compareSchema(schema, schema, EncapsulatedContentInfo.schema({
+ names: {
+ eContentType: E_CONTENT_TYPE,
+ eContent: E_CONTENT
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.eContentType = asn1.result.eContentType.valueBlock.toString();
+ if (E_CONTENT in asn1.result)
+ this.eContent = asn1.result.eContent;
+ }
+ toSchema() {
+ const outputArray = [];
+ outputArray.push(new ObjectIdentifier({ value: this.eContentType }));
+ if (this.eContent) {
+ if (EncapsulatedContentInfo.compareWithDefault(E_CONTENT, this.eContent) === false) {
+ outputArray.push(new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [this.eContent]
+ }));
+ }
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {
+ eContentType: this.eContentType
+ };
+ if (this.eContent && EncapsulatedContentInfo.compareWithDefault(E_CONTENT, this.eContent) === false) {
+ res.eContent = this.eContent.toJSON();
+ }
+ return res;
+ }
+}
+EncapsulatedContentInfo.CLASS_NAME = "EncapsulatedContentInfo";
+
+class KeyBag extends PrivateKeyInfo {
+ constructor(parameters = {}) {
+ super(parameters);
+ }
+}
+
+const MAC = "mac";
+const MAC_SALT = "macSalt";
+const ITERATIONS = "iterations";
+const CLEAR_PROPS$c = [
+ MAC,
+ MAC_SALT,
+ ITERATIONS
+];
+class MacData extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.mac = getParametersValue(parameters, MAC, MacData.defaultValues(MAC));
+ this.macSalt = getParametersValue(parameters, MAC_SALT, MacData.defaultValues(MAC_SALT));
+ if (ITERATIONS in parameters) {
+ this.iterations = getParametersValue(parameters, ITERATIONS, MacData.defaultValues(ITERATIONS));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case MAC:
+ return new DigestInfo();
+ case MAC_SALT:
+ return new OctetString();
+ case ITERATIONS:
+ return 1;
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case MAC:
+ return ((DigestInfo.compareWithDefault("digestAlgorithm", memberValue.digestAlgorithm)) &&
+ (DigestInfo.compareWithDefault("digest", memberValue.digest)));
+ case MAC_SALT:
+ return (memberValue.isEqual(MacData.defaultValues(memberName)));
+ case ITERATIONS:
+ return (memberValue === MacData.defaultValues(memberName));
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ optional: (names.optional || true),
+ value: [
+ DigestInfo.schema(names.mac || {
+ names: {
+ blockName: MAC
+ }
+ }),
+ new OctetString({ name: (names.macSalt || MAC_SALT) }),
+ new Integer({
+ optional: true,
+ name: (names.iterations || ITERATIONS)
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$c);
+ const asn1 = compareSchema(schema, schema, MacData.schema({
+ names: {
+ mac: {
+ names: {
+ blockName: MAC
+ }
+ },
+ macSalt: MAC_SALT,
+ iterations: ITERATIONS
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.mac = new DigestInfo({ schema: asn1.result.mac });
+ this.macSalt = asn1.result.macSalt;
+ if (ITERATIONS in asn1.result)
+ this.iterations = asn1.result.iterations.valueBlock.valueDec;
+ }
+ toSchema() {
+ const outputArray = [
+ this.mac.toSchema(),
+ this.macSalt
+ ];
+ if (this.iterations !== undefined) {
+ outputArray.push(new Integer({ value: this.iterations }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {
+ mac: this.mac.toJSON(),
+ macSalt: this.macSalt.toJSON(),
+ };
+ if (this.iterations !== undefined) {
+ res.iterations = this.iterations;
+ }
+ return res;
+ }
+}
+MacData.CLASS_NAME = "MacData";
+
+const HASH_ALGORITHM = "hashAlgorithm";
+const HASHED_MESSAGE = "hashedMessage";
+const CLEAR_PROPS$b = [
+ HASH_ALGORITHM,
+ HASHED_MESSAGE,
+];
+class MessageImprint extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.hashAlgorithm = getParametersValue(parameters, HASH_ALGORITHM, MessageImprint.defaultValues(HASH_ALGORITHM));
+ this.hashedMessage = getParametersValue(parameters, HASHED_MESSAGE, MessageImprint.defaultValues(HASHED_MESSAGE));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static create(hashAlgorithm, message, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const hashAlgorithmOID = crypto.getOIDByAlgorithm({ name: hashAlgorithm }, true, "hashAlgorithm");
+ const hashedMessage = yield crypto.digest(hashAlgorithm, message);
+ const res = new MessageImprint({
+ hashAlgorithm: new AlgorithmIdentifier({
+ algorithmId: hashAlgorithmOID,
+ algorithmParams: new Null(),
+ }),
+ hashedMessage: new OctetString({ valueHex: hashedMessage })
+ });
+ return res;
+ });
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case HASH_ALGORITHM:
+ return new AlgorithmIdentifier();
+ case HASHED_MESSAGE:
+ return new OctetString();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case HASH_ALGORITHM:
+ return ((memberValue.algorithmId === EMPTY_STRING) && (("algorithmParams" in memberValue) === false));
+ case HASHED_MESSAGE:
+ return (memberValue.isEqual(MessageImprint.defaultValues(memberName)) === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ AlgorithmIdentifier.schema(names.hashAlgorithm || {}),
+ new OctetString({ name: (names.hashedMessage || EMPTY_STRING) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$b);
+ const asn1 = compareSchema(schema, schema, MessageImprint.schema({
+ names: {
+ hashAlgorithm: {
+ names: {
+ blockName: HASH_ALGORITHM
+ }
+ },
+ hashedMessage: HASHED_MESSAGE
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.hashAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.hashAlgorithm });
+ this.hashedMessage = asn1.result.hashedMessage;
+ }
+ toSchema() {
+ return (new Sequence({
+ value: [
+ this.hashAlgorithm.toSchema(),
+ this.hashedMessage
+ ]
+ }));
+ }
+ toJSON() {
+ return {
+ hashAlgorithm: this.hashAlgorithm.toJSON(),
+ hashedMessage: this.hashedMessage.toJSON(),
+ };
+ }
+}
+MessageImprint.CLASS_NAME = "MessageImprint";
+
+const REQ_CERT = "reqCert";
+const SINGLE_REQUEST_EXTENSIONS = "singleRequestExtensions";
+const CLEAR_PROPS$a = [
+ REQ_CERT,
+ SINGLE_REQUEST_EXTENSIONS,
+];
+class Request extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.reqCert = getParametersValue(parameters, REQ_CERT, Request.defaultValues(REQ_CERT));
+ if (SINGLE_REQUEST_EXTENSIONS in parameters) {
+ this.singleRequestExtensions = getParametersValue(parameters, SINGLE_REQUEST_EXTENSIONS, Request.defaultValues(SINGLE_REQUEST_EXTENSIONS));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case REQ_CERT:
+ return new CertID();
+ case SINGLE_REQUEST_EXTENSIONS:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case REQ_CERT:
+ return (memberValue.isEqual(Request.defaultValues(memberName)));
+ case SINGLE_REQUEST_EXTENSIONS:
+ return (memberValue.length === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ CertID.schema(names.reqCert || {}),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [Extension.schema(names.extensions || {
+ names: {
+ blockName: (names.singleRequestExtensions || EMPTY_STRING)
+ }
+ })]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$a);
+ const asn1 = compareSchema(schema, schema, Request.schema({
+ names: {
+ reqCert: {
+ names: {
+ blockName: REQ_CERT
+ }
+ },
+ extensions: {
+ names: {
+ blockName: SINGLE_REQUEST_EXTENSIONS
+ }
+ }
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.reqCert = new CertID({ schema: asn1.result.reqCert });
+ if (SINGLE_REQUEST_EXTENSIONS in asn1.result) {
+ this.singleRequestExtensions = Array.from(asn1.result.singleRequestExtensions.valueBlock.value, element => new Extension({ schema: element }));
+ }
+ }
+ toSchema() {
+ const outputArray = [];
+ outputArray.push(this.reqCert.toSchema());
+ if (this.singleRequestExtensions) {
+ outputArray.push(new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [
+ new Sequence({
+ value: Array.from(this.singleRequestExtensions, o => o.toSchema())
+ })
+ ]
+ }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {
+ reqCert: this.reqCert.toJSON()
+ };
+ if (this.singleRequestExtensions) {
+ res.singleRequestExtensions = Array.from(this.singleRequestExtensions, o => o.toJSON());
+ }
+ return res;
+ }
+}
+Request.CLASS_NAME = "Request";
+
+const TBS = "tbs";
+const VERSION$5 = "version";
+const REQUESTOR_NAME = "requestorName";
+const REQUEST_LIST = "requestList";
+const REQUEST_EXTENSIONS = "requestExtensions";
+const TBS_REQUEST$1 = "TBSRequest";
+const TBS_REQUEST_VERSION = `${TBS_REQUEST$1}.${VERSION$5}`;
+const TBS_REQUEST_REQUESTOR_NAME = `${TBS_REQUEST$1}.${REQUESTOR_NAME}`;
+const TBS_REQUEST_REQUESTS = `${TBS_REQUEST$1}.requests`;
+const TBS_REQUEST_REQUEST_EXTENSIONS = `${TBS_REQUEST$1}.${REQUEST_EXTENSIONS}`;
+const CLEAR_PROPS$9 = [
+ TBS_REQUEST$1,
+ TBS_REQUEST_VERSION,
+ TBS_REQUEST_REQUESTOR_NAME,
+ TBS_REQUEST_REQUESTS,
+ TBS_REQUEST_REQUEST_EXTENSIONS
+];
+class TBSRequest extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.tbsView = new Uint8Array(getParametersValue(parameters, TBS, TBSRequest.defaultValues(TBS)));
+ if (VERSION$5 in parameters) {
+ this.version = getParametersValue(parameters, VERSION$5, TBSRequest.defaultValues(VERSION$5));
+ }
+ if (REQUESTOR_NAME in parameters) {
+ this.requestorName = getParametersValue(parameters, REQUESTOR_NAME, TBSRequest.defaultValues(REQUESTOR_NAME));
+ }
+ this.requestList = getParametersValue(parameters, REQUEST_LIST, TBSRequest.defaultValues(REQUEST_LIST));
+ if (REQUEST_EXTENSIONS in parameters) {
+ this.requestExtensions = getParametersValue(parameters, REQUEST_EXTENSIONS, TBSRequest.defaultValues(REQUEST_EXTENSIONS));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ get tbs() {
+ return BufferSourceConverter.toArrayBuffer(this.tbsView);
+ }
+ set tbs(value) {
+ this.tbsView = new Uint8Array(value);
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case TBS:
+ return EMPTY_BUFFER;
+ case VERSION$5:
+ return 0;
+ case REQUESTOR_NAME:
+ return new GeneralName();
+ case REQUEST_LIST:
+ case REQUEST_EXTENSIONS:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case TBS:
+ return (memberValue.byteLength === 0);
+ case VERSION$5:
+ return (memberValue === TBSRequest.defaultValues(memberName));
+ case REQUESTOR_NAME:
+ return ((memberValue.type === GeneralName.defaultValues("type")) && (Object.keys(memberValue.value).length === 0));
+ case REQUEST_LIST:
+ case REQUEST_EXTENSIONS:
+ return (memberValue.length === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || TBS_REQUEST$1),
+ value: [
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [new Integer({ name: (names.TBSRequestVersion || TBS_REQUEST_VERSION) })]
+ }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: [GeneralName.schema(names.requestorName || {
+ names: {
+ blockName: TBS_REQUEST_REQUESTOR_NAME
+ }
+ })]
+ }),
+ new Sequence({
+ name: (names.requestList || "TBSRequest.requestList"),
+ value: [
+ new Repeated({
+ name: (names.requests || TBS_REQUEST_REQUESTS),
+ value: Request.schema(names.requestNames || {})
+ })
+ ]
+ }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ },
+ value: [Extensions.schema(names.extensions || {
+ names: {
+ blockName: (names.requestExtensions || TBS_REQUEST_REQUEST_EXTENSIONS)
+ }
+ })]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$9);
+ const asn1 = compareSchema(schema, schema, TBSRequest.schema());
+ AsnError.assertSchema(asn1, this.className);
+ this.tbsView = asn1.result.TBSRequest.valueBeforeDecodeView;
+ if (TBS_REQUEST_VERSION in asn1.result)
+ this.version = asn1.result[TBS_REQUEST_VERSION].valueBlock.valueDec;
+ if (TBS_REQUEST_REQUESTOR_NAME in asn1.result)
+ this.requestorName = new GeneralName({ schema: asn1.result[TBS_REQUEST_REQUESTOR_NAME] });
+ this.requestList = Array.from(asn1.result[TBS_REQUEST_REQUESTS], element => new Request({ schema: element }));
+ if (TBS_REQUEST_REQUEST_EXTENSIONS in asn1.result)
+ this.requestExtensions = Array.from(asn1.result[TBS_REQUEST_REQUEST_EXTENSIONS].valueBlock.value, element => new Extension({ schema: element }));
+ }
+ toSchema(encodeFlag = false) {
+ let tbsSchema;
+ if (encodeFlag === false) {
+ if (this.tbsView.byteLength === 0)
+ return TBSRequest.schema();
+ const asn1 = fromBER(this.tbsView);
+ AsnError.assert(asn1, "TBS Request");
+ if (!(asn1.result instanceof Sequence)) {
+ throw new Error("ASN.1 result should be SEQUENCE");
+ }
+ tbsSchema = asn1.result;
+ }
+ else {
+ const outputArray = [];
+ if (this.version !== undefined) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [new Integer({ value: this.version })]
+ }));
+ }
+ if (this.requestorName) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: [this.requestorName.toSchema()]
+ }));
+ }
+ outputArray.push(new Sequence({
+ value: Array.from(this.requestList, o => o.toSchema())
+ }));
+ if (this.requestExtensions) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 2
+ },
+ value: [
+ new Sequence({
+ value: Array.from(this.requestExtensions, o => o.toSchema())
+ })
+ ]
+ }));
+ }
+ tbsSchema = new Sequence({
+ value: outputArray
+ });
+ }
+ return tbsSchema;
+ }
+ toJSON() {
+ const res = {};
+ if (this.version != undefined)
+ res.version = this.version;
+ if (this.requestorName) {
+ res.requestorName = this.requestorName.toJSON();
+ }
+ res.requestList = Array.from(this.requestList, o => o.toJSON());
+ if (this.requestExtensions) {
+ res.requestExtensions = Array.from(this.requestExtensions, o => o.toJSON());
+ }
+ return res;
+ }
+}
+TBSRequest.CLASS_NAME = "TBSRequest";
+
+const SIGNATURE_ALGORITHM$1 = "signatureAlgorithm";
+const SIGNATURE$1 = "signature";
+const CERTS = "certs";
+class Signature extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.signatureAlgorithm = getParametersValue(parameters, SIGNATURE_ALGORITHM$1, Signature.defaultValues(SIGNATURE_ALGORITHM$1));
+ this.signature = getParametersValue(parameters, SIGNATURE$1, Signature.defaultValues(SIGNATURE$1));
+ if (CERTS in parameters) {
+ this.certs = getParametersValue(parameters, CERTS, Signature.defaultValues(CERTS));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case SIGNATURE_ALGORITHM$1:
+ return new AlgorithmIdentifier();
+ case SIGNATURE$1:
+ return new BitString();
+ case CERTS:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case SIGNATURE_ALGORITHM$1:
+ return ((memberValue.algorithmId === EMPTY_STRING) && (("algorithmParams" in memberValue) === false));
+ case SIGNATURE$1:
+ return (memberValue.isEqual(Signature.defaultValues(memberName)));
+ case CERTS:
+ return (memberValue.length === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ AlgorithmIdentifier.schema(names.signatureAlgorithm || {}),
+ new BitString({ name: (names.signature || EMPTY_STRING) }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [
+ new Sequence({
+ value: [new Repeated({
+ name: (names.certs || EMPTY_STRING),
+ value: Certificate.schema({})
+ })]
+ })
+ ]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, [
+ SIGNATURE_ALGORITHM$1,
+ SIGNATURE$1,
+ CERTS
+ ]);
+ const asn1 = compareSchema(schema, schema, Signature.schema({
+ names: {
+ signatureAlgorithm: {
+ names: {
+ blockName: SIGNATURE_ALGORITHM$1
+ }
+ },
+ signature: SIGNATURE$1,
+ certs: CERTS
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.signatureAlgorithm = new AlgorithmIdentifier({ schema: asn1.result.signatureAlgorithm });
+ this.signature = asn1.result.signature;
+ if (CERTS in asn1.result)
+ this.certs = Array.from(asn1.result.certs, element => new Certificate({ schema: element }));
+ }
+ toSchema() {
+ const outputArray = [];
+ outputArray.push(this.signatureAlgorithm.toSchema());
+ outputArray.push(this.signature);
+ if (this.certs) {
+ outputArray.push(new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [
+ new Sequence({
+ value: Array.from(this.certs, o => o.toSchema())
+ })
+ ]
+ }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {
+ signatureAlgorithm: this.signatureAlgorithm.toJSON(),
+ signature: this.signature.toJSON(),
+ };
+ if (this.certs) {
+ res.certs = Array.from(this.certs, o => o.toJSON());
+ }
+ return res;
+ }
+}
+Signature.CLASS_NAME = "Signature";
+
+const TBS_REQUEST = "tbsRequest";
+const OPTIONAL_SIGNATURE = "optionalSignature";
+const CLEAR_PROPS$8 = [
+ TBS_REQUEST,
+ OPTIONAL_SIGNATURE
+];
+class OCSPRequest extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.tbsRequest = getParametersValue(parameters, TBS_REQUEST, OCSPRequest.defaultValues(TBS_REQUEST));
+ if (OPTIONAL_SIGNATURE in parameters) {
+ this.optionalSignature = getParametersValue(parameters, OPTIONAL_SIGNATURE, OCSPRequest.defaultValues(OPTIONAL_SIGNATURE));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case TBS_REQUEST:
+ return new TBSRequest();
+ case OPTIONAL_SIGNATURE:
+ return new Signature();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case TBS_REQUEST:
+ return ((TBSRequest.compareWithDefault("tbs", memberValue.tbs)) &&
+ (TBSRequest.compareWithDefault("version", memberValue.version)) &&
+ (TBSRequest.compareWithDefault("requestorName", memberValue.requestorName)) &&
+ (TBSRequest.compareWithDefault("requestList", memberValue.requestList)) &&
+ (TBSRequest.compareWithDefault("requestExtensions", memberValue.requestExtensions)));
+ case OPTIONAL_SIGNATURE:
+ return ((Signature.compareWithDefault("signatureAlgorithm", memberValue.signatureAlgorithm)) &&
+ (Signature.compareWithDefault("signature", memberValue.signature)) &&
+ (Signature.compareWithDefault("certs", memberValue.certs)));
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: names.blockName || "OCSPRequest",
+ value: [
+ TBSRequest.schema(names.tbsRequest || {
+ names: {
+ blockName: TBS_REQUEST
+ }
+ }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [
+ Signature.schema(names.optionalSignature || {
+ names: {
+ blockName: OPTIONAL_SIGNATURE
+ }
+ })
+ ]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$8);
+ const asn1 = compareSchema(schema, schema, OCSPRequest.schema());
+ AsnError.assertSchema(asn1, this.className);
+ this.tbsRequest = new TBSRequest({ schema: asn1.result.tbsRequest });
+ if (OPTIONAL_SIGNATURE in asn1.result)
+ this.optionalSignature = new Signature({ schema: asn1.result.optionalSignature });
+ }
+ toSchema(encodeFlag = false) {
+ const outputArray = [];
+ outputArray.push(this.tbsRequest.toSchema(encodeFlag));
+ if (this.optionalSignature)
+ outputArray.push(new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [
+ this.optionalSignature.toSchema()
+ ]
+ }));
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {
+ tbsRequest: this.tbsRequest.toJSON()
+ };
+ if (this.optionalSignature) {
+ res.optionalSignature = this.optionalSignature.toJSON();
+ }
+ return res;
+ }
+ createForCertificate(certificate, parameters, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ const certID = new CertID();
+ yield certID.createForCertificate(certificate, parameters, crypto);
+ this.tbsRequest.requestList.push(new Request({
+ reqCert: certID,
+ }));
+ });
+ }
+ sign(privateKey, hashAlgorithm = "SHA-1", crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ ParameterError.assertEmpty(privateKey, "privateKey", "OCSPRequest.sign method");
+ if (!this.optionalSignature) {
+ throw new Error("Need to create \"optionalSignature\" field before signing");
+ }
+ const signatureParams = yield crypto.getSignatureParameters(privateKey, hashAlgorithm);
+ const parameters = signatureParams.parameters;
+ this.optionalSignature.signatureAlgorithm = signatureParams.signatureAlgorithm;
+ const tbs = this.tbsRequest.toSchema(true).toBER(false);
+ const signature = yield crypto.signWithPrivateKey(tbs, privateKey, parameters);
+ this.optionalSignature.signature = new BitString({ valueHex: signature });
+ });
+ }
+ verify() {
+ }
+}
+OCSPRequest.CLASS_NAME = "OCSPRequest";
+
+const RESPONSE_TYPE = "responseType";
+const RESPONSE = "response";
+const CLEAR_PROPS$7 = [
+ RESPONSE_TYPE,
+ RESPONSE
+];
+class ResponseBytes extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.responseType = getParametersValue(parameters, RESPONSE_TYPE, ResponseBytes.defaultValues(RESPONSE_TYPE));
+ this.response = getParametersValue(parameters, RESPONSE, ResponseBytes.defaultValues(RESPONSE));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case RESPONSE_TYPE:
+ return EMPTY_STRING;
+ case RESPONSE:
+ return new OctetString();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case RESPONSE_TYPE:
+ return (memberValue === EMPTY_STRING);
+ case RESPONSE:
+ return (memberValue.isEqual(ResponseBytes.defaultValues(memberName)));
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new ObjectIdentifier({ name: (names.responseType || EMPTY_STRING) }),
+ new OctetString({ name: (names.response || EMPTY_STRING) })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$7);
+ const asn1 = compareSchema(schema, schema, ResponseBytes.schema({
+ names: {
+ responseType: RESPONSE_TYPE,
+ response: RESPONSE
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.responseType = asn1.result.responseType.valueBlock.toString();
+ this.response = asn1.result.response;
+ }
+ toSchema() {
+ return (new Sequence({
+ value: [
+ new ObjectIdentifier({ value: this.responseType }),
+ this.response
+ ]
+ }));
+ }
+ toJSON() {
+ return {
+ responseType: this.responseType,
+ response: this.response.toJSON(),
+ };
+ }
+}
+ResponseBytes.CLASS_NAME = "ResponseBytes";
+
+const RESPONSE_STATUS = "responseStatus";
+const RESPONSE_BYTES = "responseBytes";
+class OCSPResponse extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.responseStatus = getParametersValue(parameters, RESPONSE_STATUS, OCSPResponse.defaultValues(RESPONSE_STATUS));
+ if (RESPONSE_BYTES in parameters) {
+ this.responseBytes = getParametersValue(parameters, RESPONSE_BYTES, OCSPResponse.defaultValues(RESPONSE_BYTES));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case RESPONSE_STATUS:
+ return new Enumerated();
+ case RESPONSE_BYTES:
+ return new ResponseBytes();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case RESPONSE_STATUS:
+ return (memberValue.isEqual(OCSPResponse.defaultValues(memberName)));
+ case RESPONSE_BYTES:
+ return ((ResponseBytes.compareWithDefault("responseType", memberValue.responseType)) &&
+ (ResponseBytes.compareWithDefault("response", memberValue.response)));
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || "OCSPResponse"),
+ value: [
+ new Enumerated({ name: (names.responseStatus || RESPONSE_STATUS) }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [
+ ResponseBytes.schema(names.responseBytes || {
+ names: {
+ blockName: RESPONSE_BYTES
+ }
+ })
+ ]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, [
+ RESPONSE_STATUS,
+ RESPONSE_BYTES
+ ]);
+ const asn1 = compareSchema(schema, schema, OCSPResponse.schema());
+ AsnError.assertSchema(asn1, this.className);
+ this.responseStatus = asn1.result.responseStatus;
+ if (RESPONSE_BYTES in asn1.result)
+ this.responseBytes = new ResponseBytes({ schema: asn1.result.responseBytes });
+ }
+ toSchema() {
+ const outputArray = [];
+ outputArray.push(this.responseStatus);
+ if (this.responseBytes) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [this.responseBytes.toSchema()]
+ }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {
+ responseStatus: this.responseStatus.toJSON()
+ };
+ if (this.responseBytes) {
+ res.responseBytes = this.responseBytes.toJSON();
+ }
+ return res;
+ }
+ getCertificateStatus(certificate, issuerCertificate, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ let basicResponse;
+ const result = {
+ isForCertificate: false,
+ status: 2
+ };
+ if (!this.responseBytes)
+ return result;
+ if (this.responseBytes.responseType !== id_PKIX_OCSP_Basic)
+ return result;
+ try {
+ const asn1Basic = fromBER(this.responseBytes.response.valueBlock.valueHexView);
+ AsnError.assert(asn1Basic, "Basic OCSP response");
+ basicResponse = new BasicOCSPResponse({ schema: asn1Basic.result });
+ }
+ catch (ex) {
+ return result;
+ }
+ return basicResponse.getCertificateStatus(certificate, issuerCertificate, crypto);
+ });
+ }
+ sign(privateKey, hashAlgorithm, crypto = getCrypto(true)) {
+ var _a;
+ return __awaiter(this, void 0, void 0, function* () {
+ if (this.responseBytes && this.responseBytes.responseType === id_PKIX_OCSP_Basic) {
+ const basicResponse = BasicOCSPResponse.fromBER(this.responseBytes.response.valueBlock.valueHexView);
+ return basicResponse.sign(privateKey, hashAlgorithm, crypto);
+ }
+ throw new Error(`Unknown ResponseBytes type: ${((_a = this.responseBytes) === null || _a === void 0 ? void 0 : _a.responseType) || "Unknown"}`);
+ });
+ }
+ verify(issuerCertificate = null, crypto = getCrypto(true)) {
+ var _a;
+ return __awaiter(this, void 0, void 0, function* () {
+ if ((RESPONSE_BYTES in this) === false)
+ throw new Error("Empty ResponseBytes field");
+ if (this.responseBytes && this.responseBytes.responseType === id_PKIX_OCSP_Basic) {
+ const basicResponse = BasicOCSPResponse.fromBER(this.responseBytes.response.valueBlock.valueHexView);
+ if (issuerCertificate !== null) {
+ if (!basicResponse.certs) {
+ basicResponse.certs = [];
+ }
+ basicResponse.certs.push(issuerCertificate);
+ }
+ return basicResponse.verify({}, crypto);
+ }
+ throw new Error(`Unknown ResponseBytes type: ${((_a = this.responseBytes) === null || _a === void 0 ? void 0 : _a.responseType) || "Unknown"}`);
+ });
+ }
+}
+OCSPResponse.CLASS_NAME = "OCSPResponse";
+
+const TYPE = "type";
+const ATTRIBUTES = "attributes";
+const ENCODED_VALUE = "encodedValue";
+const CLEAR_PROPS$6 = [
+ ATTRIBUTES
+];
+class SignedAndUnsignedAttributes extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.type = getParametersValue(parameters, TYPE, SignedAndUnsignedAttributes.defaultValues(TYPE));
+ this.attributes = getParametersValue(parameters, ATTRIBUTES, SignedAndUnsignedAttributes.defaultValues(ATTRIBUTES));
+ this.encodedValue = getParametersValue(parameters, ENCODED_VALUE, SignedAndUnsignedAttributes.defaultValues(ENCODED_VALUE));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case TYPE:
+ return (-1);
+ case ATTRIBUTES:
+ return [];
+ case ENCODED_VALUE:
+ return EMPTY_BUFFER;
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case TYPE:
+ return (memberValue === SignedAndUnsignedAttributes.defaultValues(TYPE));
+ case ATTRIBUTES:
+ return (memberValue.length === 0);
+ case ENCODED_VALUE:
+ return (memberValue.byteLength === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Constructed({
+ name: (names.blockName || EMPTY_STRING),
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: names.tagNumber || 0
+ },
+ value: [
+ new Repeated({
+ name: (names.attributes || EMPTY_STRING),
+ value: Attribute.schema()
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$6);
+ const asn1 = compareSchema(schema, schema, SignedAndUnsignedAttributes.schema({
+ names: {
+ tagNumber: this.type,
+ attributes: ATTRIBUTES
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.type = asn1.result.idBlock.tagNumber;
+ this.encodedValue = BufferSourceConverter.toArrayBuffer(asn1.result.valueBeforeDecodeView);
+ const encodedView = new Uint8Array(this.encodedValue);
+ encodedView[0] = 0x31;
+ if ((ATTRIBUTES in asn1.result) === false) {
+ if (this.type === 0)
+ throw new Error("Wrong structure of SignedUnsignedAttributes");
+ else
+ return;
+ }
+ this.attributes = Array.from(asn1.result.attributes, element => new Attribute({ schema: element }));
+ }
+ toSchema() {
+ if (SignedAndUnsignedAttributes.compareWithDefault(TYPE, this.type) || SignedAndUnsignedAttributes.compareWithDefault(ATTRIBUTES, this.attributes))
+ throw new Error("Incorrectly initialized \"SignedAndUnsignedAttributes\" class");
+ return (new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: this.type
+ },
+ value: Array.from(this.attributes, o => o.toSchema())
+ }));
+ }
+ toJSON() {
+ if (SignedAndUnsignedAttributes.compareWithDefault(TYPE, this.type) || SignedAndUnsignedAttributes.compareWithDefault(ATTRIBUTES, this.attributes))
+ throw new Error("Incorrectly initialized \"SignedAndUnsignedAttributes\" class");
+ return {
+ type: this.type,
+ attributes: Array.from(this.attributes, o => o.toJSON())
+ };
+ }
+}
+SignedAndUnsignedAttributes.CLASS_NAME = "SignedAndUnsignedAttributes";
+
+const VERSION$4 = "version";
+const SID = "sid";
+const DIGEST_ALGORITHM = "digestAlgorithm";
+const SIGNED_ATTRS = "signedAttrs";
+const SIGNATURE_ALGORITHM = "signatureAlgorithm";
+const SIGNATURE = "signature";
+const UNSIGNED_ATTRS = "unsignedAttrs";
+const SIGNER_INFO = "SignerInfo";
+const SIGNER_INFO_VERSION = `${SIGNER_INFO}.${VERSION$4}`;
+const SIGNER_INFO_SID = `${SIGNER_INFO}.${SID}`;
+const SIGNER_INFO_DIGEST_ALGORITHM = `${SIGNER_INFO}.${DIGEST_ALGORITHM}`;
+const SIGNER_INFO_SIGNED_ATTRS = `${SIGNER_INFO}.${SIGNED_ATTRS}`;
+const SIGNER_INFO_SIGNATURE_ALGORITHM = `${SIGNER_INFO}.${SIGNATURE_ALGORITHM}`;
+const SIGNER_INFO_SIGNATURE = `${SIGNER_INFO}.${SIGNATURE}`;
+const SIGNER_INFO_UNSIGNED_ATTRS = `${SIGNER_INFO}.${UNSIGNED_ATTRS}`;
+const CLEAR_PROPS$5 = [
+ SIGNER_INFO_VERSION,
+ SIGNER_INFO_SID,
+ SIGNER_INFO_DIGEST_ALGORITHM,
+ SIGNER_INFO_SIGNED_ATTRS,
+ SIGNER_INFO_SIGNATURE_ALGORITHM,
+ SIGNER_INFO_SIGNATURE,
+ SIGNER_INFO_UNSIGNED_ATTRS
+];
+class SignerInfo extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.version = getParametersValue(parameters, VERSION$4, SignerInfo.defaultValues(VERSION$4));
+ this.sid = getParametersValue(parameters, SID, SignerInfo.defaultValues(SID));
+ this.digestAlgorithm = getParametersValue(parameters, DIGEST_ALGORITHM, SignerInfo.defaultValues(DIGEST_ALGORITHM));
+ if (SIGNED_ATTRS in parameters) {
+ this.signedAttrs = getParametersValue(parameters, SIGNED_ATTRS, SignerInfo.defaultValues(SIGNED_ATTRS));
+ }
+ this.signatureAlgorithm = getParametersValue(parameters, SIGNATURE_ALGORITHM, SignerInfo.defaultValues(SIGNATURE_ALGORITHM));
+ this.signature = getParametersValue(parameters, SIGNATURE, SignerInfo.defaultValues(SIGNATURE));
+ if (UNSIGNED_ATTRS in parameters) {
+ this.unsignedAttrs = getParametersValue(parameters, UNSIGNED_ATTRS, SignerInfo.defaultValues(UNSIGNED_ATTRS));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case VERSION$4:
+ return 0;
+ case SID:
+ return new Any();
+ case DIGEST_ALGORITHM:
+ return new AlgorithmIdentifier();
+ case SIGNED_ATTRS:
+ return new SignedAndUnsignedAttributes({ type: 0 });
+ case SIGNATURE_ALGORITHM:
+ return new AlgorithmIdentifier();
+ case SIGNATURE:
+ return new OctetString();
+ case UNSIGNED_ATTRS:
+ return new SignedAndUnsignedAttributes({ type: 1 });
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case VERSION$4:
+ return (SignerInfo.defaultValues(VERSION$4) === memberValue);
+ case SID:
+ return (memberValue instanceof Any);
+ case DIGEST_ALGORITHM:
+ if ((memberValue instanceof AlgorithmIdentifier) === false)
+ return false;
+ return memberValue.isEqual(SignerInfo.defaultValues(DIGEST_ALGORITHM));
+ case SIGNED_ATTRS:
+ return ((SignedAndUnsignedAttributes.compareWithDefault("type", memberValue.type))
+ && (SignedAndUnsignedAttributes.compareWithDefault("attributes", memberValue.attributes))
+ && (SignedAndUnsignedAttributes.compareWithDefault("encodedValue", memberValue.encodedValue)));
+ case SIGNATURE_ALGORITHM:
+ if ((memberValue instanceof AlgorithmIdentifier) === false)
+ return false;
+ return memberValue.isEqual(SignerInfo.defaultValues(SIGNATURE_ALGORITHM));
+ case SIGNATURE:
+ case UNSIGNED_ATTRS:
+ return ((SignedAndUnsignedAttributes.compareWithDefault("type", memberValue.type))
+ && (SignedAndUnsignedAttributes.compareWithDefault("attributes", memberValue.attributes))
+ && (SignedAndUnsignedAttributes.compareWithDefault("encodedValue", memberValue.encodedValue)));
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: SIGNER_INFO,
+ value: [
+ new Integer({ name: (names.version || SIGNER_INFO_VERSION) }),
+ new Choice({
+ value: [
+ IssuerAndSerialNumber.schema(names.sidSchema || {
+ names: {
+ blockName: SIGNER_INFO_SID
+ }
+ }),
+ new Choice({
+ value: [
+ new Constructed({
+ optional: true,
+ name: (names.sid || SIGNER_INFO_SID),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [new OctetString()]
+ }),
+ new Primitive({
+ optional: true,
+ name: (names.sid || SIGNER_INFO_SID),
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ }
+ }),
+ ]
+ }),
+ ]
+ }),
+ AlgorithmIdentifier.schema(names.digestAlgorithm || {
+ names: {
+ blockName: SIGNER_INFO_DIGEST_ALGORITHM
+ }
+ }),
+ SignedAndUnsignedAttributes.schema(names.signedAttrs || {
+ names: {
+ blockName: SIGNER_INFO_SIGNED_ATTRS,
+ tagNumber: 0
+ }
+ }),
+ AlgorithmIdentifier.schema(names.signatureAlgorithm || {
+ names: {
+ blockName: SIGNER_INFO_SIGNATURE_ALGORITHM
+ }
+ }),
+ new OctetString({ name: (names.signature || SIGNER_INFO_SIGNATURE) }),
+ SignedAndUnsignedAttributes.schema(names.unsignedAttrs || {
+ names: {
+ blockName: SIGNER_INFO_UNSIGNED_ATTRS,
+ tagNumber: 1
+ }
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$5);
+ const asn1 = compareSchema(schema, schema, SignerInfo.schema());
+ AsnError.assertSchema(asn1, this.className);
+ this.version = asn1.result[SIGNER_INFO_VERSION].valueBlock.valueDec;
+ const currentSid = asn1.result[SIGNER_INFO_SID];
+ if (currentSid.idBlock.tagClass === 1)
+ this.sid = new IssuerAndSerialNumber({ schema: currentSid });
+ else
+ this.sid = currentSid;
+ this.digestAlgorithm = new AlgorithmIdentifier({ schema: asn1.result[SIGNER_INFO_DIGEST_ALGORITHM] });
+ if (SIGNER_INFO_SIGNED_ATTRS in asn1.result)
+ this.signedAttrs = new SignedAndUnsignedAttributes({ type: 0, schema: asn1.result[SIGNER_INFO_SIGNED_ATTRS] });
+ this.signatureAlgorithm = new AlgorithmIdentifier({ schema: asn1.result[SIGNER_INFO_SIGNATURE_ALGORITHM] });
+ this.signature = asn1.result[SIGNER_INFO_SIGNATURE];
+ if (SIGNER_INFO_UNSIGNED_ATTRS in asn1.result)
+ this.unsignedAttrs = new SignedAndUnsignedAttributes({ type: 1, schema: asn1.result[SIGNER_INFO_UNSIGNED_ATTRS] });
+ }
+ toSchema() {
+ if (SignerInfo.compareWithDefault(SID, this.sid))
+ throw new Error("Incorrectly initialized \"SignerInfo\" class");
+ const outputArray = [];
+ outputArray.push(new Integer({ value: this.version }));
+ if (this.sid instanceof IssuerAndSerialNumber)
+ outputArray.push(this.sid.toSchema());
+ else
+ outputArray.push(this.sid);
+ outputArray.push(this.digestAlgorithm.toSchema());
+ if (this.signedAttrs) {
+ if (SignerInfo.compareWithDefault(SIGNED_ATTRS, this.signedAttrs) === false)
+ outputArray.push(this.signedAttrs.toSchema());
+ }
+ outputArray.push(this.signatureAlgorithm.toSchema());
+ outputArray.push(this.signature);
+ if (this.unsignedAttrs) {
+ if (SignerInfo.compareWithDefault(UNSIGNED_ATTRS, this.unsignedAttrs) === false)
+ outputArray.push(this.unsignedAttrs.toSchema());
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ if (SignerInfo.compareWithDefault(SID, this.sid)) {
+ throw new Error("Incorrectly initialized \"SignerInfo\" class");
+ }
+ const res = {
+ version: this.version,
+ digestAlgorithm: this.digestAlgorithm.toJSON(),
+ signatureAlgorithm: this.signatureAlgorithm.toJSON(),
+ signature: this.signature.toJSON(),
+ };
+ if (!(this.sid instanceof Any))
+ res.sid = this.sid.toJSON();
+ if (this.signedAttrs && SignerInfo.compareWithDefault(SIGNED_ATTRS, this.signedAttrs) === false) {
+ res.signedAttrs = this.signedAttrs.toJSON();
+ }
+ if (this.unsignedAttrs && SignerInfo.compareWithDefault(UNSIGNED_ATTRS, this.unsignedAttrs) === false) {
+ res.unsignedAttrs = this.unsignedAttrs.toJSON();
+ }
+ return res;
+ }
+}
+SignerInfo.CLASS_NAME = "SignerInfo";
+
+const VERSION$3 = "version";
+const POLICY = "policy";
+const MESSAGE_IMPRINT$1 = "messageImprint";
+const SERIAL_NUMBER = "serialNumber";
+const GEN_TIME = "genTime";
+const ORDERING = "ordering";
+const NONCE$1 = "nonce";
+const ACCURACY = "accuracy";
+const TSA = "tsa";
+const EXTENSIONS$1 = "extensions";
+const TST_INFO = "TSTInfo";
+const TST_INFO_VERSION = `${TST_INFO}.${VERSION$3}`;
+const TST_INFO_POLICY = `${TST_INFO}.${POLICY}`;
+const TST_INFO_MESSAGE_IMPRINT = `${TST_INFO}.${MESSAGE_IMPRINT$1}`;
+const TST_INFO_SERIAL_NUMBER = `${TST_INFO}.${SERIAL_NUMBER}`;
+const TST_INFO_GEN_TIME = `${TST_INFO}.${GEN_TIME}`;
+const TST_INFO_ACCURACY = `${TST_INFO}.${ACCURACY}`;
+const TST_INFO_ORDERING = `${TST_INFO}.${ORDERING}`;
+const TST_INFO_NONCE = `${TST_INFO}.${NONCE$1}`;
+const TST_INFO_TSA = `${TST_INFO}.${TSA}`;
+const TST_INFO_EXTENSIONS = `${TST_INFO}.${EXTENSIONS$1}`;
+const CLEAR_PROPS$4 = [
+ TST_INFO_VERSION,
+ TST_INFO_POLICY,
+ TST_INFO_MESSAGE_IMPRINT,
+ TST_INFO_SERIAL_NUMBER,
+ TST_INFO_GEN_TIME,
+ TST_INFO_ACCURACY,
+ TST_INFO_ORDERING,
+ TST_INFO_NONCE,
+ TST_INFO_TSA,
+ TST_INFO_EXTENSIONS
+];
+class TSTInfo extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.version = getParametersValue(parameters, VERSION$3, TSTInfo.defaultValues(VERSION$3));
+ this.policy = getParametersValue(parameters, POLICY, TSTInfo.defaultValues(POLICY));
+ this.messageImprint = getParametersValue(parameters, MESSAGE_IMPRINT$1, TSTInfo.defaultValues(MESSAGE_IMPRINT$1));
+ this.serialNumber = getParametersValue(parameters, SERIAL_NUMBER, TSTInfo.defaultValues(SERIAL_NUMBER));
+ this.genTime = getParametersValue(parameters, GEN_TIME, TSTInfo.defaultValues(GEN_TIME));
+ if (ACCURACY in parameters) {
+ this.accuracy = getParametersValue(parameters, ACCURACY, TSTInfo.defaultValues(ACCURACY));
+ }
+ if (ORDERING in parameters) {
+ this.ordering = getParametersValue(parameters, ORDERING, TSTInfo.defaultValues(ORDERING));
+ }
+ if (NONCE$1 in parameters) {
+ this.nonce = getParametersValue(parameters, NONCE$1, TSTInfo.defaultValues(NONCE$1));
+ }
+ if (TSA in parameters) {
+ this.tsa = getParametersValue(parameters, TSA, TSTInfo.defaultValues(TSA));
+ }
+ if (EXTENSIONS$1 in parameters) {
+ this.extensions = getParametersValue(parameters, EXTENSIONS$1, TSTInfo.defaultValues(EXTENSIONS$1));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case VERSION$3:
+ return 0;
+ case POLICY:
+ return EMPTY_STRING;
+ case MESSAGE_IMPRINT$1:
+ return new MessageImprint();
+ case SERIAL_NUMBER:
+ return new Integer();
+ case GEN_TIME:
+ return new Date(0, 0, 0);
+ case ACCURACY:
+ return new Accuracy();
+ case ORDERING:
+ return false;
+ case NONCE$1:
+ return new Integer();
+ case TSA:
+ return new GeneralName();
+ case EXTENSIONS$1:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case VERSION$3:
+ case POLICY:
+ case GEN_TIME:
+ case ORDERING:
+ return (memberValue === TSTInfo.defaultValues(ORDERING));
+ case MESSAGE_IMPRINT$1:
+ return ((MessageImprint.compareWithDefault(HASH_ALGORITHM, memberValue.hashAlgorithm)) &&
+ (MessageImprint.compareWithDefault(HASHED_MESSAGE, memberValue.hashedMessage)));
+ case SERIAL_NUMBER:
+ case NONCE$1:
+ return (memberValue.isEqual(TSTInfo.defaultValues(NONCE$1)));
+ case ACCURACY:
+ return ((Accuracy.compareWithDefault(SECONDS, memberValue.seconds)) &&
+ (Accuracy.compareWithDefault(MILLIS, memberValue.millis)) &&
+ (Accuracy.compareWithDefault(MICROS, memberValue.micros)));
+ case TSA:
+ return ((GeneralName.compareWithDefault(TYPE$4, memberValue.type)) &&
+ (GeneralName.compareWithDefault(VALUE$5, memberValue.value)));
+ case EXTENSIONS$1:
+ return (memberValue.length === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || TST_INFO),
+ value: [
+ new Integer({ name: (names.version || TST_INFO_VERSION) }),
+ new ObjectIdentifier({ name: (names.policy || TST_INFO_POLICY) }),
+ MessageImprint.schema(names.messageImprint || {
+ names: {
+ blockName: TST_INFO_MESSAGE_IMPRINT
+ }
+ }),
+ new Integer({ name: (names.serialNumber || TST_INFO_SERIAL_NUMBER) }),
+ new GeneralizedTime({ name: (names.genTime || TST_INFO_GEN_TIME) }),
+ Accuracy.schema(names.accuracy || {
+ names: {
+ blockName: TST_INFO_ACCURACY
+ }
+ }),
+ new Boolean({
+ name: (names.ordering || TST_INFO_ORDERING),
+ optional: true
+ }),
+ new Integer({
+ name: (names.nonce || TST_INFO_NONCE),
+ optional: true
+ }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [GeneralName.schema(names.tsa || {
+ names: {
+ blockName: TST_INFO_TSA
+ }
+ })]
+ }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: [
+ new Repeated({
+ name: (names.extensions || TST_INFO_EXTENSIONS),
+ value: Extension.schema(names.extension || {})
+ })
+ ]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$4);
+ const asn1 = compareSchema(schema, schema, TSTInfo.schema());
+ AsnError.assertSchema(asn1, this.className);
+ this.version = asn1.result[TST_INFO_VERSION].valueBlock.valueDec;
+ this.policy = asn1.result[TST_INFO_POLICY].valueBlock.toString();
+ this.messageImprint = new MessageImprint({ schema: asn1.result[TST_INFO_MESSAGE_IMPRINT] });
+ this.serialNumber = asn1.result[TST_INFO_SERIAL_NUMBER];
+ this.genTime = asn1.result[TST_INFO_GEN_TIME].toDate();
+ if (TST_INFO_ACCURACY in asn1.result)
+ this.accuracy = new Accuracy({ schema: asn1.result[TST_INFO_ACCURACY] });
+ if (TST_INFO_ORDERING in asn1.result)
+ this.ordering = asn1.result[TST_INFO_ORDERING].valueBlock.value;
+ if (TST_INFO_NONCE in asn1.result)
+ this.nonce = asn1.result[TST_INFO_NONCE];
+ if (TST_INFO_TSA in asn1.result)
+ this.tsa = new GeneralName({ schema: asn1.result[TST_INFO_TSA] });
+ if (TST_INFO_EXTENSIONS in asn1.result)
+ this.extensions = Array.from(asn1.result[TST_INFO_EXTENSIONS], element => new Extension({ schema: element }));
+ }
+ toSchema() {
+ const outputArray = [];
+ outputArray.push(new Integer({ value: this.version }));
+ outputArray.push(new ObjectIdentifier({ value: this.policy }));
+ outputArray.push(this.messageImprint.toSchema());
+ outputArray.push(this.serialNumber);
+ outputArray.push(new GeneralizedTime({ valueDate: this.genTime }));
+ if (this.accuracy)
+ outputArray.push(this.accuracy.toSchema());
+ if (this.ordering !== undefined)
+ outputArray.push(new Boolean({ value: this.ordering }));
+ if (this.nonce)
+ outputArray.push(this.nonce);
+ if (this.tsa) {
+ outputArray.push(new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [this.tsa.toSchema()]
+ }));
+ }
+ if (this.extensions) {
+ outputArray.push(new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: Array.from(this.extensions, o => o.toSchema())
+ }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {
+ version: this.version,
+ policy: this.policy,
+ messageImprint: this.messageImprint.toJSON(),
+ serialNumber: this.serialNumber.toJSON(),
+ genTime: this.genTime
+ };
+ if (this.accuracy)
+ res.accuracy = this.accuracy.toJSON();
+ if (this.ordering !== undefined)
+ res.ordering = this.ordering;
+ if (this.nonce)
+ res.nonce = this.nonce.toJSON();
+ if (this.tsa)
+ res.tsa = this.tsa.toJSON();
+ if (this.extensions)
+ res.extensions = Array.from(this.extensions, o => o.toJSON());
+ return res;
+ }
+ verify(params, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ if (!params.data) {
+ throw new Error("\"data\" is a mandatory attribute for TST_INFO verification");
+ }
+ const data = params.data;
+ if (params.notBefore) {
+ if (this.genTime < params.notBefore)
+ throw new Error("Generation time for TSTInfo object is less than notBefore value");
+ }
+ if (params.notAfter) {
+ if (this.genTime > params.notAfter)
+ throw new Error("Generation time for TSTInfo object is more than notAfter value");
+ }
+ const shaAlgorithm = crypto.getAlgorithmByOID(this.messageImprint.hashAlgorithm.algorithmId, true, "MessageImprint.hashAlgorithm");
+ const hash = yield crypto.digest(shaAlgorithm.name, new Uint8Array(data));
+ return BufferSourceConverter.isEqual(hash, this.messageImprint.hashedMessage.valueBlock.valueHexView);
+ });
+ }
+}
+TSTInfo.CLASS_NAME = "TSTInfo";
+
+const VERSION$2 = "version";
+const DIGEST_ALGORITHMS = "digestAlgorithms";
+const ENCAP_CONTENT_INFO = "encapContentInfo";
+const CERTIFICATES = "certificates";
+const CRLS = "crls";
+const SIGNER_INFOS = "signerInfos";
+const OCSPS = "ocsps";
+const SIGNED_DATA = "SignedData";
+const SIGNED_DATA_VERSION = `${SIGNED_DATA}.${VERSION$2}`;
+const SIGNED_DATA_DIGEST_ALGORITHMS = `${SIGNED_DATA}.${DIGEST_ALGORITHMS}`;
+const SIGNED_DATA_ENCAP_CONTENT_INFO = `${SIGNED_DATA}.${ENCAP_CONTENT_INFO}`;
+const SIGNED_DATA_CERTIFICATES = `${SIGNED_DATA}.${CERTIFICATES}`;
+const SIGNED_DATA_CRLS = `${SIGNED_DATA}.${CRLS}`;
+const SIGNED_DATA_SIGNER_INFOS = `${SIGNED_DATA}.${SIGNER_INFOS}`;
+const CLEAR_PROPS$3 = [
+ SIGNED_DATA_VERSION,
+ SIGNED_DATA_DIGEST_ALGORITHMS,
+ SIGNED_DATA_ENCAP_CONTENT_INFO,
+ SIGNED_DATA_CERTIFICATES,
+ SIGNED_DATA_CRLS,
+ SIGNED_DATA_SIGNER_INFOS
+];
+class SignedDataVerifyError extends Error {
+ constructor({ message, code = 0, date = new Date(), signatureVerified = null, signerCertificate = null, signerCertificateVerified = null, timestampSerial = null, certificatePath = [], }) {
+ super(message);
+ this.name = "SignedDataVerifyError";
+ this.date = date;
+ this.code = code;
+ this.timestampSerial = timestampSerial;
+ this.signatureVerified = signatureVerified;
+ this.signerCertificate = signerCertificate;
+ this.signerCertificateVerified = signerCertificateVerified;
+ this.certificatePath = certificatePath;
+ }
+}
+class SignedData extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.version = getParametersValue(parameters, VERSION$2, SignedData.defaultValues(VERSION$2));
+ this.digestAlgorithms = getParametersValue(parameters, DIGEST_ALGORITHMS, SignedData.defaultValues(DIGEST_ALGORITHMS));
+ this.encapContentInfo = getParametersValue(parameters, ENCAP_CONTENT_INFO, SignedData.defaultValues(ENCAP_CONTENT_INFO));
+ if (CERTIFICATES in parameters) {
+ this.certificates = getParametersValue(parameters, CERTIFICATES, SignedData.defaultValues(CERTIFICATES));
+ }
+ if (CRLS in parameters) {
+ this.crls = getParametersValue(parameters, CRLS, SignedData.defaultValues(CRLS));
+ }
+ if (OCSPS in parameters) {
+ this.ocsps = getParametersValue(parameters, OCSPS, SignedData.defaultValues(OCSPS));
+ }
+ this.signerInfos = getParametersValue(parameters, SIGNER_INFOS, SignedData.defaultValues(SIGNER_INFOS));
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case VERSION$2:
+ return 0;
+ case DIGEST_ALGORITHMS:
+ return [];
+ case ENCAP_CONTENT_INFO:
+ return new EncapsulatedContentInfo();
+ case CERTIFICATES:
+ return [];
+ case CRLS:
+ return [];
+ case OCSPS:
+ return [];
+ case SIGNER_INFOS:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case VERSION$2:
+ return (memberValue === SignedData.defaultValues(VERSION$2));
+ case ENCAP_CONTENT_INFO:
+ return EncapsulatedContentInfo.compareWithDefault("eContentType", memberValue.eContentType) &&
+ EncapsulatedContentInfo.compareWithDefault("eContent", memberValue.eContent);
+ case DIGEST_ALGORITHMS:
+ case CERTIFICATES:
+ case CRLS:
+ case OCSPS:
+ case SIGNER_INFOS:
+ return (memberValue.length === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ if (names.optional === undefined) {
+ names.optional = false;
+ }
+ return (new Sequence({
+ name: (names.blockName || SIGNED_DATA),
+ optional: names.optional,
+ value: [
+ new Integer({ name: (names.version || SIGNED_DATA_VERSION) }),
+ new Set({
+ value: [
+ new Repeated({
+ name: (names.digestAlgorithms || SIGNED_DATA_DIGEST_ALGORITHMS),
+ value: AlgorithmIdentifier.schema()
+ })
+ ]
+ }),
+ EncapsulatedContentInfo.schema(names.encapContentInfo || {
+ names: {
+ blockName: SIGNED_DATA_ENCAP_CONTENT_INFO
+ }
+ }),
+ new Constructed({
+ name: (names.certificates || SIGNED_DATA_CERTIFICATES),
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: CertificateSet.schema().valueBlock.value
+ }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: RevocationInfoChoices.schema(names.crls || {
+ names: {
+ crls: SIGNED_DATA_CRLS
+ }
+ }).valueBlock.value
+ }),
+ new Set({
+ value: [
+ new Repeated({
+ name: (names.signerInfos || SIGNED_DATA_SIGNER_INFOS),
+ value: SignerInfo.schema()
+ })
+ ]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$3);
+ const asn1 = compareSchema(schema, schema, SignedData.schema());
+ AsnError.assertSchema(asn1, this.className);
+ this.version = asn1.result[SIGNED_DATA_VERSION].valueBlock.valueDec;
+ if (SIGNED_DATA_DIGEST_ALGORITHMS in asn1.result)
+ this.digestAlgorithms = Array.from(asn1.result[SIGNED_DATA_DIGEST_ALGORITHMS], algorithm => new AlgorithmIdentifier({ schema: algorithm }));
+ this.encapContentInfo = new EncapsulatedContentInfo({ schema: asn1.result[SIGNED_DATA_ENCAP_CONTENT_INFO] });
+ if (SIGNED_DATA_CERTIFICATES in asn1.result) {
+ const certificateSet = new CertificateSet({
+ schema: new Set({
+ value: asn1.result[SIGNED_DATA_CERTIFICATES].valueBlock.value
+ })
+ });
+ this.certificates = certificateSet.certificates.slice(0);
+ }
+ if (SIGNED_DATA_CRLS in asn1.result) {
+ this.crls = Array.from(asn1.result[SIGNED_DATA_CRLS], (crl) => {
+ if (crl.idBlock.tagClass === 1)
+ return new CertificateRevocationList({ schema: crl });
+ crl.idBlock.tagClass = 1;
+ crl.idBlock.tagNumber = 16;
+ return new OtherRevocationInfoFormat({ schema: crl });
+ });
+ }
+ if (SIGNED_DATA_SIGNER_INFOS in asn1.result)
+ this.signerInfos = Array.from(asn1.result[SIGNED_DATA_SIGNER_INFOS], signerInfoSchema => new SignerInfo({ schema: signerInfoSchema }));
+ }
+ toSchema(encodeFlag = false) {
+ const outputArray = [];
+ if ((this.certificates && this.certificates.length && this.certificates.some(o => o instanceof OtherCertificateFormat))
+ || (this.crls && this.crls.length && this.crls.some(o => o instanceof OtherRevocationInfoFormat))) {
+ this.version = 5;
+ }
+ else if (this.certificates && this.certificates.length && this.certificates.some(o => o instanceof AttributeCertificateV2)) {
+ this.version = 4;
+ }
+ else if ((this.certificates && this.certificates.length && this.certificates.some(o => o instanceof AttributeCertificateV1))
+ || this.signerInfos.some(o => o.version === 3)
+ || this.encapContentInfo.eContentType !== SignedData.ID_DATA) {
+ this.version = 3;
+ }
+ else {
+ this.version = 1;
+ }
+ outputArray.push(new Integer({ value: this.version }));
+ outputArray.push(new Set({
+ value: Array.from(this.digestAlgorithms, algorithm => algorithm.toSchema())
+ }));
+ outputArray.push(this.encapContentInfo.toSchema());
+ if (this.certificates) {
+ const certificateSet = new CertificateSet({ certificates: this.certificates });
+ const certificateSetSchema = certificateSet.toSchema();
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: certificateSetSchema.valueBlock.value
+ }));
+ }
+ if (this.crls) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 1
+ },
+ value: Array.from(this.crls, crl => {
+ if (crl instanceof OtherRevocationInfoFormat) {
+ const crlSchema = crl.toSchema();
+ crlSchema.idBlock.tagClass = 3;
+ crlSchema.idBlock.tagNumber = 1;
+ return crlSchema;
+ }
+ return crl.toSchema(encodeFlag);
+ })
+ }));
+ }
+ outputArray.push(new Set({
+ value: Array.from(this.signerInfos, signerInfo => signerInfo.toSchema())
+ }));
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {
+ version: this.version,
+ digestAlgorithms: Array.from(this.digestAlgorithms, algorithm => algorithm.toJSON()),
+ encapContentInfo: this.encapContentInfo.toJSON(),
+ signerInfos: Array.from(this.signerInfos, signerInfo => signerInfo.toJSON()),
+ };
+ if (this.certificates) {
+ res.certificates = Array.from(this.certificates, certificate => certificate.toJSON());
+ }
+ if (this.crls) {
+ res.crls = Array.from(this.crls, crl => crl.toJSON());
+ }
+ return res;
+ }
+ verify({ signer = (-1), data = (EMPTY_BUFFER), trustedCerts = [], checkDate = (new Date()), checkChain = false, passedWhenNotRevValues = false, extendedMode = false, findOrigin = null, findIssuer = null } = {}, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ let signerCert = null;
+ let timestampSerial = null;
+ try {
+ let messageDigestValue = EMPTY_BUFFER;
+ let shaAlgorithm = EMPTY_STRING;
+ let certificatePath = [];
+ const signerInfo = this.signerInfos[signer];
+ if (!signerInfo) {
+ throw new SignedDataVerifyError({
+ date: checkDate,
+ code: 1,
+ message: "Unable to get signer by supplied index",
+ });
+ }
+ if (!this.certificates) {
+ throw new SignedDataVerifyError({
+ date: checkDate,
+ code: 2,
+ message: "No certificates attached to this signed data",
+ });
+ }
+ if (signerInfo.sid instanceof IssuerAndSerialNumber) {
+ for (const certificate of this.certificates) {
+ if (!(certificate instanceof Certificate))
+ continue;
+ if ((certificate.issuer.isEqual(signerInfo.sid.issuer)) &&
+ (certificate.serialNumber.isEqual(signerInfo.sid.serialNumber))) {
+ signerCert = certificate;
+ break;
+ }
+ }
+ }
+ else {
+ const sid = signerInfo.sid;
+ const keyId = sid.idBlock.isConstructed
+ ? sid.valueBlock.value[0].valueBlock.valueHex
+ : sid.valueBlock.valueHex;
+ for (const certificate of this.certificates) {
+ if (!(certificate instanceof Certificate)) {
+ continue;
+ }
+ const digest = yield crypto.digest({ name: "sha-1" }, certificate.subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHexView);
+ if (isEqualBuffer(digest, keyId)) {
+ signerCert = certificate;
+ break;
+ }
+ }
+ }
+ if (!signerCert) {
+ throw new SignedDataVerifyError({
+ date: checkDate,
+ code: 3,
+ message: "Unable to find signer certificate",
+ });
+ }
+ if (this.encapContentInfo.eContentType === id_eContentType_TSTInfo) {
+ if (!this.encapContentInfo.eContent) {
+ throw new SignedDataVerifyError({
+ date: checkDate,
+ code: 15,
+ message: "Error during verification: TSTInfo eContent is empty",
+ signatureVerified: null,
+ signerCertificate: signerCert,
+ timestampSerial,
+ signerCertificateVerified: true
+ });
+ }
+ let tstInfo;
+ try {
+ tstInfo = TSTInfo.fromBER(this.encapContentInfo.eContent.valueBlock.valueHexView);
+ }
+ catch (ex) {
+ throw new SignedDataVerifyError({
+ date: checkDate,
+ code: 15,
+ message: "Error during verification: TSTInfo wrong ASN.1 schema ",
+ signatureVerified: null,
+ signerCertificate: signerCert,
+ timestampSerial,
+ signerCertificateVerified: true
+ });
+ }
+ checkDate = tstInfo.genTime;
+ timestampSerial = tstInfo.serialNumber.valueBlock.valueHexView.slice();
+ if (data.byteLength === 0) {
+ throw new SignedDataVerifyError({
+ date: checkDate,
+ code: 4,
+ message: "Missed detached data input array",
+ });
+ }
+ if (!(yield tstInfo.verify({ data }, crypto))) {
+ throw new SignedDataVerifyError({
+ date: checkDate,
+ code: 15,
+ message: "Error during verification: TSTInfo verification is failed",
+ signatureVerified: false,
+ signerCertificate: signerCert,
+ timestampSerial,
+ signerCertificateVerified: true
+ });
+ }
+ }
+ if (checkChain) {
+ const certs = this.certificates.filter(certificate => (certificate instanceof Certificate && !!checkCA(certificate, signerCert)));
+ const chainParams = {
+ checkDate,
+ certs,
+ trustedCerts,
+ };
+ if (findIssuer) {
+ chainParams.findIssuer = findIssuer;
+ }
+ if (findOrigin) {
+ chainParams.findOrigin = findOrigin;
+ }
+ const chainEngine = new CertificateChainValidationEngine(chainParams);
+ chainEngine.certs.push(signerCert);
+ if (this.crls) {
+ for (const crl of this.crls) {
+ if ("thisUpdate" in crl)
+ chainEngine.crls.push(crl);
+ else {
+ if (crl.otherRevInfoFormat === id_PKIX_OCSP_Basic)
+ chainEngine.ocsps.push(new BasicOCSPResponse({ schema: crl.otherRevInfo }));
+ }
+ }
+ }
+ if (this.ocsps) {
+ chainEngine.ocsps.push(...(this.ocsps));
+ }
+ const verificationResult = yield chainEngine.verify({ passedWhenNotRevValues }, crypto)
+ .catch(e => {
+ throw new SignedDataVerifyError({
+ date: checkDate,
+ code: 5,
+ message: `Validation of signer's certificate failed with error: ${((e instanceof Object) ? e.resultMessage : e)}`,
+ signerCertificate: signerCert,
+ signerCertificateVerified: false
+ });
+ });
+ if (verificationResult.certificatePath) {
+ certificatePath = verificationResult.certificatePath;
+ }
+ if (!verificationResult.result)
+ throw new SignedDataVerifyError({
+ date: checkDate,
+ code: 5,
+ message: `Validation of signer's certificate failed: ${verificationResult.resultMessage}`,
+ signerCertificate: signerCert,
+ signerCertificateVerified: false
+ });
+ }
+ const signerInfoHashAlgorithm = crypto.getAlgorithmByOID(signerInfo.digestAlgorithm.algorithmId);
+ if (!("name" in signerInfoHashAlgorithm)) {
+ throw new SignedDataVerifyError({
+ date: checkDate,
+ code: 7,
+ message: `Unsupported signature algorithm: ${signerInfo.digestAlgorithm.algorithmId}`,
+ signerCertificate: signerCert,
+ signerCertificateVerified: true
+ });
+ }
+ shaAlgorithm = signerInfoHashAlgorithm.name;
+ const eContent = this.encapContentInfo.eContent;
+ if (eContent) {
+ if ((eContent.idBlock.tagClass === 1) &&
+ (eContent.idBlock.tagNumber === 4)) {
+ data = eContent.getValue();
+ }
+ else
+ data = eContent.valueBlock.valueBeforeDecodeView;
+ }
+ else {
+ if (data.byteLength === 0) {
+ throw new SignedDataVerifyError({
+ date: checkDate,
+ code: 8,
+ message: "Missed detached data input array",
+ signerCertificate: signerCert,
+ signerCertificateVerified: true
+ });
+ }
+ }
+ if (signerInfo.signedAttrs) {
+ let foundContentType = false;
+ let foundMessageDigest = false;
+ for (const attribute of signerInfo.signedAttrs.attributes) {
+ if (attribute.type === "1.2.840.113549.1.9.3")
+ foundContentType = true;
+ if (attribute.type === "1.2.840.113549.1.9.4") {
+ foundMessageDigest = true;
+ messageDigestValue = attribute.values[0].valueBlock.valueHex;
+ }
+ if (foundContentType && foundMessageDigest)
+ break;
+ }
+ if (foundContentType === false) {
+ throw new SignedDataVerifyError({
+ date: checkDate,
+ code: 9,
+ message: "Attribute \"content-type\" is a mandatory attribute for \"signed attributes\"",
+ signerCertificate: signerCert,
+ signerCertificateVerified: true
+ });
+ }
+ if (foundMessageDigest === false) {
+ throw new SignedDataVerifyError({
+ date: checkDate,
+ code: 10,
+ message: "Attribute \"message-digest\" is a mandatory attribute for \"signed attributes\"",
+ signatureVerified: null,
+ signerCertificate: signerCert,
+ signerCertificateVerified: true
+ });
+ }
+ }
+ if (signerInfo.signedAttrs) {
+ const messageDigest = yield crypto.digest(shaAlgorithm, new Uint8Array(data));
+ if (!isEqualBuffer(messageDigest, messageDigestValue)) {
+ throw new SignedDataVerifyError({
+ date: checkDate,
+ code: 15,
+ message: "Error during verification: Message digest doesn't match",
+ signatureVerified: null,
+ signerCertificate: signerCert,
+ timestampSerial,
+ signerCertificateVerified: true
+ });
+ }
+ data = signerInfo.signedAttrs.encodedValue;
+ }
+ const verifyResult = yield crypto.verifyWithPublicKey(data, signerInfo.signature, signerCert.subjectPublicKeyInfo, signerCert.signatureAlgorithm, shaAlgorithm);
+ if (extendedMode) {
+ return {
+ date: checkDate,
+ code: 14,
+ message: EMPTY_STRING,
+ signatureVerified: verifyResult,
+ signerCertificate: signerCert,
+ timestampSerial,
+ signerCertificateVerified: true,
+ certificatePath
+ };
+ }
+ else {
+ return verifyResult;
+ }
+ }
+ catch (e) {
+ if (e instanceof SignedDataVerifyError) {
+ throw e;
+ }
+ throw new SignedDataVerifyError({
+ date: checkDate,
+ code: 15,
+ message: `Error during verification: ${e instanceof Error ? e.message : e}`,
+ signatureVerified: null,
+ signerCertificate: signerCert,
+ timestampSerial,
+ signerCertificateVerified: true
+ });
+ }
+ });
+ }
+ sign(privateKey, signerIndex, hashAlgorithm = "SHA-1", data = (EMPTY_BUFFER), crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ if (!privateKey)
+ throw new Error("Need to provide a private key for signing");
+ const hashAlgorithmOID = crypto.getOIDByAlgorithm({ name: hashAlgorithm }, true, "hashAlgorithm");
+ if ((this.digestAlgorithms.filter(algorithm => algorithm.algorithmId === hashAlgorithmOID)).length === 0) {
+ this.digestAlgorithms.push(new AlgorithmIdentifier({
+ algorithmId: hashAlgorithmOID,
+ algorithmParams: new Null()
+ }));
+ }
+ const signerInfo = this.signerInfos[signerIndex];
+ if (!signerInfo) {
+ throw new RangeError("SignerInfo index is out of range");
+ }
+ signerInfo.digestAlgorithm = new AlgorithmIdentifier({
+ algorithmId: hashAlgorithmOID,
+ algorithmParams: new Null()
+ });
+ const signatureParams = yield crypto.getSignatureParameters(privateKey, hashAlgorithm);
+ const parameters = signatureParams.parameters;
+ signerInfo.signatureAlgorithm = signatureParams.signatureAlgorithm;
+ if (signerInfo.signedAttrs) {
+ if (signerInfo.signedAttrs.encodedValue.byteLength !== 0)
+ data = signerInfo.signedAttrs.encodedValue;
+ else {
+ data = signerInfo.signedAttrs.toSchema().toBER();
+ const view = BufferSourceConverter.toUint8Array(data);
+ view[0] = 0x31;
+ }
+ }
+ else {
+ const eContent = this.encapContentInfo.eContent;
+ if (eContent) {
+ if ((eContent.idBlock.tagClass === 1) &&
+ (eContent.idBlock.tagNumber === 4)) {
+ data = eContent.getValue();
+ }
+ else
+ data = eContent.valueBlock.valueBeforeDecodeView;
+ }
+ else {
+ if (data.byteLength === 0)
+ throw new Error("Missed detached data input array");
+ }
+ }
+ const signature = yield crypto.signWithPrivateKey(data, privateKey, parameters);
+ signerInfo.signature = new OctetString({ valueHex: signature });
+ });
+ }
+}
+SignedData.CLASS_NAME = "SignedData";
+SignedData.ID_DATA = id_ContentType_Data;
+
+const VERSION$1 = "version";
+const AUTH_SAFE = "authSafe";
+const MAC_DATA = "macData";
+const PARSED_VALUE = "parsedValue";
+const CLERA_PROPS = [
+ VERSION$1,
+ AUTH_SAFE,
+ MAC_DATA
+];
+class PFX extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.version = getParametersValue(parameters, VERSION$1, PFX.defaultValues(VERSION$1));
+ this.authSafe = getParametersValue(parameters, AUTH_SAFE, PFX.defaultValues(AUTH_SAFE));
+ if (MAC_DATA in parameters) {
+ this.macData = getParametersValue(parameters, MAC_DATA, PFX.defaultValues(MAC_DATA));
+ }
+ if (PARSED_VALUE in parameters) {
+ this.parsedValue = getParametersValue(parameters, PARSED_VALUE, PFX.defaultValues(PARSED_VALUE));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case VERSION$1:
+ return 3;
+ case AUTH_SAFE:
+ return (new ContentInfo());
+ case MAC_DATA:
+ return (new MacData());
+ case PARSED_VALUE:
+ return {};
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case VERSION$1:
+ return (memberValue === PFX.defaultValues(memberName));
+ case AUTH_SAFE:
+ return ((ContentInfo.compareWithDefault("contentType", memberValue.contentType)) &&
+ (ContentInfo.compareWithDefault("content", memberValue.content)));
+ case MAC_DATA:
+ return ((MacData.compareWithDefault("mac", memberValue.mac)) &&
+ (MacData.compareWithDefault("macSalt", memberValue.macSalt)) &&
+ (MacData.compareWithDefault("iterations", memberValue.iterations)));
+ case PARSED_VALUE:
+ return ((memberValue instanceof Object) && (Object.keys(memberValue).length === 0));
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Integer({ name: (names.version || VERSION$1) }),
+ ContentInfo.schema(names.authSafe || {
+ names: {
+ blockName: AUTH_SAFE
+ }
+ }),
+ MacData.schema(names.macData || {
+ names: {
+ blockName: MAC_DATA,
+ optional: true
+ }
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLERA_PROPS);
+ const asn1 = compareSchema(schema, schema, PFX.schema({
+ names: {
+ version: VERSION$1,
+ authSafe: {
+ names: {
+ blockName: AUTH_SAFE
+ }
+ },
+ macData: {
+ names: {
+ blockName: MAC_DATA
+ }
+ }
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ this.version = asn1.result.version.valueBlock.valueDec;
+ this.authSafe = new ContentInfo({ schema: asn1.result.authSafe });
+ if (MAC_DATA in asn1.result)
+ this.macData = new MacData({ schema: asn1.result.macData });
+ }
+ toSchema() {
+ const outputArray = [
+ new Integer({ value: this.version }),
+ this.authSafe.toSchema()
+ ];
+ if (this.macData) {
+ outputArray.push(this.macData.toSchema());
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const output = {
+ version: this.version,
+ authSafe: this.authSafe.toJSON()
+ };
+ if (this.macData) {
+ output.macData = this.macData.toJSON();
+ }
+ return output;
+ }
+ makeInternalValues(parameters = {}, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ ArgumentError.assert(parameters, "parameters", "object");
+ if (!this.parsedValue) {
+ throw new Error("Please call \"parseValues\" function first in order to make \"parsedValue\" data");
+ }
+ ParameterError.assertEmpty(this.parsedValue.integrityMode, "integrityMode", "parsedValue");
+ ParameterError.assertEmpty(this.parsedValue.authenticatedSafe, "authenticatedSafe", "parsedValue");
+ switch (this.parsedValue.integrityMode) {
+ case 0:
+ {
+ if (!("iterations" in parameters))
+ throw new ParameterError("iterations");
+ ParameterError.assertEmpty(parameters.pbkdf2HashAlgorithm, "pbkdf2HashAlgorithm");
+ ParameterError.assertEmpty(parameters.hmacHashAlgorithm, "hmacHashAlgorithm");
+ ParameterError.assertEmpty(parameters.password, "password");
+ const saltBuffer = new ArrayBuffer(64);
+ const saltView = new Uint8Array(saltBuffer);
+ crypto.getRandomValues(saltView);
+ const data = this.parsedValue.authenticatedSafe.toSchema().toBER(false);
+ this.authSafe = new ContentInfo({
+ contentType: ContentInfo.DATA,
+ content: new OctetString({ valueHex: data })
+ });
+ const result = yield crypto.stampDataWithPassword({
+ password: parameters.password,
+ hashAlgorithm: parameters.hmacHashAlgorithm,
+ salt: saltBuffer,
+ iterationCount: parameters.iterations,
+ contentToStamp: data
+ });
+ this.macData = new MacData({
+ mac: new DigestInfo({
+ digestAlgorithm: new AlgorithmIdentifier({
+ algorithmId: crypto.getOIDByAlgorithm({ name: parameters.hmacHashAlgorithm }, true, "hmacHashAlgorithm"),
+ }),
+ digest: new OctetString({ valueHex: result })
+ }),
+ macSalt: new OctetString({ valueHex: saltBuffer }),
+ iterations: parameters.iterations
+ });
+ }
+ break;
+ case 1:
+ {
+ if (!("signingCertificate" in parameters)) {
+ throw new ParameterError("signingCertificate");
+ }
+ ParameterError.assertEmpty(parameters.privateKey, "privateKey");
+ ParameterError.assertEmpty(parameters.hashAlgorithm, "hashAlgorithm");
+ const toBeSigned = this.parsedValue.authenticatedSafe.toSchema().toBER(false);
+ const cmsSigned = new SignedData({
+ version: 1,
+ encapContentInfo: new EncapsulatedContentInfo({
+ eContentType: "1.2.840.113549.1.7.1",
+ eContent: new OctetString({ valueHex: toBeSigned })
+ }),
+ certificates: [parameters.signingCertificate]
+ });
+ const result = yield crypto.digest({ name: parameters.hashAlgorithm }, new Uint8Array(toBeSigned));
+ const signedAttr = [];
+ signedAttr.push(new Attribute({
+ type: "1.2.840.113549.1.9.3",
+ values: [
+ new ObjectIdentifier({ value: "1.2.840.113549.1.7.1" })
+ ]
+ }));
+ signedAttr.push(new Attribute({
+ type: "1.2.840.113549.1.9.5",
+ values: [
+ new UTCTime({ valueDate: new Date() })
+ ]
+ }));
+ signedAttr.push(new Attribute({
+ type: "1.2.840.113549.1.9.4",
+ values: [
+ new OctetString({ valueHex: result })
+ ]
+ }));
+ cmsSigned.signerInfos.push(new SignerInfo({
+ version: 1,
+ sid: new IssuerAndSerialNumber({
+ issuer: parameters.signingCertificate.issuer,
+ serialNumber: parameters.signingCertificate.serialNumber
+ }),
+ signedAttrs: new SignedAndUnsignedAttributes({
+ type: 0,
+ attributes: signedAttr
+ })
+ }));
+ yield cmsSigned.sign(parameters.privateKey, 0, parameters.hashAlgorithm, undefined, crypto);
+ this.authSafe = new ContentInfo({
+ contentType: "1.2.840.113549.1.7.2",
+ content: cmsSigned.toSchema(true)
+ });
+ }
+ break;
+ default:
+ throw new Error(`Parameter "integrityMode" has unknown value: ${this.parsedValue.integrityMode}`);
+ }
+ });
+ }
+ parseInternalValues(parameters, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ ArgumentError.assert(parameters, "parameters", "object");
+ if (parameters.checkIntegrity === undefined) {
+ parameters.checkIntegrity = true;
+ }
+ this.parsedValue = {};
+ switch (this.authSafe.contentType) {
+ case ContentInfo.DATA:
+ {
+ ParameterError.assertEmpty(parameters.password, "password");
+ this.parsedValue.integrityMode = 0;
+ ArgumentError.assert(this.authSafe.content, "authSafe.content", OctetString);
+ const authSafeContent = this.authSafe.content.getValue();
+ this.parsedValue.authenticatedSafe = AuthenticatedSafe.fromBER(authSafeContent);
+ if (parameters.checkIntegrity) {
+ if (!this.macData) {
+ throw new Error("Absent \"macData\" value, can not check PKCS#12 data integrity");
+ }
+ const hashAlgorithm = crypto.getAlgorithmByOID(this.macData.mac.digestAlgorithm.algorithmId, true, "digestAlgorithm");
+ const result = yield crypto.verifyDataStampedWithPassword({
+ password: parameters.password,
+ hashAlgorithm: hashAlgorithm.name,
+ salt: BufferSourceConverter.toArrayBuffer(this.macData.macSalt.valueBlock.valueHexView),
+ iterationCount: this.macData.iterations || 1,
+ contentToVerify: authSafeContent,
+ signatureToVerify: BufferSourceConverter.toArrayBuffer(this.macData.mac.digest.valueBlock.valueHexView),
+ });
+ if (!result) {
+ throw new Error("Integrity for the PKCS#12 data is broken!");
+ }
+ }
+ }
+ break;
+ case ContentInfo.SIGNED_DATA:
+ {
+ this.parsedValue.integrityMode = 1;
+ const cmsSigned = new SignedData({ schema: this.authSafe.content });
+ const eContent = cmsSigned.encapContentInfo.eContent;
+ ParameterError.assert(eContent, "eContent", "cmsSigned.encapContentInfo");
+ ArgumentError.assert(eContent, "eContent", OctetString);
+ const data = eContent.getValue();
+ this.parsedValue.authenticatedSafe = AuthenticatedSafe.fromBER(data);
+ const ok = yield cmsSigned.verify({ signer: 0, checkChain: false }, crypto);
+ if (!ok) {
+ throw new Error("Integrity for the PKCS#12 data is broken!");
+ }
+ }
+ break;
+ default:
+ throw new Error(`Incorrect value for "this.authSafe.contentType": ${this.authSafe.contentType}`);
+ }
+ });
+ }
+}
+PFX.CLASS_NAME = "PFX";
+
+const STATUS$1 = "status";
+const STATUS_STRINGS = "statusStrings";
+const FAIL_INFO = "failInfo";
+const CLEAR_PROPS$2 = [
+ STATUS$1,
+ STATUS_STRINGS,
+ FAIL_INFO
+];
+var PKIStatus;
+(function (PKIStatus) {
+ PKIStatus[PKIStatus["granted"] = 0] = "granted";
+ PKIStatus[PKIStatus["grantedWithMods"] = 1] = "grantedWithMods";
+ PKIStatus[PKIStatus["rejection"] = 2] = "rejection";
+ PKIStatus[PKIStatus["waiting"] = 3] = "waiting";
+ PKIStatus[PKIStatus["revocationWarning"] = 4] = "revocationWarning";
+ PKIStatus[PKIStatus["revocationNotification"] = 5] = "revocationNotification";
+})(PKIStatus || (PKIStatus = {}));
+class PKIStatusInfo extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.status = getParametersValue(parameters, STATUS$1, PKIStatusInfo.defaultValues(STATUS$1));
+ if (STATUS_STRINGS in parameters) {
+ this.statusStrings = getParametersValue(parameters, STATUS_STRINGS, PKIStatusInfo.defaultValues(STATUS_STRINGS));
+ }
+ if (FAIL_INFO in parameters) {
+ this.failInfo = getParametersValue(parameters, FAIL_INFO, PKIStatusInfo.defaultValues(FAIL_INFO));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case STATUS$1:
+ return 2;
+ case STATUS_STRINGS:
+ return [];
+ case FAIL_INFO:
+ return new BitString();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case STATUS$1:
+ return (memberValue === PKIStatusInfo.defaultValues(memberName));
+ case STATUS_STRINGS:
+ return (memberValue.length === 0);
+ case FAIL_INFO:
+ return (memberValue.isEqual(PKIStatusInfo.defaultValues(memberName)));
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || EMPTY_STRING),
+ value: [
+ new Integer({ name: (names.status || EMPTY_STRING) }),
+ new Sequence({
+ optional: true,
+ value: [
+ new Repeated({
+ name: (names.statusStrings || EMPTY_STRING),
+ value: new Utf8String()
+ })
+ ]
+ }),
+ new BitString({
+ name: (names.failInfo || EMPTY_STRING),
+ optional: true
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$2);
+ const asn1 = compareSchema(schema, schema, PKIStatusInfo.schema({
+ names: {
+ status: STATUS$1,
+ statusStrings: STATUS_STRINGS,
+ failInfo: FAIL_INFO
+ }
+ }));
+ AsnError.assertSchema(asn1, this.className);
+ const _status = asn1.result.status;
+ if ((_status.valueBlock.isHexOnly === true) ||
+ (_status.valueBlock.valueDec < 0) ||
+ (_status.valueBlock.valueDec > 5))
+ throw new Error("PKIStatusInfo \"status\" has invalid value");
+ this.status = _status.valueBlock.valueDec;
+ if (STATUS_STRINGS in asn1.result)
+ this.statusStrings = asn1.result.statusStrings;
+ if (FAIL_INFO in asn1.result)
+ this.failInfo = asn1.result.failInfo;
+ }
+ toSchema() {
+ const outputArray = [];
+ outputArray.push(new Integer({ value: this.status }));
+ if (this.statusStrings) {
+ outputArray.push(new Sequence({
+ optional: true,
+ value: this.statusStrings
+ }));
+ }
+ if (this.failInfo) {
+ outputArray.push(this.failInfo);
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {
+ status: this.status
+ };
+ if (this.statusStrings) {
+ res.statusStrings = Array.from(this.statusStrings, o => o.toJSON());
+ }
+ if (this.failInfo) {
+ res.failInfo = this.failInfo.toJSON();
+ }
+ return res;
+ }
+}
+PKIStatusInfo.CLASS_NAME = "PKIStatusInfo";
+
+const VERSION = "version";
+const MESSAGE_IMPRINT = "messageImprint";
+const REQ_POLICY = "reqPolicy";
+const NONCE = "nonce";
+const CERT_REQ = "certReq";
+const EXTENSIONS = "extensions";
+const TIME_STAMP_REQ = "TimeStampReq";
+const TIME_STAMP_REQ_VERSION = `${TIME_STAMP_REQ}.${VERSION}`;
+const TIME_STAMP_REQ_MESSAGE_IMPRINT = `${TIME_STAMP_REQ}.${MESSAGE_IMPRINT}`;
+const TIME_STAMP_REQ_POLICY = `${TIME_STAMP_REQ}.${REQ_POLICY}`;
+const TIME_STAMP_REQ_NONCE = `${TIME_STAMP_REQ}.${NONCE}`;
+const TIME_STAMP_REQ_CERT_REQ = `${TIME_STAMP_REQ}.${CERT_REQ}`;
+const TIME_STAMP_REQ_EXTENSIONS = `${TIME_STAMP_REQ}.${EXTENSIONS}`;
+const CLEAR_PROPS$1 = [
+ TIME_STAMP_REQ_VERSION,
+ TIME_STAMP_REQ_MESSAGE_IMPRINT,
+ TIME_STAMP_REQ_POLICY,
+ TIME_STAMP_REQ_NONCE,
+ TIME_STAMP_REQ_CERT_REQ,
+ TIME_STAMP_REQ_EXTENSIONS,
+];
+class TimeStampReq extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.version = getParametersValue(parameters, VERSION, TimeStampReq.defaultValues(VERSION));
+ this.messageImprint = getParametersValue(parameters, MESSAGE_IMPRINT, TimeStampReq.defaultValues(MESSAGE_IMPRINT));
+ if (REQ_POLICY in parameters) {
+ this.reqPolicy = getParametersValue(parameters, REQ_POLICY, TimeStampReq.defaultValues(REQ_POLICY));
+ }
+ if (NONCE in parameters) {
+ this.nonce = getParametersValue(parameters, NONCE, TimeStampReq.defaultValues(NONCE));
+ }
+ if (CERT_REQ in parameters) {
+ this.certReq = getParametersValue(parameters, CERT_REQ, TimeStampReq.defaultValues(CERT_REQ));
+ }
+ if (EXTENSIONS in parameters) {
+ this.extensions = getParametersValue(parameters, EXTENSIONS, TimeStampReq.defaultValues(EXTENSIONS));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case VERSION:
+ return 0;
+ case MESSAGE_IMPRINT:
+ return new MessageImprint();
+ case REQ_POLICY:
+ return EMPTY_STRING;
+ case NONCE:
+ return new Integer();
+ case CERT_REQ:
+ return false;
+ case EXTENSIONS:
+ return [];
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case VERSION:
+ case REQ_POLICY:
+ case CERT_REQ:
+ return (memberValue === TimeStampReq.defaultValues(memberName));
+ case MESSAGE_IMPRINT:
+ return ((MessageImprint.compareWithDefault("hashAlgorithm", memberValue.hashAlgorithm)) &&
+ (MessageImprint.compareWithDefault("hashedMessage", memberValue.hashedMessage)));
+ case NONCE:
+ return (memberValue.isEqual(TimeStampReq.defaultValues(memberName)));
+ case EXTENSIONS:
+ return (memberValue.length === 0);
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || TIME_STAMP_REQ),
+ value: [
+ new Integer({ name: (names.version || TIME_STAMP_REQ_VERSION) }),
+ MessageImprint.schema(names.messageImprint || {
+ names: {
+ blockName: TIME_STAMP_REQ_MESSAGE_IMPRINT
+ }
+ }),
+ new ObjectIdentifier({
+ name: (names.reqPolicy || TIME_STAMP_REQ_POLICY),
+ optional: true
+ }),
+ new Integer({
+ name: (names.nonce || TIME_STAMP_REQ_NONCE),
+ optional: true
+ }),
+ new Boolean({
+ name: (names.certReq || TIME_STAMP_REQ_CERT_REQ),
+ optional: true
+ }),
+ new Constructed({
+ optional: true,
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: [new Repeated({
+ name: (names.extensions || TIME_STAMP_REQ_EXTENSIONS),
+ value: Extension.schema()
+ })]
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS$1);
+ const asn1 = compareSchema(schema, schema, TimeStampReq.schema());
+ AsnError.assertSchema(asn1, this.className);
+ this.version = asn1.result[TIME_STAMP_REQ_VERSION].valueBlock.valueDec;
+ this.messageImprint = new MessageImprint({ schema: asn1.result[TIME_STAMP_REQ_MESSAGE_IMPRINT] });
+ if (TIME_STAMP_REQ_POLICY in asn1.result)
+ this.reqPolicy = asn1.result[TIME_STAMP_REQ_POLICY].valueBlock.toString();
+ if (TIME_STAMP_REQ_NONCE in asn1.result)
+ this.nonce = asn1.result[TIME_STAMP_REQ_NONCE];
+ if (TIME_STAMP_REQ_CERT_REQ in asn1.result)
+ this.certReq = asn1.result[TIME_STAMP_REQ_CERT_REQ].valueBlock.value;
+ if (TIME_STAMP_REQ_EXTENSIONS in asn1.result)
+ this.extensions = Array.from(asn1.result[TIME_STAMP_REQ_EXTENSIONS], element => new Extension({ schema: element }));
+ }
+ toSchema() {
+ const outputArray = [];
+ outputArray.push(new Integer({ value: this.version }));
+ outputArray.push(this.messageImprint.toSchema());
+ if (this.reqPolicy)
+ outputArray.push(new ObjectIdentifier({ value: this.reqPolicy }));
+ if (this.nonce)
+ outputArray.push(this.nonce);
+ if ((CERT_REQ in this) && (TimeStampReq.compareWithDefault(CERT_REQ, this.certReq) === false))
+ outputArray.push(new Boolean({ value: this.certReq }));
+ if (this.extensions) {
+ outputArray.push(new Constructed({
+ idBlock: {
+ tagClass: 3,
+ tagNumber: 0
+ },
+ value: Array.from(this.extensions, o => o.toSchema())
+ }));
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {
+ version: this.version,
+ messageImprint: this.messageImprint.toJSON()
+ };
+ if (this.reqPolicy !== undefined)
+ res.reqPolicy = this.reqPolicy;
+ if (this.nonce !== undefined)
+ res.nonce = this.nonce.toJSON();
+ if ((this.certReq !== undefined) && (TimeStampReq.compareWithDefault(CERT_REQ, this.certReq) === false))
+ res.certReq = this.certReq;
+ if (this.extensions) {
+ res.extensions = Array.from(this.extensions, o => o.toJSON());
+ }
+ return res;
+ }
+}
+TimeStampReq.CLASS_NAME = "TimeStampReq";
+
+const STATUS = "status";
+const TIME_STAMP_TOKEN = "timeStampToken";
+const TIME_STAMP_RESP = "TimeStampResp";
+const TIME_STAMP_RESP_STATUS = `${TIME_STAMP_RESP}.${STATUS}`;
+const TIME_STAMP_RESP_TOKEN = `${TIME_STAMP_RESP}.${TIME_STAMP_TOKEN}`;
+const CLEAR_PROPS = [
+ TIME_STAMP_RESP_STATUS,
+ TIME_STAMP_RESP_TOKEN
+];
+class TimeStampResp extends PkiObject {
+ constructor(parameters = {}) {
+ super();
+ this.status = getParametersValue(parameters, STATUS, TimeStampResp.defaultValues(STATUS));
+ if (TIME_STAMP_TOKEN in parameters) {
+ this.timeStampToken = getParametersValue(parameters, TIME_STAMP_TOKEN, TimeStampResp.defaultValues(TIME_STAMP_TOKEN));
+ }
+ if (parameters.schema) {
+ this.fromSchema(parameters.schema);
+ }
+ }
+ static defaultValues(memberName) {
+ switch (memberName) {
+ case STATUS:
+ return new PKIStatusInfo();
+ case TIME_STAMP_TOKEN:
+ return new ContentInfo();
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static compareWithDefault(memberName, memberValue) {
+ switch (memberName) {
+ case STATUS:
+ return ((PKIStatusInfo.compareWithDefault(STATUS, memberValue.status)) &&
+ (("statusStrings" in memberValue) === false) &&
+ (("failInfo" in memberValue) === false));
+ case TIME_STAMP_TOKEN:
+ return ((memberValue.contentType === EMPTY_STRING) &&
+ (memberValue.content instanceof Any));
+ default:
+ return super.defaultValues(memberName);
+ }
+ }
+ static schema(parameters = {}) {
+ const names = getParametersValue(parameters, "names", {});
+ return (new Sequence({
+ name: (names.blockName || TIME_STAMP_RESP),
+ value: [
+ PKIStatusInfo.schema(names.status || {
+ names: {
+ blockName: TIME_STAMP_RESP_STATUS
+ }
+ }),
+ ContentInfo.schema(names.timeStampToken || {
+ names: {
+ blockName: TIME_STAMP_RESP_TOKEN,
+ optional: true
+ }
+ })
+ ]
+ }));
+ }
+ fromSchema(schema) {
+ clearProps(schema, CLEAR_PROPS);
+ const asn1 = compareSchema(schema, schema, TimeStampResp.schema());
+ AsnError.assertSchema(asn1, this.className);
+ this.status = new PKIStatusInfo({ schema: asn1.result[TIME_STAMP_RESP_STATUS] });
+ if (TIME_STAMP_RESP_TOKEN in asn1.result)
+ this.timeStampToken = new ContentInfo({ schema: asn1.result[TIME_STAMP_RESP_TOKEN] });
+ }
+ toSchema() {
+ const outputArray = [];
+ outputArray.push(this.status.toSchema());
+ if (this.timeStampToken) {
+ outputArray.push(this.timeStampToken.toSchema());
+ }
+ return (new Sequence({
+ value: outputArray
+ }));
+ }
+ toJSON() {
+ const res = {
+ status: this.status.toJSON()
+ };
+ if (this.timeStampToken) {
+ res.timeStampToken = this.timeStampToken.toJSON();
+ }
+ return res;
+ }
+ sign(privateKey, hashAlgorithm, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ this.assertContentType();
+ const signed = new SignedData({ schema: this.timeStampToken.content });
+ return signed.sign(privateKey, 0, hashAlgorithm, undefined, crypto);
+ });
+ }
+ verify(verificationParameters = { signer: 0, trustedCerts: [], data: EMPTY_BUFFER }, crypto = getCrypto(true)) {
+ return __awaiter(this, void 0, void 0, function* () {
+ this.assertContentType();
+ const signed = new SignedData({ schema: this.timeStampToken.content });
+ return signed.verify(verificationParameters, crypto);
+ });
+ }
+ assertContentType() {
+ if (!this.timeStampToken) {
+ throw new Error("timeStampToken is absent in TSP response");
+ }
+ if (this.timeStampToken.contentType !== id_ContentType_SignedData) {
+ throw new Error(`Wrong format of timeStampToken: ${this.timeStampToken.contentType}`);
+ }
+ }
+}
+TimeStampResp.CLASS_NAME = "TimeStampResp";
+
+function initCryptoEngine() {
+ if (typeof self !== "undefined") {
+ if ("crypto" in self) {
+ let engineName = "webcrypto";
+ if ("webkitSubtle" in self.crypto) {
+ engineName = "safari";
+ }
+ setEngine(engineName, new CryptoEngine({ name: engineName, crypto: crypto }));
+ }
+ }
+ else if (typeof crypto !== "undefined" && "webcrypto" in crypto) {
+ const name = "NodeJS ^15";
+ const nodeCrypto = crypto.webcrypto;
+ setEngine(name, new CryptoEngine({ name, crypto: nodeCrypto }));
+ }
+}
+
+initCryptoEngine();
+
+export { AbstractCryptoEngine, AccessDescription, Accuracy, AlgorithmIdentifier, AltName, ArgumentError, AsnError, AttCertValidityPeriod, Attribute, AttributeCertificateInfoV1, AttributeCertificateInfoV2, AttributeCertificateV1, AttributeCertificateV2, AttributeTypeAndValue, AuthenticatedSafe, AuthorityKeyIdentifier, BasicConstraints, BasicOCSPResponse, CAVersion, CRLBag, CRLDistributionPoints, CertBag, CertID, Certificate, CertificateChainValidationEngine, CertificatePolicies, CertificateRevocationList, CertificateSet, CertificateTemplate, CertificationRequest, ChainValidationCode, ChainValidationError, ContentInfo, CryptoEngine, DigestInfo, DistributionPoint, ECCCMSSharedInfo, ECNamedCurves, ECPrivateKey, ECPublicKey, EncapsulatedContentInfo, EncryptedContentInfo, EncryptedData, EnvelopedData, ExtKeyUsage, Extension, ExtensionValueFactory, Extensions, GeneralName, GeneralNames, GeneralSubtree, HASHED_MESSAGE, HASH_ALGORITHM, Holder, InfoAccess, IssuerAndSerialNumber, IssuerSerial, IssuingDistributionPoint, KEKIdentifier, KEKRecipientInfo, KeyAgreeRecipientIdentifier, KeyAgreeRecipientInfo, KeyBag, KeyTransRecipientInfo, MICROS, MILLIS, MacData, MessageImprint, NameConstraints, OCSPRequest, OCSPResponse, ObjectDigestInfo, OriginatorIdentifierOrKey, OriginatorInfo, OriginatorPublicKey, OtherCertificateFormat, OtherKeyAttribute, OtherPrimeInfo, OtherRecipientInfo, OtherRevocationInfoFormat, PBES2Params, PBKDF2Params, PFX, PKCS8ShroudedKeyBag, PKIStatus, PKIStatusInfo, POLICY_IDENTIFIER, POLICY_QUALIFIERS, ParameterError, PasswordRecipientinfo, PkiObject, PolicyConstraints, PolicyInformation, PolicyMapping, PolicyMappings, PolicyQualifierInfo, PrivateKeyInfo, PrivateKeyUsagePeriod, PublicKeyInfo, QCStatement, QCStatements, RDN, RSAESOAEPParams, RSAPrivateKey, RSAPublicKey, RSASSAPSSParams, RecipientEncryptedKey, RecipientEncryptedKeys, RecipientIdentifier, RecipientInfo, RecipientKeyIdentifier, RelativeDistinguishedNames, Request, ResponseBytes, ResponseData, RevocationInfoChoices, RevokedCertificate, SECONDS, SafeBag, SafeBagValueFactory, SafeContents, SecretBag, Signature, SignedAndUnsignedAttributes, SignedCertificateTimestamp, SignedCertificateTimestampList, SignedData, SignedDataVerifyError, SignerInfo, SingleResponse, SubjectDirectoryAttributes, TBSRequest, TSTInfo, TYPE$4 as TYPE, TYPE_AND_VALUES, Time, TimeStampReq, TimeStampResp, TimeType, V2Form, VALUE$5 as VALUE, VALUE_BEFORE_DECODE, checkCA, createCMSECDSASignature, createECDSASignatureFromCMS, engine, getAlgorithmByOID, getAlgorithmParameters, getCrypto, getEngine, getHashAlgorithm, getOIDByAlgorithm, getRandomValues, id_AnyPolicy, id_AuthorityInfoAccess, id_AuthorityKeyIdentifier, id_BaseCRLNumber, id_BasicConstraints, id_CRLBag_X509CRL, id_CRLDistributionPoints, id_CRLNumber, id_CRLReason, id_CertBag_AttributeCertificate, id_CertBag_SDSICertificate, id_CertBag_X509Certificate, id_CertificateIssuer, id_CertificatePolicies, id_ContentType_Data, id_ContentType_EncryptedData, id_ContentType_EnvelopedData, id_ContentType_SignedData, id_ExtKeyUsage, id_FreshestCRL, id_InhibitAnyPolicy, id_InvalidityDate, id_IssuerAltName, id_IssuingDistributionPoint, id_KeyUsage, id_MicrosoftAppPolicies, id_MicrosoftCaVersion, id_MicrosoftCertTemplateV1, id_MicrosoftCertTemplateV2, id_MicrosoftPrevCaCertHash, id_NameConstraints, id_PKIX_OCSP_Basic, id_PolicyConstraints, id_PolicyMappings, id_PrivateKeyUsagePeriod, id_QCStatements, id_SignedCertificateTimestampList, id_SubjectAltName, id_SubjectDirectoryAttributes, id_SubjectInfoAccess, id_SubjectKeyIdentifier, id_ad, id_ad_caIssuers, id_ad_ocsp, id_eContentType_TSTInfo, id_pkix, id_sha1, id_sha256, id_sha384, id_sha512, kdf, setEngine, stringPrep, verifySCTsForCertificate };
diff --git a/toolkit/components/certviewer/jar.mn b/toolkit/components/certviewer/jar.mn
new file mode 100644
index 0000000000..84dc252606
--- /dev/null
+++ b/toolkit/components/certviewer/jar.mn
@@ -0,0 +1,12 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+toolkit.jar:
+ content/global/certviewer/certviewer.html (content/certviewer.html)
+ content/global/certviewer/certviewer.css (content/certviewer.css)
+ content/global/certviewer/certviewer.mjs (content/certviewer.mjs)
+ content/global/certviewer/components/ (content/components/*.mjs)
+ content/global/certviewer/components/ (content/components/*.css)
+ content/global/certviewer/certDecoder.mjs (content/certDecoder.mjs)
+ content/global/certviewer/vendor/pkijs.js (content/vendor/pkijs.js)
diff --git a/toolkit/components/certviewer/moz.build b/toolkit/components/certviewer/moz.build
new file mode 100644
index 0000000000..d35a1bb0c1
--- /dev/null
+++ b/toolkit/components/certviewer/moz.build
@@ -0,0 +1,19 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+JAR_MANIFESTS += ["jar.mn"]
+
+BROWSER_CHROME_MANIFESTS += ["tests/browser/browser.toml"]
+
+MOCHITEST_CHROME_MANIFESTS += ["tests/chrome/chrome.toml"]
+
+EXTRA_JS_MODULES += [
+ "AboutCertViewerChild.sys.mjs",
+ "AboutCertViewerParent.sys.mjs",
+]
+
+with Files("**"):
+ BUG_COMPONENT = ("Firefox", "Security")
diff --git a/toolkit/components/certviewer/tests/browser/adjustedCerts.js b/toolkit/components/certviewer/tests/browser/adjustedCerts.js
new file mode 100644
index 0000000000..0b0c089a61
--- /dev/null
+++ b/toolkit/components/certviewer/tests/browser/adjustedCerts.js
@@ -0,0 +1,261 @@
+"use strict";
+
+/*
+To change this file you will have to add a function to download a file in toolkit/components/certviewer/content/certviewer.mjs (e.g: https://ourcodeworld.com/articles/read/189/how-to-create-a-file-and-generate-a-download-with-javascript-in-the-browser-without-a-server),
+download adjustedCerts (e.g: download("out.txt", JSON.stringify(adjustedCerts)), do it after this line https://searchfox.org/mozilla-central/rev/e3fc8f8970491aef14d3212b2d052942f4d29818/toolkit/components/certviewer/content/certviewer.mjs#428),
+then open Nightly and go to about:certificate?cert=MIIHQjCCBiqgAwIBAgIQCgYwQn9bvO1pVzllk7ZFHzANBgkqhkiG9w0BAQsFADB1MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTQwMgYDVQQDEytEaWdpQ2VydCBTSEEyIEV4dGVuZGVkIFZhbGlkYXRpb24gU2VydmVyIENBMB4XDTE4MDUwODAwMDAwMFoXDTIwMDYwMzEyMDAwMFowgccxHTAbBgNVBA8MFFByaXZhdGUgT3JnYW5pemF0aW9uMRMwEQYLKwYBBAGCNzwCAQMTAlVTMRkwFwYLKwYBBAGCNzwCAQITCERlbGF3YXJlMRAwDgYDVQQFEwc1MTU3NTUwMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEVMBMGA1UEChMMR2l0SHViLCBJbmMuMRMwEQYDVQQDEwpnaXRodWIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxjyq8jyXDDrBTyitcnB90865tWBzpHSbindG%2FXqYQkzFMBlXmqkzC%2BFdTRBYyneZw5Pz%2BXWQvL%2B74JW6LsWNc2EF0xCEqLOJuC9zjPAqbr7uroNLghGxYf13YdqbG5oj%2F4x%2BogEG3dF%2FU5YIwVr658DKyESMV6eoYV9mDVfTuJastkqcwero%2B5ZAKfYVMLUEsMwFtoTDJFmVf6JlkOWwsxp1WcQ%2FMRQK1cyqOoUFUgYylgdh3yeCDPeF22Ax8AlQxbcaI%2BGwfQL1FB7Jy%2Bh%2BKjME9lE%2FUpgV6Qt2R1xNSmvFCBWu%2BNFX6epwFP%2FJRbkMfLz0beYFUvmMgLtwVpEPSwIDAQABo4IDeTCCA3UwHwYDVR0jBBgwFoAUPdNQpdagre7zSmAKZdMh1Pj41g8wHQYDVR0OBBYEFMnCU2FmnV%2BrJfQmzQ84mqhJ6kipMCUGA1UdEQQeMByCCmdpdGh1Yi5jb22CDnd3dy5naXRodWIuY29tMA4GA1UdDwEB%2FwQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdQYDVR0fBG4wbDA0oDKgMIYuaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItZXYtc2VydmVyLWcyLmNybDA0oDKgMIYuaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItZXYtc2VydmVyLWcyLmNybDBLBgNVHSAERDBCMDcGCWCGSAGG%2FWwCATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAcGBWeBDAEBMIGIBggrBgEFBQcBAQR8MHowJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBSBggrBgEFBQcwAoZGaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkV4dGVuZGVkVmFsaWRhdGlvblNlcnZlckNBLmNydDAMBgNVHRMBAf8EAjAAMIIBfgYKKwYBBAHWeQIEAgSCAW4EggFqAWgAdgCkuQmQtBhYFIe7E6LMZ3AKPDWYBPkb37jjd80OyA3cEAAAAWNBYm0KAAAEAwBHMEUCIQDRZp38cTWsWH2GdBpe%2FuPTWnsu%2Fm4BEC2%2BdIcvSykZYgIgCP5gGv6yzaazxBK2NwGdmmyuEFNSg2pARbMJlUFgU5UAdgBWFAaaL9fC7NP14b1Esj7HRna5vJkRXMDvlJhV1onQ3QAAAWNBYm0tAAAEAwBHMEUCIQCi7omUvYLm0b2LobtEeRAYnlIo7n6JxbYdrtYdmPUWJQIgVgw1AZ51vK9ENinBg22FPxb82TvNDO05T17hxXRC2IYAdgC72d%2B8H4pxtZOUI5eqkntHOFeVCqtS6BqQlmQ2jh7RhQAAAWNBYm3fAAAEAwBHMEUCIQChzdTKUU2N%2BXcqcK0OJYrN8EYynloVxho4yPk6Dq3EPgIgdNH5u8rC3UcslQV4B9o0a0w204omDREGKTVuEpxGeOQwDQYJKoZIhvcNAQELBQADggEBAHAPWpanWOW%2Fip2oJ5grAH8mqQfaunuCVE%2Bvac%2B88lkDK%2FLVdFgl2B6kIHZiYClzKtfczG93hWvKbST4NRNHP9LiaQqdNC17e5vNHnXVUGw%2ByxyjMLGqkgepOnZ2Rb14kcTOGp4i5AuJuuaMwXmCo7jUwPwfLe1NUlVBKqg6LK0Hcq4K0sZnxE8HFxiZ92WpV2AVWjRMEc%2F2z2shNoDvxvFUYyY1Oe67xINkmyQKc%2BygSBZzyLnXSFVWmHr3u5dcaaQGGAR42v6Ydr4iL38Hd4dOiBma%2BFXsXBIqWUjbST4VXmdaol7uzFMojA4zkxQDZAvF5XgJlAFadfySna%2Fteik%3D
+open the file, and finally copy and paste it here like
+
+const adjustedCerts = <what you just copied>;
+*/
+
+const adjustedCerts = [
+ {
+ certItems: [
+ {
+ sectionId: "subject-name",
+ sectionItems: [
+ { labelId: "business-category", info: "Private Organization" },
+ { labelId: "inc-country", info: "US" },
+ { labelId: "inc-state-province", info: "Delaware" },
+ { labelId: "serial-number", info: "5157550" },
+ { labelId: "country", info: "US" },
+ { labelId: "state-province", info: "California" },
+ { labelId: "locality", info: "San Francisco" },
+ { labelId: "organization", info: "GitHub, Inc." },
+ { labelId: "common-name", info: "github.com" },
+ ],
+ Critical: false,
+ },
+ {
+ sectionId: "issuer-name",
+ sectionItems: [
+ { labelId: "country", info: "US" },
+ { labelId: "organization", info: "DigiCert Inc" },
+ { labelId: "organizational-unit", info: "www.digicert.com" },
+ {
+ labelId: "common-name",
+ info: "DigiCert SHA2 Extended Validation Server CA",
+ },
+ ],
+ Critical: false,
+ },
+ {
+ sectionId: "validity",
+ sectionItems: [
+ {
+ labelId: "not-before",
+ info: {
+ local: "5/7/2018, 9:00:00 PM (Brasilia Standard Time)",
+ utc: "Tue, 08 May 2018 00:00:00 GMT",
+ },
+ },
+ {
+ labelId: "not-after",
+ info: {
+ local: "6/3/2020, 9:00:00 AM (Brasilia Standard Time)",
+ utc: "Wed, 03 Jun 2020 12:00:00 GMT",
+ },
+ },
+ ],
+ Critical: false,
+ },
+ {
+ sectionId: "subject-alt-names",
+ sectionItems: [
+ { labelId: "dns-name", info: "github.com" },
+ { labelId: "dns-name", info: "www.github.com" },
+ ],
+ Critical: false,
+ },
+ {
+ sectionId: "public-key-info",
+ sectionItems: [
+ { labelId: "algorithm", info: "RSA" },
+ { labelId: "key-size", info: 2048 },
+ { labelId: "exponent", info: 65537 },
+ {
+ labelId: "modulus",
+ info: "C6:3C:AA:F2:3C:97:0C:3A:C1:4F:28:AD:72:70:7D:D3:CE:B9:B5:60:73:A4:74:9B:8A:77:46:FD:7A:98:42:4C:C5:30:19:57:9A:A9:33:0B:E1:5D:4D:10:58:CA:77:99:C3:93:F3:F9:75:90:BC:BF:BB:E0:95:BA:2E:C5:8D:73:61:05:D3:10:84:A8:B3:89:B8:2F:73:8C:F0:2A:6E:BE:EE:AE:83:4B:82:11:B1:61:FD:77:61:DA:9B:1B:9A:23:FF:8C:7E:A2:01:06:DD:D1:7F:53:96:08:C1:5A:FA:E7:C0:CA:C8:44:8C:57:A7:A8:61:5F:66:0D:57:D3:B8:96:AC:B6:4A:9C:C1:EA:E8:FB:96:40:29:F6:15:30:B5:04:B0:CC:05:B6:84:C3:24:59:95:7F:A2:65:90:E5:B0:B3:1A:75:59:C4:3F:31:14:0A:D5:CC:AA:3A:85:05:52:06:32:96:07:61:DF:27:82:0C:F7:85:DB:60:31:F0:09:50:C5:B7:1A:23:E1:B0:7D:02:F5:14:1E:C9:CB:E8:7E:2A:33:04:F6:51:3F:52:98:15:E9:0B:76:47:5C:4D:4A:6B:C5:08:15:AE:F8:D1:57:E9:EA:70:14:FF:C9:45:B9:0C:7C:BC:F4:6D:E6:05:52:F9:8C:80:BB:70:56:91:0F:4B",
+ },
+ ],
+ Critical: false,
+ },
+ {
+ sectionId: "miscellaneous",
+ sectionItems: [
+ {
+ labelId: "serial-number",
+ info: "0A:06:30:42:7F:5B:BC:ED:69:57:39:65:93:B6:45:1F",
+ },
+ {
+ labelId: "signature-algorithm",
+ info: "SHA-256 with RSA Encryption",
+ },
+ { labelId: "version", info: "3" },
+ {
+ labelId: "download",
+ info: "PEM (cert)PEM (chain)",
+ },
+ ],
+ Critical: false,
+ },
+ {
+ sectionId: "fingerprints",
+ sectionItems: [
+ {
+ labelId: "sha-256",
+ info: "31:11:50:0C:4A:66:01:2C:DA:E3:33:EC:3F:CA:1C:9D:DE:45:C9:54:44:0E:7E:E4:13:71:6B:FF:36:63:C0:74",
+ },
+ {
+ labelId: "sha-1",
+ info: "CA:06:F5:6B:25:8B:7A:0D:4F:2B:05:47:09:39:47:86:51:15:19:84",
+ },
+ ],
+ Critical: false,
+ },
+ {
+ sectionId: "basic-constraints",
+ sectionItems: [{ labelId: "certificate-authority", info: false }],
+ Critical: true,
+ },
+ {
+ sectionId: "key-usages",
+ sectionItems: [
+ {
+ labelId: "purposes",
+ info: ["Digital Signature", "Key Encipherment"],
+ },
+ ],
+ Critical: true,
+ },
+ {
+ sectionId: "extended-key-usages",
+ sectionItems: [
+ {
+ labelId: "purposes",
+ info: ["Server Authentication", "Client Authentication"],
+ },
+ ],
+ Critical: false,
+ },
+ {
+ sectionId: "subject-key-id",
+ sectionItems: [
+ {
+ labelId: "key-id",
+ info: "C9:C2:53:61:66:9D:5F:AB:25:F4:26:CD:0F:38:9A:A8:49:EA:48:A9",
+ },
+ ],
+ Critical: false,
+ },
+ {
+ sectionId: "authority-key-id",
+ sectionItems: [
+ {
+ labelId: "key-id",
+ info: "3D:D3:50:A5:D6:A0:AD:EE:F3:4A:60:0A:65:D3:21:D4:F8:F8:D6:0F",
+ },
+ ],
+ Critical: false,
+ },
+ {
+ sectionId: "crl-endpoints",
+ sectionItems: [
+ {
+ labelId: "distribution-point",
+ info: "http://crl3.digicert.com/sha2-ev-server-g2.crl",
+ },
+ {
+ labelId: "distribution-point",
+ info: "http://crl4.digicert.com/sha2-ev-server-g2.crl",
+ },
+ ],
+ Critical: false,
+ },
+ {
+ sectionId: "authority-info-aia",
+ sectionItems: [
+ { labelId: "location", info: "http://ocsp.digicert.com" },
+ {
+ labelId: "method",
+ info: "Online Certificate Status Protocol (OCSP)",
+ },
+ {
+ labelId: "location",
+ info: "http://cacerts.digicert.com/DigiCertSHA2ExtendedValidationServerCA.crt",
+ },
+ { labelId: "method", info: "CA Issuers" },
+ ],
+ Critical: false,
+ },
+ {
+ sectionId: "certificate-policies",
+ sectionItems: [
+ {
+ labelId: "policy",
+ info: "ANSI Organizational Identifier ( 2.16.840 )",
+ },
+ { labelId: "value", info: "2.16.840.1.114412.2.1" },
+ {
+ labelId: "qualifier",
+ info: "Practices Statement ( 1.3.6.1.5.5.7.2.1 )",
+ },
+ { labelId: "value", info: "https://www.digicert.com/CPS" },
+ { labelId: "policy", info: "Certificate Type ( 2.23.140.1.1 )" },
+ { labelId: "value", info: "Extended Validation" },
+ ],
+ Critical: false,
+ },
+ {
+ sectionId: "embedded-scts",
+ sectionItems: [
+ {
+ labelId: "logid",
+ info: "A4:B9:09:90:B4:18:58:14:87:BB:13:A2:CC:67:70:0A:3C:35:98:04:F9:1B:DF:B8:E3:77:CD:0E:C8:0D:DC:10",
+ },
+ { labelId: "name", info: "Google “Pilot”" },
+ { labelId: "signaturealgorithm", info: "SHA-256 ECDSA" },
+ { labelId: "version", info: 1 },
+ {
+ labelId: "timestamp",
+ info: {
+ local: "5/8/2018, 5:12:39 PM (Brasilia Standard Time)",
+ utc: "Tue, 08 May 2018 20:12:39 GMT",
+ },
+ },
+ {
+ labelId: "logid",
+ info: "56:14:06:9A:2F:D7:C2:EC:D3:F5:E1:BD:44:B2:3E:C7:46:76:B9:BC:99:11:5C:C0:EF:94:98:55:D6:89:D0:DD",
+ },
+ { labelId: "name", info: "DigiCert Server" },
+ { labelId: "signaturealgorithm", info: "SHA-256 ECDSA" },
+ { labelId: "version", info: 1 },
+ {
+ labelId: "timestamp",
+ info: {
+ local: "5/8/2018, 5:12:39 PM (Brasilia Standard Time)",
+ utc: "Tue, 08 May 2018 20:12:39 GMT",
+ },
+ },
+ {
+ labelId: "logid",
+ info: "BB:D9:DF:BC:1F:8A:71:B5:93:94:23:97:AA:92:7B:47:38:57:95:0A:AB:52:E8:1A:90:96:64:36:8E:1E:D1:85",
+ },
+ { labelId: "name", info: "Google “Skydiver”" },
+ { labelId: "signaturealgorithm", info: "SHA-256 ECDSA" },
+ { labelId: "version", info: 1 },
+ {
+ labelId: "timestamp",
+ info: {
+ local: "5/8/2018, 5:12:39 PM (Brasilia Standard Time)",
+ utc: "Tue, 08 May 2018 20:12:39 GMT",
+ },
+ },
+ ],
+ Critical: false,
+ },
+ ],
+ tabName: "github.com",
+ },
+];
diff --git a/toolkit/components/certviewer/tests/browser/browser.toml b/toolkit/components/certviewer/tests/browser/browser.toml
new file mode 100644
index 0000000000..c4fb2be753
--- /dev/null
+++ b/toolkit/components/certviewer/tests/browser/browser.toml
@@ -0,0 +1,38 @@
+[DEFAULT]
+support-files = [
+ "head.js",
+ "adjustedCerts.js",
+]
+
+["browser_aboutcertificateviewer.js"]
+
+["browser_certificateTabLink.js"]
+
+["browser_checkAuthorityKeyID.js"]
+
+["browser_checkLongHex.js"]
+
+["browser_checkMissingCommonName.js"]
+
+["browser_checkNonEmptyFields.js"]
+
+["browser_checkNonRepeatedCertTabs.js"]
+
+["browser_checkNonUndefinedStrings.js"]
+
+["browser_checkOCSP.js"]
+skip-if = ["true"] # Bug 1596313
+
+["browser_checkStandAlonePage.js"]
+
+["browser_checkValiditySection.js"]
+
+["browser_downloadLink.js"]
+
+["browser_handleMultipleCertsURL.js"]
+skip-if = ["true"] # Bug 1626853
+
+["browser_openTabAndSendCertInfo.js"]
+support-files = ["dummy_page.html"]
+
+["browser_renderCertToUI.js"]
diff --git a/toolkit/components/certviewer/tests/browser/browser_aboutcertificateviewer.js b/toolkit/components/certviewer/tests/browser/browser_aboutcertificateviewer.js
new file mode 100644
index 0000000000..efd78fc6f5
--- /dev/null
+++ b/toolkit/components/certviewer/tests/browser/browser_aboutcertificateviewer.js
@@ -0,0 +1,81 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const validCert =
+ "about:certificate?cert=MIIGMDCCBRigAwIBAgIQCa2oS7Nau6nwv1WyRNIJnzANBgkqhkiG9w0BAQsFADBwMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNzdXJhbmNlIFNlcnZlciBDQTAeFw0xOTA2MDYwMDAwMDBaFw0xOTA5MDQxMjAwMDBaMGExCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTETMBEGA1UEBxMKTWVubG8gUGFyazEXMBUGA1UEChMORmFjZWJvb2ssIEluYy4xFzAVBgNVBAMMDiouZmFjZWJvb2suY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEALPlfjd8gHkIMDeBOFhRt0e%2B%2F3fdm%2BZdzdM4s1WIHVbYztgmdEy20PUwDCviYKJX4GG%2BT9ivT8kJ%2FvWl1P%2FYqOCA54wggOaMB8GA1UdIwQYMBaAFFFo%2F5CvAgd1PMzZZWRiohK4WXI7MB0GA1UdDgQWBBTsQZVRTuib7KY9w3FfOYsZHvOC9zCBxwYDVR0RBIG%2FMIG8gg4qLmZhY2Vib29rLmNvbYINbWVzc2VuZ2VyLmNvbYILKi5mYmNkbi5uZXSCCCouZmIuY29tghAqLm0uZmFjZWJvb2suY29tggZmYi5jb22CDiouZmFjZWJvb2submV0gg4qLnh4LmZiY2RuLm5ldIIOKi54ei5mYmNkbi5uZXSCDyoubWVzc2VuZ2VyLmNvbYILKi5mYnNieC5jb22CDioueHkuZmJjZG4ubmV0ggxmYWNlYm9vay5jb20wDgYDVR0PAQH%2FBAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjB1BgNVHR8EbjBsMDSgMqAwhi5odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzYuY3JsMDSgMqAwhi5odHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzYuY3JsMEwGA1UdIARFMEMwNwYJYIZIAYb9bAEBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQICMIGDBggrBgEFBQcBAQR3MHUwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBNBggrBgEFBQcwAoZBaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkhpZ2hBc3N1cmFuY2VTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH%2FBAIwADCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB1AKS5CZC0GFgUh7sTosxncAo8NZgE%2BRvfuON3zQ7IDdwQAAABay5CAaUAAAQDAEYwRAIgMwBM6q%2BdBwu2mNtMMjTEwJZZxyoUlHUEYO%2BbfkId%2F9MCIAQ2bxhnxrapYv74fzyoTkt9m%2BELq6%2B43OVpivRVKDKTAHcAdH7agzGtMxCRIZzOJU9CcMK%2F%2FV5CIAjGNzV55hB7zFYAAAFrLkIA%2FAAABAMASDBGAiEA0x1xPWue6RMSE9nbjYBt637CRC86ixrODP%2FEIlI5mCgCIQCHNdqgOlswd0LqaW4QRii2JHN4bnoEj%2FD9j7%2BkqEB7LjANBgkqhkiG9w0BAQsFAAOCAQEAnRdIVNZ850s7IvLgg%2BU9kKxA18kLKVpIF%2FrJHkXTkymvBHKAGOFNfzqF2YxHFhkDMIuoMO2F%2BA1E0Eo8zb1atL6%2FL59broEHTOH6xFmJAlZW0h6mZg8iRJ9Ae0pTN%2FfowaoN9aFVRnVr9ccKhOdqsXYyEZ3Ze39sEwx7Uau9KhzyuJW12Jh3S%2BZJYUdBADeeJNL5ZXSUFIyjgkwSQZPaaWAzSGHZFt3sWhMjdNoBkjRJFlASLDM3m1ZWsKA47vuXvJc%2FDXT35lC1DJmyhYb9qNPR71a1hJ8TS7vUwdDd%2BdEHiJj2wQLV3m7Tn7YvWyJOEyi4n6%2FrPqT44LZmgK7HWw%3D%3D&cert=MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBsMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3VyYW5jZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC24C%2FCJAbIbQRf1%2B8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU%2BUDlqUH1VWtMICKq%2FQmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK%2FIHe1NnF9Xt4ZQaJn1itrSxwUfqJfJ3KSxgoQtxq2lnMcZgqaFD15EWCo3j%2F018QsIJzJa9buLnqS9UdAn4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I%2B4G3FhahnSMSTeXXkgisdaScus0Xsh5ENWV%2FUyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcftbZvySC%2FzA%2FWiaJJTL17jAgMBAAGjggFJMIIBRTASBgNVHRMBAf8ECDAGAQH%2FAgEAMA4GA1UdDwEB%2FwQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAdBgNVHQ4EFgQUUWj%2FkK8CB3U8zNllZGKiErhZcjswHwYDVR0jBBgwFoAUsT7DaQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwdaOpKj4PWUS%2BNa0QWnqxj9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk%2FgNHE%2Br1hspZcX30BJZr01lYPf7TMSVcGDiEo%2Bafgv2MW5gxTs14nhr9hctJqvIni5ly%2FD6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zuxICaEnL6VpPX%2F78whQYwvwt%2FTv9XBZ0k7YXDK%2FumdaisLRbvfXknsuvCnQsH6qqF0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY%2B3sAzm2fTYS5yh%2BRp%2FBIAV0AecPUeybQ%3D&cert=MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm%2B9S75S0tMqbf5YE%2Fyc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG%2B%2BMXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx%2BmM0aBhakaHPQNAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH%2FBAQDAgGGMA8GA1UdEwEB%2FwQFMAMBAf8wHQYDVR0OBBYEFLE%2Bw2kD%2BL9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE%2Bw2kD%2BL9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe%2FEW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9%2BMpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2Yzi9RKR%2F5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2%2FS6cCZdkGCevEsXCS%2B0yx5DaMkHJ8HSXPfqIbloEpw8nL%2Be%2FIBcm2PN7EeqJSdnoDfzAIJ9VNep%2BOkuE6N36B9K";
+
+const invalidCert = "about:certificate?cert=MIIH";
+
+const pem_to_der_error = "about:certificate?cert=MIIHQ";
+
+const error_parsing_cert =
+ "about:certificate?cert=MIIHQjCCBiqgAwIBAgIQCgYwQn9bvO11MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTQwMgYDVQQDEytEaWdpQ2VydCBTSEEyIEV4dGVuZGVkIFZhbGlkYXRpb24gU2VydmVyIENBMB4XDTE4MDUwODAwMDAwMFoXDTIwMDYwMzEyMDAwMFowgccxHTAbBgNVBA8MFFByaXZhdGUgT3JnYW5pemF0aW9uMRMwEQYLKwYBBAGCNzwCAQMTAlVTMRkwFwYLKwYBBAGCNzwCAQITCERlbGF3YXJlMRAwDgYDVQQFEwc1MTU3NTUwMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEVMBMGA1UEChMMR2l0SHViLCBJbmMuMRMwEQYDVQQDEwpnaXRodWIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxjyq8jyXDDrBTyitcnB90865tWBzpHSbindG%2FXqYQkzFMBlXmqkzC%2BFdTRBYyneZw5Pz%2BXWQvL%2B74JW6LsWNc2EF0xCEqLOJuC9zjPAqbr7uroNLghGxYf13YdqbG5oj%2F4x%2BogEG3dF%2FU5YIwVr658DKyESMV6eoYV9mDVfTuJastkqcwero%2B5ZAKfYVMLUEsMwFtoTDJFmVf6JlkOWwsxp1WcQ%2FMRQK1cyqOoUFUgYylgdh3yeCDPeF22Ax8AlQxbcaI%2BGwfQL1FB7Jy%2Bh%2BKjME9lE%2FUpgV6Qt2R1xNSmvFCBWu%2BNFX6epwFP%2FJRbkMfLz0beYFUvmMgLtwVpEPSwIDAQABo4IDeTCCA3UwHwYDVR0jBBgwFoAUPdNQpdagre7zSmAKZdMh1Pj41g8wHQYDVR0OBBYEFMnCU2FmnV%2BrJfQmzQ84mqhJ6kipMCUGA1UdEQQeMByCCmdpdGh1Yi5jb22CDnd3dy5naXRodWIuY29tMA4GA1UdDwEB%2FwQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdQYDVR0fBG4wbDA0oDKgMIYuaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItZXYtc2VydmVyLWcyLmNybDA0oDKgMIYuaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItZXYtc2VydmVyLWcyLmNybDBLBgNVHSAERDBCMDcGCWCGSAGG%2FWwCATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAcGBWeBDAEBMIGIBggrBgEFBQcBAQR8MHowJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBSBggrBgEFBQcwAoZGaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkV4dGVuZGVkVmFsaWRhdGlvblNlcnZlckNBLmNydDAMBgNVHRMBAf8EAjAAMIIBfgYKKwYBBAHWeQIEAgSCAW4EggFqAWgAdgCkuQmQtBhYFIe7E6LMZ3AKPDWYBPkb37jjd80OyA3cEAAAAWNBYm0KAAAEAwBHMEUCIQDRZp38cTWsWH2GdBpe%2FuPTWnsu%2Fm4BEC2%2BdIcvSykZYgIgCP5gGv6yzaazxBK2NwGdmmyuEFNSg2pARbMJlUFgU5UAdgBWFAaaL9fC7NP14b1Esj7HRna5vJkRXMDvlJhV1onQ3QAAAWNBYm0tAAAEAwBHMEUCIQCi7omUvYLm0b2LobtEeRAYnlIo7n6JxbYdrtYdmPUWJQIgVgw1AZ51vK9ENinBg22FPxb82TvNDO05T17hxXRC2IYAdgC72d%2B8H4pxtZOUI5eqkntHOFeVCqtS6BqQlmQ2jh7RhQAAAWNBYm3fAAAEAwBHMEUCIQChzdTKUU2N%2BXcqcK0OJYrN8EYynloVxho4yPk6Dq3EPgIgdNH5u8rC3UcslQV4B9o0a0w204omDREGKTVuEpxGeOQwDQYJKoZIhvcNAQELBQADggEBAHAPWpanWOW%2Fip2oJ5grAH8mqQfaunuCVE%2Bvac%2B88lkDK%2FLVdFgl2B6kIHZiYClzKtfczG93hWvKbST4NRNHP9LiaQqdNC17e5vNHnXVUGw%2ByxyjMLGqkgepOnZ2Rb14kcTOGp4i5AuJuuaMwXmCo7jUwPwfLe1NUlVBKqg6LK0Hcq4K0sZnxE8HFxiZ92WpV2AVWjRMEc%2F2z2shNoDvxvFUYyY1Oe67xINkmyQKc%2BygSBZzyLnXSFVWmHr3u5dcaaQGGAR42v6Ydr4iL38Hd4dOiBma%2BFXsXBIqWUjbST4VXmdaol7uzFMojA4zkxQDZAvF5XgJlAFadfySna%2Fteik%3D";
+
+async function checkForErrorSection(infoMessage, url, errorMessage, testType) {
+ info(infoMessage);
+
+ await BrowserTestUtils.withNewTab(url, async function (browser) {
+ await SpecialPowers.spawn(
+ browser,
+ [{ errorMessage, testType }],
+ async function ({ errorMessage, testType }) {
+ let errorSection;
+
+ if (testType === "invalid") {
+ await ContentTaskUtils.waitForCondition(() => {
+ return (errorSection = content.document
+ .querySelector("certificate-section")
+ .shadowRoot.querySelector("error-section"));
+ }, errorMessage);
+ ok(errorSection, errorMessage);
+ } else if (testType === "valid") {
+ ok(!errorSection, errorMessage);
+ }
+ }
+ );
+ });
+}
+
+add_task(async function test_checkForErrorSection() {
+ let itemsToTest = [
+ {
+ testType: "valid",
+ url: validCert,
+ infoMessage: "Testing for error when a valid certificate is provided.",
+ errorMessage:
+ "Error section should not be visible when URL contains a valid certificate.",
+ },
+ {
+ testType: "invalid",
+ url: invalidCert,
+ infoMessage: "Testing for error when invalid certificate is provided.",
+ errorMessage:
+ "Error section should be visible when certificate is invalid.",
+ },
+ {
+ testType: "invalid",
+ url: pem_to_der_error,
+ infoMessage: "Testing for error when PEM to DIR error occurs.",
+ errorMessage:
+ "Error section should be visible when PEM to DIR error occurs.",
+ },
+ {
+ testType: "invalid",
+ url: error_parsing_cert,
+ infoMessage: "Testing for error when parsing error occurs.",
+ errorMessage:
+ "Error section should be visible when parsing error occurs.",
+ },
+ ];
+
+ for (let i = 0; i < itemsToTest.length; i++) {
+ let item = itemsToTest[i];
+ await checkForErrorSection(
+ item.infoMessage,
+ item.url,
+ item.errorMessage,
+ item.testType
+ );
+ }
+});
diff --git a/toolkit/components/certviewer/tests/browser/browser_certificateTabLink.js b/toolkit/components/certviewer/tests/browser/browser_certificateTabLink.js
new file mode 100644
index 0000000000..9c88d2bb03
--- /dev/null
+++ b/toolkit/components/certviewer/tests/browser/browser_certificateTabLink.js
@@ -0,0 +1,61 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const validCert =
+ "about:certificate?cert=MIIGMDCCBRigAwIBAgIQCa2oS7Nau6nwv1WyRNIJnzANBgkqhkiG9w0BAQsFADBwMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNzdXJhbmNlIFNlcnZlciBDQTAeFw0xOTA2MDYwMDAwMDBaFw0xOTA5MDQxMjAwMDBaMGExCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTETMBEGA1UEBxMKTWVubG8gUGFyazEXMBUGA1UEChMORmFjZWJvb2ssIEluYy4xFzAVBgNVBAMMDiouZmFjZWJvb2suY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEALPlfjd8gHkIMDeBOFhRt0e%2B%2F3fdm%2BZdzdM4s1WIHVbYztgmdEy20PUwDCviYKJX4GG%2BT9ivT8kJ%2FvWl1P%2FYqOCA54wggOaMB8GA1UdIwQYMBaAFFFo%2F5CvAgd1PMzZZWRiohK4WXI7MB0GA1UdDgQWBBTsQZVRTuib7KY9w3FfOYsZHvOC9zCBxwYDVR0RBIG%2FMIG8gg4qLmZhY2Vib29rLmNvbYINbWVzc2VuZ2VyLmNvbYILKi5mYmNkbi5uZXSCCCouZmIuY29tghAqLm0uZmFjZWJvb2suY29tggZmYi5jb22CDiouZmFjZWJvb2submV0gg4qLnh4LmZiY2RuLm5ldIIOKi54ei5mYmNkbi5uZXSCDyoubWVzc2VuZ2VyLmNvbYILKi5mYnNieC5jb22CDioueHkuZmJjZG4ubmV0ggxmYWNlYm9vay5jb20wDgYDVR0PAQH%2FBAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjB1BgNVHR8EbjBsMDSgMqAwhi5odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzYuY3JsMDSgMqAwhi5odHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzYuY3JsMEwGA1UdIARFMEMwNwYJYIZIAYb9bAEBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQICMIGDBggrBgEFBQcBAQR3MHUwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBNBggrBgEFBQcwAoZBaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkhpZ2hBc3N1cmFuY2VTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH%2FBAIwADCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB1AKS5CZC0GFgUh7sTosxncAo8NZgE%2BRvfuON3zQ7IDdwQAAABay5CAaUAAAQDAEYwRAIgMwBM6q%2BdBwu2mNtMMjTEwJZZxyoUlHUEYO%2BbfkId%2F9MCIAQ2bxhnxrapYv74fzyoTkt9m%2BELq6%2B43OVpivRVKDKTAHcAdH7agzGtMxCRIZzOJU9CcMK%2F%2FV5CIAjGNzV55hB7zFYAAAFrLkIA%2FAAABAMASDBGAiEA0x1xPWue6RMSE9nbjYBt637CRC86ixrODP%2FEIlI5mCgCIQCHNdqgOlswd0LqaW4QRii2JHN4bnoEj%2FD9j7%2BkqEB7LjANBgkqhkiG9w0BAQsFAAOCAQEAnRdIVNZ850s7IvLgg%2BU9kKxA18kLKVpIF%2FrJHkXTkymvBHKAGOFNfzqF2YxHFhkDMIuoMO2F%2BA1E0Eo8zb1atL6%2FL59broEHTOH6xFmJAlZW0h6mZg8iRJ9Ae0pTN%2FfowaoN9aFVRnVr9ccKhOdqsXYyEZ3Ze39sEwx7Uau9KhzyuJW12Jh3S%2BZJYUdBADeeJNL5ZXSUFIyjgkwSQZPaaWAzSGHZFt3sWhMjdNoBkjRJFlASLDM3m1ZWsKA47vuXvJc%2FDXT35lC1DJmyhYb9qNPR71a1hJ8TS7vUwdDd%2BdEHiJj2wQLV3m7Tn7YvWyJOEyi4n6%2FrPqT44LZmgK7HWw%3D%3D&cert=MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBsMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3VyYW5jZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC24C%2FCJAbIbQRf1%2B8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU%2BUDlqUH1VWtMICKq%2FQmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK%2FIHe1NnF9Xt4ZQaJn1itrSxwUfqJfJ3KSxgoQtxq2lnMcZgqaFD15EWCo3j%2F018QsIJzJa9buLnqS9UdAn4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I%2B4G3FhahnSMSTeXXkgisdaScus0Xsh5ENWV%2FUyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcftbZvySC%2FzA%2FWiaJJTL17jAgMBAAGjggFJMIIBRTASBgNVHRMBAf8ECDAGAQH%2FAgEAMA4GA1UdDwEB%2FwQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAdBgNVHQ4EFgQUUWj%2FkK8CB3U8zNllZGKiErhZcjswHwYDVR0jBBgwFoAUsT7DaQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwdaOpKj4PWUS%2BNa0QWnqxj9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk%2FgNHE%2Br1hspZcX30BJZr01lYPf7TMSVcGDiEo%2Bafgv2MW5gxTs14nhr9hctJqvIni5ly%2FD6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zuxICaEnL6VpPX%2F78whQYwvwt%2FTv9XBZ0k7YXDK%2FumdaisLRbvfXknsuvCnQsH6qqF0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY%2B3sAzm2fTYS5yh%2BRp%2FBIAV0AecPUeybQ%3D&cert=MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm%2B9S75S0tMqbf5YE%2Fyc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG%2B%2BMXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx%2BmM0aBhakaHPQNAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH%2FBAQDAgGGMA8GA1UdEwEB%2FwQFMAMBAf8wHQYDVR0OBBYEFLE%2Bw2kD%2BL9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE%2Bw2kD%2BL9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe%2FEW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9%2BMpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2Yzi9RKR%2F5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2%2FS6cCZdkGCevEsXCS%2B0yx5DaMkHJ8HSXPfqIbloEpw8nL%2Be%2FIBcm2PN7EeqJSdnoDfzAIJ9VNep%2BOkuE6N36B9K";
+
+add_task(async function test_certificateTabLink() {
+ await BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
+ gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, validCert);
+ });
+
+ await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () {
+ let certificateTabs;
+ await ContentTaskUtils.waitForCondition(() => {
+ certificateTabs = content.document
+ .querySelector("certificate-section")
+ .shadowRoot.querySelectorAll(".certificate-tab");
+ return certificateTabs.length;
+ }, "Found certificate tabs.");
+
+ ok(certificateTabs.length, "Certificate tabs should exist.");
+
+ let issuerNameGroups = content.document
+ .querySelector("certificate-section")
+ .shadowRoot.querySelectorAll(".issuer-name");
+ let issuerNames = [];
+ for (let i = 0; i < issuerNameGroups.length; i++) {
+ issuerNames.push(
+ issuerNameGroups[i].shadowRoot.querySelector(".common-name")
+ );
+ }
+
+ for (let i = 0; i < issuerNames.length; i++) {
+ if (i < issuerNames.length - 1) {
+ issuerNames[i].shadowRoot.querySelector("a").click();
+ await ContentTaskUtils.waitForCondition(() => {
+ return certificateTabs[i + 1].classList.contains("selected");
+ }, "Clicking link should select new tab.");
+ ok(
+ certificateTabs[i + 1].classList.contains("selected"),
+ "Clicking link should select new tab."
+ );
+ } else {
+ await ContentTaskUtils.waitForCondition(() => {
+ return certificateTabs[i].classList.contains("selected");
+ }, "Clicking link should select new tab.");
+ ok(
+ certificateTabs[i].classList.contains("selected"),
+ "Clicking link should select new tab."
+ );
+ ok(
+ !issuerNames[i].shadowRoot.querySelector("a"),
+ "Final tab's issuer name should not be link."
+ );
+ }
+ }
+ });
+ gBrowser.removeCurrentTab(); // closes about:certificate
+});
diff --git a/toolkit/components/certviewer/tests/browser/browser_checkAuthorityKeyID.js b/toolkit/components/certviewer/tests/browser/browser_checkAuthorityKeyID.js
new file mode 100644
index 0000000000..a923f7acb3
--- /dev/null
+++ b/toolkit/components/certviewer/tests/browser/browser_checkAuthorityKeyID.js
@@ -0,0 +1,50 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+async function checkAuthorityKeyID(url, expectedKeyId) {
+ await BrowserTestUtils.withNewTab(url, async function (browser) {
+ await SpecialPowers.spawn(
+ browser,
+ [expectedKeyId],
+ async function (expectedKeyId) {
+ let certificateSection = await ContentTaskUtils.waitForCondition(() => {
+ return content.document.querySelector("certificate-section");
+ }, "Certificate section found");
+ let authorityKeySection =
+ certificateSection.shadowRoot.querySelector(".authority-key-id");
+ let subjectNameSection =
+ certificateSection.shadowRoot.querySelector(".subject-name");
+ if (!expectedKeyId) {
+ Assert.equal(authorityKeySection, null, "authorityKeySection found");
+ Assert.ok(subjectNameSection, "subjectNameSection found");
+ return;
+ }
+ Assert.ok(authorityKeySection, "authorityKeySection found");
+ let item = authorityKeySection.shadowRoot.querySelector("info-item");
+ Assert.ok(item, "item found");
+ let info = item.shadowRoot.querySelector(".info").textContent;
+ Assert.equal(info, expectedKeyId, "Key IDs must be equal");
+ }
+ );
+ });
+}
+
+add_task(async function test() {
+ let tests = [
+ {
+ url: "about:certificate?cert=MIIHQjCCBiqgAwIBAgIQCgYwQn9bvO1pVzllk7ZFHzANBgkqhkiG9w0BAQsFADB1MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTQwMgYDVQQDEytEaWdpQ2VydCBTSEEyIEV4dGVuZGVkIFZhbGlkYXRpb24gU2VydmVyIENBMB4XDTE4MDUwODAwMDAwMFoXDTIwMDYwMzEyMDAwMFowgccxHTAbBgNVBA8MFFByaXZhdGUgT3JnYW5pemF0aW9uMRMwEQYLKwYBBAGCNzwCAQMTAlVTMRkwFwYLKwYBBAGCNzwCAQITCERlbGF3YXJlMRAwDgYDVQQFEwc1MTU3NTUwMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEVMBMGA1UEChMMR2l0SHViLCBJbmMuMRMwEQYDVQQDEwpnaXRodWIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxjyq8jyXDDrBTyitcnB90865tWBzpHSbindG%2FXqYQkzFMBlXmqkzC%2BFdTRBYyneZw5Pz%2BXWQvL%2B74JW6LsWNc2EF0xCEqLOJuC9zjPAqbr7uroNLghGxYf13YdqbG5oj%2F4x%2BogEG3dF%2FU5YIwVr658DKyESMV6eoYV9mDVfTuJastkqcwero%2B5ZAKfYVMLUEsMwFtoTDJFmVf6JlkOWwsxp1WcQ%2FMRQK1cyqOoUFUgYylgdh3yeCDPeF22Ax8AlQxbcaI%2BGwfQL1FB7Jy%2Bh%2BKjME9lE%2FUpgV6Qt2R1xNSmvFCBWu%2BNFX6epwFP%2FJRbkMfLz0beYFUvmMgLtwVpEPSwIDAQABo4IDeTCCA3UwHwYDVR0jBBgwFoAUPdNQpdagre7zSmAKZdMh1Pj41g8wHQYDVR0OBBYEFMnCU2FmnV%2BrJfQmzQ84mqhJ6kipMCUGA1UdEQQeMByCCmdpdGh1Yi5jb22CDnd3dy5naXRodWIuY29tMA4GA1UdDwEB%2FwQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdQYDVR0fBG4wbDA0oDKgMIYuaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItZXYtc2VydmVyLWcyLmNybDA0oDKgMIYuaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItZXYtc2VydmVyLWcyLmNybDBLBgNVHSAERDBCMDcGCWCGSAGG%2FWwCATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAcGBWeBDAEBMIGIBggrBgEFBQcBAQR8MHowJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBSBggrBgEFBQcwAoZGaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkV4dGVuZGVkVmFsaWRhdGlvblNlcnZlckNBLmNydDAMBgNVHRMBAf8EAjAAMIIBfgYKKwYBBAHWeQIEAgSCAW4EggFqAWgAdgCkuQmQtBhYFIe7E6LMZ3AKPDWYBPkb37jjd80OyA3cEAAAAWNBYm0KAAAEAwBHMEUCIQDRZp38cTWsWH2GdBpe%2FuPTWnsu%2Fm4BEC2%2BdIcvSykZYgIgCP5gGv6yzaazxBK2NwGdmmyuEFNSg2pARbMJlUFgU5UAdgBWFAaaL9fC7NP14b1Esj7HRna5vJkRXMDvlJhV1onQ3QAAAWNBYm0tAAAEAwBHMEUCIQCi7omUvYLm0b2LobtEeRAYnlIo7n6JxbYdrtYdmPUWJQIgVgw1AZ51vK9ENinBg22FPxb82TvNDO05T17hxXRC2IYAdgC72d%2B8H4pxtZOUI5eqkntHOFeVCqtS6BqQlmQ2jh7RhQAAAWNBYm3fAAAEAwBHMEUCIQChzdTKUU2N%2BXcqcK0OJYrN8EYynloVxho4yPk6Dq3EPgIgdNH5u8rC3UcslQV4B9o0a0w204omDREGKTVuEpxGeOQwDQYJKoZIhvcNAQELBQADggEBAHAPWpanWOW%2Fip2oJ5grAH8mqQfaunuCVE%2Bvac%2B88lkDK%2FLVdFgl2B6kIHZiYClzKtfczG93hWvKbST4NRNHP9LiaQqdNC17e5vNHnXVUGw%2ByxyjMLGqkgepOnZ2Rb14kcTOGp4i5AuJuuaMwXmCo7jUwPwfLe1NUlVBKqg6LK0Hcq4K0sZnxE8HFxiZ92WpV2AVWjRMEc%2F2z2shNoDvxvFUYyY1Oe67xINkmyQKc%2BygSBZzyLnXSFVWmHr3u5dcaaQGGAR42v6Ydr4iL38Hd4dOiBma%2BFXsXBIqWUjbST4VXmdaol7uzFMojA4zkxQDZAvF5XgJlAFadfySna%2Fteik%3D",
+ expectedKeyId:
+ "3D:D3:50:A5:D6:A0:AD:EE:F3:4A:60:0A:65:D3:21:D4:F8:F8:D6:0F",
+ },
+ {
+ url: "about:certificate?cert=MIIGdjCCBF6gAwIBAgIBJjANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJKRTEPMA0GA1UECAwGSmVyc2V5MRUwEwYDVQQKDAx0Z2hvc3QuY28udWsxFTATBgNVBAMMDHRnaG9zdC5jby51azEmMCQGCSqGSIb3DQEJARYXcG9zdG1hc3RlckB0Z2hvc3QuY28udWswHhcNMTkxMTE4MjE1NjAwWhcNMjAxMTE3MjE1NjAwWjBRMQswCQYDVQQGEwJKRTEPMA0GA1UECAwGSmVyc2V5MRUwEwYDVQQKDAx0Z2hvc3QuY28udWsxGjAYBgNVBAMMEW1haWwudGdob3N0LmNvLnVrMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0CS0dR6hyjv4o6s4%2FI2VT43DCfylcaq%2F6%2B5tUn6xMDtf0tYMXPjG%2FGjtlXQk2Jq7wa%2FlRR%2Fzs8c6037BZ7wzu8Wx2i6tvRLZZSlzM2mRHxaRRDYTeHyovanhCFzKqnvi30bxKugQ3lETBK5eP7ppVpcHz58lx%2B%2BFovPOBx6SRaz4EiceUybZwFpKxUJmlhivT2MJTKM5NHF4n27vszM0dyu2qXLzhpy5dgklMEEhdnHFCT%2F9YPN7uLCvzJnCo9N%2FeWf84odJ%2FjTiEKm5NG6SGDuOZ%2FbY9KwQ8nAk26zeTkw%2BMfMXD2Rl76ZFg%2B07bpckSTiaCtLGGhbgLrqEdgNGTpz1Pu3uFjhR4QsfUsDAaSvgns0PT6eSA152cgOtin2SYo%2B4UVjVdM5d%2ByB0JgEIGHmiCRQkDdCD9%2FNZBhrnG2Xwooe64QzD5OjNS8yQSCPvjfivbSk1ulcIGjgxC0z1Ot4hc%2ByuU8aRE0ekIOf5EUEjZfJ%2FnO4EXT3J5en0CYurswJM7miOsVEiO1OIut022T00MoAF%2F%2FWP73qVW3Jbv6X0pzOBYDY3osyje4n6JRqujhPEOR0MNiaZxfz4JFNPAzi0Tq6qORbXbLgGBqPFvKh2KKIMGysfRqLlETI1lpqsHyhMxgllQW9IK33kwK9y0HgluEZvc58dvle8hOS4NK8CAwEAAaOCATQwggEwMAkGA1UdEwQCMAAwHQYDVR0OBBYEFORJOggtlruQ1S6vzucFiAS86CadMIGQBgNVHSMEgYgwgYWheKR2MHQxCzAJBgNVBAYTAkpFMQ8wDQYDVQQIDAZKZXJzZXkxFTATBgNVBAoMDHRnaG9zdC5jby51azEVMBMGA1UEAwwMdGdob3N0LmNvLnVrMSYwJAYJKoZIhvcNAQkBFhdwb3N0bWFzdGVyQHRnaG9zdC5jby51a4IJAMeNizC6cTabMDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly93d3cudGdob3N0LmNvLnVrL2NhL2NybC5wZW0wCwYDVR0PBAQDAgP4MBEGCWCGSAGG%2BEIBAQQEAwIE8DAcBgNVHREEFTATghFtYWlsLnRnaG9zdC5jby51azANBgkqhkiG9w0BAQsFAAOCAgEAKZC9pqgU9MPssbNeJhKeGcCoH49BhfhrJNPkWqlJ%2FVbUB32m8p%2F7exaqFEe%2Fk2YwV8ILMA%2FCvQLgeV36Y9rHcWKqaA8lrklhRkK6%2BfYkAkpw37vVbm8qWsTt4OMa0Ajh%2F7QBy%2FUqak8Gaarl3LkJKLKB3Pj%2Bd2BFNxNm5W3TeFia2s%2B5y0O0eKqSQwRPqlQo3qhNQU1fDimTq8yI3fH9AOByWXHePjSc5h45GHxWoXPqQKtuqCINou6pKeZa1KoTCefB2oYJqamkneL2%2B21JhwkSVkGUfseGc2hiROVLejc%2Fgzq7mpUqudOsyN672BwB6W81w6%2FHCt2cZmCTWAAT5E3b6bHqqTTn9O2uljx2zTxao5Xov4L9EZ3hdccsLJGXHYgGDqY33e6Rrf86Jc%2BV%2F4%2FL8vhGf%2B70ASKLkibUuGwFJ0%2BamQHoHnVXLZ5rnbV3ArXOQcsfegTifmEPn7pGyHm7r5%2BkJ2JIh8wCyl5B%2FUxvNwIfAFEiieU3aqRAgbjnezYXwoLoLJBKSRMXdIfZJldduIkoPaeO0zWWaJSMon3qTAeDuboM4EfYG9Ma3UWdznXVkmgiXFo%2Fz6k%2Bg4jNzaQknI8jNHbp9G5K7M9KPcvUja8hjeGG4RIULKDdkauZUe1hX6m3NrzrJLD3MJPD8YTFeAf%2Fe3HCGwl4stKWHg4%3D&cert=MIIFZDCCA0wCCQDHjYswunE2mzANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJKRTEPMA0GA1UECAwGSmVyc2V5MRUwEwYDVQQKDAx0Z2hvc3QuY28udWsxFTATBgNVBAMMDHRnaG9zdC5jby51azEmMCQGCSqGSIb3DQEJARYXcG9zdG1hc3RlckB0Z2hvc3QuY28udWswHhcNMTgwNDA4MTIyMjU0WhcNMjMwNDA4MTIyMjU0WjB0MQswCQYDVQQGEwJKRTEPMA0GA1UECAwGSmVyc2V5MRUwEwYDVQQKDAx0Z2hvc3QuY28udWsxFTATBgNVBAMMDHRnaG9zdC5jby51azEmMCQGCSqGSIb3DQEJARYXcG9zdG1hc3RlckB0Z2hvc3QuY28udWswggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCoFbHy44GNOQSymk%2BwAmZmllcAATSM6DrsW7NZgX8vHeP5OAlRaGaOgVmozKcbKSB2KSIvDvY1%2BKEKtfr5meIaeA6r%2BILeUYuNxQomnW3Oy%2B%2B7RFE53pS7R7QIt%2FLVf3k60mdZDLXF1wyFv950noGNrFZfvBvND1%2F88JeC4Gt7dVnJMy9CXOr7V0O%2F7sa5z%2Bvfm2Acufd1RYA3W%2FECbt%2F6z8KV%2FQthAgcYoabQgkmh8AxQ5cG7tBmoEAs%2BNwU%2BR8eMq1f%2B6TBCJiMa07jA1%2BQ663d7YONlk4fTSmvo3lEhXtrR%2BmrkxZAMiAD6NJs3VakcuAED9e1dS3G3%2FmPcNrKsa73aXEC5uvL9y4mKCZLypuSYjlW8cP5JpCG6vtmwL%2FATbcCtwpDwrKLcRWCrZdX0FOJirjWfKL%2BhyIWayQ5u7awdhH430h8rj03fXSMBhtTn73rohSGIANBnqVftvDDPnEQb5p17giaVbJybfA2tdMvJTZg6pEAx9%2B3zHXRECFpWOtaJDjWbmIExPMgiCSFkBPP3MEDVb7VdHKZs0CvBQg6GmpXg9M4OHZylzS6PXXO8qBCtBdKOwdFSZWbeD9E652rkvb5FuQ8laGHcxgMc2YFlVZaqVowXEkVkkld12d4sBipeRpDWNjA2kLfeUmwsXWtugG8c8Jm9IoZY8oeUkwIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQCVj6R9C5pE9hkBx7CCr9l4TLoolaEZlKngJHBRRSy5U50MndQ24Jeis2OTxEeYX7DJ%2BOy6QZdaph6FLwALxUWPfQavBcgauKR%2FCdqLQxZc267TMFkRIZvOtHUJ4obJ5qvQAWzNnmRq18b5plznfBfn9b3F2AmHgfsNX6WryQ4geR786VObcUhKTaofcaX%2FE4J9AVzL864fJ%2FDB%2FPSqhYrtskiG6PT9Ngu20ejvgAVk5aJ%2F%2F5Swsjyg6EBl%2BdwJepq2xzI313ZkwCg2pp6oqLDlxf%2Fh585Bsqke39Ax%2B42NWNM14cethcJ7jgyZoEaL3T%2BQ3O%2Bj9XEe5FbvkKtSgMIA6f0FneA4vbF8%2FECPMEi7k3k04gU1gZSR%2FGA63GPEK%2FCLqeh%2BYVgBGKDPinnMEV%2FuBrTUDQFBlDEHlELk7F9o93lxQNs6WOGQSfybfHhySla3nqoYV2phyeZZsJ%2BxMovWWIydJhVN%2F37v0fYTZhnlquGenXHvC5MHrMq2vjUY0Uy637AzXWVNWveNyQmmn9tL4jygELHQu%2Bint4GRybH7rThcslv63D5s4zZza7cITIFjmqZ%2BPrTSVKL%2BlnQLjEMpSdfB86Y2JnMimaOyv%2BbZp1QMB5fYh0PTsjYATi9We%2BDFD42c5H7Su0vFAwCTP11AiKzfbj2oBKVVwwJj3FmkYQ%3D%3D",
+ expectedKeyId: false,
+ },
+ ];
+
+ for (let test of tests) {
+ await checkAuthorityKeyID(test.url, test.expectedKeyId);
+ }
+});
diff --git a/toolkit/components/certviewer/tests/browser/browser_checkLongHex.js b/toolkit/components/certviewer/tests/browser/browser_checkLongHex.js
new file mode 100644
index 0000000000..01b54c083b
--- /dev/null
+++ b/toolkit/components/certviewer/tests/browser/browser_checkLongHex.js
@@ -0,0 +1,38 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+async function checkLongHex(url, itemClass) {
+ await BrowserTestUtils.withNewTab(url, async function (browser) {
+ await SpecialPowers.spawn(browser, [itemClass], async function (itemClass) {
+ let certificateSection = await ContentTaskUtils.waitForCondition(() => {
+ return content.document.querySelector("certificate-section");
+ }, "Certificate section found");
+ let publicKeyInfoSection =
+ certificateSection.shadowRoot.querySelector(".public-key-info");
+ Assert.ok(publicKeyInfoSection, "publicKeyInfoSection found");
+
+ let item = publicKeyInfoSection.shadowRoot.querySelector(`.${itemClass}`);
+ Assert.ok(item, `item ${itemClass} found`);
+
+ let longHex = item.shadowRoot.querySelector(".long-hex");
+ Assert.ok(longHex, "longHex class name found");
+ });
+ });
+}
+
+add_task(async function test() {
+ let tests = [
+ {
+ url: "about:certificate?cert=MIIHQjCCBiqgAwIBAgIQCgYwQn9bvO1pVzllk7ZFHzANBgkqhkiG9w0BAQsFADB1MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTQwMgYDVQQDEytEaWdpQ2VydCBTSEEyIEV4dGVuZGVkIFZhbGlkYXRpb24gU2VydmVyIENBMB4XDTE4MDUwODAwMDAwMFoXDTIwMDYwMzEyMDAwMFowgccxHTAbBgNVBA8MFFByaXZhdGUgT3JnYW5pemF0aW9uMRMwEQYLKwYBBAGCNzwCAQMTAlVTMRkwFwYLKwYBBAGCNzwCAQITCERlbGF3YXJlMRAwDgYDVQQFEwc1MTU3NTUwMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEVMBMGA1UEChMMR2l0SHViLCBJbmMuMRMwEQYDVQQDEwpnaXRodWIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxjyq8jyXDDrBTyitcnB90865tWBzpHSbindG%2FXqYQkzFMBlXmqkzC%2BFdTRBYyneZw5Pz%2BXWQvL%2B74JW6LsWNc2EF0xCEqLOJuC9zjPAqbr7uroNLghGxYf13YdqbG5oj%2F4x%2BogEG3dF%2FU5YIwVr658DKyESMV6eoYV9mDVfTuJastkqcwero%2B5ZAKfYVMLUEsMwFtoTDJFmVf6JlkOWwsxp1WcQ%2FMRQK1cyqOoUFUgYylgdh3yeCDPeF22Ax8AlQxbcaI%2BGwfQL1FB7Jy%2Bh%2BKjME9lE%2FUpgV6Qt2R1xNSmvFCBWu%2BNFX6epwFP%2FJRbkMfLz0beYFUvmMgLtwVpEPSwIDAQABo4IDeTCCA3UwHwYDVR0jBBgwFoAUPdNQpdagre7zSmAKZdMh1Pj41g8wHQYDVR0OBBYEFMnCU2FmnV%2BrJfQmzQ84mqhJ6kipMCUGA1UdEQQeMByCCmdpdGh1Yi5jb22CDnd3dy5naXRodWIuY29tMA4GA1UdDwEB%2FwQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdQYDVR0fBG4wbDA0oDKgMIYuaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItZXYtc2VydmVyLWcyLmNybDA0oDKgMIYuaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItZXYtc2VydmVyLWcyLmNybDBLBgNVHSAERDBCMDcGCWCGSAGG%2FWwCATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAcGBWeBDAEBMIGIBggrBgEFBQcBAQR8MHowJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBSBggrBgEFBQcwAoZGaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkV4dGVuZGVkVmFsaWRhdGlvblNlcnZlckNBLmNydDAMBgNVHRMBAf8EAjAAMIIBfgYKKwYBBAHWeQIEAgSCAW4EggFqAWgAdgCkuQmQtBhYFIe7E6LMZ3AKPDWYBPkb37jjd80OyA3cEAAAAWNBYm0KAAAEAwBHMEUCIQDRZp38cTWsWH2GdBpe%2FuPTWnsu%2Fm4BEC2%2BdIcvSykZYgIgCP5gGv6yzaazxBK2NwGdmmyuEFNSg2pARbMJlUFgU5UAdgBWFAaaL9fC7NP14b1Esj7HRna5vJkRXMDvlJhV1onQ3QAAAWNBYm0tAAAEAwBHMEUCIQCi7omUvYLm0b2LobtEeRAYnlIo7n6JxbYdrtYdmPUWJQIgVgw1AZ51vK9ENinBg22FPxb82TvNDO05T17hxXRC2IYAdgC72d%2B8H4pxtZOUI5eqkntHOFeVCqtS6BqQlmQ2jh7RhQAAAWNBYm3fAAAEAwBHMEUCIQChzdTKUU2N%2BXcqcK0OJYrN8EYynloVxho4yPk6Dq3EPgIgdNH5u8rC3UcslQV4B9o0a0w204omDREGKTVuEpxGeOQwDQYJKoZIhvcNAQELBQADggEBAHAPWpanWOW%2Fip2oJ5grAH8mqQfaunuCVE%2Bvac%2B88lkDK%2FLVdFgl2B6kIHZiYClzKtfczG93hWvKbST4NRNHP9LiaQqdNC17e5vNHnXVUGw%2ByxyjMLGqkgepOnZ2Rb14kcTOGp4i5AuJuuaMwXmCo7jUwPwfLe1NUlVBKqg6LK0Hcq4K0sZnxE8HFxiZ92WpV2AVWjRMEc%2F2z2shNoDvxvFUYyY1Oe67xINkmyQKc%2BygSBZzyLnXSFVWmHr3u5dcaaQGGAR42v6Ydr4iL38Hd4dOiBma%2BFXsXBIqWUjbST4VXmdaol7uzFMojA4zkxQDZAvF5XgJlAFadfySna%2Fteik%3D",
+ itemClass: "modulus",
+ },
+ {
+ url: "about:certificate?cert=MIIIMTCCBxmgAwIBAgIMFkDF1F0uxNlMfXxqMA0GCSqGSIb3DQEBCwUAMGYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMTwwOgYDVQQDEzNHbG9iYWxTaWduIE9yZ2FuaXphdGlvbiBWYWxpZGF0aW9uIENBIC0gU0hBMjU2IC0gRzIwHhcNMTgxMTA4MjEyMTA0WhcNMTkxMTIyMDc1OTU5WjB5MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEjMCEGA1UEChMaV2lraW1lZGlhIEZvdW5kYXRpb24sIEluYy4xGDAWBgNVBAMMDyoud2lraXBlZGlhLm9yZzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGd1rS7GauMxJ15BmViShjVMjwQJNjjw%2BOUhnIaqE5QF%2Fq6c%2FLIvVh4N3473a7J52JcfmlfCrXvDthHzaZNEneKjggWVMIIFkTAOBgNVHQ8BAf8EBAMCA4gwgaAGCCsGAQUFBwEBBIGTMIGQME0GCCsGAQUFBzAChkFodHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24uY29tL2NhY2VydC9nc29yZ2FuaXphdGlvbnZhbHNoYTJnMnIxLmNydDA%2FBggrBgEFBQcwAYYzaHR0cDovL29jc3AyLmdsb2JhbHNpZ24uY29tL2dzb3JnYW5pemF0aW9udmFsc2hhMmcyMFYGA1UdIARPME0wQQYJKwYBBAGgMgEUMDQwMgYIKwYBBQUHAgEWJmh0dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMAgGBmeBDAECAjAJBgNVHRMEAjAAMEkGA1UdHwRCMEAwPqA8oDqGOGh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vZ3MvZ3Nvcmdhbml6YXRpb252YWxzaGEyZzIuY3JsMIICxQYDVR0RBIICvDCCAriCDyoud2lraXBlZGlhLm9yZ4INd2lraW1lZGlhLm9yZ4INbWVkaWF3aWtpLm9yZ4INd2lraWJvb2tzLm9yZ4IMd2lraWRhdGEub3Jnggx3aWtpbmV3cy5vcmeCDXdpa2lxdW90ZS5vcmeCDndpa2lzb3VyY2Uub3Jngg93aWtpdmVyc2l0eS5vcmeCDndpa2l2b3lhZ2Uub3Jngg53aWt0aW9uYXJ5Lm9yZ4IXd2lraW1lZGlhZm91bmRhdGlvbi5vcmeCBncud2lraYISd21mdXNlcmNvbnRlbnQub3JnghEqLm0ud2lraXBlZGlhLm9yZ4IPKi53aWtpbWVkaWEub3JnghEqLm0ud2lraW1lZGlhLm9yZ4IWKi5wbGFuZXQud2lraW1lZGlhLm9yZ4IPKi5tZWRpYXdpa2kub3JnghEqLm0ubWVkaWF3aWtpLm9yZ4IPKi53aWtpYm9va3Mub3JnghEqLm0ud2lraWJvb2tzLm9yZ4IOKi53aWtpZGF0YS5vcmeCECoubS53aWtpZGF0YS5vcmeCDioud2lraW5ld3Mub3JnghAqLm0ud2lraW5ld3Mub3Jngg8qLndpa2lxdW90ZS5vcmeCESoubS53aWtpcXVvdGUub3JnghAqLndpa2lzb3VyY2Uub3JnghIqLm0ud2lraXNvdXJjZS5vcmeCESoud2lraXZlcnNpdHkub3JnghMqLm0ud2lraXZlcnNpdHkub3JnghAqLndpa2l2b3lhZ2Uub3JnghIqLm0ud2lraXZveWFnZS5vcmeCECoud2lrdGlvbmFyeS5vcmeCEioubS53aWt0aW9uYXJ5Lm9yZ4IZKi53aWtpbWVkaWFmb3VuZGF0aW9uLm9yZ4IUKi53bWZ1c2VyY29udGVudC5vcmeCDXdpa2lwZWRpYS5vcmcwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBSt4NNfC33t2i98DfZjjYpZGMJsijAfBgNVHSMEGDAWgBSW3mHxvRwWKVMcwMx9O4MAQOYafDCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB2AKS5CZC0GFgUh7sTosxncAo8NZgE%2BRvfuON3zQ7IDdwQAAABZvUzN%2FYAAAQDAEcwRQIgBATdvSzbd5NwGdtkmJ5SEvEPn6A8hgAsk6GSP6hzWcgCIQDKfHQNtObs%2FhHPfLgXsVkcnHIbjlNwmWeiukGtGHZFMgB2AG9Tdqwx8DEZ2JkApFEV%2F3cVHBHZAsEAKQaNsgiaN9kTAAABZvUzN8cAAAQDAEcwRQIgYalEnXtd%2FfPhjq9SXPoSPRhaMmeDs0IMN5o5Y6QTKfUCIQClR1uj%2BB56K4tGh%2Fmws4qugG1qSD9zfvmx8roKik3HHDANBgkqhkiG9w0BAQsFAAOCAQEAUEJyg%2FAZo%2BowG5J%2FLIk8EIDnyOcanmfgvdjMg8KnpBvh8l3Wb4HmOudluJhIeIbCUMwzEzSGqYQQ78n4wtjLaLwaDgL4WzHOVec2k%2BrbfmPT6MUCtdlz1PK5%2FWY9JQyQq6vy%2Btm3a6Wijy6M8U%2FTdrJubK5X03SFfRb0pDuFdr2fnkctLRnyCb1w0XHwGXjEcGm1LY42YKwdvbj3WIqumeSEuG4MZtquW6NURKELSil03G%2FhRHRAHHGx3zXes%2FjJcpH2GPX9eY9B%2BR1oHmCE2QF5Y%2FBh%2BuNA2%2B2Iuj%2F6UJAOw%2FZ%2F8%2BqZcnLWWnK2Dwzc34C%2FAUD%2BWb71oUcr60%2BpPg%3D%3D&cert=MIIEYjCCA0qgAwIBAgILBAAAAAABMYnGRMkwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTEwODAyMTAwMDAwWhcNMjIwODAyMTAwMDAwWjBmMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTE8MDoGA1UEAxMzR2xvYmFsU2lnbiBPcmdhbml6YXRpb24gVmFsaWRhdGlvbiBDQSAtIFNIQTI1NiAtIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxw5sPyOTf8xwpZ0gww5TP37ATsKYScpH1SPvAzSFdMijAi5GXAt9yYidT4vw%2BJxsjFU127%2Fys%2Br741bnSkbZEyLKNtWbwajjlkOT8gy85vnm6JnIY0h4f1c2aRoZHVrR1H3CnNR%2F4YASrnrqiOpX2MoKCjoSSaJiGXoNJPc367RzknsFI5sStc7rKd%2BkFAK5AaXUppxDZIje%2BH7%2B4%2FUe5f7co6jkZjHZTCXpGLmJWQmu6Z0cbTcPSh41ICjir9QhiwHERa1uK2OrkmthCk0g7XO6fM7%2BFrXbn4Dw1ots2Qh5Sk94ZdqSvL41%2BbPE%2BSeATv%2BWUuYCIOEHc%2BldK72y8QIDAQABo4IBKTCCASUwDgYDVR0PAQH%2FBAQDAgEGMBIGA1UdEwEB%2FwQIMAYBAf8CAQAwHQYDVR0OBBYEFJbeYfG9HBYpUxzAzH07gwBA5hp8MEcGA1UdIARAMD4wPAYEVR0gADA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzA2BgNVHR8ELzAtMCugKaAnhiVodHRwOi8vY3JsLmdsb2JhbHNpZ24ubmV0L3Jvb3QtcjMuY3JsMD4GCCsGAQUFBwEBBDIwMDAuBggrBgEFBQcwAYYiaHR0cDovL29jc3AyLmdsb2JhbHNpZ24uY29tL3Jvb3RyMzAfBgNVHSMEGDAWgBSP8Et%2FqC5FJK5NUPpjmove4t0bvDANBgkqhkiG9w0BAQsFAAOCAQEAugYpwLQZjCERwJQRnrs91NVDQPafuyULI2i1Gvf6VGTMKxP5IfBEreHoFVjb7v3bok3MGI8Nmm3DawGhMfCNvABAzDlfh2FRbfSV6uoVNT5AhcBi1aE0%2FniqqLJaOfM3Qfuc6D5xSlvr%2BGlYoeDGk3fpumeS62VYkHBzQn2v9CMmeReq%2BqS7meVEb2WB58rrVcj0ticRIXSUvGu3dGIpxM2uR%2FLmQlt4hgVhy5CqeYnfBH6xJnBLjUAfhHvA%2BwfmyLdOkfQ1A%2B3o60EQF0m0YsinLPLhTI8DLPMWN11n8aQ5eUmjwF3MVfkhgA%2F7zuIpalhQ6abX6xwyNrVip8H65g%3D%3D&cert=MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie%2FQV2EcWtiHL8RgJDx7KKnQRfJMsuS%2BFggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ0mpiLx9e%2BpZo34knlTifBtc%2BycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO%2FbLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c%2B9C7v%2FU9AOEGM%2BiCK65TpjoWc4zdQQ4gOsC0p6Hpsk%2BQLjJg6VfLuQSSaGjlOCZgdbKfd%2F%2BRFO%2BuIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH%2FBAQDAgEGMA8GA1UdEwEB%2FwQFMAMBAf8wHQYDVR0OBBYEFI%2FwS3%2BoLkUkrk1Q%2BmOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr%2ByAzv95ZURUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q%2Fc2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj%2B9xTaGdWPoO4zzUhw8lo%2Fs7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj%2B1EbddTKJd%2B82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws%2FzyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9%2BE7gUJTb0o2HLO02JQZR7rkpeDMdmztcpHWD9f",
+ itemClass: "public-value",
+ },
+ ];
+
+ for (let test of tests) {
+ await checkLongHex(test.url, test.itemClass);
+ }
+});
diff --git a/toolkit/components/certviewer/tests/browser/browser_checkMissingCommonName.js b/toolkit/components/certviewer/tests/browser/browser_checkMissingCommonName.js
new file mode 100644
index 0000000000..e26612c1b8
--- /dev/null
+++ b/toolkit/components/certviewer/tests/browser/browser_checkMissingCommonName.js
@@ -0,0 +1,50 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function test_check_missing_common_name() {
+ const kURL =
+ "about:certificate?cert=MIIHVDCCBTygAwIBAgIQOBNAgEopyUI1DYLsLmSWejANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ6KGM5pS%2F6ZmiMTUwMwYDVQQDDCzmlL%2FlupzkvLrmnI3lmajmlbjkvY3mhpHorYnnrqHnkIbkuK3lv4MgLSBHMTAeFw0yMDAxMjAwNjExMzBaFw0yMjAxMjAwNjExMzBaMFUxCzAJBgNVBAYTAlRXMQ8wDQYDVQQHDAboh7rngaMxEjAQBgNVBAoMCee4vee1seW6nDEhMB8GA1UEAwwYZW5nbGlzaC5wcmVzaWRlbnQuZ292LnR3MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyxCtEdUsGqr%2FVCNOMpj1TkDzBn6Gs1RBHHERU%2BsJ1q3ri6rJfydTx0rQKUbcGEMyWB2pga4dNSjzxQZ6%2BebP3kctC0H%2F%2BptEnsIOQcyD2yLN5yg8ejx6Y568z3fbU%2FRAVo4q6qGZzlBfzl2AhZMrp3AiNpQZXjLWgNHYZfirDVur7ImSjECq6atLlZ1yn%2B0RC%2FsGsPKalz5iacuxMYIkWeCvm7piA%2FdXPfw%2FVJxbIEkXMSXXxDNGrBZY0wAcmPeDHZxyLDGDOFLV%2Fpics3ZJ4UjFPphwaXuW94K9NKLcfOu7JaYP6JszpBIEiL8GRl8pMdykkKN%2FRkEZ%2F8pE7Tz%2BswIDAQABo4IDGzCCAxcwHwYDVR0jBBgwFoAU1ustnWH%2BK7twiC64B7FZsPSDImowHQYDVR0OBBYEFDxkjGSuIgKbFKTUvadNfX%2B%2BogdCMHUGCCsGAQUFBwEBBGkwZzA1BggrBgEFBQcwAoYpaHR0cDovL2d0bHNjYS5uYXQuZ292LnR3L0NlcnRzL0dUTFNDQS5jcnQwLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmd0bHNjYS5uYXQuZ292LnR3L09DU1AwIgYDVR0gBBswGTANBgsrBgEEAYG3I2QAAzAIBgZngQwBAgIwIAYDVR0lAQH%2FBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMCMGA1UdEQQcMBqCGGVuZ2xpc2gucHJlc2lkZW50Lmdvdi50dzAgBgNVHQkEGTAXMBUGB2CGdgFkAgExCgYIYIZ2AWQDAwEwQQYDVR0fBDowODA2oDSgMoYwaHR0cDovL2d0bHNjYS5uYXQuZ292LnR3L2NybC9HVExTQ0EtY29tcGxldGUuY3JsMA4GA1UdDwEB%2FwQEAwIFoDCCAXwGCisGAQQB1nkCBAIEggFsBIIBaAFmAHUApLkJkLQYWBSHuxOizGdwCjw1mAT5G9%2B443fNDsgN3BAAAAFvwZRvQAAABAMARjBEAiAWcMYq5U%2BiRndzk4q7XRQ10ykv%2FBlaHelk0SMi8LeXmAIgY%2BJUd3bzT5nSTCYQMOAMLGE52UWhnIRgxdWRtcg60uAAdQDuS723dc5guuFCaR%2Br4Z5mow9%2BX7By2IMAxHuJeqj9ywAAAW%2FBlHdGAAAEAwBGMEQCIAM72FPgBC6JzvE%2BEkvdp9g9Lt19fnJ6KfWQYNN%2BMylsAiBezZw%2FDzsg22O4Tr0QGYoY7HsnPzsHzxEJVUJGl8HXZQB2AG9Tdqwx8DEZ2JkApFEV%2F3cVHBHZAsEAKQaNsgiaN9kTAAABb8GUfQAAAAQDAEcwRQIgXVJY0MInclLEtJ1AoMPtjja0tvBD0zPHSAyxIgZ%2B3EECIQDTj7KrkhXuZqKr6sF0hqwr%2BiMiByMi7gNjK4DOqxJ7YjANBgkqhkiG9w0BAQsFAAOCAgEAeOXA%2FpFjaSlenGSQSMDbbSXM%2BL2nM0M1yQ8WxM2mxRfAxzyuH%2FDo1UGDmbvu1e6f%2FdA6Gr%2BAdx2EFia3FqIBrnB9BAymlMgYKq3pW67b83k8r6iF5UcwxISE4LXplY8iV12a59EUCHr0YnVUzK3gLN9ocPyGHnsRdzuowU7WRtZ2tMFAlVT2dEGPqG2ZKsIiCBRummp1vNF3b%2BB5g4Y5Hc7Vw1%2F1LgPMsaSPj5%2Fl4YdLCIO2tWYqnpA0LE8xuRXFSRA0fmlZQKr01N0%2B1ar2QRH6PcRJE3EJbgdnsIGDMithZ4a2COinwCWNkuj6lwB83RvfGOdwJfVv9ricvRpdMOs3HSQnRk0q1IreY42VVmtOGt6MfuCPaIMZtI0unkd3GHmCDcoe64HIu7sjdTCqWAR60JZpQ4oM%2BOpzfBulhf44BDh33zM7lNAlEtVN%2BtszLA2S3CCoDTHpUGWkes%2BzkI4qjG5Nd1eGZT%2FtqqWyRc799ROCEAI5SkgZgowqRgzMhkazdyDANLTbg2Edt4OT7O6zrdLg70JTZMxdJ5%2BAnDMmDr8NCH63URFJe72ZBOH4uAeZuV%2Bhbh9v1%2BF2kFaqVBh2VaRdY%2FHGpnoD%2By1bJ7FI1erKUJFt%2FP4ZEYjACkmT7Gtw8NifvECY3cw3aiAY7AMg2Bnk72ySxvBcXedVMU8%3D&cert=MIIGtjCCBJ6gAwIBAgIRAJltX%2Bmt4Wzcjs2%2F7bFKMpUwDQYJKoZIhvcNAQELBQAwYzELMAkGA1UEBhMCVFcxIzAhBgNVBAoMGkNodW5naHdhIFRlbGVjb20gQ28uLCBMdGQuMS8wLQYDVQQDDCZlUEtJIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjAeFw0xOTA3MTkwNjQ2NDVaFw0zMTA4MTkwNjQ2NDVaMFgxCzAJBgNVBAYTAlRXMRIwEAYDVQQKDAnooYzmlL%2FpmaIxNTAzBgNVBAMMLOaUv%2BW6nOS8uuacjeWZqOaVuOS9jeaGkeitieeuoeeQhuS4reW%2FgyAtIEcxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwg5R4LGoDj%2BmZIXmcHmRYv501jsSLIm7EoX%2FKAt74uN2yDR436V2EWkFeWhD%2BTS4sx2%2F3JCRW%2BKE%2BIX8NYBKjsWuK9OMY4Gu4FEWJpBu1XCWYjTPKyhHdEhDpxRxv91g3Zk68XgK7j2U5sEzCPx13QjkH7qc%2FMo5BFiro8YsYAfxgCoa%2FrZFEsXyZKXRJeIDw7t%2BiPxVy2cbQ0uNloO9670LGoOVzYVkYABv3IwZo%2BJRtj%2Bj7rLjB7xQKYmfJOA2Jc96yPm6li7zHrIQYfohGPdANmwR9opNNqYOo%2BLtsIYot3%2FcLp9YgAaiGdrAiKrbbEVkYH%2BzKzAHolf5mPBn%2Bh3OElYfygESitWRBp2bwfOGJwAYseTuorQHpyQps1GGcn9vcfnLhvLxa3DMrCAvSJb3SvHCyqahQz0KR0IPcu%2BVLW3icaqlbJausGIGYqp8VSN6FJ0pgmYdbunBLYc1v23VvjmVMl%2BxNJoaSFEUscmSqA4CuYANhkWSANk8HI9rNbvmzuyWhSv7tUXY6UB67mHp4ypGcKYbXrjiKqahv6QLUEb7S8FD71Ds75F2vMeO4O77i6joBs%2FL2E6WZJvSronzJCXL0IwmpYaOAsoFOf0eGVsPBVKn%2Bz4Bq0WA0%2Br7plfWofDbUGmx9Zun%2B%2BrWhoDXrma%2BodubN1Xj1RjlL3sCAwEAAaOCAW4wggFqMB8GA1UdIwQYMBaAFHJbuqpyOO4lkCS1lCL6CYjKiwr7MB0GA1UdDgQWBBTW6y2dYf4ru3CILrgHsVmw9IMiajAOBgNVHQ8BAf8EBAMCAYYwPAYDVR0fBDUwMzAxoC%2BgLYYraHR0cDovL2VjYS5oaW5ldC5uZXQvcmVwb3NpdG9yeS9DUkwyL0NBLmNybDCBggYIKwYBBQUHAQEEdjB0MDsGCCsGAQUFBzAChi9odHRwOi8vZWNhLmhpbmV0Lm5ldC9yZXBvc2l0b3J5L0NlcnRzL2VDQUcyLmNydDA1BggrBgEFBQcwAYYpaHR0cDovL29jc3AuZWNhLmhpbmV0Lm5ldC9PQ1NQL29jc3BHMnNoYTIwEgYDVR0TAQH%2FBAgwBgEB%2FwIBADAiBgNVHSAEGzAZMA0GCysGAQQBgbcjZAADMAgGBmeBDAECAjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggIBAEyrsJ9vUi6nEfwO0vgAoFefXpCRF%2BuDsmG%2F8F6OV9VRnbtzBwazHbxVmaBvDRVofLfoXWr%2BNd8dd3BXVUNxemNrkZa8Hdgdv4s8yFbRs0W6fRTWkhCcc39RpQtSeV7kyxCP1rMTYRSqCA9F%2BFcDMLXJIzZrzl7Tn6guIyqcfZv6sRN7CbbTrYKSc0JX4t26WGFun2zLjzH8kx1TZ457TE4yyjl1oSZdgiWL6Hz7l%2BnbTe6WqPVVm4am2AAmaQaLGncsGLasl7PIHx9Nc4sy7KdOMTc5r0BPCGhAiJ6ueQ6aVd49pra7BDIqFMA7Myy4pXRYfqFnjq9RuROWYiIluzLNUSxlaFtTMUVQnWjJxnlXlBDLX9L4OAxTOvdbtcNNS1GK%2BW1cWiYdTOWF4HTu5pvdUn%2F%2B8yVE4E7MPb0vGuxv3S11QG6JtVPuHkX6BGqRXHo253gY77HZU0g3g9qVs9UaZjWS5UTcqdgLmmOQnH7USaJ9%2F4rXRu%2FP8IWMPG2s6tv1dRVQV5xfq21PQ4y53ytVd0%2B%2Flp0L743%2B1AjnOw0I8t9QxP6c2ti%2Boo43rxM8YE3etVLQBeWsmJc00GOWa%2FXmFACsy8Lkctx0QScAAYwCfB2accfxj9hEX1c6MAeVUVp04YJx4dtjoIFTPI1%2FMFX%2BFkxMq4Fs6k%2BmxSm7tNvv&cert=MIIHZDCCBUygAwIBAgIRAK%2FNjWQsYtZFBn3IV%2F2o8V0wDQYJKoZIhvcNAQELBQAwXjELMAkGA1UEBhMCVFcxIzAhBgNVBAoMGkNodW5naHdhIFRlbGVjb20gQ28uLCBMdGQuMSowKAYDVQQLDCFlUEtJIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTUxMTE3MDg1MTM1WhcNMzQxMjIwMDIzMTI3WjBjMQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xLzAtBgNVBAMMJmVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEApFkfoC%2FfvuD76dy1if5alwPJOnenjlyv8uMYOfWq3Q9G0mgPV5ynY2DTWM41wqf2iMJPfxso6dCnAMQXTW3iD8UOJiMgq%2Fc6KKJMCgvMjs7mAJpaQA3UUBqb0Q2clPnb7lzQ8YoHzZorQCxJpF1iX6dr3%2B5WCFDzQhhsMbBe5ZxzkrwO0gx9xThXvLtY2yYZAu3jQ4SKTlZr262hMdnMImeWeP93ncxkxTIgau9OMNUkJf2Iea9xGv7VSxsViLwYcKq9rTgKZjBG5YmF1XYkqamz5llgD7SpU8I6nUUa1q7jd17EYjYzLzDEv5XxLTildejRapMuRYdLSqLfv1gnmspiGape1LGASZbdK%2Bxfj5vgnZeI9YQDo6%2BzpXMtQbrlB7dva3H398lar2mZsy%2FIT0LrbGtxZ3jfCqxP10qFAEYa1c24n%2BqVnQ980cYFheYI3ogXgfbVtW7qoRzXYarjWUKJnFl%2BsXxkNN1hIyo5tRCr%2FIapUxrF62rigE5ZkcA4if6zXdb7kenXsH3ZeAjM9SvMK%2BGh1pRzwf5R9Ix9CrWairn12uDJs9iPqoKDjWlTLf0ABBhKoNpU4XmMiet%2F9YLnoLl3Ta75ugI7iHbrfF2zWhPbfCkWa5nRHeRIIaINXgGI6L7xmE0%2BxxZXHF%2FhCG8cTFhDVveAZYxxDqIEZ08CAwEAAaOCAhYwggISMB8GA1UdIwQYMBaAFB4M97Zn8uGSJglFwFU5Lnc%2FQkqiMB0GA1UdDgQWBBRyW7qqcjjuJZAktZQi%2BgmIyosK%2BzAOBgNVHQ8BAf8EBAMCAQYwQAYDVR0fBDkwNzA1oDOgMYYvaHR0cDovL2VjYS5oaW5ldC5uZXQvcmVwb3NpdG9yeS9DUkxfU0hBMi9DQS5jcmwwgYIGCCsGAQUFBwEBBHYwdDA7BggrBgEFBQcwAoYvaHR0cDovL2VjYS5oaW5ldC5uZXQvcmVwb3NpdG9yeS9DZXJ0cy9lQ0FHMS5jcnQwNQYIKwYBBQUHMAGGKWh0dHA6Ly9vY3NwLmVjYS5oaW5ldC5uZXQvT0NTUC9vY3NwRzFzaGEyMA8GA1UdEwEB%2FwQFMAMBAf8wgecGA1UdIASB3zCB3DANBgsrBgEEAYG3I2QAATANBgsrBgEEAYG3I2QAAjANBgsrBgEEAYG3I2QAAzANBgsrBgEEAYG3I2QABDANBgsrBgEEAYG3I2QACTANBgsrBgEEAYG3I2QAADANBgsrBgEEAYG3I2QEATANBgsrBgEEAYG3I2QEAjANBgsrBgEEAYG3I2QEAzAJBgdghnYBZAABMAkGB2CGdgFkAAIwCQYHYIZ2AWQAAzAJBgdghnYBZAAEMAkGB2CGdgFkAAAwCAYGZ4EMAQIBMAgGBmeBDAECAjAIBgZngQwBAgMwDQYJKoZIhvcNAQELBQADggIBALwy4mxatKA6X%2BUM2IDpnWajNmek00EM4qh5E7eiQY0yZV5Eit9D%2F8q9h0hD77NjVaYPwsOWqWAiVtDAro%2BnWDHfkAG14ptRNBoGjJjzZi%2F%2BOeI2WTc8ZER6C8rAjQ7b%2FRxMzwxfDjRtgCbT2qq01rPiJ%2BqDgyUniDstbyQj08bSo3GJWp6ZsSNDAP26ygODpSgL0Ja806Byk2b4npQevdkmQ0k43S9IU0MeSlWT8hxzluyFlPRl4yuev5le91outdEdpV98KvYcgLAWwW5UcFOM6SRsYTBS2dfSRgKreDnMNdbUHmbAVsb3wLD6WqLoe6LyRNOeXctKPA6%2Be5i%2FJN6NZnqejcMopuS%2BpyWyrNiHlRShGUfTiXrcbT8fbyOswAT8JsX4fWyZYub0kKfFG8hEKQsIxNiyKH4cw6HBih31EYaYS9IEj19NxfHl0KbPm22cpBJoGwkZWgg%2F%2FPflFFHNTdKSalDxPHMKdyZbTBugLtqFVkV%2Bvu1y6WRoGfHwzpa9aQsMWAwLYRnBZnSYzfN9QFZsoHCSDJJVt30Oi6fURJy34%2Bdtvs%2BsQihiN886uYTJ0Cex1R%2BOb9HXCKFrGTumgwD%2Bnitt7hwlB74K9lqrKQrtfgfBFFMG9Tu%2FE%2FOI6JoST2j8KmSN1rpcxoMH3tamxqm3%2BxpLM9HekbBoJ0V2&cert=MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNsIZ5qyNUD9WBpj8zwIuQf5%2FdqIjG3LBXy4P4AakP%2Fh2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKilTza6We%2FCKBk49ZCt0Xvl%2FT29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q%2BRBNGMD%2BXPNjX12ruOzjjK9SXDrkb5wdJfzcq%2BXd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN%2F%2BZ0V0OWQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde%2BS%2FuUWH1%2BETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnaolQ2zepr7BxB4EW%2Fhj8e6DyUadCrlHJhBmd8hh%2BiVBmoKs2pHdmX2Os%2BPYhcZewoozRrSgx4hxyy%2Fvv9haLdnG7t4TY3OZ%2BXkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc%2FQkqiMAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLHClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B01GqZNF5sAFPZn%2FKmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI%2BymBV3QGypzqKOg4ZyYr8dW1P2WT%2BDZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC%2Fgpf36j36%2BuwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2j6%2F7Nu4tCEoduL%2BbXPjqpRugc6bY%2BG7gMwRfaKonh%2B3ZwZCc7b3jajWvY9%2BrGNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS%2FjQ6fbjpKdx2qcgw%2BBRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR%2B2zGp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8%2Fgntsm%2BHbRsZJB%2F9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW%2F2xzQ%2BDhNQ%2BIIX3Sj0rnP0qCglN6oH4EZw%3D";
+
+ await BrowserTestUtils.withNewTab(kURL, async function (browser) {
+ await SpecialPowers.spawn(browser, [], async function () {
+ let certificateSection = await ContentTaskUtils.waitForCondition(() => {
+ return content.document.querySelector("certificate-section");
+ }, "Certificate section found");
+
+ let tabs =
+ certificateSection.shadowRoot.querySelector(
+ ".certificate-tabs"
+ ).children;
+
+ Assert.ok(tabs, "Tabs were found");
+ Assert.equal(tabs.length, 4, "There should be 4 tabs");
+ for (let tab of tabs) {
+ Assert.ok(tab.textContent, "Tab should have non-empty label");
+ Assert.notEqual(
+ tab.dataset.l10nId,
+ "certificate-viewer-unknown-group-label"
+ );
+ // If there is another tab after this one, this tab should link to the
+ // next via its issuer's common name or OU, if available.
+ if (tab.nextElementSibling) {
+ tab.click();
+ let infoGroup = certificateSection.shadowRoot.querySelector(
+ ".selected info-group.issuer-name"
+ );
+ Assert.ok(infoGroup, "infoGroup found");
+ let container =
+ infoGroup.shadowRoot.querySelector(".common-name") ||
+ infoGroup.shadowRoot.querySelector(".organizational-unit");
+ Assert.ok(container, "Should find container for link");
+ Assert.ok(
+ container.shadowRoot.querySelector("a"),
+ "There should be a link in the container for " +
+ container.textContent
+ );
+ }
+ }
+ });
+ });
+});
diff --git a/toolkit/components/certviewer/tests/browser/browser_checkNonEmptyFields.js b/toolkit/components/certviewer/tests/browser/browser_checkNonEmptyFields.js
new file mode 100644
index 0000000000..e6c48dc3d1
--- /dev/null
+++ b/toolkit/components/certviewer/tests/browser/browser_checkNonEmptyFields.js
@@ -0,0 +1,82 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+async function checkNonEmptyFields(url) {
+ await BrowserTestUtils.withNewTab(url, async function (browser) {
+ await SpecialPowers.spawn(browser, [], async function () {
+ let certificateSection = await ContentTaskUtils.waitForCondition(() => {
+ return content.document.querySelector("certificate-section");
+ }, "Certificate section found");
+
+ let tabs =
+ certificateSection.shadowRoot.querySelector(
+ ".certificate-tabs"
+ ).children;
+
+ Assert.ok(tabs, "Tabs were found");
+ Assert.greater(tabs.length, 0, "There must at least one tab");
+
+ function clickTabAndCheckSelection(tabID) {
+ let selectedTabBefore = 0;
+
+ for (let i = 0; i < tabs.length; i++) {
+ if (tabs[i].className.includes("selected")) {
+ selectedTabBefore = i;
+ break;
+ }
+ }
+
+ let tabButton = certificateSection.shadowRoot.querySelector(
+ `.certificate-tabs .tab[idnumber="${tabID}"]`
+ );
+ tabButton.click();
+
+ if (tabID !== 0) {
+ Assert.notEqual(
+ selectedTabBefore,
+ tabID,
+ "A new tab should be selected now"
+ );
+ }
+ }
+
+ for (let i = 0; i < tabs.length; i++) {
+ clickTabAndCheckSelection(i);
+
+ let infoGroups =
+ certificateSection.shadowRoot.querySelectorAll("info-group");
+ Assert.ok(infoGroups, "infoGroups found");
+
+ for (let infoGroup of infoGroups) {
+ let infoItems = infoGroup.shadowRoot.querySelectorAll("info-item");
+ Assert.ok(infoItems, "infoItems found");
+
+ for (let infoItem of infoItems) {
+ let item = infoItem.shadowRoot.querySelector(".info");
+ if (item.textContent.length === 0) {
+ await ContentTaskUtils.waitForCondition(
+ () => parseInt(item.textContent.length) > 0,
+ "info-item has not been localized."
+ );
+ }
+ }
+ }
+ }
+ });
+ });
+}
+
+add_task(async function test() {
+ const url1 =
+ "about:certificate?cert=MIIIIDCCBwigAwIBAgIQdFFdOvtZKGMnFerJav62lzANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZpY2VzMSUwIwYDVQQDExxHb29nbGUgSW50ZXJuZXQgQXV0aG9yaXR5IEczMB4XDTE5MDcyOTE4NDQyN1oXDTE5MTAyMTE4MjMwMFowZjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEzARBgNVBAoMCkdvb2dsZSBMTEMxFTATBgNVBAMMDCouZ29vZ2xlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABOOufVj7d5UF%2FN49KyXmA0Z0rlQPEicHK5CbO122uECXYbWwepNlWlqM7V1GF0vRutC8YyAlxrCsUmOTrpem7NWjggWlMIIFoTATBgNVHSUEDDAKBggrBgEFBQcDATAOBgNVHQ8BAf8EBAMCB4AwggRqBgNVHREEggRhMIIEXYIMKi5nb29nbGUuY29tgg0qLmFuZHJvaWQuY29tghYqLmFwcGVuZ2luZS5nb29nbGUuY29tghIqLmNsb3VkLmdvb2dsZS5jb22CGCouY3Jvd2Rzb3VyY2UuZ29vZ2xlLmNvbYIGKi5nLmNvgg4qLmdjcC5ndnQyLmNvbYIRKi5nY3BjZG4uZ3Z0MS5jb22CCiouZ2dwaHQuY26CFiouZ29vZ2xlLWFuYWx5dGljcy5jb22CCyouZ29vZ2xlLmNhggsqLmdvb2dsZS5jbIIOKi5nb29nbGUuY28uaW6CDiouZ29vZ2xlLmNvLmpwgg4qLmdvb2dsZS5jby51a4IPKi5nb29nbGUuY29tLmFygg8qLmdvb2dsZS5jb20uYXWCDyouZ29vZ2xlLmNvbS5icoIPKi5nb29nbGUuY29tLmNvgg8qLmdvb2dsZS5jb20ubXiCDyouZ29vZ2xlLmNvbS50coIPKi5nb29nbGUuY29tLnZuggsqLmdvb2dsZS5kZYILKi5nb29nbGUuZXOCCyouZ29vZ2xlLmZyggsqLmdvb2dsZS5odYILKi5nb29nbGUuaXSCCyouZ29vZ2xlLm5sggsqLmdvb2dsZS5wbIILKi5nb29nbGUucHSCEiouZ29vZ2xlYWRhcGlzLmNvbYIPKi5nb29nbGVhcGlzLmNughEqLmdvb2dsZWNuYXBwcy5jboIUKi5nb29nbGVjb21tZXJjZS5jb22CESouZ29vZ2xldmlkZW8uY29tggwqLmdzdGF0aWMuY26CDSouZ3N0YXRpYy5jb22CEiouZ3N0YXRpY2NuYXBwcy5jboIKKi5ndnQxLmNvbYIKKi5ndnQyLmNvbYIUKi5tZXRyaWMuZ3N0YXRpYy5jb22CDCoudXJjaGluLmNvbYIQKi51cmwuZ29vZ2xlLmNvbYIWKi55b3V0dWJlLW5vY29va2llLmNvbYINKi55b3V0dWJlLmNvbYIWKi55b3V0dWJlZWR1Y2F0aW9uLmNvbYIRKi55b3V0dWJla2lkcy5jb22CByoueXQuYmWCCyoueXRpbWcuY29tghphbmRyb2lkLmNsaWVudHMuZ29vZ2xlLmNvbYILYW5kcm9pZC5jb22CG2RldmVsb3Blci5hbmRyb2lkLmdvb2dsZS5jboIcZGV2ZWxvcGVycy5hbmRyb2lkLmdvb2dsZS5jboIEZy5jb4IIZ2dwaHQuY26CBmdvby5nbIIUZ29vZ2xlLWFuYWx5dGljcy5jb22CCmdvb2dsZS5jb22CD2dvb2dsZWNuYXBwcy5jboISZ29vZ2xlY29tbWVyY2UuY29tghhzb3VyY2UuYW5kcm9pZC5nb29nbGUuY26CCnVyY2hpbi5jb22CCnd3dy5nb28uZ2yCCHlvdXR1LmJlggt5b3V0dWJlLmNvbYIUeW91dHViZWVkdWNhdGlvbi5jb22CD3lvdXR1YmVraWRzLmNvbYIFeXQuYmUwaAYIKwYBBQUHAQEEXDBaMC0GCCsGAQUFBzAChiFodHRwOi8vcGtpLmdvb2cvZ3NyMi9HVFNHSUFHMy5jcnQwKQYIKwYBBQUHMAGGHWh0dHA6Ly9vY3NwLnBraS5nb29nL0dUU0dJQUczMB0GA1UdDgQWBBRPZJy%2FftYprTgIqQTFvmZIl%2BXaGTAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFHfCuFCaZ3Z2sS3ChtCDoH6mfrpLMCEGA1UdIAQaMBgwDAYKKwYBBAHWeQIFAzAIBgZngQwBAgIwMQYDVR0fBCowKDAmoCSgIoYgaHR0cDovL2NybC5wa2kuZ29vZy9HVFNHSUFHMy5jcmwwDQYJKoZIhvcNAQELBQADggEBADc7%2BG7Np83iC8KU6GYSKizr%2F2VbPPpBjR5EzXIdUpUgxWFQ7Faxd1LVhm22QVlmMKjjYe7JUxnaIa5Zay6pBlMr5Fq%2BHbSTuA63GOt4IW1CvB1zAOaJWfxGXaNX1Xg%2F740qWEDoe95h9Xm%2FfIcFLD86FCUITAenFKBOKdaKoBMGoDBOq7jUdn492oGBYi%2BQtXfNjvcZm0yABGTjQOtH8JzyWKx1NvNLw5gSXYH5Vmj%2FQzRBEED3%2BpIJh6vgKIGEhG%2BhCg4tx4k0nnwoHGnL4a2mcemlRIWRCcjbb%2FBoF%2B05EvQvB6PcurckBaPN8r7wWCxefYViIMnHiMmzPdwZYIA%3D&cert=MIIEXDCCA0SgAwIBAgINAeOpMBz8cgY4P5pTHTANBgkqhkiG9w0BAQsFADBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0xNzA2MTUwMDAwNDJaFw0yMTEyMTUwMDAwNDJaMFQxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVHb29nbGUgVHJ1c3QgU2VydmljZXMxJTAjBgNVBAMTHEdvb2dsZSBJbnRlcm5ldCBBdXRob3JpdHkgRzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKUkvqHv%2FOJGuo2nIYaNVWXQ5IWi01CXZaz6TIHLGp%2FlOJ%2B600%2F4hbn7vn6AAB3DVzdQOts7G5pH0rJnnOFUAK71G4nzKMfHCGUksW%2Fmona%2BY2emJQ2N%2BaicwJKetPKRSIgAuPOB6Aahh8Hb2XO3h9RUk2T0HNouB2VzxoMXlkyW7XUR5mw6JkLHnA52XDVoRTWkNty5oCINLvGmnRsJ1zouAqYGVQMc%2F7sy%2B%2FEYhALrVJEA8KbtyX%2Br8snwU5C1hUrwaW6MWOARa8qBpNQcWTkaIeoYvy%2FsGIJEmjR0vFEwHdp1cSaWIr6%2F4g72n7OqXwfinu7ZYW97EfoOSQJeAzAgMBAAGjggEzMIIBLzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB%2FwQIMAYBAf8CAQAwHQYDVR0OBBYEFHfCuFCaZ3Z2sS3ChtCDoH6mfrpLMB8GA1UdIwQYMBaAFJviB1dnHB7AagbeWbSaLd%2FcGYYuMDUGCCsGAQUFBwEBBCkwJzAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AucGtpLmdvb2cvZ3NyMjAyBgNVHR8EKzApMCegJaAjhiFodHRwOi8vY3JsLnBraS5nb29nL2dzcjIvZ3NyMi5jcmwwPwYDVR0gBDgwNjA0BgZngQwBAgIwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly9wa2kuZ29vZy9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAHLeJluRT7bvs26gyAZ8so81trUISd7O45skDUmAge1cnxhG1P2cNmSxbWsoiCt2eux9LSD%2BPAj2LIYRFHW31%2F6xoic1k4tbWXkDCjir37xTTNqRAMPUyFRWSdvt%2BnlPqwnb8Oa2I%2FmaSJukcxDjNSfpDh%2FBd1lZNgdd%2F8cLdsE3%2BwypufJ9uXO1iQpnh9zbuFIwsIONGl1p3A8CgxkqI%2FUAih3JaGOqcpcdaCIzkBaR9uYQ1X4k2Vg5APRLouzVy7a8IVk6wuy6pm%2BT7HT4LY8ibS5FEZlfAFLSW8NwsVz9SBK2Vqn1N0PIMn5xA6NZVc7o835DLAFshEWfC7TIe3g%3D%3D&cert=MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6%2BLm8omUVCxKs%2BIVSbC9N%2FhHD6ErPLv4dfxn%2BG07IwXNb9rfF73OX4YJYJkhD10FPe%2B3t%2Bc4isUoh7SqbKSaZeqKeMWhG8eoLrvozps6yWJQeXSpkqBy%2B0Hne%2Fig%2B1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ%2FgkwpRl4pazq%2Br1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH%2FBAUwAwEB%2FzAdBgNVHQ4EFgQUm%2BIHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0%2FWwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP%2BDTKqttVCL1OmLNIG%2B6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavSot%2B3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h%2Bu%2FN5GJG79G%2BdwfCMNYxdAfvDbbnvRG15RjF%2BCv6pgsH%2F76tuIMRQyV%2BdTZsXjAzlAcmgQWpzU%2FqlULRuJQ%2F7TBj0%2FVLZjmmx6BEP3ojY%2Bx1J96relc8geMJgEtslQIxq%2FH5COEBkEveegeGTLg%3D%3D";
+ const url2 =
+ "about:certificate?cert=MIIDeTCCAmGgAwIBAgIJAPziuikCTox4MA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQ8wDQYDVQQKDAZCYWRTU0wxFTATBgNVBAMMDCouYmFkc3NsLmNvbTAeFw0xOTEwMDkyMzQxNTJaFw0yMTEwMDgyMzQxNTJaMGIxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQ8wDQYDVQQKDAZCYWRTU0wxFTATBgNVBAMMDCouYmFkc3NsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMIE7PiM7gTCs9hQ1XBYzJMY61yoaEmwIrX5lZ6xKyx2PmzAS2BMTOqytMAPgLaw%2BXLJhgL5XEFdEyt%2FccRLvOmULlA3pmccYYz2QULFRtMWhyefdOsKnRFSJiFzbIRMeVXk0WvoBj1IFVKtsyjbqv9u%2F2CVSndrOfEk0TG23U3AxPxTuW1CrbV8%2Fq71FdIzSOciccfCFHpsKOo3St%2FqbLVytH5aohbcabFXRNsKEqveww9HdFxBIuGa%2BRuT5q0iBikusbpJHAwnnqP7i%2FdAcgCskgjZjFeEU4EFy%2Bb%2Ba1SYQCeFxxC7c3DvaRhBB0VVfPlkPz0sw6l865MaTIbRyoUCAwEAAaMyMDAwCQYDVR0TBAIwADAjBgNVHREEHDAaggwqLmJhZHNzbC5jb22CCmJhZHNzbC5jb20wDQYJKoZIhvcNAQELBQADggEBAGlwCdbPxflZfYOaukZGCaxYK6gpincX4Lla4Ui2WdeQxE95w7fChXvP3YkE3UYUE7mupZ0eg4ZILr%2FA0e7JQDsgIu%2FSRTUE0domCKgPZ8v99k3Avka4LpLK51jHJJK7EFgo3ca2nldd97GM0MU41xHFk8qaK1tWJkfrrfcGwDJ4GQPIiLlm6i0yHq1Qg1RypAXJy5dTlRXlCLd8ufWhhiwW0W75Va5AEnJuqpQrKwl3KQVewGj67WWRgLfSr%2B4QG1mNvCZb2CkjZWmxkGPuoP40%2Fy7Yu5OFqxP5tAjj4YixCYTWEVA0pmzIzgBg%2BJIe3PdRy27T0asgQW%2FF4TY61Yk%3D";
+ const url3 =
+ "about:certificate?cert=MIIG7jCCBNagAwIBAgIBDzANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQKEwdSb290IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNBIENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRAY2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAOBgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEiMCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ8BLPRoZzYLdufujAWGSuzbCtRRcMY%2FpnCujW0r8%2B55jE8Ez64AO7NV1sId6eINm6zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42yfk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz%2BqOqfrU0j36NK2B5jcG8Y0f3%2FJHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN%2FNb5gznZY0dj4kepKwDpUeb%2BagRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE%2F9KTfWgu3YtLq1i6L43qlaegw1SJpfvbi1EinbLDvhG%2BLJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV%2FRRyH9XzQQUxPKZgh%2FTMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivUfslfrejrckzzAeVLIL%2BaplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826YreQQejdIOQpvGQpQsgi3Hia%2F0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAX8wggF7MB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TAPBgNVHRMBAf8EBTADAQH%2FMDQGCWCGSAGG%2BEIBCAQnFiVodHRwOi8vd3d3LmNhY2VydC5vcmcvaW5kZXgucGhwP2lkPTEwMFYGCWCGSAGG%2BEIBDQRJFkdUbyBnZXQgeW91ciBvd24gY2VydGlmaWNhdGUgZm9yIEZSRUUgaGVhZCBvdmVyIHRvIGh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzAxBgNVHR8EKjAoMCagJKAihiBodHRwOi8vY3JsLmNhY2VydC5vcmcvcmV2b2tlLmNybDAzBglghkgBhvhCAQQEJhYkVVJJOmh0dHA6Ly9jcmwuY2FjZXJ0Lm9yZy9yZXZva2UuY3JsMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAYYWaHR0cDovL29jc3AuY2FjZXJ0Lm9yZzAfBgNVHSMEGDAWgBQWtTIb1Mfz4OaO873SsDrusjkY0TANBgkqhkiG9w0BAQsFAAOCAgEAR5zXs6IX01JTt7Rq3b%2BbNRUhbO9vGBMggczo7R0qIh1kdhS6WzcrDoO6PkpuRg0L3qM7YQB6pw2V%2BubzF7xl4C0HWltfzPTbzAHdJtjaJQw7QaBlmAYpN2CLB6Jeg8q%2F1Xpgdw%2F%2BIP1GRwdg7xUpReUA482l4MH1kf0W0ad94SuIfNWQHcdLApmno%2FSUh1bpZyeWrMnlhkGNDKMxCCQXQ360TwFHc8dfEAaq5ry6cZzm1oetrkSviE2qofxvv1VFiQ%2B9TX3%2FzkECCsUB%2FEjPM0lxFBmu9T5Ih%2BEqns9ivmrEIQDv9tNyJHuLsDNqbUBal7OoiPZnXk9LH%2Bqb%2BpLf1ofv5noy5vX2a5OKebHe%2B0Ex%2FA7e%2BG%2FHuOjVNqhZ9j5Nispfq9zNyOHGWD8ofj8DHwB50L1Xh5H%2BEbIoga%2FhJCQnRtxWkHP699T1JpLFYwapgplivF4TFv4fqp0nHTKC1x9gGrIgvuYJl1txIKmxXdfJzgscMzqpabhtHOMXOiwQBpWzyJkofF%2Fw55e0LttZDBkEsilV%2FvW0CJsPs3eNaQF%2BiMWscGOkgLFlWsAS3HwyiYLNJo26aqyWPaIdc8E4ck7Sk08WrFrHIK3EHr4n1FZwmLpFAvucKqgl0hr%2B2jypyh5puA3KksHF3CsUzjMUvzxMhykh9zrMxQAHLBVrGwc%3D";
+
+ let urls = [url1, url2, url3];
+
+ await Promise.all(urls.map(checkNonEmptyFields));
+});
diff --git a/toolkit/components/certviewer/tests/browser/browser_checkNonRepeatedCertTabs.js b/toolkit/components/certviewer/tests/browser/browser_checkNonRepeatedCertTabs.js
new file mode 100644
index 0000000000..1e11cc4786
--- /dev/null
+++ b/toolkit/components/certviewer/tests/browser/browser_checkNonRepeatedCertTabs.js
@@ -0,0 +1,131 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+function checkCertTabs() {
+ let certificatePages = 0;
+ for (let tab of gBrowser.tabs) {
+ let spec = tab.linkedBrowser.documentURI.spec;
+ if (spec.includes("about:certificate")) {
+ certificatePages++;
+ }
+ }
+ Assert.equal(certificatePages, 1, "Do not open repeated certificate pages!");
+}
+
+add_task(async function testBadCert() {
+ info("Testing bad cert");
+
+ let tab = await openErrorPage();
+
+ let loaded = BrowserTestUtils.waitForNewTab(gBrowser, null, true);
+ for (let i = 0; i < 2; i++) {
+ // try opening two certificates that are the same
+ await SpecialPowers.spawn(tab.linkedBrowser, [], async function () {
+ let advancedButton = content.document.getElementById("advancedButton");
+ Assert.ok(advancedButton, "advancedButton found");
+ Assert.equal(
+ advancedButton.hasAttribute("disabled"),
+ false,
+ "advancedButton should be clickable"
+ );
+ advancedButton.click();
+ let viewCertificate = content.document.getElementById("viewCertificate");
+ Assert.ok(viewCertificate, "viewCertificate found");
+ Assert.equal(
+ viewCertificate.hasAttribute("disabled"),
+ false,
+ "viewCertificate should be clickable"
+ );
+
+ viewCertificate.click();
+ });
+ await loaded;
+ }
+ checkCertTabs();
+
+ gBrowser.removeCurrentTab(); // closes about:certificate
+ gBrowser.removeCurrentTab(); // closes https://expired.example.com/
+});
+
+add_task(async function testGoodCert() {
+ info("Testing page info");
+ let url = "https://example.com/";
+
+ info(`Loading ${url}`);
+ await BrowserTestUtils.withNewTab({ gBrowser, url }, async function () {
+ info("Opening pageinfo");
+ let pageInfo = BrowserPageInfo(url, "securityTab", {});
+ await BrowserTestUtils.waitForEvent(pageInfo, "load");
+
+ let securityTab = pageInfo.document.getElementById("securityTab");
+ await TestUtils.waitForCondition(
+ () => BrowserTestUtils.isVisible(securityTab),
+ "Security tab should be visible."
+ );
+ Assert.ok(securityTab, "Security tab is available");
+ let viewCertButton = pageInfo.document.getElementById("security-view-cert");
+ await TestUtils.waitForCondition(
+ () => BrowserTestUtils.isVisible(viewCertButton),
+ "view cert button should be visible."
+ );
+
+ let loaded = BrowserTestUtils.waitForNewTab(gBrowser, null, true);
+ for (let i = 0; i < 2; i++) {
+ checkAndClickButton(pageInfo.document, "security-view-cert");
+ await loaded;
+ }
+
+ pageInfo.close();
+ checkCertTabs();
+ });
+
+ gBrowser.removeCurrentTab();
+});
+
+add_task(async function testPreferencesCert() {
+ info("Testing preferences cert");
+ let url = "about:preferences#privacy";
+
+ info(`Loading ${url}`);
+ await BrowserTestUtils.withNewTab(
+ { gBrowser, url },
+ async function (browser) {
+ checkAndClickButton(browser.contentDocument, "viewCertificatesButton");
+
+ let certDialogLoaded = promiseLoadSubDialog(
+ "chrome://pippki/content/certManager.xhtml"
+ );
+ let dialogWin = await certDialogLoaded;
+ let doc = dialogWin.document;
+ Assert.ok(doc, "doc loaded");
+
+ doc.getElementById("certmanagertabs").selectedTab =
+ doc.getElementById("ca_tab");
+ let treeView = doc.getElementById("ca-tree").view;
+ let selectedCert;
+
+ for (let i = 0; i < treeView.rowCount; i++) {
+ treeView.selection.select(i);
+ dialogWin.getSelectedCerts();
+ let certs = dialogWin.selected_certs;
+ if (certs && certs.length == 1 && certs[0]) {
+ selectedCert = certs[0];
+ break;
+ }
+ }
+ Assert.ok(selectedCert, "A cert should be selected");
+ let viewButton = doc.getElementById("ca_viewButton");
+ Assert.equal(viewButton.disabled, false, "Should enable view button");
+
+ let loaded = BrowserTestUtils.waitForNewTab(gBrowser, null, true);
+ for (let i = 0; i < 2; i++) {
+ viewButton.click();
+ await loaded;
+ }
+ checkCertTabs();
+ }
+ );
+ gBrowser.removeCurrentTab(); // closes about:certificate
+});
diff --git a/toolkit/components/certviewer/tests/browser/browser_checkNonUndefinedStrings.js b/toolkit/components/certviewer/tests/browser/browser_checkNonUndefinedStrings.js
new file mode 100644
index 0000000000..5e76990592
--- /dev/null
+++ b/toolkit/components/certviewer/tests/browser/browser_checkNonUndefinedStrings.js
@@ -0,0 +1,49 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const url =
+ "about:certificate?cert=MIIGRjCCBS6gAwIBAgIQDJduPkI49CDWPd%2BG7%2Bu6kDANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5EaWdpQ2VydCBTSEEyIFNlY3VyZSBTZXJ2ZXIgQ0EwHhcNMTgxMTA1MDAwMDAwWhcNMTkxMTEzMTIwMDAwWjCBgzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxHDAaBgNVBAoTE01vemlsbGEgQ29ycG9yYXRpb24xDzANBgNVBAsTBldlYk9wczEYMBYGA1UEAxMPd3d3Lm1vemlsbGEub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuKruymkkmkqCJh7QjmXlUOBcLFRyw5LG%2FvUUWVrsxC2gsbR8WJq%2BcYoYBpoNVStKrO4U2rBh1GEbccvT6qKOQI%2BpjjDxx9cmRdubGTGp8L0MF1ohVvhIvYLumOEoRDDPU4PvGJjGhek%2FojvedPWe8dhciHkxOC2qPFZvVFMwg1%2Fo%2Fb80147BwZQmzB18mnHsmcyKlpsCN8pxw86uao9Iun8gZQrsllW64rTZlRR56pHdAcuGAoZjYZxwS9Z%2BlvrSjEgrddemWyGGalqyFp1rXlVM1Tf4%2FIYWAQXTgTUN303u3xMjss7QK7eUDsACRxiWPLW9XQDd1c%2ByvaYJKzgJ2wIDAQABo4IC6TCCAuUwHwYDVR0jBBgwFoAUD4BhHIIxYdUvKOeNRji0LOHG2eIwHQYDVR0OBBYEFNpSvSGcN2VT%2FB9TdQ8eXwebo60%2FMCcGA1UdEQQgMB6CD3d3dy5tb3ppbGxhLm9yZ4ILbW96aWxsYS5vcmcwDgYDVR0PAQH%2FBAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBrBgNVHR8EZDBiMC%2BgLaArhilodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc3NjYS1zaGEyLWc2LmNybDAvoC2gK4YpaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NzY2Etc2hhMi1nNi5jcmwwTAYDVR0gBEUwQzA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBAgIwfAYIKwYBBQUHAQEEcDBuMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wRgYIKwYBBQUHMAKGOmh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJTZWN1cmVTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH%2FBAIwADCCAQIGCisGAQQB1nkCBAIEgfMEgfAA7gB1AKS5CZC0GFgUh7sTosxncAo8NZgE%2BRvfuON3zQ7IDdwQAAABZuYWiHwAAAQDAEYwRAIgZnMSH1JdG6NASHWTwD0mlP%2Fzbr0hzP263c02Ym0DU64CIEe4QHJDP47j0b6oTFu6RrZz1NQ9cq8Az1KnMKRuaFAlAHUAh3W%2F51l8%2BIxDmV%2B9827%2FVo1HVjb%2FSrVgwbTq%2F16ggw8AAAFm5haJAgAABAMARjBEAiAxGLXkUaOAkZhXNeNR3pWyahZeKmSaMXadgu18SfK1ZAIgKtwu5eGxK76rgaszLCZ9edBIjuU0DKorzPUuxUXFY0QwDQYJKoZIhvcNAQELBQADggEBAKLJAFO3wuaP5MM%2Fed1lhk5Uc2aDokhcM7XyvdhEKSHbgPhcgMoT9YIVoPa70gNC6KHcwoXu0g8wt7X6Vm1ql%2F68G5q844kFuC6JPl4LVT9mciD%2BVW6bHUSXD9xifL9DqdJ0Ic0SllTlM%2Boq5aAeOxUQGXhXIqj6fSQv9fQN6mXxQIoc%2Fgjxteskq%2FVl8YmY1FIZP9Bh7g27kxZ9GAAGQtjTL03RzKAuSg6yeImYVdQWasc7UPnBXlRAzZ8%2BOJThUbzK16a2CI3Rg4agKSJk%2BuA47h1%2FImmngpFLRb%2FMvRX6H1oWcUuyH6O7PZdl0YpwTpw1THIuqCGl%2FwpPgyQgcTM%3D&cert=MIIElDCCA3ygAwIBAgIQAf2j627KdciIQ4tyS8%2B8kTANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaME0xCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJzAlBgNVBAMTHkRpZ2lDZXJ0IFNIQTIgU2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANyuWJBNwcQwFZA1W248ghX1LFy949v%2FcUP6ZCWA1O4Yok3wZtAKc24RmDYXZK83nf36QYSvx6%2BM%2FhpzTc8zl5CilodTgyu5pnVILR1WN3vaMTIa16yrBvSqXUu3R0bdKpPDkC55gIDvEwRqFDu1m5K%2BwgdlTvza%2FP96rtxcflUxDOg5B6TXvi%2FTC2rSsd9f%2Fld0Uzs1gN2ujkSYs58O09rg1%2FRrKatEp0tYhG2SS4HD2nOLEpdIkARFdRrdNzGXkujNVA075ME%2FOV4uuPNcfhCOhkEAjUVmR7ChZc6gqikJTvOX6%2Bguqw9ypzAO%2Bsf0%2FRR3w6RbKFfCs%2FmC%2FbdFWJsCAwEAAaOCAVowggFWMBIGA1UdEwEB%2FwQIMAYBAf8CAQAwDgYDVR0PAQH%2FBAQDAgGGMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwN6A1oDOGMWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwHQYDVR0OBBYEFA%2BAYRyCMWHVLyjnjUY4tCzhxtniMB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA0GCSqGSIb3DQEBCwUAA4IBAQAjPt9L0jFCpbZ%2BQlwaRMxp0Wi0XUvgBCFsS%2BJtzLHgl4%2BmUwnNqipl5TlPHoOlblyYoiQm5vuh7ZPHLgLGTUq%2FsELfeNqzqPlt%2FyGFUzZgTHbO7Djc1lGA8MXW5dRNJ2Srm8c%2BcftIl7gzbckTB%2B6WohsYFfZcTEDts8Ls%2F3HB40f%2F1LkAtDdC2iDJ6m6K7hQGrn2iWZiIqBtvLfTyyRRfJs8sjX7tN8Cp1Tm5gr8ZDOo0rwAhaPitc%2BLJMto4JQtV05od8GiG7S5BNO98pVAdvzr508EIDObtHopYJeS4d60tbvVS3bR0j6tJLp07kzQoH3jOlOrHvdPJbRzeXDLz&cert=MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOnTjC3U%2FdDxGkAV53ijSLdhwZAAIEJzs4bg7%2FfzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5BmV%2FSl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C%2FdxC%2F%2FAH2hdmoRBBYMql1GNXRor5H4idq9Joz%2BEkIYIvUX7Q6hL%2BhqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv%2BzbMUZBfHWymeMr%2Fy7vrTC0LUq7dBMtoM1O%2F4gdW7jVg%2FtRvoSSiicNoxBN33shbyTApOB6jtSj1etX%2BjkMOvJwIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH%2FBAUwAwEB%2FzAdBgNVHQ4EFgQUA95QNVbRTLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK%2Bt1EnE9SsPTfrgT1eXkIoyQY%2FEsrhMAtudXH%2FvTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp%2F2PV5Adg06O%2FnVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp%2BdWOIrWcBAI%2B0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU%2BKrk2U886UAb3LujEV0lsYSEY1QSteDwsOoBrp%2BuvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQkCAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4%3D";
+
+add_task(async function test() {
+ await BrowserTestUtils.withNewTab(url, async function (browser) {
+ await SpecialPowers.spawn(browser, [], async function () {
+ let certificateSection = await ContentTaskUtils.waitForCondition(() => {
+ return content.document.querySelector("certificate-section");
+ }, "Certificate section found");
+
+ let tabs =
+ certificateSection.shadowRoot.querySelector(
+ ".certificate-tabs"
+ ).children;
+
+ Assert.ok(tabs, "Tabs were found");
+
+ for (let i = 0; i < tabs.length; i++) {
+ let tabButton = certificateSection.shadowRoot.querySelector(
+ `.certificate-tabs .tab[idnumber="${i}"]`
+ );
+ tabButton.click();
+
+ let infoGroups =
+ certificateSection.shadowRoot.querySelectorAll("info-group");
+ Assert.ok(infoGroups, "infoGroups found");
+
+ for (let infoGroup of infoGroups) {
+ let infoItems = infoGroup.shadowRoot.querySelectorAll("info-item");
+ Assert.ok(infoItems, "infoItems found");
+
+ for (let infoItem of infoItems) {
+ let info = infoItem.shadowRoot.children[2].textContent;
+ Assert.equal(
+ info.includes("undefined"),
+ false,
+ "Empty strings shouldn't be rendered"
+ );
+ }
+ }
+ }
+ });
+ });
+});
diff --git a/toolkit/components/certviewer/tests/browser/browser_checkOCSP.js b/toolkit/components/certviewer/tests/browser/browser_checkOCSP.js
new file mode 100644
index 0000000000..b7d51842eb
--- /dev/null
+++ b/toolkit/components/certviewer/tests/browser/browser_checkOCSP.js
@@ -0,0 +1,46 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+async function checkOCSP(url, shouldBeRendered) {
+ await BrowserTestUtils.withNewTab(url, async function (browser) {
+ await SpecialPowers.spawn(
+ browser,
+ [shouldBeRendered],
+ async function (shouldBeRendered) {
+ let certificateSection = await ContentTaskUtils.waitForCondition(() => {
+ return content.document.querySelector("certificate-section");
+ }, "Certificate section found");
+ let OCSPSection =
+ certificateSection.shadowRoot.querySelector(".ocsp-stapling");
+ if (!shouldBeRendered) {
+ Assert.equal(OCSPSection, null, "OCSPSection found");
+ return;
+ }
+ Assert.ok(OCSPSection, "OCSPSection found");
+ let item = OCSPSection.shadowRoot.querySelector("info-item");
+ Assert.ok(item, "item found");
+ let info = item.shadowRoot.querySelector(".info").textContent;
+ Assert.equal(info, "Yes", "OCSP is required");
+ }
+ );
+ });
+}
+
+add_task(async function test() {
+ let tests = [
+ {
+ url: "about:certificate?cert=MIIE1jCCA76gAwIBAgISA8ud4ZkTgHyRgFEI060JNN%2FFMA0GCSqGSIb3DQEBCwUAMEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xOTEwMjAwODUzMTFaFw0yMDAxMTgwODUzMTFaMB0xGzAZBgNVBAMTEmRtNHByb2R1Y3Rpb25zLmNvbTB2MBAGByqGSM49AgEGBSuBBAAiA2IABAaBrphEFb0WufNLet5XJDrjo3UYUnEhNJZ5LKbbdaMeRHU%2BamVcM%2B%2Fyddoeq56%2FbeZF0p8oKptxg0TQpeVz4b5ZONe17S6Bp17DN0HLqeX6FXLKyVqRTfoesv7XR1KtW6OCAo8wggKLMA4GA1UdDwEB%2FwQEAwIHgDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH%2FBAIwADAdBgNVHQ4EFgQUNXKbW53h63%2Bz%2FBCOyd4pilpoFc8wHwYDVR0jBBgwFoAUqEpqYwR93brm0Tm3pkVl7%2FOo7KEwbwYIKwYBBQUHAQEEYzBhMC4GCCsGAQUFBzABhiJodHRwOi8vb2NzcC5pbnQteDMubGV0c2VuY3J5cHQub3JnMC8GCCsGAQUFBzAChiNodHRwOi8vY2VydC5pbnQteDMubGV0c2VuY3J5cHQub3JnLzAzBgNVHREELDAqghQqLmRtNHByb2R1Y3Rpb25zLmNvbYISZG00cHJvZHVjdGlvbnMuY29tMBEGCCsGAQUFBwEYBAUwAwIBBTBMBgNVHSAERTBDMAgGBmeBDAECATA3BgsrBgEEAYLfEwEBATAoMCYGCCsGAQUFBwIBFhpodHRwOi8vY3BzLmxldHNlbmNyeXB0Lm9yZzCCAQMGCisGAQQB1nkCBAIEgfQEgfEA7wB1ALIeBcyLos2KIE6HZvkruYolIGdr2vpw57JJUy3vi5BeAAABbeiVw3YAAAQDAEYwRAIgHUJgZEK9S5grlRSnDiZMZUWllQ1Ki10T2ldH1XgRfuUCICfKCcvcMas9Wb09athc6kPrD9WxVCi%2FTPfOWVmFv4EdAHYAb1N2rDHwMRnYmQCkURX%2FdxUcEdkCwQApBo2yCJo32RMAAAFt6JXE7wAABAMARzBFAiEAm4lY7Jsj1c%2F%2FzAES61A7hi9jJ5bqQpE1x9KCALQqd4sCIAablaGWv6L3uksVpDH1KDxj1Df9iDPGO2CJSzKjSKdNMA0GCSqGSIb3DQEBCwUAA4IBAQBjP5pR%2Fnj%2FCOZy3Z2LfqN7z%2Fcb87rz0CY7iR5p6PvdvwOs0JPq%2F1pVf4V3JTPmEduP7Z4cYIAoOp2%2BFBE0kZar0zzhp6uXcoBagrlxanG9KvgeWr1hfyJjYbnsteake8Z3vqfjdnlhB5ZFmQudHQh7QAoxtswNbdxjy%2FNwBIR5pKIDxleebVwe%2FneH%2BtokDYSPmH2vsmto0z72VM1KlFjgXC79XDIKMl83R2U%2F1B9wq23EHeFFY38cBUFKEjO67eC9q1Xxsv%2FpYAKrXVkdwwsvHfoY7evFRu%2Fj%2BsS3fWcf8uPrApaoqqJgjxpJ2jHjcXniad47iTffJUmwHqmyeigZ&cert=MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA%2FMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0NlowSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMTGkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EFq6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan%2FPQeGdxyGkOlZHP%2FuaZ6WA8SMx%2Byk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0Z8h%2FpZq4UmEUEz9l6YKHy9v6Dlb2honzhT%2BXhq%2Bw3Brvaw2VFn3EK6BlspkENnWAa6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB%2FonkxEz0tNvjj%2FPIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0TAQH%2FBAgwBgEB%2FwIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIGCCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNvbTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9kc3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf%2FEFWCFiRAwVAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcCARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwuY3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsFAAOCAQEA3TPXEfNjWDjdGBX7CVW%2Bdla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJouM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg%2BVyOeph4EYpr%2F1wXKtx8%2FwApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so%2FjoWUoHOUgwuX4Po1QYz%2B3dszkDqMp4fklxBwXRsW10KXzPMTZ%2BsOPAveyxindmjkW8lGy%2BQsRlGPfZ%2BG6Z6h7mjem0Y%2BiWlkYcV4PIWL1iwBi8saCbGS5jN2p8M%2BX%2BQ7UNKEkROb3N6KOqkqm57TH2H3eDJAkSnh6%2FDNFu0Qg%3D%3D&cert=MIIDSjCCAjKgAwIBAgIQRK%2BwgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA%2FMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN%2Bv6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi%2BDoM3ZJKuM%2FIUmTrE4Orz5Iy2Xu%2FNMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9UL2AZd%2B3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRyxXtqqzTWMIn%2F5WgTe1QLyNau7Fqckh49ZLOMxt%2B%2FyUFw7BZy1SbsOFU5Q9D8%2FRhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4%2BU9m5%2FwAl0CAwEAAaNCMEAwDwYDVR0TAQH%2FBAUwAwEB%2FzAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62%2BFLkHX%2FxBVghYkQMA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or%2BDxz9LwwmglSBd49lZRNI%2BDT69ikugdB%2FOEIKcdBodfpga3csTS7MgROSR6cz8faXbauX%2B5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK%2BrlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir%2Fmd2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL%2BT0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ",
+ shouldBeRendered: true,
+ },
+ {
+ url: "about:certificate?cert=MIIE0DCCBHegAwIBAgIQCP0zdXA01ESx6eTjfitzfzAKBggqhkjOPQQDAjBvMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xGTAXBgNVBAoTEENsb3VkRmxhcmUsIEluYy4xIDAeBgNVBAMTF0Nsb3VkRmxhcmUgSW5jIEVDQyBDQS0yMB4XDTE5MDUwMzAwMDAwMFoXDTIwMDUwMzEyMDAwMFowaDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRkwFwYDVQQKExBDbG91ZEZsYXJlLCBJbmMuMRkwFwYDVQQDExBzY290dGhlbG1lLmNvLnVrMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYQYIOYOkA0SNAxlrsvTnr7BIOoNmUaBFG2oXXyKfphkc%2F5wXXMU1Ez1%2BpqjFHSwaAtCkgTzTNEEOxkuDicJLqKOCAvowggL2MB8GA1UdIwQYMBaAFD50LR%2FPRXUEfj%2FAooc%2BTEODURPGMB0GA1UdDgQWBBSlm2TM83mhbWzqLL2SZRmdHbh%2FWDAvBgNVHREEKDAmghBzY290dGhlbG1lLmNvLnVrghIqLnNjb3R0aGVsbWUuY28udWswDgYDVR0PAQH%2FBAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjB5BgNVHR8EcjBwMDagNKAyhjBodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vQ2xvdWRGbGFyZUluY0VDQ0NBMi5jcmwwNqA0oDKGMGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9DbG91ZEZsYXJlSW5jRUNDQ0EyLmNybDBMBgNVHSAERTBDMDcGCWCGSAGG%2FWwBATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAgGBmeBDAECAjB2BggrBgEFBQcBAQRqMGgwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBABggrBgEFBQcwAoY0aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0Nsb3VkRmxhcmVJbmNFQ0NDQS0yLmNydDAMBgNVHRMBAf8EAjAAMIIBAwYKKwYBBAHWeQIEAgSB9ASB8QDvAHUA7ku9t3XOYLrhQmkfq%2BGeZqMPfl%2BwctiDAMR7iXqo%2FcsAAAFqfaV7eQAABAMARjBEAiAcD2ch9qAysZxlIFqrYjElyv%2B6fPbwBZ%2BCFSgJW7d4cgIgUnpOdauBy9OXIeQerY0ElxqlPDFo0qTx34NBoPmfyOYAdgBep3P531bA57U2SH3QSeAyepGaDIShEhKEGHWWgXFFWAAAAWp9pXsQAAAEAwBHMEUCIQDlDcpBkwV225tooGiDmWX4bwvpko6nmXnQ8RBeSltUGAIgXUCskAznLKPcqf7e55eEj9xwago28rJZny6stP9NqakwCgYIKoZIzj0EAwIDRwAwRAIfVXERnB1UkKpq73xsv0H3o0SC%2FVGdyuIizTc1HHeP6gIhAKSIp4zfgOLP3l46y2yHzir9PdeCc%2BRGUVg4P4IgAANv&cert=MIIDozCCAougAwIBAgIQD%2FPmFjmqPRoSZfQfizTltjANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTE1MTAxNDEyMDAwMFoXDTIwMTAwOTEyMDAwMFowbzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRkwFwYDVQQKExBDbG91ZEZsYXJlLCBJbmMuMSAwHgYDVQQDExdDbG91ZEZsYXJlIEluYyBFQ0MgQ0EtMjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABNFW9Jy25DGg9aRSz%2BOaeob%2F8oayXsy1WcwRx07dZP1VnGDjoEvZeFT%2FSFC6ouGhWHWPx2A3RBZNVZns7tQzeiOjggEZMIIBFTASBgNVHRMBAf8ECDAGAQH%2FAgEAMA4GA1UdDwEB%2FwQEAwIBhjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTA6BgNVHR8EMzAxMC%2BgLaArhilodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vT21uaXJvb3QyMDI1LmNybDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAdBgNVHQ4EFgQUPnQtH89FdQR%2BP8Cihz5MQ4NRE8YwHwYDVR0jBBgwFoAU5Z1ZMIJHWMys%2BghUNoZ7OrUETfAwDQYJKoZIhvcNAQELBQADggEBADhfp%2F%2F8hfJzMuTVo4mZlmCvMsEDs2Xfvh4DyqXthbKPr0uMc48qjKkADgEkF%2FfsUoV2yOUcecrDF4dQtgQzNp4qnhgXljISr0PMVxje28fYiCWD5coGJTH9vV1IO1EB3SwUx8FgUemVAdiyM1YOR2aNbM2v%2BYXZ6xxHR4g06PD6wqtPaU4JWdRXxszByOPmGcFYOFLi4oOF3iI03D%2Bm968kvOBvwKtoLVLHawVXLEIbLUiHAwyQq0hIqSi%2BNIr7uu30YJkdFXgRqtltU39pKLy3ayB2f6BVA3F59WensKAKF1eyAKmtz%2F9njD4m5ackvMJvEOiJxnCl0h%2BA7Q0%2FJxM%3D&cert=MIIDdzCCAl%2BgAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN%2BhXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsBUnuId9Mcj8e6uYi1agnnc%2BgRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9%2FlSEy%2FCG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD%2BtqYF%2FLTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f%2FxXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v%2Fyejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1BE3wMBIGA1UdEwEB%2FwQIMAYBAf8CAQMwDgYDVR0PAQH%2FBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF%2BvaKSm2eT929hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE%2FszKN%2BOMY3EU%2Ft3WgxjkzSswF07r51XgdIGn9w%2FxZchMB5hbgF%2FX%2B%2BZRGjD8ACtPhSNzkE1akxehi%2FoCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h%2B3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5%2BNauQrz4wlHrQMz2nZQ%2F1%2FI6eYs9HRCwBXbsdtTLSR9I4LtD%2Bgdwyah617jzV%2FOeBHRnDJELqYzmp",
+ shouldBeRendered: false,
+ },
+ ];
+
+ for (let test of tests) {
+ await checkOCSP(test.url, test.shouldBeRendered);
+ }
+});
diff --git a/toolkit/components/certviewer/tests/browser/browser_checkStandAlonePage.js b/toolkit/components/certviewer/tests/browser/browser_checkStandAlonePage.js
new file mode 100644
index 0000000000..02d8fdc250
--- /dev/null
+++ b/toolkit/components/certviewer/tests/browser/browser_checkStandAlonePage.js
@@ -0,0 +1,86 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const TYPE_CA = 1;
+const TYPE_USER = 2;
+const TYPE_EMAIL = 4;
+const TYPE_SERVER = 8;
+
+add_task(async function test_dbItemDisplayed() {
+ await BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
+ gBrowser.selectedTab = BrowserTestUtils.addTab(
+ gBrowser,
+ "about:certificate"
+ );
+ });
+
+ let categories = [
+ {
+ type: TYPE_CA,
+ tabName: "Authorities",
+ id: "ca",
+ },
+ {
+ type: TYPE_USER,
+ tabName: "Your Certificates",
+ id: "mine",
+ },
+ {
+ type: TYPE_EMAIL,
+ tabName: "People",
+ id: "people",
+ },
+ {
+ type: TYPE_SERVER,
+ tabName: "Servers",
+ id: "servers",
+ },
+ ];
+
+ let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
+ Ci.nsIX509CertDB
+ );
+ Assert.ok(certdb, "certdb not null");
+ let certcache = certdb.getCerts();
+ Assert.ok(certcache, "certcache not null");
+
+ for (let cert of certcache) {
+ let category = categories.find(({ type }) => type & cert.certType);
+
+ await SpecialPowers.spawn(
+ gBrowser.selectedBrowser,
+ [cert.displayName, category],
+ async function (displayName, category) {
+ let aboutCertificateSection = await ContentTaskUtils.waitForCondition(
+ () => {
+ return content.document.querySelector("about-certificate-section");
+ },
+ "Found aboutCertificateSection."
+ );
+
+ let tab = aboutCertificateSection.shadowRoot.querySelector(
+ `.certificate-tabs #certificate-viewer-tab-${category.id}`
+ );
+ Assert.ok(tab, `${category.tabName} tab should exist.`);
+ tab.click();
+
+ let certificateItems = aboutCertificateSection.shadowRoot.querySelector(
+ `.info-groups #certificate-viewer-tab-${category.id}`
+ );
+
+ let listItems =
+ certificateItems.shadowRoot.querySelectorAll("list-item");
+
+ let item = Array.from(listItems).find(
+ i =>
+ i.shadowRoot.querySelector(".item-name").textContent == displayName
+ );
+ Assert.ok(item, `${displayName} should be listed`);
+ }
+ );
+ }
+
+ gBrowser.removeCurrentTab(); // closes about:certificate
+});
diff --git a/toolkit/components/certviewer/tests/browser/browser_checkValiditySection.js b/toolkit/components/certviewer/tests/browser/browser_checkValiditySection.js
new file mode 100644
index 0000000000..10e82be94a
--- /dev/null
+++ b/toolkit/components/certviewer/tests/browser/browser_checkValiditySection.js
@@ -0,0 +1,57 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const github_url =
+ "about:certificate?cert=MIIHQjCCBiqgAwIBAgIQCgYwQn9bvO1pVzllk7ZFHzANBgkqhkiG9w0BAQsFADB1MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTQwMgYDVQQDEytEaWdpQ2VydCBTSEEyIEV4dGVuZGVkIFZhbGlkYXRpb24gU2VydmVyIENBMB4XDTE4MDUwODAwMDAwMFoXDTIwMDYwMzEyMDAwMFowgccxHTAbBgNVBA8MFFByaXZhdGUgT3JnYW5pemF0aW9uMRMwEQYLKwYBBAGCNzwCAQMTAlVTMRkwFwYLKwYBBAGCNzwCAQITCERlbGF3YXJlMRAwDgYDVQQFEwc1MTU3NTUwMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEVMBMGA1UEChMMR2l0SHViLCBJbmMuMRMwEQYDVQQDEwpnaXRodWIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxjyq8jyXDDrBTyitcnB90865tWBzpHSbindG%2FXqYQkzFMBlXmqkzC%2BFdTRBYyneZw5Pz%2BXWQvL%2B74JW6LsWNc2EF0xCEqLOJuC9zjPAqbr7uroNLghGxYf13YdqbG5oj%2F4x%2BogEG3dF%2FU5YIwVr658DKyESMV6eoYV9mDVfTuJastkqcwero%2B5ZAKfYVMLUEsMwFtoTDJFmVf6JlkOWwsxp1WcQ%2FMRQK1cyqOoUFUgYylgdh3yeCDPeF22Ax8AlQxbcaI%2BGwfQL1FB7Jy%2Bh%2BKjME9lE%2FUpgV6Qt2R1xNSmvFCBWu%2BNFX6epwFP%2FJRbkMfLz0beYFUvmMgLtwVpEPSwIDAQABo4IDeTCCA3UwHwYDVR0jBBgwFoAUPdNQpdagre7zSmAKZdMh1Pj41g8wHQYDVR0OBBYEFMnCU2FmnV%2BrJfQmzQ84mqhJ6kipMCUGA1UdEQQeMByCCmdpdGh1Yi5jb22CDnd3dy5naXRodWIuY29tMA4GA1UdDwEB%2FwQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdQYDVR0fBG4wbDA0oDKgMIYuaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItZXYtc2VydmVyLWcyLmNybDA0oDKgMIYuaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItZXYtc2VydmVyLWcyLmNybDBLBgNVHSAERDBCMDcGCWCGSAGG%2FWwCATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAcGBWeBDAEBMIGIBggrBgEFBQcBAQR8MHowJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBSBggrBgEFBQcwAoZGaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkV4dGVuZGVkVmFsaWRhdGlvblNlcnZlckNBLmNydDAMBgNVHRMBAf8EAjAAMIIBfgYKKwYBBAHWeQIEAgSCAW4EggFqAWgAdgCkuQmQtBhYFIe7E6LMZ3AKPDWYBPkb37jjd80OyA3cEAAAAWNBYm0KAAAEAwBHMEUCIQDRZp38cTWsWH2GdBpe%2FuPTWnsu%2Fm4BEC2%2BdIcvSykZYgIgCP5gGv6yzaazxBK2NwGdmmyuEFNSg2pARbMJlUFgU5UAdgBWFAaaL9fC7NP14b1Esj7HRna5vJkRXMDvlJhV1onQ3QAAAWNBYm0tAAAEAwBHMEUCIQCi7omUvYLm0b2LobtEeRAYnlIo7n6JxbYdrtYdmPUWJQIgVgw1AZ51vK9ENinBg22FPxb82TvNDO05T17hxXRC2IYAdgC72d%2B8H4pxtZOUI5eqkntHOFeVCqtS6BqQlmQ2jh7RhQAAAWNBYm3fAAAEAwBHMEUCIQChzdTKUU2N%2BXcqcK0OJYrN8EYynloVxho4yPk6Dq3EPgIgdNH5u8rC3UcslQV4B9o0a0w204omDREGKTVuEpxGeOQwDQYJKoZIhvcNAQELBQADggEBAHAPWpanWOW%2Fip2oJ5grAH8mqQfaunuCVE%2Bvac%2B88lkDK%2FLVdFgl2B6kIHZiYClzKtfczG93hWvKbST4NRNHP9LiaQqdNC17e5vNHnXVUGw%2ByxyjMLGqkgepOnZ2Rb14kcTOGp4i5AuJuuaMwXmCo7jUwPwfLe1NUlVBKqg6LK0Hcq4K0sZnxE8HFxiZ92WpV2AVWjRMEc%2F2z2shNoDvxvFUYyY1Oe67xINkmyQKc%2BygSBZzyLnXSFVWmHr3u5dcaaQGGAR42v6Ydr4iL38Hd4dOiBma%2BFXsXBIqWUjbST4VXmdaol7uzFMojA4zkxQDZAvF5XgJlAFadfySna%2Fteik%3D";
+const mozilla_url =
+ "about:certificate?cert=MIIGRjCCBS6gAwIBAgIQDJduPkI49CDWPd%2BG7%2Bu6kDANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5EaWdpQ2VydCBTSEEyIFNlY3VyZSBTZXJ2ZXIgQ0EwHhcNMTgxMTA1MDAwMDAwWhcNMTkxMTEzMTIwMDAwWjCBgzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxHDAaBgNVBAoTE01vemlsbGEgQ29ycG9yYXRpb24xDzANBgNVBAsTBldlYk9wczEYMBYGA1UEAxMPd3d3Lm1vemlsbGEub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuKruymkkmkqCJh7QjmXlUOBcLFRyw5LG%2FvUUWVrsxC2gsbR8WJq%2BcYoYBpoNVStKrO4U2rBh1GEbccvT6qKOQI%2BpjjDxx9cmRdubGTGp8L0MF1ohVvhIvYLumOEoRDDPU4PvGJjGhek%2FojvedPWe8dhciHkxOC2qPFZvVFMwg1%2Fo%2Fb80147BwZQmzB18mnHsmcyKlpsCN8pxw86uao9Iun8gZQrsllW64rTZlRR56pHdAcuGAoZjYZxwS9Z%2BlvrSjEgrddemWyGGalqyFp1rXlVM1Tf4%2FIYWAQXTgTUN303u3xMjss7QK7eUDsACRxiWPLW9XQDd1c%2ByvaYJKzgJ2wIDAQABo4IC6TCCAuUwHwYDVR0jBBgwFoAUD4BhHIIxYdUvKOeNRji0LOHG2eIwHQYDVR0OBBYEFNpSvSGcN2VT%2FB9TdQ8eXwebo60%2FMCcGA1UdEQQgMB6CD3d3dy5tb3ppbGxhLm9yZ4ILbW96aWxsYS5vcmcwDgYDVR0PAQH%2FBAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBrBgNVHR8EZDBiMC%2BgLaArhilodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc3NjYS1zaGEyLWc2LmNybDAvoC2gK4YpaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NzY2Etc2hhMi1nNi5jcmwwTAYDVR0gBEUwQzA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBAgIwfAYIKwYBBQUHAQEEcDBuMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wRgYIKwYBBQUHMAKGOmh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJTZWN1cmVTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH%2FBAIwADCCAQIGCisGAQQB1nkCBAIEgfMEgfAA7gB1AKS5CZC0GFgUh7sTosxncAo8NZgE%2BRvfuON3zQ7IDdwQAAABZuYWiHwAAAQDAEYwRAIgZnMSH1JdG6NASHWTwD0mlP%2Fzbr0hzP263c02Ym0DU64CIEe4QHJDP47j0b6oTFu6RrZz1NQ9cq8Az1KnMKRuaFAlAHUAh3W%2F51l8%2BIxDmV%2B9827%2FVo1HVjb%2FSrVgwbTq%2F16ggw8AAAFm5haJAgAABAMARjBEAiAxGLXkUaOAkZhXNeNR3pWyahZeKmSaMXadgu18SfK1ZAIgKtwu5eGxK76rgaszLCZ9edBIjuU0DKorzPUuxUXFY0QwDQYJKoZIhvcNAQELBQADggEBAKLJAFO3wuaP5MM%2Fed1lhk5Uc2aDokhcM7XyvdhEKSHbgPhcgMoT9YIVoPa70gNC6KHcwoXu0g8wt7X6Vm1ql%2F68G5q844kFuC6JPl4LVT9mciD%2BVW6bHUSXD9xifL9DqdJ0Ic0SllTlM%2Boq5aAeOxUQGXhXIqj6fSQv9fQN6mXxQIoc%2Fgjxteskq%2FVl8YmY1FIZP9Bh7g27kxZ9GAAGQtjTL03RzKAuSg6yeImYVdQWasc7UPnBXlRAzZ8%2BOJThUbzK16a2CI3Rg4agKSJk%2BuA47h1%2FImmngpFLRb%2FMvRX6H1oWcUuyH6O7PZdl0YpwTpw1THIuqCGl%2FwpPgyQgcTM%3D";
+const youtube_url =
+ "about:certificate?cert=MIIIIDCCBwigAwIBAgIQGk0sGNQUuaOL9Rii2XQ4yjANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZpY2VzMSUwIwYDVQQDExxHb29nbGUgSW50ZXJuZXQgQXV0aG9yaXR5IEczMB4XDTE5MDYxODA4MjE1OFoXDTE5MDkxMDA4MTUwMFowZjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEzARBgNVBAoMCkdvb2dsZSBMTEMxFTATBgNVBAMMDCouZ29vZ2xlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABMRScn8kk6qy3LHVktWZWxm%2FMq4kowlEdxQH40wijThZ%2B%2F5Jrqh6UlWnWuiulNorHH2DEW4OkSKreFoYze7w8O6jggWlMIIFoTATBgNVHSUEDDAKBggrBgEFBQcDATAOBgNVHQ8BAf8EBAMCB4AwggRqBgNVHREEggRhMIIEXYIMKi5nb29nbGUuY29tgg0qLmFuZHJvaWQuY29tghYqLmFwcGVuZ2luZS5nb29nbGUuY29tghIqLmNsb3VkLmdvb2dsZS5jb22CGCouY3Jvd2Rzb3VyY2UuZ29vZ2xlLmNvbYIGKi5nLmNvgg4qLmdjcC5ndnQyLmNvbYIRKi5nY3BjZG4uZ3Z0MS5jb22CCiouZ2dwaHQuY26CFiouZ29vZ2xlLWFuYWx5dGljcy5jb22CCyouZ29vZ2xlLmNhggsqLmdvb2dsZS5jbIIOKi5nb29nbGUuY28uaW6CDiouZ29vZ2xlLmNvLmpwgg4qLmdvb2dsZS5jby51a4IPKi5nb29nbGUuY29tLmFygg8qLmdvb2dsZS5jb20uYXWCDyouZ29vZ2xlLmNvbS5icoIPKi5nb29nbGUuY29tLmNvgg8qLmdvb2dsZS5jb20ubXiCDyouZ29vZ2xlLmNvbS50coIPKi5nb29nbGUuY29tLnZuggsqLmdvb2dsZS5kZYILKi5nb29nbGUuZXOCCyouZ29vZ2xlLmZyggsqLmdvb2dsZS5odYILKi5nb29nbGUuaXSCCyouZ29vZ2xlLm5sggsqLmdvb2dsZS5wbIILKi5nb29nbGUucHSCEiouZ29vZ2xlYWRhcGlzLmNvbYIPKi5nb29nbGVhcGlzLmNughEqLmdvb2dsZWNuYXBwcy5jboIUKi5nb29nbGVjb21tZXJjZS5jb22CESouZ29vZ2xldmlkZW8uY29tggwqLmdzdGF0aWMuY26CDSouZ3N0YXRpYy5jb22CEiouZ3N0YXRpY2NuYXBwcy5jboIKKi5ndnQxLmNvbYIKKi5ndnQyLmNvbYIUKi5tZXRyaWMuZ3N0YXRpYy5jb22CDCoudXJjaGluLmNvbYIQKi51cmwuZ29vZ2xlLmNvbYIWKi55b3V0dWJlLW5vY29va2llLmNvbYINKi55b3V0dWJlLmNvbYIWKi55b3V0dWJlZWR1Y2F0aW9uLmNvbYIRKi55b3V0dWJla2lkcy5jb22CByoueXQuYmWCCyoueXRpbWcuY29tghphbmRyb2lkLmNsaWVudHMuZ29vZ2xlLmNvbYILYW5kcm9pZC5jb22CG2RldmVsb3Blci5hbmRyb2lkLmdvb2dsZS5jboIcZGV2ZWxvcGVycy5hbmRyb2lkLmdvb2dsZS5jboIEZy5jb4IIZ2dwaHQuY26CBmdvby5nbIIUZ29vZ2xlLWFuYWx5dGljcy5jb22CCmdvb2dsZS5jb22CD2dvb2dsZWNuYXBwcy5jboISZ29vZ2xlY29tbWVyY2UuY29tghhzb3VyY2UuYW5kcm9pZC5nb29nbGUuY26CCnVyY2hpbi5jb22CCnd3dy5nb28uZ2yCCHlvdXR1LmJlggt5b3V0dWJlLmNvbYIUeW91dHViZWVkdWNhdGlvbi5jb22CD3lvdXR1YmVraWRzLmNvbYIFeXQuYmUwaAYIKwYBBQUHAQEEXDBaMC0GCCsGAQUFBzAChiFodHRwOi8vcGtpLmdvb2cvZ3NyMi9HVFNHSUFHMy5jcnQwKQYIKwYBBQUHMAGGHWh0dHA6Ly9vY3NwLnBraS5nb29nL0dUU0dJQUczMB0GA1UdDgQWBBT8E5DiGEc7xHswBMF5K5EmFzx6fDAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFHfCuFCaZ3Z2sS3ChtCDoH6mfrpLMCEGA1UdIAQaMBgwDAYKKwYBBAHWeQIFAzAIBgZngQwBAgIwMQYDVR0fBCowKDAmoCSgIoYgaHR0cDovL2NybC5wa2kuZ29vZy9HVFNHSUFHMy5jcmwwDQYJKoZIhvcNAQELBQADggEBAGrWCimTdP8%2B6qCqNh1Xza9Wlm%2FGDVb%2BKp0PHUZaNDMThFQQqGn2XVi7ZkhqsxTtMw88Nrl97Bi1OsnNPlabhDwxtRyWkNkLdpFxebRz73CsjyoB3cboH%2FZ8sU9LLwXe%2FIJgMkvT7fznKtKSweWV%2BmAYG%2F3KzaIyLrowYpyOsWaYytPJK7ypuk6yOPxuQcQnelotWpuHUBR3mo3FIW56BPCy20KwqwvWoZe27BNxO%2F11Ym%2FPnric2fWXwgmHdkvVqqssUMFs%2BmG2tS%2FpqnR5yZdQL60xOgDq70mVWYgQT4yUTm7i8qvugvNnuSIjjsbelHgbC8f5%2Fx%2Bo2pEyw%2FDYyKw%3D";
+
+async function checValiditySection(url) {
+ await BrowserTestUtils.withNewTab(url, async function (browser) {
+ await SpecialPowers.spawn(browser, [], async function () {
+ let certificateSection = await ContentTaskUtils.waitForCondition(() => {
+ return content.document.querySelector("certificate-section");
+ }, "Certificate section found");
+
+ let validitySection = certificateSection.shadowRoot.querySelector(
+ "info-group.validity"
+ );
+ Assert.ok(validitySection, "validitySection found");
+
+ let infoItems = validitySection.shadowRoot.querySelectorAll("info-item");
+ Assert.ok(infoItems, "infoItems found");
+ Assert.equal(
+ infoItems.length,
+ 2,
+ "There must be render just one date for Not Before and one for Not After"
+ );
+
+ for (let infoItem of infoItems) {
+ let label = infoItem.shadowRoot
+ .querySelector("label")
+ .getAttribute("data-l10n-id");
+
+ Assert.notEqual(label, "", "Label shouldn't be empty");
+
+ let infoElem = infoItem.shadowRoot.querySelector(".info");
+ let title = infoElem.textContent;
+ Assert.equal(
+ title.includes("GMT"),
+ true,
+ "UTC timezone should be displayed in the label"
+ );
+ }
+ });
+ });
+}
+
+add_task(async function test() {
+ let input = [github_url, mozilla_url, youtube_url];
+ for (let url of input) {
+ await checValiditySection(url);
+ }
+});
diff --git a/toolkit/components/certviewer/tests/browser/browser_downloadLink.js b/toolkit/components/certviewer/tests/browser/browser_downloadLink.js
new file mode 100644
index 0000000000..5b7b587733
--- /dev/null
+++ b/toolkit/components/certviewer/tests/browser/browser_downloadLink.js
@@ -0,0 +1,126 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const validCert =
+ "about:certificate?cert=MIIGMDCCBRigAwIBAgIQCa2oS7Nau6nwv1WyRNIJnzANBgkqhkiG9w0BAQsFADBwMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNzdXJhbmNlIFNlcnZlciBDQTAeFw0xOTA2MDYwMDAwMDBaFw0xOTA5MDQxMjAwMDBaMGExCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTETMBEGA1UEBxMKTWVubG8gUGFyazEXMBUGA1UEChMORmFjZWJvb2ssIEluYy4xFzAVBgNVBAMMDiouZmFjZWJvb2suY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEALPlfjd8gHkIMDeBOFhRt0e%2B%2F3fdm%2BZdzdM4s1WIHVbYztgmdEy20PUwDCviYKJX4GG%2BT9ivT8kJ%2FvWl1P%2FYqOCA54wggOaMB8GA1UdIwQYMBaAFFFo%2F5CvAgd1PMzZZWRiohK4WXI7MB0GA1UdDgQWBBTsQZVRTuib7KY9w3FfOYsZHvOC9zCBxwYDVR0RBIG%2FMIG8gg4qLmZhY2Vib29rLmNvbYINbWVzc2VuZ2VyLmNvbYILKi5mYmNkbi5uZXSCCCouZmIuY29tghAqLm0uZmFjZWJvb2suY29tggZmYi5jb22CDiouZmFjZWJvb2submV0gg4qLnh4LmZiY2RuLm5ldIIOKi54ei5mYmNkbi5uZXSCDyoubWVzc2VuZ2VyLmNvbYILKi5mYnNieC5jb22CDioueHkuZmJjZG4ubmV0ggxmYWNlYm9vay5jb20wDgYDVR0PAQH%2FBAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjB1BgNVHR8EbjBsMDSgMqAwhi5odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzYuY3JsMDSgMqAwhi5odHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzYuY3JsMEwGA1UdIARFMEMwNwYJYIZIAYb9bAEBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQICMIGDBggrBgEFBQcBAQR3MHUwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBNBggrBgEFBQcwAoZBaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkhpZ2hBc3N1cmFuY2VTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH%2FBAIwADCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB1AKS5CZC0GFgUh7sTosxncAo8NZgE%2BRvfuON3zQ7IDdwQAAABay5CAaUAAAQDAEYwRAIgMwBM6q%2BdBwu2mNtMMjTEwJZZxyoUlHUEYO%2BbfkId%2F9MCIAQ2bxhnxrapYv74fzyoTkt9m%2BELq6%2B43OVpivRVKDKTAHcAdH7agzGtMxCRIZzOJU9CcMK%2F%2FV5CIAjGNzV55hB7zFYAAAFrLkIA%2FAAABAMASDBGAiEA0x1xPWue6RMSE9nbjYBt637CRC86ixrODP%2FEIlI5mCgCIQCHNdqgOlswd0LqaW4QRii2JHN4bnoEj%2FD9j7%2BkqEB7LjANBgkqhkiG9w0BAQsFAAOCAQEAnRdIVNZ850s7IvLgg%2BU9kKxA18kLKVpIF%2FrJHkXTkymvBHKAGOFNfzqF2YxHFhkDMIuoMO2F%2BA1E0Eo8zb1atL6%2FL59broEHTOH6xFmJAlZW0h6mZg8iRJ9Ae0pTN%2FfowaoN9aFVRnVr9ccKhOdqsXYyEZ3Ze39sEwx7Uau9KhzyuJW12Jh3S%2BZJYUdBADeeJNL5ZXSUFIyjgkwSQZPaaWAzSGHZFt3sWhMjdNoBkjRJFlASLDM3m1ZWsKA47vuXvJc%2FDXT35lC1DJmyhYb9qNPR71a1hJ8TS7vUwdDd%2BdEHiJj2wQLV3m7Tn7YvWyJOEyi4n6%2FrPqT44LZmgK7HWw%3D%3D&cert=MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBsMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3VyYW5jZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC24C%2FCJAbIbQRf1%2B8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU%2BUDlqUH1VWtMICKq%2FQmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK%2FIHe1NnF9Xt4ZQaJn1itrSxwUfqJfJ3KSxgoQtxq2lnMcZgqaFD15EWCo3j%2F018QsIJzJa9buLnqS9UdAn4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I%2B4G3FhahnSMSTeXXkgisdaScus0Xsh5ENWV%2FUyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcftbZvySC%2FzA%2FWiaJJTL17jAgMBAAGjggFJMIIBRTASBgNVHRMBAf8ECDAGAQH%2FAgEAMA4GA1UdDwEB%2FwQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAdBgNVHQ4EFgQUUWj%2FkK8CB3U8zNllZGKiErhZcjswHwYDVR0jBBgwFoAUsT7DaQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwdaOpKj4PWUS%2BNa0QWnqxj9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk%2FgNHE%2Br1hspZcX30BJZr01lYPf7TMSVcGDiEo%2Bafgv2MW5gxTs14nhr9hctJqvIni5ly%2FD6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zuxICaEnL6VpPX%2F78whQYwvwt%2FTv9XBZ0k7YXDK%2FumdaisLRbvfXknsuvCnQsH6qqF0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY%2B3sAzm2fTYS5yh%2BRp%2FBIAV0AecPUeybQ%3D&cert=MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm%2B9S75S0tMqbf5YE%2Fyc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG%2B%2BMXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx%2BmM0aBhakaHPQNAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH%2FBAQDAgGGMA8GA1UdEwEB%2FwQFMAMBAf8wHQYDVR0OBBYEFLE%2Bw2kD%2BL9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE%2Bw2kD%2BL9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe%2FEW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9%2BMpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2Yzi9RKR%2F5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2%2FS6cCZdkGCevEsXCS%2B0yx5DaMkHJ8HSXPfqIbloEpw8nL%2Be%2FIBcm2PN7EeqJSdnoDfzAIJ9VNep%2BOkuE6N36B9K";
+
+add_task(async function test_checkForErrorSection() {
+ await BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
+ gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, validCert);
+ });
+
+ await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () {
+ let infoGroups;
+ let downloadLinkContainers = [];
+
+ await ContentTaskUtils.waitForCondition(() => {
+ infoGroups = content.document
+ .querySelector("certificate-section")
+ .shadowRoot.querySelectorAll(".miscellaneous");
+ for (let i = 0; i < infoGroups.length; i++) {
+ downloadLinkContainers.push(
+ infoGroups[i].shadowRoot
+ .querySelector(".download")
+ .shadowRoot.querySelector(".info")
+ );
+ }
+ return downloadLinkContainers.length;
+ }, "Found download info items.");
+
+ ok(downloadLinkContainers.length, "Download info items should exist.");
+
+ let certTabs = content.document
+ .querySelector("certificate-section")
+ .shadowRoot.querySelectorAll(".certificate-tab");
+
+ await ContentTaskUtils.waitForCondition(
+ () => certTabs.length,
+ "Certificate tabs should exist."
+ );
+
+ let url = new URL(content.document.documentURI);
+ let certs = url.searchParams.getAll("cert");
+ let certChain = [];
+ for (let i = 0; i < certs.length; i++) {
+ certChain.push(
+ `-----BEGIN CERTIFICATE-----\r\n${certs[i]}\r\n-----END CERTIFICATE-----\r\n`
+ );
+ }
+ certChain = certChain.join("").replace(/(\r\n|\n|\r)/gm, "");
+
+ for (let i = 0; i < certTabs.length; i++) {
+ let downloadLink =
+ downloadLinkContainers[i].querySelector(".download-link");
+
+ let downloadChainLink = downloadLinkContainers[i].querySelector(
+ ".download-link-chain"
+ );
+
+ let cert = certs[i];
+ cert = `-----BEGIN CERTIFICATE-----\r\n${cert}\r\n-----END CERTIFICATE-----\r\n`;
+ cert = cert.replace(/(\r\n|\n|\r)/gm, "");
+
+ let linkCert = downloadLink.getAttribute("href");
+ linkCert = linkCert.replace("data:,", "");
+ linkCert = decodeURI(linkCert);
+ let certLineLength = Math.max(
+ ...linkCert.split(/\r\n|\n|\r/m).map(x => x.length)
+ );
+ linkCert = linkCert.replace(/(\r\n|\n|\r)/gm, "");
+
+ let downloadChainCert = downloadChainLink.getAttribute("href");
+ downloadChainCert = downloadChainCert.replace("data:,", "");
+ downloadChainCert = decodeURI(downloadChainCert);
+ let chainLineLength = Math.max(
+ ...downloadChainCert.split(/\r\n|\n|\r/m).map(x => x.length)
+ );
+ downloadChainCert = downloadChainCert.replace(/(\r\n|\n|\r)/gm, "");
+
+ Assert.lessOrEqual(
+ certLineLength,
+ 64,
+ "PEM cert line length should be capped to 64"
+ );
+ Assert.lessOrEqual(
+ chainLineLength,
+ 64,
+ "PEM chain line length should be capped to 64"
+ );
+
+ Assert.equal(
+ cert,
+ linkCert,
+ "Download link href should be equal to URL cert."
+ );
+
+ Assert.equal(
+ certChain,
+ downloadChainCert,
+ "Download chain link href should be equal to URL cert."
+ );
+
+ await content.document.l10n.translateElements([
+ downloadChainLink,
+ downloadLink,
+ ]);
+
+ Assert.equal(
+ downloadLinkContainers[i].textContent,
+ "PEM (cert)PEM (chain)",
+ "Download should contain links to PEM cert and PEM chain."
+ );
+
+ if (certTabs[i + 1]) {
+ certTabs[i + 1].click();
+
+ await ContentTaskUtils.waitForCondition(
+ () => certTabs[i + 1].classList.contains("selected"),
+ "Cert tab should be selected"
+ );
+ }
+ }
+ });
+ gBrowser.removeCurrentTab(); // closes about:certificate
+});
diff --git a/toolkit/components/certviewer/tests/browser/browser_handleMultipleCertsURL.js b/toolkit/components/certviewer/tests/browser/browser_handleMultipleCertsURL.js
new file mode 100644
index 0000000000..b0199cce83
--- /dev/null
+++ b/toolkit/components/certviewer/tests/browser/browser_handleMultipleCertsURL.js
@@ -0,0 +1,251 @@
+// valids
+const multipleCerts1 =
+ "about:certificate?cert=MIIGRjCCBS6gAwIBAgIQDJduPkI49CDWPd%2BG7%2Bu6kDANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5EaWdpQ2VydCBTSEEyIFNlY3VyZSBTZXJ2ZXIgQ0EwHhcNMTgxMTA1MDAwMDAwWhcNMTkxMTEzMTIwMDAwWjCBgzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxHDAaBgNVBAoTE01vemlsbGEgQ29ycG9yYXRpb24xDzANBgNVBAsTBldlYk9wczEYMBYGA1UEAxMPd3d3Lm1vemlsbGEub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuKruymkkmkqCJh7QjmXlUOBcLFRyw5LG%2FvUUWVrsxC2gsbR8WJq%2BcYoYBpoNVStKrO4U2rBh1GEbccvT6qKOQI%2BpjjDxx9cmRdubGTGp8L0MF1ohVvhIvYLumOEoRDDPU4PvGJjGhek%2FojvedPWe8dhciHkxOC2qPFZvVFMwg1%2Fo%2Fb80147BwZQmzB18mnHsmcyKlpsCN8pxw86uao9Iun8gZQrsllW64rTZlRR56pHdAcuGAoZjYZxwS9Z%2BlvrSjEgrddemWyGGalqyFp1rXlVM1Tf4%2FIYWAQXTgTUN303u3xMjss7QK7eUDsACRxiWPLW9XQDd1c%2ByvaYJKzgJ2wIDAQABo4IC6TCCAuUwHwYDVR0jBBgwFoAUD4BhHIIxYdUvKOeNRji0LOHG2eIwHQYDVR0OBBYEFNpSvSGcN2VT%2FB9TdQ8eXwebo60%2FMCcGA1UdEQQgMB6CD3d3dy5tb3ppbGxhLm9yZ4ILbW96aWxsYS5vcmcwDgYDVR0PAQH%2FBAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBrBgNVHR8EZDBiMC%2BgLaArhilodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc3NjYS1zaGEyLWc2LmNybDAvoC2gK4YpaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NzY2Etc2hhMi1nNi5jcmwwTAYDVR0gBEUwQzA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBAgIwfAYIKwYBBQUHAQEEcDBuMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wRgYIKwYBBQUHMAKGOmh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJTZWN1cmVTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH%2FBAIwADCCAQIGCisGAQQB1nkCBAIEgfMEgfAA7gB1AKS5CZC0GFgUh7sTosxncAo8NZgE%2BRvfuON3zQ7IDdwQAAABZuYWiHwAAAQDAEYwRAIgZnMSH1JdG6NASHWTwD0mlP%2Fzbr0hzP263c02Ym0DU64CIEe4QHJDP47j0b6oTFu6RrZz1NQ9cq8Az1KnMKRuaFAlAHUAh3W%2F51l8%2BIxDmV%2B9827%2FVo1HVjb%2FSrVgwbTq%2F16ggw8AAAFm5haJAgAABAMARjBEAiAxGLXkUaOAkZhXNeNR3pWyahZeKmSaMXadgu18SfK1ZAIgKtwu5eGxK76rgaszLCZ9edBIjuU0DKorzPUuxUXFY0QwDQYJKoZIhvcNAQELBQADggEBAKLJAFO3wuaP5MM%2Fed1lhk5Uc2aDokhcM7XyvdhEKSHbgPhcgMoT9YIVoPa70gNC6KHcwoXu0g8wt7X6Vm1ql%2F68G5q844kFuC6JPl4LVT9mciD%2BVW6bHUSXD9xifL9DqdJ0Ic0SllTlM%2Boq5aAeOxUQGXhXIqj6fSQv9fQN6mXxQIoc%2Fgjxteskq%2FVl8YmY1FIZP9Bh7g27kxZ9GAAGQtjTL03RzKAuSg6yeImYVdQWasc7UPnBXlRAzZ8%2BOJThUbzK16a2CI3Rg4agKSJk%2BuA47h1%2FImmngpFLRb%2FMvRX6H1oWcUuyH6O7PZdl0YpwTpw1THIuqCGl%2FwpPgyQgcTM%3D&cert=MIIHQjCCBiqgAwIBAgIQCgYwQn9bvO1pVzllk7ZFHzANBgkqhkiG9w0BAQsFADB1MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTQwMgYDVQQDEytEaWdpQ2VydCBTSEEyIEV4dGVuZGVkIFZhbGlkYXRpb24gU2VydmVyIENBMB4XDTE4MDUwODAwMDAwMFoXDTIwMDYwMzEyMDAwMFowgccxHTAbBgNVBA8MFFByaXZhdGUgT3JnYW5pemF0aW9uMRMwEQYLKwYBBAGCNzwCAQMTAlVTMRkwFwYLKwYBBAGCNzwCAQITCERlbGF3YXJlMRAwDgYDVQQFEwc1MTU3NTUwMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEVMBMGA1UEChMMR2l0SHViLCBJbmMuMRMwEQYDVQQDEwpnaXRodWIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxjyq8jyXDDrBTyitcnB90865tWBzpHSbindG%2FXqYQkzFMBlXmqkzC%2BFdTRBYyneZw5Pz%2BXWQvL%2B74JW6LsWNc2EF0xCEqLOJuC9zjPAqbr7uroNLghGxYf13YdqbG5oj%2F4x%2BogEG3dF%2FU5YIwVr658DKyESMV6eoYV9mDVfTuJastkqcwero%2B5ZAKfYVMLUEsMwFtoTDJFmVf6JlkOWwsxp1WcQ%2FMRQK1cyqOoUFUgYylgdh3yeCDPeF22Ax8AlQxbcaI%2BGwfQL1FB7Jy%2Bh%2BKjME9lE%2FUpgV6Qt2R1xNSmvFCBWu%2BNFX6epwFP%2FJRbkMfLz0beYFUvmMgLtwVpEPSwIDAQABo4IDeTCCA3UwHwYDVR0jBBgwFoAUPdNQpdagre7zSmAKZdMh1Pj41g8wHQYDVR0OBBYEFMnCU2FmnV%2BrJfQmzQ84mqhJ6kipMCUGA1UdEQQeMByCCmdpdGh1Yi5jb22CDnd3dy5naXRodWIuY29tMA4GA1UdDwEB%2FwQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdQYDVR0fBG4wbDA0oDKgMIYuaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItZXYtc2VydmVyLWcyLmNybDA0oDKgMIYuaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItZXYtc2VydmVyLWcyLmNybDBLBgNVHSAERDBCMDcGCWCGSAGG%2FWwCATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAcGBWeBDAEBMIGIBggrBgEFBQcBAQR8MHowJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBSBggrBgEFBQcwAoZGaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkV4dGVuZGVkVmFsaWRhdGlvblNlcnZlckNBLmNydDAMBgNVHRMBAf8EAjAAMIIBfgYKKwYBBAHWeQIEAgSCAW4EggFqAWgAdgCkuQmQtBhYFIe7E6LMZ3AKPDWYBPkb37jjd80OyA3cEAAAAWNBYm0KAAAEAwBHMEUCIQDRZp38cTWsWH2GdBpe%2FuPTWnsu%2Fm4BEC2%2BdIcvSykZYgIgCP5gGv6yzaazxBK2NwGdmmyuEFNSg2pARbMJlUFgU5UAdgBWFAaaL9fC7NP14b1Esj7HRna5vJkRXMDvlJhV1onQ3QAAAWNBYm0tAAAEAwBHMEUCIQCi7omUvYLm0b2LobtEeRAYnlIo7n6JxbYdrtYdmPUWJQIgVgw1AZ51vK9ENinBg22FPxb82TvNDO05T17hxXRC2IYAdgC72d%2B8H4pxtZOUI5eqkntHOFeVCqtS6BqQlmQ2jh7RhQAAAWNBYm3fAAAEAwBHMEUCIQChzdTKUU2N%2BXcqcK0OJYrN8EYynloVxho4yPk6Dq3EPgIgdNH5u8rC3UcslQV4B9o0a0w204omDREGKTVuEpxGeOQwDQYJKoZIhvcNAQELBQADggEBAHAPWpanWOW%2Fip2oJ5grAH8mqQfaunuCVE%2Bvac%2B88lkDK%2FLVdFgl2B6kIHZiYClzKtfczG93hWvKbST4NRNHP9LiaQqdNC17e5vNHnXVUGw%2ByxyjMLGqkgepOnZ2Rb14kcTOGp4i5AuJuuaMwXmCo7jUwPwfLe1NUlVBKqg6LK0Hcq4K0sZnxE8HFxiZ92WpV2AVWjRMEc%2F2z2shNoDvxvFUYyY1Oe67xINkmyQKc%2BygSBZzyLnXSFVWmHr3u5dcaaQGGAR42v6Ydr4iL38Hd4dOiBma%2BFXsXBIqWUjbST4VXmdaol7uzFMojA4zkxQDZAvF5XgJlAFadfySna%2Fteik%3D";
+const multipleCerts2 =
+ "about:certificate?cert=MIIIIDCCBwigAwIBAgIQGk0sGNQUuaOL9Rii2XQ4yjANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZpY2VzMSUwIwYDVQQDExxHb29nbGUgSW50ZXJuZXQgQXV0aG9yaXR5IEczMB4XDTE5MDYxODA4MjE1OFoXDTE5MDkxMDA4MTUwMFowZjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEzARBgNVBAoMCkdvb2dsZSBMTEMxFTATBgNVBAMMDCouZ29vZ2xlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABMRScn8kk6qy3LHVktWZWxm%2FMq4kowlEdxQH40wijThZ%2B%2F5Jrqh6UlWnWuiulNorHH2DEW4OkSKreFoYze7w8O6jggWlMIIFoTATBgNVHSUEDDAKBggrBgEFBQcDATAOBgNVHQ8BAf8EBAMCB4AwggRqBgNVHREEggRhMIIEXYIMKi5nb29nbGUuY29tgg0qLmFuZHJvaWQuY29tghYqLmFwcGVuZ2luZS5nb29nbGUuY29tghIqLmNsb3VkLmdvb2dsZS5jb22CGCouY3Jvd2Rzb3VyY2UuZ29vZ2xlLmNvbYIGKi5nLmNvgg4qLmdjcC5ndnQyLmNvbYIRKi5nY3BjZG4uZ3Z0MS5jb22CCiouZ2dwaHQuY26CFiouZ29vZ2xlLWFuYWx5dGljcy5jb22CCyouZ29vZ2xlLmNhggsqLmdvb2dsZS5jbIIOKi5nb29nbGUuY28uaW6CDiouZ29vZ2xlLmNvLmpwgg4qLmdvb2dsZS5jby51a4IPKi5nb29nbGUuY29tLmFygg8qLmdvb2dsZS5jb20uYXWCDyouZ29vZ2xlLmNvbS5icoIPKi5nb29nbGUuY29tLmNvgg8qLmdvb2dsZS5jb20ubXiCDyouZ29vZ2xlLmNvbS50coIPKi5nb29nbGUuY29tLnZuggsqLmdvb2dsZS5kZYILKi5nb29nbGUuZXOCCyouZ29vZ2xlLmZyggsqLmdvb2dsZS5odYILKi5nb29nbGUuaXSCCyouZ29vZ2xlLm5sggsqLmdvb2dsZS5wbIILKi5nb29nbGUucHSCEiouZ29vZ2xlYWRhcGlzLmNvbYIPKi5nb29nbGVhcGlzLmNughEqLmdvb2dsZWNuYXBwcy5jboIUKi5nb29nbGVjb21tZXJjZS5jb22CESouZ29vZ2xldmlkZW8uY29tggwqLmdzdGF0aWMuY26CDSouZ3N0YXRpYy5jb22CEiouZ3N0YXRpY2NuYXBwcy5jboIKKi5ndnQxLmNvbYIKKi5ndnQyLmNvbYIUKi5tZXRyaWMuZ3N0YXRpYy5jb22CDCoudXJjaGluLmNvbYIQKi51cmwuZ29vZ2xlLmNvbYIWKi55b3V0dWJlLW5vY29va2llLmNvbYINKi55b3V0dWJlLmNvbYIWKi55b3V0dWJlZWR1Y2F0aW9uLmNvbYIRKi55b3V0dWJla2lkcy5jb22CByoueXQuYmWCCyoueXRpbWcuY29tghphbmRyb2lkLmNsaWVudHMuZ29vZ2xlLmNvbYILYW5kcm9pZC5jb22CG2RldmVsb3Blci5hbmRyb2lkLmdvb2dsZS5jboIcZGV2ZWxvcGVycy5hbmRyb2lkLmdvb2dsZS5jboIEZy5jb4IIZ2dwaHQuY26CBmdvby5nbIIUZ29vZ2xlLWFuYWx5dGljcy5jb22CCmdvb2dsZS5jb22CD2dvb2dsZWNuYXBwcy5jboISZ29vZ2xlY29tbWVyY2UuY29tghhzb3VyY2UuYW5kcm9pZC5nb29nbGUuY26CCnVyY2hpbi5jb22CCnd3dy5nb28uZ2yCCHlvdXR1LmJlggt5b3V0dWJlLmNvbYIUeW91dHViZWVkdWNhdGlvbi5jb22CD3lvdXR1YmVraWRzLmNvbYIFeXQuYmUwaAYIKwYBBQUHAQEEXDBaMC0GCCsGAQUFBzAChiFodHRwOi8vcGtpLmdvb2cvZ3NyMi9HVFNHSUFHMy5jcnQwKQYIKwYBBQUHMAGGHWh0dHA6Ly9vY3NwLnBraS5nb29nL0dUU0dJQUczMB0GA1UdDgQWBBT8E5DiGEc7xHswBMF5K5EmFzx6fDAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFHfCuFCaZ3Z2sS3ChtCDoH6mfrpLMCEGA1UdIAQaMBgwDAYKKwYBBAHWeQIFAzAIBgZngQwBAgIwMQYDVR0fBCowKDAmoCSgIoYgaHR0cDovL2NybC5wa2kuZ29vZy9HVFNHSUFHMy5jcmwwDQYJKoZIhvcNAQELBQADggEBAGrWCimTdP8%2B6qCqNh1Xza9Wlm%2FGDVb%2BKp0PHUZaNDMThFQQqGn2XVi7ZkhqsxTtMw88Nrl97Bi1OsnNPlabhDwxtRyWkNkLdpFxebRz73CsjyoB3cboH%2FZ8sU9LLwXe%2FIJgMkvT7fznKtKSweWV%2BmAYG%2F3KzaIyLrowYpyOsWaYytPJK7ypuk6yOPxuQcQnelotWpuHUBR3mo3FIW56BPCy20KwqwvWoZe27BNxO%2F11Ym%2FPnric2fWXwgmHdkvVqqssUMFs%2BmG2tS%2FpqnR5yZdQL60xOgDq70mVWYgQT4yUTm7i8qvugvNnuSIjjsbelHgbC8f5%2Fx%2Bo2pEyw%2FDYyKw%3D&cert=MIIGcTCCBVmgAwIBAgIQCHx760AsIFydVjey10GPXTANBgkqhkiG9w0BAQsFADBwMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNzdXJhbmNlIFNlcnZlciBDQTAeFw0xOTA1MjQwMDAwMDBaFw0yMDA1MjMxMjAwMDBaMHkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRYwFAYDVQQKEw1Ud2l0dGVyLCBJbmMuMQ0wCwYDVQQLEwRhdGxhMRYwFAYDVQQDDA0qLnR3aXR0ZXIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4IL8Mo0RIfgZmVhwMiaq30EfjJzcB1dalwHZb2K6P6LtmEpLs%2Bnqm1FCdfZgKO3u4CAbd5Oc2EaZB5KjhOcEo6GjhGKcLS430y%2FXhqWo6dDWWYal1Ulu7CCvNLir0Q5aQ2m8EJuafK%2BqwxSBCGXiWeT4HXqabyU34i70bQbgBSjvffaHr27HVrD4hxq0DspKTIpf0fc4%2B%2Fs%2FTTbxEmX7FbVgmu3Y3rTpeNXegL2Lp5nrGp1drWpcM6g8PlrlhcWujdD2Sb0BpIO0dFNCmvOwDspKt8Ih7t0Sw3Q7u0EGEGJLt%2BgY7nrBoRm1G0DSBd0Ih4coHzfgoGBPy11atynvLwIDAQABo4IC%2FDCCAvgwHwYDVR0jBBgwFoAUUWj%2FkK8CB3U8zNllZGKiErhZcjswHQYDVR0OBBYEFNFZBVr1ptzC%2FiUkvSIQ8QAGfB5jMCUGA1UdEQQeMByCDSoudHdpdHRlci5jb22CC3R3aXR0ZXIuY29tMA4GA1UdDwEB%2FwQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdQYDVR0fBG4wbDA0oDKgMIYuaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItaGEtc2VydmVyLWc2LmNybDA0oDKgMIYuaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItaGEtc2VydmVyLWc2LmNybDBMBgNVHSAERTBDMDcGCWCGSAGG%2FWwBATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAgGBmeBDAECAjCBgwYIKwYBBQUHAQEEdzB1MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wTQYIKwYBBQUHMAKGQWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJIaWdoQXNzdXJhbmNlU2VydmVyQ0EuY3J0MAwGA1UdEwEB%2FwQCMAAwggEFBgorBgEEAdZ5AgQCBIH2BIHzAPEAdgDuS723dc5guuFCaR%2Br4Z5mow9%2BX7By2IMAxHuJeqj9ywAAAWrrCDXmAAAEAwBHMEUCIQCSwzRMoifj1DjYLJuMOH%2BZ6coX83bWIgWgWynLUED87wIgFKdipP9ycAE8S9apXJxKQyp0RoA%2Ftca5%2BWHQE5VlF68AdwCHdb%2FnWXz4jEOZX73zbv9WjUdWNv9KtWDBtOr%2FXqCDDwAAAWrrCDakAAAEAwBIMEYCIQCcmFOfp58BDMFZZS%2FRVl2uiY94RcTozBrcmtkpoWhgkgIhAN%2BX3ODViV4HnN2ZpZ383mFaEHIjKACRdWTRL%2BcYA43lMA0GCSqGSIb3DQEBCwUAA4IBAQB8LQLmUzevGtdw%2FXVL8aFrotloF3zsUPb2Q7CONLzlMGrmfv%2BNKDXN9xqPLLzmX4MddOjfpbVcDX1mJkuvuYNhh5AQrsaxcfEgfMcqPOdELA1mHPfk8H5a8Tvno1nF9wQWqkCQjLedjKReivmDOGfs1%2Fl%2FDnrprc0v4f28cWvN7YkJsdqfEGLbJ6SKsAxNbtNn%2Ffi6LxnemjLbcTrZYps11Ex55PtDNc200ejqpbpzHolgAew4KUzsyElaYSvDwkLMdmfwYSI9wgcPmrPBfZ0N12TAfmJJbE%2FkZc0jIOi92A%2FVgZLKvQrxadnBqPzAR%2F2SrZMT5joWa5sHpwl9fg5Z";
+
+// both invalids
+const errorCerts1 = "about:certificate?cert=aa&cert=bb&cert=abc";
+// one invalid and other valid
+const errorCerts2 =
+ "about:certificate?cert=aa&cert=MIIGRjCCBS6gAwIBAgIQDJduPkI49CDWPd%2BG7%2Bu6kDANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5EaWdpQ2VydCBTSEEyIFNlY3VyZSBTZXJ2ZXIgQ0EwHhcNMTgxMTA1MDAwMDAwWhcNMTkxMTEzMTIwMDAwWjCBgzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxHDAaBgNVBAoTE01vemlsbGEgQ29ycG9yYXRpb24xDzANBgNVBAsTBldlYk9wczEYMBYGA1UEAxMPd3d3Lm1vemlsbGEub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuKruymkkmkqCJh7QjmXlUOBcLFRyw5LG%2FvUUWVrsxC2gsbR8WJq%2BcYoYBpoNVStKrO4U2rBh1GEbccvT6qKOQI%2BpjjDxx9cmRdubGTGp8L0MF1ohVvhIvYLumOEoRDDPU4PvGJjGhek%2FojvedPWe8dhciHkxOC2qPFZvVFMwg1%2Fo%2Fb80147BwZQmzB18mnHsmcyKlpsCN8pxw86uao9Iun8gZQrsllW64rTZlRR56pHdAcuGAoZjYZxwS9Z%2BlvrSjEgrddemWyGGalqyFp1rXlVM1Tf4%2FIYWAQXTgTUN303u3xMjss7QK7eUDsACRxiWPLW9XQDd1c%2ByvaYJKzgJ2wIDAQABo4IC6TCCAuUwHwYDVR0jBBgwFoAUD4BhHIIxYdUvKOeNRji0LOHG2eIwHQYDVR0OBBYEFNpSvSGcN2VT%2FB9TdQ8eXwebo60%2FMCcGA1UdEQQgMB6CD3d3dy5tb3ppbGxhLm9yZ4ILbW96aWxsYS5vcmcwDgYDVR0PAQH%2FBAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBrBgNVHR8EZDBiMC%2BgLaArhilodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc3NjYS1zaGEyLWc2LmNybDAvoC2gK4YpaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NzY2Etc2hhMi1nNi5jcmwwTAYDVR0gBEUwQzA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBAgIwfAYIKwYBBQUHAQEEcDBuMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wRgYIKwYBBQUHMAKGOmh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJTZWN1cmVTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH%2FBAIwADCCAQIGCisGAQQB1nkCBAIEgfMEgfAA7gB1AKS5CZC0GFgUh7sTosxncAo8NZgE%2BRvfuON3zQ7IDdwQAAABZuYWiHwAAAQDAEYwRAIgZnMSH1JdG6NASHWTwD0mlP%2Fzbr0hzP263c02Ym0DU64CIEe4QHJDP47j0b6oTFu6RrZz1NQ9cq8Az1KnMKRuaFAlAHUAh3W%2F51l8%2BIxDmV%2B9827%2FVo1HVjb%2FSrVgwbTq%2F16ggw8AAAFm5haJAgAABAMARjBEAiAxGLXkUaOAkZhXNeNR3pWyahZeKmSaMXadgu18SfK1ZAIgKtwu5eGxK76rgaszLCZ9edBIjuU0DKorzPUuxUXFY0QwDQYJKoZIhvcNAQELBQADggEBAKLJAFO3wuaP5MM%2Fed1lhk5Uc2aDokhcM7XyvdhEKSHbgPhcgMoT9YIVoPa70gNC6KHcwoXu0g8wt7X6Vm1ql%2F68G5q844kFuC6JPl4LVT9mciD%2BVW6bHUSXD9xifL9DqdJ0Ic0SllTlM%2Boq5aAeOxUQGXhXIqj6fSQv9fQN6mXxQIoc%2Fgjxteskq%2FVl8YmY1FIZP9Bh7g27kxZ9GAAGQtjTL03RzKAuSg6yeImYVdQWasc7UPnBXlRAzZ8%2BOJThUbzK16a2CI3Rg4agKSJk%2BuA47h1%2FImmngpFLRb%2FMvRX6H1oWcUuyH6O7PZdl0YpwTpw1THIuqCGl%2FwpPgyQgcTM%3D";
+
+async function checkSubjectName(inputPage, subjectsNameInfo) {
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url: inputPage,
+ },
+ async function (browser) {
+ await SpecialPowers.spawn(
+ browser,
+ [subjectsNameInfo],
+ async function (subjectsNameInfoExpected) {
+ let certificateSection = await ContentTaskUtils.waitForCondition(
+ () => {
+ return content.document.querySelector("certificate-section");
+ },
+ "Certificate section found"
+ );
+
+ async function selectTab(tabName, index) {
+ let tabs =
+ certificateSection.shadowRoot.querySelector(".certificate-tabs");
+
+ let tab = tabs.querySelector(`.tab[idnumber="${index}"]`);
+ Assert.ok(tab, `Tab at index ${index} found`);
+ Assert.equal(
+ tab.innerText,
+ tabName,
+ `Tab name should be ${tabName}`
+ );
+
+ tab.click();
+ }
+
+ function checkSelectedTab(sectionItemsExpected, index) {
+ let infoGroup = certificateSection.shadowRoot.querySelector(
+ `#panel${index} info-group`
+ );
+ Assert.ok(infoGroup, "infoGroup found");
+
+ let sectionTitle =
+ infoGroup.shadowRoot.querySelector(".info-group-title").innerText;
+ Assert.equal(
+ sectionTitle,
+ "Subject Name",
+ "Subject Name must be the selected item"
+ );
+
+ let infoItems = infoGroup.shadowRoot.querySelectorAll("info-item");
+ Assert.equal(
+ infoItems.length,
+ sectionItemsExpected.length,
+ "sectionItems must be the same length"
+ );
+ }
+
+ for (let i = 0; i < subjectsNameInfoExpected.length; i++) {
+ await selectTab(subjectsNameInfoExpected[i].tabName, i);
+ checkSelectedTab(subjectsNameInfoExpected[i].sectionItems, i);
+ }
+ }
+ );
+ }
+ );
+}
+
+async function checkTabsName(inputPage, tabsNames) {
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url: inputPage,
+ },
+ async function (browser) {
+ await SpecialPowers.spawn(
+ browser,
+ [tabsNames],
+ async function (expectedTabsNames) {
+ let certificateSection = await ContentTaskUtils.waitForCondition(
+ () => {
+ return content.document.querySelector("certificate-section");
+ },
+ "Certificate section found"
+ );
+
+ let tabsSection =
+ certificateSection.shadowRoot.querySelector(".certificate-tabs");
+ Assert.ok(tabsSection, "Tabs section found");
+
+ let tabs = tabsSection.children;
+ Assert.equal(
+ tabs.length,
+ expectedTabsNames.length,
+ `There must be ${expectedTabsNames.length} tabs`
+ );
+
+ for (let i = 0; i < expectedTabsNames.length; i++) {
+ Assert.equal(
+ tabs[i].innerText,
+ expectedTabsNames[i],
+ "Tab name must be equal to expected tab name"
+ );
+ if (i === 0) {
+ Assert.ok(
+ tabs[i].className.includes("selected"),
+ "First tab must be selected"
+ );
+ } else {
+ Assert.equal(
+ tabs[i].className.includes("selected"),
+ false,
+ "Just the first tab must be selected"
+ );
+ }
+ }
+ }
+ );
+ }
+ );
+}
+
+async function checkDOM(inputPage, errorExpected) {
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url: inputPage,
+ },
+ async function (browser) {
+ await SpecialPowers.spawn(
+ browser,
+ [errorExpected],
+ async function (errorExpected) {
+ let certificateSection = await ContentTaskUtils.waitForCondition(
+ () => {
+ return content.document.querySelector("certificate-section");
+ },
+ "Certificate section found"
+ );
+
+ let errorSection =
+ certificateSection.shadowRoot.querySelector("error-section");
+
+ if (errorExpected) {
+ // should render error page
+ Assert.ok(errorSection, "Error section found");
+ } else {
+ // should render page with certificate info
+ Assert.equal(errorSection, null, "Error section was not found");
+ }
+ }
+ );
+ }
+ );
+}
+
+add_task(async function runTests() {
+ let inputs = [
+ {
+ url: multipleCerts1,
+ tabsNames: ["www.mozilla.org", "github.com"],
+ errorPageExpected: false,
+ subjectNameInfo: [
+ {
+ tabName: "www.mozilla.org",
+ sectionTitle: "Subject Name",
+ sectionItems: [
+ { label: "Country", info: "US" },
+ { label: "State / Province", info: "California" },
+ { label: "Locality", info: "Mountain View" },
+ { label: "Organization", info: "Mozilla Corporation" },
+ { label: "Organizational Unit", info: "WebOps" },
+ { label: "Common Name", info: "www.mozilla.org" },
+ ],
+ },
+ {
+ tabName: "github.com",
+ sectionTitle: "Subject Name",
+ sectionItems: [
+ { label: "Business Category", info: "Private Organization" },
+ { label: "Inc. Country", info: "US" },
+ { label: "Inc. State / Province", info: "Delaware" },
+ { label: "Serial Number", info: "5157550" },
+ { label: "Country", info: "US" },
+ { label: "State / Province", info: "California" },
+ { label: "Locality", info: "San Francisco" },
+ { label: "Organization", info: "GitHub, Inc." },
+ { label: "Common Name", info: "github.com" },
+ ],
+ },
+ ],
+ },
+ {
+ url: multipleCerts2,
+ tabsNames: ["*.google.com", "*.twitter.com"],
+ errorPageExpected: false,
+ subjectNameInfo: [
+ {
+ tabName: "*.google.com",
+ sectionTitle: "Subject Name",
+ sectionItems: [
+ { label: "Country", info: "US" },
+ { label: "State / Province", info: "California" },
+ { label: "Locality", info: "Mountain View" },
+ { label: "Organization", info: "Google LLC" },
+ { label: "Common Name", info: "*.google.com" },
+ ],
+ },
+ {
+ tabName: "*.twitter.com",
+ sectionTitle: "Subject Name",
+ sectionItems: [
+ { label: "Country", info: "US" },
+ { label: "State / Province", info: "California" },
+ { label: "Locality", info: "San Francisco" },
+ { label: "Organization", info: "Twitter, Inc." },
+ { label: "Organizational Unit", info: "atla" },
+ { label: "Common Name", info: "*.twitter.com" },
+ ],
+ },
+ ],
+ },
+ {
+ url: errorCerts1,
+ tabsNames: [],
+ errorPageExpected: true,
+ },
+ {
+ url: errorCerts2,
+ tabsNames: [],
+ errorPageExpected: true,
+ },
+ ];
+
+ for (let input of inputs) {
+ await checkDOM(input.url, input.errorPageExpected);
+ if (!input.errorPageExpected) {
+ await checkTabsName(input.url, input.tabsNames);
+ await checkSubjectName(input.url, input.subjectNameInfo);
+ }
+ }
+});
diff --git a/toolkit/components/certviewer/tests/browser/browser_openTabAndSendCertInfo.js b/toolkit/components/certviewer/tests/browser/browser_openTabAndSendCertInfo.js
new file mode 100644
index 0000000000..c6307f529a
--- /dev/null
+++ b/toolkit/components/certviewer/tests/browser/browser_openTabAndSendCertInfo.js
@@ -0,0 +1,271 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const TEST_CERT_BASE64 =
+ "MIIGRjCCBS6gAwIBAgIQDJduPkI49CDWPd+G7+u6kDANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5EaWdpQ2VydCBTSEEyIFNlY3VyZSBTZXJ2ZXIgQ0EwHhcNMTgxMTA1MDAwMDAwWhcNMTkxMTEzMTIwMDAwWjCBgzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxHDAaBgNVBAoTE01vemlsbGEgQ29ycG9yYXRpb24xDzANBgNVBAsTBldlYk9wczEYMBYGA1UEAxMPd3d3Lm1vemlsbGEub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuKruymkkmkqCJh7QjmXlUOBcLFRyw5LG/vUUWVrsxC2gsbR8WJq+cYoYBpoNVStKrO4U2rBh1GEbccvT6qKOQI+pjjDxx9cmRdubGTGp8L0MF1ohVvhIvYLumOEoRDDPU4PvGJjGhek/ojvedPWe8dhciHkxOC2qPFZvVFMwg1/o/b80147BwZQmzB18mnHsmcyKlpsCN8pxw86uao9Iun8gZQrsllW64rTZlRR56pHdAcuGAoZjYZxwS9Z+lvrSjEgrddemWyGGalqyFp1rXlVM1Tf4/IYWAQXTgTUN303u3xMjss7QK7eUDsACRxiWPLW9XQDd1c+yvaYJKzgJ2wIDAQABo4IC6TCCAuUwHwYDVR0jBBgwFoAUD4BhHIIxYdUvKOeNRji0LOHG2eIwHQYDVR0OBBYEFNpSvSGcN2VT/B9TdQ8eXwebo60/MCcGA1UdEQQgMB6CD3d3dy5tb3ppbGxhLm9yZ4ILbW96aWxsYS5vcmcwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBrBgNVHR8EZDBiMC+gLaArhilodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc3NjYS1zaGEyLWc2LmNybDAvoC2gK4YpaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NzY2Etc2hhMi1nNi5jcmwwTAYDVR0gBEUwQzA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBAgIwfAYIKwYBBQUHAQEEcDBuMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wRgYIKwYBBQUHMAKGOmh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJTZWN1cmVTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH/BAIwADCCAQIGCisGAQQB1nkCBAIEgfMEgfAA7gB1AKS5CZC0GFgUh7sTosxncAo8NZgE+RvfuON3zQ7IDdwQAAABZuYWiHwAAAQDAEYwRAIgZnMSH1JdG6NASHWTwD0mlP/zbr0hzP263c02Ym0DU64CIEe4QHJDP47j0b6oTFu6RrZz1NQ9cq8Az1KnMKRuaFAlAHUAh3W/51l8+IxDmV+9827/Vo1HVjb/SrVgwbTq/16ggw8AAAFm5haJAgAABAMARjBEAiAxGLXkUaOAkZhXNeNR3pWyahZeKmSaMXadgu18SfK1ZAIgKtwu5eGxK76rgaszLCZ9edBIjuU0DKorzPUuxUXFY0QwDQYJKoZIhvcNAQELBQADggEBAKLJAFO3wuaP5MM/ed1lhk5Uc2aDokhcM7XyvdhEKSHbgPhcgMoT9YIVoPa70gNC6KHcwoXu0g8wt7X6Vm1ql/68G5q844kFuC6JPl4LVT9mciD+VW6bHUSXD9xifL9DqdJ0Ic0SllTlM+oq5aAeOxUQGXhXIqj6fSQv9fQN6mXxQIoc/gjxteskq/Vl8YmY1FIZP9Bh7g27kxZ9GAAGQtjTL03RzKAuSg6yeImYVdQWasc7UPnBXlRAzZ8+OJThUbzK16a2CI3Rg4agKSJk+uA47h1/ImmngpFLRb/MvRX6H1oWcUuyH6O7PZdl0YpwTpw1THIuqCGl/wpPgyQgcTM=";
+
+function checkSpec(spec) {
+ Assert.ok(
+ spec.startsWith("about:certificate"),
+ "about:certificate was opened"
+ );
+
+ let newUrl = new URL(spec);
+ let certEncoded = newUrl.searchParams.get("cert");
+ let certDecoded = decodeURIComponent(certEncoded);
+ Assert.equal(
+ btoa(atob(certDecoded)),
+ certDecoded,
+ "We received an base64 string"
+ );
+}
+
+function checksCertTab(tabsCount) {
+ Assert.equal(gBrowser.tabs.length, tabsCount + 1, "New tab was opened");
+ let spec = gBrowser.tabs[tabsCount].linkedBrowser.documentURI.spec;
+ checkSpec(spec);
+}
+
+async function checkCertChain(browser) {
+ await SpecialPowers.spawn(browser, [], async function () {
+ let certificateTabs;
+ await ContentTaskUtils.waitForCondition(() => {
+ let certificateSection = content.document.querySelector(
+ "certificate-section"
+ );
+ if (!certificateSection) {
+ return false;
+ }
+ certificateTabs =
+ certificateSection.shadowRoot.querySelectorAll(".certificate-tab");
+ return certificateTabs.length;
+ }, "Found certificate tabs.");
+
+ Assert.greaterOrEqual(
+ certificateTabs.length,
+ 1,
+ "Certificate chain tabs shown"
+ );
+ });
+}
+
+// taken from https://searchfox.org/mozilla-central/rev/7ed8e2d3d1d7a1464ba42763a33fd2e60efcaedc/security/manager/ssl/tests/mochitest/browser/browser_downloadCert_ui.js#47
+function openCertDownloadDialog(cert) {
+ let returnVals = Cc["@mozilla.org/hash-property-bag;1"].createInstance(
+ Ci.nsIWritablePropertyBag2
+ );
+ let win = window.openDialog(
+ "chrome://pippki/content/downloadcert.xhtml",
+ "",
+ "",
+ cert,
+ returnVals
+ );
+ return new Promise((resolve, reject) => {
+ win.addEventListener(
+ "load",
+ function () {
+ executeSoon(() => resolve([win]));
+ },
+ { once: true }
+ );
+ });
+}
+
+add_task(async function openFromPopUp() {
+ info("Testing openFromPopUp");
+
+ const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
+ Ci.nsIX509CertDB
+ );
+ let cert = certdb.constructX509FromBase64(TEST_CERT_BASE64);
+
+ let [win] = await openCertDownloadDialog(cert);
+ let viewCertButton = win.document.getElementById("viewC-button");
+ let newWinOpened = BrowserTestUtils.waitForNewWindow();
+ viewCertButton.click();
+
+ let topWin = await newWinOpened;
+ let browser = topWin.gBrowser.selectedBrowser;
+
+ // We're racing against messages sent up from the content process that
+ // loads about:certificate. It may or may not have had the opportunity
+ // to tell the parent that it had loaded the page yet. If not, we wait
+ // for the page to load.
+ //
+ // Note that we can't use the URL parameter for
+ // BrowserTestUtils.waitForNewWindow, since we need to use a function
+ // to choose the right URL.
+ if (!browser.currentURI.spec.startsWith("about:certificate")) {
+ await BrowserTestUtils.browserLoaded(browser, false, spec =>
+ spec.startsWith("about:certificate")
+ );
+ }
+
+ let spec = browser.currentURI.spec;
+ checkSpec(spec);
+
+ await checkCertChain(browser);
+
+ await BrowserTestUtils.closeWindow(topWin); // closes about:certificate
+ win.document.getElementById("download_cert").cancelDialog();
+ await BrowserTestUtils.windowClosed(win);
+});
+
+add_task(async function testBadCert() {
+ info("Testing bad cert");
+
+ let tab = await openErrorPage();
+
+ let tabsCount = gBrowser.tabs.length;
+ let loaded = BrowserTestUtils.waitForNewTab(gBrowser, null, true);
+
+ await SpecialPowers.spawn(tab.linkedBrowser, [], async function () {
+ let advancedButton = content.document.getElementById("advancedButton");
+ Assert.ok(advancedButton, "advancedButton found");
+ Assert.equal(
+ advancedButton.hasAttribute("disabled"),
+ false,
+ "advancedButton should be clickable"
+ );
+ advancedButton.click();
+ let viewCertificate = content.document.getElementById("viewCertificate");
+ Assert.ok(viewCertificate, "viewCertificate found");
+ Assert.equal(
+ viewCertificate.hasAttribute("disabled"),
+ false,
+ "viewCertificate should be clickable"
+ );
+
+ viewCertificate.click();
+ });
+ await loaded;
+ checksCertTab(tabsCount);
+ await checkCertChain(gBrowser.selectedBrowser);
+
+ gBrowser.removeCurrentTab(); // closes about:certificate
+ gBrowser.removeCurrentTab(); // closes https://expired.example.com/
+});
+
+add_task(async function testBadCertIframe() {
+ info("Testing bad cert in an iframe");
+
+ let tab = await openErrorPage(true);
+
+ let tabsCount = gBrowser.tabs.length;
+ let loaded = BrowserTestUtils.waitForNewTab(gBrowser, null, true);
+
+ await SpecialPowers.spawn(tab.linkedBrowser, [], async function () {
+ let doc = content.document.querySelector("iframe").contentDocument;
+ let advancedButton = doc.getElementById("advancedButton");
+ Assert.ok(advancedButton, "advancedButton found");
+ Assert.equal(
+ advancedButton.hasAttribute("disabled"),
+ false,
+ "advancedButton should be clickable"
+ );
+ advancedButton.click();
+ let viewCertificate = doc.getElementById("viewCertificate");
+ Assert.ok(viewCertificate, "viewCertificate found");
+ Assert.equal(
+ viewCertificate.hasAttribute("disabled"),
+ false,
+ "viewCertificate should be clickable"
+ );
+
+ viewCertificate.click();
+ });
+ await loaded;
+ checksCertTab(tabsCount);
+ await checkCertChain(gBrowser.selectedBrowser);
+
+ gBrowser.removeCurrentTab(); // closes about:certificate
+ gBrowser.removeCurrentTab(); // closes https://expired.example.com/
+});
+
+add_task(async function testGoodCert() {
+ info("Testing page info");
+ let url = "https://example.com/";
+
+ let tabsCount = gBrowser.tabs.length;
+
+ info(`Loading ${url}`);
+ await BrowserTestUtils.withNewTab({ gBrowser, url }, async function () {
+ info("Opening pageinfo");
+ let pageInfo = BrowserPageInfo(url, "securityTab", {});
+ await BrowserTestUtils.waitForEvent(pageInfo, "load");
+
+ let securityTab = pageInfo.document.getElementById("securityTab");
+ await TestUtils.waitForCondition(
+ () => BrowserTestUtils.isVisible(securityTab),
+ "Security tab should be visible."
+ );
+ Assert.ok(securityTab, "Security tab is available");
+ let viewCertButton = pageInfo.document.getElementById("security-view-cert");
+ await TestUtils.waitForCondition(
+ () => BrowserTestUtils.isVisible(viewCertButton),
+ "view cert button should be visible."
+ );
+
+ let loaded = BrowserTestUtils.waitForNewTab(gBrowser, null, true);
+ checkAndClickButton(pageInfo.document, "security-view-cert");
+ await loaded;
+
+ await checkCertChain(gBrowser.selectedBrowser);
+ pageInfo.close();
+ });
+ checksCertTab(tabsCount);
+
+ gBrowser.removeCurrentTab(); // closes about:certificate
+});
+
+add_task(async function testPreferencesCert() {
+ info("Testing preferences cert");
+ let url = "about:preferences#privacy";
+
+ let tabsCount;
+
+ info(`Loading ${url}`);
+ await BrowserTestUtils.withNewTab(
+ { gBrowser, url },
+ async function (browser) {
+ tabsCount = gBrowser.tabs.length;
+ checkAndClickButton(browser.contentDocument, "viewCertificatesButton");
+
+ let certDialogLoaded = promiseLoadSubDialog(
+ "chrome://pippki/content/certManager.xhtml"
+ );
+ let dialogWin = await certDialogLoaded;
+ let doc = dialogWin.document;
+ Assert.ok(doc, "doc loaded");
+
+ doc.getElementById("certmanagertabs").selectedTab =
+ doc.getElementById("mine_tab");
+ let treeView = doc.getElementById("user-tree").view;
+ let selectedCert;
+ // See https://searchfox.org/mozilla-central/rev/40ef22080910c2e2c27d9e2120642376b1d8b8b2/browser/components/preferences/in-content/tests/browser_cert_export.js#41
+ for (let i = 0; i < treeView.rowCount; i++) {
+ treeView.selection.select(i);
+ dialogWin.getSelectedCerts();
+ let certs = dialogWin.selected_certs;
+ if (certs && certs[0]) {
+ selectedCert = certs[0];
+ break;
+ }
+ }
+ Assert.ok(selectedCert, "A cert should be selected");
+ let viewButton = doc.getElementById("mine_viewButton");
+ Assert.equal(viewButton.disabled, false, "Should enable view button");
+
+ let loaded = BrowserTestUtils.waitForNewTab(gBrowser, null, true);
+ viewButton.click();
+ await loaded;
+
+ checksCertTab(tabsCount);
+ await checkCertChain(gBrowser.selectedBrowser);
+ }
+ );
+ gBrowser.removeCurrentTab(); // closes about:certificate
+});
diff --git a/toolkit/components/certviewer/tests/browser/browser_renderCertToUI.js b/toolkit/components/certviewer/tests/browser/browser_renderCertToUI.js
new file mode 100644
index 0000000000..0ecb93f176
--- /dev/null
+++ b/toolkit/components/certviewer/tests/browser/browser_renderCertToUI.js
@@ -0,0 +1,192 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const url =
+ "about:certificate?cert=MIIHQjCCBiqgAwIBAgIQCgYwQn9bvO1pVzllk7ZFHzANBgkqhkiG9w0BAQsFADB1MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTQwMgYDVQQDEytEaWdpQ2VydCBTSEEyIEV4dGVuZGVkIFZhbGlkYXRpb24gU2VydmVyIENBMB4XDTE4MDUwODAwMDAwMFoXDTIwMDYwMzEyMDAwMFowgccxHTAbBgNVBA8MFFByaXZhdGUgT3JnYW5pemF0aW9uMRMwEQYLKwYBBAGCNzwCAQMTAlVTMRkwFwYLKwYBBAGCNzwCAQITCERlbGF3YXJlMRAwDgYDVQQFEwc1MTU3NTUwMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEVMBMGA1UEChMMR2l0SHViLCBJbmMuMRMwEQYDVQQDEwpnaXRodWIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxjyq8jyXDDrBTyitcnB90865tWBzpHSbindG%2FXqYQkzFMBlXmqkzC%2BFdTRBYyneZw5Pz%2BXWQvL%2B74JW6LsWNc2EF0xCEqLOJuC9zjPAqbr7uroNLghGxYf13YdqbG5oj%2F4x%2BogEG3dF%2FU5YIwVr658DKyESMV6eoYV9mDVfTuJastkqcwero%2B5ZAKfYVMLUEsMwFtoTDJFmVf6JlkOWwsxp1WcQ%2FMRQK1cyqOoUFUgYylgdh3yeCDPeF22Ax8AlQxbcaI%2BGwfQL1FB7Jy%2Bh%2BKjME9lE%2FUpgV6Qt2R1xNSmvFCBWu%2BNFX6epwFP%2FJRbkMfLz0beYFUvmMgLtwVpEPSwIDAQABo4IDeTCCA3UwHwYDVR0jBBgwFoAUPdNQpdagre7zSmAKZdMh1Pj41g8wHQYDVR0OBBYEFMnCU2FmnV%2BrJfQmzQ84mqhJ6kipMCUGA1UdEQQeMByCCmdpdGh1Yi5jb22CDnd3dy5naXRodWIuY29tMA4GA1UdDwEB%2FwQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdQYDVR0fBG4wbDA0oDKgMIYuaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItZXYtc2VydmVyLWcyLmNybDA0oDKgMIYuaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItZXYtc2VydmVyLWcyLmNybDBLBgNVHSAERDBCMDcGCWCGSAGG%2FWwCATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAcGBWeBDAEBMIGIBggrBgEFBQcBAQR8MHowJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBSBggrBgEFBQcwAoZGaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkV4dGVuZGVkVmFsaWRhdGlvblNlcnZlckNBLmNydDAMBgNVHRMBAf8EAjAAMIIBfgYKKwYBBAHWeQIEAgSCAW4EggFqAWgAdgCkuQmQtBhYFIe7E6LMZ3AKPDWYBPkb37jjd80OyA3cEAAAAWNBYm0KAAAEAwBHMEUCIQDRZp38cTWsWH2GdBpe%2FuPTWnsu%2Fm4BEC2%2BdIcvSykZYgIgCP5gGv6yzaazxBK2NwGdmmyuEFNSg2pARbMJlUFgU5UAdgBWFAaaL9fC7NP14b1Esj7HRna5vJkRXMDvlJhV1onQ3QAAAWNBYm0tAAAEAwBHMEUCIQCi7omUvYLm0b2LobtEeRAYnlIo7n6JxbYdrtYdmPUWJQIgVgw1AZ51vK9ENinBg22FPxb82TvNDO05T17hxXRC2IYAdgC72d%2B8H4pxtZOUI5eqkntHOFeVCqtS6BqQlmQ2jh7RhQAAAWNBYm3fAAAEAwBHMEUCIQChzdTKUU2N%2BXcqcK0OJYrN8EYynloVxho4yPk6Dq3EPgIgdNH5u8rC3UcslQV4B9o0a0w204omDREGKTVuEpxGeOQwDQYJKoZIhvcNAQELBQADggEBAHAPWpanWOW%2Fip2oJ5grAH8mqQfaunuCVE%2Bvac%2B88lkDK%2FLVdFgl2B6kIHZiYClzKtfczG93hWvKbST4NRNHP9LiaQqdNC17e5vNHnXVUGw%2ByxyjMLGqkgepOnZ2Rb14kcTOGp4i5AuJuuaMwXmCo7jUwPwfLe1NUlVBKqg6LK0Hcq4K0sZnxE8HFxiZ92WpV2AVWjRMEc%2F2z2shNoDvxvFUYyY1Oe67xINkmyQKc%2BygSBZzyLnXSFVWmHr3u5dcaaQGGAR42v6Ydr4iL38Hd4dOiBma%2BFXsXBIqWUjbST4VXmdaol7uzFMojA4zkxQDZAvF5XgJlAFadfySna%2Fteik%3D";
+
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/toolkit/components/certviewer/tests/browser/adjustedCerts.js",
+ this
+);
+
+add_task(async function test() {
+ Assert.ok(adjustedCerts, "adjustedCerts found");
+
+ let tabName = adjustedCerts[0].tabName;
+ let certItems = adjustedCerts[0].certItems;
+
+ await BrowserTestUtils.withNewTab(url, async function (browser) {
+ await SpecialPowers.spawn(
+ browser,
+ [[certItems, tabName]],
+ async function ([adjustedCerts, expectedTabName]) {
+ let certificateSection = await ContentTaskUtils.waitForCondition(() => {
+ return content.document.querySelector("certificate-section");
+ }, "Certificate section found");
+
+ let infoGroups =
+ certificateSection.shadowRoot.querySelectorAll("info-group");
+ Assert.ok(infoGroups, "infoGroups found");
+ Assert.equal(
+ infoGroups.length,
+ adjustedCerts.length,
+ "infoGroups must have the same length of adjustedCerts"
+ );
+
+ let tabName =
+ certificateSection.shadowRoot.querySelector(
+ ".tab[idnumber='0']"
+ ).textContent;
+ Assert.equal(tabName, expectedTabName, "Tab name should be the same");
+
+ function getElementByAttribute(source, property, target) {
+ for (let elem of source) {
+ if (elem.hasOwnProperty(property) && elem[property] === target) {
+ return elem;
+ }
+ }
+ return null;
+ }
+
+ function checkBooleans(got, expected) {
+ info(
+ "If adjustedCertElments returned true, this value should be Yes, otherwise it should be No"
+ );
+ let gotBool;
+ if (got === "Yes") {
+ gotBool = true;
+ } else if (got === "No") {
+ gotBool = false;
+ } else {
+ gotBool = null;
+ }
+ Assert.equal(
+ gotBool,
+ expected,
+ `Expected ${expected}, got ${gotBool}`
+ );
+ }
+
+ for (let infoGroup of infoGroups) {
+ let sectionId = infoGroup.shadowRoot
+ .querySelector(".info-group-title")
+ .getAttribute("data-l10n-id")
+ .replace("certificate-viewer-", "");
+
+ let adjustedCertsElem = getElementByAttribute(
+ adjustedCerts,
+ "sectionId",
+ sectionId
+ );
+ Assert.ok(adjustedCertsElem, "The element exists in adjustedCerts");
+
+ let infoItems = infoGroup.shadowRoot.querySelectorAll("info-item");
+ Assert.equal(
+ infoItems.length,
+ adjustedCertsElem.sectionItems.length,
+ "sectionItems must be the same length"
+ );
+
+ let i = 0;
+ // Message ID mappings
+ let stringMapping = {
+ signaturealgorithm: "signature-algorithm",
+ };
+ for (let infoItem of infoItems) {
+ let infoItemLabel = infoItem.shadowRoot
+ .querySelector("label")
+ .getAttribute("data-l10n-id");
+ let infoElem = infoItem.shadowRoot.querySelector(".info");
+ let infoItemInfo = infoElem.textContent;
+ let adjustedCertsElemLabel =
+ adjustedCertsElem.sectionItems[i].labelId;
+ let adjustedCertsElemInfo = adjustedCertsElem.sectionItems[i].info;
+
+ if (adjustedCertsElemLabel == null) {
+ adjustedCertsElemLabel = "";
+ }
+ adjustedCertsElemLabel = adjustedCertsElemLabel
+ .replace(/\s+/g, "-")
+ .replace(/\./g, "")
+ .replace(/\//g, "")
+ .replace(/--/g, "-")
+ .toLowerCase();
+ adjustedCertsElemLabel =
+ stringMapping[adjustedCertsElemLabel] || adjustedCertsElemLabel;
+
+ if (adjustedCertsElemInfo == null) {
+ adjustedCertsElemInfo = "";
+ }
+ if (typeof adjustedCertsElemInfo === "boolean") {
+ checkBooleans(infoItemInfo, adjustedCertsElemInfo);
+ continue;
+ }
+
+ if (
+ adjustedCertsElemLabel === "timestamp" ||
+ adjustedCertsElemLabel === "not-after" ||
+ adjustedCertsElemLabel === "not-before"
+ ) {
+ Assert.equal(
+ infoElem.textContent,
+ adjustedCertsElemInfo.utc,
+ "Timestamps must be equal"
+ );
+ i++;
+ continue;
+ }
+ if (adjustedCertsElemLabel === "download") {
+ Assert.equal(infoElem.children.length, 2, "Should have 2 links.");
+ for (let kid of infoElem.children) {
+ Assert.equal(
+ kid.localName,
+ "a",
+ "Should get a cert/chain link."
+ );
+ Assert.ok(
+ kid.download.endsWith("pem"),
+ "Link `download` attribute should point to pem file."
+ );
+ Assert.ok(
+ kid.dataset.l10nId.includes("pem"),
+ "Link should be labeled"
+ );
+ Assert.equal(
+ kid.dataset.l10nId.includes("chain"),
+ kid.download.includes("chain"),
+ "Download label and filename should match"
+ );
+ }
+ // Remaining tests in browser_downloadLink.js
+
+ i++;
+ continue;
+ }
+
+ if (Array.isArray(adjustedCertsElemInfo)) {
+ // there is a case where we have a boolean
+ adjustedCertsElemInfo = adjustedCertsElemInfo
+ .toString()
+ .replace(/,/g, ", ");
+ }
+
+ Assert.ok(
+ infoItemLabel.includes(adjustedCertsElemLabel),
+ "data-l10n-id must contain the original label"
+ );
+
+ Assert.equal(
+ infoItemInfo,
+ adjustedCertsElemInfo,
+ "Info must be equal"
+ );
+
+ i++;
+ }
+ }
+ }
+ );
+ });
+});
diff --git a/toolkit/components/certviewer/tests/browser/dummy_page.html b/toolkit/components/certviewer/tests/browser/dummy_page.html
new file mode 100644
index 0000000000..1a87e28408
--- /dev/null
+++ b/toolkit/components/certviewer/tests/browser/dummy_page.html
@@ -0,0 +1,9 @@
+<html>
+<head>
+<title>Dummy test page</title>
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8"></meta>
+</head>
+<body>
+<p>Dummy test page</p>
+</body>
+</html>
diff --git a/toolkit/components/certviewer/tests/browser/head.js b/toolkit/components/certviewer/tests/browser/head.js
new file mode 100644
index 0000000000..2a28444f9b
--- /dev/null
+++ b/toolkit/components/certviewer/tests/browser/head.js
@@ -0,0 +1,124 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+function checkAndClickButton(document, id) {
+ let button = document.getElementById(id);
+ Assert.ok(button, `${id} button found`);
+ Assert.equal(
+ button.hasAttribute("disabled"),
+ false,
+ "button should be clickable"
+ );
+ button.click();
+}
+
+function is_element_visible(aElement, aMsg) {
+ isnot(aElement, null, "Element should not be null, when checking visibility");
+ Assert.ok(!BrowserTestUtils.isHidden(aElement), aMsg);
+}
+
+// Extracted from https://searchfox.org/mozilla-central/rev/40ef22080910c2e2c27d9e2120642376b1d8b8b2/browser/components/preferences/in-content/tests/head.js#41
+function promiseLoadSubDialog(aURL) {
+ return new Promise((resolve, reject) => {
+ content.gSubDialog._dialogStack.addEventListener(
+ "dialogopen",
+ function dialogopen(aEvent) {
+ if (
+ aEvent.detail.dialog._frame.contentWindow.location == "about:blank"
+ ) {
+ return;
+ }
+ content.gSubDialog._dialogStack.removeEventListener(
+ "dialogopen",
+ dialogopen
+ );
+
+ Assert.equal(
+ aEvent.detail.dialog._frame.contentWindow.location.toString(),
+ aURL,
+ "Check the proper URL is loaded"
+ );
+
+ // Check visibility
+ is_element_visible(aEvent.detail.dialog._overlay, "Overlay is visible");
+
+ // Check that stylesheets were injected
+ let expectedStyleSheetURLs =
+ aEvent.detail.dialog._injectedStyleSheets.slice(0);
+ for (let styleSheet of aEvent.detail.dialog._frame.contentDocument
+ .styleSheets) {
+ let i = expectedStyleSheetURLs.indexOf(styleSheet.href);
+ if (i >= 0) {
+ info("found " + styleSheet.href);
+ expectedStyleSheetURLs.splice(i, 1);
+ }
+ }
+ Assert.equal(
+ expectedStyleSheetURLs.length,
+ 0,
+ "All expectedStyleSheetURLs should have been found"
+ );
+
+ // Wait for the next event tick to make sure the remaining part of the
+ // testcase runs after the dialog gets ready for input.
+ executeSoon(() => resolve(aEvent.detail.dialog._frame.contentWindow));
+ }
+ );
+ });
+}
+
+function injectErrorPageFrame(tab, src) {
+ return SpecialPowers.spawn(
+ tab.linkedBrowser,
+ [{ frameSrc: src }],
+ async function ({ frameSrc }) {
+ let loaded = ContentTaskUtils.waitForEvent(
+ content.wrappedJSObject,
+ "DOMFrameContentLoaded"
+ );
+ let iframe = content.document.createElement("iframe");
+ iframe.src = frameSrc;
+ content.document.body.appendChild(iframe);
+ await loaded;
+ // We will have race conditions when accessing the frame content after setting a src,
+ // so we can't wait for AboutNetErrorLoad. Let's wait for the certerror class to
+ // appear instead (which should happen at the same time as AboutNetErrorLoad).
+ await ContentTaskUtils.waitForCondition(() =>
+ iframe.contentDocument.body.classList.contains("certerror")
+ );
+ }
+ );
+}
+
+async function openErrorPage(useFrame = false) {
+ let src = "https://expired.example.com/";
+ let dummyPage =
+ getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "https://example.com"
+ ) + "dummy_page.html";
+
+ let tab;
+ if (useFrame) {
+ info("Loading cert error page in an iframe");
+ tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, dummyPage);
+ await injectErrorPageFrame(tab, src);
+ } else {
+ let certErrorLoaded;
+ tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ () => {
+ gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, src);
+ let browser = gBrowser.selectedBrowser;
+ certErrorLoaded = BrowserTestUtils.waitForErrorPage(browser);
+ },
+ false
+ );
+ info("Loading and waiting for the cert error");
+ await certErrorLoaded;
+ }
+
+ return tab;
+}
diff --git a/toolkit/components/certviewer/tests/chrome/CSoutput.mjs b/toolkit/components/certviewer/tests/chrome/CSoutput.mjs
new file mode 100644
index 0000000000..d90026353e
--- /dev/null
+++ b/toolkit/components/certviewer/tests/chrome/CSoutput.mjs
@@ -0,0 +1,144 @@
+export const certOutputCS = [
+ {
+ ext: {
+ aia: {
+ descriptions: [
+ {
+ location: "http://ocsp.digicert.com",
+ method: "Online Certificate Status Protocol (OCSP)",
+ },
+ {
+ location:
+ "http://cacerts.digicert.com/DigiCertSHA2SecureServerCA.crt",
+ method: "CA Issuers",
+ },
+ ],
+ critical: false,
+ },
+ aKID: {
+ critical: false,
+ id: "0F:80:61:1C:82:31:61:D5:2F:28:E7:8D:46:38:B4:2C:E1:C6:D9:E2",
+ },
+ basicConstraints: { cA: false, critical: true },
+ crlPoints: {
+ critical: false,
+ points: [
+ "http://crl3.digicert.com/ssca-sha2-g6.crl",
+ "http://crl4.digicert.com/ssca-sha2-g6.crl",
+ ],
+ },
+ cp: {
+ critical: false,
+ policies: [
+ {
+ id: "2.16.840",
+ name: "ANSI Organizational Identifier",
+ qualifiers: [
+ {
+ qualifierId: "1.3.6.1.5.5.7.2.1",
+ qualifierName: "Practices Statement",
+ qualifierValue: "https://www.digicert.com/CPS",
+ },
+ ],
+ value: "2.16.840.1.114412.1.1",
+ },
+ {
+ id: "2.23.140.1.2.2",
+ name: "Certificate Type",
+ value: "Organization Validation",
+ },
+ ],
+ },
+ eKeyUsages: {
+ critical: false,
+ purposes: ["Server Authentication", "Client Authentication"],
+ },
+ keyUsages: {
+ critical: true,
+ purposes: ["Digital Signature", "Key Encipherment"],
+ },
+ msCrypto: { exists: false },
+ ocspStaple: { critical: false, required: false },
+ scts: {
+ critical: false,
+ timestamps: [
+ {
+ logId:
+ "A4:B9:09:90:B4:18:58:14:87:BB:13:A2:CC:67:70:0A:3C:35:98:04:F9:1B:DF:B8:E3:77:CD:0E:C8:0D:DC:10",
+ name: "Google “Pilot”",
+ signatureAlgorithm: "SHA-256 ECDSA",
+ timestamp: "11/5/2018, 8:55:28 PM (Brasilia Standard Time)",
+ timestampUTC: "Mon, 05 Nov 2018 22:55:28 GMT",
+ version: 1,
+ },
+ {
+ logId:
+ "87:75:BF:E7:59:7C:F8:8C:43:99:5F:BD:F3:6E:FF:56:8D:47:56:36:FF:4A:B5:60:C1:B4:EA:FF:5E:A0:83:0F",
+ name: "DigiCert Server 2",
+ signatureAlgorithm: "SHA-256 ECDSA",
+ timestamp: "11/5/2018, 8:55:28 PM (Brasilia Standard Time)",
+ timestampUTC: "Mon, 05 Nov 2018 22:55:28 GMT",
+ version: 1,
+ },
+ ],
+ },
+ sKID: {
+ critical: false,
+ id: "DA:52:BD:21:9C:37:65:53:FC:1F:53:75:0F:1E:5F:07:9B:A3:AD:3F",
+ },
+ san: {
+ altNames: [
+ ["DNS Name", "www.mozilla.org"],
+ ["DNS Name", "mozilla.org"],
+ ],
+ critical: false,
+ },
+ },
+ files: {
+ pem: "-----BEGIN%20CERTIFICATE-----%0D%0AMIIGRjCCBS6gAwIBAgIQDJduPkI49CDWPd+G7+u6kDANBgkqhkiG9w0BAQsFADBN%0D%0AMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5E%0D%0AaWdpQ2VydCBTSEEyIFNlY3VyZSBTZXJ2ZXIgQ0EwHhcNMTgxMTA1MDAwMDAwWhcN%0D%0AMTkxMTEzMTIwMDAwWjCBgzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3Ju%0D%0AaWExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxHDAaBgNVBAoTE01vemlsbGEgQ29y%0D%0AcG9yYXRpb24xDzANBgNVBAsTBldlYk9wczEYMBYGA1UEAxMPd3d3Lm1vemlsbGEu%0D%0Ab3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuKruymkkmkqCJh7Q%0D%0AjmXlUOBcLFRyw5LG/vUUWVrsxC2gsbR8WJq+cYoYBpoNVStKrO4U2rBh1GEbccvT%0D%0A6qKOQI+pjjDxx9cmRdubGTGp8L0MF1ohVvhIvYLumOEoRDDPU4PvGJjGhek/ojve%0D%0AdPWe8dhciHkxOC2qPFZvVFMwg1/o/b80147BwZQmzB18mnHsmcyKlpsCN8pxw86u%0D%0Aao9Iun8gZQrsllW64rTZlRR56pHdAcuGAoZjYZxwS9Z+lvrSjEgrddemWyGGalqy%0D%0AFp1rXlVM1Tf4/IYWAQXTgTUN303u3xMjss7QK7eUDsACRxiWPLW9XQDd1c+yvaYJ%0D%0AKzgJ2wIDAQABo4IC6TCCAuUwHwYDVR0jBBgwFoAUD4BhHIIxYdUvKOeNRji0LOHG%0D%0A2eIwHQYDVR0OBBYEFNpSvSGcN2VT/B9TdQ8eXwebo60/MCcGA1UdEQQgMB6CD3d3%0D%0Ady5tb3ppbGxhLm9yZ4ILbW96aWxsYS5vcmcwDgYDVR0PAQH/BAQDAgWgMB0GA1Ud%0D%0AJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBrBgNVHR8EZDBiMC+gLaArhilodHRw%0D%0AOi8vY3JsMy5kaWdpY2VydC5jb20vc3NjYS1zaGEyLWc2LmNybDAvoC2gK4YpaHR0%0D%0AcDovL2NybDQuZGlnaWNlcnQuY29tL3NzY2Etc2hhMi1nNi5jcmwwTAYDVR0gBEUw%0D%0AQzA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNl%0D%0AcnQuY29tL0NQUzAIBgZngQwBAgIwfAYIKwYBBQUHAQEEcDBuMCQGCCsGAQUFBzAB%0D%0AhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wRgYIKwYBBQUHMAKGOmh0dHA6Ly9j%0D%0AYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJTZWN1cmVTZXJ2ZXJDQS5j%0D%0AcnQwDAYDVR0TAQH/BAIwADCCAQIGCisGAQQB1nkCBAIEgfMEgfAA7gB1AKS5CZC0%0D%0AGFgUh7sTosxncAo8NZgE+RvfuON3zQ7IDdwQAAABZuYWiHwAAAQDAEYwRAIgZnMS%0D%0AH1JdG6NASHWTwD0mlP/zbr0hzP263c02Ym0DU64CIEe4QHJDP47j0b6oTFu6RrZz%0D%0A1NQ9cq8Az1KnMKRuaFAlAHUAh3W/51l8+IxDmV+9827/Vo1HVjb/SrVgwbTq/16g%0D%0Agw8AAAFm5haJAgAABAMARjBEAiAxGLXkUaOAkZhXNeNR3pWyahZeKmSaMXadgu18%0D%0ASfK1ZAIgKtwu5eGxK76rgaszLCZ9edBIjuU0DKorzPUuxUXFY0QwDQYJKoZIhvcN%0D%0AAQELBQADggEBAKLJAFO3wuaP5MM/ed1lhk5Uc2aDokhcM7XyvdhEKSHbgPhcgMoT%0D%0A9YIVoPa70gNC6KHcwoXu0g8wt7X6Vm1ql/68G5q844kFuC6JPl4LVT9mciD+VW6b%0D%0AHUSXD9xifL9DqdJ0Ic0SllTlM+oq5aAeOxUQGXhXIqj6fSQv9fQN6mXxQIoc/gjx%0D%0Ateskq/Vl8YmY1FIZP9Bh7g27kxZ9GAAGQtjTL03RzKAuSg6yeImYVdQWasc7UPnB%0D%0AXlRAzZ8+OJThUbzK16a2CI3Rg4agKSJk+uA47h1/ImmngpFLRb/MvRX6H1oWcUuy%0D%0AH6O7PZdl0YpwTpw1THIuqCGl/wpPgyQgcTM=%0D%0A-----END%20CERTIFICATE-----%0D%0A",
+ },
+ fingerprint: {
+ sha1: "0E:95:79:81:17:5C:51:D2:76:05:AC:8E:C4:61:71:61:97:29:ED:61",
+ sha256:
+ "30:23:CB:EC:1B:A8:C2:D9:E7:45:05:D5:4A:E2:0F:73:E1:51:C4:2D:46:59:CE:B4:EE:E6:51:7B:9E:CB:84:7B",
+ },
+ issuer: {
+ cn: "DigiCert SHA2 Secure Server CA",
+ dn: "c=US, o=DigiCert Inc, cn=DigiCert SHA2 Secure Server CA",
+ entries: [
+ ["Country", "US"],
+ ["Organization", "DigiCert Inc"],
+ ["Common Name", "DigiCert SHA2 Secure Server CA"],
+ ],
+ },
+ notBefore: "11/4/2018, 10:00:00 PM (Brasilia Standard Time)",
+ notBeforeUTC: "Mon, 05 Nov 2018 00:00:00 GMT",
+ notAfter: "11/13/2019, 10:00:00 AM (Brasilia Standard Time)",
+ notAfterUTC: "Wed, 13 Nov 2019 12:00:00 GMT",
+ subject: {
+ cn: "www.mozilla.org",
+ dn: "c=US, s=California, l=Mountain View, o=Mozilla Corporation, ou=WebOps, cn=www.mozilla.org",
+ entries: [
+ ["Country", "US"],
+ ["State / Province", "California"],
+ ["Locality", "Mountain View"],
+ ["Organization", "Mozilla Corporation"],
+ ["Organizational Unit", "WebOps"],
+ ["Common Name", "www.mozilla.org"],
+ ],
+ },
+ serialNumber: "0C:97:6E:3E:42:38:F4:20:D6:3D:DF:86:EF:EB:BA:90",
+ signature: {
+ name: "SHA-256 with RSA Encryption",
+ type: "1.2.840.113549.1.1.11",
+ },
+ subjectPublicKeyInfo: {
+ e: 65537,
+ kty: "RSA",
+ n: "B8:AA:EE:CA:69:24:9A:4A:82:26:1E:D0:8E:65:E5:50:E0:5C:2C:54:72:C3:92:C6:FE:F5:14:59:5A:EC:C4:2D:A0:B1:B4:7C:58:9A:BE:71:8A:18:06:9A:0D:55:2B:4A:AC:EE:14:DA:B0:61:D4:61:1B:71:CB:D3:EA:A2:8E:40:8F:A9:8E:30:F1:C7:D7:26:45:DB:9B:19:31:A9:F0:BD:0C:17:5A:21:56:F8:48:BD:82:EE:98:E1:28:44:30:CF:53:83:EF:18:98:C6:85:E9:3F:A2:3B:DE:74:F5:9E:F1:D8:5C:88:79:31:38:2D:AA:3C:56:6F:54:53:30:83:5F:E8:FD:BF:34:D7:8E:C1:C1:94:26:CC:1D:7C:9A:71:EC:99:CC:8A:96:9B:02:37:CA:71:C3:CE:AE:6A:8F:48:BA:7F:20:65:0A:EC:96:55:BA:E2:B4:D9:95:14:79:EA:91:DD:01:CB:86:02:86:63:61:9C:70:4B:D6:7E:96:FA:D2:8C:48:2B:75:D7:A6:5B:21:86:6A:5A:B2:16:9D:6B:5E:55:4C:D5:37:F8:FC:86:16:01:05:D3:81:35:0D:DF:4D:EE:DF:13:23:B2:CE:D0:2B:B7:94:0E:C0:02:47:18:96:3C:B5:BD:5D:00:DD:D5:CF:B2:BD:A6:09:2B:38:09:DB",
+ keysize: 2048,
+ },
+ unsupportedExtensions: [],
+ version: "3",
+ },
+];
diff --git a/toolkit/components/certviewer/tests/chrome/chrome.toml b/toolkit/components/certviewer/tests/chrome/chrome.toml
new file mode 100644
index 0000000000..2afba193c0
--- /dev/null
+++ b/toolkit/components/certviewer/tests/chrome/chrome.toml
@@ -0,0 +1,13 @@
+[DEFAULT]
+scheme = "https"
+
+["test_adjustCertInformation.html"]
+support-files = ["parseOutput.mjs"]
+
+["test_certDecoder.html"]
+
+["test_certDecoderFields.html"]
+support-files = ["CSoutput.mjs"]
+
+["test_kebabCaseInAdjustCertInformation.html"]
+support-files = ["parseOutput.mjs"]
diff --git a/toolkit/components/certviewer/tests/chrome/parseOutput.mjs b/toolkit/components/certviewer/tests/chrome/parseOutput.mjs
new file mode 100644
index 0000000000..947801145e
--- /dev/null
+++ b/toolkit/components/certviewer/tests/chrome/parseOutput.mjs
@@ -0,0 +1,330 @@
+export const parseOutput = [
+ {
+ ext: {
+ aia: {
+ descriptions: [
+ {
+ location: "http://ocsp.digicert.com",
+ method: "Online Certificate Status Protocol (OCSP)",
+ },
+ {
+ location:
+ "http://cacerts.digicert.com/DigiCertSHA2ExtendedValidationServerCA.crt",
+ method: "CA Issuers",
+ },
+ ],
+ critical: false,
+ },
+ aKID: {
+ critical: false,
+ id: "3D:D3:50:A5:D6:A0:AD:EE:F3:4A:60:0A:65:D3:21:D4:F8:F8:D6:0F",
+ },
+ basicConstraints: { cA: false, critical: true },
+ crlPoints: {
+ critical: false,
+ points: [
+ "http://crl3.digicert.com/sha2-ev-server-g2.crl",
+ "http://crl4.digicert.com/sha2-ev-server-g2.crl",
+ ],
+ },
+ cp: {
+ critical: false,
+ policies: [
+ {
+ id: "2.16.840",
+ name: "ANSI Organizational Identifier",
+ qualifiers: [
+ {
+ id: "1.3.6.1.5.5.7.2.1",
+ name: "Practices Statement",
+ value: "https://www.digicert.com/CPS",
+ },
+ ],
+ value: "2.16.840.1.114412.2.1",
+ },
+ {
+ id: "2.23.140.1.1",
+ name: "Certificate Type",
+ value: "Extended Validation",
+ },
+ ],
+ },
+ eKeyUsages: {
+ critical: false,
+ purposes: ["Server Authentication", "Client Authentication"],
+ },
+ keyUsages: {
+ critical: true,
+ purposes: ["Digital Signature", "Key Encipherment"],
+ },
+ msCrypto: { exists: false },
+ ocspStaple: { critical: false, required: false },
+ scts: {
+ critical: false,
+ timestamps: [
+ {
+ logId:
+ "A4:B9:09:90:B4:18:58:14:87:BB:13:A2:CC:67:70:0A:3C:35:98:04:F9:1B:DF:B8:E3:77:CD:0E:C8:0D:DC:10",
+ name: "Google “Pilot”",
+ signatureAlgorithm: "SHA-256 ECDSA",
+ timestamp: "11/7/2018, 7:50:01 PM (Brasilia Standard Time)",
+ timestampUTC: "Wed, 07 Nov 2018 21:50:01 GMT",
+ version: 1,
+ },
+ {
+ logId:
+ "87:75:BF:E7:59:7C:F8:8C:43:99:5F:BD:F3:6E:FF:56:8D:47:56:36:FF:4A:B5:60:C1:B4:EA:FF:5E:A0:83:0F",
+ name: "DigiCert Server 2",
+ signatureAlgorithm: "SHA-256 ECDSA",
+ timestamp: "11/7/2018, 7:50:01 PM (Brasilia Standard Time)",
+ timestampUTC: "Wed, 07 Nov 2018 21:50:01 GMT",
+ version: 1,
+ },
+ {
+ logId:
+ "EE:4B:BD:B7:75:CE:60:BA:E1:42:69:1F:AB:E1:9E:66:A3:0F:7E:5F:B0:72:D8:83:00:C4:7B:89:7A:A8:FD:CB",
+ name: "Google “Rocketeer”",
+ signatureAlgorithm: "SHA-256 ECDSA",
+ timestamp: "11/7/2018, 7:50:01 PM (Brasilia Standard Time)",
+ timestampUTC: "Wed, 07 Nov 2018 21:50:01 GMT",
+ version: 1,
+ },
+ ],
+ },
+ sKID: {
+ critical: false,
+ id: "6C:B0:43:56:FE:3D:E8:12:EC:D9:12:F5:63:D5:C4:CA:07:AF:B0:76",
+ },
+ san: {
+ altNames: [
+ ["DNS Name", "www.digicert.com"],
+ ["DNS Name", "admin.digicert.com"],
+ ["DNS Name", "digicert.com"],
+ ["DNS Name", "content.digicert.com"],
+ ["DNS Name", "login.digicert.com"],
+ ["DNS Name", "api.digicert.com"],
+ ["DNS Name", "ws.digicert.com"],
+ ["DNS Name", "www.origin.digicert.com"],
+ ],
+ critical: false,
+ },
+ },
+ files: {
+ pem: "-----BEGIN%20CERTIFICATE-----%0D%0AMIIIzDCCB7SgAwIBAgIQDrbqtBjIc9jzwDHc3d8YsDANBgkqhkiG9w0BAQsFADB1%0D%0AMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3%0D%0Ad3cuZGlnaWNlcnQuY29tMTQwMgYDVQQDEytEaWdpQ2VydCBTSEEyIEV4dGVuZGVk%0D%0AIFZhbGlkYXRpb24gU2VydmVyIENBMB4XDTE4MTEwNzAwMDAwMFoXDTIwMTExMzEy%0D%0AMDAwMFowgc8xHTAbBgNVBA8MFFByaXZhdGUgT3JnYW5pemF0aW9uMRMwEQYLKwYB%0D%0ABAGCNzwCAQMTAlVTMRUwEwYLKwYBBAGCNzwCAQITBFV0YWgxFTATBgNVBAUTDDUy%0D%0AOTk1MzctMDE0MjELMAkGA1UEBhMCVVMxDTALBgNVBAgTBFV0YWgxDTALBgNVBAcT%0D%0ABExlaGkxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMQwwCgYDVQQLEwNTUkUxGTAX%0D%0ABgNVBAMTEHd3dy5kaWdpY2VydC5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw%0D%0AggIKAoICAQDOn4XKOTAwt/aYabScEF1QOyVj0OVo1NmlyizWNZWyPg0pi53ggUoE%0D%0A98CeNUkz+6scEYqWNY6l3qKB56pJJIqNQmo9NoWO8k2G/jTIjFFGqNWYIq23i4+H%0D%0AqaXi1/H/aWFgazk1qkyyAOQQA/p56bG9m5Ok/IBM/BZnLqVJLGJOx9ihgG1dI9Dr%0D%0A6vap+8QaPRau3t9sEd2cxe4Ix7gLdaYG3vxsYf3BycKTSKtyrbkX1Qy0dsSxy+GC%0D%0AM2ETxE1gMa7vRomQ/ZoZo8Ib55kFp6lIT6UOOkkdyiJdpWPXIZZlsZR5wkegWDsJ%0D%0AP7Xv7nE0WMkY1+05iNYtrzZRhhlnBw2AoMGNI+tsBXLQKeZfWFmU30bhkzX99pmv%0D%0AIYJ3f1fQGLao44nQEjdknIvpm0HMgvagYCnQVnnhJStzyYz324flWLPSp57OQeNM%0D%0Atr6O5W0HdWyhUZU+D4R6wObYQMZ5biYjRhtAQjMg8EVQEfZzEdr0WGO5JRHLHyot%0D%0A8tErXM9DiF5cCbzfcjeuoik2SHW+vbuPagMiHTM9+3lr0oRO+ZWwcM7fJvn1JfR2%0D%0APDLAaI3QUv7OLhSH32UfQsk+1ICq05m2HwSxiAviDRl5De66MEZDdvu03sUAQTHv%0D%0AWnw0Mr7Jgbjtn0DeUKLYwsRWg+spqoFTJHWGbb9RIb+3lxev7nIqOQIDAQABo4ID%0D%0A+zCCA/cwHwYDVR0jBBgwFoAUPdNQpdagre7zSmAKZdMh1Pj41g8wHQYDVR0OBBYE%0D%0AFGywQ1b+PegS7NkS9WPVxMoHr7B2MIGlBgNVHREEgZ0wgZqCEHd3dy5kaWdpY2Vy%0D%0AdC5jb22CEmFkbWluLmRpZ2ljZXJ0LmNvbYIMZGlnaWNlcnQuY29tghRjb250ZW50%0D%0ALmRpZ2ljZXJ0LmNvbYISbG9naW4uZGlnaWNlcnQuY29tghBhcGkuZGlnaWNlcnQu%0D%0AY29tgg93cy5kaWdpY2VydC5jb22CF3d3dy5vcmlnaW4uZGlnaWNlcnQuY29tMA4G%0D%0AA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdQYD%0D%0AVR0fBG4wbDA0oDKgMIYuaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItZXYt%0D%0Ac2VydmVyLWcyLmNybDA0oDKgMIYuaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3No%0D%0AYTItZXYtc2VydmVyLWcyLmNybDBLBgNVHSAERDBCMDcGCWCGSAGG/WwCATAqMCgG%0D%0ACCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAcGBWeBDAEB%0D%0AMIGIBggrBgEFBQcBAQR8MHowJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2lj%0D%0AZXJ0LmNvbTBSBggrBgEFBQcwAoZGaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29t%0D%0AL0RpZ2lDZXJ0U0hBMkV4dGVuZGVkVmFsaWRhdGlvblNlcnZlckNBLmNydDAMBgNV%0D%0AHRMBAf8EAjAAMIIBfwYKKwYBBAHWeQIEAgSCAW8EggFrAWkAdQCkuQmQtBhYFIe7%0D%0AE6LMZ3AKPDWYBPkb37jjd80OyA3cEAAAAWbwJ1QeAAAEAwBGMEQCIAzNFnn0UQyL%0D%0A5ZkwA7BX2JiQkjCk9QZrNHR9S1So7l8LAiAzoHDpWV5Dq5iM5NU86nJwqB1qsjZt%0D%0Aa4fWlvNKs0S+eQB3AId1v+dZfPiMQ5lfvfNu/1aNR1Y2/0q1YMG06v9eoIMPAAAB%0D%0AZvAnVbMAAAQDAEgwRgIhAOr0s3YbgyIs7dytmC1s5ClugVmo+r+W6ZKqRpphsIjT%0D%0AAiEAqgzFns9X9+SKwTSz0h1epijxrnWH+qZ815QgaJVd83UAdwDuS723dc5guuFC%0D%0AaR+r4Z5mow9+X7By2IMAxHuJeqj9ywAAAWbwJ1RAAAAEAwBIMEYCIQCsFv4KXmNK%0D%0A+POADrfs37hcjApxSuiK14+tN5wFGby6QQIhANa+RvbVx1nYk13IyLCBiCMENLEV%0D%0A9urcBZfprZN+ZsrlMA0GCSqGSIb3DQEBCwUAA4IBAQB+tQhW07rk6eb2L2Ir+Wwq%0D%0Al5ZJaoaZq3zwoG8vPMFTZbcWPYsSVI5KuXELdB1QnmPbHebTJuI/gjfD65vf7C3N%0D%0ABjgLoXui39mwN4UNTBCc2Ls8s8/aVfTZGPCNNwynCEsY9h0HRobI8kiVPvU0kyBJ%0D%0AO3p3msqR7W2lAIWciJWmoPQkEFh7u84/oc7Pz2SSE6tqMW9lZmyBqjSuBufRJn1g%0D%0ACTdp/5DZdQWTNL6L5GSsRoXQnarsVtFVriqOjWf5R4O4z6LQznlbBQCMUR3geUNq%0D%0A0vSblnmgav0+L9HK97wqtONu1CrJ9/Q2JwoxFAs/zps/nh9oJU2ToK9lzl/38gpo%0D%0A-----END%20CERTIFICATE-----%0D%0A",
+ },
+ fingerprint: {
+ sha1: "8E:43:B7:D0:84:FD:B2:6C:08:9E:D3:F1:10:0C:D2:1D:D4:AD:C6:DF",
+ sha256:
+ "37:BF:44:A9:28:03:8A:22:AE:0C:E3:2D:96:3C:36:F5:D2:2D:37:99:D6:B2:63:CB:9C:1D:45:D1:CF:FE:B0:69",
+ },
+ issuer: {
+ cn: "DigiCert SHA2 Extended Validation Server CA",
+ dn: "c=US, o=DigiCert Inc, ou=www.digicert.com, cn=DigiCert SHA2 Extended Validation Server CA",
+ entries: [
+ ["Country", "US"],
+ ["Organization", "DigiCert Inc"],
+ ["Organizational Unit", "www.digicert.com"],
+ ["Common Name", "DigiCert SHA2 Extended Validation Server CA"],
+ ],
+ },
+ notBefore: "11/6/2018, 10:00:00 PM (Brasilia Standard Time)",
+ notBeforeUTC: "Wed, 07 Nov 2018 00:00:00 GMT",
+ notAfter: "11/13/2020, 9:00:00 AM (Brasilia Standard Time)",
+ notAfterUTC: "Fri, 13 Nov 2020 12:00:00 GMT",
+ subject: {
+ cn: "www.digicert.com",
+ dn: "OID.2.5.4.15=Private Organization, OID.1.3.6.1.4.1.311.60.2.1.3=US, OID.1.3.6.1.4.1.311.60.2.1.2=Utah, serialNumber=5299537-0142, c=US, s=Utah, l=Lehi, o=DigiCert, Inc., ou=SRE, cn=www.digicert.com",
+ entries: [
+ ["Business Category", "Private Organization"],
+ ["Inc. Country", "US"],
+ ["Inc. State / Province", "Utah"],
+ ["Serial Number", "5299537-0142"],
+ ["Country", "US"],
+ ["State / Province", "Utah"],
+ ["Locality", "Lehi"],
+ ["Organization", "DigiCert, Inc."],
+ ["Organizational Unit", "SRE"],
+ ["Common Name", "www.digicert.com"],
+ ],
+ },
+ serialNumber: "0E:B6:EA:B4:18:C8:73:D8:F3:C0:31:DC:DD:DF:18:B0",
+ signature: {
+ name: "SHA-256 with RSA Encryption",
+ type: "1.2.840.113549.1.1.11",
+ },
+ subjectPublicKeyInfo: {
+ e: 65537,
+ kty: "RSA",
+ n: "CE:9F:85:CA:39:30:30:B7:F6:98:69:B4:9C:10:5D:50:3B:25:63:D0:E5:68:D4:D9:A5:CA:2C:D6:35:95:B2:3E:0D:29:8B:9D:E0:81:4A:04:F7:C0:9E:35:49:33:FB:AB:1C:11:8A:96:35:8E:A5:DE:A2:81:E7:AA:49:24:8A:8D:42:6A:3D:36:85:8E:F2:4D:86:FE:34:C8:8C:51:46:A8:D5:98:22:AD:B7:8B:8F:87:A9:A5:E2:D7:F1:FF:69:61:60:6B:39:35:AA:4C:B2:00:E4:10:03:FA:79:E9:B1:BD:9B:93:A4:FC:80:4C:FC:16:67:2E:A5:49:2C:62:4E:C7:D8:A1:80:6D:5D:23:D0:EB:EA:F6:A9:FB:C4:1A:3D:16:AE:DE:DF:6C:11:DD:9C:C5:EE:08:C7:B8:0B:75:A6:06:DE:FC:6C:61:FD:C1:C9:C2:93:48:AB:72:AD:B9:17:D5:0C:B4:76:C4:B1:CB:E1:82:33:61:13:C4:4D:60:31:AE:EF:46:89:90:FD:9A:19:A3:C2:1B:E7:99:05:A7:A9:48:4F:A5:0E:3A:49:1D:CA:22:5D:A5:63:D7:21:96:65:B1:94:79:C2:47:A0:58:3B:09:3F:B5:EF:EE:71:34:58:C9:18:D7:ED:39:88:D6:2D:AF:36:51:86:19:67:07:0D:80:A0:C1:8D:23:EB:6C:05:72:D0:29:E6:5F:58:59:94:DF:46:E1:93:35:FD:F6:99:AF:21:82:77:7F:57:D0:18:B6:A8:E3:89:D0:12:37:64:9C:8B:E9:9B:41:CC:82:F6:A0:60:29:D0:56:79:E1:25:2B:73:C9:8C:F7:DB:87:E5:58:B3:D2:A7:9E:CE:41:E3:4C:B6:BE:8E:E5:6D:07:75:6C:A1:51:95:3E:0F:84:7A:C0:E6:D8:40:C6:79:6E:26:23:46:1B:40:42:33:20:F0:45:50:11:F6:73:11:DA:F4:58:63:B9:25:11:CB:1F:2A:2D:F2:D1:2B:5C:CF:43:88:5E:5C:09:BC:DF:72:37:AE:A2:29:36:48:75:BE:BD:BB:8F:6A:03:22:1D:33:3D:FB:79:6B:D2:84:4E:F9:95:B0:70:CE:DF:26:F9:F5:25:F4:76:3C:32:C0:68:8D:D0:52:FE:CE:2E:14:87:DF:65:1F:42:C9:3E:D4:80:AA:D3:99:B6:1F:04:B1:88:0B:E2:0D:19:79:0D:EE:BA:30:46:43:76:FB:B4:DE:C5:00:41:31:EF:5A:7C:34:32:BE:C9:81:B8:ED:9F:40:DE:50:A2:D8:C2:C4:56:83:EB:29:AA:81:53:24:75:86:6D:BF:51:21:BF:B7:97:17:AF:EE:72:2A:39",
+ keysize: 4096,
+ },
+ unsupportedExtensions: [],
+ version: "3",
+ },
+ {
+ ext: {
+ aia: {
+ descriptions: [
+ {
+ location: "http://ocsp.digicert.com",
+ method: "Online Certificate Status Protocol (OCSP)",
+ },
+ ],
+ critical: false,
+ },
+ aKID: {
+ critical: false,
+ id: "B1:3E:C3:69:03:F8:BF:47:01:D4:98:26:1A:08:02:EF:63:64:2B:C3",
+ },
+ basicConstraints: { cA: true, critical: true },
+ crlPoints: {
+ critical: false,
+ points: ["http://crl4.digicert.com/DigiCertHighAssuranceEVRootCA.crl"],
+ },
+ cp: {
+ critical: false,
+ policies: [
+ {
+ id: "2.5.29.32.0",
+ qualifiers: [
+ {
+ id: "1.3.6.1.5.5.7.2.1",
+ name: "Practices Statement",
+ value: "https://www.digicert.com/CPS",
+ },
+ ],
+ },
+ ],
+ },
+ eKeyUsages: {
+ critical: false,
+ purposes: ["Server Authentication", "Client Authentication"],
+ },
+ keyUsages: {
+ critical: true,
+ purposes: ["Digital Signature", "Certificate Signing", "CRL Signing"],
+ },
+ msCrypto: { exists: false },
+ ocspStaple: { critical: false, required: false },
+ scts: { critical: false, timestamps: [] },
+ sKID: {
+ critical: false,
+ id: "3D:D3:50:A5:D6:A0:AD:EE:F3:4A:60:0A:65:D3:21:D4:F8:F8:D6:0F",
+ },
+ san: { altNames: [], critical: false },
+ },
+ files: {
+ pem: "-----BEGIN%20CERTIFICATE-----%0D%0AMIIEtjCCA56gAwIBAgIQDHmpRLCMEZUgkmFf4msdgzANBgkqhkiG9w0BAQsFADBs%0D%0AMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3%0D%0Ad3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j%0D%0AZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowdTEL%0D%0AMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3%0D%0ALmRpZ2ljZXJ0LmNvbTE0MDIGA1UEAxMrRGlnaUNlcnQgU0hBMiBFeHRlbmRlZCBW%0D%0AYWxpZGF0aW9uIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC%0D%0AggEBANdTpARR+JmmFkhLZyeqk0nQOe0MsLAAh/FnKIaFjI5j2ryxQDji0/XspQUY%0D%0AuD0+xZkXMuwYjPrxDKZkIYXLBxA0sFKIKx9om9KxjxKws9LniB8f7zh3VFNfgHk/%0D%0ALhqqqB5LKw2rt2O5Nbd9FLxZS99RStKh4gzikIKHaq7q12TWmFXo/a8aUGxUvBHy%0D%0A/Urynbt/DvTVvo4WiRJV2MBxNO723C3sxIclho3YIeSwTQyJ3DkmF93215SF2AQh%0D%0AcJ1vb/9cuhnhRctWVyh+HA1BV6q3uCe7seT6Ku8hI3UarS2bhjWMnHe1c63YlC3k%0D%0A8wyd7sFOYn4XwHGeLN7x+RAoGTMCAwEAAaOCAUkwggFFMBIGA1UdEwEB/wQIMAYB%0D%0AAf8CAQAwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF%0D%0ABQcDAjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp%0D%0AZ2ljZXJ0LmNvbTBLBgNVHR8ERDBCMECgPqA8hjpodHRwOi8vY3JsNC5kaWdpY2Vy%0D%0AdC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3JsMD0GA1UdIAQ2%0D%0AMDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5j%0D%0Ab20vQ1BTMB0GA1UdDgQWBBQ901Cl1qCt7vNKYApl0yHU+PjWDzAfBgNVHSMEGDAW%0D%0AgBSxPsNpA/i/RwHUmCYaCALvY2QrwzANBgkqhkiG9w0BAQsFAAOCAQEAnbbQkIbh%0D%0AhgLtxaDwNBx0wY12zIYKqPBKikLWP8ipTa18CK3mtlC4ohpNiAexKSHc59rGPCHg%0D%0A4xFJcKx6HQGkyhE6V6t9VypAdP3THYUYUN9XR3WhfVUgLkc3UHKMf4Ib0mKPLQNa%0D%0A2sPIoc4sUqIAY+tzunHISScjl2SFnjgOrWNoPLpSgVh5oywM395t6zHyuqB8bPEs%0D%0A1OG9d4Q3A84ytciagRpKkk47RpqF/oOi+Z6Mo8wNXrM9zwR4jxQUezKcxwCmXMS1%0D%0AoVWNWlZopCJwqjyBcdmdqEU79OX2olHdx3ti6G8MdOu42vi/hw15UJGQmxg7kVkn%0D%0A8TUoE6smftX3eg==%0D%0A-----END%20CERTIFICATE-----%0D%0A",
+ },
+ fingerprint: {
+ sha1: "7E:2F:3A:4F:8F:E8:FA:8A:57:30:AE:CA:02:96:96:63:7E:98:6F:3F",
+ sha256:
+ "40:3E:06:2A:26:53:05:91:13:28:5B:AF:80:A0:D4:AE:42:2C:84:8C:9F:78:FA:D0:1F:C9:4B:C5:B8:7F:EF:1A",
+ },
+ issuer: {
+ cn: "DigiCert High Assurance EV Root CA",
+ dn: "c=US, o=DigiCert Inc, ou=www.digicert.com, cn=DigiCert High Assurance EV Root CA",
+ entries: [
+ ["Country", "US"],
+ ["Organization", "DigiCert Inc"],
+ ["Organizational Unit", "www.digicert.com"],
+ ["Common Name", "DigiCert High Assurance EV Root CA"],
+ ],
+ },
+ notBefore: "10/22/2013, 10:00:00 AM (Brasilia Standard Time)",
+ notBeforeUTC: "Tue, 22 Oct 2013 12:00:00 GMT",
+ notAfter: "10/22/2028, 9:00:00 AM (Brasilia Standard Time)",
+ notAfterUTC: "Sun, 22 Oct 2028 12:00:00 GMT",
+ subject: {
+ cn: "DigiCert SHA2 Extended Validation Server CA",
+ dn: "c=US, o=DigiCert Inc, ou=www.digicert.com, cn=DigiCert SHA2 Extended Validation Server CA",
+ entries: [
+ ["Country", "US"],
+ ["Organization", "DigiCert Inc"],
+ ["Organizational Unit", "www.digicert.com"],
+ ["Common Name", "DigiCert SHA2 Extended Validation Server CA"],
+ ],
+ },
+ serialNumber: "0C:79:A9:44:B0:8C:11:95:20:92:61:5F:E2:6B:1D:83",
+ signature: {
+ name: "SHA-256 with RSA Encryption",
+ type: "1.2.840.113549.1.1.11",
+ },
+ subjectPublicKeyInfo: {
+ e: 65537,
+ kty: "RSA",
+ n: "D7:53:A4:04:51:F8:99:A6:16:48:4B:67:27:AA:93:49:D0:39:ED:0C:B0:B0:00:87:F1:67:28:86:85:8C:8E:63:DA:BC:B1:40:38:E2:D3:F5:EC:A5:05:18:B8:3D:3E:C5:99:17:32:EC:18:8C:FA:F1:0C:A6:64:21:85:CB:07:10:34:B0:52:88:2B:1F:68:9B:D2:B1:8F:12:B0:B3:D2:E7:88:1F:1F:EF:38:77:54:53:5F:80:79:3F:2E:1A:AA:A8:1E:4B:2B:0D:AB:B7:63:B9:35:B7:7D:14:BC:59:4B:DF:51:4A:D2:A1:E2:0C:E2:90:82:87:6A:AE:EA:D7:64:D6:98:55:E8:FD:AF:1A:50:6C:54:BC:11:F2:FD:4A:F2:9D:BB:7F:0E:F4:D5:BE:8E:16:89:12:55:D8:C0:71:34:EE:F6:DC:2D:EC:C4:87:25:86:8D:D8:21:E4:B0:4D:0C:89:DC:39:26:17:DD:F6:D7:94:85:D8:04:21:70:9D:6F:6F:FF:5C:BA:19:E1:45:CB:56:57:28:7E:1C:0D:41:57:AA:B7:B8:27:BB:B1:E4:FA:2A:EF:21:23:75:1A:AD:2D:9B:86:35:8C:9C:77:B5:73:AD:D8:94:2D:E4:F3:0C:9D:EE:C1:4E:62:7E:17:C0:71:9E:2C:DE:F1:F9:10:28:19:33",
+ keysize: 2048,
+ },
+ unsupportedExtensions: [],
+ version: "3",
+ },
+ {
+ ext: {
+ aia: { critical: false },
+ aKID: {
+ critical: false,
+ id: "B1:3E:C3:69:03:F8:BF:47:01:D4:98:26:1A:08:02:EF:63:64:2B:C3",
+ },
+ basicConstraints: { cA: true, critical: true },
+ cp: { critical: false },
+ keyUsages: {
+ critical: true,
+ purposes: ["Digital Signature", "Certificate Signing", "CRL Signing"],
+ },
+ msCrypto: { exists: false },
+ ocspStaple: { critical: false, required: false },
+ scts: { critical: false, timestamps: [] },
+ sKID: {
+ critical: false,
+ id: "B1:3E:C3:69:03:F8:BF:47:01:D4:98:26:1A:08:02:EF:63:64:2B:C3",
+ },
+ san: { altNames: [], critical: false },
+ },
+ files: {
+ pem: "-----BEGIN%20CERTIFICATE-----%0D%0AMIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs%0D%0AMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3%0D%0Ad3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j%0D%0AZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL%0D%0AMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3%0D%0ALmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug%0D%0ARVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm%0D%0A+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW%0D%0APNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM%0D%0AxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB%0D%0AIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3%0D%0AhzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg%0D%0AEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF%0D%0AMAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA%0D%0AFLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec%0D%0AnzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z%0D%0AeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF%0D%0AhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2%0D%0AYzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe%0D%0AvEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep%0D%0A+OkuE6N36B9K%0D%0A-----END%20CERTIFICATE-----%0D%0A",
+ },
+ fingerprint: {
+ sha1: "5F:B7:EE:06:33:E2:59:DB:AD:0C:4C:9A:E6:D3:8F:1A:61:C7:DC:25",
+ sha256:
+ "74:31:E5:F4:C3:C1:CE:46:90:77:4F:0B:61:E0:54:40:88:3B:A9:A0:1E:D0:0B:A6:AB:D7:80:6E:D3:B1:18:CF",
+ },
+ issuer: {
+ cn: "DigiCert High Assurance EV Root CA",
+ dn: "c=US, o=DigiCert Inc, ou=www.digicert.com, cn=DigiCert High Assurance EV Root CA",
+ entries: [
+ ["Country", "US"],
+ ["Organization", "DigiCert Inc"],
+ ["Organizational Unit", "www.digicert.com"],
+ ["Common Name", "DigiCert High Assurance EV Root CA"],
+ ],
+ },
+ notBefore: "11/9/2006, 10:00:00 PM (Brasilia Standard Time)",
+ notBeforeUTC: "Fri, 10 Nov 2006 00:00:00 GMT",
+ notAfter: "11/9/2031, 9:00:00 PM (Brasilia Standard Time)",
+ notAfterUTC: "Mon, 10 Nov 2031 00:00:00 GMT",
+ subject: {
+ cn: "DigiCert High Assurance EV Root CA",
+ dn: "c=US, o=DigiCert Inc, ou=www.digicert.com, cn=DigiCert High Assurance EV Root CA",
+ entries: [
+ ["Country", "US"],
+ ["Organization", "DigiCert Inc"],
+ ["Organizational Unit", "www.digicert.com"],
+ ["Common Name", "DigiCert High Assurance EV Root CA"],
+ ],
+ },
+ serialNumber: "02:AC:5C:26:6A:0B:40:9B:8F:0B:79:F2:AE:46:25:77",
+ signature: {
+ name: "SHA-1 with RSA Encryption",
+ type: "1.2.840.113549.1.1.5",
+ },
+ subjectPublicKeyInfo: {
+ e: 65537,
+ kty: "RSA",
+ n: "C6:CC:E5:73:E6:FB:D4:BB:E5:2D:2D:32:A6:DF:E5:81:3F:C9:CD:25:49:B6:71:2A:C3:D5:94:34:67:A2:0A:1C:B0:5F:69:A6:40:B1:C4:B7:B2:8F:D0:98:A4:A9:41:59:3A:D3:DC:94:D6:3C:DB:74:38:A4:4A:CC:4D:25:82:F7:4A:A5:53:12:38:EE:F3:49:6D:71:91:7E:63:B6:AB:A6:5F:C3:A4:84:F8:4F:62:51:BE:F8:C5:EC:DB:38:92:E3:06:E5:08:91:0C:C4:28:41:55:FB:CB:5A:89:15:7E:71:E8:35:BF:4D:72:09:3D:BE:3A:38:50:5B:77:31:1B:8D:B3:C7:24:45:9A:A7:AC:6D:00:14:5A:04:B7:BA:13:EB:51:0A:98:41:41:22:4E:65:61:87:81:41:50:A6:79:5C:89:DE:19:4A:57:D5:2E:E6:5D:1C:53:2C:7E:98:CD:1A:06:16:A4:68:73:D0:34:04:13:5C:A1:71:D3:5A:7C:55:DB:5E:64:E1:37:87:30:56:04:E5:11:B4:29:80:12:F1:79:39:88:A2:02:11:7C:27:66:B7:88:B7:78:F2:CA:0A:A8:38:AB:0A:64:C2:BF:66:5D:95:84:C1:A1:25:1E:87:5D:1A:50:0B:20:12:CC:41:BB:6E:0B:51:38:B8:4B:CB",
+ keysize: 2048,
+ },
+ unsupportedExtensions: [],
+ version: "3",
+ },
+];
diff --git a/toolkit/components/certviewer/tests/chrome/test_adjustCertInformation.html b/toolkit/components/certviewer/tests/chrome/test_adjustCertInformation.html
new file mode 100644
index 0000000000..ddd4c8a0b3
--- /dev/null
+++ b/toolkit/components/certviewer/tests/chrome/test_adjustCertInformation.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>certviewer adjustCertInformation test</title>
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+ </head>
+<body>
+ <script type="module">
+ function hasNullElements(obj) {
+ for (let key of Object.keys(obj)) {
+ if (obj[key] == null) return false;
+ if (typeof(obj[key]) === 'object') {
+ if (hasNullElements(obj[key]) === false) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ async function doTest() {
+ const { adjustCertInformation } = await import("chrome://global/content/certviewer/certviewer.mjs");
+ const { parseOutput } = await import("./parseOutput.mjs");
+
+ ok(adjustCertInformation, "adjustCertInformation should be available in this context");
+ ok(parseOutput, "parseOutput should be available in this context");
+ is(typeof(parseOutput), 'object', "parseOutput must be an object");
+
+ for (let cert of parseOutput) {
+ let adjustedCerts = adjustCertInformation(cert);
+ let result = hasNullElements(adjustedCerts.certItems);
+ ok(result, "adjustCertInformation function shouldn't return null elements");
+ }
+
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ doTest();
+
+ </script>
+</body>
+</html>
diff --git a/toolkit/components/certviewer/tests/chrome/test_certDecoder.html b/toolkit/components/certviewer/tests/chrome/test_certDecoder.html
new file mode 100644
index 0000000000..67ad083242
--- /dev/null
+++ b/toolkit/components/certviewer/tests/chrome/test_certDecoder.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>certviewer parse test</title>
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+ </head>
+<body>
+ <script type="module">
+ // inputPEM is the same input to CS extension (https://github.com/april/certainly-something)
+ const inputPEM = "MIIGRjCCBS6gAwIBAgIQDJduPkI49CDWPd+G7+u6kDANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5EaWdpQ2VydCBTSEEyIFNlY3VyZSBTZXJ2ZXIgQ0EwHhcNMTgxMTA1MDAwMDAwWhcNMTkxMTEzMTIwMDAwWjCBgzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxHDAaBgNVBAoTE01vemlsbGEgQ29ycG9yYXRpb24xDzANBgNVBAsTBldlYk9wczEYMBYGA1UEAxMPd3d3Lm1vemlsbGEub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuKruymkkmkqCJh7QjmXlUOBcLFRyw5LG/vUUWVrsxC2gsbR8WJq+cYoYBpoNVStKrO4U2rBh1GEbccvT6qKOQI+pjjDxx9cmRdubGTGp8L0MF1ohVvhIvYLumOEoRDDPU4PvGJjGhek/ojvedPWe8dhciHkxOC2qPFZvVFMwg1/o/b80147BwZQmzB18mnHsmcyKlpsCN8pxw86uao9Iun8gZQrsllW64rTZlRR56pHdAcuGAoZjYZxwS9Z+lvrSjEgrddemWyGGalqyFp1rXlVM1Tf4/IYWAQXTgTUN303u3xMjss7QK7eUDsACRxiWPLW9XQDd1c+yvaYJKzgJ2wIDAQABo4IC6TCCAuUwHwYDVR0jBBgwFoAUD4BhHIIxYdUvKOeNRji0LOHG2eIwHQYDVR0OBBYEFNpSvSGcN2VT/B9TdQ8eXwebo60/MCcGA1UdEQQgMB6CD3d3dy5tb3ppbGxhLm9yZ4ILbW96aWxsYS5vcmcwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBrBgNVHR8EZDBiMC+gLaArhilodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc3NjYS1zaGEyLWc2LmNybDAvoC2gK4YpaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NzY2Etc2hhMi1nNi5jcmwwTAYDVR0gBEUwQzA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBAgIwfAYIKwYBBQUHAQEEcDBuMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wRgYIKwYBBQUHMAKGOmh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJTZWN1cmVTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH/BAIwADCCAQIGCisGAQQB1nkCBAIEgfMEgfAA7gB1AKS5CZC0GFgUh7sTosxncAo8NZgE+RvfuON3zQ7IDdwQAAABZuYWiHwAAAQDAEYwRAIgZnMSH1JdG6NASHWTwD0mlP/zbr0hzP263c02Ym0DU64CIEe4QHJDP47j0b6oTFu6RrZz1NQ9cq8Az1KnMKRuaFAlAHUAh3W/51l8+IxDmV+9827/Vo1HVjb/SrVgwbTq/16ggw8AAAFm5haJAgAABAMARjBEAiAxGLXkUaOAkZhXNeNR3pWyahZeKmSaMXadgu18SfK1ZAIgKtwu5eGxK76rgaszLCZ9edBIjuU0DKorzPUuxUXFY0QwDQYJKoZIhvcNAQELBQADggEBAKLJAFO3wuaP5MM/ed1lhk5Uc2aDokhcM7XyvdhEKSHbgPhcgMoT9YIVoPa70gNC6KHcwoXu0g8wt7X6Vm1ql/68G5q844kFuC6JPl4LVT9mciD+VW6bHUSXD9xifL9DqdJ0Ic0SllTlM+oq5aAeOxUQGXhXIqj6fSQv9fQN6mXxQIoc/gjxteskq/Vl8YmY1FIZP9Bh7g27kxZ9GAAGQtjTL03RzKAuSg6yeImYVdQWasc7UPnBXlRAzZ8+OJThUbzK16a2CI3Rg4agKSJk+uA47h1/ImmngpFLRb/MvRX6H1oWcUuyH6O7PZdl0YpwTpw1THIuqCGl/wpPgyQgcTM=";
+ const certOutputCS = "-----BEGIN%20CERTIFICATE-----%0D%0AMIIGRjCCBS6gAwIBAgIQDJduPkI49CDWPd+G7+u6kDANBgkqhkiG9w0BAQsFADBN%0D%0AMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5E%0D%0AaWdpQ2VydCBTSEEyIFNlY3VyZSBTZXJ2ZXIgQ0EwHhcNMTgxMTA1MDAwMDAwWhcN%0D%0AMTkxMTEzMTIwMDAwWjCBgzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3Ju%0D%0AaWExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxHDAaBgNVBAoTE01vemlsbGEgQ29y%0D%0AcG9yYXRpb24xDzANBgNVBAsTBldlYk9wczEYMBYGA1UEAxMPd3d3Lm1vemlsbGEu%0D%0Ab3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuKruymkkmkqCJh7Q%0D%0AjmXlUOBcLFRyw5LG/vUUWVrsxC2gsbR8WJq+cYoYBpoNVStKrO4U2rBh1GEbccvT%0D%0A6qKOQI+pjjDxx9cmRdubGTGp8L0MF1ohVvhIvYLumOEoRDDPU4PvGJjGhek/ojve%0D%0AdPWe8dhciHkxOC2qPFZvVFMwg1/o/b80147BwZQmzB18mnHsmcyKlpsCN8pxw86u%0D%0Aao9Iun8gZQrsllW64rTZlRR56pHdAcuGAoZjYZxwS9Z+lvrSjEgrddemWyGGalqy%0D%0AFp1rXlVM1Tf4/IYWAQXTgTUN303u3xMjss7QK7eUDsACRxiWPLW9XQDd1c+yvaYJ%0D%0AKzgJ2wIDAQABo4IC6TCCAuUwHwYDVR0jBBgwFoAUD4BhHIIxYdUvKOeNRji0LOHG%0D%0A2eIwHQYDVR0OBBYEFNpSvSGcN2VT/B9TdQ8eXwebo60/MCcGA1UdEQQgMB6CD3d3%0D%0Ady5tb3ppbGxhLm9yZ4ILbW96aWxsYS5vcmcwDgYDVR0PAQH/BAQDAgWgMB0GA1Ud%0D%0AJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBrBgNVHR8EZDBiMC+gLaArhilodHRw%0D%0AOi8vY3JsMy5kaWdpY2VydC5jb20vc3NjYS1zaGEyLWc2LmNybDAvoC2gK4YpaHR0%0D%0AcDovL2NybDQuZGlnaWNlcnQuY29tL3NzY2Etc2hhMi1nNi5jcmwwTAYDVR0gBEUw%0D%0AQzA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNl%0D%0AcnQuY29tL0NQUzAIBgZngQwBAgIwfAYIKwYBBQUHAQEEcDBuMCQGCCsGAQUFBzAB%0D%0AhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wRgYIKwYBBQUHMAKGOmh0dHA6Ly9j%0D%0AYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJTZWN1cmVTZXJ2ZXJDQS5j%0D%0AcnQwDAYDVR0TAQH/BAIwADCCAQIGCisGAQQB1nkCBAIEgfMEgfAA7gB1AKS5CZC0%0D%0AGFgUh7sTosxncAo8NZgE+RvfuON3zQ7IDdwQAAABZuYWiHwAAAQDAEYwRAIgZnMS%0D%0AH1JdG6NASHWTwD0mlP/zbr0hzP263c02Ym0DU64CIEe4QHJDP47j0b6oTFu6RrZz%0D%0A1NQ9cq8Az1KnMKRuaFAlAHUAh3W/51l8+IxDmV+9827/Vo1HVjb/SrVgwbTq/16g%0D%0Agw8AAAFm5haJAgAABAMARjBEAiAxGLXkUaOAkZhXNeNR3pWyahZeKmSaMXadgu18%0D%0ASfK1ZAIgKtwu5eGxK76rgaszLCZ9edBIjuU0DKorzPUuxUXFY0QwDQYJKoZIhvcN%0D%0AAQELBQADggEBAKLJAFO3wuaP5MM/ed1lhk5Uc2aDokhcM7XyvdhEKSHbgPhcgMoT%0D%0A9YIVoPa70gNC6KHcwoXu0g8wt7X6Vm1ql/68G5q844kFuC6JPl4LVT9mciD+VW6b%0D%0AHUSXD9xifL9DqdJ0Ic0SllTlM+oq5aAeOxUQGXhXIqj6fSQv9fQN6mXxQIoc/gjx%0D%0Ateskq/Vl8YmY1FIZP9Bh7g27kxZ9GAAGQtjTL03RzKAuSg6yeImYVdQWasc7UPnB%0D%0AXlRAzZ8+OJThUbzK16a2CI3Rg4agKSJk+uA47h1/ImmngpFLRb/MvRX6H1oWcUuy%0D%0AH6O7PZdl0YpwTpw1THIuqCGl/wpPgyQgcTM=%0D%0A-----END%20CERTIFICATE-----%0D%0A";
+
+
+ async function doTest() {
+ const { parse, pemToDER } = await import("chrome://global/content/certviewer/certDecoder.mjs");
+
+ ok(parse, "parse should be available in this context");
+ ok(pemToDER, "pemToDER should be available in this context");
+
+ let input = inputPEM.trim()
+ .replace(/\r|\n|\0/g, "")
+ .split()
+ .filter(v => v.startsWith("MII"))[0];
+
+ let certDER = pemToDER(input);
+ let cert = await parse(certDER);
+ ok(cert, "There should be a result");
+ is(cert.files.pem, certOutputCS, "certificates output must be the same");
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ doTest();
+
+ </script>
+</body>
+</html>
diff --git a/toolkit/components/certviewer/tests/chrome/test_certDecoderFields.html b/toolkit/components/certviewer/tests/chrome/test_certDecoderFields.html
new file mode 100644
index 0000000000..1f54cced4b
--- /dev/null
+++ b/toolkit/components/certviewer/tests/chrome/test_certDecoderFields.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>certviewer parse test</title>
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+ </head>
+<body>
+ <script type="module">
+ // inputPEM is the same input to CS extension (https://github.com/april/certainly-something)
+ const inputPEM = "MIIGRjCCBS6gAwIBAgIQDJduPkI49CDWPd+G7+u6kDANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5EaWdpQ2VydCBTSEEyIFNlY3VyZSBTZXJ2ZXIgQ0EwHhcNMTgxMTA1MDAwMDAwWhcNMTkxMTEzMTIwMDAwWjCBgzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxHDAaBgNVBAoTE01vemlsbGEgQ29ycG9yYXRpb24xDzANBgNVBAsTBldlYk9wczEYMBYGA1UEAxMPd3d3Lm1vemlsbGEub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuKruymkkmkqCJh7QjmXlUOBcLFRyw5LG/vUUWVrsxC2gsbR8WJq+cYoYBpoNVStKrO4U2rBh1GEbccvT6qKOQI+pjjDxx9cmRdubGTGp8L0MF1ohVvhIvYLumOEoRDDPU4PvGJjGhek/ojvedPWe8dhciHkxOC2qPFZvVFMwg1/o/b80147BwZQmzB18mnHsmcyKlpsCN8pxw86uao9Iun8gZQrsllW64rTZlRR56pHdAcuGAoZjYZxwS9Z+lvrSjEgrddemWyGGalqyFp1rXlVM1Tf4/IYWAQXTgTUN303u3xMjss7QK7eUDsACRxiWPLW9XQDd1c+yvaYJKzgJ2wIDAQABo4IC6TCCAuUwHwYDVR0jBBgwFoAUD4BhHIIxYdUvKOeNRji0LOHG2eIwHQYDVR0OBBYEFNpSvSGcN2VT/B9TdQ8eXwebo60/MCcGA1UdEQQgMB6CD3d3dy5tb3ppbGxhLm9yZ4ILbW96aWxsYS5vcmcwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBrBgNVHR8EZDBiMC+gLaArhilodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc3NjYS1zaGEyLWc2LmNybDAvoC2gK4YpaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NzY2Etc2hhMi1nNi5jcmwwTAYDVR0gBEUwQzA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBAgIwfAYIKwYBBQUHAQEEcDBuMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wRgYIKwYBBQUHMAKGOmh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJTZWN1cmVTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH/BAIwADCCAQIGCisGAQQB1nkCBAIEgfMEgfAA7gB1AKS5CZC0GFgUh7sTosxncAo8NZgE+RvfuON3zQ7IDdwQAAABZuYWiHwAAAQDAEYwRAIgZnMSH1JdG6NASHWTwD0mlP/zbr0hzP263c02Ym0DU64CIEe4QHJDP47j0b6oTFu6RrZz1NQ9cq8Az1KnMKRuaFAlAHUAh3W/51l8+IxDmV+9827/Vo1HVjb/SrVgwbTq/16ggw8AAAFm5haJAgAABAMARjBEAiAxGLXkUaOAkZhXNeNR3pWyahZeKmSaMXadgu18SfK1ZAIgKtwu5eGxK76rgaszLCZ9edBIjuU0DKorzPUuxUXFY0QwDQYJKoZIhvcNAQELBQADggEBAKLJAFO3wuaP5MM/ed1lhk5Uc2aDokhcM7XyvdhEKSHbgPhcgMoT9YIVoPa70gNC6KHcwoXu0g8wt7X6Vm1ql/68G5q844kFuC6JPl4LVT9mciD+VW6bHUSXD9xifL9DqdJ0Ic0SllTlM+oq5aAeOxUQGXhXIqj6fSQv9fQN6mXxQIoc/gjxteskq/Vl8YmY1FIZP9Bh7g27kxZ9GAAGQtjTL03RzKAuSg6yeImYVdQWasc7UPnBXlRAzZ8+OJThUbzK16a2CI3Rg4agKSJk+uA47h1/ImmngpFLRb/MvRX6H1oWcUuyH6O7PZdl0YpwTpw1THIuqCGl/wpPgyQgcTM=";
+ const inputPEMerror1 = "MIIGRjCCBS6gAwIBAgIQDJduPkI49CDWPd+G7+u6kDANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5EaWdpQ2VydCBTSEEyIFNlY3VyZSBTZXJ2ZXIgQ0EwHhcNMTgxMTA1MDAwMDAwWhcNMTkxMTEzMTIwMDAwWjCBgzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxHDAaBgNVBAoTE01vemlsbGEgQ29ycG9yYXRpb24xDzANBgNVBAsTBldlYk9wczEYMBYGA1UEAxMPd3d3Lm1vemlsbGEub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuKruymkkmkqCJh7QjmXlUOBcLFRyw5LG/vUUWVrsxC2gsbR8WJq+cYoYBpoNVStKrO4U2rBh1GEbccvT6qKOQI+pjjDxx9cmRdubGTGp8L0MF1ohVvhIvYLumOEoRDDPU4PvGJjGhek/ojvedPWe8dhciHkxOC2qPFZvVFMwg1/o/b80147BwZQmzB18mnHsmcyKlpsCN8pxw86uao9Iun8gZQrsllW64rTZlRR56pHdAcuGAoZjYZxwS9Z+lvrSjEgrddemWyGGalqyFp1rXlVM1Tf4/IYWAQXTgTUN303u3xMjss7QK7eUDsACRxiWPLW9XQDd1c+yvaYJKzgJ2wIDAQABo4IC6TCCAuUwHwYDVR0jBBgwFoAUD4BhHIIxYdUvKOeNRji0LOHG2eIwHQYDVR0OBBYEFNpSvSGcN2VT/B9TdQ8eXwebo60/MCcGA1UdEQQgMB6CD3d3dy5tb3ppbGxhLm9yZ4ILbW96aWxsYS5vcmcwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBrBgNVHR8EZDBiMC+gLaArhilodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc3NjYS1zaGEyLWc2LmNybDAvoC2gK4YpaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NzY2Etc2hhMi1nNi5jcmwwTAYDVR0gBEUwQzA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBAgIwfAYIKwYBBQUHAQEEcDBuMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wRgYIKwYBBQUHMAKGOmh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJTZWN1cmVTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH/BAIwADCCAQIGCisGAQQB1nkCBAIEgfMEgfAA7gB1AKS5CZC0GFgUh7sTosxncAo8NZgE+RvfuON3zQ7IDdwQAAABZuYWiHwAAAQDAEYwRAIgZnMSH1JdG6NASHWTwD0mlP/zbr0hzP263c02Ym0DU64CIEe4QHJDP47j0b6oTFu6RrZz1NQ9cq8Az1KnMKRuaFAlAHUAh3W/51l8+IxDmV+9827/Vo1HVjb/SrVgwbTq/16ggw8AAAFm5haJAgAABAMARjBEAiAxGLXkUaOAkZhXNeNR3pWyahZeKmSaMXadgu18SfK1ZAIgKtwu5eGxK76rgaszLCZ9edBIjuU0DKorzPUuxUXFY0QwDQYJKoZIhvcNAQELBQADggEBAKLJAFO3wuaP5MM/ed1lhk5Uc2aDokhcM7XyvdhEKSHbgPhcgMoT9YIVoPa70gNC6KHcwoXu0g8wt7X6Vm1ql/68G5q844kFuC6JPl4LVT9mciD+VW6bHUSXD9xifL9D";
+ const inputPEMerror2 = "VUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5EaWdpQ2VydCBTSEEyIFNlY3VyZSBTZXJ2ZXIgQ0EwHhcNMTgxMTA1MDAwMDAwWhcNMTkxMTEzMTIwMDAwWjCBgzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxHDAaBgNVBAoTE01vemlsbGEgQ29ycG9yYXRpb24xDzANBgNVBAsTBldlYk9wczEYMBYGA1UEAxMPd3d3Lm1vemlsbGEub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuKruymkkmkqCJh7QjmXlUOBcLFRyw5LG/vUUWVrsxC2gsbR8WJq+cYoYBpoNVStKrO4U2rBh1GEbccvT6qKOQI+pjjDxx9cmRdubGTGp8L0MF1ohVvhIvYLumOEoRDDPU4PvGJjGhek/ojvedPWe8dhciHkxOC2qPFZvVFMwg1/o/b80147BwZQmzB18mnHsmcyKlpsCN8pxw86uao9Iun8gZQrsllW64rTZlRR56pHdAcuGAoZjYZxwS9Z+lvrSjEgrddemWyGGalqyFp1rXlVM1Tf4/IYWAQXTgTUN303u3xMjss7QK7eUDsACRxiWPLW9XQDd1c+yvaYJKzgJ2wIDAQABo4IC6TCCAuUwHwYDVR0jBBgwFoAUD4BhHIIxYdUvKOeNRji0LOHG2eIwHQYDVR0OBBYEFNpSvSGcN2VT/B9TdQ8eXwebo60/MCcGA1UdEQQgMB6CD3d3dy5tb3ppbGxhLm9yZ4ILbW96aWxsYS5vcmcwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBrBgNVHR8EZDBiMC+gLaArhilodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc3NjYS1zaGEyLWc2LmNybDAvoC2gK4YpaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NzY2Etc2hhMi1nNi5jcmwwTAYDVR0gBEUwQzA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBAgIwfAYIKwYBBQUHAQEEcDBuMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wRgYIKwYBBQUHMAKGOmh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJTZWN1cmVTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH/BAIwADCCAQIGCisGAQQB1nkCBAIEgfMEgfAA7gB1AKS5CZC0GFgUh7sTosxncAo8NZgE+RvfuON3zQ7IDdwQAAABZuYWiHwAAAQDAEYwRAIgZnMSH1JdG6NASHWTwD0mlP/zbr0hzP263c02Ym0DU64CIEe4QHJDP47j0b6oTFu6RrZz1NQ9cq8Az1KnMKRuaFAlAHUAh3W/51l8+IxDmV+9827/Vo1HVjb/SrVgwbTq/16ggw8AAAFm5haJAgAABAMARjBEAiAxGLXkUaOAkZhXNeNR3pWyahZeKmSaMXadgu18SfK1ZAIgKtwu5eGxK76rgaszLCZ9edBIjuU0DKorzPUuxUXFY0QwDQYJKoZIhvcNAQELBQADggEBAKLJAFO3wuaP5MM/ed1lhk5Uc2aDokhcM7XyvdhEKSHbgPhcgMoT9YIVoPa70gNC6KHcwoXu0g8wt7X6Vm1ql/68G5q844kFuC6JPl4LVT9mciD+VW6bHUSXD9xifL9DqdJ0Ic0SllTlM+oq5aAeOxUQGXhXIqj6fSQv9fQN6mXxQIoc/gjxteskq/Vl8YmY1FIZP9Bh7g27kxZ9GAAGQtjTL03RzKAuSg6yeImYVdQWasc7UPnBXlRAzZ8+OJThUbzK16a2CI3Rg4agKSJk+uA47h1/ImmngpFLRb/MvRX6H1oWcUuyH6O7PZdl0YpwTpw1THIuqCGl/wpPgyQgcTM=";
+
+ async function run(input, expected) {
+ const { parse, pemToDER } = await import("chrome://global/content/certviewer/certDecoder.mjs");
+
+ ok(parse, "parse should be available in this context");
+ ok(pemToDER, "pemToDER should be available in this context");
+
+ let certDER;
+ try {
+ certDER = pemToDER(input);
+ } catch (err) {
+ is("error", expected, "OK, error found when executing pemToDER function");
+ return;
+ }
+ ok(certDER, "pemToDER returned a non null value");
+
+ let cert;
+ try {
+ cert = await parse(certDER);
+ } catch (err) {
+ is("error", expected, "OK, error found when executing parse function");
+ return;
+ }
+ ok(cert, "Parse function returned an Object");
+
+ // "Because the representation of JS Date objects will vary depending on the timezone,
+ // we don't consider them in the test. Instead we test their corresponding UTC values (e.g notAfterUTC)."
+ cert.notAfter = "";
+ expected.notAfter = "";
+
+ cert.notBefore = "";
+ expected.notBefore = "";
+
+ cert.ext.scts.timestamps = cert.ext.scts.timestamps.map(elem => elem.timestamp = "");
+ expected.ext.scts.timestamps = expected.ext.scts.timestamps.map(elem => elem.timestamp = "");
+
+ is(JSON.stringify(cert), JSON.stringify(expected), "All the fields in CS must be equal to our output");
+ }
+
+ async function doTest() {
+ const { certOutputCS } = await import("./CSoutput.mjs");
+
+ ok(certOutputCS, "certOutputCS should be available in this context");
+ is(typeof(certOutputCS), 'object', "certOutputCS must be an object");
+
+ let inputs = [
+ inputPEM,
+ inputPEMerror1,
+ inputPEMerror2
+ ];
+
+ let expected = [
+ certOutputCS[0],
+ "error",
+ "error"
+ ];
+
+ for (let i = 0; i < inputs.length; i++) {
+ await run(inputs[i], expected[i]);
+ }
+
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ doTest();
+
+ </script>
+</body>
+</html>
diff --git a/toolkit/components/certviewer/tests/chrome/test_kebabCaseInAdjustCertInformation.html b/toolkit/components/certviewer/tests/chrome/test_kebabCaseInAdjustCertInformation.html
new file mode 100644
index 0000000000..b9f7b98d89
--- /dev/null
+++ b/toolkit/components/certviewer/tests/chrome/test_kebabCaseInAdjustCertInformation.html
@@ -0,0 +1,106 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>certviewer adjustCertInformation test</title>
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+ </head>
+<body>
+ <script type="module">
+ function isKebabCase(str) {
+ if (str === "") return true;
+ return /^([a-z][a-z0-9]*)(-[a-z0-9]+)*$/.test(str);
+ }
+
+ function validateIsKebabCase() {
+ let tests = [
+ {
+ input: "",
+ expected: true
+ },
+ {
+ input: "A",
+ expected: false
+ },
+ {
+ input: "Ab",
+ expected: false
+ },
+ {
+ input: "Ab-ad",
+ expected: false
+ },
+ {
+ input: "ad-Az",
+ expected: false
+ },
+ {
+ input: "ad- z",
+ expected: false
+ },
+ {
+ input: "ad-z ",
+ expected: false
+ },
+ {
+ input: "ad z",
+ expected: false
+ },
+ {
+ input: "ad--fz",
+ expected: false
+ },
+ {
+ input: "-a-b-c",
+ expected: false
+ },
+ {
+ input: "ad-fz",
+ expected: true
+ },
+ {
+ input: "ad",
+ expected: true
+ },
+ {
+ input: "a-b-c",
+ expected: true
+ },
+ ];
+
+ for (let test of tests) {
+ let result = isKebabCase(test.input);
+ is(result, test.expected, `${test.input} should${test.expected === false ? "n't" : ""} be a kebab-case string`);
+ }
+ }
+
+ async function doTest() {
+ const { adjustCertInformation } = await import("chrome://global/content/certviewer/certviewer.mjs");
+ const { parseOutput } = await import("./parseOutput.mjs");
+
+ ok(adjustCertInformation, "adjustCertInformation should be available in this context");
+ ok(parseOutput, "parseOutput should be available in this context");
+ is(typeof(parseOutput), 'object', "parseOutput must be an object");
+
+ validateIsKebabCase();
+
+ for (let cert of parseOutput) {
+ let adjustedCerts = adjustCertInformation(cert);
+ adjustedCerts.certItems.forEach(item => {
+ ok(isKebabCase(item.sectionId), `${item.sectionId} should be a valid kebab-case string`);
+ item.sectionItems.forEach(element => {
+ ok(isKebabCase(element.label), `${element.label} should be a valid kebab-case string`);
+ });
+ });
+ }
+
+ SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ doTest();
+
+ </script>
+</body>
+</html>