Skip to content

Commit

Permalink
Giant overhaul
Browse files Browse the repository at this point in the history
  • Loading branch information
James-E-A committed May 30, 2021
1 parent 89e4f6f commit 3a9048c
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 150 deletions.
14 changes: 8 additions & 6 deletions src/js/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@ const fp_host_alt = new Map();

//TODO TODO TODO TODO TODO TODO TODO
fp_host_alt.set('07:ED:BD:82:4A:49:88:CF:EF:42:15:DA:20:D4:8C:2B:41:D7:15:29:D7:C9:00:F5:70:92:6F:27:7C:C2:30:C5', 'cacert.org');
fp_host_alt.set('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
fp_host_alt.set('B1:07:B3:3F:45:3E:55:10:F6:8E:51:31:10:C6:F6:94:4B:AC:C2:63:DF:01:37:F8:21:C1:B3:C2:F8:F8:63:D2', 'us'); // whytf does the DoD have so many roots, and why was this one never cross-signed?
fp_host_alt.set('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', 'gov'); // fpki.gov
fp_host_alt.set('B1:07:B3:3F:45:3E:55:10:F6:8E:51:31:10:C6:F6:94:4B:AC:C2:63:DF:01:37:F8:21:C1:B3:C2:F8:F8:63:D2', 'gov'); // whytf does the DoD have so many roots, and why was this one never cross-signed?
host_country.set('cacert.org', 'nl');
host_country.set('gov', 'us');

//Record the SHA-256 Fingerprint -> (reduced) hostname mappings
//As well as non-idiopathic SHA-256 Fingerprint -> country mappings
// Record the Fingerprint -> (reduced) hostname mappings
// As well as non-idiopathic Fingerprint -> country mappings
getAsset("db/IncludedCACertificateReport.json", "json")
.filter(ca => new Set(ca['Trust Bits'].split(';')).has('Websites'))
.forEach(ca => {
Expand All @@ -48,13 +50,13 @@ getAsset("db/IncludedCACertificateReport.json", "json")
fp_host.set(fp, host);

let country = identifyCountry(host);
if( country ) host_country.get(host) = country;
if( country ) host_country.set(host, country);
});

//Apply idiopathic country mappings
Object.entries(getAsset("db/host_cityStateCountry.json","json"))
.forEach(([host, [city, state, country]]) => {
if( host in host_country ) {
if( host_country.has(host) ) {
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,
Expand Down
111 changes: 111 additions & 0 deletions src/js/oop.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
class SecurityDetails {
constructor(requestDetails,securityInfo) {
this.securityInfo = securityInfo;
this.requestDetails = requestDetails;

Object.freeze(this.securityInfo);
Object.freeze(this.requestDetails);

//lazily-evaluated:
this._secType=undefined;
this._caId=undefined;
}

get secType() {
if( this._secType === undefined ) {
this._secType = SecurityDetails.identifySecType(this.securityInfo);
}
return this._secType;
}

get caId() {
if( this._caId === undefined ) {
this._caId = SecurityDetails.identifyCaId(this.securityInfo);
}
return this._caId;
}

static 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':
// ANY HTTPS-secured connection //

const certChain=securityInfo.certificates;

//If it's length-0 -OR- somehow undefined/null/etc
if(!( certChain.length >= 1 )) {
//TODO/FIXME: Mozilla doesn't provide
//any access whatsoever to self-signed
//or otherwise nominally-invalid certs
// https://bugzilla.mozilla.org/show_bug.cgi?id=1678492
return secTypes.unknown;
} else if( certChain.length == 1 ) {

return secTypes.selfSigned;
}

const 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(fp_host_alt.has(rootCert.fingerprint[fp_alg])) {
return secTypes.aRootKnown;
} else {
return secTypes.aRootUnknown;
}
}
}
default:
throw {status:'thisShouldNeverHappen',securityInfo:securityInfo};
}
} catch(e) {
console.error(e.status||e,{securityInfo:securityInfo});
return secTypes.unknown;
}
}

static identifyCaId(securityInfo) {
try {
const certChain = securityInfo.certificates;
if( ! certChain.length ) {
return null;
} else if( certChain.length == 1 ) {
return 'self';
} else {
const rootCert = certChain[certChain.length-1];
const fp = rootCert.fingerprint[fp_alg];
if( fp_host.has(fp) ){
return fp_host.get(fp);
} else if( fp_host_alt.has(fp) ){
return fp_host_alt.get(fp);
} else {
console.warn('Unknown CA',certChain);
return fp;
}
}
throw {status:'thisShouldNeverHappen',securityInfo:securityInfo};
} catch(e) {
console.error(e.status||e,{securityInfo:securityInfo});
return null;
}
}
}
153 changes: 10 additions & 143 deletions src/js/util.js
Original file line number Diff line number Diff line change
@@ -1,117 +1,5 @@
browser.browserAction.disable();//This should be greyed-out by default

