node-mitmproxy1
Version:
Node.js MITM Proxy
262 lines (232 loc) • 7.28 kB
JavaScript
'use strict';
var forge = require('node-forge');
var fs = require('fs');
var path = require('path');
var config = require('../common/config');
var _ = require('lodash');
var mkdirp = require('mkdirp');
var colors = require('colors');
var utils = exports;
var pki = forge.pki;
utils.createCA = function (CN) {
var keys = pki.rsa.generateKeyPair(2046);
var cert = pki.createCertificate();
cert.publicKey = keys.publicKey;
cert.serialNumber = new Date().getTime() + '';
cert.validity.notBefore = new Date();
cert.validity.notBefore.setFullYear(cert.validity.notBefore.getFullYear() - 5);
cert.validity.notAfter = new Date();
cert.validity.notAfter.setFullYear(cert.validity.notAfter.getFullYear() + 20);
var attrs = [{
name: 'commonName',
value: CN
}, {
name: 'countryName',
value: 'CN'
}, {
shortName: 'ST',
value: 'GuangDong'
}, {
name: 'localityName',
value: 'ShenZhen'
}, {
name: 'organizationName',
value: 'node-mitmproxy'
}, {
shortName: 'OU',
value: 'https://github.com/wuchangming/node-mitmproxy'
}];
cert.setSubject(attrs);
cert.setIssuer(attrs);
cert.setExtensions([{
name: 'basicConstraints',
critical: true,
cA: true
}, {
name: 'keyUsage',
critical: true,
keyCertSign: true
}, {
name: 'subjectKeyIdentifier'
}]);
// self-sign certificate
cert.sign(keys.privateKey, forge.md.sha256.create());
return {
key: keys.privateKey,
cert: cert
};
};
utils.covertNodeCertToForgeCert = function (originCertificate) {
var obj = forge.asn1.fromDer(originCertificate.raw.toString('binary'));
return forge.pki.certificateFromAsn1(obj);
};
utils.createFakeCertificateByDomain = function (caKey, caCert, domain) {
var keys = pki.rsa.generateKeyPair(2046);
var cert = pki.createCertificate();
cert.publicKey = keys.publicKey;
cert.serialNumber = new Date().getTime() + '';
cert.validity.notBefore = new Date();
cert.validity.notBefore.setFullYear(cert.validity.notBefore.getFullYear() - 1);
cert.validity.notAfter = new Date();
cert.validity.notAfter.setFullYear(cert.validity.notAfter.getFullYear() + 1);
var attrs = [{
name: 'commonName',
value: domain
}, {
name: 'countryName',
value: 'CN'
}, {
shortName: 'ST',
value: 'GuangDong'
}, {
name: 'localityName',
value: 'ShengZhen'
}, {
name: 'organizationName',
value: 'node-mitmproxy'
}, {
shortName: 'OU',
value: 'https://github.com/wuchangming/node-mitmproxy'
}];
cert.setIssuer(caCert.subject.attributes);
cert.setSubject(attrs);
cert.setExtensions([{
name: 'basicConstraints',
critical: true,
cA: false
}, {
name: 'keyUsage',
critical: true,
digitalSignature: true,
contentCommitment: true,
keyEncipherment: true,
dataEncipherment: true,
keyAgreement: true,
keyCertSign: true,
cRLSign: true,
encipherOnly: true,
decipherOnly: true
}, {
name: 'subjectAltName',
altNames: [{
type: 2,
value: domain
}]
}, {
name: 'subjectKeyIdentifier'
}, {
name: 'extKeyUsage',
serverAuth: true,
clientAuth: true,
codeSigning: true,
emailProtection: true,
timeStamping: true
}, {
name: 'authorityKeyIdentifier'
}]);
cert.sign(caKey, forge.md.sha256.create());
return {
key: keys.privateKey,
cert: cert
};
};
utils.createFakeCertificateByCA = function (caKey, caCert, originCertificate) {
var certificate = utils.covertNodeCertToForgeCert(originCertificate);
var keys = pki.rsa.generateKeyPair(2046);
var cert = pki.createCertificate();
cert.publicKey = keys.publicKey;
cert.serialNumber = certificate.serialNumber;
cert.validity.notBefore = new Date();
cert.validity.notBefore.setFullYear(cert.validity.notBefore.getFullYear() - 1);
cert.validity.notAfter = new Date();
cert.validity.notAfter.setFullYear(cert.validity.notAfter.getFullYear() + 1);
cert.setSubject(certificate.subject.attributes);
cert.setIssuer(caCert.subject.attributes);
certificate.subjectaltname && (cert.subjectaltname = certificate.subjectaltname);
var subjectAltName = _.find(certificate.extensions, { name: 'subjectAltName' });
cert.setExtensions([{
name: 'basicConstraints',
critical: true,
cA: false
}, {
name: 'keyUsage',
critical: true,
digitalSignature: true,
contentCommitment: true,
keyEncipherment: true,
dataEncipherment: true,
keyAgreement: true,
keyCertSign: true,
cRLSign: true,
encipherOnly: true,
decipherOnly: true
}, {
name: 'subjectAltName',
altNames: subjectAltName.altNames
}, {
name: 'subjectKeyIdentifier'
}, {
name: 'extKeyUsage',
serverAuth: true,
clientAuth: true,
codeSigning: true,
emailProtection: true,
timeStamping: true
}, {
name: 'authorityKeyIdentifier'
}]);
cert.sign(caKey, forge.md.sha256.create());
return {
key: keys.privateKey,
cert: cert
};
};
utils.isBrowserRequest = function () {
return (/Mozilla/i.test(userAgent)
);
};
//
// /^[^.]+\.a\.com$/.test('c.a.com')
//
utils.isMappingHostName = function (DNSName, hostname) {
var reg = DNSName.replace(/\./g, '\\.').replace(/\*/g, '[^.]+');
reg = '^' + reg + '$';
return new RegExp(reg).test(hostname);
};
utils.getMappingHostNamesFormCert = function (cert) {
var mappingHostNames = [];
mappingHostNames.push(cert.subject.getField('CN') ? cert.subject.getField('CN').value : '');
var altNames = cert.getExtension('subjectAltName') ? cert.getExtension('subjectAltName').altNames : [];
mappingHostNames = mappingHostNames.concat(_.map(altNames, 'value'));
return mappingHostNames;
};
// sync
utils.initCA = function () {
var basePath = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : config.getDefaultCABasePath();
var caCertPath = path.resolve(basePath, config.caCertFileName);
var caKeyPath = path.resolve(basePath, config.caKeyFileName);
try {
fs.accessSync(caCertPath, fs.F_OK);
fs.accessSync(caKeyPath, fs.F_OK);
// has exist
return {
caCertPath: caCertPath,
caKeyPath: caKeyPath,
create: false
};
} catch (e) {
var caObj = utils.createCA(config.caName);
var caCert = caObj.cert;
var cakey = caObj.key;
var certPem = pki.certificateToPem(caCert);
var keyPem = pki.privateKeyToPem(cakey);
mkdirp.sync(path.dirname(caCertPath));
fs.writeFileSync(caCertPath, certPem);
fs.writeFileSync(caKeyPath, keyPem);
}
return {
caCertPath: caCertPath,
caKeyPath: caKeyPath,
create: true
};
};