<?

// -------------------------------------------------------------
// 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$DSKOPENSSL_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"$sk0"/"$myhosttruetrue);
}

// 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>