diff --git a/handshake/crypto_setup_client.go b/handshake/crypto_setup_client.go index cb43b49d..50ca9227 100644 --- a/handshake/crypto_setup_client.go +++ b/handshake/crypto_setup_client.go @@ -312,6 +312,25 @@ func (h *cryptoSetupClient) Seal(dst, src []byte, packetNumber protocol.PacketNu return (&crypto.NullAEAD{}).Seal(dst, src, packetNumber, associatedData), protocol.EncryptionUnencrypted } +func (h *cryptoSetupClient) SealWith(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte, forceEncryptionLevel protocol.EncryptionLevel) ([]byte, protocol.EncryptionLevel, error) { + switch forceEncryptionLevel { + case protocol.EncryptionUnencrypted: + return (&crypto.NullAEAD{}).Seal(dst, src, packetNumber, associatedData), protocol.EncryptionUnencrypted, nil + case protocol.EncryptionSecure: + if h.secureAEAD == nil { + return nil, protocol.EncryptionUnspecified, errors.New("CryptoSetupClient: no secureAEAD") + } + return h.secureAEAD.Seal(dst, src, packetNumber, associatedData), protocol.EncryptionSecure, nil + case protocol.EncryptionForwardSecure: + if h.forwardSecureAEAD == nil { + return nil, protocol.EncryptionUnspecified, errors.New("CryptoSetupClient: no forwardSecureAEAD") + } + return h.forwardSecureAEAD.Seal(dst, src, packetNumber, associatedData), protocol.EncryptionForwardSecure, nil + } + + return nil, protocol.EncryptionUnspecified, errors.New("no encryption level specified") +} + func (h *cryptoSetupClient) DiversificationNonce() []byte { panic("not needed for cryptoSetupClient") } diff --git a/handshake/crypto_setup_client_test.go b/handshake/crypto_setup_client_test.go index bece3b40..b8a88519 100644 --- a/handshake/crypto_setup_client_test.go +++ b/handshake/crypto_setup_client_test.go @@ -744,6 +744,48 @@ var _ = Describe("Crypto setup", func() { Expect(enc).To(Equal(protocol.EncryptionForwardSecure)) }) }) + + Context("forcing encryption levels", func() { + It("forces null encryption", func() { + d, enc, err := cs.SealWith(nil, []byte("foobar"), 0, []byte{}, protocol.EncryptionUnencrypted) + Expect(err).ToNot(HaveOccurred()) + Expect(d).To(Equal(foobarFNVSigned)) + Expect(enc).To(Equal(protocol.EncryptionUnencrypted)) + }) + + It("forces initial encryption", func() { + doCompleteREJ() + d, enc, err := cs.SealWith(nil, []byte("foobar"), 0, []byte{}, protocol.EncryptionSecure) + Expect(err).ToNot(HaveOccurred()) + Expect(d).To(Equal([]byte("foobar normal sec"))) + Expect(enc).To(Equal(protocol.EncryptionSecure)) + }) + + It("errors of no AEAD for initial encryption is available", func() { + _, enc, err := cs.SealWith(nil, []byte("foobar"), 0, []byte{}, protocol.EncryptionSecure) + Expect(err).To(MatchError("CryptoSetupClient: no secureAEAD")) + Expect(enc).To(Equal(protocol.EncryptionUnspecified)) + }) + + It("forces forward-secure encryption", func() { + doSHLO() + d, enc, err := cs.SealWith(nil, []byte("foobar"), 0, []byte{}, protocol.EncryptionForwardSecure) + Expect(err).ToNot(HaveOccurred()) + Expect(d).To(Equal([]byte("foobar forward sec"))) + Expect(enc).To(Equal(protocol.EncryptionForwardSecure)) + }) + + It("errors of no AEAD for forward-secure encryption is available", func() { + _, enc, err := cs.SealWith(nil, []byte("foobar"), 0, []byte{}, protocol.EncryptionForwardSecure) + Expect(err).To(MatchError("CryptoSetupClient: no forwardSecureAEAD")) + Expect(enc).To(Equal(protocol.EncryptionUnspecified)) + }) + + It("errors if no encryption level is specified", func() { + _, _, err := cs.SealWith(nil, []byte("foobar"), 0, []byte{}, protocol.EncryptionUnspecified) + Expect(err).To(MatchError("no encryption level specified")) + }) + }) }) Context("Diversification Nonces", func() { diff --git a/handshake/crypto_setup_interface.go b/handshake/crypto_setup_interface.go index 42cd923c..49952525 100644 --- a/handshake/crypto_setup_interface.go +++ b/handshake/crypto_setup_interface.go @@ -7,6 +7,7 @@ type CryptoSetup interface { HandleCryptoStream() error Open(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, protocol.EncryptionLevel, error) Seal(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, protocol.EncryptionLevel) + SealWith(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte, forceEncryptionLevel protocol.EncryptionLevel) ([]byte, protocol.EncryptionLevel, error) LockForSealing() UnlockForSealing() HandshakeComplete() bool diff --git a/handshake/crypto_setup_server.go b/handshake/crypto_setup_server.go index 7176b861..fe6fcef2 100644 --- a/handshake/crypto_setup_server.go +++ b/handshake/crypto_setup_server.go @@ -4,6 +4,7 @@ import ( "bytes" "crypto/rand" "encoding/binary" + "errors" "io" "sync" @@ -195,6 +196,25 @@ func (h *cryptoSetupServer) Seal(dst, src []byte, packetNumber protocol.PacketNu } } +func (h *cryptoSetupServer) SealWith(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte, forceEncryptionLevel protocol.EncryptionLevel) ([]byte, protocol.EncryptionLevel, error) { + switch forceEncryptionLevel { + case protocol.EncryptionUnencrypted: + return (&crypto.NullAEAD{}).Seal(dst, src, packetNumber, associatedData), protocol.EncryptionUnencrypted, nil + case protocol.EncryptionSecure: + if h.secureAEAD == nil { + return nil, protocol.EncryptionUnspecified, errors.New("CryptoSetupServer: no secureAEAD") + } + return h.secureAEAD.Seal(dst, src, packetNumber, associatedData), protocol.EncryptionSecure, nil + case protocol.EncryptionForwardSecure: + if h.forwardSecureAEAD == nil { + return nil, protocol.EncryptionUnspecified, errors.New("CryptoSetupServer: no forwardSecureAEAD") + } + return h.forwardSecureAEAD.Seal(dst, src, packetNumber, associatedData), protocol.EncryptionForwardSecure, nil + } + + return nil, protocol.EncryptionUnspecified, errors.New("no encryption level specified") +} + func (h *cryptoSetupServer) isInchoateCHLO(cryptoData map[Tag][]byte, cert []byte) bool { if _, ok := cryptoData[TagPUBS]; !ok { return true diff --git a/handshake/crypto_setup_server_test.go b/handshake/crypto_setup_server_test.go index f90a8467..39313ff0 100644 --- a/handshake/crypto_setup_server_test.go +++ b/handshake/crypto_setup_server_test.go @@ -659,6 +659,48 @@ var _ = Describe("Crypto setup", func() { Expect(enc).To(Equal(protocol.EncryptionForwardSecure)) }) }) + + Context("forcing encryption levels", func() { + It("forces null encryption", func() { + d, enc, err := cs.SealWith(nil, []byte("foobar"), 0, []byte{}, protocol.EncryptionUnencrypted) + Expect(err).ToNot(HaveOccurred()) + Expect(d).To(Equal(foobarFNVSigned)) + Expect(enc).To(Equal(protocol.EncryptionUnencrypted)) + }) + + It("forces initial encryption", func() { + doCHLO() + d, enc, err := cs.SealWith(nil, []byte("foobar"), 0, []byte{}, protocol.EncryptionSecure) + Expect(err).ToNot(HaveOccurred()) + Expect(d).To(Equal([]byte("foobar normal sec"))) + Expect(enc).To(Equal(protocol.EncryptionSecure)) + }) + + It("errors of no AEAD for initial encryption is available", func() { + _, enc, err := cs.SealWith(nil, []byte("foobar"), 0, []byte{}, protocol.EncryptionSecure) + Expect(err).To(MatchError("CryptoSetupServer: no secureAEAD")) + Expect(enc).To(Equal(protocol.EncryptionUnspecified)) + }) + + It("forces forward-secure encryption", func() { + doCHLO() + d, enc, err := cs.SealWith(nil, []byte("foobar"), 0, []byte{}, protocol.EncryptionForwardSecure) + Expect(err).ToNot(HaveOccurred()) + Expect(d).To(Equal([]byte("foobar forward sec"))) + Expect(enc).To(Equal(protocol.EncryptionForwardSecure)) + }) + + It("errors of no AEAD for forward-secure encryption is available", func() { + _, enc, err := cs.SealWith(nil, []byte("foobar"), 0, []byte{}, protocol.EncryptionForwardSecure) + Expect(err).To(MatchError("CryptoSetupServer: no forwardSecureAEAD")) + Expect(enc).To(Equal(protocol.EncryptionUnspecified)) + }) + + It("errors if no encryption level is specified", func() { + _, _, err := cs.SealWith(nil, []byte("foobar"), 0, []byte{}, protocol.EncryptionUnspecified) + Expect(err).To(MatchError("no encryption level specified")) + }) + }) }) Context("STK verification and creation", func() { diff --git a/packet_packer_test.go b/packet_packer_test.go index b76918a5..6e7f5025 100644 --- a/packet_packer_test.go +++ b/packet_packer_test.go @@ -24,6 +24,9 @@ func (m *mockCryptoSetup) Open(dst, src []byte, packetNumber protocol.PacketNumb func (m *mockCryptoSetup) Seal(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, protocol.EncryptionLevel) { return append(src, bytes.Repeat([]byte{0}, 12)...), m.encLevelSeal } +func (m *mockCryptoSetup) SealWith(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte, encLevel protocol.EncryptionLevel) ([]byte, protocol.EncryptionLevel, error) { + panic("not implemented") +} func (m *mockCryptoSetup) LockForSealing() {} func (m *mockCryptoSetup) UnlockForSealing() {} func (m *mockCryptoSetup) HandshakeComplete() bool { return m.handshakeComplete }