From f1810ae82dab2f1ec219c3ab1d8c78130d52d376 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Fri, 11 Nov 2016 00:30:31 +0700 Subject: [PATCH] generate a client nonce after receiving a server config --- handshake/crypto_setup_client.go | 31 +++++++++++++++++------- handshake/crypto_setup_client_test.go | 35 +++++++++++++++++++++------ 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/handshake/crypto_setup_client.go b/handshake/crypto_setup_client.go index 9acde21b..fc575c18 100644 --- a/handshake/crypto_setup_client.go +++ b/handshake/crypto_setup_client.go @@ -24,6 +24,7 @@ type cryptoSetupClient struct { stk []byte sno []byte + nonc []byte diversificationNonce []byte certManager *crypto.CertManager } @@ -32,7 +33,8 @@ var _ crypto.AEAD = &cryptoSetupClient{} var _ CryptoSetup = &cryptoSetupClient{} var ( - errNoObitForClientNonce = errors.New("No OBIT for client nonce available") + errNoObitForClientNonce = errors.New("CryptoSetup BUG: No OBIT for client nonce available") + errClientNonceAlreadyExists = errors.New("CryptoSetup BUG: A client nonce was already generated") errConflictingDiversificationNonces = errors.New("Received two different diversification nonces") ) @@ -100,6 +102,12 @@ func (h *cryptoSetupClient) handleREJMessage(cryptoData map[Tag][]byte) error { if err != nil { return err } + + // now that we have a server config, we can use its OBIT value to generate a client nonce + err = h.generateClientNonce() + if err != nil { + return err + } } if crt, ok := cryptoData[TagCERT]; ok { @@ -185,20 +193,25 @@ func (h *cryptoSetupClient) getTags() map[Tag][]byte { return tags } -func (h *cryptoSetupClient) generateClientNonce() ([]byte, error) { - nonce := make([]byte, 32) - binary.BigEndian.PutUint32(nonce, uint32(time.Now().Unix())) +func (h *cryptoSetupClient) generateClientNonce() error { + if len(h.nonc) > 0 { + return errClientNonceAlreadyExists + } + + nonc := make([]byte, 32) + binary.BigEndian.PutUint32(nonc, uint32(time.Now().Unix())) if len(h.serverConfig.obit) != 8 { - return nil, errNoObitForClientNonce + return errNoObitForClientNonce } - copy(nonce[4:12], h.serverConfig.obit) + copy(nonc[4:12], h.serverConfig.obit) - _, err := rand.Read(nonce[12:]) + _, err := rand.Read(nonc[12:]) if err != nil { - return nil, err + return err } - return nonce, nil + h.nonc = nonc + return nil } diff --git a/handshake/crypto_setup_client_test.go b/handshake/crypto_setup_client_test.go index 2943e97c..59445f8e 100644 --- a/handshake/crypto_setup_client_test.go +++ b/handshake/crypto_setup_client_test.go @@ -35,7 +35,7 @@ var _ = Describe("Crypto setup", func() { Expect(err).To(MatchError(qerr.InvalidCryptoMessageType)) }) - It("errors on invalid hanshake messages", func() { + It("errors on invalid handshake messages", func() { b := &bytes.Buffer{} WriteHandshakeMessage(b, TagCHLO, tagMap) stream.dataToRead.Write(b.Bytes()[:b.Len()-2]) // cut the handshake message @@ -81,6 +81,15 @@ var _ = Describe("Crypto setup", func() { Expect(cs.serverConfig.ID).To(Equal(scfg[TagSCID])) }) + It("generates a client nonce after reading a server config", func() { + b := &bytes.Buffer{} + WriteHandshakeMessage(b, TagSCFG, getDefaultServerConfigClient()) + tagMap[TagSCFG] = b.Bytes() + err := cs.handleREJMessage(tagMap) + Expect(err).ToNot(HaveOccurred()) + Expect(cs.nonc).To(HaveLen(32)) + }) + It("passes on errors from reading the server config", func() { b := &bytes.Buffer{} WriteHandshakeMessage(b, TagSHLO, make(map[Tag][]byte)) @@ -169,25 +178,35 @@ var _ = Describe("Crypto setup", func() { It("generates a client nonce", func() { now := time.Now() - nonce, err := cs.generateClientNonce() - Expect(nonce).To(HaveLen(32)) + err := cs.generateClientNonce() + Expect(cs.nonc).To(HaveLen(32)) Expect(err).ToNot(HaveOccurred()) - Expect(time.Unix(int64(binary.BigEndian.Uint32(nonce[0:4])), 0)).To(BeTemporally("~", now, 1*time.Second)) - Expect(nonce[4:12]).To(Equal(cs.serverConfig.obit)) + Expect(time.Unix(int64(binary.BigEndian.Uint32(cs.nonc[0:4])), 0)).To(BeTemporally("~", now, 1*time.Second)) + Expect(cs.nonc[4:12]).To(Equal(cs.serverConfig.obit)) }) It("uses random values for the last 20 bytes", func() { - nonce1, err := cs.generateClientNonce() + err := cs.generateClientNonce() Expect(err).ToNot(HaveOccurred()) - nonce2, err := cs.generateClientNonce() + nonce1 := cs.nonc + cs.nonc = []byte{} + err = cs.generateClientNonce() Expect(err).ToNot(HaveOccurred()) + nonce2 := cs.nonc Expect(nonce1[4:12]).To(Equal(nonce2[4:12])) Expect(nonce1[12:]).ToNot(Equal(nonce2[12:])) }) + It("errors if a client nonce has already been generated", func() { + err := cs.generateClientNonce() + Expect(err).ToNot(HaveOccurred()) + err = cs.generateClientNonce() + Expect(err).To(MatchError(errClientNonceAlreadyExists)) + }) + It("errors if no OBIT value is available", func() { cs.serverConfig.obit = []byte{} - _, err := cs.generateClientNonce() + err := cs.generateClientNonce() Expect(err).To(MatchError(errNoObitForClientNonce)) }) })