Skip to content

Commit 82fe814

Browse files
committed
🔒 Strict base64 decoding of SASL challenges
`unpack("m")` will silently ignore a range of bad data. By adding error handling to authenticate, we can convert those errors into cancellation of the authentication exchange rather than crashing the connection or silently ignoring them.
1 parent 146ad37 commit 82fe814

File tree

1 file changed

+13
-4
lines changed

1 file changed

+13
-4
lines changed

lib/net/imap.rb

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1253,13 +1253,12 @@ def authenticate(mechanism, *creds, sasl_ir: true, **props, &callback)
12531253
if sasl_ir && capable?("SASL-IR") && auth_capable?(mechanism) &&
12541254
SASL.initial_response?(authenticator)
12551255
response = authenticator.process(nil)
1256-
cmdargs << (response.empty? ? "=" : [response].pack("m0"))
1256+
cmdargs << sasl_encode_ir(response)
12571257
end
12581258
result = send_command(*cmdargs) do |resp|
12591259
if resp.instance_of?(ContinuationRequest)
1260-
challenge = resp.data.text.unpack1("m")
1261-
response = authenticator.process(challenge)
1262-
response = [response].pack("m0")
1260+
challenge = sasl_decode resp.data.text
1261+
response = sasl_encode authenticator.process challenge
12631262
put_string(response + CRLF)
12641263
end
12651264
end
@@ -1271,6 +1270,16 @@ def authenticate(mechanism, *creds, sasl_ir: true, **props, &callback)
12711270
result
12721271
end
12731272

1273+
private
1274+
1275+
# RFC-2060 simply used base64 encoding. RFC-3051 and RFC9051 require empty
1276+
# strings be replaced with "=".
1277+
def sasl_encode_ir(str) str.empty? ? "=" : sasl_encode(str) end
1278+
def sasl_decode(str) str.unpack1("m0") end
1279+
def sasl_encode(str) [str].pack("m0") end
1280+
1281+
public
1282+
12741283
# Sends a {LOGIN command [IMAP4rev1 §6.2.3]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.2.3]
12751284
# to identify the client and carries the plaintext +password+ authenticating
12761285
# this +user+. If successful, the connection enters the "_authenticated_"

0 commit comments

Comments
 (0)