mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 21:15:32 +09:00
fix(desktop): trust locally added CAs in Chromium on Linux (#3315)
This commit is contained in:
1 parent
4b1afc953f
commit
b146b8ee33
23 files changed
+1109
-1
No files matched your search
@@ -0,0 +1,109 @@
|
|||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
export const CHROMIUM_SPKI_BLOCKLIST_SOURCE = 'chromium 152.0.7977.78 net/cert/cert_verify_proc_blocklist.inc';
|
||||||
|
|
||||||
|
export const CHROMIUM_SPKI_BLOCKLIST: ReadonlySet<string> = new Set([
|
||||||
|
'04dde9aa9a79f61498682325fa0870276707fb9ca95384120b46893268494fc9',
|
||||||
|
'0c43ea8bcde9fc3bca165664ac8215567e3489d5393a0c81e1a79141992e1953',
|
||||||
|
'12132360a33bfdc6c3bf7b7fab26a1684874e72c1263c1f5de565bb49ef03753',
|
||||||
|
'127da27a9e45f082280b31bf1e561520389f96659093b2697c40fe8600236c8c',
|
||||||
|
'130ad4e0633521290531b6651f5759b0bc7bc656709ff8f365c2143b0389b6f6',
|
||||||
|
'15e7ae40cc4b3f7222a5a6fe3e7dc47f6e46ee9a2251839db296d62ada2a0df7',
|
||||||
|
'1528397da212890a830b0b95a59968cef234773779df5181cf10fa647534bb65',
|
||||||
|
'1af56c98ff043ef92bebff54cebb4dd67a25ba956c817f3e6dd3c1e52eb584c1',
|
||||||
|
'1f4224cec84fc99ced881ff6fcfd3e21f8c519c547aa6a5dd3de247302ce50d1',
|
||||||
|
'25da1ad58bbfcfb227d8723b1857d4c18e7baa7417b4f9eff9366b5e869f8b39',
|
||||||
|
'2c998e761160c3b06d82faa9fdc7545d9bda9eb60310f992aa510a6280b74245',
|
||||||
|
'2dc4cb591f7ef0663441646bcf5c0e9dbcded77ca02945193cefc6edb1740614',
|
||||||
|
'30efe41382476c3380f02f7e23e66ba2f867b059ee1ea68796b441b85b5d1256',
|
||||||
|
'32ecc96f912f96d889e73088cd031c7ded2c651c805016157a23b6f32f798a3b',
|
||||||
|
'36ea96128c89839fb621f8ad0e1ee0b9c2206f62ab7b4da2c6765893c9b7ced2',
|
||||||
|
'381a3fc7a8b082fa28613a4d07f2c7553f4e1918ee07caa9e8b7cede5a9ca06a',
|
||||||
|
'383e0e137c37bfb9db29f9a8e45e9ff8dd4c30e440fec2acd3dba7b6c720b993',
|
||||||
|
'394cff589e689312cfc071ee0bc19fe4c606216ce543429de6db62e42dbb3bc1',
|
||||||
|
'3edbd9ace639ba1a2d4ad04718711fda23e859b2fbf5d137d424045e7919dfb9',
|
||||||
|
'455b87e96f1cea2f8b6dae0808ec24738fd92b7fd306757198bf389d755c0b6c',
|
||||||
|
'490b6ec6beb2d6034720b5149b6b29cd35515988cc16af854148b07b9b1f8a11',
|
||||||
|
'4bb8f35ba1e126f8dde1b0c420625ed86dce61a7bddadbdea9aba578ff13145e',
|
||||||
|
'4cdb060f3cfe4c3d3f5e31c300fd68a91e0d1e5f46b64e4895f20e1b5cf8269f',
|
||||||
|
'4eada9b5311e718199d98ea82b95005cba93198ab1f97efcbe8dc6201628f8af',
|
||||||
|
'4f7162b974491c98585ec28fe759aa00c330d0b465190a896cc4b616231831fc',
|
||||||
|
'57809446eaf114843854fe636ed9bcb552e3c616663bc44cc95acf5650016d3e',
|
||||||
|
'5c722cb70fb311f21e0da0e7d12ebc8e05f60796bc49cf511849d5bc62030382',
|
||||||
|
'5e53f26467f894fde53b3fa406a440cbb3b076bb5b758fe4834ad66500208907',
|
||||||
|
'6adb8e3e055460922d1501cb97f94c6a02e39c8f2774ca408825b7b58379dc14',
|
||||||
|
'707d364e72ae521431dd953897f9c4846d5b8c324298fe53fbd4ada1f2d1157f',
|
||||||
|
'7165e991ade7916d86b466abebb6e457ca931c804e58ce1fbabae509156ffb43',
|
||||||
|
'781a4cf2e92452f3ee01d0c381a4214f3904165c390adbd61fcd11244e09b2dc',
|
||||||
|
'7aedddf36b18f8acb7379fe1ce183212b2350d0788abe0e82457be9badad6d54',
|
||||||
|
'7afe4b071a2f1f46f8ba944a26d584d5960b92fb48c3ba1b7cab84905f32aacd',
|
||||||
|
'7cd295b75544808abd9409466f0837c5aadc02e33b6150c6644de0a09659f23c',
|
||||||
|
'7d5e3f50508197b9a478b11340b7dce20a3c4de49c48c9a294158a895c44a21b',
|
||||||
|
'7e7058ea35ad4359654159973f560187f16d19c514b939c5055672d1d2a518ac',
|
||||||
|
'87bfd8afa3af5b429d09a9aa54ee61364f5ae11131e438fc41095343cd16b135',
|
||||||
|
'8a2affbd1a1c5d1bdccbb7f548ba995f966806b3fd0c3a00fae2e52f3c853989',
|
||||||
|
'8e12d0cb3b7df3ea2257579489fd8658c95603ea6cf4b73163a41eb7b7e93fee',
|
||||||
|
'8f591f7aa4dc3efe9490c38a4692c9011ed128f1de595569406d77b6fa1f6b4c',
|
||||||
|
'927a1b8562280576d048c50321ada43d8703d2d9521a18c28b8c46cc6aae4efd',
|
||||||
|
'93ca2d436cae7f68d2b4256ca175c985ce39926dc9f7eeaeecf2f8970fb97802',
|
||||||
|
'962e4b54bb98a7ee5d5feb9633f991d3c3300e9514dade7b0d4f828c794f8e87',
|
||||||
|
'968dba69fbff15bf3762089431ade5a7ead4b7eaf1be70026810bc57d1c64f6e',
|
||||||
|
'99ba4784f9b08512902eb0c3c86df0ec049eac9b65f77a9ba42be9d6ebce320f',
|
||||||
|
'9b8a93decccfbafcf4d04d3442128fb35218cfe437a3d8d0328c99f89089e450',
|
||||||
|
'9c59a3ccaea4699842b068cfc52cf945db51986957c832cdb18ca73849fbb9ee',
|
||||||
|
'9d98a1fb60538c4cc4857ff1a8c8034faf6fc592093f619994b2c813d250b864',
|
||||||
|
'9dd55fc573f546cb6a3831d1112d8710a6f4f82dc87f5fae9d3a1a028dd36e4b',
|
||||||
|
'a0cf53f422651e39317ae31af64577be450fa376e289ed8342b7fc133c697419',
|
||||||
|
'a903af8c07bb91b0d9e3f3a30c6d53339fc5bd47e5d6bdb476598860c068a024',
|
||||||
|
'a9b55a9b5531bbf7c71a1e4920efe796c2b67968f55a6ce5cb62172ed9945bca',
|
||||||
|
'af591518e2e6c60ebbfc0907afaa49bc4051d45e7f214abfee7512ee00f661ed',
|
||||||
|
'b13fa2e6131a888a01f3d62056fb0efbe999eb6b6e14927613e02ba8b8fb046e',
|
||||||
|
'b3182e289ae34ddf2be643ab79c244301605fa0f1eaae6d10fb929600af84df0',
|
||||||
|
'b4d5c920415ed0cc4f5dbc7f542636762e80da6625f33f2b6ad6db68bdbab29a',
|
||||||
|
'b5ba8dd7f89564c2889d3d6453c84998c77824919b64ea0835aa62986591be50',
|
||||||
|
'b89bcbb8acd474c1bea7dad65037f48dcecc9dfaa0612c3c2445956419df32fe',
|
||||||
|
'c0ed205346bbbde06eb560f5cee02a3634e2474a7e76cf8fbef563bb117dd0e3',
|
||||||
|
'c173f0626456ca854ff2a7f0b133a7cf4d0211e552f24b3e33ade8c59f0a424c',
|
||||||
|
'c4387d45364a313fbfe79812b35b815d42852ab03b06f11589638021c8f2cb44',
|
||||||
|
'c601234e2b9325dc92e3eabac19600b0b49947d4d04d8c99d32127493ea028f8',
|
||||||
|
'c63d68c648a18b77641c427a669d61c9768a55f4fcd0322eac96c57700299cf1',
|
||||||
|
'c8fddc75cb1bdbb58c07b4ea847287f626659dd66bc10a26add9b575b3a0a38d',
|
||||||
|
'cdee9f3305572a677e1a6c82dc1e02a35b11cae6a684338c9f37fe1ac8daec23',
|
||||||
|
'ced43902ab5fb57b442322dc0e172a4fb55f7178b808f94e780a6fd6cc6bd818',
|
||||||
|
'd31ec39285b7a5319d0157db420ed87c743e333bbc77f8771f70464f436a6049',
|
||||||
|
'd34b255b2fe7d1a09656cbab6409f73c796ec7d66af73653ecc39af978297310',
|
||||||
|
'd6a18443d348db994f934ccd8e635d833a27ac1e56f8afaf7c97cb4f43eab68b',
|
||||||
|
'db15c0062b520f318a19dacfecd64f9e7a3fbe609fd586796f20ae028e8e3058',
|
||||||
|
'db1d13ec42a2cba3673ba67af2def812e9c35566617576d95b4d6face3ef0ae8',
|
||||||
|
'dd3eeb779bee07f9efdac382408b28d142fa842c78e8bc0e33348d57b92f0583',
|
||||||
|
'de8f05074ec0318e7e7e8d3190dae8b00894f0e8dddfd3913d01759b4f79b05d',
|
||||||
|
'e42f24bd4d37f4aa2e56b979d83d1e65219fe0e9e3a382a1b3cb66c93955de75',
|
||||||
|
'e6e136c86154f32c3e49f47cfc6b338ff2dc61ce14fc7589b3b56a1450132701',
|
||||||
|
'e7b932ae7e9bdc701d771d6f39e8a653449eea43bdb47bd91022950d9179d87e',
|
||||||
|
'e849c7176c93df65f64b616982366e5663117812b6fa2bc0c8fa8aeaee4181cc',
|
||||||
|
'ea08c8d45d52ca593de524f0513ca6418da9859f7b08ef13ff9dd7bf612d6a37',
|
||||||
|
'ea87f462deefffbd7775aa2a4b7e0fcb91c22eee6df69ed90100ccc73b311476',
|
||||||
|
'ef551284715232de92e246c323329362b132493bb16b589e4775520beb871a56',
|
||||||
|
'f034f642ca1d9e88e9efeafcb15c7c937aa19e04b080f27335e1da70d1ca1201',
|
||||||
|
'f2bbe04c5dc70d763e89c5a0527048cd9ecd39eb621e2072ff9a5f8432571aa0',
|
||||||
|
'f30e8f61011d65873ccb81b40fa6219749b994f01fa24d0201d521c2435603ca',
|
||||||
|
'f5293d47ed38d4c31b2d42dee3b5b3ace97ca26ca2ac0365e3622ee802131fbb',
|
||||||
|
'fa00bec73dd99795df1162c789987004c26cbf90af4db442f66220de41354ac9',
|
||||||
|
'fcd76cca2347e5cd5b39347f51cf43654b69a2bfc9073670a6be47d8701e6e0e',
|
||||||
|
'b0fcce78c1664e293544c143e3d2689f723f5b6e6317107e163d22ba8069794a',
|
||||||
|
'c56217b7a828c7341c0ae7a590d8790d4def536652e60ae5b8bdfa26978fe09c',
|
||||||
|
'e47c5cd2dc8babb4e53f8a4983920275ef6ffaacb089e87a2c1fbe5a585f05ed',
|
||||||
|
'39736588b94a4ce767f731cad53f4cbe44137e321eadcaef8ce79a229bbca989',
|
||||||
|
'ea12705de7c48f6fcce2cb8dbc542e0fc38ac38e08880dd04a02ef67c93ae135',
|
||||||
|
'a6aca1ec9809cc5b4821ff9d29c5ebe651960b91b1f19cc89b55ef87818a9509',
|
||||||
|
'02a95f43431019e9dc225f05f419330190deb4a3f1869caac9842b403dcbee77',
|
||||||
|
'8928c59398b0f171c0f96fdae6ab8dd0f48ee06d174da10c404ac00143c7a749',
|
||||||
|
'6c0702e86e0238abdb974f44a30e1a75f627cc50b4e7ce6bb1c0923b98d0e81c',
|
||||||
|
'f806c390ef8d1165ef61bc77ef66de4b245a31f5bebf1029038ff31c50a63f59',
|
||||||
|
'cef8710dff5e87a2830daa85e884f082033de58ed395a10f7e7c7334b5bfbe58',
|
||||||
|
'5be28fcf7e31ba64fb2459e278ef032e3a09b61851952d6e85f746150fcadff1',
|
||||||
|
'29ec436daffa63d25f502cc9952277581876f6893feb783a0444a6f5e73aa422',
|
||||||
|
'36ce75edea806f0985145683294e54dbdff02fc821870cf5067a308d1504be3a',
|
||||||
|
'a4e9af01416e3a029b5d35e5b119de00cfe156c5cf95fc823cf6d05e3c1a8237',
|
||||||
|
'3472e4f16c570e0dd388aaaa4a64a34a4b939f1ca770996b5be0037c1aded9c1',
|
||||||
|
]);
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import {X509Certificate} from 'node:crypto';
|
||||||
|
import fs from 'node:fs';
|
||||||
|
import os from 'node:os';
|
||||||
|
import path from 'node:path';
|
||||||
|
import {describe, test} from 'node:test';
|
||||||
|
import {fileURLToPath} from 'node:url';
|
||||||
|
import {installElectronStub} from './LocalAppTestSupport.test.mjs';
|
||||||
|
|
||||||
|
installElectronStub();
|
||||||
|
|
||||||
|
const {buildDesktopTrustAnchors, verifyAgainstDesktopSystemTrust} = await import('./DesktopSystemTrustVerifier.ts');
|
||||||
|
const {resolveDesktopLocallyAddedCertificates} = await import('./DesktopTrustedCertificates.ts');
|
||||||
|
|
||||||
|
const FIXTURES = path.join(path.dirname(fileURLToPath(import.meta.url)), 'fixtures', 'desktop-trust');
|
||||||
|
const read = (name) => fs.readFileSync(path.join(FIXTURES, `${name}.pem`), 'utf8');
|
||||||
|
const AUTHORITY_INVALID = -202;
|
||||||
|
const DEFER = -3;
|
||||||
|
const ACCEPT = 0;
|
||||||
|
|
||||||
|
function chain(names) {
|
||||||
|
let certificate;
|
||||||
|
for (const name of [...names].reverse()) certificate = {data: read(name), issuerCert: certificate};
|
||||||
|
return certificate;
|
||||||
|
}
|
||||||
|
|
||||||
|
function verify(names, {hostname = 'host.example', errorCode = AUTHORITY_INVALID, anchors = ['root']} = {}) {
|
||||||
|
const store = buildDesktopTrustAnchors(anchors.map(read));
|
||||||
|
return verifyAgainstDesktopSystemTrust({hostname, certificate: chain(names), errorCode}, () => store);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('desktop system trust verifier', () => {
|
||||||
|
test('accepts a chain that ends at a locally added CA', () => {
|
||||||
|
assert.equal(verify(['leaf', 'int']), ACCEPT);
|
||||||
|
assert.equal(verify(['leaf', 'int'], {hostname: 'HOST.example.'}), ACCEPT);
|
||||||
|
assert.equal(verify(['leaf', 'int'], {hostname: '127.0.0.1'}), ACCEPT);
|
||||||
|
assert.equal(verify(['leaf', 'int'], {hostname: '[::1]'}), ACCEPT);
|
||||||
|
assert.equal(verify(['ec_leaf']), ACCEPT);
|
||||||
|
assert.equal(verify(['wc_leaf'], {hostname: 'a.lan.home.example'}), ACCEPT);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('defers to Chromium for other errors, anchors and hosts', () => {
|
||||||
|
assert.equal(verify(['leaf', 'int'], {errorCode: -201}), DEFER);
|
||||||
|
assert.equal(verify(['leaf', 'int'], {anchors: ['pl_int']}), DEFER);
|
||||||
|
assert.equal(verify(['leaf', 'int'], {hostname: 'other.example'}), DEFER);
|
||||||
|
assert.equal(verify(['wc_leaf'], {hostname: 'a.b.lan.home.example'}), DEFER);
|
||||||
|
assert.equal(verify(['wc_leaf'], {hostname: 'a.home.example'}), DEFER);
|
||||||
|
assert.equal(verify(['wc_leaf'], {hostname: 'victim.co.uk'}), DEFER);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('defers on constrained, weak or unknown certificates in the path', () => {
|
||||||
|
assert.equal(verify(['nc_leaf', 'nc_int']), DEFER);
|
||||||
|
assert.equal(verify(['nc_leaf'], {anchors: ['nc_int']}), DEFER);
|
||||||
|
assert.equal(verify(['eku_leaf', 'eku_int']), DEFER);
|
||||||
|
assert.equal(verify(['pl_leaf', 'pl_int2', 'pl_int']), DEFER);
|
||||||
|
assert.equal(verify(['crit_leaf']), DEFER);
|
||||||
|
assert.equal(verify(['sha1_leaf']), DEFER);
|
||||||
|
assert.equal(verify(['weak_leaf']), DEFER);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('rejects non-DER booleans and Chromium blocklisted keys', () => {
|
||||||
|
assert.equal(verify(['bool_ff_leaf']), ACCEPT);
|
||||||
|
assert.equal(verify(['bool_01_leaf']), DEFER);
|
||||||
|
assert.equal(buildDesktopTrustAnchors([read('kz_root')]).size, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('anchors only on admin added CAs that the distro bundle still trusts', () => {
|
||||||
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'desktop-trust-'));
|
||||||
|
const write = (file, content) => {
|
||||||
|
fs.mkdirSync(path.dirname(path.join(root, file)), {recursive: true});
|
||||||
|
fs.writeFileSync(path.join(root, file), content);
|
||||||
|
};
|
||||||
|
const der = (name) => new X509Certificate(read(name)).raw;
|
||||||
|
try {
|
||||||
|
assert.deepEqual(resolveDesktopLocallyAddedCertificates(root), []);
|
||||||
|
write('etc/ssl/certs/ca-certificates.crt', [read('root'), read('int'), read('kz_root')].join('\n'));
|
||||||
|
write('usr/local/share/ca-certificates/site/root.crt', read('root'));
|
||||||
|
write('usr/local/share/ca-certificates/int.der', der('int'));
|
||||||
|
write('usr/local/share/ca-certificates/deselected.crt', read('pl_int'));
|
||||||
|
write('cert.pem', read('pl_int'));
|
||||||
|
process.env.SSL_CERT_FILE = path.join(root, 'cert.pem');
|
||||||
|
const added = resolveDesktopLocallyAddedCertificates(root).map((pem) => new X509Certificate(pem).subject);
|
||||||
|
assert.deepEqual(added.sort(), ['CN=Trust Test Int', 'CN=Trust Test Root']);
|
||||||
|
} finally {
|
||||||
|
delete process.env.SSL_CERT_FILE;
|
||||||
|
fs.rmSync(root, {recursive: true, force: true});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,448 @@
|
|||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
import {createHash, X509Certificate} from 'node:crypto';
|
||||||
|
import net from 'node:net';
|
||||||
|
import {createChildLogger} from '@electron/common/Logger';
|
||||||
|
import {CHROMIUM_SPKI_BLOCKLIST, CHROMIUM_SPKI_BLOCKLIST_SOURCE} from '@electron/main/DesktopChromiumSPKIBlocklist';
|
||||||
|
import {resolveDesktopLocallyAddedCertificates} from '@electron/main/DesktopTrustedCertificates';
|
||||||
|
import type {Certificate, Session} from 'electron';
|
||||||
|
|
||||||
|
const logger = createChildLogger('DesktopSystemTrustVerifier');
|
||||||
|
|
||||||
|
const CHROMIUM_DEFAULT_RESULT = -3;
|
||||||
|
const CHROMIUM_ACCEPT = 0;
|
||||||
|
const CHROMIUM_CERT_AUTHORITY_INVALID = -202;
|
||||||
|
const MAX_CHAIN_LENGTH = 6;
|
||||||
|
const MAX_SIGNATURE_CHECKS = 25;
|
||||||
|
const MIN_RSA_BITS = 2048;
|
||||||
|
const MAX_RSA_BITS = 8192;
|
||||||
|
const MIN_WILDCARD_BASE_LABELS = 3;
|
||||||
|
const DER_TRUE = 0xff;
|
||||||
|
|
||||||
|
const OID = {
|
||||||
|
basicConstraints: '2.5.29.19',
|
||||||
|
keyUsage: '2.5.29.15',
|
||||||
|
subjectAltName: '2.5.29.17',
|
||||||
|
extendedKeyUsage: '2.5.29.37',
|
||||||
|
nameConstraints: '2.5.29.30',
|
||||||
|
policyConstraints: '2.5.29.36',
|
||||||
|
inhibitAnyPolicy: '2.5.29.54',
|
||||||
|
serverAuth: '1.3.6.1.5.5.7.3.1',
|
||||||
|
anyExtendedKeyUsage: '2.5.29.37.0',
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
const ALLOWED_CRITICAL_EXTENSIONS: ReadonlySet<string> = new Set([
|
||||||
|
OID.basicConstraints,
|
||||||
|
OID.keyUsage,
|
||||||
|
OID.subjectAltName,
|
||||||
|
OID.extendedKeyUsage,
|
||||||
|
]);
|
||||||
|
const FORBIDDEN_EXTENSIONS: ReadonlySet<string> = new Set([
|
||||||
|
OID.nameConstraints,
|
||||||
|
OID.policyConstraints,
|
||||||
|
OID.inhibitAnyPolicy,
|
||||||
|
]);
|
||||||
|
const ALLOWED_SIGNATURE_ALGORITHMS: ReadonlySet<string> = new Set([
|
||||||
|
'1.2.840.113549.1.1.11',
|
||||||
|
'1.2.840.113549.1.1.12',
|
||||||
|
'1.2.840.113549.1.1.13',
|
||||||
|
'1.2.840.10045.4.3.2',
|
||||||
|
'1.2.840.10045.4.3.3',
|
||||||
|
'1.2.840.10045.4.3.4',
|
||||||
|
'1.3.101.112',
|
||||||
|
]);
|
||||||
|
const ALLOWED_EC_CURVES: ReadonlySet<string> = new Set(['prime256v1', 'secp384r1']);
|
||||||
|
|
||||||
|
const KEY_USAGE_DIGITAL_SIGNATURE = 0;
|
||||||
|
const KEY_USAGE_KEY_ENCIPHERMENT = 2;
|
||||||
|
const KEY_USAGE_KEY_CERT_SIGN = 5;
|
||||||
|
|
||||||
|
const TAG_BOOLEAN = 0x01;
|
||||||
|
const TAG_INTEGER = 0x02;
|
||||||
|
const TAG_BIT_STRING = 0x03;
|
||||||
|
const TAG_OCTET_STRING = 0x04;
|
||||||
|
const TAG_OID = 0x06;
|
||||||
|
const TAG_SEQUENCE = 0x30;
|
||||||
|
const TAG_VERSION = 0xa0;
|
||||||
|
const TAG_EXTENSIONS = 0xa3;
|
||||||
|
const TAG_SAN_DNS = 0x82;
|
||||||
|
const TAG_SAN_IP = 0x87;
|
||||||
|
|
||||||
|
class MalformedCertificateError extends Error {
|
||||||
|
constructor() {
|
||||||
|
super('Malformed certificate DER');
|
||||||
|
this.name = 'MalformedCertificateError';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DerNode {
|
||||||
|
readonly tag: number;
|
||||||
|
readonly content: Buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Extension {
|
||||||
|
readonly critical: boolean;
|
||||||
|
readonly value: Buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ParsedCertificate {
|
||||||
|
readonly x509: X509Certificate;
|
||||||
|
readonly signatureAlgorithm: string;
|
||||||
|
readonly extensions: ReadonlyMap<string, Extension>;
|
||||||
|
readonly isCA: boolean;
|
||||||
|
readonly pathLength: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DesktopSystemTrustRequest {
|
||||||
|
readonly hostname: string;
|
||||||
|
readonly certificate: Certificate;
|
||||||
|
readonly errorCode: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DesktopTrustAnchors = ReadonlyMap<string, ReadonlyArray<ParsedCertificate>>;
|
||||||
|
|
||||||
|
function readNodes(buffer: Buffer): Array<DerNode> {
|
||||||
|
const nodes: Array<DerNode> = [];
|
||||||
|
let offset = 0;
|
||||||
|
while (offset < buffer.length) {
|
||||||
|
if (offset + 2 > buffer.length) throw new MalformedCertificateError();
|
||||||
|
const tag = buffer[offset];
|
||||||
|
if ((tag & 0x1f) === 0x1f) throw new MalformedCertificateError();
|
||||||
|
let length = buffer[offset + 1];
|
||||||
|
let cursor = offset + 2;
|
||||||
|
if (length & 0x80) {
|
||||||
|
const size = length & 0x7f;
|
||||||
|
if (size === 0 || size > 4 || cursor + size > buffer.length) throw new MalformedCertificateError();
|
||||||
|
length = 0;
|
||||||
|
for (let index = 0; index < size; index++) length = length * 256 + buffer[cursor + index];
|
||||||
|
cursor += size;
|
||||||
|
}
|
||||||
|
if (cursor + length > buffer.length) throw new MalformedCertificateError();
|
||||||
|
nodes.push({tag, content: buffer.subarray(cursor, cursor + length)});
|
||||||
|
offset = cursor + length;
|
||||||
|
}
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
function expect(node: DerNode | undefined, tag: number): DerNode {
|
||||||
|
if (node == null || node.tag !== tag) throw new MalformedCertificateError();
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
function only(buffer: Buffer, tag: number): DerNode {
|
||||||
|
const nodes = readNodes(buffer);
|
||||||
|
if (nodes.length !== 1) throw new MalformedCertificateError();
|
||||||
|
return expect(nodes[0], tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
function readDerTrue(node: DerNode): true {
|
||||||
|
if (node.content.length !== 1 || node.content[0] !== DER_TRUE) throw new MalformedCertificateError();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeOid(content: Buffer): string {
|
||||||
|
if (content.length === 0) throw new MalformedCertificateError();
|
||||||
|
const parts: Array<number> = [];
|
||||||
|
let value = 0;
|
||||||
|
for (const byte of content) {
|
||||||
|
value = value * 128 + (byte & 0x7f);
|
||||||
|
if (value > Number.MAX_SAFE_INTEGER / 128) throw new MalformedCertificateError();
|
||||||
|
if ((byte & 0x80) === 0) {
|
||||||
|
parts.push(value);
|
||||||
|
value = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((content[content.length - 1] & 0x80) !== 0) throw new MalformedCertificateError();
|
||||||
|
const first = parts.shift() ?? 0;
|
||||||
|
const head = first < 80 ? [Math.floor(first / 40), first % 40] : [2, first - 80];
|
||||||
|
return [...head, ...parts].join('.');
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseExtensions(tbs: ReadonlyArray<DerNode>): Map<string, Extension> {
|
||||||
|
const extensions = new Map<string, Extension>();
|
||||||
|
const wrapper = tbs.find((node) => node.tag === TAG_EXTENSIONS);
|
||||||
|
if (wrapper == null) return extensions;
|
||||||
|
for (const entry of readNodes(only(wrapper.content, TAG_SEQUENCE).content)) {
|
||||||
|
const fields = readNodes(expect(entry, TAG_SEQUENCE).content);
|
||||||
|
const oid = decodeOid(expect(fields[0], TAG_OID).content);
|
||||||
|
const hasCritical = fields[1]?.tag === TAG_BOOLEAN;
|
||||||
|
const critical = hasCritical && readDerTrue(fields[1]);
|
||||||
|
const value = expect(fields[hasCritical ? 2 : 1], TAG_OCTET_STRING).content;
|
||||||
|
if (fields.length !== (hasCritical ? 3 : 2) || extensions.has(oid)) throw new MalformedCertificateError();
|
||||||
|
extensions.set(oid, {critical, value});
|
||||||
|
}
|
||||||
|
return extensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseBasicConstraints(extension: Extension | undefined): {isCA: boolean; pathLength: number | null} {
|
||||||
|
if (extension == null) return {isCA: false, pathLength: null};
|
||||||
|
const fields = readNodes(only(extension.value, TAG_SEQUENCE).content);
|
||||||
|
let index = 0;
|
||||||
|
let isCA = false;
|
||||||
|
if (fields[index]?.tag === TAG_BOOLEAN) {
|
||||||
|
isCA = readDerTrue(fields[index]);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
let pathLength: number | null = null;
|
||||||
|
if (fields[index]?.tag === TAG_INTEGER) {
|
||||||
|
const content = fields[index].content;
|
||||||
|
if (content.length === 0 || content.length > 2 || (content[0] & 0x80) !== 0) throw new MalformedCertificateError();
|
||||||
|
pathLength = content.readUIntBE(0, content.length);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
if (index !== fields.length) throw new MalformedCertificateError();
|
||||||
|
return {isCA, pathLength};
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseCertificate(x509: X509Certificate): ParsedCertificate {
|
||||||
|
const parts = readNodes(only(x509.raw, TAG_SEQUENCE).content);
|
||||||
|
if (parts.length !== 3) throw new MalformedCertificateError();
|
||||||
|
const tbs = readNodes(expect(parts[0], TAG_SEQUENCE).content);
|
||||||
|
const algorithm = readNodes(expect(parts[1], TAG_SEQUENCE).content);
|
||||||
|
const signatureAlgorithm = decodeOid(expect(algorithm[0], TAG_OID).content);
|
||||||
|
if (tbs[0]?.tag !== TAG_VERSION && tbs.some((node) => node.tag === TAG_EXTENSIONS)) {
|
||||||
|
throw new MalformedCertificateError();
|
||||||
|
}
|
||||||
|
const extensions = parseExtensions(tbs);
|
||||||
|
return {x509, signatureAlgorithm, extensions, ...parseBasicConstraints(extensions.get(OID.basicConstraints))};
|
||||||
|
}
|
||||||
|
|
||||||
|
function keyUsageHas(certificate: ParsedCertificate, bit: number): boolean | null {
|
||||||
|
const extension = certificate.extensions.get(OID.keyUsage);
|
||||||
|
if (extension == null) return null;
|
||||||
|
const bits = only(extension.value, TAG_BIT_STRING).content;
|
||||||
|
const byte = bits[1 + (bit >> 3)];
|
||||||
|
return byte != null && (byte & (0x80 >> (bit & 7))) !== 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function extendedKeyUsages(certificate: ParsedCertificate): ReadonlyArray<string> | null {
|
||||||
|
const extension = certificate.extensions.get(OID.extendedKeyUsage);
|
||||||
|
if (extension == null) return null;
|
||||||
|
return readNodes(only(extension.value, TAG_SEQUENCE).content).map((node) => decodeOid(expect(node, TAG_OID).content));
|
||||||
|
}
|
||||||
|
|
||||||
|
function allowsServerAuth(certificate: ParsedCertificate): boolean {
|
||||||
|
const usages = extendedKeyUsages(certificate);
|
||||||
|
return usages == null || usages.includes(OID.serverAuth) || usages.includes(OID.anyExtendedKeyUsage);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasAcceptableKey(certificate: ParsedCertificate): boolean {
|
||||||
|
const key = certificate.x509.publicKey;
|
||||||
|
const details = key.asymmetricKeyDetails ?? {};
|
||||||
|
switch (key.asymmetricKeyType) {
|
||||||
|
case 'rsa': {
|
||||||
|
const bits = details.modulusLength ?? 0;
|
||||||
|
return bits >= MIN_RSA_BITS && bits <= MAX_RSA_BITS;
|
||||||
|
}
|
||||||
|
case 'ec':
|
||||||
|
return details.namedCurve != null && ALLOWED_EC_CURVES.has(details.namedCurve);
|
||||||
|
case 'ed25519':
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isBlocklisted(certificate: ParsedCertificate): boolean {
|
||||||
|
const spki = certificate.x509.publicKey.export({type: 'spki', format: 'der'});
|
||||||
|
return CHROMIUM_SPKI_BLOCKLIST.has(createHash('sha256').update(spki).digest('hex'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function isCurrentlyValid(certificate: ParsedCertificate, now: number): boolean {
|
||||||
|
return Date.parse(certificate.x509.validFrom) <= now && now <= Date.parse(certificate.x509.validTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
function passesCommonChecks(certificate: ParsedCertificate, now: number): boolean {
|
||||||
|
for (const [oid, extension] of certificate.extensions) {
|
||||||
|
if (FORBIDDEN_EXTENSIONS.has(oid)) return false;
|
||||||
|
if (extension.critical && !ALLOWED_CRITICAL_EXTENSIONS.has(oid)) return false;
|
||||||
|
}
|
||||||
|
return isCurrentlyValid(certificate, now) && hasAcceptableKey(certificate) && !isBlocklisted(certificate);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isUsableAuthority(certificate: ParsedCertificate, now: number): boolean {
|
||||||
|
return (
|
||||||
|
certificate.isCA &&
|
||||||
|
keyUsageHas(certificate, KEY_USAGE_KEY_CERT_SIGN) !== false &&
|
||||||
|
allowsServerAuth(certificate) &&
|
||||||
|
passesCommonChecks(certificate, now)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isUsableIntermediate(certificate: ParsedCertificate, now: number): boolean {
|
||||||
|
return ALLOWED_SIGNATURE_ALGORITHMS.has(certificate.signatureAlgorithm) && isUsableAuthority(certificate, now);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isUsableLeaf(certificate: ParsedCertificate, now: number): boolean {
|
||||||
|
if (certificate.isCA || !ALLOWED_SIGNATURE_ALGORITHMS.has(certificate.signatureAlgorithm)) return false;
|
||||||
|
const digitalSignature = keyUsageHas(certificate, KEY_USAGE_DIGITAL_SIGNATURE);
|
||||||
|
if (digitalSignature === false && keyUsageHas(certificate, KEY_USAGE_KEY_ENCIPHERMENT) === false) return false;
|
||||||
|
return allowsServerAuth(certificate) && passesCommonChecks(certificate, now);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeHost(hostname: string): string {
|
||||||
|
return hostname
|
||||||
|
.replace(/^\[(.*)\]$/u, '$1')
|
||||||
|
.replace(/\.$/u, '')
|
||||||
|
.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function ipBytes(host: string): Buffer | null {
|
||||||
|
if (net.isIPv4(host)) return Buffer.from(host.split('.').map(Number));
|
||||||
|
if (!net.isIPv6(host)) return null;
|
||||||
|
const [head = '', tail = ''] = host.split('::');
|
||||||
|
const words = (part: string) => (part === '' ? [] : part.split(':'));
|
||||||
|
const headWords = words(head);
|
||||||
|
const tailWords = words(tail);
|
||||||
|
const all = host.includes('::')
|
||||||
|
? [...headWords, ...Array(8 - headWords.length - tailWords.length).fill('0'), ...tailWords]
|
||||||
|
: headWords;
|
||||||
|
if (all.length !== 8) return null;
|
||||||
|
return Buffer.from(all.flatMap((word) => [parseInt(word, 16) >> 8, parseInt(word, 16) & 0xff]));
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchesDnsName(pattern: string, host: string): boolean {
|
||||||
|
const name = pattern.replace(/\.$/u, '').toLowerCase();
|
||||||
|
if (!name.includes('*')) return name === host;
|
||||||
|
if (!name.startsWith('*.') || name.indexOf('*', 1) !== -1) return false;
|
||||||
|
const base = name.slice(2);
|
||||||
|
if (base.split('.').length < MIN_WILDCARD_BASE_LABELS) return false;
|
||||||
|
const dot = host.indexOf('.');
|
||||||
|
return dot > 0 && host.slice(dot + 1) === base;
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchesHost(leaf: ParsedCertificate, hostname: string): boolean {
|
||||||
|
const extension = leaf.extensions.get(OID.subjectAltName);
|
||||||
|
if (extension == null || typeof hostname !== 'string') return false;
|
||||||
|
const host = normalizeHost(hostname);
|
||||||
|
const address = ipBytes(host);
|
||||||
|
for (const name of readNodes(only(extension.value, TAG_SEQUENCE).content)) {
|
||||||
|
if (address != null && name.tag === TAG_SAN_IP && name.content.equals(address)) return true;
|
||||||
|
if (address == null && name.tag === TAG_SAN_DNS && matchesDnsName(name.content.toString('latin1'), host)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PathSearch {
|
||||||
|
readonly intermediates: ReadonlyArray<ParsedCertificate>;
|
||||||
|
readonly anchors: DesktopTrustAnchors;
|
||||||
|
readonly now: number;
|
||||||
|
readonly signatures: Map<ParsedCertificate, Map<ParsedCertificate, boolean>>;
|
||||||
|
signatureChecks: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isIssuedBy(search: PathSearch, certificate: ParsedCertificate, issuer: ParsedCertificate): boolean {
|
||||||
|
if (!certificate.x509.checkIssued(issuer.x509)) return false;
|
||||||
|
let byIssuer = search.signatures.get(certificate);
|
||||||
|
if (byIssuer == null) {
|
||||||
|
byIssuer = new Map();
|
||||||
|
search.signatures.set(certificate, byIssuer);
|
||||||
|
}
|
||||||
|
const cached = byIssuer.get(issuer);
|
||||||
|
if (cached != null) return cached;
|
||||||
|
if (search.signatureChecks >= MAX_SIGNATURE_CHECKS) return false;
|
||||||
|
search.signatureChecks++;
|
||||||
|
const verified = certificate.x509.verify(issuer.x509.publicKey);
|
||||||
|
byIssuer.set(issuer, verified);
|
||||||
|
return verified;
|
||||||
|
}
|
||||||
|
|
||||||
|
function withinPathLength(authority: ParsedCertificate, intermediatesBelow: number): boolean {
|
||||||
|
return authority.pathLength == null || intermediatesBelow <= authority.pathLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildsPath(search: PathSearch, current: ParsedCertificate, path: ReadonlyArray<ParsedCertificate>): boolean {
|
||||||
|
const below = path.length - 1;
|
||||||
|
for (const anchor of search.anchors.get(current.x509.issuer) ?? []) {
|
||||||
|
if (
|
||||||
|
isCurrentlyValid(anchor, search.now) &&
|
||||||
|
withinPathLength(anchor, below) &&
|
||||||
|
isIssuedBy(search, current, anchor)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (path.length >= MAX_CHAIN_LENGTH - 1) return false;
|
||||||
|
for (const candidate of search.intermediates) {
|
||||||
|
if (path.includes(candidate) || !withinPathLength(candidate, below)) continue;
|
||||||
|
if (isIssuedBy(search, current, candidate) && buildsPath(search, candidate, [...path, candidate])) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function presentedChain(certificate: Certificate): Array<X509Certificate> {
|
||||||
|
const chain: Array<X509Certificate> = [];
|
||||||
|
let current: Certificate | undefined = certificate;
|
||||||
|
while (current != null) {
|
||||||
|
if (chain.length >= MAX_CHAIN_LENGTH) throw new MalformedCertificateError();
|
||||||
|
chain.push(new X509Certificate(current.data));
|
||||||
|
current = current.issuerCert;
|
||||||
|
}
|
||||||
|
return chain;
|
||||||
|
}
|
||||||
|
|
||||||
|
function chainsToDesktopTrustAnchor(
|
||||||
|
certificate: Certificate,
|
||||||
|
hostname: string,
|
||||||
|
anchors: DesktopTrustAnchors,
|
||||||
|
now: number,
|
||||||
|
): boolean {
|
||||||
|
const [leafX509, ...rest] = presentedChain(certificate);
|
||||||
|
if (leafX509 == null) return false;
|
||||||
|
const leaf = parseCertificate(leafX509);
|
||||||
|
if (!isUsableLeaf(leaf, now) || !matchesHost(leaf, hostname)) return false;
|
||||||
|
const intermediates = rest.map(parseCertificate).filter((candidate) => isUsableIntermediate(candidate, now));
|
||||||
|
return buildsPath({intermediates, anchors, now, signatures: new Map(), signatureChecks: 0}, leaf, [leaf]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildDesktopTrustAnchors(
|
||||||
|
certificates: ReadonlyArray<string>,
|
||||||
|
now: number = Date.now(),
|
||||||
|
): DesktopTrustAnchors {
|
||||||
|
const anchors = new Map<string, Array<ParsedCertificate>>();
|
||||||
|
for (const pem of certificates) {
|
||||||
|
let anchor: ParsedCertificate;
|
||||||
|
try {
|
||||||
|
anchor = parseCertificate(new X509Certificate(pem));
|
||||||
|
} catch {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!isUsableAuthority(anchor, now)) continue;
|
||||||
|
const bySubject = anchors.get(anchor.x509.subject);
|
||||||
|
if (bySubject == null) anchors.set(anchor.x509.subject, [anchor]);
|
||||||
|
else bySubject.push(anchor);
|
||||||
|
}
|
||||||
|
return anchors;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function verifyAgainstDesktopSystemTrust(
|
||||||
|
request: DesktopSystemTrustRequest,
|
||||||
|
loadAnchors: () => DesktopTrustAnchors,
|
||||||
|
): number {
|
||||||
|
if (request.errorCode !== CHROMIUM_CERT_AUTHORITY_INVALID) return CHROMIUM_DEFAULT_RESULT;
|
||||||
|
try {
|
||||||
|
const anchors = loadAnchors();
|
||||||
|
if (anchors.size > 0 && chainsToDesktopTrustAnchor(request.certificate, request.hostname, anchors, Date.now())) {
|
||||||
|
logger.debug('Accepted a certificate that chains to a locally added CA', {hostname: request.hostname});
|
||||||
|
return CHROMIUM_ACCEPT;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.warn('Could not check a certificate against locally added CAs', {hostname: request.hostname, error});
|
||||||
|
}
|
||||||
|
return CHROMIUM_DEFAULT_RESULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function installDesktopSystemTrustVerifier(target: Session): void {
|
||||||
|
if (process.platform !== 'linux') return;
|
||||||
|
const anchors = buildDesktopTrustAnchors(resolveDesktopLocallyAddedCertificates());
|
||||||
|
if (anchors.size === 0) return;
|
||||||
|
logger.info('Trusting locally added CAs for Chromium requests', {
|
||||||
|
count: anchors.size,
|
||||||
|
blocklist: CHROMIUM_SPKI_BLOCKLIST_SOURCE,
|
||||||
|
});
|
||||||
|
target.setCertificateVerifyProc((request, callback) => {
|
||||||
|
callback(verifyAgainstDesktopSystemTrust(request, () => anchors));
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
import {X509Certificate} from 'node:crypto';
|
||||||
|
import fs from 'node:fs';
|
||||||
|
import path from 'node:path';
|
||||||
import tls from 'node:tls';
|
import tls from 'node:tls';
|
||||||
import {createChildLogger} from '@electron/common/Logger';
|
import {createChildLogger} from '@electron/common/Logger';
|
||||||
|
|
||||||
@@ -25,3 +28,92 @@ export function resolveDesktopTrustedCertificates(
|
|||||||
for (const certificate of readStore(source, 'system')) merged.add(certificate);
|
for (const certificate of readStore(source, 'system')) merged.add(certificate);
|
||||||
return [...merged];
|
return [...merged];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface DistroTrustLayout {
|
||||||
|
readonly bundle: string;
|
||||||
|
readonly anchorDirectories: ReadonlyArray<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DISTRO_TRUST_LAYOUTS: ReadonlyArray<DistroTrustLayout> = Object.freeze([
|
||||||
|
{bundle: 'etc/ssl/certs/ca-certificates.crt', anchorDirectories: ['usr/local/share/ca-certificates']},
|
||||||
|
{
|
||||||
|
bundle: 'etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem',
|
||||||
|
anchorDirectories: ['etc/pki/ca-trust/source/anchors', 'usr/share/pki/ca-trust-source/anchors'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bundle: 'etc/ca-certificates/extracted/tls-ca-bundle.pem',
|
||||||
|
anchorDirectories: ['etc/ca-certificates/trust-source/anchors', 'usr/share/ca-certificates/trust-source/anchors'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bundle: 'var/lib/ca-certificates/ca-bundle.pem',
|
||||||
|
anchorDirectories: ['etc/pki/trust/anchors', 'usr/share/pki/trust/anchors'],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const PEM_BLOCK = /-----BEGIN CERTIFICATE-----[\s\S]+?-----END CERTIFICATE-----/gu;
|
||||||
|
const MAX_ANCHOR_DEPTH = 4;
|
||||||
|
const MAX_ANCHOR_FILES = 512;
|
||||||
|
const MAX_ANCHOR_FILE_BYTES = 1024 * 1024;
|
||||||
|
|
||||||
|
function pemBody(pem: string): string {
|
||||||
|
return pem.replace(/-----[^-]+-----|\s/gu, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
function readBundle(file: string): ReadonlySet<string> | null {
|
||||||
|
try {
|
||||||
|
return new Set((fs.readFileSync(file, 'utf8').match(PEM_BLOCK) ?? []).map(pemBody));
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function anchorFiles(directory: string, depth: number, files: Array<string>): void {
|
||||||
|
let entries: Array<fs.Dirent>;
|
||||||
|
try {
|
||||||
|
entries = fs.readdirSync(directory, {withFileTypes: true});
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const entry of entries) {
|
||||||
|
if (files.length >= MAX_ANCHOR_FILES) return;
|
||||||
|
const target = path.join(directory, entry.name);
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
if (depth < MAX_ANCHOR_DEPTH) anchorFiles(target, depth + 1, files);
|
||||||
|
} else if (entry.isFile() || entry.isSymbolicLink()) {
|
||||||
|
files.push(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function readAnchorFile(file: string): ReadonlyArray<X509Certificate> {
|
||||||
|
try {
|
||||||
|
const stat = fs.statSync(file);
|
||||||
|
if (!stat.isFile() || stat.size > MAX_ANCHOR_FILE_BYTES) return [];
|
||||||
|
const content = fs.readFileSync(file);
|
||||||
|
const blocks = content.toString('latin1').match(PEM_BLOCK);
|
||||||
|
if (blocks == null) return [new X509Certificate(content)];
|
||||||
|
return blocks.flatMap((block) => {
|
||||||
|
try {
|
||||||
|
return [new X509Certificate(block)];
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveDesktopLocallyAddedCertificates(root: string = '/'): ReadonlyArray<string> {
|
||||||
|
const added = new Map<string, string>();
|
||||||
|
for (const layout of DISTRO_TRUST_LAYOUTS) {
|
||||||
|
const bundle = readBundle(path.join(root, layout.bundle));
|
||||||
|
if (bundle == null) continue;
|
||||||
|
const files: Array<string> = [];
|
||||||
|
for (const directory of layout.anchorDirectories) anchorFiles(path.join(root, directory), 0, files);
|
||||||
|
for (const certificate of files.flatMap(readAnchorFile)) {
|
||||||
|
const body = certificate.raw.toString('base64');
|
||||||
|
if (bundle.has(body)) added.set(body, certificate.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [...added.values()];
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIC5TCCAc2gAwIBAgIBTjANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDDA9UcnVz
|
||||||
|
dCBUZXN0IFJvb3QwIhgPMjAyNTAxMDEwMDAwMDBaGA8yMTI1MDEwMTAwMDAwMFow
|
||||||
|
DDEKMAgGA1UEAwwBeDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALdv
|
||||||
|
Oze1slSycxDpCnpZYKClaHOXTRWnzAI8mHMhoiEpgjmXrbN1T75+aruMCQAr2VSB
|
||||||
|
1YOkxzf8Ntsb0ACfaSEJj2AwcCR6NfXoYbbSIE+V//1HkD/BbrOCUb81wubNFxjd
|
||||||
|
RZpJjhr6x6wb7DDM5rh8ly2t92N6r9Kh6il7Nssf27v2UZbb8XsjPgKxz2YmCtT8
|
||||||
|
Ry5ZiwGes9e4qEzV650Fl4xVjOiKKTJMy7ByNnm7guqL8ALhyHoIeRZUmTF85D4I
|
||||||
|
Pp90AkkMv9qjYllv5pBDHMjj68VldwhTYRTGAvhZjy8eIXA0OQXbpySPL5i8TZVM
|
||||||
|
O4jLoJFm3Kn5WIvdWO8CAwEAAaNAMD4wDgYDVR0PAQEBBAQDAgWgMBMGA1UdJQQM
|
||||||
|
MAoGCCsGAQUFBwMBMBcGA1UdEQQQMA6CDGhvc3QuZXhhbXBsZTANBgkqhkiG9w0B
|
||||||
|
AQsFAAOCAQEAftI9a2g+PexV+mSm/HHLxeGuWdK0IB5Dts/WhisGgAnxjabbZHJI
|
||||||
|
UZ6GoD5iQqX8RpZMqF2Cilq1oDfBUoWIujHG4JEzTj3WA0vQOE5wgcsmO4QcypNJ
|
||||||
|
cEn2KezBgDqzWbJ1hTRA3wwlzzOqJIHStt+4QjwetFvhM36R2o/6WzDlfyKmPSIi
|
||||||
|
1+eQYA7vl2DWr/j13+Oo3e4X/Uqr9KIVJPNYCdg73oRmi98gTi4aNvBcCb2Pz7ty
|
||||||
|
8lVgQ3iCysa2LYqk14pfGLm2Rs4QeYC0rRI0z3/Jbu5W81Y09FhW+5yyp9pJXmjO
|
||||||
|
ZxT7ZtgZsmmqp8iW7vpyQjQMhBA+HKtTBg==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIC5TCCAc2gAwIBAgIBTTANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDDA9UcnVz
|
||||||
|
dCBUZXN0IFJvb3QwIhgPMjAyNTAxMDEwMDAwMDBaGA8yMTI1MDEwMTAwMDAwMFow
|
||||||
|
DDEKMAgGA1UEAwwBeDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALdv
|
||||||
|
Oze1slSycxDpCnpZYKClaHOXTRWnzAI8mHMhoiEpgjmXrbN1T75+aruMCQAr2VSB
|
||||||
|
1YOkxzf8Ntsb0ACfaSEJj2AwcCR6NfXoYbbSIE+V//1HkD/BbrOCUb81wubNFxjd
|
||||||
|
RZpJjhr6x6wb7DDM5rh8ly2t92N6r9Kh6il7Nssf27v2UZbb8XsjPgKxz2YmCtT8
|
||||||
|
Ry5ZiwGes9e4qEzV650Fl4xVjOiKKTJMy7ByNnm7guqL8ALhyHoIeRZUmTF85D4I
|
||||||
|
Pp90AkkMv9qjYllv5pBDHMjj68VldwhTYRTGAvhZjy8eIXA0OQXbpySPL5i8TZVM
|
||||||
|
O4jLoJFm3Kn5WIvdWO8CAwEAAaNAMD4wDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQM
|
||||||
|
MAoGCCsGAQUFBwMBMBcGA1UdEQQQMA6CDGhvc3QuZXhhbXBsZTANBgkqhkiG9w0B
|
||||||
|
AQsFAAOCAQEAddtLsvQf8S/uuGyOMUgV8NKw4Ki1kX+BTr5xzsq1A01WgCfdYG5u
|
||||||
|
HL32V6uATwDzO3cH3piDoGLoXAF0sstnciBnfeibCgeBcOrj/8PTXGrRch5kkHnw
|
||||||
|
kK3OBZQSutT4BafIKoVIpiH95+3t/5sy2dWSkt1NGQN7noPBgddqSTmDiq4nxx+i
|
||||||
|
LQ+NhT5sX+AkWB6GZNyxnvEC1UtUJiY7k8DQIvV5vLPj4+oCa7XRiY/8rFzVoyBo
|
||||||
|
5Yq5FP5WgyGXKlWLhtwIeaD+7pAYjrUSnrTR9gWJsJ0l6/vCWhH3aT2vbPf9JUwS
|
||||||
|
3aHt4faDpfGbcvhlkXWyKHS7T3XYgnFf4A==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDWjCCAkKgAwIBAgIUA+GJ9S/l9MoO3gPga8JwUYNpaewwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwGjEYMBYGA1UEAwwPVHJ1c3QgVGVzdCBSb290MCAXDTI2MTAwODE3MTk0NVoY
|
||||||
|
DzIxMjYwOTE0MTcxOTQ1WjAMMQowCAYDVQQDDAF4MIIBIjANBgkqhkiG9w0BAQEF
|
||||||
|
AAOCAQ8AMIIBCgKCAQEAvD4+ud9Fp9RwYMtvhL366FKGNhEL6Y6oTouFjU97eQ4a
|
||||||
|
jTBIgizBsc2CwOoFyNAIK5UDRw68Kvs3m417L07BiDoTh4Y8J/62CKAGsJ5S2KAw
|
||||||
|
xgZh3BIyvs0gLGa5CAy0FqZ5tzCe546XHZdeGg4ETW3zEQmkB1Zq1ZwtCPX86pr4
|
||||||
|
N2MrKthotsaRug7ZQ5I8KC0XI819zdA2Bi6LvXIUCilDaWfZb9oeRUsrNCBzTvX4
|
||||||
|
/uL2sMJDwuiP1Dfk7heqnjsvP2s9N+0k6uw3thIBisTy4F2yhCpfCi9WT+OJZoEH
|
||||||
|
UjLgOAR0H2fhAVPBR9YTPtVwy7di0PMWsYdfYGvB4QIDAQABo4GjMIGgMAwGA1Ud
|
||||||
|
EwEB/wQCMAAwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMB8G
|
||||||
|
A1UdIwQYMBaAFDl9W8k1XKQCubIn46G/oYwjeDkqMBcGA1UdEQQQMA6CDGhvc3Qu
|
||||||
|
ZXhhbXBsZTASBgkrBgEEAYaNHwEBAf8EAgUAMB0GA1UdDgQWBBQmoqL8NAcX6wuB
|
||||||
|
1XmVPq0bFnxPKDANBgkqhkiG9w0BAQsFAAOCAQEAYZQW4q0zeprbMilnHRk6C6Td
|
||||||
|
sXOaOHhB5DiRZW1wjhe3LO1zPLe/nckzqFG+g+jTFa7nLuC6APRlj1yk0pCoyWiD
|
||||||
|
zkHtdPDy1VdkkIOMEcPdMVPOgEPcIZYFZY77sMz4Ac8d6qRlAcqhJDKwapaQYGZV
|
||||||
|
ddy1pwPNZxk3EL0DcXYRThD/VOk3FuxZRZseuFNUkdyQ8a14bv+2mrHCFHcYxH26
|
||||||
|
Q73GvjMsyuL2oncG/ZhFza2kXoOUzi+ZHWh/KIDtWGruXLeFYDvEssaUUVykP2mV
|
||||||
|
0hy/XEGdOZmUP88GJ4N4CYu1SSn1shGiho42KLrXwpnDqOp43+bAUIOJAYnV1A==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICezCCAWOgAwIBAgIUA+GJ9S/l9MoO3gPga8JwUYNpaecwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwGjEYMBYGA1UEAwwPVHJ1c3QgVGVzdCBSb290MCAXDTI2MTAwODE3MTk0NFoY
|
||||||
|
DzIxMjYwOTE0MTcxOTQ0WjAMMQowCAYDVQQDDAF4MFkwEwYHKoZIzj0CAQYIKoZI
|
||||||
|
zj0DAQcDQgAEHHjSNNp5dsZfAnkKCGhzX70d/Ulaz8UFm9caIp6vOi2y1EXi10dZ
|
||||||
|
VAEgXal5HYc27/wbIFqLztnfofpu+0SlEqOBjzCBjDAMBgNVHRMBAf8EAjAAMA4G
|
||||||
|
A1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAfBgNVHSMEGDAWgBQ5
|
||||||
|
fVvJNVykArmyJ+Ohv6GMI3g5KjAXBgNVHREEEDAOggxob3N0LmV4YW1wbGUwHQYD
|
||||||
|
VR0OBBYEFNjhzyL6G+did2jKx0TJnTj2NhWHMA0GCSqGSIb3DQEBCwUAA4IBAQCs
|
||||||
|
ITZEqDiKXMtJvSrnfJ6ZGwuQBy/AU3tbw/DlCvTr/UMfcZk8qJ92otWf3MRgKOU7
|
||||||
|
XBgvCdruxCcG0ST3GqLq9PmGVt+fMwsx5FGF/qzWlDK8ZkFi0Adzsptw732v3/0H
|
||||||
|
BR8rh+59/NUmyLnag6Xw+nOY0boCVJ87CtNgBNsVmUL65YmVgCHEopen7Fv1q5ms
|
||||||
|
uGgi+HtWxfGnSiz+4Upw6RdcNmedH+F5M8wzZ4q4Iv4Wmupz3iaLdwGcucpuuC1R
|
||||||
|
6HIrDOEk+TOBofytCEd+iDorjjIXxNsgBDQf/gjKCvtHh7OVX0MFgQysgPNyIDC6
|
||||||
|
9mhFYM4YwMfhsMauBm5x
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDNDCCAhygAwIBAgIUA+GJ9S/l9MoO3gPga8JwUYNpaeowDQYJKoZIhvcNAQEL
|
||||||
|
BQAwGjEYMBYGA1UEAwwPVHJ1c3QgVGVzdCBSb290MCAXDTI2MTAwODE3MTk0NFoY
|
||||||
|
DzIxMjYwOTE0MTcxOTQ0WjASMRAwDgYDVQQDDAdFS1UgSW50MIIBIjANBgkqhkiG
|
||||||
|
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4v27QD9YFXG8+oPhwytCyErQCaV2PYeHGVm/
|
||||||
|
l0D0zc+9EHQfI6UbKC/1KjRXgMjmsFNGpGEAj2xVwXMsN04QmsxBhSrrOqrH36Fw
|
||||||
|
adSj5ewBaKf5/jaFOkJ8O1t4NOl4Ki0Fle4Op6r6IJZwzGpy4qNqlYbgRoPj8H7J
|
||||||
|
R9BufEtoC18jXcQNlwQP/4go7sq4YwtbFjOJ9mK/mlaAeD9zCb3LApLcYyQyqQaQ
|
||||||
|
bFEOMifJhCNE6WxbrTXH/+nTEM7nmPaGFqzovAf+0PBNjTkYSd+NqZJDD/fvU3XF
|
||||||
|
VMiqlAWj8R/UP03KKoTemqey9rXxbocxLTh0wJr/gPjOt7/+VQIDAQABo3gwdjAP
|
||||||
|
BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUMG5Sf79f
|
||||||
|
OgByO3UsgJsjlV8lvfEwHwYDVR0jBBgwFoAUOX1byTVcpAK5sifjob+hjCN4OSow
|
||||||
|
EwYDVR0lBAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEBAFprsUH/ZoMC
|
||||||
|
QgPZUnW33Tc5tnsEMBgREiqU5LDKdXAy9Qko1b/C2JaDIefYntBcu7eIlLVAfhSs
|
||||||
|
cBk+XhgditEjAG5yYjV/NPZRh/+L4OjVcVmFRtCtQ+z+DGwVWGn3PzbUL228izFK
|
||||||
|
djJOitXUPFGu8U1sbA/zv6Z+DpngnLkRWFwJz8cl84beyCnaExXh2MIg3AleDNdf
|
||||||
|
FoVU0lylC47nx9FHqEthOtGqRn7BHi49htqcCXd4E4OE3c8CLKU0WTRP8ofjK0FW
|
||||||
|
IdwXVsxWSheDVWRa1Gs3OOsv2TPWRyaRhEQ9mcCws7nVMbhZ94HIC3Rixy3YcLPY
|
||||||
|
vQXMYpMWrgo=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDPjCCAiagAwIBAgIUOuSVRC3VFKpaTRwNlFx7hNY+hPUwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwEjEQMA4GA1UEAwwHRUtVIEludDAgFw0yNjEwMDgxNzE5NDRaGA8yMTI2MDkx
|
||||||
|
NDE3MTk0NFowDDEKMAgGA1UEAwwBeDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
|
||||||
|
AQoCggEBAMYnHmYegqC2h4F4iCFCMo/jGGtOLPmVj4QoX676VEq7Ilw1qMoLfKwe
|
||||||
|
neNYPt0odizU1wWGf0SuEZ3QrWT5kgh14yzu0AQPboYUpMeYwkIjSxclrMbKqN63
|
||||||
|
bVT8BVYYuAnOV+4wGKLtSjZS2c3QcJKUijp+C50jyYdJ3DHYuiOviiaCSsCL7jo5
|
||||||
|
W6I4q5GfyifGA+T089YnLtlQYljhsqz2CWRNsxObD0RcjiAls23ZUAARKVU5cZ/V
|
||||||
|
PO2H/zF7tSuRSA8nE3/HepSO5pOcAS0/Gz0AEqmr9FdGztixhJ55RLfMIAGDDM3G
|
||||||
|
DC1wzg/Q0iG53vuJpmIEVpfx3ED5i/sCAwEAAaOBjzCBjDAMBgNVHRMBAf8EAjAA
|
||||||
|
MA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAfBgNVHSMEGDAW
|
||||||
|
gBQwblJ/v186AHI7dSyAmyOVXyW98TAXBgNVHREEEDAOggxob3N0LmV4YW1wbGUw
|
||||||
|
HQYDVR0OBBYEFNtHkj6LRNuSCFCEDvWcb/vaxmOKMA0GCSqGSIb3DQEBCwUAA4IB
|
||||||
|
AQCymlwRyp0JOXJltxNG5qHLpes+juIN9p5COTs9FhvAkpC58W+w1ynkN23J1UVk
|
||||||
|
WA5G1t5BOO/eyU7lZkdabDA/Mb0hvxdWIG4a028EUkd8vgkJEeDjPbjSZDPaIdL8
|
||||||
|
RAq9lq88LcetWP9g8NOZRFBhDbigphqYmwGNzk/J1ZIYhOfsNr0SU5BU/xe4ogT1
|
||||||
|
WmcBkaPw9g+7yPsevNXNmaMPlcKRiEL9AJA4rMZSU8aLnZ4+WXRleQnhSzHdBWPx
|
||||||
|
Li2jb41I39ECmY7gXPCJqRAORcaov4AO8WZCNVKqRLd/uFmOddpBABlPN9RyiyIn
|
||||||
|
pivGrcARZfTLYxHrOpQu74gz
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDJjCCAg6gAwIBAgIUA+GJ9S/l9MoO3gPga8JwUYNpaeYwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwGjEYMBYGA1UEAwwPVHJ1c3QgVGVzdCBSb290MCAXDTI2MTAwODE3MTk0M1oY
|
||||||
|
DzIxMjYwOTE0MTcxOTQzWjAZMRcwFQYDVQQDDA5UcnVzdCBUZXN0IEludDCCASIw
|
||||||
|
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKTTaf/jUVe80O44xs2+jRQSnv7w
|
||||||
|
zKiGMUnDMTwLheS3NlOuXUJAPfggtOUmp8fWdLUi9tmvwO/jSjOZZLnQ2fz9bGiV
|
||||||
|
Oovs9y9TgywdxOH1nnCMQ+hKLw0cMdk8X2Pm8wGZdGEblEcPJBXFF09JX1t6y3h6
|
||||||
|
cHlV5tpxdAUjNNdxjREnXclixWUPBDF4IziRrg4fOi+aB5FFREhhKLGlvJJ0NNq5
|
||||||
|
t9N3quFHoQCAGvwrnQQXsey58zRF58yK1AS6VrNMvkYRhcs/N+5W8Cxb6hVhthhz
|
||||||
|
0n96GgJ1BcGwpSGPC/69WpZHQot9VrT6qUoKJHUg3fnTHyzodJcRkHyAsKUCAwEA
|
||||||
|
AaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
|
||||||
|
FGa9d7RPsqY3+fnUCK3+sbIHKdCZMB8GA1UdIwQYMBaAFDl9W8k1XKQCubIn46G/
|
||||||
|
oYwjeDkqMA0GCSqGSIb3DQEBCwUAA4IBAQDJsifCCoydUHayqGMitWtCnAhts+hz
|
||||||
|
bOtYafchsnsmgn+LyetPC5ghdocn7QBHFZqmwoSfmZG2xrS5YfwSNJH5a65meFF1
|
||||||
|
Ca0eqxo0KZcNt3YSMH5bEOf1aphw9ame/UqNB89ZjJjSoIF2/Us/Yr2uLO0LLBmK
|
||||||
|
01HF1JqWFIXUOZ7g0VPhR1ulV7apYFvgXUtj0A9PUWOcJb+lxrepU4uWbV4TN0BM
|
||||||
|
EveNKX91kIzujemL0L1LDKpqU76lUG9sPAVrareKBDsDP9h4xGOJLzsybK0tpFHS
|
||||||
|
5rXCepsRIh2h9liL4ofxyIrD3bMKlSd/mo5hC6EaaHCLh4XtRuw8Iw93
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIGFDCCA/ygAwIBAgIUKH3ODOPG96qjP/ll526pjIJKWdswDQYJKoZIhvcNAQEL
|
||||||
|
BQAwVjE4MDYGA1UEAxMvSW5mb3JtYXRpb24gU2VjdXJpdHkgQ2VydGlmaWNhdGlv
|
||||||
|
biBBdXRob3JpdHkgQ0ExDTALBgNVBAoTBElTQ0ExCzAJBgNVBAYTAktaMB4XDTIw
|
||||||
|
MDIyODA0MDgwM1oXDTQwMDIyODA0MDgwM1owVjE4MDYGA1UEAxMvSW5mb3JtYXRp
|
||||||
|
b24gU2VjdXJpdHkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgQ0ExDTALBgNVBAoT
|
||||||
|
BElTQ0ExCzAJBgNVBAYTAktaMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
|
||||||
|
AgEA2Q8hjYT89iYfD+gdxiaKw5NNRq0sfKDj1xAXbtmhQh+tA5DhnVPehqFybVFH
|
||||||
|
ZBsyMwmL9SA4Bp/2ytE7CmnDefqg9xfRuNX2p6RzUgrsarYaZgXgaPW+g/TZ+nXU
|
||||||
|
uGgYb1I01XOg5xhFr65cjIM5DX5L9tr90tzRE1afjeUyvT0AYkSodQzJmweQG1nz
|
||||||
|
WQ9INEf//smQf6Dvguwe6pCZye8RcwbdH8P+1U5uHtmIKGSWVRzX347M2TGREtOe
|
||||||
|
arAblsfmB75t/eIracWIP0+goQSf8O942GrhBpqlMHYhPYn1ALYpgJVTp/mlIYtl
|
||||||
|
GtDDEeu8LHbF5z0orEBLp+x5aAbqbwIUXdvIejehFS669Mxb2p5K9XDbFWJJ5osn
|
||||||
|
6pAKFdTx7oo0HvGQP6vVEdsHkzZMenhj8U76jDlJKLAZi2Rww3Usfy0obssPT1Iu
|
||||||
|
R8JLjqpVgwXwKMaeLsGf4GUkqBLNsj72fNK5NGCJWeRged0G+jqaP2/Lf2UCbMxV
|
||||||
|
pAmoAciNdVexY9ytH+wPXLLKbGPIKAKPqepF3vhX4yHoL2Q+gR9Hx194r6hRdfHV
|
||||||
|
AKknDoG6/MWWzaqEieec28oXCNZwXdkPWJyssa1E6W1fojL/xhdvmiHUFUeR3rgs
|
||||||
|
xiMOdxvhFusKbuHjYpGwb9/D6+D7hUQGlSZ/8UMW3hfWiJcCAwEAAaOB2TCB1jAP
|
||||||
|
BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUqH3ODOPG
|
||||||
|
96qjP/ll526pjIJKWdswgZMGA1UdIwSBizCBiIAUqH3ODOPG96qjP/ll526pjIJK
|
||||||
|
WduhWqRYMFYxODA2BgNVBAMTL0luZm9ybWF0aW9uIFNlY3VyaXR5IENlcnRpZmlj
|
||||||
|
YXRpb24gQXV0aG9yaXR5IENBMQ0wCwYDVQQKEwRJU0NBMQswCQYDVQQGEwJLWoIU
|
||||||
|
KH3ODOPG96qjP/ll526pjIJKWdswDQYJKoZIhvcNAQELBQADggIBAD3Qw2GXqOJ8
|
||||||
|
BUqdN382O6KwdDljJzVhgxkOzcC6avfisoZ+Vhj74dy7qoMmQ84M+yXnA7BCCzHr
|
||||||
|
wBYsDKUwLT/WiHKcjToFtsejMteofiU/M0/ljigoI4Fbcl5w0tl8C47wAm5R2qAJ
|
||||||
|
sU4re9npst1z+AX4Ll7BurgsBKtTvA3PtZtRlsPm3zd7xS2xCGRaybXdMkLYWDRZ
|
||||||
|
J6R+A/iK1NM7UzAeEYpCyhDZo/OCrFgNWDpqwVTiOe3CPqM3aEBPPbohTbjMV9Gj
|
||||||
|
L0g7m1j2BI+X3ByHvTEYqZia36HOgmy4jrOuMsWeSqXw/RjTINBWtOzQDnm7Enrq
|
||||||
|
RpjR1kpugkAzNvGFSEUvkj7moKo++ixH46iOjSNGexPx21ktQijUXAvQ9ETO9EsJ
|
||||||
|
jmUNOiTd+iRjUEnACaGn+od99CsgEXBDq9EtP65KedzXIy5MTu6fMULSSLaQdzLh
|
||||||
|
Vd827PEzgMvNCj45pqVisVJ6l+N73J7yLrtq6Ad6BQ1N+jC0MMiiYn2r7E5Gt54j
|
||||||
|
+GzQMZgHgdoHbk6tiUw3UXrM8CGzaHJhSu/g/oUkGU0EDKlduHigTNCuHLX9uuvw
|
||||||
|
gNglHhejbQE8ai7ApOwoEmZMXBH9B+oFkwU5CSN1AoNDiQIUlzqS2mv41GU7q2iX
|
||||||
|
k3zu7DCQingYbxGab/J8R/e9aTMNhD8W
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDXTCCAkWgAwIBAgIUEPlNJxZrwg60AMmYq4fl4iKEp6MwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwGTEXMBUGA1UEAwwOVHJ1c3QgVGVzdCBJbnQwIBcNMjYxMDA4MTcxOTQ0WhgP
|
||||||
|
MjEyNjA5MTQxNzE5NDRaMAwxCjAIBgNVBAMMAXgwggEiMA0GCSqGSIb3DQEBAQUA
|
||||||
|
A4IBDwAwggEKAoIBAQDh/WlixnDuMipvbyvaXShC9Oa6b8fG7focttANGZtwwCpX
|
||||||
|
+TkEO6NTRvlwOBCdj1zGZEPuEQDZtbVgyz0DIxCuDK8sdlY7UgZjUY9ifThKhAmA
|
||||||
|
ux7CC2UcDLnr7P16ixVd3z1ev14zWqkyl0wZPG6udBoIyLUo/DzLj8j/YQQC0+Zt
|
||||||
|
JxGrtY2mwYbwyj0OFafkVrWGLe8EJZV8IrV7N0+OGGUi9ZHuvzbtgP4fc8xJj7Md
|
||||||
|
zQtxa2vA+Uq02PHfR+iYyAFow1taltelKV+mbfVJypy6RgQEnyIlEPpACMXD4HoU
|
||||||
|
QLG4dZAca0KFzdgI1IsxTSeC5SJxKk0RYp3ElyfJAgMBAAGjgacwgaQwDAYDVR0T
|
||||||
|
AQH/BAIwADAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHwYD
|
||||||
|
VR0jBBgwFoAUZr13tE+ypjf5+dQIrf6xsgcp0JkwLwYDVR0RBCgwJoIMaG9zdC5l
|
||||||
|
eGFtcGxlhwR/AAABhxAAAAAAAAAAAAAAAAAAAAABMB0GA1UdDgQWBBRgGEvI6VZt
|
||||||
|
KCBl88e6Icmez0rXPjANBgkqhkiG9w0BAQsFAAOCAQEABG/ol4K9If/YAfPGGqfn
|
||||||
|
7FVzGQOjgviCaWpQEQueBAmSLDSjgCyN4pRoZuFwIjzc0m0UkL8fQdS2ypF9dtHq
|
||||||
|
dIFCZRlBugqpTwzLvuPwJk6pPcPkwqpBB3jIJo25PFo6LokH/sA9sNnndprLmlwA
|
||||||
|
6iBC8wh3Nn81ge9Go2tM/yueOHAlFkSIMUXlq2/qPkRPSk/I9S9K94ESML4mLVY3
|
||||||
|
SQ/ysv6G3Djjucey2Nasm5JJukzjgcUd047Yrnw88SDpO/jcmpoGwuCfmqMTr5gS
|
||||||
|
pBo8L1D4yJaG1CQM/OLlOBnDQrAyCUZ696nVQH/U5zJhjTR3wdzt9UeyE9kQEOJr
|
||||||
|
RA==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDQzCCAiugAwIBAgIUA+GJ9S/l9MoO3gPga8JwUYNpaekwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwGjEYMBYGA1UEAwwPVHJ1c3QgVGVzdCBSb290MCAXDTI2MTAwODE3MTk0NFoY
|
||||||
|
DzIxMjYwOTE0MTcxOTQ0WjARMQ8wDQYDVQQDDAZOQyBJbnQwggEiMA0GCSqGSIb3
|
||||||
|
DQEBAQUAA4IBDwAwggEKAoIBAQDBpGTjp6pklNYbUn+TAOFFojcQOry16ECScxx7
|
||||||
|
VGZKHMYxBa1/9LCoAeS/z81CaiPIK6dv6kHOvKh3OA4VJinfoT03MPFo77tBtgie
|
||||||
|
Fgyt7GgROHMQHjjnSHCeMrv4UgF7qRgUMDpBOa+mXHx+gw1hLGSajnHMByQYjPSn
|
||||||
|
FUdn99c3GfA435sInwsneK3Z6K6w9dnaGfa5/cNcGs/LdFRARuBzutVFm0ZFz44E
|
||||||
|
nVoMeHppw3OBb4ZEA18Gn8cERW06+yA4/De98dzo8gPVt3IMwjx4Y5TPX5xm8JeI
|
||||||
|
vofKiHPofvTHnBlqCzvUeOxUafQUUKaexyygooiiB4NEymwfAgMBAAGjgYcwgYQw
|
||||||
|
DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHWJVS3H
|
||||||
|
Wh0c4hnE52bOWg2s/aGvMB8GA1UdIwQYMBaAFDl9W8k1XKQCubIn46G/oYwjeDkq
|
||||||
|
MCEGA1UdHgEB/wQXMBWgEzARgg9hbGxvd2VkLmV4YW1wbGUwDQYJKoZIhvcNAQEL
|
||||||
|
BQADggEBAKkFGxFm6cibc6Y853pNWoDN30fvkbt1e8YGf/Ws+E7e18wf9JM+HxfU
|
||||||
|
cCF5NFI9rZAScaLPifcoewxRnO0lqMtkNYk52/iJYE8WHkcn0/sCxluuHpD5HOVI
|
||||||
|
7YEbniFcPGBhTM/62An1FGtsCFd02vjP6dZ1m79fxgONYVKsMpJoiGZsYeScFixE
|
||||||
|
J0qpqXsJ8cfvhH0FkxQeSX28PHRKV9cay2ElmP8yAelpA9DGeowcE67KeIa2GH0E
|
||||||
|
75DIZlqa8+HTYSXGZOBKlEdPtLWtluGS/ewhDNN8jTmWu4rxPLvUU4VcnoOxHWri
|
||||||
|
WUK2t8zRGPlReSvQhSwZC54hBJx4e+c=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDPTCCAiWgAwIBAgIUetjuFkPGZNknh/9qYSrAMnZYVfAwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwETEPMA0GA1UEAwwGTkMgSW50MCAXDTI2MTAwODE3MTk0NFoYDzIxMjYwOTE0
|
||||||
|
MTcxOTQ0WjAMMQowCAYDVQQDDAF4MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
|
||||||
|
CgKCAQEAyhDyS5OTWf9yoZbBFCY69Em5fa2AVKSXnjQsLn/LRSfPrMyXp0doKdmI
|
||||||
|
gmhNsaFcEFMxyavyD8V2uMfpgg7QMEoEvRXZXdQkNPpT1k2WRPtkkQReig9vOtsc
|
||||||
|
sKL4oK3uU099jFaVOC5CmDUDElHTdTK83/WP2x2cLoPi2cfj7vwrmc2y9x2LGkzC
|
||||||
|
pOoKsDYEFMRZ2cyffSiudC1uT8kYKI8c32AO9hDwJF1sEyaqIzTVBh4P3zOw/g6O
|
||||||
|
dsWSSxFIHd+pbFjMXQSIePIpMSMuYVs5Pgz8mMuEJSNnWsfr6a5phEiezyM4rcMs
|
||||||
|
MZ6NCUqK9XThsxLXGw1QVPatbyTXLQIDAQABo4GPMIGMMAwGA1UdEwEB/wQCMAAw
|
||||||
|
DgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMB8GA1UdIwQYMBaA
|
||||||
|
FHWJVS3HWh0c4hnE52bOWg2s/aGvMBcGA1UdEQQQMA6CDGhvc3QuZXhhbXBsZTAd
|
||||||
|
BgNVHQ4EFgQUqEPPZG734QvkFZT6gtaRMTCcK2owDQYJKoZIhvcNAQELBQADggEB
|
||||||
|
AEy+iqqtgRXNk2CCClBLi2HrU2dBjr6FdbYNWPyWZ2FrvQigiAsbkzxql4bKlE6Q
|
||||||
|
jRGhf57nELD3W5jVbkh57X6Km5cGQcyBhPvpZzYjbMk9dDOWeyd8zyxnrZsOaXoo
|
||||||
|
Q0djdYu+uyqcBMvz4OfZn+GDybXRdwzY5PgeSSjRMbDhR7XIIMOiBmOv1A6sJoGC
|
||||||
|
6qqoo4nQPKrCGHBBNVv8sy78ZUTgDs2vGX9+Sx0VUyrAlrXLDF/6vxgjhTCEED6p
|
||||||
|
FX3agZtNVgkbj/B3I3sML4DzDZ+SMtlyyeOhuJgdWkI5YnptfDfhtPG1G1SHTBvL
|
||||||
|
u03WVlBWeiYY6to1/OD7SGc=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDITCCAgmgAwIBAgIUA+GJ9S/l9MoO3gPga8JwUYNpaeswDQYJKoZIhvcNAQEL
|
||||||
|
BQAwGjEYMBYGA1UEAwwPVHJ1c3QgVGVzdCBSb290MCAXDTI2MTAwODE3MTk0NFoY
|
||||||
|
DzIxMjYwOTE0MTcxOTQ0WjARMQ8wDQYDVQQDDAZQTCBJbnQwggEiMA0GCSqGSIb3
|
||||||
|
DQEBAQUAA4IBDwAwggEKAoIBAQCvpCVepJ8mvuB1zxlU2n9jMSDCDEDydVkBvcKW
|
||||||
|
fQQr2e8OWKcQ6y86DQ8ZCyLNWe+L4pZTMyV1Wq/T0jIo7vEJ3PfJjzcjaiT6yW+k
|
||||||
|
ZhxuaA4bWtnt8OArTNXRThTavkw1Ef7euhYL1degRZUxDJEpm86zNnwfv6YBRwoF
|
||||||
|
y6F1oh4Z7nTJyPs9xc63MrgATOltJ3t2gHjAOXdRyWglUBYRae2IWofgQScSk7jT
|
||||||
|
0T1KwD2ce5Q6RvCNpuhyXlzvZ6y9YcnijY1EjV5I0rnFwIV3u1PQQJt5v6RxL4rL
|
||||||
|
g2uJrnAhnKGBGonhl4QcpUw0nazcGa5jMHh8iZv9p18qf23fAgMBAAGjZjBkMBIG
|
||||||
|
A1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQ2CJRo
|
||||||
|
uL2JbMe/bo3463fl8YjK/zAfBgNVHSMEGDAWgBQ5fVvJNVykArmyJ+Ohv6GMI3g5
|
||||||
|
KjANBgkqhkiG9w0BAQsFAAOCAQEAhyqPUkysJw0CV07uTU39sdYnYS6LyDqFKEwE
|
||||||
|
1ToZ+1u4pL5QZRo8yJ65psR0+9w8NTsSnmKS3bgkTqxq08VsC/P5x/wZFeL02JAg
|
||||||
|
4mzfDn8Xb/FxACQDs5QafRyU6MXHhHI0m6ndS5EhLnWu/IPKcoUAxPWstlLe6ixR
|
||||||
|
VXY7FXjiraiU1smT97tHxbd2woVwaoJxPlaK1NupLMYY8KGNTOHBn6gLMWspdl/J
|
||||||
|
bi/3JkNc5E9TCILFBAtWH9sWw3/PY8Mb7ir7k88DWHq3HJIDSYTDt0tOpdUfAke4
|
||||||
|
M/QdhHDS2pFQYCZxtSwK3RZ3OQHTfcZY7L2ospNTIsjsujGLZw==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDFjCCAf6gAwIBAgIUI9bf0eiAxYZ4G3OLjOVETtL3aOQwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwETEPMA0GA1UEAwwGUEwgSW50MCAXDTI2MTAwODE3MTk0NVoYDzIxMjYwOTE0
|
||||||
|
MTcxOTQ1WjASMRAwDgYDVQQDDAdQTCBJbnQyMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
||||||
|
AQ8AMIIBCgKCAQEAzeWnMybz8DmgEmziIs39MNQsnWvmqnhh7q10kDdOZDwV0v7C
|
||||||
|
rdDCQ6vPf3jaLt79jMvWURAQz1zJU4bpNsYw53+yqrraNw999jPyKI8k6ZJw1QPs
|
||||||
|
Na3VBxnulZb4sc8HQYD1RMXDrGeJwE07+AVFw1ej8FrWRsERLd5O4/gY2+eW1Sxi
|
||||||
|
aXkjzgA/iYpZW3p4+KKHGT93sseU7N7Alm54DgcHiksRGoQPwBSempty0p17f/R5
|
||||||
|
PlvQX4/MmmLcpreEcOAiVtJDTf6qq8zXaogaCGvyEjYb/m4wfdRkuPBp03T9JA1I
|
||||||
|
VWugtXPqp+2oR/XDF9O2ZD9VlysagJNctoY5OQIDAQABo2MwYTAPBgNVHRMBAf8E
|
||||||
|
BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUkR09mkxkUjE/r7WNfrt1
|
||||||
|
T3fICNIwHwYDVR0jBBgwFoAUNgiUaLi9iWzHv26N+Ot35fGIyv8wDQYJKoZIhvcN
|
||||||
|
AQELBQADggEBAJXeXPehboZGaAV85eEfasMW9cd17zNXFh7/WWE+9b7Rwz+5q6RY
|
||||||
|
G4yMizRFlSqorBiCidN9lKBqmCEETEkMjD1UI8iXQWXcMBHSUI9xvfdJiZ+I7xrV
|
||||||
|
Cjq4A5KJeKhayjlMTb27GlUV1g+irdh7g/rCDtN84LRGOMhpKZTcd6DerQCx6zrA
|
||||||
|
QxCP3vMexoyYh9Rv/90K7CO7mSXuplPGUX2zV6TUhwTR09M4+J+quvA32aamc7Wc
|
||||||
|
mtqoRTnG8HPh5ey2hjKJAjrbAA2edGDWaQb+0uOQyFhtJAHRpoGu6Mv7bt4Kk5Jb
|
||||||
|
A/WlHsdIlt1q1lS0iOCSLOZVaiaJB9y2Ce4=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDPjCCAiagAwIBAgIUTTXPR16Bluu+wyeTi8GeJHAm+4QwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwEjEQMA4GA1UEAwwHUEwgSW50MjAgFw0yNjEwMDgxNzE5NDVaGA8yMTI2MDkx
|
||||||
|
NDE3MTk0NVowDDEKMAgGA1UEAwwBeDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
|
||||||
|
AQoCggEBALXpnV/pQz+nAooMhg52ANUSOZup3lVVRoSoqGiEZRoBUqEM9tVRbd9W
|
||||||
|
u2ZlWGqdquvxmR1IZtqvgW3cjp1+Fr4eoi/GCbGPXgdiNMVnmjP54M+qY93hMriR
|
||||||
|
TYA3KHVXhYR/XUnVuXsgHRnIeYC2yPx/W+pn5A58tQqODvPp/AFMCi/nWlitCOI+
|
||||||
|
/UpMzuYVBm+vzAxBBCY8t/7MnTp7IyccxIShrDf9AHcGG2FPm9ZHZMSUeL7Dqnx+
|
||||||
|
OXxZcGGSZfOdJRfIqUoOkO6KJqnha34SMSke3pj35IeTS9FLGecGY1UaWnN44SlO
|
||||||
|
IJgKze7MNXNNxxCKONjsnGsYzSJg01kCAwEAAaOBjzCBjDAMBgNVHRMBAf8EAjAA
|
||||||
|
MA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAfBgNVHSMEGDAW
|
||||||
|
gBSRHT2aTGRSMT+vtY1+u3VPd8gI0jAXBgNVHREEEDAOggxob3N0LmV4YW1wbGUw
|
||||||
|
HQYDVR0OBBYEFEJ84ALu2SsxcnbD5p7C4pLStNcVMA0GCSqGSIb3DQEBCwUAA4IB
|
||||||
|
AQC4O6dQxcm6Grf4Q//XMo4zMBI/HcosD7Pqt8ToMfOMlmcpV5y9iuWD04K4yrrJ
|
||||||
|
KqhNdzqtuIPw/tPwDXfFX/vw2n3wvUXx2W4AP2951FnC5dWuE+CxgQA9kXjiqOiw
|
||||||
|
pZIUAqO+hjXfIswOtocMxmwCKvCbibh6DS4p+GMhDXFYPiBx60155DenUtfdfxps
|
||||||
|
0xgs42n/+UzesZhF+cUqvEtF8VrfkP2SpHrJXwxaII/0Yc0yqxCfd5xMAUw+ccP2
|
||||||
|
FWoBMm4QSPI62OmXSXk3lGjn8zZAABilPONqo2nsSv2HcOH82OqvleloRVXnVIMK
|
||||||
|
58Dib6o7IcPlgsnoH/tKoy7J
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDBjCCAe6gAwIBAgIUU93kzExCdrzi3lnMnhSZgjnowIswDQYJKoZIhvcNAQEL
|
||||||
|
BQAwGjEYMBYGA1UEAwwPVHJ1c3QgVGVzdCBSb290MCAXDTI2MTAwODE3MTk0M1oY
|
||||||
|
DzIxMjYwOTE0MTcxOTQzWjAaMRgwFgYDVQQDDA9UcnVzdCBUZXN0IFJvb3QwggEi
|
||||||
|
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDc4SkwOK60qqk09EjIPTRGvSnH
|
||||||
|
sOPJu0A1+IfRKsdfdMk6pTXL1Xm01nOLLqbsW4oz3rRfFQJyZPOSpPzzkCAdjKfp
|
||||||
|
y8KtKUZjzlnz8ADOoaeGLCnCyELw09anO/JsbnDv0snPMInYS5R2Onq5+M6qlEdH
|
||||||
|
iSe9uG0qiWx0OGXBkoDs+zF+Buc5ilYEKVNHZBho3V3qUoFjKKEE2O9DyKJ1qL+v
|
||||||
|
KgvTg0Z6KPjiyvlkkMRdn2UCHsJl5XTxU2dLLbs99F3/GSGbVjk+UXcUcJp4ZpA/
|
||||||
|
/oQd99g4MYqKGDJIItFYQ0WQDTk1s2rEzqaOKS9DA83eXCwgvDBfOGaY+HCjAgMB
|
||||||
|
AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQW
|
||||||
|
BBQ5fVvJNVykArmyJ+Ohv6GMI3g5KjANBgkqhkiG9w0BAQsFAAOCAQEAZKD6bPnD
|
||||||
|
8l6xoyaai0AhqEx03MK1rBLiji2iK65FznWOFlRJCJX6MH5fJbGyafCHiM7fkTOw
|
||||||
|
BX2hY/hXC8Yg4AtsOvf6hRNYHEy0Z0Nj7qfCY9BpJXHzMvPLkJqqJB0UJisr5EDk
|
||||||
|
FKNiBiXftwbAUeUXuzncfviKbXroHlT5oLHBvApb6jhxIPhb7dBrbpN2urRfMzZu
|
||||||
|
ezbK+jWUB89h79xupK4ph7B8zFY5swiIZ3bjXDFqlNDzyksgzqqWOoZqyI3FoCJY
|
||||||
|
msORGKupBklLJgm78AjDJdu1/lhGfLflM9pspYi7A8Kct6fQerw2SJ+5xoFw9WKz
|
||||||
|
CUKllHzH9kJnew==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDRjCCAi6gAwIBAgIUA+GJ9S/l9MoO3gPga8JwUYNpae0wDQYJKoZIhvcNAQEF
|
||||||
|
BQAwGjEYMBYGA1UEAwwPVHJ1c3QgVGVzdCBSb290MCAXDTI2MTAwODE3MTk0NVoY
|
||||||
|
DzIxMjYwOTE0MTcxOTQ1WjAMMQowCAYDVQQDDAF4MIIBIjANBgkqhkiG9w0BAQEF
|
||||||
|
AAOCAQ8AMIIBCgKCAQEAj3JW39sTg/nPYlrrd1wcXpP4Ya2WmjizYVfXIujTj+ud
|
||||||
|
mOYFUM373ZCPo+VgyT4HP4DM6sq4p3vO6EuuVzyJ8soeFEnrDeikeQAnQbKw/2Zt
|
||||||
|
3S87iFMurZ34pMAWDauxUxVcONnwuf7meNME4aQoBWjPHbcGWke/Ri3xPNHKOODQ
|
||||||
|
3nt3HHr6wIBALOJXnUMWWRjovn4GcUxO0O1OGghr6taoI2MCsrBGbvv2BZ4TXtVd
|
||||||
|
anz5sQx1l9cAi9HlvnqpcIl07mkpvJ4nXf8wlmESZPpgrlKmI17R3CFhtoI0lhNW
|
||||||
|
WCx5KetPhgKYQmqHYCF5REdV0gjNbQqyyIv2KEnGTQIDAQABo4GPMIGMMAwGA1Ud
|
||||||
|
EwEB/wQCMAAwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMB8G
|
||||||
|
A1UdIwQYMBaAFDl9W8k1XKQCubIn46G/oYwjeDkqMBcGA1UdEQQQMA6CDGhvc3Qu
|
||||||
|
ZXhhbXBsZTAdBgNVHQ4EFgQU0IoQbg1eN6pJMBqiJndYE2R3Z4gwDQYJKoZIhvcN
|
||||||
|
AQEFBQADggEBACgpJLT7wIynXT7UIO9ysQZZHICrTW92oopBh6CxnwzJuLsTjG4g
|
||||||
|
bQEnGO6NHQIBC3SCilyaEC9tDfDIpjJwfzyX4DuH/7UfAA6+xnJWxbaUFfAssiAG
|
||||||
|
DGTChKZlmZvRhf7V415QKKbEWeQz9I+j+X47at6aki/64BAmMw7ErDPHQukg74kB
|
||||||
|
zQvNFvkpSVcO6dgbYKP/+F/x3drAierIvJkfhcox/HoZSwcgKGDp2VFcfEKxUK91
|
||||||
|
PkyDw78ONQANiM53PNSAjfSRVzRzW3PsPjNiF+OHGg+FNp6Cp8VbS6fSyhN6qf2q
|
||||||
|
RXlF1J0mj226t9l9v7JkWfjTkiktRBnJoXU=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDZTCCAk2gAwIBAgIUA+GJ9S/l9MoO3gPga8JwUYNpae8wDQYJKoZIhvcNAQEL
|
||||||
|
BQAwGjEYMBYGA1UEAwwPVHJ1c3QgVGVzdCBSb290MCAXDTI2MTAwODE3MjAyNFoY
|
||||||
|
DzIxMjYwOTE0MTcyMDI0WjAMMQowCAYDVQQDDAF4MIIBIjANBgkqhkiG9w0BAQEF
|
||||||
|
AAOCAQ8AMIIBCgKCAQEApbYcbze7NDc8K8nCy4yoCy++oUFvoppPJpPaPb7SpRRD
|
||||||
|
0AHISMpE09/yXr2+NNVf80yzhmsSfuej7cq4TMYN2m6cZUVe9r+lCZC7QztfpZdO
|
||||||
|
9UZLWv/S53rWcLA/rtH2yg5Q1DRgt2uoY/FlCmMJt3cgrr3H7R9vCtQUrhSayGyY
|
||||||
|
PfPwyrwkL6Rja3ztkKPlco83CgqRnWMOwG6gpxcqTAcyzH1WAcyDkTWmhkr+1G50
|
||||||
|
oL852GdVV+kO0rLNAI4+bPdsbPOKk4HikaTHHE0SQV78eb0Z5X/D0wFGu1iGopJ/
|
||||||
|
BBGSym2LYibMbNLvkaWrnAT2vdVP1n/6afcJxAjj+wIDAQABo4GuMIGrMAwGA1Ud
|
||||||
|
EwEB/wQCMAAwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMB8G
|
||||||
|
A1UdIwQYMBaAFDl9W8k1XKQCubIn46G/oYwjeDkqMDYGA1UdEQQvMC2CEioubGFu
|
||||||
|
LmhvbWUuZXhhbXBsZYIOKi5ob21lLmV4YW1wbGWCByouY28udWswHQYDVR0OBBYE
|
||||||
|
FNDwHsBO73UfLTCvRi/q/XHb0o6dMA0GCSqGSIb3DQEBCwUAA4IBAQDLXwJYrYI+
|
||||||
|
efdLGjymEXT0CR/M67x6BIQKB8w0onIGyz26WedaTX+LKuji+WGgenY/AkIEC6AL
|
||||||
|
T4rv6dBVjxHv4+x8TgnzU+aWNOEEdDWNeaXc8sb+3ZZzm5mkPooVWfVdnej9i/G1
|
||||||
|
WHjAFo/p0RHs613UuGRoZ6ZCmMomNYs9nwFoz6EmHUseARwj4dCAkdih+Z64j3NR
|
||||||
|
610hnoRsirKk/Ihjcn8RxUTVrBA+N6RkbIJByCeNzyhNzSmfNi8XvyvCqjjiUNon
|
||||||
|
b83rGCcF+V0px7NaZU8QwUJPDDekcUo/k8mQ+LjjLEAHByTJ9+Ap+3lhRuv21DWg
|
||||||
|
kJIAoFUaST7C
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICwjCCAaqgAwIBAgIUA+GJ9S/l9MoO3gPga8JwUYNpae4wDQYJKoZIhvcNAQEL
|
||||||
|
BQAwGjEYMBYGA1UEAwwPVHJ1c3QgVGVzdCBSb290MCAXDTI2MTAwODE3MTk0NVoY
|
||||||
|
DzIxMjYwOTE0MTcxOTQ1WjAMMQowCAYDVQQDDAF4MIGfMA0GCSqGSIb3DQEBAQUA
|
||||||
|
A4GNADCBiQKBgQDWzciJ+1PQ5RoweAE4xbNqaEnbwIyOR0+NwdUt02tcjezWlQfy
|
||||||
|
A9hWb/DkETcfw6LQx3u458vmBXM1YVmnYAhnd2P8OIwlQ0Se2xQ17iKJdpoa7IQ/
|
||||||
|
aTkF1yjBvFxD8DoDRojpVupPI+mh5wg+wCCvgznX+fpZYkXEPorTFeDe2QIDAQAB
|
||||||
|
o4GPMIGMMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoG
|
||||||
|
CCsGAQUFBwMBMB8GA1UdIwQYMBaAFDl9W8k1XKQCubIn46G/oYwjeDkqMBcGA1Ud
|
||||||
|
EQQQMA6CDGhvc3QuZXhhbXBsZTAdBgNVHQ4EFgQU/l8az3OuVEjRNlmpfraqM0+p
|
||||||
|
NT8wDQYJKoZIhvcNAQELBQADggEBANJhIs3MqR/U3CZshOZSduYdDz3xXUbqg5K6
|
||||||
|
/z6EynXzF+DW26LiwZcWa3bJxfi15NbQ3urMu9UueyX2JJ1tffRNRnwWEPRG6qZ5
|
||||||
|
oD4y7hyrPvbPSVMCGTZJPX1mBi1Fo0ijPNtrziujNw9xEuFL/3Exan3xelJJpg8J
|
||||||
|
jLdVYzvzgzqT/m0Q1gy9ceRb6VJhtUN1ingYLyUvRwiih64pLLslBwvluEGrHqZ8
|
||||||
|
f6JmpvxKX5kjaWXH8M6ZjgJofmD2vaCDjnb3Y7dZAMNlxMpDXhW0hxQEjycnh3dZ
|
||||||
|
cpLB7DwofmR/ov/wE/tVmjA+lqR6Fp8fpyy5vtvGCeVMnJv32/I=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -58,6 +58,7 @@ import {
|
|||||||
import {recordDesktopLastRoute} from '@electron/main/DesktopLastRoute';
|
import {recordDesktopLastRoute} from '@electron/main/DesktopLastRoute';
|
||||||
import {cleanupDesktopOutboundHTTP} from '@electron/main/DesktopOutboundHTTP';
|
import {cleanupDesktopOutboundHTTP} from '@electron/main/DesktopOutboundHTTP';
|
||||||
import {registerDesktopRuntimeConfigHandlers} from '@electron/main/DesktopRuntimeConfigIpc';
|
import {registerDesktopRuntimeConfigHandlers} from '@electron/main/DesktopRuntimeConfigIpc';
|
||||||
|
import {installDesktopSystemTrustVerifier} from '@electron/main/DesktopSystemTrustVerifier';
|
||||||
import {destroyDesktopTray, hasActiveDesktopTray, initializeDesktopTray} from '@electron/main/DesktopTray';
|
import {destroyDesktopTray, hasActiveDesktopTray, initializeDesktopTray} from '@electron/main/DesktopTray';
|
||||||
import {registerDisplayMediaHandlers} from '@electron/main/DisplayMedia';
|
import {registerDisplayMediaHandlers} from '@electron/main/DisplayMedia';
|
||||||
import {initializeDockMenu} from '@electron/main/DockMenu';
|
import {initializeDockMenu} from '@electron/main/DockMenu';
|
||||||
@@ -119,7 +120,7 @@ import {
|
|||||||
DesktopLegacyImportPhase,
|
DesktopLegacyImportPhase,
|
||||||
readDesktopLegacyImportPhase,
|
readDesktopLegacyImportPhase,
|
||||||
} from '@fluxer/desktop_ipc/src/StorageContract';
|
} from '@fluxer/desktop_ipc/src/StorageContract';
|
||||||
import {app, dialog, ipcMain, netLog, shell} from 'electron';
|
import {app, dialog, ipcMain, netLog, session, shell} from 'electron';
|
||||||
import log from 'electron-log';
|
import log from 'electron-log';
|
||||||
|
|
||||||
log.transports.file.level = 'info';
|
log.transports.file.level = 'info';
|
||||||
@@ -395,6 +396,11 @@ if (launchConfigurationError) {
|
|||||||
log.error('[Init] Failed to configure the host resolver:', error);
|
log.error('[Init] Failed to configure the host resolver:', error);
|
||||||
}
|
}
|
||||||
await runStartupPhaseAsync('launch-net-log', startLaunchNetLog);
|
await runStartupPhaseAsync('launch-net-log', startLaunchNetLog);
|
||||||
|
try {
|
||||||
|
runStartupPhase('system-trust', () => installDesktopSystemTrustVerifier(session.defaultSession));
|
||||||
|
} catch (error) {
|
||||||
|
log.error('[Init] Failed to install the system trust verifier:', error);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
await runStartupPhaseAsync('desktop-debug-info', async () => {
|
await runStartupPhaseAsync('desktop-debug-info', async () => {
|
||||||
logDesktopDebugInfo(await getDesktopDebugInfo(userDataConfig.base, {nativeProbes: false}));
|
logDesktopDebugInfo(await getDesktopDebugInfo(userDataConfig.base, {nativeProbes: false}));
|
||||||
|
|||||||
Reference in new issue
Block a user