11func base64Decode(s string) []byte {
12 buf, err := base64.StdEncoding.DecodeString(s)
19func tcheck(t *testing.T, err error, msg string) {
22 t.Fatalf("%s: %s", msg, err)
26func TestSCRAMSHA1Server(t *testing.T) {
28 salt := base64Decode("QSXCR+Q6sek8bf92")
29 saltedPassword := SaltPassword(sha1.New, "pencil", salt, 4096)
31 server, err := NewServer(sha1.New, []byte("n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL"))
32 server.serverNonceOverride = "3rfcNHYJY1ZVvWVs7j"
33 tcheck(t, err, "newserver")
34 resp, err := server.ServerFirst(4096, salt)
35 tcheck(t, err, "server first")
36 if resp != "r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096" {
37 t.Fatalf("bad server first")
39 serverFinal, err := server.Finish([]byte("c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts="), saltedPassword)
40 tcheck(t, err, "finish")
41 if serverFinal != "v=rmF9pqV8S7suAoZWja4dJRkFsKQ=" {
42 t.Fatalf("bad server final")
46func TestSCRAMSHA256Server(t *testing.T) {
48 salt := base64Decode("W22ZaJ0SNY7soEsUEjb6gQ==")
49 saltedPassword := SaltPassword(sha256.New, "pencil", salt, 4096)
51 server, err := NewServer(sha256.New, []byte("n,,n=user,r=rOprNGfwEbeRWgbNEkqO"))
52 server.serverNonceOverride = "%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0"
53 tcheck(t, err, "newserver")
54 resp, err := server.ServerFirst(4096, salt)
55 tcheck(t, err, "server first")
56 if resp != "r=rOprNGfwEbeRWgbNEkqO%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0,s=W22ZaJ0SNY7soEsUEjb6gQ==,i=4096" {
57 t.Fatalf("bad server first")
59 serverFinal, err := server.Finish([]byte("c=biws,r=rOprNGfwEbeRWgbNEkqO%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0,p=dHzbZapWIk4jUhN+Ute9ytag9zjfMHgsqmmiz7AndVQ="), saltedPassword)
60 tcheck(t, err, "finish")
61 if serverFinal != "v=6rriTRBi23WpRR/wtup+mMhUZUn/dB5nLTJRsjl95G4=" {
62 t.Fatalf("bad server final")
66// Bad attempt with wrong password.
67func TestScramServerBadPassword(t *testing.T) {
68 salt := base64Decode("W22ZaJ0SNY7soEsUEjb6gQ==")
69 saltedPassword := SaltPassword(sha256.New, "marker", salt, 4096)
71 server, err := NewServer(sha256.New, []byte("n,,n=user,r=rOprNGfwEbeRWgbNEkqO"))
72 server.serverNonceOverride = "%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0"
73 tcheck(t, err, "newserver")
74 _, err = server.ServerFirst(4096, salt)
75 tcheck(t, err, "server first")
76 _, err = server.Finish([]byte("c=biws,r=rOprNGfwEbeRWgbNEkqO%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0,p=dHzbZapWIk4jUhN+Ute9ytag9zjfMHgsqmmiz7AndVQ="), saltedPassword)
77 if !errors.Is(err, ErrInvalidProof) {
78 t.Fatalf("got %v, expected ErrInvalidProof", err)
82// Bad attempt with different number of rounds.
83func TestScramServerBadIterations(t *testing.T) {
84 salt := base64Decode("W22ZaJ0SNY7soEsUEjb6gQ==")
85 saltedPassword := SaltPassword(sha256.New, "pencil", salt, 2048)
87 server, err := NewServer(sha256.New, []byte("n,,n=user,r=rOprNGfwEbeRWgbNEkqO"))
88 server.serverNonceOverride = "%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0"
89 tcheck(t, err, "newserver")
90 _, err = server.ServerFirst(4096, salt)
91 tcheck(t, err, "server first")
92 _, err = server.Finish([]byte("c=biws,r=rOprNGfwEbeRWgbNEkqO%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0,p=dHzbZapWIk4jUhN+Ute9ytag9zjfMHgsqmmiz7AndVQ="), saltedPassword)
93 if !errors.Is(err, ErrInvalidProof) {
94 t.Fatalf("got %v, expected ErrInvalidProof", err)
98// Another attempt but with a randomly different nonce.
99func TestScramServerBad(t *testing.T) {
100 salt := base64Decode("W22ZaJ0SNY7soEsUEjb6gQ==")
101 saltedPassword := SaltPassword(sha256.New, "pencil", salt, 4096)
103 server, err := NewServer(sha256.New, []byte("n,,n=user,r=rOprNGfwEbeRWgbNEkqO"))
104 tcheck(t, err, "newserver")
105 _, err = server.ServerFirst(4096, salt)
106 tcheck(t, err, "server first")
107 _, err = server.Finish([]byte("c=biws,r="+server.nonce+",p=dHzbZapWIk4jUhN+Ute9ytag9zjfMHgsqmmiz7AndVQ="), saltedPassword)
108 if !errors.Is(err, ErrInvalidProof) {
109 t.Fatalf("got %v, expected ErrInvalidProof", err)
113func TestScramClient(t *testing.T) {
114 c := NewClient(sha256.New, "user", "")
115 c.clientNonce = "rOprNGfwEbeRWgbNEkqO"
116 clientFirst, err := c.ClientFirst()
117 tcheck(t, err, "ClientFirst")
118 if clientFirst != "n,,n=user,r=rOprNGfwEbeRWgbNEkqO" {
119 t.Fatalf("bad clientFirst")
121 clientFinal, err := c.ServerFirst([]byte("r=rOprNGfwEbeRWgbNEkqO%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0,s=W22ZaJ0SNY7soEsUEjb6gQ==,i=4096"), "pencil")
122 tcheck(t, err, "ServerFirst")
123 if clientFinal != "c=biws,r=rOprNGfwEbeRWgbNEkqO%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0,p=dHzbZapWIk4jUhN+Ute9ytag9zjfMHgsqmmiz7AndVQ=" {
124 t.Fatalf("bad clientFinal")
126 err = c.ServerFinal([]byte("v=6rriTRBi23WpRR/wtup+mMhUZUn/dB5nLTJRsjl95G4="))
127 tcheck(t, err, "ServerFinal")
130func TestScram(t *testing.T) {
131 run := func(expErr error, username, authzid, password string, iterations int, clientNonce, serverNonce string) {
136 if x == nil || x == "" {
142 // check err is either nil or the expected error. if the expected error, panic to abort the authentication session.
143 xerr := func(err error, msg string) {
145 if err != nil && !errors.Is(err, expErr) {
146 t.Fatalf("%s: got %v, expected %v", msg, err, expErr)
149 panic("") // Abort test.
154 saltedPassword := SaltPassword(sha256.New, password, salt, iterations)
156 client := NewClient(sha256.New, username, "")
157 client.clientNonce = clientNonce
158 clientFirst, err := client.ClientFirst()
159 xerr(err, "client.ClientFirst")
161 server, err := NewServer(sha256.New, []byte(clientFirst))
162 xerr(err, "NewServer")
163 server.serverNonceOverride = serverNonce
165 serverFirst, err := server.ServerFirst(iterations, salt)
166 xerr(err, "server.ServerFirst")
168 clientFinal, err := client.ServerFirst([]byte(serverFirst), password)
169 xerr(err, "client.ServerFirst")
171 serverFinal, err := server.Finish([]byte(clientFinal), saltedPassword)
172 xerr(err, "server.Finish")
174 err = client.ServerFinal([]byte(serverFinal))
175 xerr(err, "client.ServerFinal")
178 t.Fatalf("got no error, expected %v", expErr)
182 run(nil, "user", "", "pencil", 4096, "", "")
183 run(nil, "mjl@mox.example", "", "testtest", 4096, "", "")
184 run(nil, "mjl@mox.example", "", "short", 4096, "", "")
185 run(nil, "mjl@mox.example", "", "short", 2048, "", "")
186 run(nil, "mjl@mox.example", "mjl@mox.example", "testtest", 4096, "", "")
187 run(nil, "mjl@mox.example", "other@mox.example", "testtest", 4096, "", "")
188 run(ErrUnsafe, "user", "", "pencil", 1, "", "") // Few iterations.
189 run(ErrUnsafe, "user", "", "pencil", 2048, "short", "") // Short client nonce.
190 run(ErrUnsafe, "user", "", "pencil", 2048, "test1234", "test") // Server added too few random data.