Skip to content

Commit

Permalink
MASSIVE refactor
Browse files Browse the repository at this point in the history
cachedSecurityDetails[tabId][url]=new SecurityDetails(details,securityInfo);
…
let securityDetails = cachedSecurityDetails[tabId][url];
(changeInfo.status == 'complete' && securityDetails) ? extraCmds = {enable:tabId} : extraCmds = {};
applyBrowserActionSpec({tabId:tabId},browserActionSpec,extraCmds);
  • Loading branch information
James-E-A committed Sep 27, 2020
1 parent 0df692c commit 3d97828
Show file tree
Hide file tree
Showing 5 changed files with 305 additions and 170 deletions.
56 changes: 28 additions & 28 deletions src/db/host_cityStateCountry.json
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
{
"camerfirma.com": "Madrid, Madrid, ES",
"certum.eu": "Szczecin, West Pomeranian, PL",
"amazontrust.com": "North Seattle, Washington, US",
"atos.net": "Meppen, Lower Saxony, DE",
"firmaprofesional.com": "Barcelona, Catalonia, ES",
"aoc.cat": "Barcelona, Catalonia, ES",
"digicert.com": "Lehi, Utah, US",
"emudhra.com": "Bangalore, Karnataka, IN",
"entrust.net": "Ottawa, Ontario, CA",
"globalsign.com": "Leuven, Flemish Brabant, BE",
"godaddy.com": "Scottsdale, Arizona, US",
"goog": "Mountain View, California, US",
"identrust.com": "Salt Lake City, Utah, US",
"letsencrypt.org": "San Francisco, California, US",
"izenpe.com": "Vitoria-Gasteiz, Alava, ES",
"microsoft.com": "Redmond, Washington, US",
"wisekey.com": "Geneva, Geneva, CH",
"quovadisglobal.com": "Hamilton, Pembroke, BM",
"secomtrust.net": "Mitaka-Shi, Tokyo, JP",
"sectigo.com": "Salford, Greater Manchester, GB",
"trustwave.com": "Chicago, Ilinois, US",
"sheca.com": "Hongkou, Shanghai, CN",
"ssl.com": "Houston, Texas, US",
"swisssign.com": "Glattbrugg, Opfikon, CH",
"teliasonera.com": "Helsinki, Uusimaa, FI",
"trustcorsystems.com": "Toronto, Ontario, CA",
"trustis.com": "Thatcham, Berkshire, GB",
"networksolutions.com": "Herndon, Virginia, US"
"camerfirma.com": ["Madrid", "Madrid", "ES"],
"certum.eu": ["Szczecin", "West Pomeranian", "PL"],
"amazontrust.com": ["North Seattle", "Washington", "US"],
"atos.net": ["Meppen", "Lower Saxony", "DE"],
"firmaprofesional.com": ["Barcelona", "Catalonia", "ES"],
"aoc.cat": ["Barcelona", "Catalonia", "ES"],
"digicert.com": ["Lehi", "Utah", "US"],
"emudhra.com": ["Bangalore", "Karnataka", "IN"],
"entrust.net": ["Ottawa", "Ontario", "CA"],
"globalsign.com": ["Leuven", "Flemish Brabant", "BE"],
"godaddy.com": ["Scottsdale", "Arizona", "US"],
"goog": ["Mountain View", "California", "US"],
"identrust.com": ["Salt Lake City", "Utah", "US"],
"letsencrypt.org": ["San Francisco", "California", "US"],
"izenpe.com": ["Vitoria-Gasteiz", "Alava", "ES"],
"microsoft.com": ["Redmond", "Washington", "US"],
"wisekey.com": ["Geneva", "Geneva", "CH"],
"quovadisglobal.com": ["Hamilton", "Pembroke", "BM"],
"secomtrust.net": ["Mitaka-Shi", "Tokyo", "JP"],
"sectigo.com": ["Salford", "Greater Manchester", "GB"],
"trustwave.com": ["Chicago", "Ilinois", "US"],
"sheca.com": ["Hongkou", "Shanghai", "CN"],
"ssl.com": ["Houston", "Texas", "US"],
"swisssign.com": ["Glattbrugg", "Opfikon", "CH"],
"teliasonera.com": ["Helsinki", "Uusimaa", "FI"],
"trustcorsystems.com": ["Toronto", "Ontario", "CA"],
"trustis.com": ["Thatcham", "Berkshire", "GB"],
"networksolutions.com": ["Herndon", "Virginia", "US"]
}
62 changes: 29 additions & 33 deletions src/js/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const secTypes={
MitM: 1,
aRootKnown: 2,
aRootUnknown: 3,
selfSigned: 4,
unknown: 254,
insecure: 255
};
Expand All @@ -17,41 +18,36 @@ sha256fp_host_alt['07:ED:BD:82:4A:49:88:CF:EF:42:15:DA:20:D4:8C:2B:41:D7:15:29:D
sha256fp_host_alt['89:4E:BC:0B:23:DA:2A:50:C0:18:6B:7F:8F:25:EF:1F:6B:29:35:AF:32:A9:45:84:EF:80:AA:F8:77:A3:A0:6E']='us';//fpki.gov=us
Object.freeze(sha256fp_host_alt);

{
let data=JSON.parse(getAsset("db/IncludedCACertificateReport.json"));
data.forEach(ca=>{
let reducedHostname;
let sha256fp=ca["SHA-256 Fingerprint"]
.replaceAll(/(\w{2})(?=\w)/g,'$1:'); //perforate the fingerprints with : every 2 characters

let hostParts=(new URL(ca["Company Website"])).hostname.split('.')

//www isn't a real subdomain
if(hostParts[0]=='www') hostParts.splice(0,1);

//neither is pki
if(hostParts[0]=='pki') hostParts.splice(0,1);

//.<ccTLD> is from that country
if(hostParts[hostParts.length-1].length==2){
//gov is also a non-semantic subdomain
if(hostParts[hostParts.length-2]=='gov') hostParts.splice(0,hostParts.length-1);
reducedHostname=hostParts.join('.');
host_country[reducedHostname]=hostParts[hostParts.length-1].toUpperCase();
} else {
reducedHostname=hostParts.join('.');
}

sha256fp_host[sha256fp]=reducedHostname;
});
}
//Record the SHA-256 Fingerprint -> (reduced) hostname mappings
//As well as non-idiopathic SHA-256 Fingerprint -> country mappings
getAsset("db/IncludedCACertificateReport.json","json")
.forEach(ca => {
const sha256fp = ca["SHA-256 Fingerprint"].replaceAll(/(\w{2})(?=\w)/g,'$1:');
//perforate the fingerprints with : every 2 characters
//(i.e. convert from CCADB-format to Firefox-format)

const host = reduceHostname(new URL(ca["Company Website"]).hostname);

sha256fp_host[sha256fp] = host;

let country = identifyCountry(host);
if( country ) host_country[host] = country;
});
Object.freeze(sha256fp_host);

{
let data=JSON.parse(getAsset("db/host_cityStateCountry.json"));
for(let host in data){
host_country[host]=data[host].split(', ')[2];
//Apply idiopathic country mappings
Object.entries(getAsset("db/host_cityStateCountry.json","json"))
.forEach(([host,[city,state,country]]) => {
if( host in host_country ) {
console.warn("Overwriting country! Database may need to be checked.\nIf you're seeing this, please open an issue on GitHub; include the following:",
{
host: host,
currently: host_country[host],
csc: [city,state,country]
}
);
}
}
host_country[host] = country.toLowerCase();
});
Object.freeze(host_country);

105 changes: 23 additions & 82 deletions src/js/main.js
Original file line number Diff line number Diff line change
@@ -1,106 +1,47 @@
//Global cache of securityInfo objects:
const cachedSecurityInfosByTabIdAndURL=new Object();

function identifySecType(securityInfo){
//Takes in a browser.webRequest.getSecurityInfo object
//and returns an integer from secTypes corresponding to the
try {
switch(securityInfo.state) {
case 'insecure':

//genuinely not HTTPS
return secTypes.insecure;

case 'secure':
let certChain=securityInfo.certificates;

if(certChain.length==0) {
//TODO/FIXME: Mozilla doesn't provide
//any access whatsoever to self-signed
//or otherwise nominally-invalid certs
// https://discourse.mozilla.org/t/webrequest-getsecurityinfo-cant-get-self-signed-tofu-exception-certificates/67135
return secTypes.unknown;
}

let rootCert=certChain[certChain.length-1];

//Now, this connection is...
if(rootCert.isBuiltInRoot){
//...Mozilla-supported
return secTypes.Mozilla;
}

if(!securityInfo.isUntrusted){//why didn't they use .isTrusted lol
//...supported by a Non-Mozilla cert,...
if(isItMitM(rootCert)){ //TODO
//...a TLS MITM proxy
return secTypes.MitM;
} else {
//...an alternative Root CA
if(certChain[certChain.length-1].fingerprint.sha256 in sha256fp_host_alt) {
return secTypes.aRootKnown;
} else {
return secTypes.aRootUnknown;
}
}
}
default:
throw {status:'thisShouldNeverHappen',securityInfo:securityInfo};
}
} catch(e) {
switch(e.status){
default:
console.error(e.status||e,{securityInfo:securityInfo});
return secTypes.unknown;
}
}
}
//Global cache of SecurityDetails objects:
const cachedSecurityDetails=new Object();

browser.tabs.onUpdated.addListener(
function onTabUpdatedStatusListener(tabId,changeInfo,tabInfo){
let securityInfo,secType,certChain,browserActionSpec,extraCmds=[];
let browserActionSpec = genBrowserActionSpec(secTypes.unknown);
let extraCmds = {};
try {
let url=removeFragment(tabInfo.url);
securityInfo=cachedSecurityInfosByTabIdAndURL[tabId][url];
if(changeInfo.status=='complete' && securityInfo) extraCmds={enable:tabId};
secType=identifySecType(securityInfo);
certChain=securityInfo.certificates;
browserActionSpec=genBrowserActionSpec(secType,certChain);
} catch(e) {
secType=secTypes.unknown;
const url = removeFragment(tabInfo.url);
const securityDetails = cachedSecurityDetails[tabId][url];
if( changeInfo.status == 'complete' && securityDetails ) extraCmds.enable = tabId;
browserActionSpec = genBrowserActionSpec(securityDetails.secType,securityDetails.caId);
} finally {
applyBrowserActionSpec({tabId:tabId},browserActionSpec,extraCmds);
}
},
{
properties: ["status"]
properties: ["status"]//TODO: include "url"? -will require some refactoring.
}
);

browser.tabs.onRemoved.addListener(
async function onTabRemovedListener(tabId,removeInfo){
delete cachedSecurityInfosByTabIdAndURL[tabId];
delete cachedSecurityDetails[tabId];
}
);

//this is the only point we can getSecurityInfo.
//this is a design flaw IMO, since it allows attackers
//to intercept at least one outbound request (no matter
//how well we code) before detection.
//TODO: pester Mozilla about this
browser.webRequest.onHeadersReceived.addListener(
//this is the only point we can getSecurityInfo.
//this is a design flaw IMO, since it allows attackers
//to intercept at least one outbound request (no matter
//how well we code) before detection.
//TODO: pester Mozilla about this
async function onHeadersReceivedListener(details){
let tabId=details.tabId;
let type=details.type;
let requestId=details.requestId;
let requestUrl=details.url;
let securityInfo = await browser.webRequest.getSecurityInfo(requestId,{certificateChain:true,rawDER:true});
const tabId = details.tabId;
const type = details.type;
const requestId = details.requestId;
const requestUrl = removeFragment(details.url);
const securityInfo = await browser.webRequest.getSecurityInfo(requestId,{certificateChain:true,rawDER:true});
switch(type){
case 'main_frame':
if(!(tabId in cachedSecurityInfosByTabIdAndURL)) cachedSecurityInfosByTabIdAndURL[tabId]=new Object();
cachedSecurityInfosByTabIdAndURL[tabId][requestUrl]=securityInfo;
return;
break;
if(!( tabId in cachedSecurityDetails )) cachedSecurityDetails[tabId] = new Object();
const secDetails = new SecurityDetails(details, securityInfo);
return cachedSecurityDetails[tabId][requestUrl] = secDetails;
default:
//TODO
return;
Expand Down
Loading

0 comments on commit 3d97828

Please sign in to comment.