41 end |
41 end |
42 |
42 |
43 local function scram(stream, name) |
43 local function scram(stream, name) |
44 local username = "n=" .. value_safe(stream.username); |
44 local username = "n=" .. value_safe(stream.username); |
45 local c_nonce = base64(crypto.rand.bytes(15)); |
45 local c_nonce = base64(crypto.rand.bytes(15)); |
46 local nonce = "r=" .. c_nonce; |
46 local our_nonce = "r=" .. c_nonce; |
47 local client_first_message_bare = username .. "," .. nonce; |
47 local client_first_message_bare = username .. "," .. our_nonce; |
48 local cbind_data = ""; |
48 local cbind_data = ""; |
49 local gs2_cbind_flag = "y"; |
49 local gs2_cbind_flag = "y"; |
50 if name == "SCRAM-SHA-1-PLUS" then |
50 if name == "SCRAM-SHA-1-PLUS" then |
51 cbind_data = stream.conn:socket():getfinished(); |
51 cbind_data = stream.conn:socket():getfinished(); |
52 gs2_cbind_flag = "p=tls-unique"; |
52 gs2_cbind_flag = "p=tls-unique"; |
54 local gs2_header = gs2_cbind_flag .. ",,"; |
54 local gs2_header = gs2_cbind_flag .. ",,"; |
55 local client_first_message = gs2_header .. client_first_message_bare; |
55 local client_first_message = gs2_header .. client_first_message_bare; |
56 local cont, server_first_message = coroutine.yield(client_first_message); |
56 local cont, server_first_message = coroutine.yield(client_first_message); |
57 if cont ~= "challenge" then return false end |
57 if cont ~= "challenge" then return false end |
58 |
58 |
59 local salt, iteration_count; |
59 local nonce, salt, iteration_count = server_first_message:match("(r=[^,]+),s=([^,]*),i=(%d+)"); |
60 nonce, salt, iteration_count = server_first_message:match("(r=[^,]+),s=([^,]*),i=(%d+)"); |
|
61 local i = tonumber(iteration_count); |
60 local i = tonumber(iteration_count); |
62 salt = unbase64(salt); |
61 salt = unbase64(salt); |
63 if not nonce or not salt or not i then |
62 if not nonce or not salt or not i then |
64 return false, "Could not parse server_first_message"; |
63 return false, "Could not parse server_first_message"; |
65 elseif nonce:find(c_nonce, 3, true) ~= 3 then |
64 elseif nonce:find(c_nonce, 3, true) ~= 3 then |
66 return false, "nonce sent by server does not match our nonce"; |
65 return false, "nonce sent by server does not match our nonce"; |
67 elseif nonce == c_nonce then |
66 elseif nonce == our_nonce then |
68 return false, "server did not append s-nonce to nonce"; |
67 return false, "server did not append s-nonce to nonce"; |
69 end |
68 end |
70 |
69 |
71 local cbind_input = gs2_header .. cbind_data; |
70 local cbind_input = gs2_header .. cbind_data; |
72 local channel_binding = "c=" .. base64(cbind_input); |
71 local channel_binding = "c=" .. base64(cbind_input); |