Skip to content

Commit b529d90

Browse files
committed
Fix excessive null-termination for auth data in handshake
1 parent 5edbaa0 commit b529d90

File tree

3 files changed

+48
-24
lines changed

3 files changed

+48
-24
lines changed

auth_test.go

+19-11
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"crypto/rsa"
1414
"crypto/tls"
1515
"crypto/x509"
16+
"encoding/hex"
1617
"encoding/pem"
1718
"fmt"
1819
"testing"
@@ -363,13 +364,16 @@ func TestAuthFastCleartextPassword(t *testing.T) {
363364
}
364365

365366
// check written auth response
366-
authRespStart := 4 + 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1
367+
authRespStart := 4 + 4 + 4 + 1 + 23 + len(mc.cfg.User)
367368
authRespEnd := authRespStart + 1 + len(authResp)
368-
writtenAuthRespLen := conn.written[authRespStart]
369369
writtenAuthResp := conn.written[authRespStart+1 : authRespEnd]
370-
expectedAuthResp := []byte{115, 101, 99, 114, 101, 116}
371-
if writtenAuthRespLen != 6 || !bytes.Equal(writtenAuthResp, expectedAuthResp) {
372-
t.Fatalf("unexpected written auth response (%d bytes): %v", writtenAuthRespLen, writtenAuthResp)
370+
expectedAuthResp := []byte("secret")
371+
if !bytes.Equal(writtenAuthResp, expectedAuthResp) {
372+
t.Fatalf("unexpected written auth response:\n%s\nExpected:\n%s\n",
373+
hex.Dump(writtenAuthResp), hex.Dump(expectedAuthResp))
374+
}
375+
if conn.written[authRespEnd] != 0 {
376+
t.Fatalf("Expected null-terminated")
373377
}
374378
conn.written = nil
375379

@@ -683,14 +687,18 @@ func TestAuthFastSHA256PasswordSecure(t *testing.T) {
683687
}
684688

685689
// check written auth response
686-
authRespStart := 4 + 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1
687-
authRespEnd := authRespStart + 1 + len(authResp) + 1
688-
writtenAuthRespLen := conn.written[authRespStart]
690+
authRespStart := 4 + 4 + 4 + 1 + 23 + len(mc.cfg.User)
691+
authRespEnd := authRespStart + 1 + len(authResp)
689692
writtenAuthResp := conn.written[authRespStart+1 : authRespEnd]
690-
expectedAuthResp := []byte{115, 101, 99, 114, 101, 116, 0}
691-
if writtenAuthRespLen != 6 || !bytes.Equal(writtenAuthResp, expectedAuthResp) {
692-
t.Fatalf("unexpected written auth response (%d bytes): %v", writtenAuthRespLen, writtenAuthResp)
693+
expectedAuthResp := []byte("secret")
694+
if !bytes.Equal(writtenAuthResp, expectedAuthResp) {
695+
t.Fatalf("unexpected written auth response:\n%s\nExpected:\n%s\n",
696+
hex.Dump(writtenAuthResp), hex.Dump(expectedAuthResp))
693697
}
698+
if conn.written[authRespEnd] != 0 {
699+
t.Fatalf("Expected null-terminated")
700+
}
701+
694702
conn.written = nil
695703

696704
// auth response (OK)

const.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ const (
4646
clientIgnoreSIGPIPE
4747
clientTransactions
4848
clientReserved
49-
clientSecureConn
49+
clientSecureConn // reserved2 in 8.0
5050
clientMultiStatements
5151
clientMultiResults
5252
clientPSMultiResults
@@ -56,6 +56,8 @@ const (
5656
clientCanHandleExpiredPasswords
5757
clientSessionTrack
5858
clientDeprecateEOF
59+
clientSslVerifyServerCert clientFlag = 1 << 30
60+
clientRememberOptions clientFlag = 1 << 31
5961
)
6062

6163
const (

packets.go

+26-12
Original file line numberDiff line numberDiff line change
@@ -251,10 +251,9 @@ func (mc *mysqlConn) readHandshakePacket() ([]byte, string, error) {
251251

252252
// Client Authentication Packet
253253
// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse
254-
func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, addNUL bool, plugin string) error {
254+
func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, insecureAuth bool, plugin string) error {
255255
// Adjust client flags based on server support
256256
clientFlags := clientProtocol41 |
257-
clientSecureConn |
258257
clientLongPassword |
259258
clientTransactions |
260259
clientLocalFiles |
@@ -275,17 +274,21 @@ func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, addNUL bool,
275274
clientFlags |= clientMultiStatements
276275
}
277276

277+
if !insecureAuth {
278+
clientFlags |= clientSecureConn
279+
}
280+
278281
// encode length of the auth plugin data
279282
var authRespLEIBuf [9]byte
280283
authRespLEI := appendLengthEncodedInteger(authRespLEIBuf[:0], uint64(len(authResp)))
281-
if len(authRespLEI) > 1 {
284+
if len(authRespLEI) > 1 && clientFlags&clientSecureConn != 0 {
282285
// if the length can not be written in 1 byte, it must be written as a
283286
// length encoded integer
284287
clientFlags |= clientPluginAuthLenEncClientData
285288
}
286289

287290
pktLen := 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 + len(authRespLEI) + len(authResp) + 21 + 1
288-
if addNUL {
291+
if clientFlags&clientSecureConn == 0 || clientFlags&clientPluginAuthLenEncClientData == 0 {
289292
pktLen++
290293
}
291294

@@ -308,7 +311,7 @@ func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, addNUL bool,
308311
}
309312

310313
// To specify a db name
311-
if n := len(mc.cfg.DBName); n > 0 {
314+
if n := len(mc.cfg.DBName); mc.flags&clientConnectWithDB != 0 && n > 0 {
312315
clientFlags |= clientConnectWithDB
313316
pktLen += n + 1
314317
}
@@ -373,25 +376,36 @@ func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, addNUL bool,
373376
data[pos] = 0x00
374377
pos++
375378

376-
// Auth Data [length encoded integer]
377-
pos += copy(data[pos:], authRespLEI)
379+
// Auth Data [length encoded integer + data] if clientPluginAuthLenEncClientData
380+
// clientSecureConn => 1 byte len + data
381+
// else null-terminated
382+
if clientFlags&clientPluginAuthLenEncClientData != 0 {
383+
pos += copy(data[pos:], authRespLEI)
384+
} else if clientFlags&clientSecureConn != 0 {
385+
data[pos] = uint8(len(authResp))
386+
pos++
387+
}
378388
pos += copy(data[pos:], authResp)
379-
if addNUL {
389+
if clientFlags&clientSecureConn == 0 && clientFlags&clientPluginAuthLenEncClientData == 0 {
380390
data[pos] = 0x00
381391
pos++
382392
}
383393

384394
// Databasename [null terminated string]
385-
if len(mc.cfg.DBName) > 0 {
395+
if clientFlags&clientConnectWithDB != 0 {
386396
pos += copy(data[pos:], mc.cfg.DBName)
387397
data[pos] = 0x00
388398
pos++
389399
}
390400

391-
pos += copy(data[pos:], plugin)
392-
data[pos] = 0x00
393-
pos++
401+
// auth plugin name [null terminated string]
402+
if clientFlags&clientPluginAuth != 0 {
403+
pos += copy(data[pos:], plugin)
404+
data[pos] = 0x00
405+
pos++
406+
}
394407

408+
// connection attributes [lenenc-int total + lenenc-str key-value pairs]
395409
if clientFlags&clientConnectAttrs != 0 {
396410
pos += copy(data[pos:], connectAttrsBuf)
397411
}

0 commit comments

Comments
 (0)