forked from quic-go/quic-go
@@ -12,7 +12,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// DeriveKeysChacha20 derives the client and server keys and creates a matching chacha20poly1305 instance
|
// DeriveKeysChacha20 derives the client and server keys and creates a matching chacha20poly1305 instance
|
||||||
func DeriveKeysChacha20(forwardSecure bool, sharedSecret, nonces []byte, connID protocol.ConnectionID, chlo []byte, scfg []byte, cert []byte) (AEAD, error) {
|
func DeriveKeysChacha20(version protocol.VersionNumber, forwardSecure bool, sharedSecret, nonces []byte, connID protocol.ConnectionID, chlo []byte, scfg []byte, cert []byte, divNonce []byte) (AEAD, error) {
|
||||||
var info bytes.Buffer
|
var info bytes.Buffer
|
||||||
if forwardSecure {
|
if forwardSecure {
|
||||||
info.Write([]byte("QUIC forward secure key expansion\x00"))
|
info.Write([]byte("QUIC forward secure key expansion\x00"))
|
||||||
@@ -44,5 +44,28 @@ func DeriveKeysChacha20(forwardSecure bool, sharedSecret, nonces []byte, connID
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !forwardSecure && version >= protocol.VersionNumber(33) {
|
||||||
|
if err := diversify(myKey, myIV, divNonce); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return NewAEADChacha20Poly1305(otherKey, myKey, otherIV, myIV)
|
return NewAEADChacha20Poly1305(otherKey, myKey, otherIV, myIV)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func diversify(key, iv, divNonce []byte) error {
|
||||||
|
secret := make([]byte, len(key)+len(iv))
|
||||||
|
copy(secret, key)
|
||||||
|
copy(secret[len(key):], iv)
|
||||||
|
|
||||||
|
r := hkdf.New(sha256.New, secret, divNonce, []byte("QUIC key diversification"))
|
||||||
|
|
||||||
|
if _, err := io.ReadFull(r, key); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := io.ReadFull(r, iv); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
var _ = Describe("KeyDerivation", func() {
|
var _ = Describe("KeyDerivation", func() {
|
||||||
It("derives non-fs keys", func() {
|
It("derives non-fs keys", func() {
|
||||||
aead, err := DeriveKeysChacha20(
|
aead, err := DeriveKeysChacha20(
|
||||||
|
32,
|
||||||
false,
|
false,
|
||||||
[]byte("0123456789012345678901"),
|
[]byte("0123456789012345678901"),
|
||||||
[]byte("nonce"),
|
[]byte("nonce"),
|
||||||
@@ -17,6 +18,7 @@ var _ = Describe("KeyDerivation", func() {
|
|||||||
[]byte("chlo"),
|
[]byte("chlo"),
|
||||||
[]byte("scfg"),
|
[]byte("scfg"),
|
||||||
[]byte("cert"),
|
[]byte("cert"),
|
||||||
|
nil,
|
||||||
)
|
)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
chacha := aead.(*aeadChacha20Poly1305)
|
chacha := aead.(*aeadChacha20Poly1305)
|
||||||
@@ -27,6 +29,7 @@ var _ = Describe("KeyDerivation", func() {
|
|||||||
|
|
||||||
It("derives fs keys", func() {
|
It("derives fs keys", func() {
|
||||||
aead, err := DeriveKeysChacha20(
|
aead, err := DeriveKeysChacha20(
|
||||||
|
32,
|
||||||
true,
|
true,
|
||||||
[]byte("0123456789012345678901"),
|
[]byte("0123456789012345678901"),
|
||||||
[]byte("nonce"),
|
[]byte("nonce"),
|
||||||
@@ -34,6 +37,7 @@ var _ = Describe("KeyDerivation", func() {
|
|||||||
[]byte("chlo"),
|
[]byte("chlo"),
|
||||||
[]byte("scfg"),
|
[]byte("scfg"),
|
||||||
[]byte("cert"),
|
[]byte("cert"),
|
||||||
|
nil,
|
||||||
)
|
)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
chacha := aead.(*aeadChacha20Poly1305)
|
chacha := aead.(*aeadChacha20Poly1305)
|
||||||
@@ -41,4 +45,42 @@ var _ = Describe("KeyDerivation", func() {
|
|||||||
Expect(chacha.myIV).To(Equal([]byte{0xf5, 0x73, 0x11, 0x79}))
|
Expect(chacha.myIV).To(Equal([]byte{0xf5, 0x73, 0x11, 0x79}))
|
||||||
Expect(chacha.otherIV).To(Equal([]byte{0xf7, 0x26, 0x4d, 0x2c}))
|
Expect(chacha.otherIV).To(Equal([]byte{0xf7, 0x26, 0x4d, 0x2c}))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("does not use diversification nonces in FS key derivation", func() {
|
||||||
|
aead, err := DeriveKeysChacha20(
|
||||||
|
33,
|
||||||
|
true,
|
||||||
|
[]byte("0123456789012345678901"),
|
||||||
|
[]byte("nonce"),
|
||||||
|
protocol.ConnectionID(42),
|
||||||
|
[]byte("chlo"),
|
||||||
|
[]byte("scfg"),
|
||||||
|
[]byte("cert"),
|
||||||
|
[]byte("divnonce"),
|
||||||
|
)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
chacha := aead.(*aeadChacha20Poly1305)
|
||||||
|
// If the IVs match, the keys will match too, since the keys are read earlier
|
||||||
|
Expect(chacha.myIV).To(Equal([]byte{0xf5, 0x73, 0x11, 0x79}))
|
||||||
|
Expect(chacha.otherIV).To(Equal([]byte{0xf7, 0x26, 0x4d, 0x2c}))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("uses diversification nonces in initial key derivation", func() {
|
||||||
|
aead, err := DeriveKeysChacha20(
|
||||||
|
33,
|
||||||
|
false,
|
||||||
|
[]byte("0123456789012345678901"),
|
||||||
|
[]byte("nonce"),
|
||||||
|
protocol.ConnectionID(42),
|
||||||
|
[]byte("chlo"),
|
||||||
|
[]byte("scfg"),
|
||||||
|
[]byte("cert"),
|
||||||
|
[]byte("divnonce"),
|
||||||
|
)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
chacha := aead.(*aeadChacha20Poly1305)
|
||||||
|
// If the IVs match, the keys will match too, since the keys are read earlier
|
||||||
|
Expect(chacha.myIV).To(Equal([]byte{0xc4, 0x12, 0x25, 0x64}))
|
||||||
|
Expect(chacha.otherIV).To(Equal([]byte{0x75, 0xd8, 0xa2, 0x8d}))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// KeyDerivationFunction is used for key derivation
|
// 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)
|
type KeyDerivationFunction func(version protocol.VersionNumber, forwardSecure bool, sharedSecret, nonces []byte, connID protocol.ConnectionID, chlo []byte, scfg []byte, cert []byte, divNonce []byte) (crypto.AEAD, error)
|
||||||
|
|
||||||
// KeyExchangeFunction is used to make a new KEX
|
// KeyExchangeFunction is used to make a new KEX
|
||||||
type KeyExchangeFunction func() (crypto.KeyExchange, error)
|
type KeyExchangeFunction func() (crypto.KeyExchange, error)
|
||||||
@@ -206,9 +206,6 @@ func (h *CryptoSetup) handleCHLO(sni string, data []byte, cryptoData map[Tag][]b
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var fsNonce bytes.Buffer
|
|
||||||
fsNonce.Write(cryptoData[TagNONC])
|
|
||||||
fsNonce.Write(h.nonce)
|
|
||||||
|
|
||||||
h.mutex.Lock()
|
h.mutex.Lock()
|
||||||
defer h.mutex.Unlock()
|
defer h.mutex.Unlock()
|
||||||
@@ -218,12 +215,25 @@ func (h *CryptoSetup) handleCHLO(sni string, data []byte, cryptoData map[Tag][]b
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
h.secureAEAD, err = h.keyDerivation(false, sharedSecret, cryptoData[TagNONC], h.connID, data, h.scfg.Get(), certUncompressed)
|
h.secureAEAD, err = h.keyDerivation(
|
||||||
|
h.version,
|
||||||
|
false,
|
||||||
|
sharedSecret,
|
||||||
|
cryptoData[TagNONC],
|
||||||
|
h.connID,
|
||||||
|
data,
|
||||||
|
h.scfg.Get(),
|
||||||
|
certUncompressed,
|
||||||
|
h.diversificationNonce,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a new curve instance to derive the forward secure key
|
// Generate a new curve instance to derive the forward secure key
|
||||||
|
var fsNonce bytes.Buffer
|
||||||
|
fsNonce.Write(cryptoData[TagNONC])
|
||||||
|
fsNonce.Write(h.nonce)
|
||||||
ephermalKex, err := h.keyExchange()
|
ephermalKex, err := h.keyExchange()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -232,7 +242,16 @@ func (h *CryptoSetup) handleCHLO(sni string, data []byte, cryptoData map[Tag][]b
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
h.forwardSecureAEAD, err = h.keyDerivation(true, ephermalSharedSecret, fsNonce.Bytes(), h.connID, data, h.scfg.Get(), certUncompressed)
|
h.forwardSecureAEAD, err = h.keyDerivation(h.version,
|
||||||
|
true,
|
||||||
|
ephermalSharedSecret,
|
||||||
|
fsNonce.Bytes(),
|
||||||
|
h.connID,
|
||||||
|
data,
|
||||||
|
h.scfg.Get(),
|
||||||
|
certUncompressed,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ func (mockAEAD) DiversificationNonce() []byte { return nil }
|
|||||||
var expectedInitialNonceLen int
|
var expectedInitialNonceLen int
|
||||||
var expectedFSNonceLen int
|
var expectedFSNonceLen int
|
||||||
|
|
||||||
func mockKeyDerivation(forwardSecure bool, sharedSecret, nonces []byte, connID protocol.ConnectionID, chlo []byte, scfg []byte, cert []byte) (crypto.AEAD, error) {
|
func mockKeyDerivation(v protocol.VersionNumber, forwardSecure bool, sharedSecret, nonces []byte, connID protocol.ConnectionID, chlo []byte, scfg []byte, cert []byte, divNonce []byte) (crypto.AEAD, error) {
|
||||||
if forwardSecure {
|
if forwardSecure {
|
||||||
Expect(nonces).To(HaveLen(expectedFSNonceLen))
|
Expect(nonces).To(HaveLen(expectedFSNonceLen))
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user