Provisional OAuth, OpenID token check timing attack patches

This commit is contained in:
Brion Vibber 2010-07-19 16:47:49 -07:00
parent d51820adc5
commit f0620a74c8
2 changed files with 54 additions and 1 deletions

View File

@ -374,7 +374,42 @@ class Auth_OpenID_Association {
} }
$calculated_sig = $this->getMessageSignature($message); $calculated_sig = $this->getMessageSignature($message);
return $calculated_sig == $sig;
return $this->constantTimeCompare($calculated_sig, $sig);
}
/**
* String comparison function which will complete in a constant time
* for strings of any given matching length, to help prevent an attacker
* from distinguishing how much of a signature token they have guessed
* correctly.
*
* For this usage, it's assumed that the length of the string is known,
* so we may safely short-circuit on mismatched lengths which will be known
* to be invalid by the attacker.
*
* http://lists.openid.net/pipermail/openid-security/2010-July/001156.html
* http://rdist.root.org/2010/01/07/timing-independent-array-comparison/
*/
private function constantTimeCompare($a, $b)
{
$len = strlen($a);
if (strlen($b) !== $len) {
// Short-circuit on length mismatch; attackers will already know
// the correct target length so this is safe.
return false;
}
if ($len == 0) {
// 0-length valid input shouldn't really happen. :)
return true;
}
$result = 0;
for ($i = 0; $i < strlen($a); $i++) {
// We use scary bitwise operations to avoid logical short-circuits
// in lower-level code.
$result |= ord($a{$i}) ^ ord($b{$i});
}
return ($result == 0);
} }
} }

View File

@ -54,6 +54,24 @@ class OAuthSignatureMethod {/*{{{*/
public function check_signature(&$request, $consumer, $token, $signature) { public function check_signature(&$request, $consumer, $token, $signature) {
$built = $this->build_signature($request, $consumer, $token); $built = $this->build_signature($request, $consumer, $token);
return $built == $signature; return $built == $signature;
// Check for zero length, although unlikely here
if (strlen($built) == 0 || strlen($signature) == 0) {
return false;
}
if (strlen($built) != strlen($signature)) {
return false;
}
$result = 0;
// Avoid a timing leak with a (hopefully) time insensitive compare
for ($i = 0; $i < strlen($signature); $i++) {
$result |= ord($built{$i}) ^ ord($signature{$i});
}
return $result == 0;
} }
}/*}}}*/ }/*}}}*/