Make all hash algorithms available (but whitelist by default)

sha1 is whitelisted only because StatusNet requires it.
This commit is contained in:
Mikael Nordfeldth 2016-06-28 11:51:11 +02:00
parent 3166a04cef
commit a833eaa651
2 changed files with 27 additions and 17 deletions

View File

@ -64,6 +64,9 @@ $default =
'notice' => null, // site wide notice text 'notice' => null, // site wide notice text
'build' => 1, // build number, for code-dependent cache 'build' => 1, // build number, for code-dependent cache
), ),
'security' =>
array('hash_algos' => ['sha1', 'sha256', 'sha512'], // set to null for anything that hash_hmac() can handle (and is in hash_algos())
),
'db' => 'db' =>
array('database' => null, // must be set array('database' => null, // must be set
'schema_location' => INSTALLDIR . '/classes', 'schema_location' => INSTALLDIR . '/classes',

View File

@ -442,10 +442,10 @@ class FeedSub extends Managed_DataObject
*/ */
public function receive($post, $hmac) public function receive($post, $hmac)
{ {
common_log(LOG_INFO, __METHOD__ . ": packet for \"" . $this->getUri() . "\"! $hmac $post"); common_log(LOG_INFO, sprintf(__METHOD__.': packet for %s with HMAC %s', _ve($this->getUri()), _ve($hmac)));
if (!in_array($this->sub_state, array('active', 'nohub'))) { if (!in_array($this->sub_state, array('active', 'nohub'))) {
common_log(LOG_ERR, __METHOD__ . ": ignoring PuSH for inactive feed " . $this->getUri() . " (in state '$this->sub_state')"); common_log(LOG_ERR, sprintf(__METHOD__.': ignoring PuSH for inactive feed %s (in state %s)', _ve($this->getUri()), _ve($this->sub_state)));
return; return;
} }
@ -480,7 +480,7 @@ class FeedSub extends Managed_DataObject
* shared secret that was set up at subscription time. * shared secret that was set up at subscription time.
* *
* If we don't have a shared secret, there should be no signature. * If we don't have a shared secret, there should be no signature.
* If we we do, our the calculated HMAC should match theirs. * If we do, our calculated HMAC should match theirs.
* *
* @param string $post raw XML source as POSTed to us * @param string $post raw XML source as POSTed to us
* @param string $hmac X-Hub-Signature HTTP header value, or empty * @param string $hmac X-Hub-Signature HTTP header value, or empty
@ -489,29 +489,36 @@ class FeedSub extends Managed_DataObject
protected function validatePushSig($post, $hmac) protected function validatePushSig($post, $hmac)
{ {
if ($this->secret) { if ($this->secret) {
if (preg_match('/^sha1=([0-9a-fA-F]{40})$/', $hmac, $matches)) { // {3,16} because shortest hash algorithm name is 3 characters (md2,md4,md5) and longest
$their_hmac = strtolower($matches[1]); // is currently 11 characters, but we'll leave some margin in the end...
$our_hmac = hash_hmac('sha1', $post, $this->secret); if (preg_match('/^([0-9a-zA-Z\-\,]{3,16})=([0-9a-fA-F]+)$/', $hmac, $matches)) {
$hash_algo = strtolower($matches[1]);
$their_hmac = strtolower($matches[2]);
common_debug(sprintf(__METHOD__ . ': PuSH from feed %s uses HMAC algorithm %s with value: %s', _ve($this->getUri()), _ve($hash_algo), _ve($their_hmac)));
if (!in_array($hash_algo, hash_algos())) {
// We can't handle this at all, PHP doesn't recognize the algorithm name ('md5', 'sha1', 'sha256' etc: https://secure.php.net/manual/en/function.hash-algos.php)
common_log(LOG_ERR, sprintf(__METHOD__.': HMAC algorithm %s unsupported, not found in PHP hash_algos()', _ve($hash_algo)));
return false;
} elseif (!is_null(common_config('security', 'hash_algos')) && !in_array($hash_algo, common_config('security', 'hash_algos'))) {
// We _won't_ handle this because there is a list of accepted hash algorithms and this one is not in it.
common_log(LOG_ERR, sprintf(__METHOD__.': Whitelist for HMAC algorithms exist, but %s is not included.', _ve($hash_algo)));
return false;
}
$our_hmac = hash_hmac($hash_algo, $post, $this->secret);
if ($their_hmac === $our_hmac) { if ($their_hmac === $our_hmac) {
return true; return true;
} }
if (common_config('feedsub', 'debug')) { common_log(LOG_ERR, sprintf(__METHOD__.': ignoring PuSH with bad HMAC hash: got %s, expected %s for feed %s from hub %s', _ve($their_hmac), _ve($our_hmac), _ve($this->getUri()), _ve($this->huburi)));
$tempfile = tempnam(sys_get_temp_dir(), 'feedsub-receive');
if ($tempfile) {
file_put_contents($tempfile, $post);
}
common_log(LOG_ERR, __METHOD__ . ": ignoring PuSH with bad SHA-1 HMAC: got $their_hmac, expected $our_hmac for feed " . $this->getUri() . " on $this->huburi; saved to $tempfile");
} else { } else {
common_log(LOG_ERR, __METHOD__ . ": ignoring PuSH with bad SHA-1 HMAC: got $their_hmac, expected $our_hmac for feed " . $this->getUri() . " on $this->huburi"); common_log(LOG_ERR, sprintf(__METHOD__.': ignoring PuSH with bogus HMAC==', _ve($hmac)));
}
} else {
common_log(LOG_ERR, __METHOD__ . ": ignoring PuSH with bogus HMAC '$hmac'");
} }
} else { } else {
if (empty($hmac)) { if (empty($hmac)) {
return true; return true;
} else { } else {
common_log(LOG_ERR, __METHOD__ . ": ignoring PuSH with unexpected HMAC '$hmac'"); common_log(LOG_ERR, sprintf(__METHOD__.': ignoring PuSH with unexpected HMAC==%s', _ve($hmac)));
} }
} }
return false; return false;