github.com/Oyster-zx/tendermint@v0.34.24-fork/p2p/conn/evil_secret_connection_test.go (about) 1 package conn 2 3 import ( 4 "bytes" 5 "errors" 6 "io" 7 "testing" 8 9 gogotypes "github.com/gogo/protobuf/types" 10 "github.com/gtank/merlin" 11 "github.com/stretchr/testify/assert" 12 "golang.org/x/crypto/chacha20poly1305" 13 14 "github.com/tendermint/tendermint/crypto" 15 "github.com/tendermint/tendermint/crypto/ed25519" 16 cryptoenc "github.com/tendermint/tendermint/crypto/encoding" 17 "github.com/tendermint/tendermint/libs/protoio" 18 tmp2p "github.com/tendermint/tendermint/proto/tendermint/p2p" 19 ) 20 21 type buffer struct { 22 next bytes.Buffer 23 } 24 25 func (b *buffer) Read(data []byte) (n int, err error) { 26 return b.next.Read(data) 27 } 28 29 func (b *buffer) Write(data []byte) (n int, err error) { 30 return b.next.Write(data) 31 } 32 33 func (b *buffer) Bytes() []byte { 34 return b.next.Bytes() 35 } 36 37 func (b *buffer) Close() error { 38 return nil 39 } 40 41 type evilConn struct { 42 secretConn *SecretConnection 43 buffer *buffer 44 45 locEphPub *[32]byte 46 locEphPriv *[32]byte 47 remEphPub *[32]byte 48 privKey crypto.PrivKey 49 50 readStep int 51 writeStep int 52 readOffset int 53 54 shareEphKey bool 55 badEphKey bool 56 shareAuthSignature bool 57 badAuthSignature bool 58 } 59 60 func newEvilConn(shareEphKey, badEphKey, shareAuthSignature, badAuthSignature bool) *evilConn { 61 privKey := ed25519.GenPrivKey() 62 locEphPub, locEphPriv := genEphKeys() 63 var rep [32]byte 64 c := &evilConn{ 65 locEphPub: locEphPub, 66 locEphPriv: locEphPriv, 67 remEphPub: &rep, 68 privKey: privKey, 69 70 shareEphKey: shareEphKey, 71 badEphKey: badEphKey, 72 shareAuthSignature: shareAuthSignature, 73 badAuthSignature: badAuthSignature, 74 } 75 76 return c 77 } 78 79 func (c *evilConn) Read(data []byte) (n int, err error) { 80 if !c.shareEphKey { 81 return 0, io.EOF 82 } 83 84 switch c.readStep { 85 case 0: 86 if !c.badEphKey { 87 lc := *c.locEphPub 88 bz, err := protoio.MarshalDelimited(&gogotypes.BytesValue{Value: lc[:]}) 89 if err != nil { 90 panic(err) 91 } 92 copy(data, bz[c.readOffset:]) 93 n = len(data) 94 } else { 95 bz, err := protoio.MarshalDelimited(&gogotypes.BytesValue{Value: []byte("drop users;")}) 96 if err != nil { 97 panic(err) 98 } 99 copy(data, bz) 100 n = len(data) 101 } 102 c.readOffset += n 103 104 if n >= 32 { 105 c.readOffset = 0 106 c.readStep = 1 107 if !c.shareAuthSignature { 108 c.readStep = 2 109 } 110 } 111 112 return n, nil 113 case 1: 114 signature := c.signChallenge() 115 if !c.badAuthSignature { 116 pkpb, err := cryptoenc.PubKeyToProto(c.privKey.PubKey()) 117 if err != nil { 118 panic(err) 119 } 120 bz, err := protoio.MarshalDelimited(&tmp2p.AuthSigMessage{PubKey: pkpb, Sig: signature}) 121 if err != nil { 122 panic(err) 123 } 124 n, err = c.secretConn.Write(bz) 125 if err != nil { 126 panic(err) 127 } 128 if c.readOffset > len(c.buffer.Bytes()) { 129 return len(data), nil 130 } 131 copy(data, c.buffer.Bytes()[c.readOffset:]) 132 } else { 133 bz, err := protoio.MarshalDelimited(&gogotypes.BytesValue{Value: []byte("select * from users;")}) 134 if err != nil { 135 panic(err) 136 } 137 n, err = c.secretConn.Write(bz) 138 if err != nil { 139 panic(err) 140 } 141 if c.readOffset > len(c.buffer.Bytes()) { 142 return len(data), nil 143 } 144 copy(data, c.buffer.Bytes()) 145 } 146 c.readOffset += len(data) 147 return n, nil 148 default: 149 return 0, io.EOF 150 } 151 } 152 153 func (c *evilConn) Write(data []byte) (n int, err error) { 154 switch c.writeStep { 155 case 0: 156 var ( 157 bytes gogotypes.BytesValue 158 remEphPub [32]byte 159 ) 160 err := protoio.UnmarshalDelimited(data, &bytes) 161 if err != nil { 162 panic(err) 163 } 164 copy(remEphPub[:], bytes.Value) 165 c.remEphPub = &remEphPub 166 c.writeStep = 1 167 if !c.shareAuthSignature { 168 c.writeStep = 2 169 } 170 return len(data), nil 171 case 1: 172 // Signature is not needed, therefore skipped. 173 return len(data), nil 174 default: 175 return 0, io.EOF 176 } 177 } 178 179 func (c *evilConn) Close() error { 180 return nil 181 } 182 183 func (c *evilConn) signChallenge() []byte { 184 // Sort by lexical order. 185 loEphPub, hiEphPub := sort32(c.locEphPub, c.remEphPub) 186 187 transcript := merlin.NewTranscript("TENDERMINT_SECRET_CONNECTION_TRANSCRIPT_HASH") 188 189 transcript.AppendMessage(labelEphemeralLowerPublicKey, loEphPub[:]) 190 transcript.AppendMessage(labelEphemeralUpperPublicKey, hiEphPub[:]) 191 192 // Check if the local ephemeral public key was the least, lexicographically 193 // sorted. 194 locIsLeast := bytes.Equal(c.locEphPub[:], loEphPub[:]) 195 196 // Compute common diffie hellman secret using X25519. 197 dhSecret, err := computeDHSecret(c.remEphPub, c.locEphPriv) 198 if err != nil { 199 panic(err) 200 } 201 202 transcript.AppendMessage(labelDHSecret, dhSecret[:]) 203 204 // Generate the secret used for receiving, sending, challenge via HKDF-SHA2 205 // on the transcript state (which itself also uses HKDF-SHA2 to derive a key 206 // from the dhSecret). 207 recvSecret, sendSecret := deriveSecrets(dhSecret, locIsLeast) 208 209 const challengeSize = 32 210 var challenge [challengeSize]byte 211 challengeSlice := transcript.ExtractBytes(labelSecretConnectionMac, challengeSize) 212 213 copy(challenge[:], challengeSlice[0:challengeSize]) 214 215 sendAead, err := chacha20poly1305.New(sendSecret[:]) 216 if err != nil { 217 panic(errors.New("invalid send SecretConnection Key")) 218 } 219 recvAead, err := chacha20poly1305.New(recvSecret[:]) 220 if err != nil { 221 panic(errors.New("invalid receive SecretConnection Key")) 222 } 223 224 b := &buffer{} 225 c.secretConn = &SecretConnection{ 226 conn: b, 227 recvBuffer: nil, 228 recvNonce: new([aeadNonceSize]byte), 229 sendNonce: new([aeadNonceSize]byte), 230 recvAead: recvAead, 231 sendAead: sendAead, 232 } 233 c.buffer = b 234 235 // Sign the challenge bytes for authentication. 236 locSignature, err := signChallenge(&challenge, c.privKey) 237 if err != nil { 238 panic(err) 239 } 240 241 return locSignature 242 } 243 244 // TestMakeSecretConnection creates an evil connection and tests that 245 // MakeSecretConnection errors at different stages. 246 func TestMakeSecretConnection(t *testing.T) { 247 testCases := []struct { 248 name string 249 conn *evilConn 250 errMsg string 251 }{ 252 {"refuse to share ethimeral key", newEvilConn(false, false, false, false), "EOF"}, 253 {"share bad ethimeral key", newEvilConn(true, true, false, false), "wrong wireType"}, 254 {"refuse to share auth signature", newEvilConn(true, false, false, false), "EOF"}, 255 {"share bad auth signature", newEvilConn(true, false, true, true), "failed to decrypt SecretConnection"}, 256 {"all good", newEvilConn(true, false, true, false), ""}, 257 } 258 259 for _, tc := range testCases { 260 tc := tc 261 t.Run(tc.name, func(t *testing.T) { 262 privKey := ed25519.GenPrivKey() 263 _, err := MakeSecretConnection(tc.conn, privKey) 264 if tc.errMsg != "" { 265 if assert.Error(t, err) { 266 assert.Contains(t, err.Error(), tc.errMsg) 267 } 268 } else { 269 assert.NoError(t, err) 270 } 271 }) 272 } 273 }