add tests for crypto escalation

This commit is contained in:
Lucas Clemente
2016-04-17 17:11:54 +02:00
parent 5c6e72303e
commit d32a1b8a2b
2 changed files with 93 additions and 12 deletions

View File

@@ -11,6 +11,9 @@ import (
"github.com/lucas-clemente/quic-go/protocol"
)
// KeyDerivationFunction is used for key derivation
type KeyDerivationFunction func(forwardSecure bool, sharedSecret, nonces []byte, connID protocol.ConnectionID, chlo []byte, scfg []byte, cert []byte) (crypto.AEAD, error)
// The CryptoSetup handles all things crypto for the Session
type CryptoSetup struct {
connID protocol.ConnectionID
@@ -20,8 +23,9 @@ type CryptoSetup struct {
secureAEAD crypto.AEAD
forwardSecureAEAD crypto.AEAD
receivedSecurePacket bool
receivedForwardSecurePacket bool
keyDerivation KeyDerivationFunction
}
// NewCryptoSetup creates a new CryptoSetup instance
@@ -31,10 +35,11 @@ func NewCryptoSetup(connID protocol.ConnectionID, version protocol.VersionNumber
panic(err)
}
return &CryptoSetup{
connID: connID,
version: version,
scfg: scfg,
nonce: nonce,
connID: connID,
version: version,
scfg: scfg,
nonce: nonce,
keyDerivation: crypto.DeriveKeysChacha20,
}
}
@@ -122,12 +127,12 @@ func (h *CryptoSetup) handleCHLO(data []byte, cryptoData map[Tag][]byte) ([]byte
nonce.Write(cryptoData[TagNONC])
nonce.Write(h.nonce)
h.secureAEAD, err = crypto.DeriveKeysChacha20(false, sharedSecret, nonce.Bytes(), h.connID, data, h.scfg.Get(), h.scfg.signer.GetCertUncompressed())
h.secureAEAD, err = h.keyDerivation(false, sharedSecret, nonce.Bytes(), h.connID, data, h.scfg.Get(), h.scfg.signer.GetCertUncompressed())
if err != nil {
return nil, err
}
// TODO: Use new curve
h.forwardSecureAEAD, err = crypto.DeriveKeysChacha20(true, sharedSecret, nonce.Bytes(), h.connID, data, h.scfg.Get(), h.scfg.signer.GetCertUncompressed())
h.forwardSecureAEAD, err = h.keyDerivation(true, sharedSecret, nonce.Bytes(), h.connID, data, h.scfg.Get(), h.scfg.signer.GetCertUncompressed())
if err != nil {
return nil, err
}

View File

@@ -2,8 +2,11 @@ package handshake
import (
"bytes"
"errors"
"io"
"io/ioutil"
"github.com/lucas-clemente/quic-go/crypto"
"github.com/lucas-clemente/quic-go/protocol"
. "github.com/onsi/ginkgo"
@@ -36,6 +39,32 @@ func (*mockSigner) GetCertUncompressed() []byte {
return []byte("certuncompressed")
}
type mockAEAD struct {
forwardSecure bool
}
func (m *mockAEAD) Seal(packetNumber protocol.PacketNumber, b *bytes.Buffer, associatedData []byte, plaintext []byte) {
if m.forwardSecure {
b.Write([]byte("forward secure encrypted"))
} else {
b.Write([]byte("encrypted"))
}
}
func (m *mockAEAD) Open(packetNumber protocol.PacketNumber, associatedData []byte, ciphertext io.Reader) (*bytes.Reader, error) {
data, _ := ioutil.ReadAll(ciphertext)
if m.forwardSecure && string(data) == "forward secure encrypted" {
return bytes.NewReader([]byte("decrypted")), nil
} else if !m.forwardSecure && string(data) == "encrypted" {
return bytes.NewReader([]byte("decrypted")), nil
}
return nil, errors.New("authentication failed")
}
func mockKeyDerivation(forwardSecure bool, sharedSecret, nonces []byte, connID protocol.ConnectionID, chlo []byte, scfg []byte, cert []byte) (crypto.AEAD, error) {
return &mockAEAD{forwardSecure: forwardSecure}, nil
}
var _ = Describe("Crypto setup", func() {
var (
kex *mockKEX
@@ -52,6 +81,7 @@ var _ = Describe("Crypto setup", func() {
scfg = NewServerConfig(kex, signer)
v := protocol.SupportedVersions[len(protocol.SupportedVersions)-1]
cs = NewCryptoSetup(protocol.ConnectionID(42), v, scfg)
cs.keyDerivation = mockKeyDerivation
})
It("has a nonce", func() {
@@ -111,6 +141,11 @@ var _ = Describe("Crypto setup", func() {
Context("escalating crypto", func() {
foobarFNVSigned := []byte{0x18, 0x6f, 0x44, 0xba, 0x97, 0x35, 0xd, 0x6f, 0xbf, 0x64, 0x3c, 0x79, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72}
doCHLO := func() {
_, err := cs.handleCHLO([]byte("chlo-data"), map[Tag][]byte{TagPUBS: []byte("pubs-c")})
Expect(err).ToNot(HaveOccurred())
}
Context("null encryption", func() {
It("is used initially", func() {
cs.Seal(0, buf, []byte{}, []byte("foobar"))
@@ -126,19 +161,60 @@ var _ = Describe("Crypto setup", func() {
})
It("is not accepted after CHLO", func() {
_, err := cs.handleCHLO([]byte("chlo-data"), map[Tag][]byte{TagPUBS: []byte("pubs-c")})
Expect(err).ToNot(HaveOccurred())
doCHLO()
Expect(cs.secureAEAD).ToNot(BeNil())
_, err = cs.Open(0, []byte{}, bytes.NewReader(foobarFNVSigned))
_, err := cs.Open(0, []byte{}, bytes.NewReader(foobarFNVSigned))
Expect(err).To(MatchError("authentication failed"))
})
It("is not used after CHLO", func() {
_, err := cs.handleCHLO([]byte("chlo-data"), map[Tag][]byte{TagPUBS: []byte("pubs-c")})
Expect(err).ToNot(HaveOccurred())
doCHLO()
cs.Seal(0, buf, []byte{}, []byte("foobar"))
Expect(buf.Bytes()).ToNot(Equal(foobarFNVSigned))
})
})
Context("initial encryption", func() {
It("is used after CHLO", func() {
doCHLO()
cs.Seal(0, buf, []byte{}, []byte("foobar"))
Expect(buf.Bytes()).To(Equal([]byte("encrypted")))
})
It("is accepted after CHLO", func() {
doCHLO()
r, err := cs.Open(0, []byte{}, bytes.NewReader([]byte("encrypted")))
Expect(err).ToNot(HaveOccurred())
d, err := ioutil.ReadAll(r)
Expect(err).ToNot(HaveOccurred())
Expect(d).To(Equal([]byte("decrypted")))
})
It("is not used after receiving forward secure packet", func() {
doCHLO()
_, err := cs.Open(0, []byte{}, bytes.NewReader([]byte("forward secure encrypted")))
Expect(err).ToNot(HaveOccurred())
cs.Seal(0, buf, []byte{}, []byte("foobar"))
Expect(buf.Bytes()).To(Equal([]byte("forward secure encrypted")))
})
It("is not accepted after receiving forward secure packet", func() {
doCHLO()
_, err := cs.Open(0, []byte{}, bytes.NewReader([]byte("forward secure encrypted")))
Expect(err).ToNot(HaveOccurred())
_, err = cs.Open(0, []byte{}, bytes.NewReader([]byte("encrypted")))
Expect(err).To(MatchError("authentication failed"))
})
})
Context("forward secure encryption", func() {
It("is used after receiving forward secure packet", func() {
doCHLO()
_, err := cs.Open(0, []byte{}, bytes.NewReader([]byte("forward secure encrypted")))
Expect(err).ToNot(HaveOccurred())
cs.Seal(0, buf, []byte{}, []byte("foobar"))
Expect(buf.Bytes()).To(Equal([]byte("forward secure encrypted")))
})
})
})
})