Annotate

util/sasl/scram.lua @ 454:9f27a2075e9e

util.sasl.scram: Disable 'tls-unique' channel binding on TLS 1.3 See background in https://issues.prosody.im/1542
author Kim Alvefur <zash@zash.se>
date Wed, 03 Aug 2022 03:06:26 +0200
parent 453:e60c776b7760
child 455:753d6983dc45
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
453
e60c776b7760 util.sasl.scram: Refactor channel binding
Kim Alvefur <zash@zash.se>
parents: 407
diff changeset
38 local function cb(conn)
e60c776b7760 util.sasl.scram: Refactor channel binding
Kim Alvefur <zash@zash.se>
parents: 407
diff changeset
39 if conn:ssl() then
454
9f27a2075e9e util.sasl.scram: Disable 'tls-unique' channel binding on TLS 1.3
Kim Alvefur <zash@zash.se>
parents: 453
diff changeset
40 local sock = conn:socket();
9f27a2075e9e util.sasl.scram: Disable 'tls-unique' channel binding on TLS 1.3
Kim Alvefur <zash@zash.se>
parents: 453
diff changeset
41 if sock.info and sock:info().protocol == "TLSv1.3" then
9f27a2075e9e util.sasl.scram: Disable 'tls-unique' channel binding on TLS 1.3
Kim Alvefur <zash@zash.se>
parents: 453
diff changeset
42 return false
9f27a2075e9e util.sasl.scram: Disable 'tls-unique' channel binding on TLS 1.3
Kim Alvefur <zash@zash.se>
parents: 453
diff changeset
43 elseif sock.getfinished then
453
e60c776b7760 util.sasl.scram: Refactor channel binding
Kim Alvefur <zash@zash.se>
parents: 407
diff changeset
44 return "p=tls-unique", sock:getfinished();
e60c776b7760 util.sasl.scram: Refactor channel binding
Kim Alvefur <zash@zash.se>
parents: 407
diff changeset
45 end
e60c776b7760 util.sasl.scram: Refactor channel binding
Kim Alvefur <zash@zash.se>
parents: 407
diff changeset
46 end
e60c776b7760 util.sasl.scram: Refactor channel binding
Kim Alvefur <zash@zash.se>
parents: 407
diff changeset
47 end
e60c776b7760 util.sasl.scram: Refactor channel binding
Kim Alvefur <zash@zash.se>
parents: 407
diff changeset
48
355
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
49 local function scram(stream, name)
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
50 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
51 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
52 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
53 local client_first_message_bare = username .. "," .. our_nonce;
355
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
54 local cbind_data = "";
453
e60c776b7760 util.sasl.scram: Refactor channel binding
Kim Alvefur <zash@zash.se>
parents: 407
diff changeset
55 local gs2_cbind_flag = "n";
356
f95e797895ee SCRAM: Add channel binding support (SCRAM-SHA-1-PLUS)
Kim Alvefur <zash@zash.se>
parents: 355
diff changeset
56 if name == "SCRAM-SHA-1-PLUS" then
453
e60c776b7760 util.sasl.scram: Refactor channel binding
Kim Alvefur <zash@zash.se>
parents: 407
diff changeset
57 gs2_cbind_flag, cbind_data = cb(stream.conn);
e60c776b7760 util.sasl.scram: Refactor channel binding
Kim Alvefur <zash@zash.se>
parents: 407
diff changeset
58 elseif cb(stream.conn) then
e60c776b7760 util.sasl.scram: Refactor channel binding
Kim Alvefur <zash@zash.se>
parents: 407
diff changeset
59 gs2_cbind_flag = "y";
356
f95e797895ee SCRAM: Add channel binding support (SCRAM-SHA-1-PLUS)
Kim Alvefur <zash@zash.se>
parents: 355
diff changeset
60 end
355
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
61 local gs2_header = gs2_cbind_flag .. ",,";
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
62 local client_first_message = gs2_header .. client_first_message_bare;
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
63 local cont, server_first_message = coroutine.yield(client_first_message);
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
64 if cont ~= "challenge" then return false end
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
65
362
d8c3e94d765d util.sasl.scram: Correctly verify that the server added its own nonce
Kim Alvefur <zash@zash.se>
parents: 359
diff changeset
66 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
67 local i = tonumber(iteration_count);
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
68 salt = unbase64(salt);
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
69 if not nonce or not salt or not i then
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
70 return false, "Could not parse server_first_message";
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
71 elseif nonce:find(c_nonce, 3, true) ~= 3 then
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
72 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
73 elseif nonce == our_nonce then
355
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
74 return false, "server did not append s-nonce to nonce";
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
75 end
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
76
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
77 local cbind_input = gs2_header .. cbind_data;
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
78 local channel_binding = "c=" .. base64(cbind_input);
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
79 local client_final_message_without_proof = channel_binding .. "," .. nonce;
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
80
407
c99db5172309 util.sasl.scram: Add support for authenticating with pre-hashed password
Kim Alvefur <zash@zash.se>
parents: 390
diff changeset
81 local SaltedPassword;
c99db5172309 util.sasl.scram: Add support for authenticating with pre-hashed password
Kim Alvefur <zash@zash.se>
parents: 390
diff changeset
82 local ClientKey;
c99db5172309 util.sasl.scram: Add support for authenticating with pre-hashed password
Kim Alvefur <zash@zash.se>
parents: 390
diff changeset
83 local ServerKey;
c99db5172309 util.sasl.scram: Add support for authenticating with pre-hashed password
Kim Alvefur <zash@zash.se>
parents: 390
diff changeset
84
c99db5172309 util.sasl.scram: Add support for authenticating with pre-hashed password
Kim Alvefur <zash@zash.se>
parents: 390
diff changeset
85 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
86 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
87 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
88 else
c99db5172309 util.sasl.scram: Add support for authenticating with pre-hashed password
Kim Alvefur <zash@zash.se>
parents: 390
diff changeset
89 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
90 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
91 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
92 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
93 end
c99db5172309 util.sasl.scram: Add support for authenticating with pre-hashed password
Kim Alvefur <zash@zash.se>
parents: 390
diff changeset
94 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
95 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
96 end
c99db5172309 util.sasl.scram: Add support for authenticating with pre-hashed password
Kim Alvefur <zash@zash.se>
parents: 390
diff changeset
97
355
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
98 local StoredKey = H(ClientKey);
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
99 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
100 local ClientSignature = HMAC(StoredKey, AuthMessage);
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
101 local ClientProof = XOR(ClientKey, ClientSignature);
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
102 local ServerSignature = HMAC(ServerKey, AuthMessage);
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
103
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
104 local proof = "p=" .. base64(ClientProof);
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
105 local client_final_message = client_final_message_without_proof .. "," .. proof;
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
106
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
107 local ok, server_final_message = coroutine.yield(client_final_message);
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
108 if ok ~= "success" then return false, "success-expected" end
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
109
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
110 local verifier = server_final_message:match("v=([^,]+)");
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
111 if unbase64(verifier) ~= ServerSignature then
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
112 return false, "server signature did not match";
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
113 end
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
114 return true;
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
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 return function (stream, name)
355
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
118 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
119 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
120 return scram, 99;
359
a7aa761a436d util.sasl.scram: Fix typo
Kim Alvefur <zash@zash.se>
parents: 358
diff changeset
121 elseif name == "SCRAM-SHA-1-PLUS" then
453
e60c776b7760 util.sasl.scram: Refactor channel binding
Kim Alvefur <zash@zash.se>
parents: 407
diff changeset
122 if cb(stream.conn) 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
123 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
124 end
356
f95e797895ee SCRAM: Add channel binding support (SCRAM-SHA-1-PLUS)
Kim Alvefur <zash@zash.se>
parents: 355
diff changeset
125 end
355
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
126 end
dfe095fcf89c Add SCRAM-SHA-1 implementation
Kim Alvefur <zash@zash.se>
parents:
diff changeset
127 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
128