Author: jfthomps
Date: Mon Jun 5 20:10:44 2017
New Revision: 1797695
URL: http://svn.apache.org/viewvc?rev=1797695&view=rev
Log:
VCL-1045 - Method of encrypting sensitive database entries
addomain.php:
-modified submitToggleDeleteResourceExtra: changed call to deleteSecrets to
call deleteSecretKeys to reflect function rename
-modified AJsaveResource: added code to handle a web server missing a
cryptsecred for a value being set; now creates a new secret key, encrypts
submitted password, and encrypts new secret key with any public keys already
having entries for the old secret key
-modified addResource: changed call to getSecretID to call getSecretKeyID to
reflect function rename
-modified addEditDialogHTML: (unrelated to this JIRA) added help text for
domaindnsname and dnsserverhelp
utils.php:
-modified initGlobals: added defines for crypto parameters: SYMALGO, SYMOPT,
SYMLEN, ASYMALGO, ASYMOPT, and ASYMLEN; when values need to be updated in the
future due to standards changing, these can be changed to cause everything to
use new values
-modified checkCryptkey: set algorithm and key length from defined constants;
add used crypto parameters to cryptkey table when inserting keys
-modified encryptData decryptData: added parameters to accept crypto
parameters; set used crypto algorithm, key length, and mode from arguments
-removed encryptDataAsymmetric
-modified encryptDBdata: get crypto parameters from database; renamed call to
decryptSecret to call decryptSecretKey to reflect function rename
-renamed encryptSecret to encryptSecretKey and moved to be before definition of
decryptSecretKey; modified to get padding information from database and default
to PKCS1 OAEP if a cryptkey is passed for $cryptkey instead of a key id
-renamed decryptSecret to decryptSecretKey and added code to determine padding
from constant
-renamed getSecretID to getSecretKeyID; renamed call to encryptSecret to call
encryptSecretKey to reflect function rename; added crypto parameters to INSERT;
added check for dbLastInsertID returning < 1; renamed call to encryptSecrets to
call encryptWebSecretKeys to reflect function rename
-renamed deleteSecrets to deleteSecretKeys
-renamed encryptSecrets to encryptWebSecretKeys; renamed call to encryptSecret
to call encryptSecretKey to reflect function rename; added crypto parameters to
INSERT
-renamed updateSecrets to checkCryptSecrets; moved chunk of function to
separate functions
-added getMNcryptkeyUpdates (code from checkCryptSecrets)
-added addMNcryptkeyUpdates (code from checkCryptSecrets)
-modified addRequest: renamed call to updateSecrets to call checkCryptSecrets
to reflect function rename
-modified getVMProfiles: removed rsakey and rsapub from returned data
-modified addContinuationsEntry: added crypto parameters to call to encryptData
-modified getContinuationsData: added crypto parameters to call to decryptData
-modified xmlrpccall: renamed XMLRPCupdateSecrets to XMLRPCcheckCryptSecrets
vm.php:
-modified editVMInfo: removed fields for RSA Public Key and RSA Private Key
File; removed help for rsapubhelp and rsakeyhelp
-modified AJupdateVMprofileItem: removed rsakey and rsapub from preg_match
validation; removed code that uses rsapub and calls encryptDataAsymmetric and
allow new code to handle all password encryption; renamed call to deleteSecrets
to call deleteSecretKeys to reflect function rename; added code to handle if
web server is missing a cryptsecret entry for this password field
xmlrpcWrappers.php: renamed XMLRPCupdateSecrets to XMLRPCcheckCryptSecrets;
added check for specified reservationid existing in database; added code to
return 'noupdate' if no secretids are missing; modified query to handle finding
cryptsecrets for management nodes for which the web server is also missing
cryptsecrets; call addMNcryptkeyUpdates to do insert into cryptsecret table;
added error return code for case of web server not being able to add any
cryptsecret entries; added partial return code for when web server can only add
some cryptsecret entries
vm.js: modified getVMprofileDataCB: removed references to prsakey and prsapub
Modified:
vcl/trunk/web/.ht-inc/addomain.php
vcl/trunk/web/.ht-inc/utils.php
vcl/trunk/web/.ht-inc/vm.php
vcl/trunk/web/.ht-inc/xmlrpcWrappers.php
vcl/trunk/web/js/vm.js
Modified: vcl/trunk/web/.ht-inc/addomain.php
URL:
http://svn.apache.org/viewvc/vcl/trunk/web/.ht-inc/addomain.php?rev=1797695&r1=1797694&r2=1797695&view=diff
==============================================================================
--- vcl/trunk/web/.ht-inc/addomain.php (original)
+++ vcl/trunk/web/.ht-inc/addomain.php Mon Jun 5 20:10:44 2017
@@ -139,7 +139,7 @@ class ADdomain extends Resource {
/////////////////////////////////////////////////////////////////////////////
function submitToggleDeleteResourceExtra($rscid, $deleted=0) {
$data = $this->getData(array('rscid' => $rscid));
- deleteSecrets($data[$rscid]['secretid']);
+ deleteSecretKeys($data[$rscid]['secretid']);
}
/////////////////////////////////////////////////////////////////////////////
@@ -185,7 +185,41 @@ class ADdomain extends Resource {
$updates[] = "username = '{$data['username']}'";
# password
if(strlen($data['password'])) {
- // TODO handle this web server not having an
entry for this secret in cryptsecret
+ $oldsecretid = $olddata['secretid'];
+ # check that we have a cryptsecret entry for
this secret
+ $cryptkeyid = getCryptKeyID();
+ $query = "SELECT cryptsecret "
+ . "FROM cryptsecret "
+ . "WHERE cryptkeyid = $cryptkeyid AND "
+ . "secretid = $oldsecretid";
+ $qh = doQuery($query);
+ if(! ($row = mysql_fetch_assoc($qh))) {
+ # generate a new secret
+ $newsecretid =
getSecretKeyID('addomain', 'secretid', 0);
+ $delids = array($oldsecretid);
+ if($newsecretid == $oldsecretid) {
+ $delids[] = $newsecretid;
+ $newsecretid =
getSecretKeyID('addomain', 'secretid', 0);
+ }
+ $delids = implode(',', $delids);
+ # encrypt new secret with any
management node keys
+ $secretidset = array();
+ $query = "SELECT ck.hostid AS mnid "
+ . "FROM cryptkey ck "
+ . "JOIN cryptsecret cs ON (ck.id
= cs.cryptkeyid) "
+ . "WHERE cs.secretid =
$oldsecretid AND "
+ . "ck.hosttype =
'managementnode'";
+ $qh = doQuery($query);
+ while($row = mysql_fetch_assoc($qh))
+
$secretidset[$row['mnid']][$newsecretid] = 1;
+ $values =
getMNcryptkeyUpdates($secretidset, $cryptkeyid);
+ addMNcryptkeyUpdates($values);
+ $olddata['secretid'] = $newsecretid;
+ $updates[] = "secretid = $newsecretid";
+ # clean up old cryptsecret entries for
management nodes
+ $query = "DELETE FROM cryptsecret WHERE
secretid IN ($delids)";
+ doQuery($query);
+ }
$encpass = encryptDBdata($data['password'],
$olddata['secretid']);
if($encpass == NULL) {
$ret = array('status' => 'error', 'msg'
=> "Error encountered while updating password");
@@ -287,7 +321,7 @@ class ADdomain extends Resource {
$ownerid = getUserlistID($data['owner']);
- $secretid = getSecretID('addomain', 'secretid', 0);
+ $secretid = getSecretKeyID('addomain', 'secretid', 0);
$encpass = encryptDBdata($data['password'], $secretid);
$query = "INSERT INTO addomain"
@@ -421,10 +455,9 @@ class ADdomain extends Resource {
$h .= "</div>\n"; # groupdlg
$h .= "<div id=\"tooltips\">\n";
- # todo fill in all help contents
- $h .= helpTooltip('domaindnsnamehelp', i(""));
+ $h .= helpTooltip('domaindnsnamehelp', i("domain name
registered in DNS for Active Directory Domain (ex: ad.example.com)"));
$h .= helpTooltip('usernamehelp', i("These credentials will be
used to register reserved computers with AD."));
- $h .= helpTooltip('dnsservershelp', i(""));
+ $h .= helpTooltip('dnsservershelp', i("comma delimited list of
IP addresses for DNS servers that handle Domain DNS"));
$h .= "</div>\n"; # tooltips
return $h;
Modified: vcl/trunk/web/.ht-inc/utils.php
URL:
http://svn.apache.org/viewvc/vcl/trunk/web/.ht-inc/utils.php?rev=1797695&r1=1797694&r2=1797695&view=diff
==============================================================================
--- vcl/trunk/web/.ht-inc/utils.php (original)
+++ vcl/trunk/web/.ht-inc/utils.php Mon Jun 5 20:10:44 2017
@@ -68,6 +68,15 @@ function initGlobals() {
define("SECINWEEK", 604800);
define("SECINMONTH", 2678400);
define("SECINYEAR", 31536000);
+
+ define("SYMALGO", "AES");
+ define("SYMOPT", "CBC");
+ define("SYMLEN", 256);
+
+ define("ASYMALGO", "RSA");
+ define("ASYMOPT", "OAEP");
+ define("ASYMLEN", 4096);
+
if(! defined('QUERYLOGGING'))
define('QUERYLOGGING', 1);
# TODO validate security of this
@@ -617,6 +626,7 @@ function checkAccess() {
////////////////////////////////////////////////////////////////////////////////
function checkCryptkey() {
global $pemkey;
+
$reg = "|" . SCRIPT . "$|";
$filebase = preg_replace($reg, '', $_SERVER['SCRIPT_FILENAME']);
$filebase .= "/.ht-inc/cryptkey";
@@ -642,9 +652,10 @@ function checkCryptkey() {
$keyfile = "$filebase/private.pem";
- $args = array('private_key_bits' => 4096,
- 'private_key_type' => OPENSSL_KEYTYPE_RSA,
- 'digest_alg' => 'sha512');
+ $_algorithm = constant("OPENSSL_KEYTYPE_" . ASYMALGO);
+
+ $args = array('private_key_bits' => ASYMLEN,
+ 'private_key_type' => $_algorithm);
# open and lock id file before generating key
$fh = fopen($idfile, 'w');
if(! flock($fh, LOCK_EX | LOCK_NB)) {
@@ -674,10 +685,16 @@ function checkCryptkey() {
$query = "INSERT INTO cryptkey "
. "(hostid, "
. "hosttype, "
- . "pubkey) "
+ . "pubkey, "
+ . "algorithm, "
+ . "algorithmoption, "
+ . "keylength) "
. "SELECT COALESCE(MAX(hostid), 0) + 1, "
. "'web', "
- . "'$pubkey' "
+ . "'$pubkey', "
+ . "'" . ASYMALGO . "', "
+ . "'" . ASYMOPT . "', "
+ . ASYMLEN . " "
. "FROM cryptkey "
. "WHERE hosttype = 'web'";
doQuery($query);
@@ -2649,33 +2666,43 @@ function getKey($data) {
////////////////////////////////////////////////////////////////////////////////
///
-/// \fn encryptData($data, $cryptkey)
+/// \fn encryptData($data, $cryptkey, $algo, $option, $keylength)
///
/// \param $data - a string
/// \param $cryptkey - key for encryption
+/// \param $algo - algorithm to use for decryption
+/// \param $option - an algorithm option (such as CBC)
+/// \param $keylength - length of key being used
///
/// \return an encrypted form of $data that has been base64 encoded or NULL if
/// encryption failed
///
-/// \brief encrypts $data with AES and base64 encodes it; IV is generated and
-/// prepended to encrypted data before base64 encoding
+/// \brief encrypts $data with $algo and $option and base64 encodes it; IV is
+/// generated and prepended to encrypted data before base64 encoding
///
////////////////////////////////////////////////////////////////////////////////
-function encryptData($data, $cryptkey) {
+function encryptData($data, $cryptkey, $algo, $option, $keylength) {
global $ivsize;
if(! $data)
return false;
if(USE_PHPSECLIB) {
- $iv = crypt_random_string($ivsize);
- $aes = new Crypt_AES();
+ # only AES is currently supported
+ if($algo == 'AES') {
+ $mode = constant("CRYPT_AES_MODE_$option");
+ $aes = new Crypt_AES($mode);
+ }
+ else
+ return false;
+ $aes->setKeyLength($keylength);
$aes->setKey($cryptkey);
+ $iv = crypt_random_string($ivsize);
$aes->setIV($iv);
- $aes->setKeyLength(256);
$cryptdata = $aes->encrypt($data);
}
else {
$iv = openssl_random_pseudo_bytes($ivsize);
- $cryptdata = openssl_encrypt($data, 'AES-256-CBC', $cryptkey,
1, $iv);
+ $mode = "{$algo}-{$keylength}-{$option}";
+ $cryptdata = openssl_encrypt($data, $mode, $cryptkey, 1, $iv);
if($cryptdata === FALSE)
return NULL;
}
@@ -2685,10 +2712,13 @@ function encryptData($data, $cryptkey) {
////////////////////////////////////////////////////////////////////////////////
///
-/// \fn decryptData($data, $cryptkey)
+/// \fn decryptData($data, $cryptkey, $algo, $option, $keylength)
///
/// \param $data - a string
/// \param $cryptkey - key for decryption
+/// \param $algo - algorithm to use for decryption
+/// \param $option - an algorithm option (such as CBC)
+/// \param $keylength - length of key being used
///
/// \return decrypted form of $data or false on error
///
@@ -2696,7 +2726,7 @@ function encryptData($data, $cryptkey) {
/// encrypted data after base64 decoding
///
////////////////////////////////////////////////////////////////////////////////
-function decryptData($data, $cryptkey) {
+function decryptData($data, $cryptkey, $algo, $option, $keylength) {
global $ivsize;
if(! $data)
return false;
@@ -2704,14 +2734,20 @@ function decryptData($data, $cryptkey) {
$iv = substr($cryptdata, 0, $ivsize);
$cryptdata = substr($cryptdata, $ivsize);
if(USE_PHPSECLIB) {
- $aes = new Crypt_AES();
+ if($algo == 'AES') {
+ $mode = constant("CRYPT_AES_MODE_$option");
+ $aes = new Crypt_AES($mode);
+ }
+ else
+ return false;
+ $aes->setKeyLength($keylength);
$aes->setKey($cryptkey);
$aes->setIV($iv);
- $aes->setKeyLength(256);
$decryptdata = $aes->decrypt($cryptdata);
}
else {
- $decryptdata = openssl_decrypt($cryptdata, 'AES-256-CBC',
$cryptkey, 1, $iv);
+ $mode = "{$algo}-{$keylength}-{$option}";
+ $decryptdata = openssl_decrypt($cryptdata, $mode, $cryptkey, 1,
$iv);
if($decryptdata === FALSE)
return false;
}
@@ -2720,34 +2756,6 @@ function decryptData($data, $cryptkey) {
////////////////////////////////////////////////////////////////////////////////
///
-/// \fn encryptDataAsymmetric($data, $public_key)
-///
-/// \param $data - a string
-///
-/// \param $public_key - either a filename for a public key or the public key
-/// itself
-///
-/// \return hex-encoded, encrypted form of $data
-///
-/// \brief generate public key encrypted data
-///
-////////////////////////////////////////////////////////////////////////////////
-function encryptDataAsymmetric($data, $public_key){
- if(file_exists($public_key)){
- $key = openssl_pkey_get_public(file_get_contents($public_key));
- } else {
- $key = openssl_pkey_get_public($public_key);
- }
-
- openssl_public_encrypt($data, $encrypted, $key,
OPENSSL_PKCS1_OAEP_PADDING);
- openssl_free_key($key);
-
- $hexformatted = unpack("H*hex", $encrypted);
- return $hexformatted['hex'];
-}
-
-////////////////////////////////////////////////////////////////////////////////
-///
/// \fn encryptDBdata($data, $secretid)
///
/// \param $data - a string
@@ -2763,31 +2771,64 @@ function encryptDBdata($data, $secretid)
$cryptkeyid = getCryptKeyID();
if($cryptkeyid == NULL)
return NULL;
- $query = "SELECT cryptsecret "
+ $query = "SELECT cryptsecret, "
+ . "algorithm, "
+ . "algorithmoption, "
+ . "keylength "
. "FROM cryptsecret "
. "WHERE cryptkeyid = $cryptkeyid AND "
. "secretid = $secretid";
$qh = doQuery($query);
if(! ($row = mysql_fetch_assoc($qh)))
return NULL;
- $secret = decryptSecret($row['cryptsecret']);
+ $secret = decryptSecretKey($row['cryptsecret']);
if($secret === NULL)
return NULL;
- # encrypt $data using secret
- if(USE_PHPSECLIB)
- $iv = crypt_random_string(32);
- else {
- $iv = openssl_random_pseudo_bytes(32);
- if($iv === FALSE)
+ $edata = encryptData($data, $secret, $row['algorithm'],
$row['algorithmoption'], $row['keylength']);
+ return $edata;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \fn encryptSecretKey($secret, $cryptkey)
+///
+/// \param $secret - secret key to encrypt
+/// \param $cryptkey - id from cryptkey table for public key to use or public
+/// key itself
+///
+/// \return encrypted data; returns NULL on error
+///
+/// \brief encrypts $secret with key for $cryptkeyid
+///
+////////////////////////////////////////////////////////////////////////////////
+function encryptSecretKey($secret, $cryptkey) {
+ if(is_numeric($cryptkey)) {
+ $query = "SELECT pubkey, "
+ . "algorithmoption "
+ . "FROM cryptkey "
+ . "WHERE id = $cryptkey";
+ $qh = doQuery($query);
+ if(! ($row = mysql_fetch_assoc($qh)))
return NULL;
+ $cryptkey = $row['pubkey'];
+ if($row['algorithmoption'] == 'OAEP' || 1) # OAEP only
currently supported option
+ $padding = constant('OPENSSL_PKCS1_OAEP_PADDING');
}
- $edata = encryptData($data, $secret, $iv);
- return $edata;
+ else
+ $padding = constant('OPENSSL_PKCS1_OAEP_PADDING');
+ $savehdlr = set_error_handler(create_function('', ''));
+ if(@openssl_public_encrypt($secret, $encdata, $cryptkey, $padding)) {
+ set_error_handler($savehdlr);
+ $b64data = base64_encode($encdata);
+ return $b64data;
+ }
+ set_error_handler($savehdlr);
+ return NULL;
}
////////////////////////////////////////////////////////////////////////////////
///
-/// \fn decryptSecret($encsecret)
+/// \fn decryptSecretKey($encsecret)
///
/// \param $encsecret - encrypted secret
///
@@ -2796,7 +2837,7 @@ function encryptDBdata($data, $secretid)
/// \brief decrypts $encsecret using web server's secret key
///
////////////////////////////////////////////////////////////////////////////////
-function decryptSecret($encsecret) {
+function decryptSecretKey($encsecret) {
global $pemkey;
$cryptsecret = base64_decode($encsecret);
# read private key from file
@@ -2806,7 +2847,10 @@ function decryptSecret($encsecret) {
$prikey = openssl_pkey_get_private("file://$file", $pemkey);
# decrypt secret using private key
$savehdlr = set_error_handler(create_function('', ''));
- if(! openssl_private_decrypt($cryptsecret, $secret, $prikey,
OPENSSL_PKCS1_OAEP_PADDING)) {
+ if(ASYMOPT == 'OAEP')
+ $padding = constant('OPENSSL_PKCS1_OAEP_PADDING');
+ # OAEP currently only supported padding option
+ if(! openssl_private_decrypt($cryptsecret, $secret, $prikey, $padding))
{
set_error_handler($savehdlr);
return NULL;
}
@@ -2815,7 +2859,7 @@ function decryptSecret($encsecret) {
////////////////////////////////////////////////////////////////////////////////
///
-/// \fn getSecretID($table, $field, $recordid)
+/// \fn getSecretKeyID($table, $field, $recordid)
///
/// \param $table - name of a database table having a secret
/// \param $field - name of field in table referencing secretid
@@ -2829,7 +2873,7 @@ function decryptSecret($encsecret) {
/// saved in cryptsecret
///
////////////////////////////////////////////////////////////////////////////////
-function getSecretID($table, $field, $recordid) {
+function getSecretKeyID($table, $field, $recordid) {
$query = "SELECT $field FROM $table WHERE id = $recordid";
$qh = doQuery($query);
if(($row = mysql_fetch_row($qh)) && $row[0] != 0)
@@ -2847,39 +2891,47 @@ function getSecretID($table, $field, $re
$cryptkeyid = getCryptKeyID();
if($cryptkeyid === NULL)
return NULL;
- $encdata = encryptSecret($key, $cryptkeyid);
+ $encdata = encryptSecretKey($key, $cryptkeyid);
if($encdata === NULL)
return NULL;
# write to cryptsecret
$query = "INSERT INTO cryptsecret "
. "(cryptkeyid, "
. "secretid, "
- . "cryptsecret) "
+ . "cryptsecret, "
+ . "algorithm, "
+ . "algorithmoption, "
+ . "keylength) "
. "SELECT $cryptkeyid, "
. "COALESCE(MAX(secretid), 0) + 1, "
- . "'$encdata' "
+ . "'$encdata', "
+ . "'" . SYMALGO . "', "
+ . "'" . SYMOPT . "', "
+ . SYMLEN . " "
. "FROM cryptsecret";
doQuery($query);
$id = dbLastInsertID();
+ if($id < 1)
+ return NULL;
$query = "SELECT secretid FROM cryptsecret WHERE id = $id";
$qh = doQuery($query);
if(! ($row = mysql_fetch_assoc($qh)))
return NULL;
# encrypt with all other public keys and write to cryptsecret
- encryptSecrets($key, $row['secretid'], $cryptkeyid);
+ encryptWebSecretKeys($key, $row['secretid'], $cryptkeyid);
return $row['secretid'];
}
////////////////////////////////////////////////////////////////////////////////
///
-/// \fn deleteSecrets($secretid)
+/// \fn deleteSecretKeys($secretid)
///
/// \param $secretid - secretid value corresponding to cryptsecret.secretid
///
/// \brief deletes all entries in cryptsecret for $secretid
///
////////////////////////////////////////////////////////////////////////////////
-function deleteSecrets($secretid) {
+function deleteSecretKeys($secretid) {
$query = "DELETE FROM cryptsecret WHERE secretid = $secretid";
doQuery($query);
}
@@ -2936,40 +2988,7 @@ function getCryptKeyID() {
////////////////////////////////////////////////////////////////////////////////
///
-/// \fn encryptSecret($secret, $cryptkey)
-///
-/// \param $secret - secret key to encrypt
-/// \param $cryptkey - id from cryptkey table for public key to use or public
-/// key itself
-///
-/// \return encrypted data; returns NULL on error
-///
-/// \brief encrypts $secret with key for $cryptkeyid
-///
-////////////////////////////////////////////////////////////////////////////////
-function encryptSecret($secret, $cryptkey) {
- if(is_numeric($cryptkey)) {
- $query = "SELECT pubkey "
- . "FROM cryptkey "
- . "WHERE id = $cryptkey";
- $qh = doQuery($query);
- if(! ($row = mysql_fetch_assoc($qh)))
- return NULL;
- $cryptkey = $row['pubkey'];
- }
- $savehdlr = set_error_handler(create_function('', ''));
- if(@openssl_public_encrypt($secret, $encdata, $cryptkey,
OPENSSL_PKCS1_OAEP_PADDING)) {
- set_error_handler($savehdlr);
- $b64data = base64_encode($encdata);
- return $b64data;
- }
- set_error_handler($savehdlr);
- return NULL;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-///
-/// \fn encryptSecrets($secret, $secretid, $skipkeyid=0)
+/// \fn encryptWebSecretKeys($secret, $secretid, $skipkeyid=0)
///
/// \param $secret - secret key to encrypt
/// \param $secretid - id for secret from cryptsecret.secretid
@@ -2979,7 +2998,7 @@ function encryptSecret($secret, $cryptke
/// \brief encrypts $secret using any existing web server cryptkeys in database
///
////////////////////////////////////////////////////////////////////////////////
-function encryptSecrets($secret, $secretid, $skipkeyid=0) {
+function encryptWebSecretKeys($secret, $secretid, $skipkeyid=0) {
$query = "SELECT id, "
. "pubkey "
. "FROM cryptkey "
@@ -2988,17 +3007,21 @@ function encryptSecrets($secret, $secret
$qh = doQuery($query);
$values = array();
while($row = mysql_fetch_assoc($qh)) {
- $cryptsecret = encryptSecret($secret, $row['pubkey']);
+ $cryptsecret = encryptSecretKey($secret, $row['pubkey']);
if($cryptsecret === NULL)
continue;
- $values[] = "({$row['id']}, $secretid, '$cryptsecret')";
+ $values[] = "({$row['id']}, $secretid, '$cryptsecret', '"
+ . SYMALGO . "', '" . SYMOPT . "', " . SYMLEN . ")";
}
if(! empty($values)) {
$allvalues = implode(',', $values);
$query = "INSERT INTO cryptsecret "
. "(cryptkeyid, "
. "secretid, "
- . "cryptsecret) "
+ . "cryptsecret, "
+ . "algorithm, "
+ . "algorithmoption, "
+ . "keylength) "
. "VALUES $allvalues";
doQuery($query);
}
@@ -3006,7 +3029,7 @@ function encryptSecrets($secret, $secret
////////////////////////////////////////////////////////////////////////////////
///
-/// \fn updateSecrets($requestid)
+/// \fn checkCryptSecrets($requestid)
///
/// \param $requestid - id from request table
///
@@ -3014,7 +3037,7 @@ function encryptSecrets($secret, $secret
/// $requestid
///
////////////////////////////////////////////////////////////////////////////////
-function updateSecrets($requestid) {
+function checkCryptSecrets($requestid) {
# determine any secretids needed from addomain
$secretids = array();
$query = "SELECT ad.secretid, "
@@ -3050,8 +3073,34 @@ function updateSecrets($requestid) {
}
# find any missing secrets for management nodes
+ $values = getMNcryptkeyUpdates($secretids, $mycryptkeyid);
+ # add secrets
+ addMNcryptkeyUpdates($values);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \fn getMNcryptkeyUpdates($secretidset, $cryptkeyid)
+///
+/// \param $secretidset - array where keys are management node ids and values
+/// are arrays with keys being secretids to add and values being 1:\n
+/// array('mnid1' =>\n
+/// array('secretid1' => 1,\n
+/// 'secretid1' => 1...\n
+/// )\n
+/// )
+/// \param $cryptkeyid - id from cryptkey table
+///
+/// \return array of values to be added to the cryptsecret table
+///
+/// \brief determines what secretids are missing from the set passed in,
creates
+/// encrypted values for each passed in management node, and returns a set of
+/// values that can then be inserted into the cryptsecret table
+///
+////////////////////////////////////////////////////////////////////////////////
+function getMNcryptkeyUpdates($secretidset, $cryptkeyid) {
$values = array();
- foreach($secretids as $mnid => $secretids) {
+ foreach($secretidset as $mnid => $secretids) {
$secretids = array_keys($secretids);
$allsecretids = implode(',', $secretids);
$query = "SELECT ck.id as cryptkeyid, "
@@ -3060,30 +3109,47 @@ function updateSecrets($requestid) {
. "mycs.cryptsecret AS mycryptsecret "
. "FROM cryptkey ck "
. "JOIN (SELECT DISTINCT secretid AS id FROM
cryptsecret) AS s "
- . "JOIN (SELECT cryptsecret, secretid FROM cryptsecret
WHERE cryptkeyid = $mycryptkeyid) AS mycs "
+ . "JOIN (SELECT cryptsecret, secretid FROM cryptsecret
WHERE cryptkeyid = $cryptkeyid) AS mycs "
. "LEFT JOIN cryptsecret cs ON (s.id = cs.secretid AND
ck.id = cs.cryptkeyid) "
. "WHERE mycs.secretid = s.id AND "
. "ck.hostid = $mnid AND "
. "ck.hosttype = 'managementnode' AND "
. "s.id in ($allsecretids) AND "
- . "cs.id IS NULL";
+ . "cs.secretid IS NULL";
$qh = doQuery($query);
while($row = mysql_fetch_assoc($qh)) {
- $secret = decryptSecret($row['mycryptsecret']);
- $encsecret = encryptSecret($secret, $row['cryptkey']);
- $values[] = "({$row['cryptkeyid']}, {$row['secretid']},
'$encsecret')";
+ $secret = decryptSecretKey($row['mycryptsecret']);
+ $encsecret = encryptSecretKey($secret,
$row['cryptkey']);
+ $values[] = "({$row['cryptkeyid']}, {$row['secretid']},
'$encsecret', '"
+ . SYMALGO . "', '" . SYMOPT . "', " . SYMLEN
. ")";
}
}
- # add secrets
- if(! empty($values)) {
- $allvalues = implode(',', $values);
- $query = "INSERT INTO cryptsecret "
- . "(cryptkeyid, "
- . "secretid, "
- . "cryptsecret) "
- . "VALUES $allvalues";
- doQuery($query);
- }
+ return $values;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \fn addMNcryptkeyUpdates($values)
+///
+/// \param $values - array of cryptsecret values that can be joined by commas
+/// and used as the VALUES portion of an INSERT statement
+///
+/// \brief inserts values into cryptsecret table
+///
+////////////////////////////////////////////////////////////////////////////////
+function addMNcryptkeyUpdates($values) {
+ if(empty($values))
+ return;
+ $allvalues = implode(',', $values);
+ $query = "INSERT INTO cryptsecret "
+ . "(cryptkeyid, "
+ . "secretid, "
+ . "cryptsecret, "
+ . "algorithm, "
+ . "algorithmoption, "
+ . "keylength) "
+ . "VALUES $allvalues";
+ doQuery($query);
}
////////////////////////////////////////////////////////////////////////////////
@@ -5783,7 +5849,7 @@ function addRequest($forimaging=0, $revi
// release semaphore lock
cleanSemaphore();
- updateSecrets($requestid);
+ checkCryptSecrets($requestid);
return $requestid;
}
@@ -11926,8 +11992,6 @@ function getVMProfiles($id="") {
. "vp.username, "
. "CHAR_LENGTH(vp.password) as pwdlength, "
. "vp.secretid, "
- . "vp.rsakey, "
- . "vp.rsapub, "
. "vp.eth0generated, "
. "vp.eth1generated "
. "FROM vmprofile vp "
@@ -12067,7 +12131,7 @@ function addContinuationsEntry($nextmode
$salt = generateString(8);
$now = time();
$data = "$salt:$contid:{$user['id']}:$now";
- $edata = encryptData($data, $cryptkey);
+ $edata = encryptData($data, $cryptkey, SYMALGO, SYMOPT, SYMLEN);
$udata = urlencode($edata);
return $udata;
}
@@ -12093,7 +12157,7 @@ function getContinuationsData($data) {
$edata = urldecode($data);
else
$edata = $data;
- if(! ($ddata = decryptData($edata, $cryptkey)))
+ if(! ($ddata = decryptData($edata, $cryptkey, SYMALGO, SYMOPT, SYMLEN)))
return array('error' => 'invalid input');
$items = explode(':', $ddata);
$now = time();
@@ -12529,7 +12593,7 @@ function xmlrpccall() {
xmlrpc_server_register_method($xmlrpc_handle,
"XMLRPCaddImageGroupToComputerGroup", "xmlRPChandler");
xmlrpc_server_register_method($xmlrpc_handle,
"XMLRPCremoveImageGroupFromComputerGroup", "xmlRPChandler");
xmlrpc_server_register_method($xmlrpc_handle,
"XMLRPCfinishBaseImageCapture", "xmlRPChandler");
- xmlrpc_server_register_method($xmlrpc_handle, "XMLRPCupdateSecrets",
"xmlRPChandler");
+ xmlrpc_server_register_method($xmlrpc_handle,
"XMLRPCcheckCryptSecrets", "xmlRPChandler");
print xmlrpc_server_call_method($xmlrpc_handle, $HTTP_RAW_POST_DATA,
'');
xmlrpc_server_destroy($xmlrpc_handle);
@@ -12924,7 +12988,7 @@ function sendJSON($arr, $identifier='',
if($REST)
print json_encode($arr);
elseif(! empty($identifier))
- print "{} && {identifier: '$identifier', 'items':" .
json_encode($arr) . '}'; # TODO
+ print "{} && {identifier: '$identifier', 'items':" .
json_encode($arr) . '}';
else
print '{} && {"items":' . json_encode($arr) . '}';
}
Modified: vcl/trunk/web/.ht-inc/vm.php
URL:
http://svn.apache.org/viewvc/vcl/trunk/web/.ht-inc/vm.php?rev=1797695&r1=1797694&r2=1797695&view=diff
==============================================================================
--- vcl/trunk/web/.ht-inc/vm.php (original)
+++ vcl/trunk/web/.ht-inc/vm.php Mon Jun 5 20:10:44 2017
@@ -259,20 +259,6 @@ function editVMInfo() {
print " </select><img tabindex=0 src=\"images/helpicon.png\"
id=\"genmac1help\" /></td>\n";
print " </tr>\n";
print " <tr>\n";
- print " <th align=right>RSA Public Key:</th>\n";
- print " <td>\n";
- print " <span id=prsapub dojoType=\"dijit.InlineEditBox\"
editor=\"dijit.form.Textarea\"
onChange=\"updateProfile('prsapub','rsapub')\"></span>\n";
- print " <img tabindex=0 src=\"images/helpicon.png\"
id=\"rsapubhelp\" />\n";
- print " </td>\n";
- print " </tr>\n";
- print " <tr>\n";
- print " <th align=right>RSA Private Key File:</th>\n";
- print " <td>\n";
- print " <span id=prsakey dojoType=\"dijit.InlineEditBox\"
onChange=\"updateProfile('prsakey','rsakey');\"></span>\n";
- print " <img tabindex=0 src=\"images/helpicon.png\"
id=\"rsakeyhelp\" />\n";
- print " </td>\n";
- print " </tr>\n";
- print " <tr>\n";
print " <th align=right>Username:</th>\n";
print " <td><span id=pusername dojoType=\"dijit.InlineEditBox\"
onChange=\"updateProfile('pusername', 'username');\"></span><img tabindex=0
src=\"images/helpicon.png\" id=\"usernamehelp\" /></td>\n";
print " </tr>\n";
@@ -346,12 +332,6 @@ function editVMInfo() {
print "<div dojoType=\"dijit.Tooltip\" connectId=\"genmac1help\">\n";
print i("Specifies whether VMs are assigned MAC addresses defined in
the VCL database or if random MAC addresses should be assigned.");
print "</div>\n";
- print "<div dojoType=\"dijit.Tooltip\" connectId=\"rsapubhelp\">\n";
- print i("(Optional) In order to encrypt the VM Host password in the
database, create an RSA public/private key pair on the relevant management
node. Enter the public key here. Note that while this value will be available
to every management node in your system, only those management nodes with the
designated private key will be able to decrypt the password.");
- print "</div>\n";
- print "<div dojoType=\"dijit.Tooltip\" connectId=\"rsakeyhelp\">\n";
- print i("(Optional) In order to decrypt an encrypted VM Host password,
enter the path to a private key on the management node. Any management node
without this private key will not be able to decrypt the password.");
- print "</div>\n";
print "<div dojoType=\"dijit.Tooltip\" connectId=\"usernamehelp\">\n";
print i("Name of the administrative or root user residing on the VM
host.");
print "</div>\n";
@@ -830,7 +810,7 @@ function AJupdateVMprofileItem() {
}
$profileid = processInputVar('profileid', ARG_NUMERIC);
$item = processInputVar('item', ARG_STRING);
- if(!
preg_match('/^(profilename|imageid|resourcepath|folderpath|repositorypath|repositoryimagetypeid|datastorepath|datastoreimagetypeid|vmdisk|vmpath|virtualswitch[0-3]|username|password|eth0generated|eth1generated|rsakey|rsapub)$/',
$item)) {
+ if(!
preg_match('/^(profilename|imageid|resourcepath|folderpath|repositorypath|repositoryimagetypeid|datastorepath|datastoreimagetypeid|vmdisk|vmpath|virtualswitch[0-3]|username|password|eth0generated|eth1generated)$/',
$item)) {
print "alert('Invalid data submitted.');";
return;
}
@@ -867,48 +847,70 @@ function AJupdateVMprofileItem() {
$item = mysql_real_escape_string($item);
$profile = getVMProfiles($profileid);
if($item == 'password') {
- if($profile[$profileid]['rsapub']) {
- $encrypted = encryptDataAsymmetric($newvalue,
$profile[$profileid]['rsapub']);
- $escaped = mysql_real_escape_string($encrypted);
- $query = "UPDATE vmprofile "
- . "SET `encryptedpasswd` = '$escaped', "
- . "`password` = NULL "
- . "WHERE id = $profileid";
- doQuery($query);
- }
- else {
- $pwdlen = strlen($newvalue);
- if($pwdlen == 0) {
- if($profile[$profileid]['pwdlength'] != 0) {
- $secretid = getSecretID('vmprofile',
'secretid', $profileid);
- if($secretid === NULL) {
- print
"dojo.byId('savestatus').innerHTML = '';";
- print "alert('Error saving
password');";
- return;
- }
- deleteSecrets($secretid);
- $query = "UPDATE vmprofile "
- . "SET password = NULL, "
- . "secretid = NULL "
- . "WHERE id = $profileid";
- doQuery($query);
- }
- }
- else {
- $secretid = getSecretID('vmprofile',
'secretid', $profileid);
+ $pwdlen = strlen($newvalue);
+ if($pwdlen == 0) {
+ if($profile[$profileid]['pwdlength'] != 0) {
+ $secretid = getSecretKeyID('vmprofile',
'secretid', $profileid);
if($secretid === NULL) {
print
"dojo.byId('savestatus').innerHTML = '';";
print "alert('Error saving password');";
return;
}
- $encpass = encryptDBdata($newvalue, $secretid);
+ deleteSecretKeys($secretid);
$query = "UPDATE vmprofile "
- . "SET password = '$encpass', "
- . "secretid = '$secretid' "
+ . "SET password = NULL, "
+ . "secretid = NULL "
. "WHERE id = $profileid";
doQuery($query);
}
}
+ else {
+ $secretid = getSecretKeyID('vmprofile', 'secretid',
$profileid);
+ # check that we have a cryptsecret entry for this secret
+ $cryptkeyid = getCryptKeyID();
+ $query = "SELECT cryptsecret "
+ . "FROM cryptsecret "
+ . "WHERE cryptkeyid = $cryptkeyid AND "
+ . "secretid = $secretid";
+ $qh = doQuery($query);
+ if(! ($row = mysql_fetch_assoc($qh))) {
+ # generate a new secret
+ $newsecretid = getSecretKeyID('vmprofile',
'secretid', 0);
+ $delids = array($secretid);
+ if($newsecretid == $secretid) {
+ $delids[] = $secretid;
+ $newsecretid =
getSecretKeyID('addomain', 'secretid', 0);
+ }
+ $delids = implode(',', $delids);
+ # encrypt new secret with any management node
keys
+ $secretidset = array();
+ $query = "SELECT ck.hostid AS mnid "
+ . "FROM cryptkey ck "
+ . "JOIN cryptsecret cs ON (ck.id =
cs.cryptkeyid) "
+ . "WHERE cs.secretid = $secretid AND "
+ . "ck.hosttype = 'managementnode'";
+ $qh = doQuery($query);
+ while($row = mysql_fetch_assoc($qh))
+
$secretidset[$row['mnid']][$newsecretid] = 1;
+ $values = getMNcryptkeyUpdates($secretidset,
$cryptkeyid);
+ addMNcryptkeyUpdates($values);
+ $secretid = $newsecretid;
+ # clean up old cryptsecret entries for
management nodes
+ $query = "DELETE FROM cryptsecret WHERE
secretid IN ($delids)";
+ doQuery($query);
+ }
+ if($secretid === NULL) {
+ print "dojo.byId('savestatus').innerHTML = '';";
+ print "alert('Error saving password');";
+ return;
+ }
+ $encpass = encryptDBdata($newvalue, $secretid);
+ $query = "UPDATE vmprofile "
+ . "SET password = '$encpass', "
+ . "secretid = '$secretid' "
+ . "WHERE id = $profileid";
+ doQuery($query);
+ }
print "dojo.byId('savestatus').innerHTML = 'Saved'; ";
print "setTimeout(function() {dojo.byId('savestatus').innerHTML
= '';}, 3000); ";
print "curprofile.pwdlength = $pwdlen;";
Modified: vcl/trunk/web/.ht-inc/xmlrpcWrappers.php
URL:
http://svn.apache.org/viewvc/vcl/trunk/web/.ht-inc/xmlrpcWrappers.php?rev=1797695&r1=1797694&r2=1797695&view=diff
==============================================================================
--- vcl/trunk/web/.ht-inc/xmlrpcWrappers.php (original)
+++ vcl/trunk/web/.ht-inc/xmlrpcWrappers.php Mon Jun 5 20:10:44 2017
@@ -3739,7 +3739,7 @@ function XMLRPCfinishBaseImageCapture($o
////////////////////////////////////////////////////////////////////////////////
///
-/// \fn XMLRPCupdateSecrets($reservationid)
+/// \fn XMLRPCcheckCryptSecrets($reservationid)
///
/// \param $reservationid - id from reservation table
///
@@ -3750,6 +3750,7 @@ function XMLRPCfinishBaseImageCapture($o
/// \li \b errormsg - error string\n
/// \b success - indicates all secrets were successfully
/// updated\n
+/// \b partial - indicates only some needed secrets were successfully updates\n
/// \b noupdate - indicates no missing values were found to be added to
/// cryptsecret table
///
@@ -3757,12 +3758,13 @@ function XMLRPCfinishBaseImageCapture($o
/// node to be able to process $reservationid
///
////////////////////////////////////////////////////////////////////////////////
-function XMLRPCupdateSecrets($reservationid) {
+function XMLRPCcheckCryptSecrets($reservationid) {
global $user, $xmlrpcBlockAPIUsers;
+
if(! in_array($user['id'], $xmlrpcBlockAPIUsers)) {
return array('status' => 'error',
'errorcode' => 99,
- 'errormsg' => 'access denied for call to
XMLRPCupdateSecrets');
+ 'errormsg' => 'access denied for call to
XMLRPCcheckCryptSecrets');
}
# query to find any cryptkeys that don't have values in cryptsecret
$mycryptkeyid = getCryptKeyID();
@@ -3771,6 +3773,14 @@ function XMLRPCupdateSecrets($reservatio
'errorcode' => 100,
'errormsg' => 'Encryption key missing for this web
server');
}
+ # check for existance of $reservationid
+ $query = "SELECT id FROM reservation WHERE id = $reservationid";
+ $qh = doQuery($query);
+ if(! ($row = mysql_fetch_assoc($qh))) {
+ return array('status' => 'error',
+ 'errorcode' => 101,
+ 'errormsg' => 'Specified reservation does not
exist');
+ }
# determine any secretids needed from addomain
$secretids = array();
$mnid = 0;
@@ -3801,39 +3811,55 @@ function XMLRPCupdateSecrets($reservatio
$mnid = $row['managementnodeid'];
}
+ if(empty($secretids))
+ return array('status' => 'noupdate');
+
# find any missing secrets for management nodes
$values = array();
- $allsecretids = implode(',', $secretids);
+ $fails = array();
+ $secret1 = array_shift($secretids);
+ $subquery = "SELECT $secret1 AS id";
+ if(count($secretids) == 1)
+ $subquery .= " UNION SELECT {$secretids[0]}";
+ else
+ $subquery .= " UNION SELECT " . implode(' UNION SELECT ',
$secretids);
$query = "SELECT ck.id as cryptkeyid, "
. "ck.pubkey as cryptkey, "
. "s.id as secretid, "
. "mycs.cryptsecret AS mycryptsecret "
. "FROM cryptkey ck "
- . "JOIN (SELECT DISTINCT secretid AS id FROM cryptsecret) AS s "
- . "JOIN (SELECT cryptsecret, secretid FROM cryptsecret WHERE
cryptkeyid = $mycryptkeyid) AS mycs "
+ . "JOIN ($subquery) AS s "
+ . "LEFT JOIN (SELECT cryptsecret, secretid "
+ . "FROM cryptsecret "
+ . "WHERE cryptkeyid = $mycryptkeyid) AS mycs ON (s.id
= mycs.secretid) "
. "LEFT JOIN cryptsecret cs ON (s.id = cs.secretid AND ck.id =
cs.cryptkeyid) "
- . "WHERE mycs.secretid = s.id AND "
- . "ck.hostid = $mnid AND "
+ . "WHERE ck.hostid = $mnid AND "
. "ck.hosttype = 'managementnode' AND "
- . "s.id in ($allsecretids) AND "
. "cs.id IS NULL";
$qh = doQuery($query);
while($row = mysql_fetch_assoc($qh)) {
- $secret = decryptSecret($row['mycryptsecret']);
- $encsecret = encryptSecret($secret, $row['cryptkey']);
+ if($row['mycryptsecret'] == NULL) {
+ $fails[] = $row['secretid'];
+ continue;
+ }
+ $secret = decryptSecretKey($row['mycryptsecret']);
+ $encsecret = encryptSecretKey($secret, $row['cryptkey']);
$encsecret = mysql_real_escape_string($encsecret);
- $values[] = "({$row['cryptkeyid']}, {$row['secretid']},
'$encsecret')";
+ $values[] = "({$row['cryptkeyid']}, {$row['secretid']},
'$encsecret', '"
+ . SYMALGO . "', '" . SYMOPT . "', " . SYMLEN . ")";
}
- if(empty($values))
+ if(empty($values) && empty($fails))
return array('status' => 'noupdate');
- $allvalues = implode(',', $values);
- $query = "INSERT INTO cryptsecret "
- . "(cryptkeyid, "
- . "secretid, "
- . "cryptsecret) "
- . "VALUES $allvalues";
- doQuery($query);
+ addMNcryptkeyUpdates($values);
+
+ if(count($values) && count($fails))
+ return array('status' => 'partial');
+ elseif(count($fails))
+ return array('status' => 'error',
+ 'errorcode' => 102,
+ 'errormsg' => 'Encryption secret missing for this
web server');
+
return array('status' => 'success');
}
Modified: vcl/trunk/web/js/vm.js
URL:
http://svn.apache.org/viewvc/vcl/trunk/web/js/vm.js?rev=1797695&r1=1797694&r2=1797695&view=diff
==============================================================================
--- vcl/trunk/web/js/vm.js (original)
+++ vcl/trunk/web/js/vm.js Mon Jun 5 20:10:44 2017
@@ -519,8 +519,6 @@ function getVMprofileDataCB(data, ioArgs
dijit.byId('pvs2').noValueIndicator = '(empty)';
dijit.byId('pvs3').noValueIndicator = '(empty)';
dijit.byId('pusername').noValueIndicator = '(empty)';
- dijit.byId('prsakey').noValueIndicator = '(empty)';
- dijit.byId('prsapub').noValueIndicator = '(empty)';
dijit.byId('pname').setValue(curprofile.profilename);
dijit.byId('presourcepath').setValue(curprofile.resourcepath);
@@ -537,8 +535,6 @@ function getVMprofileDataCB(data, ioArgs
dijit.byId('pusername').setValue(curprofile.username);
dijit.byId('pgenmac0').setValue(curprofile.eth0generated);
dijit.byId('pgenmac1').setValue(curprofile.eth1generated);
- dijit.byId('prsapub').setValue(curprofile.rsapub);
- dijit.byId('prsakey').setValue(curprofile.rsakey);
if(curprofile.pwdlength == 0) {
dojo.byId('ppassword').value = '';
dojo.byId('ppwdconfirm').value = '';