Skip to content
Snippets Groups Projects
Commit a01340e5 authored by Marcus Comstedt's avatar Marcus Comstedt
Browse files

__builtin.Nettle.Hash.SCRAM: Validate incoming nonce and make it 7bit

Also remove lots of superfluous softcasts.
parent faa6db04
No related branches found
No related tags found
No related merge requests found
...@@ -579,8 +579,8 @@ final void SCRAM_set_salted_password(string(8bit) SaltedPassword, string key) { ...@@ -579,8 +579,8 @@ final void SCRAM_set_salted_password(string(8bit) SaltedPassword, string key) {
//! @[client_1], @[server_1] //! @[client_1], @[server_1]
class SCRAM class SCRAM
{ {
private string(8bit) first, nonce; private string(8bit) first;
private string(7bit) server_signature; private string(7bit) nonce, server_signature;
private string(7bit) encode64(string(8bit) raw) { private string(7bit) encode64(string(8bit) raw) {
return MIME.encode_base64(raw, 1); return MIME.encode_base64(raw, 1);
...@@ -590,6 +590,15 @@ class SCRAM ...@@ -590,6 +590,15 @@ class SCRAM
return encode64(random_string(18)); return encode64(random_string(18));
} }
private string(7bit) validate_nonce(string r) {
[int min, int max] = String.range(r);
if (min < 32 || max > 126 || search(r, ",") >= 0)
/* Invalid nonce */
return 0;
/* Check above guarantees 7bit-ness */
return [string(7bit)]r;
}
private string(7bit) clientproof(string(8bit) salted_password) { private string(7bit) clientproof(string(8bit) salted_password) {
_HMAC.State hmacsaltedpw = HMAC(salted_password); _HMAC.State hmacsaltedpw = HMAC(salted_password);
salted_password = hmacsaltedpw("Client Key"); salted_password = hmacsaltedpw("Client Key");
...@@ -614,9 +623,13 @@ class SCRAM ...@@ -614,9 +623,13 @@ class SCRAM
//! @[client_2] //! @[client_2]
string(7bit) client_1(void|string username) { string(7bit) client_1(void|string username) {
nonce = randomstring(); nonce = randomstring();
return [string(7bit)](first = [string(8bit)]sprintf("n,,n=%s,r=%s", string(7bit) request =
username && username != "" ? Standards.IDNA.to_ascii(username, 1) : "", sprintf("n,,n=%s,r=%s",
nonce)); username && username != "" ?
[string(7bit)]Standards.IDNA.to_ascii(username, 1) : "",
nonce);
first = request;
return request;
} }
//! Server-side step 1 in the SCRAM handshake. //! Server-side step 1 in the SCRAM handshake.
...@@ -634,9 +647,10 @@ class SCRAM ...@@ -634,9 +647,10 @@ class SCRAM
constant format = "n,,n=%s,r=%s"; constant format = "n,,n=%s,r=%s";
string username, r; string username, r;
catch { catch {
first = [string(8bit)]line[3..]; first = line[3..];
[username, r] = array_sscanf(line, format); [username, r] = array_sscanf(line, format);
nonce = [string(8bit)]r; if (!(nonce = validate_nonce(r)))
return 0;
username = Standards.IDNA.to_unicode(username); username = Standards.IDNA.to_unicode(username);
}; };
return username; return username;
...@@ -657,10 +671,10 @@ class SCRAM ...@@ -657,10 +671,10 @@ class SCRAM
//! @seealso //! @seealso
//! @[server_3] //! @[server_3]
string(7bit) server_2(string(8bit) salt, int iters) { string(7bit) server_2(string(8bit) salt, int iters) {
string response = sprintf("r=%s,s=%s,i=%d", string(7bit) response = sprintf("r=%s,s=%s,i=%d",
nonce += randomstring(), encode64(salt), iters); nonce += randomstring(), encode64(salt), iters);
first += "," + response + ","; first += "," + response + ",";
return [string(7bit)]response; return response;
} }
//! Client-side step 2 in the SCRAM handshake. //! Client-side step 2 in the SCRAM handshake.
...@@ -677,30 +691,36 @@ class SCRAM ...@@ -677,30 +691,36 @@ class SCRAM
//! //!
//! @seealso //! @seealso
//! @[client_3] //! @[client_3]
string(7bit) client_2(string(8bit) line, string(8bit) pass) { string(7bit) client_2(string(8bit) line, string pass) {
constant format = "r=%s,s=%s,i=%d"; constant format = "r=%s,s=%s,i=%d";
string(8bit) r, salt; string(8bit) r, salt;
string(7bit) punypass;
string(7bit) validated_r;
string(7bit) response;
int iters; int iters;
if (!catch([r, salt, iters] = [array(string(8bit)|int)] if (!catch([r, salt, iters] = [array(string(8bit)|int)]
array_sscanf(line, format)) array_sscanf(line, format))
&& iters > 0 && iters > 0
&& (validated_r = validate_nonce(r))
&& has_prefix(r, nonce)) { && has_prefix(r, nonce)) {
line = [string(8bit)]sprintf("c=biws,r=%s", r); string(7bit) newline = sprintf("c=biws,r=%s", validated_r);
first = [string(8bit)]sprintf("%s,r=%s,s=%s,i=%d,%s", first = sprintf("%s,r=%s,s=%s,i=%d,%s",
first[3..], r, salt, iters, line); first[3..], validated_r, salt, iters, newline);
if (pass != "") if (pass != "")
pass = [string(7bit)]Standards.IDNA.to_ascii(pass); punypass = [string(7bit)]Standards.IDNA.to_ascii(pass);
else
punypass = "";
salt = MIME.decode_base64(salt); salt = MIME.decode_base64(salt);
string key = sprintf("%s,%s,%d", pass, salt, iters); string key = sprintf("%s,%s,%d", punypass, salt, iters);
if (!(r = SCRAM_get_salted_password(key))) { if (!(r = SCRAM_get_salted_password(key))) {
r = pbkdf2(pass, salt, iters, digest_size()); r = pbkdf2(punypass, salt, iters, digest_size());
SCRAM_set_salted_password(r, key); SCRAM_set_salted_password(r, key);
} }
salt = sprintf("%s,p=%s", line, clientproof(r)); response = sprintf("%s,p=%s", newline, clientproof(r));
first = 0; // Free memory first = 0; // Free memory
} else } else
salt = 0; response = 0;
return [string(7bit)]salt; return response;
} }
//! Final server-side step in the SCRAM handshake. //! Final server-side step in the SCRAM handshake.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment