Skip to content

Added constant time string comparison to avoid possible time-based attacks. #3836

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Nov 21, 2017
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion libraries/ArduinoOTA/ArduinoOTA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ void ArduinoOTAClass::_onRx(){
String result = _challengemd5.toString();

ota_ip.addr = (uint32_t)_ota_ip;
if(result.equals(response)){
if(constantTimeEquals(result, response)){
_state = OTA_RUNUPDATE;
} else {
_udp_ota->append("Authentication Failed", 21);
Expand Down Expand Up @@ -358,6 +358,27 @@ int ArduinoOTAClass::getCommand() {
return _cmd;
}

// To avoid possible time-based attacks present function compares given
// strings in a constant time.
bool ArduinoOTAClass::constantTimeEquals(const String & string1,
const String & string2) {

// Preliminary check
if(string1.length() != string2.length()) {
return false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

}

// Evaluates every character
bool equals = true;
unsigned int len = string1.length();
for(unsigned int i = 0; i < len; i++){
equals &= (string1.charAt(i) == string2.charAt(i));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be interesting to see the generated code for this loop at -O2 optimization level... I wonder whether the compiler is smart enough to convert this 'and' into 'branch-if-zero'.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. Maybe better to write not so easily optimizable code. Ill think about that

}

// Return result
return equals;
}

#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_ARDUINOOTA)
ArduinoOTAClass ArduinoOTA;
#endif
1 change: 1 addition & 0 deletions libraries/ArduinoOTA/ArduinoOTA.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ class ArduinoOTAClass
void _onRx(void);
int parseInt(void);
String readStringUntil(char end);
bool constantTimeEquals(const String &string1, const String &string2);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: can this method be moved into String class, so reuse in other places is possible?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I'll do that

};

#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_ARDUINOOTA)
Expand Down