<?
// -------------------------------------------------------------
// Defensive Script Server
// -------------------------------------------------------------
// Manages defensive scripts and authentication of origin.
// DJCL and default keys are also automatically injected.
// -------------------------------------------------------------
// DSS private key, DB password, HWK host wrapping key
require "config.php";
$myhost = getenv('HTTP_HOST');
// Force TLS
if(getenv('SERVER_PORT') != 443)
{
header("Location: https://$myhost".getenv('REQUEST_URI'));
die();
}
// Database of registered origins and scripts
$sql = mysql_connect($DB_HOST, $DB_USER, $DB_PASSWORD);
// The private key of the defensive server, used to sign origins
$DSK = openssl_pkey_get_private($DSS_PK);
// By default print our own source code
if(!$sql || !isset($_GET['script']))
{
highlight_file("index.php");
die();
}
mysql_select_db($DB_NAME);
mysql_set_charset("utf8");
header('Content-Type: text/javascript');
header("Cache-Control: no-cache, must-revalidate");
$script = (int)$_GET['script'];
// Check registered script
$q = mysql_query("SELECT * FROM `scripts` WHERE id='$script' LIMIT 1");
if(!($s = mysql_fetch_assoc($q))) die("/* This script ID is not registered */");
// Get associated origin
$q = mysql_query("SELECT * FROM `origins` WHERE id='{$s['oid']}' LIMIT 1");
if(!($org = mysql_fetch_assoc($q)))
{
mysql_query("DELETE FROM `scripts` WHERE id='$script' LIMIT 1");
die("/* No script associated with origin */");
}
// Origin authentication
if(isset($_POST['challenge']))
{
// Browser origin does not match claimed origin
if(getenv('HTTP_ORIGIN') != $org['origin'] || strlen($c = $_POST['challenge']) != 64)
{
die(header("HTTP/1.1 403 Access denied"));
}
// Grant CORS access
header("Access-Control-Allow-Origin: {$org['origin']}");
header('Access-Control-Allow-Methods: POST');
$data = json_encode(array("token"=>$c,"origin"=>$org['origin']));
$sig = "";
// Sign the token and origin with DSS's private key
openssl_sign($data, $sig, $DSK, OPENSSL_ALGO_SHA1);
die(json_encode(array("data"=>$data,"sig"=>bin2hex($sig))));
}
// Session Key
if(isset($_COOKIE['sessionKey']))
{
$sk = $_COOKIE['sessionKey'];
}
else
{
$sk = bin2hex(openssl_random_pseudo_bytes(32));
setCookie("sessionKey", $sk, 0, "/", $myhost, true, true);
}
// Parse host public key (for JSON format)
$hpk = openssl_pkey_get_details(openssl_pkey_get_public($org['pk']));
$hpk = $hpk['rsa'];
// Parse DSS private key (to inject public values as JSON)
$dk = openssl_pkey_get_details($DSK);
$dk = $dk['rsa'];
?>
//<script>
try{
with({_tok: '<?=bin2hex(openssl_random_pseudo_bytes(32))?>'})
with({defensive: (function(){
/** DJCL **/
<?
// Include DJCL. It will be available in namespace of the script
include "djcl/djcl".($s['utf8']?"":"_ascii").".js";
?>
var origin = ''; // Origin
var oa = false; // Origin authenticated?
// Origin authentication function (CORS)
// Parse and check signature of token and set authenticated origin
var _ = function(s)
{
var so = {data: "", sig:""};
var co = {token: "", origin: ""};
var pub = {<?='n: "'.bin2hex($dk['n']).'", e: "'.bin2hex($dk['e']).'"'?>};
oa = true;
if(DJSON.parse(s, so, {type:'object', props:[
{name: "data", value: {type: "string", props:[]}},
{name: "sig", value: {type: "string", props:[]}}
]}))
{
rsa.signature_hash = hashing.sha1;
if(rsa.verify_pkcs1_v1_5(so.data, so.sig, pub)
&& DJSON.parse(so.data, co, {type:'object', props:[
{name: "token", value: {type: "string", props:[]}},
{name: "origin", value: {type: "string", props:[]}}
]}) && co.token == _tok)
{
origin = co.origin;
return "OK";
}
}
return "FAIL";
}
// The actual defensive script to load
var $ = function(input)
{
var publicKey = {n: "<?=bin2hex($hpk['n'])?>", e: "<?=bin2hex($hpk['e'])?>"};
var hostKey = '<?=bin2hex(openssl_random_pseudo_bytes(32))?>';
var sessionKey = '<?=$sk?>';
// Start of registered script
<?=$s['script']?>
// End of registered script
}
return function(s){ if(typeof(s)=="string") return !oa ? _(s) : (!origin ? '' : $(s))}
})()})
{
(function(){
var _xhr = new XMLHttpRequest();
var outer = function(){
// Start of registered outer code (called after origin is authenticated)
<?=$s['outer']?>
// End of registered outer code
};
// Check origin using CORS (most widely supported)
// Send fresh token and check the returned signature
_xhr.open('POST', 'https://<?=$myhost?>/?script=<?=$script?>', 1);
_xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
_xhr.onload = function(){ if(defensive(_xhr.responseText+'') == "OK") outer(); };
_xhr.send("challenge="+_tok);
})();
}}
catch(e){}
//</script>