class SecurityDetails {
constructor(requestDetails,securityInfo) {
this.securityInfo = securityInfo;
this.requestDetails = requestDetails;

Object.freeze(this.securityInfo);
Object.freeze(this.requestDetails);

//lazily-evaluated:
this._secType=undefined;
this._caId=undefined;
}

get secType() {
if( this._secType === undefined ) {
this._secType = SecurityDetails.identifySecType(this.securityInfo);
}
return this._secType;
}

get caId() {
if( this._caId === undefined ) {
this._caId = SecurityDetails.identifyCaId(this.securityInfo);
}
return this._caId;
}

static 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':
// ANY HTTPS-secured connection //

const certChain=securityInfo.certificates;

//If it's length-0 -OR- somehow undefined/null/etc
if(!( certChain.length >= 1 )) {
//TODO/FIXME: Mozilla doesn't provide
//any access whatsoever to self-signed
//or otherwise nominally-invalid certs
// https://bugzilla.mozilla.org/show_bug.cgi?id=1678492
return secTypes.unknown;
} else if( certChain.length == 1 ) {

return secTypes.selfSigned;
}

const 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[fp_alg] in fp_host_alt) {
return secTypes.aRootKnown;
} else {
return secTypes.aRootUnknown;
}
}
}
default:
throw {status:'thisShouldNeverHappen',securityInfo:securityInfo};
}
} catch(e) {
console.error(e.status||e,{securityInfo:securityInfo});
return secTypes.unknown;
}
}

static identifyCaId(securityInfo) {
try {
const certChain = securityInfo.certificates;
if( ! certChain.length ) {
return null;
} else if( certChain.length == 1 ) {
return 'self';
} else {
const rootCert = certChain[certChain.length-1];
const fp = rootCert.fingerprint[fp_alg];
if( fp in fp_host){
return fp_host.get(fp);
} else if( fp_host_alt.has(fp) ){
return fp_host_alt.get(fp);
} else {
console.warn('Unknown CA',certChain);
return fp;
}
}
throw {status:'thisShouldNeverHappen',securityInfo:securityInfo};
} catch(e) {
console.error(e.status||e,{securityInfo:securityInfo});
return null;
}
}
}

function getAsset(path,type=null){
const assetURL = browser.runtime.getURL(path);
const xhr = new XMLHttpRequest();
Expand All @@ -132,12 +20,12 @@ function flag(s){
return String.fromCodePoint(...s.split('').map(u=>u.codePointAt()+127365));
}

function removeFragment(url){
function urldefrag(url){
//Removes the fragment from a URL
//TODO? iff profiler indicts this function:
// return url.match(/^[^#]*/)[0];
let u=new URL(url);
u.hash="";
let u = new URL(url);
u.hash = "";
return u.toString();
}

Expand All @@ -152,7 +40,7 @@ function genBrowserActionSpec(secType=null, caId=null){
case secTypes.Mozilla:
return {
Icon: {path: `images/root_icons/${caId}.ico`},
Title: {title: `${flag(host_country.get(caId)||'XX')} ${caId}\n(Mozilla-trusted Root CA)`},
Title: {title: `${flag(identifyCountry(caId)||'XX')} ${caId}\n(Mozilla-trusted Root CA)`},
BadgeText: {text: '\uD83E\uDD8A'},
BadgeBackgroundColor: {color: 'LimeGreen'}
};
Expand All @@ -166,8 +54,8 @@ function genBrowserActionSpec(secType=null, caId=null){
case secTypes.aRootKnown:
return {
Icon: {path: `images/alt_root_icons/${caId}.ico`},
Title: {title: `${caId}\n(Alternative Root CA)`},
BadgeText: {text: rootHost[0].toUpperCase()}, //TODO
Title: {title: `${flag(identifyCountry(caId)||'XX')} ${caId}\n(Alternative Root CA)`},
BadgeText: {text: caId[0]}, //TODO
BadgeBackgroundColor: {color: 'Teal'}
};
case secTypes.aRootUnknown:
Expand Down Expand Up @@ -269,36 +157,15 @@ function match0(s,r){

function identifyCountry(hostname, only_gov=false){
const h = hostname.split ? hostname.split('.') : hostname;
if( host_country.has(h.join('.')) ) return host_country.get(h.join('.'));
const len = h.length;
const tld = len >= 1 ? h[len-1] : null;
const sld = len >= 2 ? h[len-2] : null;

if( only_gov && sld != 'gov' && tld != 'gov' ) return null;

if( country_tld_exceptions.has(tld) ) return country_tld_exceptions.get(tld);
else return null;
if( only_gov && sld != 'gov' ) return null;
if
switch( match0(tld,exceptionRe) ) {
case 'uk':

return 'gb';
case 'ac':

return 'sh';
case 'gov':

return 'us';
case null:
//2-letter TLD *not* in the exception list;
//it's a valid ccTLD corresponding to its country
return tld;
default:
//2-letter TLD *in* the exception list (e.g.: .eu);
//it's not a valid ccTLD and we don't know the country
return null;
}
} else {
return null;
}
else if( tld.length == 2 ) return tld;
}

function reduceHostname(hostname){
Expand Down
2 changes: 1 addition & 1 deletion src/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"manifest_version": 2,
"name": "cerdicator",
"version": "0.0.12",
"version": "0.1.0",

"description": "Enhanced TLS indicator with an emphasis on information about the Root Certificate Authority from which the connection's authenticity is derived.",

Expand Down

0 comments on commit 3a9048c

Please sign in to comment.