Annotate

util/sasl/scram.lua @ 445:b119dc4d8bc2

plugins.smacks: Don't warn about zero stanzas acked It's only if the count somehow goes backwards that something is really wrong. An ack for zero stanzas is fine and we don't need to do anything.
author Kim Alvefur <zash@zash.se>
date Thu, 10 Jun 2021 11:58:23 +0200
parent 407:c99db5172309
child 453:e60c776b7760
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
355
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
1
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
2 local base64, unbase64 = require "mime".b64, require"mime".unb64;
390
7f535a1d5827 util.sasl.scram: Use the new util.hashes and util.random
Kim Alvefur <zash@zash.se>
parents: 365
diff changeset
3 local hashes = require"util.hashes";
355
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
4 local bit = require"bit";
390
7f535a1d5827 util.sasl.scram: Use the new util.hashes and util.random
Kim Alvefur <zash@zash.se>
parents: 365
diff changeset
5 local random = require"util.random";
355
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
6
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
7 local tonumber = tonumber;
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
8 local char, byte = string.char, string.byte;
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
9 local gsub = string.gsub;
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
10 local xor = bit.bxor;
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
11
358
a8f6fd6a70ed plugins.sasl: Alter mechanism loading and pass name of loaded mechanism. Fixes attempting SCRAM-PLUS when only SCRAM is offered
Kim Alvefur <zash@zash.se>
parents: 356
diff changeset
12 local function XOR(a, b)
355
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
13 return (gsub(a, "()(.)", function(i, c)
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
14 return char(xor(byte(c), byte(b, i)))
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
15 end));
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
16 end
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
17
390
7f535a1d5827 util.sasl.scram: Use the new util.hashes and util.random
Kim Alvefur <zash@zash.se>
parents: 365
diff changeset
18 local H, HMAC = hashes.sha1, hashes.hmac_sha1;
355
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
19
358
a8f6fd6a70ed plugins.sasl: Alter mechanism loading and pass name of loaded mechanism. Fixes attempting SCRAM-PLUS when only SCRAM is offered
Kim Alvefur <zash@zash.se>
parents: 356
diff changeset
20 local function Hi(str, salt, i)
355
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
21 local U = HMAC(str, salt .. "\0\0\0\1");
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
22 local ret = U;
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
23 for _ = 2, i do
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
24 U = HMAC(str, U);
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
25 ret = XOR(ret, U);
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
26 end
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
27 return ret;
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
28 end
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
29
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
30 local function Normalize(str)
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
31 return str; -- TODO
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
32 end
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
33
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
34 local function value_safe(str)
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
35 return (gsub(str, "[,=]", { [","] = "=2C", ["="] = "=3D" }));
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
36 end
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
37
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
38 local function scram(stream, name)
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
39 local username = "n=" .. value_safe(stream.username);
390
7f535a1d5827 util.sasl.scram: Use the new util.hashes and util.random
Kim Alvefur <zash@zash.se>
parents: 365
diff changeset
40 local c_nonce = base64(random.bytes(15));
362
d8c3e94d765d util.sasl.scram: Correctly verify that the server added its own nonce
Kim Alvefur <zash@zash.se>
parents: 359
diff changeset
41 local our_nonce = "r=" .. c_nonce;
d8c3e94d765d util.sasl.scram: Correctly verify that the server added its own nonce
Kim Alvefur <zash@zash.se>
parents: 359
diff changeset
42 local client_first_message_bare = username .. "," .. our_nonce;
355
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
43 local cbind_data = "";
365
48bf6993b4c4 util.sasl.scram: Only indicate channel binding support when TLS is used
Kim Alvefur <zash@zash.se>
parents: 363
diff changeset
44 local gs2_cbind_flag = stream.conn:ssl() and "y" or "n";
356
f95e797895ee SCRAM: Add channel binding support (SCRAM-SHA-1-PLUS)
Kim Alvefur <zash@zash.se>
parents: 355
diff changeset
45 if name == "SCRAM-SHA-1-PLUS" then
f95e797895ee SCRAM: Add channel binding support (SCRAM-SHA-1-PLUS)
Kim Alvefur <zash@zash.se>
parents: 355
diff changeset
46 cbind_data = stream.conn:socket():getfinished();
f95e797895ee SCRAM: Add channel binding support (SCRAM-SHA-1-PLUS)
Kim Alvefur <zash@zash.se>
parents: 355
diff changeset
47 gs2_cbind_flag = "p=tls-unique";
f95e797895ee SCRAM: Add channel binding support (SCRAM-SHA-1-PLUS)
Kim Alvefur <zash@zash.se>
parents: 355
diff changeset
48 end
355
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
49 local gs2_header = gs2_cbind_flag .. ",,";
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
50 local client_first_message = gs2_header .. client_first_message_bare;
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
51 local cont, server_first_message = coroutine.yield(client_first_message);
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
52 if cont ~= "challenge" then return false end
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
53
362
d8c3e94d765d util.sasl.scram: Correctly verify that the server added its own nonce
Kim Alvefur <zash@zash.se>
parents: 359
diff changeset
54 local nonce, salt, iteration_count = server_first_message:match("(r=[^,]+),s=([^,]*),i=(%d+)");
355
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
55 local i = tonumber(iteration_count);
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
56 salt = unbase64(salt);
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
57 if not nonce or not salt or not i then
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
58 return false, "Could not parse server_first_message";
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
59 elseif nonce:find(c_nonce, 3, true) ~= 3 then
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
60 return false, "nonce sent by server does not match our nonce";
362
d8c3e94d765d util.sasl.scram: Correctly verify that the server added its own nonce
Kim Alvefur <zash@zash.se>
parents: 359
diff changeset
61 elseif nonce == our_nonce then
355
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
62 return false, "server did not append s-nonce to nonce";
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
63 end
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
64
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
65 local cbind_input = gs2_header .. cbind_data;
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
66 local channel_binding = "c=" .. base64(cbind_input);
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
67 local client_final_message_without_proof = channel_binding .. "," .. nonce;
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
68
407
c99db5172309 util.sasl.scram: Add support for authenticating with pre-hashed password
Kim Alvefur <zash@zash.se>
parents: 390
diff changeset
69 local SaltedPassword;
c99db5172309 util.sasl.scram: Add support for authenticating with pre-hashed password
Kim Alvefur <zash@zash.se>
parents: 390
diff changeset
70 local ClientKey;
c99db5172309 util.sasl.scram: Add support for authenticating with pre-hashed password
Kim Alvefur <zash@zash.se>
parents: 390
diff changeset
71 local ServerKey;
c99db5172309 util.sasl.scram: Add support for authenticating with pre-hashed password
Kim Alvefur <zash@zash.se>
parents: 390
diff changeset
72
c99db5172309 util.sasl.scram: Add support for authenticating with pre-hashed password
Kim Alvefur <zash@zash.se>
parents: 390
diff changeset
73 if stream.client_key and stream.server_key then
c99db5172309 util.sasl.scram: Add support for authenticating with pre-hashed password
Kim Alvefur <zash@zash.se>
parents: 390
diff changeset
74 ClientKey = stream.client_key;
c99db5172309 util.sasl.scram: Add support for authenticating with pre-hashed password
Kim Alvefur <zash@zash.se>
parents: 390
diff changeset
75 ServerKey = stream.server_key;
c99db5172309 util.sasl.scram: Add support for authenticating with pre-hashed password
Kim Alvefur <zash@zash.se>
parents: 390
diff changeset
76 else
c99db5172309 util.sasl.scram: Add support for authenticating with pre-hashed password
Kim Alvefur <zash@zash.se>
parents: 390
diff changeset
77 if stream.salted_password then
c99db5172309 util.sasl.scram: Add support for authenticating with pre-hashed password
Kim Alvefur <zash@zash.se>
parents: 390
diff changeset
78 SaltedPassword = stream.salted_password;
c99db5172309 util.sasl.scram: Add support for authenticating with pre-hashed password
Kim Alvefur <zash@zash.se>
parents: 390
diff changeset
79 elseif stream.password then
c99db5172309 util.sasl.scram: Add support for authenticating with pre-hashed password
Kim Alvefur <zash@zash.se>
parents: 390
diff changeset
80 SaltedPassword = Hi(Normalize(stream.password), salt, i);
c99db5172309 util.sasl.scram: Add support for authenticating with pre-hashed password
Kim Alvefur <zash@zash.se>
parents: 390
diff changeset
81 end
c99db5172309 util.sasl.scram: Add support for authenticating with pre-hashed password
Kim Alvefur <zash@zash.se>
parents: 390
diff changeset
82 ServerKey = HMAC(SaltedPassword, "Server Key");
c99db5172309 util.sasl.scram: Add support for authenticating with pre-hashed password
Kim Alvefur <zash@zash.se>
parents: 390
diff changeset
83 ClientKey = HMAC(SaltedPassword, "Client Key");
c99db5172309 util.sasl.scram: Add support for authenticating with pre-hashed password
Kim Alvefur <zash@zash.se>
parents: 390
diff changeset
84 end
c99db5172309 util.sasl.scram: Add support for authenticating with pre-hashed password
Kim Alvefur <zash@zash.se>
parents: 390
diff changeset
85
355
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
86 local StoredKey = H(ClientKey);
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
87 local AuthMessage = client_first_message_bare .. "," .. server_first_message .. "," .. client_final_message_without_proof;
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
88 local ClientSignature = HMAC(StoredKey, AuthMessage);
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
89 local ClientProof = XOR(ClientKey, ClientSignature);
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
90 local ServerSignature = HMAC(ServerKey, AuthMessage);
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
91
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
92 local proof = "p=" .. base64(ClientProof);
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
93 local client_final_message = client_final_message_without_proof .. "," .. proof;
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
94
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
95 local ok, server_final_message = coroutine.yield(client_final_message);
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
96 if ok ~= "success" then return false, "success-expected" end
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
97
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
98 local verifier = server_final_message:match("v=([^,]+)");
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
99 if unbase64(verifier) ~= ServerSignature then
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
100 return false, "server signature did not match";
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
101 end
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
102 return true;
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
103 end
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
104
358
a8f6fd6a70ed plugins.sasl: Alter mechanism loading and pass name of loaded mechanism. Fixes attempting SCRAM-PLUS when only SCRAM is offered
Kim Alvefur <zash@zash.se>
parents: 356
diff changeset
105 return function (stream, name)
355
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
106 if stream.username and (stream.password or (stream.client_key or stream.server_key)) then
358
a8f6fd6a70ed plugins.sasl: Alter mechanism loading and pass name of loaded mechanism. Fixes attempting SCRAM-PLUS when only SCRAM is offered
Kim Alvefur <zash@zash.se>
parents: 356
diff changeset
107 if name == "SCRAM-SHA-1" then
a8f6fd6a70ed plugins.sasl: Alter mechanism loading and pass name of loaded mechanism. Fixes attempting SCRAM-PLUS when only SCRAM is offered
Kim Alvefur <zash@zash.se>
parents: 356
diff changeset
108 return scram, 99;
359
a7aa761a436d util.sasl.scram: Fix typo
Kim Alvefur <zash@zash.se>
parents: 358
diff changeset
109 elseif name == "SCRAM-SHA-1-PLUS" then
358
a8f6fd6a70ed plugins.sasl: Alter mechanism loading and pass name of loaded mechanism. Fixes attempting SCRAM-PLUS when only SCRAM is offered
Kim Alvefur <zash@zash.se>
parents: 356
diff changeset
110 local sock = stream.conn:ssl() and stream.conn:socket();
a8f6fd6a70ed plugins.sasl: Alter mechanism loading and pass name of loaded mechanism. Fixes attempting SCRAM-PLUS when only SCRAM is offered
Kim Alvefur <zash@zash.se>
parents: 356
diff changeset
111 if sock and sock.getfinished then
a8f6fd6a70ed plugins.sasl: Alter mechanism loading and pass name of loaded mechanism. Fixes attempting SCRAM-PLUS when only SCRAM is offered
Kim Alvefur <zash@zash.se>
parents: 356
diff changeset
112 return scram, 100;
a8f6fd6a70ed plugins.sasl: Alter mechanism loading and pass name of loaded mechanism. Fixes attempting SCRAM-PLUS when only SCRAM is offered
Kim Alvefur <zash@zash.se>
parents: 356
diff changeset
113 end
356
f95e797895ee SCRAM: Add channel binding support (SCRAM-SHA-1-PLUS)
Kim Alvefur <zash@zash.se>
parents: 355
diff changeset
114 end
355
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
115 end
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
116 end
358
a8f6fd6a70ed plugins.sasl: Alter mechanism loading and pass name of loaded mechanism. Fixes attempting SCRAM-PLUS when only SCRAM is offered
Kim Alvefur <zash@zash.se>
parents: 356
diff changeset
117