allow version negotiation between IETF QUIC and gQUIC, and vice versa

This commit is contained in:
Marten Seemann
2018-08-15 16:02:57 +07:00
parent 58eae32bc9
commit c840bd4177
4 changed files with 48 additions and 32 deletions

View File

@@ -283,17 +283,14 @@ func (c *client) dial(ctx context.Context) error {
}
func (c *client) dialGQUIC(ctx context.Context) error {
var cerr error
for {
if err := c.createNewGQUICSession(); err != nil {
return err
}
cerr = c.establishSecureConnection(ctx)
if cerr != errCloseSessionForNewVersion {
break
}
if err := c.createNewGQUICSession(); err != nil {
return err
}
return cerr
err := c.establishSecureConnection(ctx)
if err == errCloseSessionForNewVersion {
return c.dial(ctx)
}
return err
}
func (c *client) dialTLS(ctx context.Context) error {
@@ -315,17 +312,14 @@ func (c *client) dialTLS(ctx context.Context) error {
mintConf.ServerName = c.hostname
c.mintConf = mintConf
var cerr error
for {
if err := c.createNewTLSSession(extHandler.GetPeerParams(), c.version); err != nil {
return err
}
cerr = c.establishSecureConnection(ctx)
if cerr != errCloseSessionForRetry && cerr != errCloseSessionForNewVersion {
break
}
if err := c.createNewTLSSession(extHandler.GetPeerParams(), c.version); err != nil {
return err
}
return cerr
err = c.establishSecureConnection(ctx)
if err == errCloseSessionForRetry || err == errCloseSessionForNewVersion {
return c.dial(ctx)
}
return err
}
// establishSecureConnection runs the session, and tries to establish a secure connection

View File

@@ -86,18 +86,20 @@ func NewCryptoSetupClient(
}
divNonceChan := make(chan struct{})
cs := &cryptoSetupClient{
cryptoStream: cryptoStream,
hostname: hostname,
connID: connID,
version: version,
certManager: crypto.NewCertManager(tlsConfig),
params: params,
keyDerivation: crypto.DeriveQuicCryptoAESKeys,
nullAEAD: nullAEAD,
paramsChan: paramsChan,
handshakeEvent: handshakeEvent,
initialVersion: initialVersion,
negotiatedVersions: negotiatedVersions,
cryptoStream: cryptoStream,
hostname: hostname,
connID: connID,
version: version,
certManager: crypto.NewCertManager(tlsConfig),
params: params,
keyDerivation: crypto.DeriveQuicCryptoAESKeys,
nullAEAD: nullAEAD,
paramsChan: paramsChan,
handshakeEvent: handshakeEvent,
initialVersion: initialVersion,
// The server might have sent greased versions in the Version Negotiation packet.
// We need strip those from the list, since they won't be included in the handshake tag.
negotiatedVersions: protocol.StripGreasedVersions(negotiatedVersions),
divNonceChan: divNonceChan,
logger: logger,
}

View File

@@ -152,3 +152,14 @@ func GetGreasedVersions(supported []VersionNumber) []VersionNumber {
copy(greased[randPos+1:], supported[randPos:])
return greased
}
// StripGreasedVersions strips all greased versions from a slice of versions
func StripGreasedVersions(versions []VersionNumber) []VersionNumber {
realVersions := make([]VersionNumber, 0, len(versions))
for _, v := range versions {
if v&0x0f0f0f0f != 0x0a0a0a0a {
realVersions = append(realVersions, v)
}
}
return realVersions
}

View File

@@ -169,6 +169,15 @@ var _ = Describe("Version", func() {
Expect(isReservedVersion(greased[0])).To(BeTrue())
})
It("strips greased versions", func() {
v := SupportedVersions[0]
greased := GetGreasedVersions([]VersionNumber{v})
Expect(greased).To(HaveLen(2))
stripped := StripGreasedVersions(greased)
Expect(stripped).To(HaveLen(1))
Expect(stripped[0]).To(Equal(v))
})
It("creates greased lists of version numbers", func() {
supported := []VersionNumber{10, 18, 29}
for _, v := range supported {