UNPKG

electron-root-ssl-pinning

Version:
90 lines (89 loc) 3.83 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const CertificateChainValidationEngine_1 = __importDefault(require("pkijs/build/CertificateChainValidationEngine")); const utils_1 = require("./utils"); const types_1 = require("./types"); const utils_2 = require("./utils"); function createChainVerifier(caStore) { return async (request) => { try { const chain = createCertificatesChainFromRequest(request); const isHostnameAllowed = validateHostname(request.hostname, chain[0]); if (!isHostnameAllowed) { return types_1.VerificationResult.INVALID; } const result = await verifyChain(chain, caStore); return result; } catch (err) { console.error(err); return types_1.VerificationResult.INTERNAL_ERROR; } }; } exports.createChainVerifier = createChainVerifier; function createCertificatesChainFromRequest(request) { const chain = []; function getCert(requestCert) { const cert = utils_1.createPKICertificate(requestCert.data); if (!utils_1.isRootCertificate(cert)) { chain.push(cert); if (requestCert.issuerCert) { getCert(requestCert.issuerCert); } } } getCert(request.certificate); return chain; } exports.createCertificatesChainFromRequest = createCertificatesChainFromRequest; async function verifyChain(chain, caStore) { if (chain.every(cert => utils_2.isValidityPeriodCorrect(cert) && !utils_2.isWeakEncryption(cert))) { const lastIntermediateCert = chain[chain.length - 1]; if (lastIntermediateCert) { const rootCaKey = utils_1.findDistinguishedName(lastIntermediateCert, "issuer"); if (caStore[rootCaKey] !== undefined) { const validator = new CertificateChainValidationEngine_1.default({ certs: [...chain, caStore[rootCaKey]], trustedCerts: [caStore[rootCaKey]], }); const { result } = await validator.verify(); if (result) { return types_1.VerificationResult.VALID; } } } } return types_1.VerificationResult.INVALID; } exports.verifyChain = verifyChain; function validateHostname(hostname, leafCert) { if (leafCert) { const foundSubjectAlternativeNames = leafCert.extensions && leafCert.extensions.find(({ extnID }) => extnID === utils_2.subjectAlternativeNameOid); const foundSubjectCommonName = leafCert.subject.typesAndValues.find(({ type }) => String(type) === utils_2.commonNameOid); if (foundSubjectAlternativeNames) { return foundSubjectAlternativeNames.parsedValue.altNames.some((allowedName) => isAllowedDomain(hostname, allowedName.value)); } if (foundSubjectCommonName) { return isAllowedDomain(hostname, foundSubjectCommonName.value.valueBlock.value); } } return false; } exports.validateHostname = validateHostname; function isAllowedDomain(hostname, allowedName) { const hostNameDomains = hostname.split(".").reverse(); const allowedDomains = allowedName.split(".").reverse(); const isTooFarSubdomain = hostNameDomains.length > allowedDomains.length; if (isTooFarSubdomain) { return false; } return allowedDomains.every((domain, index) => { const correspondingHostNameDomain = hostNameDomains[index] || ""; return domain.toLowerCase() === correspondingHostNameDomain.toLowerCase() || domain === "*"; }); } exports.isAllowedDomain = isAllowedDomain;