mirror of
https://github.com/tlsnotary/PageSigner.git
synced 2026-01-09 14:48:07 -05:00
make compatible with pagesigner-cli
This commit is contained in:
@@ -43,16 +43,19 @@ class FakeFS{
|
||||
// All future invocations of Pagesigner use these serialized cached circuits.
|
||||
export class FirstTimeSetup{
|
||||
async start(pm){
|
||||
const worker = new Worker(chrome.extension.getURL('core/twopc/webWorkers/serializeCircuits.js'));
|
||||
console.log('parsing circuits, this is done only once on first launch and will take ~30 secs');
|
||||
console.time('parsing raw circuits');
|
||||
const url = chrome.extension.getURL('core/twopc/webWorkers/serializeCircuits.js')
|
||||
const worker = new Worker(url);
|
||||
console.log('Parsing circuits. This is done only once on first launch and will take ~30 secs');
|
||||
console.time('time_to_parse');
|
||||
const obj = {};
|
||||
const oldfs = window['fs'];
|
||||
window['fs'] = new FakeFS();
|
||||
await window['fs'].init();
|
||||
if (typeof(window) !== 'undefined') {
|
||||
// we are in the browser; init a fake filesystem
|
||||
window['fs'] = new FakeFS();
|
||||
await window['fs'].init();
|
||||
}
|
||||
// start from the last circuits in order to give the user a quicker initial update
|
||||
for (let n=1; n < 7; n++){
|
||||
const i = 7-n;
|
||||
const i = 7-n;
|
||||
const text = CASM.parseAndAssemble('c'+i+'.casm');
|
||||
const newobj = await new Promise(function(resolve) {
|
||||
worker.onmessage = function(event) {
|
||||
@@ -63,82 +66,10 @@ export class FirstTimeSetup{
|
||||
worker.postMessage({'text': text});
|
||||
});
|
||||
obj[i] = newobj;
|
||||
pm.update('first_time', {'current': n, 'total': 6});
|
||||
if (pm) pm.update('first_time', {'current': n, 'total': 6});
|
||||
await wait(100); // make sure update reaches popup
|
||||
}
|
||||
window['fs'] = oldfs;
|
||||
console.timeEnd('parsing raw circuits');
|
||||
console.timeEnd('time_to_parse');
|
||||
return obj;
|
||||
}
|
||||
|
||||
parseCircuitFirstTime(text){
|
||||
const obj = {};
|
||||
// we don't do any sanity/formatting checks because the circuits
|
||||
// were output by casm.js and have a well-defined structure
|
||||
const rows = text.split('\n');
|
||||
obj['gatesCount'] = Number(rows[0].split(' ')[0]);
|
||||
console.log('obj[\'gatesCount\']', obj['gatesCount']);
|
||||
obj['wiresCount'] = Number(rows[0].split(' ')[1]);
|
||||
obj['notaryInputSize'] = Number(rows[1].split(' ')[1]);
|
||||
obj['clientInputSize'] = Number(rows[1].split(' ')[2]);
|
||||
obj['outputSize'] = Number(rows[2].split(' ')[1]);
|
||||
|
||||
// each gate is serialized as
|
||||
// 1 byte: gate type XOR==0 AND==1 INV==2
|
||||
// 3 bytes: 1st input wire number
|
||||
// 3 bytes: 2nd input wire number
|
||||
// 3 bytes: output wire number
|
||||
const gateByteSize = 10;
|
||||
const opBytes = {'XOR': 0, 'AND': 1, 'INV': 2};
|
||||
// first 3 rows are not gates but metadata
|
||||
const blob = new Uint8Array((rows.length-3)*gateByteSize);
|
||||
let blobOffset = 0;
|
||||
let andCount = 0;
|
||||
for (let i=0; i < (rows.length-3); i++){
|
||||
const gate = rows[3+i];
|
||||
const tokens = gate.split(' ');
|
||||
const op = tokens[tokens.length-1];
|
||||
const opByte = opBytes[op];
|
||||
blob.set([opByte], blobOffset);
|
||||
blobOffset+=1;
|
||||
if (op === 'XOR' || op === 'AND'){
|
||||
const in1 = this.intToThreeBytes(tokens[tokens.length-4]);
|
||||
const in2 = this.intToThreeBytes(tokens[tokens.length-3]);
|
||||
const out = this.intToThreeBytes(tokens[tokens.length-2]);
|
||||
blob.set(in1, blobOffset);
|
||||
blobOffset+=3;
|
||||
blob.set(in2, blobOffset);
|
||||
blobOffset+=3;
|
||||
blob.set(out, blobOffset);
|
||||
blobOffset+=3;
|
||||
if (op == 'AND'){
|
||||
andCount+=1;
|
||||
}
|
||||
}
|
||||
else if (op === 'INV'){
|
||||
const in1 = this.intToThreeBytes(tokens[tokens.length-3]);
|
||||
const out = this.intToThreeBytes(tokens[tokens.length-2]);
|
||||
blob.set(in1, blobOffset);
|
||||
blobOffset+=3;
|
||||
blob.set([0,0,0], blobOffset);
|
||||
blobOffset+=3;
|
||||
blob.set(out, blobOffset);
|
||||
blobOffset+=3;
|
||||
}
|
||||
else {
|
||||
throw('unknown op');
|
||||
}
|
||||
}
|
||||
obj['andGateCount'] = andCount;
|
||||
obj['gatesBlob'] = blob;
|
||||
return obj;
|
||||
}
|
||||
|
||||
intToThreeBytes(i){
|
||||
const byteArray = Array(3);
|
||||
byteArray[0] = (i >> 16) & 0xFF;
|
||||
byteArray[1] = (i >> 8) & 0xFF;
|
||||
byteArray[2] = i & 0xFF;
|
||||
return byteArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
88
core/Main.js
88
core/Main.js
@@ -1,20 +1,19 @@
|
||||
/* eslint-disable no-import-assign */
|
||||
/* eslint-disable no-case-declarations */
|
||||
import {parse_certs, verifyChain, checkCertSubjName, getCommonName, getAltNames} from './verifychain.js';
|
||||
import {ba2str, b64decode, concatTA, int2ba, sha256, b64encode, str2ba, verifySig, assert,
|
||||
ba2int, getTime, dechunk_http, gunzip_http, xor, eq, wait, AESECBencrypt, wildcardTest,
|
||||
pubkeyPEM2raw, ba2hex} from './utils.js';
|
||||
import {getPref, getSessionBlob, getSession, getAllSessions, saveNewSession as saveNewSession, init_db,
|
||||
import {parse_certs, verifyChain, getCommonName, getAltNames} from './verifychain.js';
|
||||
import {ba2str, b64decode, concatTA, int2ba, sha256, b64encode, verifySig, assert,
|
||||
ba2int, xor, eq, wait, AESECBencrypt, wildcardTest, pubkeyPEM2raw, import_resource} from './utils.js';
|
||||
import {getPref, getSessionBlob, getSession, getAllSessions, saveNewSession, init_db,
|
||||
addNewPreference, setPref, renameSession, deleteSession} from './indexeddb.js';
|
||||
import {global} from './globals.js';
|
||||
import {globals} from './globals.js';
|
||||
import {Socket} from './Socket.js';
|
||||
import {TLS, getExpandedKeys, decrypt_tls_responseV6} from './TLS.js';
|
||||
import {verify_oracle as verifyNotary, getURLFetcherDoc} from './oracles.js';
|
||||
import {verifyNotary, getURLFetcherDoc} from './oracles.js';
|
||||
import {TLSNotarySession} from './TLSNotarySession.js';
|
||||
import {ProgressMonitor} from './ProgressMonitor.js';
|
||||
import {FirstTimeSetup} from './FirstTimeSetup.js';
|
||||
|
||||
class Main{
|
||||
export class Main{
|
||||
constructor(){
|
||||
this.messageListener;
|
||||
this.notarization_in_progress = false;
|
||||
@@ -31,13 +30,15 @@ class Main{
|
||||
// trustedOracle is an object {'IP':<IP address>, 'pubkeyPEM':<pubkey in PEM format>}
|
||||
// describing the oracle server which was verified and can be used for notarization.
|
||||
this.trustedOracle = null;
|
||||
this.is_chrome = window.navigator.userAgent.match('Chrome') ? true : false;
|
||||
this.is_firefox = window.navigator.userAgent.match('Firefox') ? true : false;
|
||||
this.is_edge = window.navigator.userAgent.match('Edg') ? true : false;
|
||||
this.is_opera = window.navigator.userAgent.match('OPR') ? true : false;
|
||||
// pm is the only instance of ProgressMonitor that is reused between
|
||||
// notarization sesions
|
||||
this.pm = new ProgressMonitor();
|
||||
if (typeof(window) != 'undefined') {
|
||||
this.is_chrome = window.navigator.userAgent.match('Chrome') ? true : false;
|
||||
this.is_firefox = window.navigator.userAgent.match('Firefox') ? true : false;
|
||||
this.is_edge = window.navigator.userAgent.match('Edg') ? true : false;
|
||||
this.is_opera = window.navigator.userAgent.match('OPR') ? true : false;
|
||||
// pm is the only instance of ProgressMonitor that is reused between
|
||||
// notarization sesions
|
||||
this.pm = new ProgressMonitor();
|
||||
}
|
||||
// trustedOracleReady will be set to true after we performed AWS HTTP queries
|
||||
// and verified that an oracle is trusted (we verify only once)
|
||||
this.trustedOracleReady = false;
|
||||
@@ -46,7 +47,7 @@ class Main{
|
||||
async main() {
|
||||
// perform browser-specific init first
|
||||
if (this.is_edge || this.is_firefox || this.is_opera){
|
||||
global.usePythonBackend = true;
|
||||
globals.usePythonBackend = true;
|
||||
}
|
||||
if (this.is_firefox){
|
||||
// Firefox asks user for permission to access the current website.
|
||||
@@ -84,9 +85,13 @@ class Main{
|
||||
if (await getPref('trustedOracle') === null){
|
||||
await addNewPreference('trustedOracle', {});
|
||||
}
|
||||
await parse_certs();
|
||||
if (global.useNotaryNoSandbox){
|
||||
await this.queryNotaryNoSandbox(global.defaultNotaryIP);
|
||||
const text = await import_resource('core/third-party/certs.txt');
|
||||
await parse_certs(text);
|
||||
if (globals.useNotaryNoSandbox){
|
||||
const obj = await this.queryNotaryNoSandbox(globals.defaultNotaryIP);
|
||||
this.trustedOracle = obj;
|
||||
this.trustedOracleReady = true;
|
||||
await setPref('trustedOracle', obj);
|
||||
return;
|
||||
}
|
||||
this.trustedOracle = await getPref('trustedOracle');
|
||||
@@ -100,17 +105,17 @@ class Main{
|
||||
return;
|
||||
}
|
||||
// on first launch trustedOracle is not set, verify the default one asynchronously
|
||||
if (await this.pingNotary(global.defaultNotaryIP) !== true){
|
||||
await this.tryBackupNotary(global.defaultNotaryIP);
|
||||
if (await this.pingNotary(globals.defaultNotaryIP) !== true){
|
||||
await this.tryBackupNotary(globals.defaultNotaryIP);
|
||||
return;
|
||||
}
|
||||
// notary is online
|
||||
const URLFetcherDoc = await getURLFetcherDoc(global.defaultNotaryIP);
|
||||
const URLFetcherDoc = await getURLFetcherDoc(globals.defaultNotaryIP, globals.defaultNotaryPort);
|
||||
const trustedPubkeyPEM = await verifyNotary(URLFetcherDoc);
|
||||
assert(trustedPubkeyPEM != undefined);
|
||||
// verification was successful
|
||||
const obj = {
|
||||
'IP': global.defaultNotaryIP,
|
||||
'IP': globals.defaultNotaryIP,
|
||||
'pubkeyPEM': trustedPubkeyPEM,
|
||||
'URLFetcherDoc': URLFetcherDoc
|
||||
};
|
||||
@@ -121,25 +126,22 @@ class Main{
|
||||
|
||||
async queryNotaryNoSandbox(IP){
|
||||
// just fetch the pubkey and trust it
|
||||
const resp = await fetch('http://'+IP+':' + global.defaultNotaryPort + '/getPubKey', {
|
||||
const resp = await fetch('http://'+IP+':' + globals.defaultNotaryPort + '/getPubKey', {
|
||||
method: 'POST',
|
||||
mode: 'cors',
|
||||
cache: 'no-store',
|
||||
});
|
||||
const trustedPubkeyPEM = await resp.text();
|
||||
const obj = {
|
||||
return {
|
||||
'IP': IP,
|
||||
'pubkeyPEM': trustedPubkeyPEM,
|
||||
};
|
||||
await setPref('trustedOracle', obj);
|
||||
this.trustedOracle = obj;
|
||||
this.trustedOracleReady = true;
|
||||
}
|
||||
|
||||
// pingNotary returns true if notary's IP address is reachable
|
||||
async pingNotary(IP){
|
||||
// ping the notary, it should respond with 404 not found
|
||||
const fProm = fetch('http://'+IP+':'+ global.defaultNotaryPort + '/ping', {
|
||||
const fProm = fetch('http://'+IP+':'+ globals.defaultNotaryPort + '/ping', {
|
||||
mode: 'no-cors'
|
||||
});
|
||||
const out = await Promise.race([fProm, wait(5000)])
|
||||
@@ -156,7 +158,7 @@ class Main{
|
||||
// tryBackupNotary tries to use a backup notary. It checks that the backup notary
|
||||
// is not the same as failedNotaryIP
|
||||
async tryBackupNotary(failedNotaryIP){
|
||||
const resp = await fetch(global.backupUrl);
|
||||
const resp = await fetch(globals.backupUrl);
|
||||
const backupIP = await resp.text();
|
||||
if (backupIP === failedNotaryIP){
|
||||
throw('Notary is unreachable. Please let the Pagesigner devs know about this.');
|
||||
@@ -165,7 +167,7 @@ class Main{
|
||||
console.log('Backup notary is unreachable.');
|
||||
throw('Notary is unreachable. Please let the Pagesigner devs know about this.');
|
||||
}
|
||||
const URLFetcherDoc = await getURLFetcherDoc(backupIP);
|
||||
const URLFetcherDoc = await getURLFetcherDoc(backupIP, globals.defaultNotaryPort);
|
||||
const trustedPubkeyPEM = await verifyNotary(URLFetcherDoc);
|
||||
assert(trustedPubkeyPEM != undefined);
|
||||
const obj = {
|
||||
@@ -458,7 +460,7 @@ class Main{
|
||||
x.splice(0, 3);
|
||||
const resource_url = x.join('/');
|
||||
|
||||
const http_version = global.useHTTP11 ? ' HTTP/1.1':' HTTP/1.0';
|
||||
const http_version = globals.useHTTP11 ? ' HTTP/1.1':' HTTP/1.0';
|
||||
let headers = obj.method + ' /' + resource_url + http_version + '\r\n';
|
||||
// Chrome doesnt add Host header. Firefox does
|
||||
if (this.is_chrome){
|
||||
@@ -604,11 +606,11 @@ class Main{
|
||||
}
|
||||
const circuits = await getPref('parsedCircuits');
|
||||
const session = new TLSNotarySession(
|
||||
server, port, headers, this.trustedOracle, global.sessionOptions, circuits, this.pm);
|
||||
server, port, headers, this.trustedOracle, globals.sessionOptions, circuits, this.pm);
|
||||
const obj = await session.start();
|
||||
obj['title'] = 'PageSigner notarization file';
|
||||
obj['version'] = 6;
|
||||
if (! global.useNotaryNoSandbox){
|
||||
if (! globals.useNotaryNoSandbox){
|
||||
obj['URLFetcher attestation'] = this.trustedOracle.URLFetcherDoc;
|
||||
}
|
||||
const [host, request, response, date] = await this.verifyPgsgV6(obj);
|
||||
@@ -704,7 +706,7 @@ class Main{
|
||||
assert(obj['version'] === 6);
|
||||
|
||||
// Step 1. Verify URLFetcher attestation doc and get notary's pubkey
|
||||
if (! global.useNotaryNoSandbox){
|
||||
if (! globals.useNotaryNoSandbox){
|
||||
// by default we verify that the notary is indeed a properly sandboxed machine
|
||||
var URLFetcherDoc = obj['URLFetcher attestation'];
|
||||
var notaryPubkey = await verifyNotary(URLFetcherDoc);
|
||||
@@ -844,9 +846,7 @@ class Main{
|
||||
const responseRecords = await decrypt_tls_responseV6(
|
||||
obj['server response records'], swk, siv);
|
||||
const response = ba2str(concatTA(...responseRecords));
|
||||
console.log(response);
|
||||
return [host, request, response, date.toGMTString()];
|
||||
|
||||
return [host, request, response, date.toGMTString()];
|
||||
}
|
||||
|
||||
async importPgsgAndShow(importedData) {
|
||||
@@ -1045,8 +1045,8 @@ class Main{
|
||||
}
|
||||
|
||||
async useNotaryNoSandbox(IP){
|
||||
global.defaultNotaryIP = IP;
|
||||
global.useNotaryNoSandbox = true;
|
||||
globals.defaultNotaryIP = IP;
|
||||
globals.useNotaryNoSandbox = true;
|
||||
await this.queryNotaryNoSandbox(IP);
|
||||
}
|
||||
}
|
||||
@@ -1062,12 +1062,4 @@ if (typeof(window) != 'undefined') {
|
||||
text: err
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (typeof module !== 'undefined'){ // we are in node.js environment
|
||||
module.exports={
|
||||
save_session,
|
||||
verifyPgsg
|
||||
};
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
// We do not communicate directly with the server but we send messages to the helper app
|
||||
// It is the helper app which opens a TCP socket and sends/receives data
|
||||
|
||||
import {global} from './globals.js';
|
||||
import {globals} from './globals.js';
|
||||
import {ba2str, b64decode, concatTA, b64encode, str2ba, ba2int} from './utils.js';
|
||||
|
||||
export class Socket {
|
||||
@@ -42,7 +42,7 @@ export class Socket {
|
||||
}, that.connectTimeout);
|
||||
|
||||
const msg = {'command': 'connect','args': {'name': that.name,'port': that.port},'uid': that.uid};
|
||||
if (global.usePythonBackend){
|
||||
if (globals.usePythonBackend){
|
||||
const url = 'http://127.0.0.1:' + that.backendPort;
|
||||
const payload = JSON.stringify(msg);
|
||||
try{
|
||||
@@ -58,7 +58,7 @@ export class Socket {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
chrome.runtime.sendMessage(global.appId, msg, function(response) {resolve(response);});
|
||||
chrome.runtime.sendMessage(globals.appId, msg, function(response) {resolve(response);});
|
||||
}
|
||||
})
|
||||
.catch(function(e){
|
||||
@@ -87,13 +87,13 @@ export class Socket {
|
||||
|
||||
async send(data_in) {
|
||||
var msg = {'command': 'send', 'args': {'data': Array.from(data_in)}, 'uid': this.uid};
|
||||
if (global.usePythonBackend){
|
||||
if (globals.usePythonBackend){
|
||||
msg.args.data = Array.from(b64encode(msg.args.data));
|
||||
await fetch('http://127.0.0.1:20022', {method:'POST', body: JSON.stringify(msg),
|
||||
cache: 'no-store'});
|
||||
}
|
||||
else{
|
||||
chrome.runtime.sendMessage(global.appId, msg);
|
||||
chrome.runtime.sendMessage(globals.appId, msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ export class Socket {
|
||||
var that = this;
|
||||
var response = await new Promise(async function(resolve){
|
||||
var msg = {'command': 'recv', 'uid': that.uid};
|
||||
if (global.usePythonBackend){
|
||||
if (globals.usePythonBackend){
|
||||
var req = await fetch('http://127.0.0.1:20022', {method:'POST', body: JSON.stringify(msg),
|
||||
cache: 'no-store'});
|
||||
var text = new Uint8Array(await req.arrayBuffer());
|
||||
@@ -116,7 +116,7 @@ export class Socket {
|
||||
resolve(response);
|
||||
}
|
||||
else {
|
||||
chrome.runtime.sendMessage(global.appId, msg, function(response) {resolve(response);});
|
||||
chrome.runtime.sendMessage(globals.appId, msg, function(response) {resolve(response);});
|
||||
}
|
||||
});
|
||||
if (response.data.length > 0){
|
||||
@@ -130,11 +130,8 @@ export class Socket {
|
||||
|
||||
// fetchLoop has built up the recv buffer
|
||||
// check if there are complete records in the buffer,return them if yes or wait some more if no
|
||||
recv (is_handshake) {
|
||||
if (is_handshake == undefined) {
|
||||
is_handshake = false;
|
||||
}
|
||||
var that = this;
|
||||
recv (is_handshake = false) {
|
||||
const that = this;
|
||||
return new Promise(function(resolve, reject) {
|
||||
var dataLastSeen = new Date().getTime();
|
||||
var complete_records = new Uint8Array();
|
||||
@@ -179,7 +176,7 @@ export class Socket {
|
||||
const rv = that.check_complete_records(buf);
|
||||
complete_records = concatTA(complete_records, rv.comprecs);
|
||||
if (!rv.is_complete) {
|
||||
console.log('check_complete_records failed', that.uid);
|
||||
console.log('waiting for complete records...', that.uid);
|
||||
buf = rv.incomprecs;
|
||||
setTimeout(function() {check();}, 100);
|
||||
return;
|
||||
@@ -210,12 +207,12 @@ export class Socket {
|
||||
this.wasClosed = true;
|
||||
var msg = {'command': 'close','uid': this.uid};
|
||||
console.log('closing socket', this.uid);
|
||||
if (global.usePythonBackend){
|
||||
if (globals.usePythonBackend){
|
||||
await fetch('http://127.0.0.1:20022', {method:'POST', body: JSON.stringify(msg),
|
||||
cache: 'no-store'});
|
||||
}
|
||||
else {
|
||||
chrome.runtime.sendMessage(global.appId, msg);
|
||||
chrome.runtime.sendMessage(globals.appId, msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
24
core/TLS.js
24
core/TLS.js
@@ -1,8 +1,5 @@
|
||||
import {TWOPC} from './twopc/TWOPC.js';
|
||||
import {global} from './globals.js';
|
||||
import {ba2str, b64decode, concatTA, int2ba, sha256, b64encode, str2ba, assert,
|
||||
ba2int, dechunk_http, gunzip_http, getRandom, sigDER2p1363, pubkeyPEM2raw, eq,
|
||||
xor, AESECBencrypt, buildChunkMetadata, b64urlencode} from './utils.js';
|
||||
import {concatTA, int2ba, sha256, str2ba, assert, ba2int, getRandom, sigDER2p1363,
|
||||
pubkeyPEM2raw, eq, xor, AESECBencrypt, b64urlencode} from './utils.js';
|
||||
import {verifyChain, checkCertSubjName} from './verifychain.js';
|
||||
import {Socket} from './Socket.js';
|
||||
|
||||
@@ -44,7 +41,12 @@ export class TLS {
|
||||
this.useMaxFragmentLength = options.useMaxFragmentLength;
|
||||
this.notaryWillEncryptRequest = options.notaryWillEncryptRequest;
|
||||
this.mustVerifyCert = options.mustVerifyCert;
|
||||
this.sckt = new Socket(serverName, port);
|
||||
if (typeof(window) !== 'undefined'){
|
||||
this.sckt = new Socket(serverName, port);
|
||||
} else {
|
||||
// in node SocketNode was made global
|
||||
this.sckt = new SocketNode(serverName, port);
|
||||
}
|
||||
}
|
||||
|
||||
buildClientHello(){
|
||||
@@ -614,14 +616,4 @@ export async function getExpandedKeys(preMasterSecret, cr, sr){
|
||||
const client_write_IV = ek.slice(32, 36);
|
||||
const server_write_IV = ek.slice(36, 40);
|
||||
return [client_write_key, server_write_key, client_write_IV, server_write_IV, MS_CryptoKey];
|
||||
}
|
||||
|
||||
|
||||
if (typeof module !== 'undefined'){ // we are in node.js environment
|
||||
module.exports={
|
||||
computeCommitHash,
|
||||
decrypt_tls_responseV5,
|
||||
start_audit,
|
||||
getExpandedKeys
|
||||
};
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import {TWOPC} from './twopc/TWOPC.js';
|
||||
import {TLS} from './TLS.js';
|
||||
import {concatTA, sha256, assert, eq, xor, str2ba, pubkeyPEM2raw} from './utils.js';
|
||||
import {concatTA, sha256, assert, xor, str2ba} from './utils.js';
|
||||
|
||||
|
||||
// class TLSNotarySession impements one notarization session
|
||||
@@ -17,7 +17,7 @@ export class TLSNotarySession{
|
||||
request;
|
||||
notary;
|
||||
pm;
|
||||
constructor(server, port, request, notary, sessionOptions, circuits, progressMonitor){
|
||||
constructor(server, port, request, notary, sessionOptions, circuits, progressMonitor){
|
||||
this.twopc = new TWOPC(notary, request.length, circuits, progressMonitor);
|
||||
this.tls = new TLS(server, port, request, sessionOptions);
|
||||
this.probeTLS = new TLS(server, port, request, sessionOptions);
|
||||
@@ -35,9 +35,9 @@ export class TLSNotarySession{
|
||||
const serverEcPubkey = await this.tls.receiveAndParseServerHello();
|
||||
const serverX = serverEcPubkey.slice(1,33);
|
||||
const serverY = serverEcPubkey.slice(33,65);
|
||||
this.pm.update('last_stage', {'current': 3, 'total': 10});
|
||||
if ( this.pm) this.pm.update('last_stage', {'current': 3, 'total': 10});
|
||||
const [pmsShare, cpubBytes] = await this.twopc.getECDHShare(serverX, serverY);
|
||||
this.pm.update('last_stage', {'current': 4, 'total': 10});
|
||||
if ( this.pm) this.pm.update('last_stage', {'current': 4, 'total': 10});
|
||||
|
||||
await this.tls.buildClientKeyExchange(cpubBytes);
|
||||
const [cr, sr] = await this.tls.getRandoms();
|
||||
@@ -47,13 +47,13 @@ export class TLSNotarySession{
|
||||
await this.tls.sendClientFinished(encCF, tagCF);
|
||||
const encSF = await this.tls.receiveServerFinished();
|
||||
await this.twopc.checkServerFinished(encSF, this.tls.getAllHandshakes());
|
||||
this.pm.update('last_stage', {'current': 5, 'total': 10});
|
||||
if ( this.pm) this.pm.update('last_stage', {'current': 5, 'total': 10});
|
||||
|
||||
const encCountersForRequest = await this.twopc.getEncryptedCounters();
|
||||
this.pm.update('last_stage', {'current': 9, 'total': 10});
|
||||
if ( this.pm) this.pm.update('last_stage', {'current': 9, 'total': 10});
|
||||
const encRequestBlocks = this.encryptRequest(this.request, encCountersForRequest);
|
||||
const gctrBlocks = await this.twopc.getGctrBlocks();
|
||||
this.pm.update('last_stage', {'current': 10, 'total': 10});
|
||||
if ( this.pm) this.pm.update('last_stage', {'current': 10, 'total': 10});
|
||||
const [ghashOutputs, ghashInputsBlob] = await this.twopc.getTagFromPowersOfH(encRequestBlocks);
|
||||
await this.tls.buildAndSendRequest(gctrBlocks, ghashOutputs, encRequestBlocks);
|
||||
const serverRecords = await this.tls.receiveServerResponse();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const global = {
|
||||
export const globals = {
|
||||
// defaultNotaryIP/Port is the default IP address/port of the notary server.
|
||||
// If this IP address becomes unavailable, Pagesigner will query backupUrl for
|
||||
// a new notary's IP address and will save the new IP address in the preferences.
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import {global} from './globals.js';
|
||||
import {ba2str, b64decode, assert, ba2int, verifyAttestationDoc, ba2hex, eq,
|
||||
sha256} from './utils.js';
|
||||
|
||||
@@ -224,11 +223,11 @@ async function fetch_and_parse(obj){
|
||||
return xmlDoc;
|
||||
}
|
||||
|
||||
export async function getURLFetcherDoc(IP){
|
||||
export async function getURLFetcherDoc(IP, port = 10011){
|
||||
// get URLFetcher document containing attestation for AWS HTTP API URLs needed to
|
||||
// verify that the oracle was correctly set up.
|
||||
// https://github.com/tlsnotary/URLFetcher
|
||||
const resp = await fetch('http://' + IP + ':' + global.defaultNotaryPort + '/getURLFetcherDoc', {
|
||||
const resp = await fetch('http://' + IP + ':' + port + '/getURLFetcherDoc', {
|
||||
method: 'POST',
|
||||
mode: 'cors',
|
||||
cache: 'no-store',
|
||||
@@ -236,7 +235,7 @@ export async function getURLFetcherDoc(IP){
|
||||
return new Uint8Array(await resp.arrayBuffer());
|
||||
}
|
||||
|
||||
export async function verify_oracle(URLFetcherDoc) {
|
||||
export async function verifyNotary(URLFetcherDoc) {
|
||||
// URLFetcherDoc is a concatenation of 4-byte transcript length | transcript | attestation doc
|
||||
const transcriptLen = ba2int(URLFetcherDoc.slice(0,4));
|
||||
const transcript = URLFetcherDoc.slice(4,4+transcriptLen);
|
||||
|
||||
4
core/third-party/SOURCES.third-party
vendored
4
core/third-party/SOURCES.third-party
vendored
@@ -13,7 +13,7 @@ sed -i 's#from "bytestreamjs"#from "./bytestream.js"#g' *
|
||||
|
||||
|
||||
bigint-crypto-utils.esm.js from
|
||||
https://github.com/juanelas/bigint-crypto-utils/tree/954321199d4a8038c3d27113aec825ff2e5bf544/dist/bundles
|
||||
https://github.com/juanelas/bigint-crypto-utils/tree/954321199d4a8038c3d27113aec825ff2e5bf544/dist/bundles -> math.js
|
||||
|
||||
https://github.com/Azero123/simple-js-ec-math
|
||||
browserify simple-js-ec-math/src/index.js --standalone ECSimple > simple-js-ec-math.js
|
||||
@@ -24,7 +24,7 @@ cbor.js and cose.js are used to verify the enclave attestation document
|
||||
cbor.js is from https://github.com/paroga/cbor-js/blob/master/cbor.js
|
||||
cose.js was built with browserify coseverify.js --standalone COSE > cose.js
|
||||
|
||||
pako.js ---> SOURCE???
|
||||
https://github.com/jedisct1/libsodium.js/blob/354ec814b92e2e5ba0471e9a8a96c1e21c30f171/dist/browsers-sumo/sodium.js --> sodium.js
|
||||
|
||||
certs.txt is Mozilla'a root store taken from
|
||||
https://ccadb-public.secure.force.com/mozilla/IncludedCACertificateReportPEMCSV
|
||||
|
||||
76
core/third-party/chacha.js
vendored
76
core/third-party/chacha.js
vendored
@@ -1,76 +0,0 @@
|
||||
/* This is free and unencumbered software released into the public domain. */
|
||||
"use strict";
|
||||
const CHACHA_ROUNDS = 20;
|
||||
const CHACHA_KEYSIZE = 32;
|
||||
const CHACHA_IVSIZE = 8;
|
||||
|
||||
/**
|
||||
* Create a new ChaCha generator seeded from the given KEY and IV.
|
||||
* Both KEY and IV must be ArrayBuffer objects of at least the
|
||||
* appropriate byte lengths (CHACHA_KEYSIZE, CHACHA_IVSIZE). Bytes
|
||||
* beyond the specified length are ignored.
|
||||
*
|
||||
* Returns a closure that takes no arguments. This closure, when
|
||||
* invoked, returns a 64-byte ArrayBuffer of the next 64 bytes of
|
||||
* output. Note: This buffer object is "owned" by the closure, and
|
||||
* the same buffer object is always returned, each time filled with
|
||||
* fresh output.
|
||||
*/
|
||||
function ChaCha(key, iv) {
|
||||
if (key.byteLength < CHACHA_KEYSIZE)
|
||||
throw new Error('key too short');
|
||||
if (iv.byteLength < CHACHA_IVSIZE)
|
||||
throw new Error('IV too short');
|
||||
const state = new Uint32Array(16);
|
||||
let view = new DataView(key);
|
||||
state[ 0] = 0x61707865; // "expand 32-byte k"
|
||||
state[ 1] = 0x3320646e; //
|
||||
state[ 2] = 0x79622d32; //
|
||||
state[ 3] = 0x6b206574; //
|
||||
state[ 4] = view.getUint32( 0, true);
|
||||
state[ 5] = view.getUint32( 4, true);
|
||||
state[ 6] = view.getUint32( 8, true);
|
||||
state[ 7] = view.getUint32(12, true);
|
||||
state[ 8] = view.getUint32(16, true);
|
||||
state[ 9] = view.getUint32(20, true);
|
||||
state[10] = view.getUint32(24, true);
|
||||
state[11] = view.getUint32(28, true);
|
||||
view = new DataView(iv);
|
||||
state[14] = view.getUint32( 0, true);
|
||||
state[15] = view.getUint32( 4, true);
|
||||
|
||||
/* Generator */
|
||||
const output = new Uint32Array(16);
|
||||
const outview = new DataView(output.buffer);
|
||||
return function() {
|
||||
function quarterround(x, a, b, c, d) {
|
||||
function rotate(v, n) { return (v << n) | (v >>> (32 - n)); }
|
||||
x[a] += x[b]; x[d] = rotate(x[d] ^ x[a], 16);
|
||||
x[c] += x[d]; x[b] = rotate(x[b] ^ x[c], 12);
|
||||
x[a] += x[b]; x[d] = rotate(x[d] ^ x[a], 8);
|
||||
x[c] += x[d]; x[b] = rotate(x[b] ^ x[c], 7);
|
||||
}
|
||||
output.set(state);
|
||||
for (let i = 0; i < CHACHA_ROUNDS; i += 2) {
|
||||
quarterround(output, 0, 4, 8, 12);
|
||||
quarterround(output, 1, 5, 9, 13);
|
||||
quarterround(output, 2, 6, 10, 14);
|
||||
quarterround(output, 3, 7, 11, 15);
|
||||
quarterround(output, 0, 5, 10, 15);
|
||||
quarterround(output, 1, 6, 11, 12);
|
||||
quarterround(output, 2, 7, 8, 13);
|
||||
quarterround(output, 3, 4, 9, 14);
|
||||
}
|
||||
for (let i = 0; i < 16; i++)
|
||||
outview.setUint32(i * 4, output[i] + state[i], true);
|
||||
state[12]++;
|
||||
if (state[12] == 0) {
|
||||
state[13]++;
|
||||
if (state[13] == 0) {
|
||||
/* One zebibyte of output reached! */
|
||||
throw new Error('output exhausted');
|
||||
}
|
||||
}
|
||||
return output.buffer;
|
||||
}
|
||||
}
|
||||
5
core/third-party/coseverify.js
vendored
5
core/third-party/coseverify.js
vendored
@@ -1,10 +1,11 @@
|
||||
// this file is not used by the extension, it serves as an input to to create cose.js with:
|
||||
// browserify coseverify.js --standalone COSE > cose.js
|
||||
|
||||
const cose = require('cose-js');
|
||||
//const cose = require('cose-js');
|
||||
import * as cose from 'cose-js'
|
||||
|
||||
// x,y,doc is an ArrayBuffer
|
||||
const verify = function (x, y, doc){
|
||||
export const verify = function (x, y, doc){
|
||||
const verifier = {
|
||||
'key': {
|
||||
'x': Buffer.from(x),
|
||||
|
||||
1
core/third-party/math.js
vendored
1
core/third-party/math.js
vendored
@@ -1,3 +1,4 @@
|
||||
|
||||
/**
|
||||
* Absolute value. abs(a)==a if a>=0. abs(a)==-a if a<0
|
||||
*
|
||||
|
||||
2391
core/third-party/nacl-fast_orig.js
vendored
2391
core/third-party/nacl-fast_orig.js
vendored
File diff suppressed because it is too large
Load Diff
6373
core/third-party/pako.js
vendored
6373
core/third-party/pako.js
vendored
File diff suppressed because it is too large
Load Diff
6429
core/third-party/sodium.js
vendored
6429
core/third-party/sodium.js
vendored
File diff suppressed because one or more lines are too long
@@ -72,7 +72,7 @@ export class Garbler{
|
||||
|
||||
// garble the rest of the circuits asyncronously
|
||||
const allPromises = [];
|
||||
for (let cNo =1; cNo < this.s.cs.length; cNo++){
|
||||
for (let cNo = 1; cNo < this.s.cs.length; cNo++){
|
||||
if (cNo === 5){
|
||||
allPromises.push(Promise.resolve('empty'));
|
||||
continue;
|
||||
|
||||
@@ -3,7 +3,7 @@ import {concatTA, int2ba, assert, encrypt_generic, decrypt_generic} from './../u
|
||||
|
||||
export class OT{
|
||||
// class OT implements oblivious transfer protocol based on
|
||||
// [1] The Simplest Protocol for Oblivious Transfer
|
||||
// Chou-Orlandi "Simplest OT"
|
||||
// as much pre-computation as possiblle is done in the offline phase
|
||||
|
||||
constructor(){
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable max-classes-per-file */
|
||||
|
||||
import * as bcu from './../third-party/math.js';
|
||||
import {ba2str, concatTA, int2ba, str2ba, ba2hex, ba2int} from './../utils.js';
|
||||
var bcu
|
||||
if (typeof(window) !== 'undefined'){
|
||||
bcu = await import('./../third-party/math.js');
|
||||
} else {
|
||||
// we are in node. bcuNode must have been made global
|
||||
bcu = bcuNode
|
||||
}
|
||||
import {ba2str, concatTA, int2ba, str2ba, ba2int} from './../utils.js';
|
||||
|
||||
function pad(str) {
|
||||
if (str.length % 2 === 1) {
|
||||
|
||||
@@ -10,7 +10,7 @@ import {Evaluator} from './Evaluator.js';
|
||||
import {OT} from './OT.js';
|
||||
import {Paillier2PC} from './Paillier2PC.js';
|
||||
import {GCWorker} from './GCWorker.js';
|
||||
import {global} from './../globals.js';
|
||||
import {globals} from './../globals.js';
|
||||
|
||||
|
||||
// class C is initialized once and then it is a read-only struct
|
||||
@@ -132,7 +132,7 @@ export class TWOPC {
|
||||
|
||||
// destroy de-registers listeners, terminates workers
|
||||
destroy(){
|
||||
this.pm.destroy();
|
||||
if (this.pm) this.pm.destroy();
|
||||
for (let i=1; i < this.workers.length; i++){
|
||||
const gcworker = this.workers[i];
|
||||
for (let j=0; j < gcworker.workers.length; j++){
|
||||
@@ -784,12 +784,13 @@ export class TWOPC {
|
||||
}
|
||||
|
||||
const fetchPromise = fetch(
|
||||
'http://'+this.notary.IP+':'+global.defaultNotaryPort+'/'+cmd+'?'+this.uid,
|
||||
'http://'+this.notary.IP+':'+globals.defaultNotaryPort+'/'+cmd+'?'+this.uid,
|
||||
{
|
||||
method: 'POST',
|
||||
mode: 'cors',
|
||||
cache: 'no-store',
|
||||
// keepalive: true, <-- trips up chrome
|
||||
agent: typeof(window) === 'undefined' ? keepAliveAgent : null,
|
||||
//keepalive: true, // <-- trips up chrome
|
||||
body: to_be_sent.buffer
|
||||
});
|
||||
const that = this;
|
||||
@@ -839,7 +840,7 @@ export class TWOPC {
|
||||
console.log('allFixedInputs.length', allFixedInputsCount);
|
||||
console.log('precomputePool size', allNonFixedInputsCount + this.ghashOTNeeded);
|
||||
|
||||
this.pm.update('last_stage', {'current': 1, 'total': 10});
|
||||
if (this.pm) this.pm.update('last_stage', {'current': 1, 'total': 10});
|
||||
const receiverBs = await this.ot.saveDecryptionKeys([].concat(...allFixedInputs));
|
||||
await this.ot.precomputePool(allNonFixedInputsCount + this.ghashOTNeeded);
|
||||
|
||||
@@ -867,7 +868,7 @@ export class TWOPC {
|
||||
}
|
||||
}
|
||||
assert(fixedOTBlob.length === idx*32);
|
||||
this.pm.update('last_stage', {'current': 2, 'total': 10});
|
||||
if (this.pm) this.pm.update('last_stage', {'current': 2, 'total': 10});
|
||||
}
|
||||
|
||||
// preCompute() should be called before run() is called
|
||||
@@ -954,7 +955,7 @@ export class TWOPC {
|
||||
let chunk = blob.slice(sentSoFar, sentSoFar + oneMB);
|
||||
await that.send('setBlobChunk', chunk);
|
||||
sentSoFar += chunk.length;
|
||||
that.pm.update('upload', {'current': i+1, 'total': chunkCount});
|
||||
if (that.pm) that.pm.update('upload', {'current': i+1, 'total': chunkCount});
|
||||
}
|
||||
that.send('setBlobChunk', str2ba('magic: no more data'));
|
||||
}
|
||||
@@ -975,7 +976,7 @@ export class TWOPC {
|
||||
let chunk = await this.send('getBlobChunk', int2ba(needBytes, 4));
|
||||
allChunks.push(chunk);
|
||||
soFarBytes += chunk.length;
|
||||
this.pm.update('download', {'current': soFarBytes, 'total': totalBytes});
|
||||
if (this.pm) this.pm.update('download', {'current': soFarBytes, 'total': totalBytes});
|
||||
}
|
||||
const rv = concatTA(...allChunks);
|
||||
assert(rv.length === totalBytes);
|
||||
|
||||
@@ -25,12 +25,10 @@ export default class WorkerPool{
|
||||
promises.push(Promise.resolve('empty'));
|
||||
}
|
||||
for (let i=0; i < batch.length; i++){
|
||||
console.log('round ', i);
|
||||
// console.log('round ', i);
|
||||
// wait until we have a free worker
|
||||
const out = await Promise.any(promises);
|
||||
if (pm != undefined){
|
||||
pm.update(pmtype, {'current': i+1, 'total': batch.length});
|
||||
}
|
||||
if (pm){pm.update(pmtype, {'current': i+1, 'total': batch.length});}
|
||||
// find which worker resolved
|
||||
let worker = null;
|
||||
let idx = null;
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
// of garbled circuits
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
importScripts('./../../third-party/nacl-fast.js');
|
||||
|
||||
var parentPort_;
|
||||
let circuit = null;
|
||||
let truthTable = null;
|
||||
let timeEvaluating = 0;
|
||||
@@ -16,11 +15,41 @@ const byteArray = new Uint8Array(24);
|
||||
let randomPool;
|
||||
// randomPoolOffset will be moved after data was read from randomPool
|
||||
let randomPoolOffset = 0;
|
||||
let garbledAssigment;
|
||||
let garbledAssigment;
|
||||
var crypto_;
|
||||
var nacl;
|
||||
|
||||
self.onmessage = function(event) {
|
||||
const msg = event.data.msg;
|
||||
const data = event.data.data;
|
||||
if (typeof(importScripts) !== 'undefined') {
|
||||
importScripts('./../../third-party/nacl-fast.js');
|
||||
crypto_ = self.crypto;
|
||||
self.onmessage = function(event) {
|
||||
processMessage(event.data);
|
||||
};
|
||||
} else {
|
||||
// we are in nodejs
|
||||
import('module').then((module) => {
|
||||
// we cannot use the "import" keyword here because on first pass the browser unconditionaly
|
||||
// parses this if clause and will error out if "import" is found
|
||||
// using process.argv instead of import.meta.url to get the name of this script
|
||||
const filePath = 'file://' + process.argv[1];
|
||||
// this workaround allows to require() from ES6 modules, which is not allowed by default
|
||||
const require = module.createRequire(filePath)
|
||||
nacl = require('tweetnacl')
|
||||
const { parentPort } = require('worker_threads');
|
||||
parentPort_ = parentPort
|
||||
const { Crypto } = require("@peculiar/webcrypto");
|
||||
crypto_ = new Crypto();
|
||||
const perf = {'now':function(){return 0;}}
|
||||
global.performance = perf;
|
||||
parentPort.on('message', msg => {
|
||||
processMessage(msg);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function processMessage(obj){
|
||||
const msg = obj.msg;
|
||||
const data = obj.data;
|
||||
if (msg === 'parse'){
|
||||
circuit = data;
|
||||
garbledAssigment = new Uint8Array(32*(circuit.wiresCount));
|
||||
@@ -31,7 +60,6 @@ self.onmessage = function(event) {
|
||||
truthTable = new Uint8Array(data);
|
||||
}
|
||||
else if (msg === 'garble'){
|
||||
console.log('in garble with circuit', circuit);
|
||||
if (circuit == null){
|
||||
console.log('error: need to parse circuit before garble');
|
||||
return;
|
||||
@@ -47,7 +75,7 @@ self.onmessage = function(event) {
|
||||
assert (outputLabels.length === circuit.outputSize*32);
|
||||
const obj = {'tt': truthTable.buffer, 'il': inputLabels.buffer, 'ol': outputLabels.buffer, 'R': R};
|
||||
console.timeEnd('garbling done in');
|
||||
postMessage(obj, [truthTable.buffer, inputLabels.buffer, outputLabels.buffer]);
|
||||
postMsg(obj, [truthTable.buffer, inputLabels.buffer, outputLabels.buffer]);
|
||||
}
|
||||
else if (msg === 'evaluate'){
|
||||
if (circuit == null || truthTable == null){
|
||||
@@ -59,12 +87,22 @@ self.onmessage = function(event) {
|
||||
assert (inputLabels.length === circuit.clientInputSize*16 + circuit.notaryInputSize*16);
|
||||
const outputLabels = evaluate(circuit, garbledAssigment, truthTable, inputLabels);
|
||||
assert (outputLabels.length === circuit.outputSize*16);
|
||||
postMessage(outputLabels.buffer);
|
||||
postMsg(outputLabels.buffer);
|
||||
}
|
||||
else {
|
||||
console.log('Error: unexpected message in worker');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function postMsg(value, transferList){
|
||||
if (typeof importScripts !== 'function'){
|
||||
parentPort_.postMessage({data:value}, transferList)
|
||||
} else {
|
||||
postMessage(value, transferList);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function newR(){
|
||||
const R = getRandom(16);
|
||||
@@ -324,7 +362,7 @@ function encrypt(a, b, t, m) {
|
||||
}
|
||||
|
||||
function randomOracle(m, t) {
|
||||
return self.nacl.secretbox(
|
||||
return nacl.secretbox(
|
||||
m,
|
||||
longToByteArray(t),
|
||||
sha0,
|
||||
@@ -372,7 +410,7 @@ function fillRandom(count){
|
||||
const randomChunks = [];
|
||||
const chunkCount = Math.ceil(count/65536);
|
||||
for (let i=0; i < chunkCount; i++){
|
||||
randomChunks.push(self.crypto.getRandomValues(new Uint8Array(65536)));
|
||||
randomChunks.push(crypto_.getRandomValues(new Uint8Array(65536)));
|
||||
}
|
||||
randomPool = concatTA(...randomChunks);
|
||||
randomPoolOffset = 0;
|
||||
|
||||
@@ -1,32 +1,67 @@
|
||||
// otworker.js is a WebWorker where most of the heavy computations for
|
||||
// oblivious transfer happen
|
||||
// Oblivious Transfer happen. Based on Chou-Orlandi "Simplest OT"
|
||||
|
||||
importScripts('./../../third-party/sodium.js');
|
||||
var sodium
|
||||
var parentPort_;
|
||||
|
||||
self.onmessage = function(event) {
|
||||
const msg = event.data.msg;
|
||||
const data = event.data.data;
|
||||
|
||||
if (typeof(importScripts) === 'undefined'){
|
||||
// we are in nodejs
|
||||
import('module').then((module) => {
|
||||
// we cannot use the "import" keyword here because on first pass the browser unconditionaly
|
||||
// parses this if clause and will error out if "import" is found
|
||||
// using process.argv instead of import.meta.url to get the name of this script
|
||||
const filePath = 'file://' + process.argv[1];
|
||||
// this workaround allows to require() from ES6 modules, which is not allowed by default
|
||||
const require = module.createRequire(filePath)
|
||||
const { parentPort } = require('worker_threads');
|
||||
parentPort_ = parentPort
|
||||
sodium = require('libsodium-wrappers-sumo');
|
||||
parentPort.on('message', msg => {
|
||||
processMessage(msg);
|
||||
})
|
||||
})
|
||||
} else {
|
||||
importScripts('./../../third-party/sodium.js');
|
||||
self.onmessage = function(event) {
|
||||
processMessage(event.data);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function processMessage(obj){
|
||||
const msg = obj.msg;
|
||||
const data = obj.data;
|
||||
if (msg === 'saveDecryptionKeys'){
|
||||
const bytes = new Uint8Array(data.bytes);
|
||||
const A = new Uint8Array(data.A);
|
||||
const rv = saveDecryptionKeys(bytes, A);
|
||||
postMessage({'blob': rv.buffer});
|
||||
postMsg({'blob': rv.buffer});
|
||||
|
||||
}
|
||||
else if (msg === 'precomputePool'){
|
||||
const count = data.count;
|
||||
const A = new Uint8Array(data.A);
|
||||
const rv = precomputePool(count, A);
|
||||
postMessage({'blob': rv.buffer});
|
||||
postMsg({'blob': rv.buffer});
|
||||
}
|
||||
else if (msg === 'prepareEncryptionKeys'){
|
||||
const bytes = new Uint8Array(data.bytes);
|
||||
const a = new Uint8Array(data.a, data.A);
|
||||
const A = new Uint8Array(data.A);
|
||||
const rv = prepareEncryptionKeys(bytes, a, A);
|
||||
postMessage({'blob': rv.buffer});
|
||||
postMsg({'blob': rv.buffer});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function postMsg(value, transferList){
|
||||
if (typeof importScripts !== 'function'){
|
||||
parentPort_.postMessage({data:value}, transferList)
|
||||
} else {
|
||||
postMessage(value, transferList);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function prepareEncryptionKeys(bytes, a, A){
|
||||
|
||||
@@ -1,10 +1,30 @@
|
||||
// Serializes the circuit into a compact representation
|
||||
|
||||
self.onmessage = function(event) {
|
||||
const text = event.data.text;
|
||||
const [obj, blob] = serializeCircuit(text);
|
||||
postMessage({'obj': obj, blob: blob.buffer});
|
||||
};
|
||||
if (typeof(importScripts) === 'undefined'){
|
||||
// we are in nodejs
|
||||
import('module').then((module) => {
|
||||
// we cannot use the "import" keyword here because on first pass the browser unconditionaly
|
||||
// parses this if clause and will error out if "import" is found
|
||||
// using process.argv instead of import.meta.url to get the name of this script
|
||||
const filePath = 'file://' + process.argv[1];
|
||||
// this workaround allows to require() from ES6 modules, which is not allowed by default
|
||||
const require = module.createRequire(filePath)
|
||||
const { parentPort } = require('worker_threads');
|
||||
parentPort.on('message', msg => {
|
||||
const text = msg.text;
|
||||
const [obj, blob] = serializeCircuit(text);
|
||||
parentPort.postMessage({data: {'obj': obj, blob: blob.buffer}});
|
||||
})
|
||||
});
|
||||
}
|
||||
else {
|
||||
self.onmessage = function(event) {
|
||||
const text = event.data.text;
|
||||
const [obj, blob] = serializeCircuit(text);
|
||||
postMessage({'obj': obj, blob: blob.buffer});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function serializeCircuit(text){
|
||||
const obj = {};
|
||||
|
||||
@@ -168,9 +168,9 @@ export async function verifySig(pubkeyRaw, sig_p1363, signed_digest){
|
||||
// input is Uint8Array
|
||||
export async function verifyAttestationDoc(doc){
|
||||
// extract x,y from EC pubkey
|
||||
const decoded = window.CBOR.decode(doc.buffer);
|
||||
const decoded = CBOR.decode(doc.buffer);
|
||||
const payload = decoded[2].slice(); // need to copy otherwise .buffer will access ab
|
||||
const doc_obj = window.CBOR.decode(payload.buffer);
|
||||
const doc_obj = CBOR.decode(payload.buffer);
|
||||
const leafCertDer = doc_obj.certificate.slice();
|
||||
const cert_asn1 = asn1js.fromBER(leafCertDer.buffer);
|
||||
const leafCert = new Certificate({ schema: cert_asn1.result });
|
||||
@@ -205,7 +205,7 @@ export async function verifyAttestationDoc(doc){
|
||||
|
||||
export function b64encode(ba) {
|
||||
assert(ba instanceof Uint8Array);
|
||||
if (typeof window === 'undefined') {
|
||||
if (typeof(window) === 'undefined') {
|
||||
// running in nodejs
|
||||
return Buffer.from(ba).toString('base64');
|
||||
}
|
||||
@@ -224,29 +224,23 @@ export function b64encode(ba) {
|
||||
|
||||
|
||||
export function b64decode(str) {
|
||||
if (typeof window === 'undefined') {
|
||||
let dec;
|
||||
if (typeof(window) === 'undefined') {
|
||||
// running in nodejs
|
||||
return Buffer.from(str, 'base64').toJSON().data;
|
||||
dec = Buffer.from(str, 'base64');
|
||||
}
|
||||
else {
|
||||
const arr = atob(str).split('').map(function(c) {
|
||||
dec = atob(str).split('').map(function(c) {
|
||||
return c.charCodeAt(0);
|
||||
});
|
||||
return new Uint8Array(arr);
|
||||
}
|
||||
return new Uint8Array(dec);
|
||||
}
|
||||
|
||||
// conform to base64url format replace +/= with -_
|
||||
export function b64urlencode (ba){
|
||||
assert(ba instanceof Uint8Array);
|
||||
let str;
|
||||
if (typeof window === 'undefined') {
|
||||
// running in nodejs
|
||||
str = Buffer.from(ba).toString('base64');
|
||||
}
|
||||
else {
|
||||
str = b64encode(ba);
|
||||
}
|
||||
let str = b64encode(ba);
|
||||
return str.split('+').join('-').split('/').join('_').split('=').join('');
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ var trustedCertificates = [];
|
||||
|
||||
|
||||
// extract PEMs from Mozilla's CA store and convert into asn1js's Certificate object
|
||||
export async function parse_certs(){
|
||||
export async function parse_certs(text){
|
||||
// wait for pkijs module to load
|
||||
while (typeof(asn1js) == 'undefined'){
|
||||
console.log('waiting for pkijs');
|
||||
@@ -19,7 +19,6 @@ export async function parse_certs(){
|
||||
});
|
||||
}
|
||||
|
||||
const text = await import_resource('core/third-party/certs.txt');
|
||||
const lines = text.split('"\n"').slice(1); // discard the first line - headers
|
||||
for (const line of lines){
|
||||
const fields = line.split('","');
|
||||
|
||||
Reference in New Issue
Block a user