client: defer large SASL initial response instead of inlining it (#301) - #307
client: defer large SASL initial response instead of inlining it (#301)#307youdie006 wants to merge 2 commits into
Conversation
Client.Auth always appended the base64 initial response to the AUTH command line. For mechanisms with a large initial response (e.g. GSSAPI, whose first token can be 1-2 KB), that line exceeds the 512-octet command-line limit of RFC 5321 section 4.5.3.1.4, and strict servers (e.g. Dovecot submission) reject it with "500 5.5.2 Line too long" before authentication can proceed. When inlining would overflow the limit, send "AUTH <mech>" and provide the initial response on the first server challenge instead, as allowed by RFC 4954 section 4. Add a regression test. Fixes emersion#301
emersion
left a comment
There was a problem hiding this comment.
Code structure is pretty hard to follow here. Can we send the too-large initial response outside of the loop?
|
You're right, thanks — restructured so the deferred response is sent before the loop, and the loop is byte-for-byte what it was before this PR. authCmd := strings.TrimSpace(fmt.Sprintf("AUTH %s %s", mech, resp64))
if len(authCmd)+2 > 512 && len(resp64) > 0 {
// The initial response does not fit in the 512-octet command line (RFC 5321
// section 4.5.3.1.4), so send it as the reply to the first challenge instead
// (RFC 4954 section 4).
code, msg64, err = c.cmd(0, "AUTH %s", mech)
if err == nil && code == 334 {
code, msg64, err = c.cmd(0, "%s", resp64)
}
} else {
code, msg64, err = c.cmd(0, "%s", authCmd)
}
for err == nil {
// unchangedThe Net change to |
|
My codebase differs a little bit, but I think this should work here too. In my understanding TrimSpace was added to remove the whitespace between %s and %s if resp64 is empty. So if we reuse the branch we can remove the TrimSpace and extra fmt.Sprintf like this (uponusolutions@21f3d24): |
Fixes #301.
Problem
Client.Authalways appends the base64 initial response to theAUTHcommand line:For SASL mechanisms whose initial response is large (e.g. GSSAPI, whose first token can be 1-2 KB with a PAC), that line exceeds the 512-octet command-line limit of RFC 5321 section 4.5.3.1.4. Strict servers (e.g. Dovecot submission) then reject it with
500 5.5.2 Line too longbefore authentication can proceed.Fix
When inlining the initial response would overflow the 512-octet limit, send
AUTH <mech>alone and provide the initial response as the reply to the first server challenge instead, as permitted by RFC 4954 section 4. Mechanisms whose initial response fits (the common case) are unchanged and still inline it.Test
Added
TestClientAuthLargeInitialResponse: a SASL client returning a 600-byte initial response, driven through the existingfakermock. Red-green verified withgo test -run TestClientAuth ./...: before the change the AUTH command line is 813 octets (initial response inlined, over the 512 limit); after, the command line isAUTH LARGEand the response is sent on its own line following the challenge.gofmtandgo vetare clean.Disclosure: I used AI assistance (Claude) while preparing this change. I verified the root cause against the RFCs, ran the tests (red-green), and take responsibility for the contribution.