cipher_test.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. // Copyright 2011 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package ssh
  5. import (
  6. "bytes"
  7. "crypto"
  8. "crypto/rand"
  9. "encoding/binary"
  10. "io"
  11. "testing"
  12. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/crypto/internal/poly1305"
  13. "golang.org/x/crypto/chacha20"
  14. )
  15. func TestDefaultCiphersExist(t *testing.T) {
  16. for _, cipherAlgo := range supportedCiphers {
  17. if _, ok := cipherModes[cipherAlgo]; !ok {
  18. t.Errorf("supported cipher %q is unknown", cipherAlgo)
  19. }
  20. }
  21. for _, cipherAlgo := range preferredCiphers {
  22. if _, ok := cipherModes[cipherAlgo]; !ok {
  23. t.Errorf("preferred cipher %q is unknown", cipherAlgo)
  24. }
  25. }
  26. }
  27. func TestPacketCiphers(t *testing.T) {
  28. defaultMac := "hmac-sha2-256"
  29. defaultCipher := "aes128-ctr"
  30. for cipher := range cipherModes {
  31. t.Run("cipher="+cipher,
  32. func(t *testing.T) { testPacketCipher(t, cipher, defaultMac) })
  33. }
  34. for mac := range macModes {
  35. t.Run("mac="+mac,
  36. func(t *testing.T) { testPacketCipher(t, defaultCipher, mac) })
  37. }
  38. }
  39. func testPacketCipher(t *testing.T, cipher, mac string) {
  40. kr := &kexResult{Hash: crypto.SHA1}
  41. algs := directionAlgorithms{
  42. Cipher: cipher,
  43. MAC: mac,
  44. Compression: "none",
  45. }
  46. client, err := newPacketCipher(clientKeys, algs, kr)
  47. if err != nil {
  48. t.Fatalf("newPacketCipher(client, %q, %q): %v", cipher, mac, err)
  49. }
  50. server, err := newPacketCipher(clientKeys, algs, kr)
  51. if err != nil {
  52. t.Fatalf("newPacketCipher(client, %q, %q): %v", cipher, mac, err)
  53. }
  54. want := "bla bla"
  55. input := []byte(want)
  56. buf := &bytes.Buffer{}
  57. if err := client.writeCipherPacket(0, buf, rand.Reader, input); err != nil {
  58. t.Fatalf("writeCipherPacket(%q, %q): %v", cipher, mac, err)
  59. }
  60. packet, err := server.readCipherPacket(0, buf)
  61. if err != nil {
  62. t.Fatalf("readCipherPacket(%q, %q): %v", cipher, mac, err)
  63. }
  64. if string(packet) != want {
  65. t.Errorf("roundtrip(%q, %q): got %q, want %q", cipher, mac, packet, want)
  66. }
  67. }
  68. func TestCBCOracleCounterMeasure(t *testing.T) {
  69. kr := &kexResult{Hash: crypto.SHA1}
  70. algs := directionAlgorithms{
  71. Cipher: aes128cbcID,
  72. MAC: "hmac-sha1",
  73. Compression: "none",
  74. }
  75. client, err := newPacketCipher(clientKeys, algs, kr)
  76. if err != nil {
  77. t.Fatalf("newPacketCipher(client): %v", err)
  78. }
  79. want := "bla bla"
  80. input := []byte(want)
  81. buf := &bytes.Buffer{}
  82. if err := client.writeCipherPacket(0, buf, rand.Reader, input); err != nil {
  83. t.Errorf("writeCipherPacket: %v", err)
  84. }
  85. packetSize := buf.Len()
  86. buf.Write(make([]byte, 2*maxPacket))
  87. // We corrupt each byte, but this usually will only test the
  88. // 'packet too large' or 'MAC failure' cases.
  89. lastRead := -1
  90. for i := 0; i < packetSize; i++ {
  91. server, err := newPacketCipher(clientKeys, algs, kr)
  92. if err != nil {
  93. t.Fatalf("newPacketCipher(client): %v", err)
  94. }
  95. fresh := &bytes.Buffer{}
  96. fresh.Write(buf.Bytes())
  97. fresh.Bytes()[i] ^= 0x01
  98. before := fresh.Len()
  99. _, err = server.readCipherPacket(0, fresh)
  100. if err == nil {
  101. t.Errorf("corrupt byte %d: readCipherPacket succeeded ", i)
  102. continue
  103. }
  104. if _, ok := err.(cbcError); !ok {
  105. t.Errorf("corrupt byte %d: got %v (%T), want cbcError", i, err, err)
  106. continue
  107. }
  108. after := fresh.Len()
  109. bytesRead := before - after
  110. if bytesRead < maxPacket {
  111. t.Errorf("corrupt byte %d: read %d bytes, want more than %d", i, bytesRead, maxPacket)
  112. continue
  113. }
  114. if i > 0 && bytesRead != lastRead {
  115. t.Errorf("corrupt byte %d: read %d bytes, want %d bytes read", i, bytesRead, lastRead)
  116. }
  117. lastRead = bytesRead
  118. }
  119. }
  120. func TestCVE202143565(t *testing.T) {
  121. tests := []struct {
  122. cipher string
  123. constructPacket func(packetCipher) io.Reader
  124. }{
  125. {
  126. cipher: gcm128CipherID,
  127. constructPacket: func(client packetCipher) io.Reader {
  128. internalCipher := client.(*gcmCipher)
  129. b := &bytes.Buffer{}
  130. prefix := [4]byte{}
  131. if _, err := b.Write(prefix[:]); err != nil {
  132. t.Fatal(err)
  133. }
  134. internalCipher.buf = internalCipher.aead.Seal(internalCipher.buf[:0], internalCipher.iv, []byte{}, prefix[:])
  135. if _, err := b.Write(internalCipher.buf); err != nil {
  136. t.Fatal(err)
  137. }
  138. internalCipher.incIV()
  139. return b
  140. },
  141. },
  142. {
  143. cipher: chacha20Poly1305ID,
  144. constructPacket: func(client packetCipher) io.Reader {
  145. internalCipher := client.(*chacha20Poly1305Cipher)
  146. b := &bytes.Buffer{}
  147. nonce := make([]byte, 12)
  148. s, err := chacha20.NewUnauthenticatedCipher(internalCipher.contentKey[:], nonce)
  149. if err != nil {
  150. t.Fatal(err)
  151. }
  152. var polyKey, discardBuf [32]byte
  153. s.XORKeyStream(polyKey[:], polyKey[:])
  154. s.XORKeyStream(discardBuf[:], discardBuf[:]) // skip the next 32 bytes
  155. internalCipher.buf = make([]byte, 4+poly1305.TagSize)
  156. binary.BigEndian.PutUint32(internalCipher.buf, 0)
  157. ls, err := chacha20.NewUnauthenticatedCipher(internalCipher.lengthKey[:], nonce)
  158. if err != nil {
  159. t.Fatal(err)
  160. }
  161. ls.XORKeyStream(internalCipher.buf, internalCipher.buf[:4])
  162. if _, err := io.ReadFull(rand.Reader, internalCipher.buf[4:4]); err != nil {
  163. t.Fatal(err)
  164. }
  165. s.XORKeyStream(internalCipher.buf[4:], internalCipher.buf[4:4])
  166. var tag [poly1305.TagSize]byte
  167. poly1305.Sum(&tag, internalCipher.buf[:4], &polyKey)
  168. copy(internalCipher.buf[4:], tag[:])
  169. if _, err := b.Write(internalCipher.buf); err != nil {
  170. t.Fatal(err)
  171. }
  172. return b
  173. },
  174. },
  175. }
  176. for _, tc := range tests {
  177. mac := "hmac-sha2-256"
  178. kr := &kexResult{Hash: crypto.SHA1}
  179. algs := directionAlgorithms{
  180. Cipher: tc.cipher,
  181. MAC: mac,
  182. Compression: "none",
  183. }
  184. client, err := newPacketCipher(clientKeys, algs, kr)
  185. if err != nil {
  186. t.Fatalf("newPacketCipher(client, %q, %q): %v", tc.cipher, mac, err)
  187. }
  188. server, err := newPacketCipher(clientKeys, algs, kr)
  189. if err != nil {
  190. t.Fatalf("newPacketCipher(client, %q, %q): %v", tc.cipher, mac, err)
  191. }
  192. b := tc.constructPacket(client)
  193. wantErr := "ssh: empty packet"
  194. _, err = server.readCipherPacket(0, b)
  195. if err == nil {
  196. t.Fatalf("readCipherPacket(%q, %q): didn't fail with empty packet", tc.cipher, mac)
  197. } else if err.Error() != wantErr {
  198. t.Fatalf("readCipherPacket(%q, %q): unexpected error, got %q, want %q", tc.cipher, mac, err, wantErr)
  199. }
  200. }
  201. }