Skip to content

feat: PostgreSQL startup + authentication (MD5, SCRAM-SHA-256) #124

@FumingPower3925

Description

@FumingPower3925

Summary

Implement the PostgreSQL connection startup sequence including the full authentication handshake for MD5 and SCRAM-SHA-256 (the two most common auth methods).

Design

Package: driver/postgres/protocol/startup.go

Startup Sequence

Client → Server:  StartupMessage (protocol 3.0, user, database, params)
Server → Client:  Authentication request (one of several types)
  ... auth exchange ...
Server → Client:  ParameterStatus* (server_version, client_encoding, etc.)
Server → Client:  BackendKeyData (PID + secret key for cancel)
Server → Client:  ReadyForQuery ('I' = idle)

Authentication Methods

MD5 (R=5):

Server: AuthenticationMD5Password { salt [4]byte }
Client: PasswordMessage { "md5" + md5(md5(password + user) + salt) }
Server: AuthenticationOk

SCRAM-SHA-256 (R=10):
Multi-round-trip:

Server: AuthenticationSASL { mechanisms: ["SCRAM-SHA-256"] }
Client: SASLInitialResponse { mechanism, client-first-message }
Server: AuthenticationSASLContinue { server-first-message }
Client: SASLResponse { client-final-message }
Server: AuthenticationSASLFinal { server-final-message }
Server: AuthenticationOk

SCRAM implementation:

  • Client nonce generation (crypto/rand)
  • SaltedPassword = Hi(password, salt, iterations) using PBKDF2
  • ClientKey, StoredKey, ClientSignature, ClientProof
  • ServerKey, ServerSignature (verified against server-final-message)

Trust/Password (R=0, R=3):

  • Trust: no password needed
  • Cleartext: send password directly (rare, for completeness)

State Machine

type StartupState struct {
    phase    startupPhase  // INIT, WAIT_AUTH, SASL_CONTINUE, SASL_FINAL, READY
    user     string
    password string
    database string
    pid      int32
    secret   int32
    params   map[string]string  // server parameters
    sasl     *scramState        // SCRAM state across round-trips
}

func (s *StartupState) Start(w *Writer) []byte           // StartupMessage
func (s *StartupState) Handle(msgType byte, payload []byte, w *Writer) (done bool, response []byte, err error)

The state machine is designed for the event loop model — each Handle call processes one message and optionally returns a response to send.

Acceptance Criteria

  • StartupMessage serialization with protocol 3.0
  • MD5 authentication works
  • SCRAM-SHA-256 full handshake works (including server signature verification)
  • Trust and cleartext password auth work
  • ParameterStatus values captured
  • BackendKeyData (PID + secret) stored for cancel support
  • State machine handles message-at-a-time event loop model
  • Unit tests with captured PG auth exchanges
  • SCRAM test vectors from RFC 5802

Dependencies

  • Depends on 123 (wire protocol message framing)

Metadata

Metadata

Labels

area/driverDatabase/cache driver infrastructuredriver/postgresPostgreSQL driver

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions