mirror of
https://github.com/tlsnotary/PageSigner.git
synced 2026-01-09 14:48:07 -05:00
oracles: add DescribeImages check. Allow import of older pgsg files
This commit is contained in:
@@ -656,6 +656,20 @@ async function verifyPgsg(json) {
|
||||
var notary_signature = b64decode(json['notary signature'])
|
||||
var ec_privkey = b64decode(json['client EC privkey'])
|
||||
var time = b64decode(json['notarization time'])
|
||||
var notaryName = json["notary name"]
|
||||
var notary;
|
||||
if (notaryName == oracle.name){
|
||||
notary = oracle;
|
||||
}
|
||||
else{
|
||||
var rv = await verifyOldOracle(notaryName);
|
||||
if (rv.result == true){
|
||||
notary = rv.oracle;
|
||||
}
|
||||
else{
|
||||
throw('unrecognized oracle in the imported file')
|
||||
}
|
||||
}
|
||||
|
||||
var seconds = ba2int(time)
|
||||
var date = new Date(seconds*1000)
|
||||
@@ -705,12 +719,12 @@ async function verifyPgsg(json) {
|
||||
var commit_hash = await sha256(server_response)
|
||||
//check notary server signature
|
||||
var signed_data_ba = await sha256([].concat(ec_privkey, ec_pubkey_server, commit_hash, time))
|
||||
assert(await verifyNotarySig(notary_signature, chosen_notary.pubkeyPEM, signed_data_ba) == true)
|
||||
assert(await verifyNotarySig(notary_signature, notary.pubkeyPEM, signed_data_ba) == true)
|
||||
//aesgcm decrypt the data
|
||||
var cleartext = await decrypt_tls_response (server_response, server_write_key, server_write_IV)
|
||||
var dechunked = dechunk_http(ba2str(cleartext))
|
||||
var ungzipped = gunzip_http(dechunked)
|
||||
return [ungzipped, commonName];
|
||||
return [ungzipped, commonName, notaryName];
|
||||
}
|
||||
|
||||
|
||||
@@ -731,8 +745,9 @@ async function verify_pgsg_and_show_data(imported_data, create) {
|
||||
if (!create) return;
|
||||
var cleartext = a[0];
|
||||
var commonName = a[1];
|
||||
var notaryName = a[2]
|
||||
var creationTime = getTime();
|
||||
await createNewSession (creationTime, commonName, cleartext, json, true)
|
||||
await createNewSession (creationTime, commonName, notaryName, cleartext, json, true)
|
||||
await openTab(creationTime);
|
||||
var allSessions = await getAllSessions();
|
||||
sendSessions(allSessions); //refresh manager
|
||||
@@ -828,11 +843,18 @@ async function viewRaw(sid) {
|
||||
function sendSessions(sessions) {
|
||||
var rows = []
|
||||
for (let session of sessions){
|
||||
var verifier;
|
||||
if (session.notaryName == undefined){
|
||||
verifier = 'tlsnotarygroup8'
|
||||
}
|
||||
else {
|
||||
verifier = session.notaryName;
|
||||
}
|
||||
rows.push({
|
||||
'sessionName': session.sessionName,
|
||||
'serverName': session.serverName,
|
||||
'is_imported': session.is_imported,
|
||||
'verifier': 'tlsnotarygroup8',
|
||||
'verifier': verifier,
|
||||
'creationTime': session.creationTime,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
var snapshotID = 'snap-0f838cf4591ac24e0';
|
||||
var imageID = 'ami-0a93db37bec3fda42';
|
||||
var oracles_intact = false; //must be explicitely set to true
|
||||
|
||||
var oracle = {
|
||||
'snapshotId': 'snap-0f838cf4591ac24e0',
|
||||
'imageId': 'ami-0a93db37bec3fda42',
|
||||
'name': 'tlsnotarygroup8',
|
||||
'IP': '34.229.208.191',
|
||||
'port': '10011',
|
||||
@@ -13,10 +13,22 @@ var oracle = {
|
||||
'DIAud':'https://ec2.us-east-1.amazonaws.com/?AWSAccessKeyId=AKIAIHZGACNJKBHFWOTQ&Action=DescribeInstanceAttribute&Attribute=userData&Expires=2025-01-01&InstanceId=i-0c4f98aeeac5308da&SignatureMethod=HmacSHA256&SignatureVersion=2&Version=2014-10-01&Signature=mu8lWuB688ouVOkSL7M5ZS0y%2FLCcxMME4%2Bg6iikS5TE%3D',
|
||||
'DIAk':'https://ec2.us-east-1.amazonaws.com/?AWSAccessKeyId=AKIAIHZGACNJKBHFWOTQ&Action=DescribeInstanceAttribute&Attribute=kernel&Expires=2025-01-01&InstanceId=i-0c4f98aeeac5308da&SignatureMethod=HmacSHA256&SignatureVersion=2&Version=2014-10-01&Signature=MmEJF7Ic4eOnWeH%2BGyheVApqKh8mrQX2rwQabiyvWhw%3D',
|
||||
'DIAr':'https://ec2.us-east-1.amazonaws.com/?AWSAccessKeyId=AKIAIHZGACNJKBHFWOTQ&Action=DescribeInstanceAttribute&Attribute=ramdisk&Expires=2025-01-01&InstanceId=i-0c4f98aeeac5308da&SignatureMethod=HmacSHA256&SignatureVersion=2&Version=2014-10-01&Signature=IqNgbD%2FlGhvYQ8ndbMCz3PMFQjeGqBPvTU83repfJEs%3D',
|
||||
'DImg':'https://ec2.us-east-1.amazonaws.com/?AWSAccessKeyId=AKIAIHZGACNJKBHFWOTQ&Action=DescribeImages&Expires=2025-01-01&ImageId.1=ami-0a93db37bec3fda42&SignatureMethod=HmacSHA256&SignatureVersion=2&Version=2014-10-01&Signature=xFhBqWoOyltYXRv%2F5SDCMfQBpDXFH2QPQBkgQahE8Ic%3D',
|
||||
'instanceId': 'i-0c4f98aeeac5308da',
|
||||
'pubkeyPEM': '-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1XR5GYA7XmgMqH87HNaay4Xlzozs\nRflEv4VHWchpJteey5MRTn31e+pycFpOdaw6ybH8qfzkml1apoSl8+mO2A==\n-----END PUBLIC KEY-----'
|
||||
}
|
||||
|
||||
//until we deploy tlsnotarygroup9 this is just a placeholder
|
||||
var old_oracle = {
|
||||
// 'snapshotId': 'snap-0f838cf4591ac24e0',
|
||||
// 'imageId': 'ami-0a93db37bec3fda42',
|
||||
// 'name': 'tlsnotarygroup7',
|
||||
// 'IP': '34.229.208.191',
|
||||
// 'port': '10011',
|
||||
// 'instanceId': 'i-0c4f98aeeac5308da',
|
||||
// 'pubkeyPEM': '-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1XR5GYA7XmgMqH87HNaay4Xlzozs\nRflEv4VHWchpJteey5MRTn31e+pycFpOdaw6ybH8qfzkml1apoSl8+mO2A==\n-----END PUBLIC KEY-----'
|
||||
}
|
||||
|
||||
|
||||
|
||||
//there can be potentially multiple oracles to choose from
|
||||
@@ -43,7 +55,7 @@ function getSecondsDelta(later, sooner) {
|
||||
|
||||
|
||||
|
||||
function checkDescribeInstances(xmlDoc, instanceId, IP) {
|
||||
function checkDescribeInstances(xmlDoc, instanceId, IP, imageId) {
|
||||
try {
|
||||
var rs = xmlDoc.getElementsByTagName('reservationSet');
|
||||
assert(rs.length === 1);
|
||||
@@ -56,7 +68,7 @@ function checkDescribeInstances(xmlDoc, instanceId, IP) {
|
||||
assert(instances.length === 1);
|
||||
var parent = instances[0];
|
||||
assert(parent.getElementsByTagName('instanceId')[0].textContent === instanceId);
|
||||
assert(parent.getElementsByTagName('imageId')[0].textContent === imageID);
|
||||
assert(parent.getElementsByTagName('imageId')[0].textContent === imageId);
|
||||
assert(parent.getElementsByTagName('instanceState')[0].getElementsByTagName('name')[0].textContent === 'running');
|
||||
var launchTime = parent.getElementsByTagName('launchTime')[0].textContent;
|
||||
assert(parent.getElementsByTagName('ipAddress')[0].textContent === IP);
|
||||
@@ -83,13 +95,13 @@ function checkDescribeInstances(xmlDoc, instanceId, IP) {
|
||||
}
|
||||
|
||||
|
||||
function checkDescribeVolumes(xmlDoc, instanceId, volumeId, volAttachTime) {
|
||||
function checkDescribeVolumes(xmlDoc, instanceId, volumeId, volAttachTime, snapshotId) {
|
||||
try {
|
||||
var volumes = xmlDoc.getElementsByTagName('volumeSet')[0].children;
|
||||
assert(volumes.length === 1);
|
||||
var volume = volumes[0];
|
||||
assert(volume.getElementsByTagName('volumeId')[0].textContent === volumeId);
|
||||
assert(volume.getElementsByTagName('snapshotId')[0].textContent === snapshotID);
|
||||
assert(volume.getElementsByTagName('snapshotId')[0].textContent === snapshotId);
|
||||
assert(volume.getElementsByTagName('status')[0].textContent === 'in-use');
|
||||
var volCreateTime = volume.getElementsByTagName('createTime')[0].textContent;
|
||||
var attVolumes = volume.getElementsByTagName('attachmentSet')[0].getElementsByTagName('item');
|
||||
@@ -193,24 +205,49 @@ function checkGetUser(xmlDoc, ownerId) {
|
||||
}
|
||||
|
||||
|
||||
async function fetch_and_parse(url){
|
||||
var req = await fetch(url)
|
||||
var text = await req.text()
|
||||
function checkDescribeImages(xmlDoc, imageId, snapshotId){
|
||||
var images = xmlDoc.getElementsByTagName('imagesSet')[0].children;
|
||||
assert(images.length == 1);
|
||||
var image = images[0];
|
||||
assert(image.getElementsByTagName('imageId')[0].textContent == imageId);
|
||||
assert(image.getElementsByTagName('rootDeviceName')[0].textContent == '/dev/xvda');
|
||||
var devices = image.getElementsByTagName('blockDeviceMapping')[0].children;
|
||||
assert(devices.length == 1);
|
||||
var device = devices[0];
|
||||
var ebs = device.getElementsByTagName('ebs')[0];
|
||||
assert(ebs.getElementsByTagName('snapshotId')[0].textContent == snapshotId);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
async function fetch_and_parse(resource){
|
||||
var text;
|
||||
if (typeof(resource) == 'string'){
|
||||
var req = await fetch(resource)
|
||||
text = await req.text()
|
||||
}
|
||||
else if (typeof(resource) == 'object'){
|
||||
text = resource.text
|
||||
}
|
||||
else {
|
||||
throw('unknown resource type in fetch_and_parse')
|
||||
}
|
||||
var xmlDoc = new DOMParser().parseFromString(text, "text/xml")
|
||||
return xmlDoc
|
||||
}
|
||||
|
||||
|
||||
async function check_oracle(o) {
|
||||
async function check_oracle(o, isOld) {
|
||||
var xmlDocDI = await fetch_and_parse(o.DI)
|
||||
var rv = checkDescribeInstances(xmlDocDI, o.instanceId, o.IP);
|
||||
var rv = checkDescribeInstances(xmlDocDI, o.instanceId, o.IP, o.imageId);
|
||||
var volumeId = rv.volumeId
|
||||
var volAttachTime = rv.volAttachTime
|
||||
var ownerId = rv.ownerId
|
||||
var launchTime = rv.launchTime
|
||||
|
||||
var xmlDocDV = await fetch_and_parse(o.DV)
|
||||
checkDescribeVolumes(xmlDocDV, o.instanceId, volumeId, volAttachTime);
|
||||
checkDescribeVolumes(xmlDocDV, o.instanceId, volumeId, volAttachTime, o.snapshotId);
|
||||
|
||||
var xmlDocGU = await fetch_and_parse(o.GU)
|
||||
checkGetUser(xmlDocGU, ownerId);
|
||||
@@ -227,13 +264,23 @@ async function check_oracle(o) {
|
||||
var xmlDocDIAr = await fetch_and_parse(o.DIAr)
|
||||
checkDescribeInstanceAttributeRamdisk(xmlDocDIAr, o.instanceId);
|
||||
|
||||
var xmlDocDImg = await fetch_and_parse(o.DImg)
|
||||
checkDescribeImages(xmlDocDImg, o.imageId, o.snapshotId);
|
||||
|
||||
if (isOld == true){
|
||||
//unfortunately there is no way to perform the 'AWSAccessKeyId=' check (see below)
|
||||
//for an old oracle server
|
||||
console.log('oracle verification successfully finished');
|
||||
return true;
|
||||
}
|
||||
|
||||
var mark = 'AWSAccessKeyId=';
|
||||
var start;
|
||||
var id;
|
||||
var ids = [];
|
||||
//"AWSAccessKeyId" should be the same to prove that the queries are made on behalf of AWS user "root".
|
||||
//The attacker can be a user with limited privileges for whom the API would report only partial information.
|
||||
for (var url in [o.DI, o.DV, o.GU, o.GCO, o.DIA]) {
|
||||
for (var url in [o.DI, o.DV, o.GU, o.GCO, o.DIAud, o.DIAk, o.DIAr, o.DImg]) {
|
||||
start = url.search(mark) + mark.length;
|
||||
id = url.slice(start, start + url.slice(start).search('&'));
|
||||
ids.push(id);
|
||||
@@ -243,6 +290,32 @@ async function check_oracle(o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
async function verifyOldOracle(name){
|
||||
if (old_oracle.name != name){
|
||||
return {result:false}
|
||||
}
|
||||
var o = old_oracle;
|
||||
for (let key of ['DI', 'DV', 'GU', 'GCO', 'DIAud', 'DIAk', 'DIAr', 'DImg']){
|
||||
var pgsg = await import_resource('old oracles/'+name+'/'+key+'.pgsg')
|
||||
var rv = await verifyPgsg(JSON.parse(pgsg))
|
||||
var serverName = rv[1]
|
||||
assert(serverName.split('.').slice(-2).join('.') == 'amazonaws.com')
|
||||
var clearText = rv[0]
|
||||
//remove HTTP headers
|
||||
var httpBody = clearText.split('\r\n\r\n').slice(1)
|
||||
o[key] = {text:httpBody}
|
||||
}
|
||||
var rv = await check_oracle(o, true);
|
||||
if (rv == true){
|
||||
return {result:true, oracle:o};
|
||||
}
|
||||
return {{result:false};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (typeof module !== 'undefined'){ //we are in node.js environment
|
||||
module.exports={
|
||||
check_oracle,
|
||||
|
||||
Reference in New Issue
Block a user