Line 0
Link Here
|
|
|
1 |
--- lib/RT/User.pm.orig 2016-07-18 20:20:17 UTC |
2 |
+++ lib/RT/User.pm |
3 |
@@ -84,6 +84,7 @@ use RT::Principals; |
4 |
use RT::ACE; |
5 |
use RT::Interface::Email; |
6 |
use Text::Password::Pronounceable; |
7 |
+use RT::Util; |
8 |
|
9 |
sub _OverlayAccessible { |
10 |
{ |
11 |
@@ -1087,11 +1088,17 @@ sub IsPassword { |
12 |
# If it's a new-style (>= RT 4.0) password, it starts with a '!' |
13 |
my (undef, $method, @rest) = split /!/, $stored; |
14 |
if ($method eq "bcrypt") { |
15 |
- return 0 unless $self->_GeneratePassword_bcrypt($value, @rest) eq $stored; |
16 |
+ return 0 unless RT::Util::constant_time_eq( |
17 |
+ $self->_GeneratePassword_bcrypt($value, @rest), |
18 |
+ $stored |
19 |
+ ); |
20 |
# Upgrade to a larger number of rounds if necessary |
21 |
return 1 unless $rest[0] < RT->Config->Get('BcryptCost'); |
22 |
} elsif ($method eq "sha512") { |
23 |
- return 0 unless $self->_GeneratePassword_sha512($value, @rest) eq $stored; |
24 |
+ return 0 unless RT::Util::constant_time_eq( |
25 |
+ $self->_GeneratePassword_sha512($value, @rest), |
26 |
+ $stored |
27 |
+ ); |
28 |
} else { |
29 |
$RT::Logger->warn("Unknown hash method $method"); |
30 |
return 0; |
31 |
@@ -1101,16 +1108,28 @@ sub IsPassword { |
32 |
my $hash = MIME::Base64::decode_base64($stored); |
33 |
# Decoding yields 30 byes; first 4 are the salt, the rest are substr(SHA256,0,26) |
34 |
my $salt = substr($hash, 0, 4, ""); |
35 |
- return 0 unless substr(Digest::SHA::sha256($salt . Digest::MD5::md5(Encode::encode( "UTF-8", $value))), 0, 26) eq $hash; |
36 |
+ return 0 unless RT::Util::constant_time_eq( |
37 |
+ substr(Digest::SHA::sha256($salt . Digest::MD5::md5(Encode::encode( "UTF-8", $value))), 0, 26), |
38 |
+ $hash |
39 |
+ ); |
40 |
} elsif (length $stored == 32) { |
41 |
# Hex nonsalted-md5 |
42 |
- return 0 unless Digest::MD5::md5_hex(Encode::encode( "UTF-8", $value)) eq $stored; |
43 |
+ return 0 unless RT::Util::constant_time_eq( |
44 |
+ Digest::MD5::md5_hex(Encode::encode( "UTF-8", $value)), |
45 |
+ $stored |
46 |
+ ); |
47 |
} elsif (length $stored == 22) { |
48 |
# Base64 nonsalted-md5 |
49 |
- return 0 unless Digest::MD5::md5_base64(Encode::encode( "UTF-8", $value)) eq $stored; |
50 |
+ return 0 unless RT::Util::constant_time_eq( |
51 |
+ Digest::MD5::md5_base64(Encode::encode( "UTF-8", $value)), |
52 |
+ $stored |
53 |
+ ); |
54 |
} elsif (length $stored == 13) { |
55 |
# crypt() output |
56 |
- return 0 unless crypt(Encode::encode( "UTF-8", $value), $stored) eq $stored; |
57 |
+ return 0 unless RT::Util::constant_time_eq( |
58 |
+ crypt(Encode::encode( "UTF-8", $value), $stored), |
59 |
+ $stored |
60 |
+ ); |
61 |
} else { |
62 |
$RT::Logger->warning("Unknown password form"); |
63 |
return 0; |
64 |
@@ -1206,19 +1225,20 @@ sub GenerateAuthString { |
65 |
|
66 |
=head3 ValidateAuthString |
67 |
|
68 |
-Takes auth string and protected string. Returns true is protected string |
69 |
+Takes auth string and protected string. Returns true if protected string |
70 |
has been protected by user's L</AuthToken>. See also L</GenerateAuthString>. |
71 |
|
72 |
=cut |
73 |
|
74 |
sub ValidateAuthString { |
75 |
my $self = shift; |
76 |
- my $auth_string = shift; |
77 |
+ my $auth_string_to_validate = shift; |
78 |
my $protected = shift; |
79 |
|
80 |
my $str = Encode::encode( "UTF-8", $self->AuthToken . $protected ); |
81 |
+ my $valid_auth_string = substr(Digest::MD5::md5_hex($str),0,16); |
82 |
|
83 |
- return $auth_string eq substr(Digest::MD5::md5_hex($str),0,16); |
84 |
+ return RT::Util::constant_time_eq( $auth_string_to_validate, $valid_auth_string ); |
85 |
} |
86 |
|
87 |
=head2 SetDisabled |