40
40
import com .sun .identity .shared .debug .Debug ;
41
41
import com .sun .identity .sm .SMSException ;
42
42
import java .io .IOException ;
43
+ import java .security .MessageDigest ;
43
44
import java .util .ArrayList ;
44
45
import java .util .Arrays ;
45
46
import java .util .Collections ;
@@ -599,7 +600,7 @@ private boolean checkOTP(String otp, AMIdentity id, OathDeviceSettings settings)
599
600
for (int i = 0 ; i <= windowSize ; i ++) {
600
601
otpGen = HOTPAlgorithm .generateOTP (secretKeyBytes , counter + i , passLen , checksum ,
601
602
truncationOffset );
602
- if (otpGen . equals ( otp )) {
603
+ if (isEqual ( otpGen , otp )) {
603
604
//OTP is correct set the counter value to counter+i (+1 for having been successful)
604
605
setCounterAttr (id , counter + i + 1 , settings );
605
606
return true ;
@@ -633,6 +634,11 @@ private boolean checkOTP(String otp, AMIdentity id, OathDeviceSettings settings)
633
634
//get Time Step
634
635
long localTime = (time / totpTimeStep ) + (settings .getClockDriftSeconds () / totpTimeStep );
635
636
637
+ if (lastLoginTimeStep == localTime ){
638
+ debug .error ("OATH.checkOTP(): Login failed attempting to use the same OTP in same Time Step: " + localTime );
639
+ throw new InvalidPasswordException (amAuthOATH , "authFailed" , null , userName , null );
640
+ }
641
+
636
642
boolean sameWindow = false ;
637
643
638
644
//check if we are in the time window to prevent 2 logins within the window using the same OTP
@@ -648,7 +654,7 @@ private boolean checkOTP(String otp, AMIdentity id, OathDeviceSettings settings)
648
654
String passLenStr = Integer .toString (passLen );
649
655
otpGen = TOTPAlgorithm .generateTOTP (secretKey , Long .toHexString (localTime ), passLenStr );
650
656
651
- if (otpGen . equals ( otp )) {
657
+ if (isEqual ( otpGen , otp )) {
652
658
setLoginTime (id , localTime , settings );
653
659
return true ;
654
660
}
@@ -660,19 +666,19 @@ private boolean checkOTP(String otp, AMIdentity id, OathDeviceSettings settings)
660
666
//check time step after current time
661
667
otpGen = TOTPAlgorithm .generateTOTP (secretKey , Long .toHexString (time1 ), passLenStr );
662
668
663
- if (otpGen . equals ( otp )) {
669
+ if (isEqual ( otpGen , otp )) {
664
670
setLoginTime (id , time1 , settings );
665
671
return true ;
666
672
}
667
673
668
674
//check time step before current time
669
675
otpGen = TOTPAlgorithm .generateTOTP (secretKey , Long .toHexString (time2 ), passLenStr );
670
676
671
- if (otpGen . equals ( otp ) && sameWindow ) {
677
+ if (isEqual ( otpGen , otp ) && sameWindow ) {
672
678
debug .error ("OATH.checkOTP() : Logging in in the same window with a OTP that is older " +
673
679
"than the current times OTP" );
674
680
return false ;
675
- } else if (otpGen . equals ( otp ) && !sameWindow ) {
681
+ } else if (isEqual ( otpGen , otp ) && !sameWindow ) {
676
682
setLoginTime (id , time2 , settings );
677
683
return true ;
678
684
}
@@ -790,4 +796,16 @@ private void setLoginTime(AMIdentity id, long time, OathDeviceSettings settings)
790
796
devicesDao .saveDeviceProfiles (id .getName (), id .getRealm (),
791
797
Collections .singletonList (JsonConversionUtils .toJsonValue (settings )));
792
798
}
799
+
800
+ /**
801
+ * Perform time constant equality check.
802
+ * Both values should not be null.
803
+ *
804
+ * @param str1 first value
805
+ * @param str2 second vale
806
+ * @return true if values are equal
807
+ */
808
+ private boolean isEqual (String str1 , String str2 ) {
809
+ return MessageDigest .isEqual (str1 .getBytes (), str2 .getBytes ());
810
+ }
793
811
}
0 commit comments