Skip to content

Commit

Permalink
🔒 Strict base64 decoding of SASL challenges
Browse files Browse the repository at this point in the history
`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.
  • Loading branch information
nevans committed Sep 26, 2023
1 parent 146ad37 commit 82fe814
Showing 1 changed file with 13 additions and 4 deletions.
17 changes: 13 additions & 4 deletions lib/net/imap.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1253,13 +1253,12 @@ def authenticate(mechanism, *creds, sasl_ir: true, **props, &callback)
if sasl_ir && capable?("SASL-IR") && auth_capable?(mechanism) &&
SASL.initial_response?(authenticator)
response = authenticator.process(nil)
cmdargs << (response.empty? ? "=" : [response].pack("m0"))
cmdargs << sasl_encode_ir(response)
end
result = send_command(*cmdargs) do |resp|
if resp.instance_of?(ContinuationRequest)
challenge = resp.data.text.unpack1("m")
response = authenticator.process(challenge)
response = [response].pack("m0")
challenge = sasl_decode resp.data.text
response = sasl_encode authenticator.process challenge
put_string(response + CRLF)
end
end
Expand All @@ -1271,6 +1270,16 @@ def authenticate(mechanism, *creds, sasl_ir: true, **props, &callback)
result
end

private

# RFC-2060 simply used base64 encoding. RFC-3051 and RFC9051 require empty
# strings be replaced with "=".
def sasl_encode_ir(str) str.empty? ? "=" : sasl_encode(str) end
def sasl_decode(str) str.unpack1("m0") end
def sasl_encode(str) [str].pack("m0") end

public

# Sends a {LOGIN command [IMAP4rev1 §6.2.3]}[https://www.rfc-editor.org/rfc/rfc3501#section-6.2.3]
# to identify the client and carries the plaintext +password+ authenticating
# this +user+. If successful, the connection enters the "_authenticated_"
Expand Down

0 comments on commit 82fe814

Please sign in to comment.