aboutsummaryrefslogtreecommitdiffstats
path: root/includes/session
diff options
context:
space:
mode:
authorGergő Tisza <gtisza@wikimedia.org>2016-05-30 22:05:14 +0000
committerGergő Tisza <gtisza@wikimedia.org>2016-05-31 16:01:07 +0000
commitc331a1ae08a98fc6300dce8d407d369db271256f (patch)
tree89481cb2d093e8562fdf5e857d385e1aa7d7e117 /includes/session
parent3ef1ed0bed9be109843ffe58994f9d36133c504b (diff)
downloadmediawikicore-c331a1ae08a98fc6300dce8d407d369db271256f.tar.gz
mediawikicore-c331a1ae08a98fc6300dce8d407d369db271256f.zip
Fix encryption code in Session
* verify that the algorithm that's about to be used is available * fix exception namespace Bug: T136587 Change-Id: I9f8636bef0e10b4f2b8bfe232a26a8c33376ca04
Diffstat (limited to 'includes/session')
-rw-r--r--includes/session/Session.php139
1 files changed, 82 insertions, 57 deletions
diff --git a/includes/session/Session.php b/includes/session/Session.php
index 3d48101acc4a..719f905ee24d 100644
--- a/includes/session/Session.php
+++ b/includes/session/Session.php
@@ -406,6 +406,38 @@ final class Session implements \Countable, \Iterator, \ArrayAccess {
}
/**
+ * Decide what type of encryption to use, based on system capabilities.
+ * @return array
+ */
+ private function getEncryptionAlgorithm() {
+ global $wgSessionInsecureSecrets;
+
+ if (
+ function_exists( 'openssl_encrypt' )
+ && in_array( 'aes-256-ctr', openssl_get_cipher_methods(), true )
+ ) {
+ return [ 'openssl', 'aes-256-ctr' ];
+ } elseif (
+ function_exists( 'mcrypt_encrypt' )
+ && in_array( 'rijndael-128', mcrypt_list_algorithms(), true )
+ && in_array( 'ctr', mcrypt_list_modes(), true )
+ ) {
+ return [ 'mcrypt', 'rijndael-128', 'ctr' ];
+ } elseif ( $wgSessionInsecureSecrets ) {
+ // @todo: import a pure-PHP library for AES instead of this
+ return [ 'insecure' ];
+ } else {
+ throw new \BadMethodCallException(
+ 'Encryption is not available. You really should install the PHP OpenSSL extension, ' .
+ 'or failing that the mcrypt extension. But if you really can\'t and you\'re willing ' .
+ 'to accept insecure storage of sensitive session data, set ' .
+ '$wgSessionInsecureSecrets = true in LocalSettings.php to make this exception go away.'
+ );
+ }
+
+ }
+
+ /**
* Set a value in the session, encrypted
*
* This relies on the secrecy of $wgSecretKey (by default), or $wgSessionSecret.
@@ -414,8 +446,6 @@ final class Session implements \Countable, \Iterator, \ArrayAccess {
* @param mixed $value
*/
public function setSecret( $key, $value ) {
- global $wgSessionInsecureSecrets;
-
list( $encKey, $hmacKey ) = $this->getSecretKeys();
$serialized = serialize( $value );
@@ -425,27 +455,27 @@ final class Session implements \Countable, \Iterator, \ArrayAccess {
// Encrypt
// @todo: import a pure-PHP library for AES instead of doing $wgSessionInsecureSecrets
$iv = \MWCryptRand::generate( 16, true );
- if ( function_exists( 'openssl_encrypt' ) ) {
- $ciphertext = openssl_encrypt( $serialized, 'aes-256-ctr', $encKey, OPENSSL_RAW_DATA, $iv );
- if ( $ciphertext === false ) {
- throw new UnexpectedValueException( 'Encryption failed: ' . openssl_error_string() );
- }
- } elseif ( function_exists( 'mcrypt_encrypt' ) ) {
- $ciphertext = mcrypt_encrypt( 'rijndael-128', $encKey, $serialized, 'ctr', $iv );
- if ( $ciphertext === false ) {
- throw new UnexpectedValueException( 'Encryption failed' );
- }
- } elseif ( $wgSessionInsecureSecrets ) {
- $ex = new \Exception( 'No encryption is available, storing data as plain text' );
- $this->logger->warning( $ex->getMessage(), [ 'exception' => $ex ] );
- $ciphertext = $serialized;
- } else {
- throw new \BadMethodCallException(
- 'Encryption is not available. You really should install the PHP OpenSSL extension, ' .
- 'or failing that the mcrypt extension. But if you really can\'t and you\'re willing ' .
- 'to accept insecure storage of sensitive session data, set ' .
- '$wgSessionInsecureSecrets = true in LocalSettings.php to make this exception go away.'
- );
+ $algorithm = $this->getEncryptionAlgorithm();
+ switch ( $algorithm[0] ) {
+ case 'openssl':
+ $ciphertext = openssl_encrypt( $serialized, $algorithm[1], $encKey, OPENSSL_RAW_DATA, $iv );
+ if ( $ciphertext === false ) {
+ throw new \UnexpectedValueException( 'Encryption failed: ' . openssl_error_string() );
+ }
+ break;
+ case 'mcrypt':
+ $ciphertext = mcrypt_encrypt( $algorithm[1], $encKey, $serialized, $algorithm[2], $iv );
+ if ( $ciphertext === false ) {
+ throw new \UnexpectedValueException( 'Encryption failed' );
+ }
+ break;
+ case 'insecure':
+ $ex = new \Exception( 'No encryption is available, storing data as plain text' );
+ $this->logger->warning( $ex->getMessage(), [ 'exception' => $ex ] );
+ $ciphertext = $serialized;
+ break;
+ default:
+ throw new \LogicException( 'invalid algorithm' );
}
// Seal
@@ -464,8 +494,6 @@ final class Session implements \Countable, \Iterator, \ArrayAccess {
* @return mixed
*/
public function getSecret( $key, $default = null ) {
- global $wgSessionInsecureSecrets;
-
// Fetch
$encrypted = $this->get( $key, null );
if ( $encrypted === null ) {
@@ -493,38 +521,35 @@ final class Session implements \Countable, \Iterator, \ArrayAccess {
}
// Decrypt
- // @todo: import a pure-PHP library for AES instead of doing $wgSessionInsecureSecrets
- if ( function_exists( 'openssl_decrypt' ) ) {
- $serialized = openssl_decrypt(
- base64_decode( $ciphertext ), 'aes-256-ctr', $encKey, OPENSSL_RAW_DATA, base64_decode( $iv )
- );
- if ( $serialized === false ) {
- $ex = new \Exception( 'Decyption failed: ' . openssl_error_string() );
- $this->logger->debug( $ex->getMessage(), [ 'exception' => $ex ] );
- return $default;
- }
- } elseif ( function_exists( 'mcrypt_decrypt' ) ) {
- $serialized = mcrypt_decrypt(
- 'rijndael-128', $encKey, base64_decode( $ciphertext ), 'ctr', base64_decode( $iv )
- );
- if ( $serialized === false ) {
- $ex = new \Exception( 'Decyption failed' );
- $this->logger->debug( $ex->getMessage(), [ 'exception' => $ex ] );
- return $default;
- }
- } elseif ( $wgSessionInsecureSecrets ) {
- $ex = new \Exception(
- 'No encryption is available, retrieving data that was stored as plain text'
- );
- $this->logger->warning( $ex->getMessage(), [ 'exception' => $ex ] );
- $serialized = base64_decode( $ciphertext );
- } else {
- throw new \BadMethodCallException(
- 'Encryption is not available. You really should install the PHP OpenSSL extension, ' .
- 'or failing that the mcrypt extension. But if you really can\'t and you\'re willing ' .
- 'to accept insecure storage of sensitive session data, set ' .
- '$wgSessionInsecureSecrets = true in LocalSettings.php to make this exception go away.'
- );
+ $algorithm = $this->getEncryptionAlgorithm();
+ switch ( $algorithm[0] ) {
+ case 'openssl':
+ $serialized = openssl_decrypt( base64_decode( $ciphertext ), $algorithm[1], $encKey,
+ OPENSSL_RAW_DATA, base64_decode( $iv ) );
+ if ( $serialized === false ) {
+ $ex = new \Exception( 'Decyption failed: ' . openssl_error_string() );
+ $this->logger->debug( $ex->getMessage(), [ 'exception' => $ex ] );
+ return $default;
+ }
+ break;
+ case 'mcrypt':
+ $serialized = mcrypt_decrypt( $algorithm[1], $encKey, base64_decode( $ciphertext ),
+ $algorithm[2], base64_decode( $iv ) );
+ if ( $serialized === false ) {
+ $ex = new \Exception( 'Decyption failed' );
+ $this->logger->debug( $ex->getMessage(), [ 'exception' => $ex ] );
+ return $default;
+ }
+ break;
+ case 'insecure':
+ $ex = new \Exception(
+ 'No encryption is available, retrieving data that was stored as plain text'
+ );
+ $this->logger->warning( $ex->getMessage(), [ 'exception' => $ex ] );
+ $serialized = base64_decode( $ciphertext );
+ break;
+ default:
+ throw new \LogicException( 'invalid algorithm' );
}
$value = unserialize( $serialized );