From: donal72 Date: Mon, 15 Jan 2007 09:03:39 +0000 (+0000) Subject: Mnet: Key rotation: A more robust changeover for fresh keys X-Git-Url: http://git.mjollnir.org/gw?a=commitdiff_plain;h=9dd0e6115de6b73759cead6643ce64acdf6a6046;p=moodle.git Mnet: Key rotation: A more robust changeover for fresh keys --- diff --git a/mnet/remote_client.php b/mnet/remote_client.php index 2cfcfcffc4..649e7de657 100644 --- a/mnet/remote_client.php +++ b/mnet/remote_client.php @@ -46,5 +46,27 @@ class mnet_remote_client extends mnet_peer { return false; } + + function refresh_key() { + // set up an RPC request + $mnetrequest = new mnet_xmlrpc_client(); + // Use any method - listServices is pretty lightweight. + $mnetrequest->set_method('system/listServices'); + + // Do RPC call and store response + if ($mnetrequest->send($this) === true) { + // Ok - we actually don't care about the result + $temp = new mnet_peer(); + $temp->set_id($this->id); + if($this->public_key != $temp->public_key) { + $newkey = param_clean($temp->public_key, PARAM_PEM); + if(!empty($newkey)) { + $this->public_key = $newkey; + return true; + } + } + } + return false; + } } ?> \ No newline at end of file diff --git a/mnet/xmlrpc/client.php b/mnet/xmlrpc/client.php index 663a7d3e6f..96e5f0d897 100644 --- a/mnet/xmlrpc/client.php +++ b/mnet/xmlrpc/client.php @@ -203,6 +203,25 @@ class mnet_xmlrpc_client { $isOpen = openssl_open(base64_decode($data), $payload, base64_decode($key), $MNET->get_private_key()); if (!$isOpen) { + // Decryption failed... let's try our archived keys + $result = get_config('mnet', 'openssl_history'); + if(empty($result)) { + set_config('openssl_history', serialize(array()), 'mnet'); + $result = get_config('mnet', 'openssl_history'); + } + $openssl_history = unserialize($result->value); + foreach($openssl_history as $keyset) { + $keyresource = openssl_pkey_get_private($keyset['keypair_PEM']); + $isOpen = openssl_open(base64_decode($data), $payload, base64_decode($key), $keyresource); + if ($isOpen) { + // It's an older code, sir, but it checks out + break; + } + } + } + + if (!$isOpen) { + trigger_error("None of our keys could open the payload from host {$mnet_peer->wwwroot} with id {$mnet_peer->id}."); return false; } @@ -256,14 +275,22 @@ class mnet_xmlrpc_client { if($this->response['faultCode'] == 7025 && empty($mnet_peer->re_key)) { $record = new stdClass(); $record->id = $mnet_peer->id; - $record->public_key = $this->response['faultString']; - $details = openssl_x509_parse($record->public_key); - $record->public_key_expires = $details['validTo_time_t']; - update_record('mnet_host', $record); - $mnet_peer2 = new mnet_peer(); - $mnet_peer2->set_id($record->id); - $mnet_peer2->re_key = true; - $this->send($mnet_peer2); + if($this->response['faultString'] == clean_param($this->response['faultString'], PARAM_PEM)) { + $record->public_key = $this->response['faultString']; + $details = openssl_x509_parse($record->public_key); + if(is_array($details) && isset($details['validTo_time_t'])) { + $record->public_key_expires = $details['validTo_time_t']; + update_record('mnet_host', $record); + $mnet_peer2 = new mnet_peer(); + $mnet_peer2->set_id($record->id); + $mnet_peer2->re_key = true; + $this->send($mnet_peer2); + } else { + $this->error[] = $this->response['faultCode'] . " : " . $this->response['faultString']; + } + } else { + $this->error[] = $this->response['faultCode'] . " : " . $this->response['faultString']; + } } else { $this->error[] = $this->response['faultCode'] . " : " . $this->response['faultString']; } diff --git a/mnet/xmlrpc/server.php b/mnet/xmlrpc/server.php index b097586b90..ad36654b01 100644 --- a/mnet/xmlrpc/server.php +++ b/mnet/xmlrpc/server.php @@ -121,6 +121,15 @@ function mnet_server_strip_wrappers($HTTP_RAW_POST_DATA) { $crypt_parser = new mnet_encxml_parser(); $crypt_parser->parse($HTTP_RAW_POST_DATA); + // Make sure we know who we're talking to + $host_record_exists = $MNET_REMOTE_CLIENT->set_wwwroot($crypt_parser->remote_wwwroot); + + if (false == $host_record_exists) { + exit(mnet_server_fault(7020, 'wrong-wwwroot', $crypt_parser->remote_wwwroot)); + } elseif (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] != $MNET_REMOTE_CLIENT->ip_address) { + exit(mnet_server_fault(7017, 'wrong-ip')); + } + if ($crypt_parser->payload_encrypted) { $key = array_pop($crypt_parser->cipher); // This key is Symmetric @@ -128,8 +137,8 @@ function mnet_server_strip_wrappers($HTTP_RAW_POST_DATA) { $crypt_parser->free_resource(); - // Initialize payload var - $payload = ''; + $payload = ''; // Initialize payload var + $push_current_key = false; // True if we need to push a fresh key to the peer // &$payload $isOpen = openssl_open(base64_decode($data), $payload, base64_decode($key), $MNET->get_private_key()); @@ -147,7 +156,7 @@ function mnet_server_strip_wrappers($HTTP_RAW_POST_DATA) { $isOpen = openssl_open(base64_decode($data), $payload, base64_decode($key), $keyresource); if ($isOpen) { // It's an older code, sir, but it checks out - exit(mnet_server_fault(7025, $MNET->public_key)); + $push_current_key = true; } } } @@ -170,12 +179,12 @@ function mnet_server_strip_wrappers($HTTP_RAW_POST_DATA) { unset($payload); - $host_record_exists = $MNET_REMOTE_CLIENT->set_wwwroot($sig_parser->remote_wwwroot); - - if (false == $host_record_exists) { - exit(mnet_server_fault(7020, 'wrong-wwwroot', $sig_parser->remote_wwwroot)); - } elseif (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] != $MNET_REMOTE_CLIENT->ip_address) { - exit(mnet_server_fault(7017, 'wrong-ip')); + // if the peer used one of our public keys that have expired, we will + // return a signed/encrypted error message with our new public key + if($push_current_key) { + // NOTE: Here, we use the 'mnet_server_fault_xml' to avoid + // get_string being called on our public_key + exit(mnet_server_fault_xml(7025, $MNET->public_key)); } /** @@ -194,7 +203,16 @@ function mnet_server_strip_wrappers($HTTP_RAW_POST_DATA) { if ($signature_verified == 1) { // Parse the XML } elseif ($signature_verified == 0) { - exit(mnet_server_fault(710, 'verifysignature-invalid')); + $currkey = mnet_get_public_key($MNET_REMOTE_CLIENT->wwwroot); + if($currkey != $certificate) { + // Has the server updated its certificate since our last + // handshake? + if(!$MNET_REMOTE_CLIENT->refresh_key()) { + exit(mnet_server_fault(7026, 'verifysignature-invalid')); + } + } else { + exit(mnet_server_fault(710, 'verifysignature-invalid')); + } } else { exit(mnet_server_fault(711, 'verifysignature-error')); }