add a method to generate a client nonce (NONC)

This commit is contained in:
Marten Seemann
2016-11-08 17:49:28 +07:00
parent 1031ad5288
commit 674287a8f4
2 changed files with 60 additions and 0 deletions

View File

@@ -2,8 +2,11 @@ package handshake
import (
"bytes"
"crypto/rand"
"encoding/binary"
"errors"
"io"
"time"
"github.com/lucas-clemente/quic-go/crypto"
"github.com/lucas-clemente/quic-go/protocol"
@@ -23,6 +26,10 @@ type cryptoSetupClient struct {
var _ crypto.AEAD = &cryptoSetupClient{}
var _ CryptoSetup = &cryptoSetupClient{}
var (
errNoObitForClientNonce = errors.New("No OBIT for client nonce available")
)
// NewCryptoSetupClient creates a new CryptoSetup instance for a client
func NewCryptoSetupClient(
connID protocol.ConnectionID,
@@ -114,3 +121,21 @@ func (h *cryptoSetupClient) sendInchoateCHLO() error {
}
return nil
}
func (h *cryptoSetupClient) generateClientNonce() ([]byte, error) {
nonce := make([]byte, 32)
binary.BigEndian.PutUint32(nonce, uint32(time.Now().Unix()))
if len(h.serverConfig.obit) != 8 {
return nil, errNoObitForClientNonce
}
copy(nonce[4:12], h.serverConfig.obit)
_, err := rand.Read(nonce[12:])
if err != nil {
return nil, err
}
return nonce, nil
}

View File

@@ -1,6 +1,9 @@
package handshake
import (
"encoding/binary"
"time"
"github.com/lucas-clemente/quic-go/protocol"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
@@ -10,8 +13,10 @@ var _ = Describe("Crypto setup", func() {
var cs cryptoSetupClient
BeforeEach(func() {
scfg := serverConfigClient{}
cs = cryptoSetupClient{
cryptoStream: &mockStream{},
serverConfig: &scfg,
version: protocol.Version36,
}
})
@@ -30,4 +35,34 @@ var _ = Describe("Crypto setup", func() {
Expect(cs.cryptoStream.(*mockStream).dataWritten.Len()).To(BeNumerically(">", protocol.ClientHelloMinimumSize))
})
})
Context("Client Nonce generation", func() {
BeforeEach(func() {
cs.serverConfig.obit = []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}
})
It("generates a client nonce", func() {
now := time.Now()
nonce, err := cs.generateClientNonce()
Expect(nonce).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))
})
It("uses random values for the last 20 bytes", func() {
nonce1, err := cs.generateClientNonce()
Expect(err).ToNot(HaveOccurred())
nonce2, err := cs.generateClientNonce()
Expect(err).ToNot(HaveOccurred())
Expect(nonce1[4:12]).To(Equal(nonce2[4:12]))
Expect(nonce1[12:]).ToNot(Equal(nonce2[12:]))
})
It("errors if no OBIT value is available", func() {
cs.serverConfig.obit = []byte{}
_, err := cs.generateClientNonce()
Expect(err).To(MatchError(errNoObitForClientNonce))
})
})
})