...

Source file src/github.com/google/s2a-go/internal/record/record_test.go

Documentation: github.com/google/s2a-go/internal/record

     1  /*
     2   *
     3   * Copyright 2021 Google LLC
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     https://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   */
    18  
    19  package record
    20  
    21  import (
    22  	"bytes"
    23  	"errors"
    24  	"net"
    25  	"reflect"
    26  	"testing"
    27  
    28  	"github.com/google/go-cmp/cmp"
    29  	"google.golang.org/protobuf/testing/protocmp"
    30  
    31  	commonpb "github.com/google/s2a-go/internal/proto/common_go_proto"
    32  	"github.com/google/s2a-go/internal/record/internal/aeadcrypter/testutil"
    33  )
    34  
    35  var errFakeConnEOF = errors.New("fakeConn is out of bounds")
    36  
    37  // fakeConn is a fake implementation of the net.Conn interface used for testing.
    38  type fakeConn struct {
    39  	net.Conn
    40  	// bufCount tracks the current index of the buf.
    41  	bufCount int
    42  	buf      [][]byte
    43  	// additionalBuf is used to store records sent through the fakeConn. It is
    44  	// used in record write tests and TestConnReadKeyUpdates.
    45  	additionalBuf [][]byte
    46  	closed        bool
    47  }
    48  
    49  // Read returns part of the `in` buffer in sequential order each time it is
    50  // called.
    51  func (c *fakeConn) Read(b []byte) (n int, err error) {
    52  	if c.bufCount >= len(c.buf) {
    53  		return 0, errFakeConnEOF
    54  	}
    55  	n = copy(b, c.buf[c.bufCount])
    56  	if n < len(c.buf[c.bufCount]) {
    57  		c.buf[c.bufCount] = c.buf[c.bufCount][n:]
    58  	} else {
    59  		c.bufCount++
    60  	}
    61  	return n, nil
    62  }
    63  
    64  // Write copies the given buffer b, stores it in the `out` buffer, and returns
    65  // the number of bytes copied.
    66  func (c *fakeConn) Write(b []byte) (n int, err error) {
    67  	buf := make([]byte, len(b))
    68  	n = copy(buf, b)
    69  	c.additionalBuf = append(c.additionalBuf, buf)
    70  	return n, nil
    71  }
    72  
    73  func (c *fakeConn) Close() error {
    74  	c.closed = true
    75  	return nil
    76  }
    77  
    78  type fakeTicketSender struct {
    79  	sessionTickets [][]byte
    80  }
    81  
    82  func (f *fakeTicketSender) sendTicketsToS2A(sessionTickets [][]byte, callComplete chan bool) {
    83  	f.sessionTickets = sessionTickets
    84  	go func() {
    85  		callComplete <- true
    86  		close(callComplete)
    87  	}()
    88  }
    89  
    90  func TestNewS2ARecordConn(t *testing.T) {
    91  	for _, tc := range []struct {
    92  		desc                     string
    93  		options                  *ConnParameters
    94  		outUnusedBytesBuf        []byte
    95  		outOverheadSize          int
    96  		outHandshakerServiceAddr string
    97  		outConnectionID          uint64
    98  		outLocalIdentity         *commonpb.Identity
    99  		outErr                   bool
   100  	}{
   101  		{
   102  			desc:   "nil conn options",
   103  			outErr: true,
   104  		},
   105  		{
   106  			desc: "invalid input traffic secret size",
   107  			options: &ConnParameters{
   108  				NetConn:          &fakeConn{},
   109  				Ciphersuite:      commonpb.Ciphersuite_AES_256_GCM_SHA384,
   110  				TLSVersion:       commonpb.TLSVersion_TLS1_3,
   111  				InTrafficSecret:  testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   112  				OutTrafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   113  				HSAddr:           "test handshaker address",
   114  			},
   115  			outErr: true,
   116  		},
   117  		{
   118  			desc: "invalid output traffic secret size",
   119  			options: &ConnParameters{
   120  				NetConn:          &fakeConn{},
   121  				Ciphersuite:      commonpb.Ciphersuite_AES_256_GCM_SHA384,
   122  				TLSVersion:       commonpb.TLSVersion_TLS1_3,
   123  				InTrafficSecret:  testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   124  				OutTrafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   125  				HSAddr:           "test handshaker address",
   126  			},
   127  			outErr: true,
   128  		},
   129  		{
   130  			desc: "invalid tls version",
   131  			options: &ConnParameters{
   132  				NetConn:          &fakeConn{},
   133  				Ciphersuite:      commonpb.Ciphersuite_AES_128_GCM_SHA256,
   134  				TLSVersion:       commonpb.TLSVersion_TLS1_2,
   135  				InTrafficSecret:  testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   136  				OutTrafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   137  				HSAddr:           "test handshaker address",
   138  			},
   139  			outErr: true,
   140  		},
   141  		{
   142  			desc: "basic with AES-128-GCM-SHA256",
   143  			options: &ConnParameters{
   144  				NetConn:          &fakeConn{},
   145  				Ciphersuite:      commonpb.Ciphersuite_AES_128_GCM_SHA256,
   146  				TLSVersion:       commonpb.TLSVersion_TLS1_3,
   147  				InTrafficSecret:  testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   148  				OutTrafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   149  				HSAddr:           "test handshaker address",
   150  				ConnectionID:     1,
   151  				LocalIdentity: &commonpb.Identity{
   152  					IdentityOneof: &commonpb.Identity_SpiffeId{
   153  						SpiffeId: "test_spiffe_id",
   154  					},
   155  				},
   156  			},
   157  			// outOverheadSize = header size (5) + record type byte (1) +
   158  			// tag size (16).
   159  			outOverheadSize:          22,
   160  			outHandshakerServiceAddr: "test handshaker address",
   161  			outConnectionID:          1,
   162  			outLocalIdentity: &commonpb.Identity{
   163  				IdentityOneof: &commonpb.Identity_SpiffeId{
   164  					SpiffeId: "test_spiffe_id",
   165  				},
   166  			},
   167  		},
   168  		{
   169  			desc: "basic with AES-256-GCM-SHA384",
   170  			options: &ConnParameters{
   171  				NetConn:          &fakeConn{},
   172  				Ciphersuite:      commonpb.Ciphersuite_AES_256_GCM_SHA384,
   173  				TLSVersion:       commonpb.TLSVersion_TLS1_3,
   174  				InTrafficSecret:  testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   175  				OutTrafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   176  				HSAddr:           "test handshaker address",
   177  				ConnectionID:     1,
   178  				LocalIdentity: &commonpb.Identity{
   179  					IdentityOneof: &commonpb.Identity_SpiffeId{
   180  						SpiffeId: "test_spiffe_id",
   181  					},
   182  				},
   183  			},
   184  			// outOverheadSize = header size (5) + record type byte (1) +
   185  			// tag size (16).
   186  			outOverheadSize:          22,
   187  			outHandshakerServiceAddr: "test handshaker address",
   188  			outConnectionID:          1,
   189  			outLocalIdentity: &commonpb.Identity{
   190  				IdentityOneof: &commonpb.Identity_SpiffeId{
   191  					SpiffeId: "test_spiffe_id",
   192  				},
   193  			},
   194  		},
   195  		{
   196  			desc: "basic with CHACHA20-POLY1305-SHA256",
   197  			options: &ConnParameters{
   198  				NetConn:          &fakeConn{},
   199  				Ciphersuite:      commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
   200  				TLSVersion:       commonpb.TLSVersion_TLS1_3,
   201  				InTrafficSecret:  testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   202  				OutTrafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   203  				HSAddr:           "test handshaker address",
   204  				ConnectionID:     1,
   205  				LocalIdentity: &commonpb.Identity{
   206  					IdentityOneof: &commonpb.Identity_SpiffeId{
   207  						SpiffeId: "test_spiffe_id",
   208  					},
   209  				},
   210  			},
   211  			// outOverheadSize = header size (5) + record type byte (1) +
   212  			// tag size (16).
   213  			outOverheadSize:          22,
   214  			outHandshakerServiceAddr: "test handshaker address",
   215  			outConnectionID:          1,
   216  			outLocalIdentity: &commonpb.Identity{
   217  				IdentityOneof: &commonpb.Identity_SpiffeId{
   218  					SpiffeId: "test_spiffe_id",
   219  				},
   220  			},
   221  		},
   222  		{
   223  			desc: "basic with unusedBytes",
   224  			options: &ConnParameters{
   225  				NetConn:          &fakeConn{},
   226  				Ciphersuite:      commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
   227  				TLSVersion:       commonpb.TLSVersion_TLS1_3,
   228  				InTrafficSecret:  testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   229  				OutTrafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   230  				UnusedBuf:        testutil.Dehex("ffffffff"),
   231  				HSAddr:           "test handshaker address",
   232  			},
   233  			outUnusedBytesBuf: testutil.Dehex("ffffffff"),
   234  			// outOverheadSize = header size (5) + record type byte (1) +
   235  			// tag size (16).
   236  			outOverheadSize:          22,
   237  			outHandshakerServiceAddr: "test handshaker address",
   238  		},
   239  	} {
   240  		t.Run(tc.desc, func(t *testing.T) {
   241  			NetConn, err := NewConn(tc.options)
   242  			if got, want := err == nil, !tc.outErr; got != want {
   243  				t.Errorf("NewConn(%v) = (err=nil) = %v, want %v", *tc.options, got, want)
   244  			}
   245  			if err != nil {
   246  				return
   247  			}
   248  			conn := NetConn.(*conn)
   249  			if got, want := conn.unusedBuf, tc.outUnusedBytesBuf; !bytes.Equal(got, want) {
   250  				t.Errorf("conn.unusedBytes = %v, want %v", got, want)
   251  			}
   252  			if got, want := conn.overheadSize, tc.outOverheadSize; got != want {
   253  				t.Errorf("conn.overheadSize = %v, want %v", got, want)
   254  			}
   255  			ticketSender := conn.ticketSender.(*ticketSender)
   256  			if got, want := ticketSender.hsAddr, tc.outHandshakerServiceAddr; got != want {
   257  				t.Errorf("ticketSender.hsAddr = %v, want %v", got, want)
   258  			}
   259  			if got, want := ticketSender.connectionID, tc.outConnectionID; got != want {
   260  				t.Errorf("ticketSender.connectionID = %v, want %v", got, want)
   261  			}
   262  			if got, want := ticketSender.localIdentity, tc.outLocalIdentity; !cmp.Equal(got, want, protocmp.Transform()) {
   263  				t.Errorf("ticketSender.localIdentity = %v, want %v", got, want)
   264  			}
   265  		})
   266  	}
   267  }
   268  
   269  func TestStripPaddingAndType(t *testing.T) {
   270  	for _, tc := range []struct {
   271  		desc                                              string
   272  		pendingApplicationData, outPendingApplicationData []byte
   273  		outContentType                                    recordType
   274  	}{
   275  		{
   276  			desc:                   "no padding",
   277  			pendingApplicationData: []byte{byte(alert)},
   278  			outContentType:         alert,
   279  		},
   280  		{
   281  			desc:                   "single padding",
   282  			pendingApplicationData: []byte{byte(applicationData), 0x00},
   283  			outContentType:         applicationData,
   284  		},
   285  		{
   286  			desc:                   "multi padding",
   287  			pendingApplicationData: []byte{byte(handshake), 0x00, 0x00},
   288  			outContentType:         handshake,
   289  		},
   290  		{
   291  			desc:                      "app data with no padding",
   292  			pendingApplicationData:    []byte{0xff, byte(handshake)},
   293  			outPendingApplicationData: []byte{0xff},
   294  			outContentType:            handshake,
   295  		},
   296  		{
   297  			desc:                      "app data with padding",
   298  			pendingApplicationData:    []byte{0xff, byte(handshake), 0x00},
   299  			outPendingApplicationData: []byte{0xff},
   300  			outContentType:            handshake,
   301  		},
   302  	} {
   303  		t.Run(tc.desc, func(t *testing.T) {
   304  			c := conn{pendingApplicationData: tc.pendingApplicationData}
   305  			ct, err := c.stripPaddingAndType()
   306  			if err != nil {
   307  				t.Errorf("c.stripPaddingAndType() failed: %v", err)
   308  			}
   309  			if got, want := c.pendingApplicationData, tc.outPendingApplicationData; !bytes.Equal(got, want) {
   310  				t.Errorf("c.pendingApplicationData = %v, want %v", got, want)
   311  			}
   312  			if got, want := ct, tc.outContentType; got != want {
   313  				t.Errorf("ct = %v, want %v", got, want)
   314  			}
   315  		})
   316  	}
   317  }
   318  
   319  func TestParseRecord(t *testing.T) {
   320  	for _, tc := range []struct {
   321  		desc                             string
   322  		b                                []byte
   323  		maxLen                           uint16
   324  		outCompletedRecord, outRemaining []byte
   325  		outErr                           bool
   326  	}{
   327  		{
   328  			desc:         "buffer smaller than header size",
   329  			b:            make([]byte, 1),
   330  			outRemaining: make([]byte, 1),
   331  		},
   332  		{
   333  			desc:         "header payload size larger than maxLen",
   334  			b:            testutil.Dehex("000000ffff"),
   335  			maxLen:       1,
   336  			outRemaining: testutil.Dehex("000000ffff"),
   337  			outErr:       true,
   338  		},
   339  		{
   340  			desc:               "header payload size same as maxLen",
   341  			b:                  testutil.Dehex("0000000003ffffff"),
   342  			maxLen:             3,
   343  			outCompletedRecord: testutil.Dehex("0000000003ffffff"),
   344  		},
   345  		{
   346  			desc:         "incomplete record",
   347  			b:            testutil.Dehex("0000000001"),
   348  			maxLen:       10,
   349  			outRemaining: testutil.Dehex("0000000001"),
   350  		},
   351  		{
   352  			desc:               "complete record",
   353  			b:                  testutil.Dehex("0000000001ff"),
   354  			maxLen:             10,
   355  			outCompletedRecord: testutil.Dehex("0000000001ff"),
   356  		},
   357  	} {
   358  		t.Run(tc.desc, func(t *testing.T) {
   359  			completedRecord, remaining, err := parseReadBuffer(tc.b, tc.maxLen)
   360  			if got, want := err == nil, !tc.outErr; got != want {
   361  				t.Errorf("parseReadBuffer(%v, %v) = (err=nil) = %v, want %v", tc.b, tc.maxLen, got, want)
   362  			}
   363  			if err != nil {
   364  				return
   365  			}
   366  			if got, want := completedRecord, tc.outCompletedRecord; !bytes.Equal(got, want) {
   367  				t.Errorf("completedRecord = %v, want %v", got, want)
   368  			}
   369  			if got, want := remaining, tc.outRemaining; !bytes.Equal(got, want) {
   370  				t.Errorf("remaining = %v, want %v", got, want)
   371  			}
   372  		})
   373  	}
   374  }
   375  
   376  func TestReadCompletedRecord(t *testing.T) {
   377  	for _, tc := range []struct {
   378  		desc                  string
   379  		connBufs              [][]byte
   380  		nextRecord, unusedBuf []byte
   381  		outCompletedRecords   [][]byte
   382  		outErr                bool
   383  	}{
   384  		{
   385  			desc:       "invalid record header size",
   386  			nextRecord: testutil.Dehex("170303ffff"),
   387  			outErr:     true,
   388  		},
   389  		{
   390  			desc: "complete record in single read",
   391  			connBufs: [][]byte{
   392  				testutil.Dehex("1703030001ff"),
   393  			},
   394  			outCompletedRecords: [][]byte{
   395  				testutil.Dehex("1703030001ff"),
   396  			},
   397  		},
   398  		{
   399  			desc:       "complete record in single read from leftover buffer",
   400  			nextRecord: testutil.Dehex("1703030001ff"),
   401  			outCompletedRecords: [][]byte{
   402  				testutil.Dehex("1703030001ff"),
   403  			},
   404  		},
   405  		{
   406  			desc: "complete record split in header",
   407  			connBufs: [][]byte{
   408  				testutil.Dehex("170303"),
   409  				testutil.Dehex("0001ff"),
   410  			},
   411  			unusedBuf: make([]byte, tlsRecordMaxPlaintextSize),
   412  			outCompletedRecords: [][]byte{
   413  				testutil.Dehex("1703030001ff"),
   414  			},
   415  		},
   416  		{
   417  			desc: "complete record split in ciphertext",
   418  			connBufs: [][]byte{
   419  				testutil.Dehex("1703030002ff"),
   420  				testutil.Dehex("ff"),
   421  			},
   422  			unusedBuf: make([]byte, tlsRecordMaxPlaintextSize),
   423  			outCompletedRecords: [][]byte{
   424  				testutil.Dehex("1703030002ffff"),
   425  			},
   426  		},
   427  		{
   428  			desc: "two complete records split in header",
   429  			connBufs: [][]byte{
   430  				testutil.Dehex("170303"),
   431  				testutil.Dehex("0002ffff1703030001ff"),
   432  			},
   433  			unusedBuf: make([]byte, tlsRecordMaxPlaintextSize),
   434  			outCompletedRecords: [][]byte{
   435  				testutil.Dehex("1703030002ffff"),
   436  				testutil.Dehex("1703030001ff"),
   437  			},
   438  		},
   439  		{
   440  			desc: "two complete records split in second header",
   441  			connBufs: [][]byte{
   442  				testutil.Dehex("1703030002ffff1703"),
   443  				testutil.Dehex("030001ff"),
   444  			},
   445  			unusedBuf: make([]byte, tlsRecordMaxPlaintextSize),
   446  			outCompletedRecords: [][]byte{
   447  				testutil.Dehex("1703030002ffff"),
   448  				testutil.Dehex("1703030001ff"),
   449  			},
   450  		},
   451  		{
   452  			desc: "two complete records split in ciphertext",
   453  			connBufs: [][]byte{
   454  				testutil.Dehex("1703030002ff"),
   455  				testutil.Dehex("ff1703030001ff"),
   456  			},
   457  			unusedBuf: make([]byte, tlsRecordMaxPlaintextSize),
   458  			outCompletedRecords: [][]byte{
   459  				testutil.Dehex("1703030002ffff"),
   460  				testutil.Dehex("1703030001ff"),
   461  			},
   462  		},
   463  		{
   464  			desc: "two complete records split in second ciphertext",
   465  			connBufs: [][]byte{
   466  				testutil.Dehex("1703030002ffff1703030002ff"),
   467  				testutil.Dehex("ff"),
   468  			},
   469  			unusedBuf: make([]byte, tlsRecordMaxPlaintextSize),
   470  			outCompletedRecords: [][]byte{
   471  				testutil.Dehex("1703030002ffff"),
   472  				testutil.Dehex("1703030002ffff"),
   473  			},
   474  		},
   475  		{
   476  			desc: "complete record split by each byte",
   477  			connBufs: [][]byte{
   478  				{0x17}, {0x03}, {0x03}, {0x00}, {0x01}, {0xff},
   479  			},
   480  			unusedBuf: make([]byte, tlsRecordMaxPlaintextSize),
   481  			outCompletedRecords: [][]byte{
   482  				testutil.Dehex("1703030001ff"),
   483  			},
   484  		},
   485  	} {
   486  		t.Run(tc.desc, func(t *testing.T) {
   487  			fConn := &fakeConn{buf: tc.connBufs}
   488  			c := &conn{Conn: fConn, nextRecord: tc.nextRecord, unusedBuf: tc.unusedBuf}
   489  			for _, outCompletedRecord := range tc.outCompletedRecords {
   490  				completedRecord, err := c.readFullRecord()
   491  				if got, want := err == nil, !tc.outErr; got != want {
   492  					t.Errorf("c.readCompletecRecord() = (err=nil) = %v, want %v", got, want)
   493  				}
   494  				if err != nil {
   495  					return
   496  				}
   497  				if got, want := completedRecord, outCompletedRecord; !bytes.Equal(got, want) {
   498  					t.Errorf("c.readFullRecord() = %v, want %v", got, want)
   499  				}
   500  			}
   501  		})
   502  	}
   503  }
   504  
   505  func TestSplitAndValidateHeader(t *testing.T) {
   506  	for _, tc := range []struct {
   507  		desc                     string
   508  		completedRecord          []byte
   509  		outHeader, outCiphertext []byte
   510  		outErr                   bool
   511  	}{
   512  		{
   513  			desc:            "invalid header type",
   514  			completedRecord: make([]byte, tlsRecordHeaderSize),
   515  			outErr:          true,
   516  		},
   517  		{
   518  			desc:            "invalid legacy record version",
   519  			completedRecord: []byte{byte(tlsApplicationData), 0x00, 0x00, 0x00, 0x00},
   520  			outErr:          true,
   521  		},
   522  		{
   523  			desc:            "basic with no ciphertext",
   524  			completedRecord: []byte{byte(tlsApplicationData), 0x03, 0x03, 0x00, 0x00},
   525  			outHeader:       []byte{byte(tlsApplicationData), 0x03, 0x03, 0x00, 0x00},
   526  		},
   527  		{
   528  			desc:            "basic with ciphertext",
   529  			completedRecord: []byte{byte(tlsApplicationData), 0x03, 0x03, 0x00, 0x01, 0xff},
   530  			outHeader:       []byte{byte(tlsApplicationData), 0x03, 0x03, 0x00, 0x01},
   531  			outCiphertext:   []byte{0xff},
   532  		},
   533  	} {
   534  		t.Run(tc.desc, func(t *testing.T) {
   535  			header, ciphertext, err := splitAndValidateHeader(tc.completedRecord)
   536  			if got, want := err == nil, !tc.outErr; got != want {
   537  				t.Errorf("splitAndValidateHeader(%v) = (err=nil) = %v, want %v", tc.completedRecord, got, want)
   538  			}
   539  			if err != nil {
   540  				return
   541  			}
   542  			if got, want := header, tc.outHeader; !bytes.Equal(got, want) {
   543  				t.Errorf("header = %v, want %v", got, want)
   544  			}
   545  			if got, want := ciphertext, tc.outCiphertext; !bytes.Equal(got, want) {
   546  				t.Errorf("ciphertext = %v, want %v", got, want)
   547  			}
   548  		})
   549  	}
   550  }
   551  
   552  func TestConnReadApplicationData(t *testing.T) {
   553  	for _, tc := range []struct {
   554  		desc             string
   555  		ciphersuite      commonpb.Ciphersuite
   556  		trafficSecret    []byte
   557  		completedRecords [][]byte
   558  		outPlaintexts    [][]byte
   559  		outErr           bool
   560  	}{
   561  		// The traffic secrets were chosen randomly and are equivalent to the
   562  		// ones used in C++ and Java. The ciphertext was constructed using an
   563  		// existing TLS library.
   564  		{
   565  			desc:          "AES-128-GCM-SHA256 with no padding",
   566  			ciphersuite:   commonpb.Ciphersuite_AES_128_GCM_SHA256,
   567  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   568  			completedRecords: [][]byte{
   569  				testutil.Dehex("1703030017f2e4e411ac6760e4e3f074a36574c45ee4c1906103db0d"),
   570  				testutil.Dehex("170303001ad7853afd6d7ceaabab950a0b6707905d2b908894871c7c62021f"),
   571  			},
   572  			outPlaintexts: [][]byte{
   573  				[]byte("123456"),
   574  				[]byte("789123456"),
   575  			},
   576  		},
   577  		{
   578  			desc:          "AES-128-GCM-SHA256 with padding",
   579  			ciphersuite:   commonpb.Ciphersuite_AES_128_GCM_SHA256,
   580  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   581  			completedRecords: [][]byte{
   582  				testutil.Dehex("1703030021f2e4e411ac6760e84726e4886d7432e39b34f0fccfc1f4558303c68a19535c0ff5"),
   583  			},
   584  			outPlaintexts: [][]byte{
   585  				[]byte("123456"),
   586  			},
   587  		},
   588  		{
   589  			desc:          "AES-128-GCM-SHA256 empty",
   590  			ciphersuite:   commonpb.Ciphersuite_AES_128_GCM_SHA256,
   591  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   592  			completedRecords: [][]byte{
   593  				testutil.Dehex("1703030011d47cb2ec040f26cc8989330339c669dd4e"),
   594  			},
   595  			outPlaintexts: [][]byte{
   596  				[]byte(""),
   597  			},
   598  		},
   599  		{
   600  			desc:          "AES-256-GCM-SHA384 with no padding",
   601  			ciphersuite:   commonpb.Ciphersuite_AES_256_GCM_SHA384,
   602  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   603  			completedRecords: [][]byte{
   604  				testutil.Dehex("170303001724efee5af1a62170ad5a95f899d038b965386a1a7daed9"),
   605  				testutil.Dehex("170303001a832a5fd271b6442e74bc02111a8e8b52a74b14dd3eca8598b293"),
   606  			},
   607  			outPlaintexts: [][]byte{
   608  				[]byte("123456"),
   609  				[]byte("789123456"),
   610  			},
   611  		},
   612  		{
   613  			desc:          "AES-256-GCM-SHA384 with padding",
   614  			ciphersuite:   commonpb.Ciphersuite_AES_256_GCM_SHA384,
   615  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   616  			completedRecords: [][]byte{
   617  				testutil.Dehex("170303002124efee5af1a621e8a4d1f269930e7835cfdd05e2d0bec5b01a67decfa6372c2af7"),
   618  			},
   619  			outPlaintexts: [][]byte{
   620  				[]byte("123456"),
   621  			},
   622  		},
   623  		{
   624  			desc:          "AES-256-GCM-SHA384 empty",
   625  			ciphersuite:   commonpb.Ciphersuite_AES_256_GCM_SHA384,
   626  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   627  			completedRecords: [][]byte{
   628  				testutil.Dehex("170303001102a04134d38c1118f36b01d177c5d2dcf7"),
   629  			},
   630  			outPlaintexts: [][]byte{
   631  				[]byte(""),
   632  			},
   633  		},
   634  		{
   635  			desc:          "CHACHA20-POLY1305-SHA256 with no padding",
   636  			ciphersuite:   commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
   637  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   638  			completedRecords: [][]byte{
   639  				testutil.Dehex("1703030017c947ffa470304370338bb07ce468e6b8a0944a338ba402"),
   640  				testutil.Dehex("170303001a0cedeb922170c110c172262542c67916b78fa0d1c1261709cd00"),
   641  			},
   642  			outPlaintexts: [][]byte{
   643  				[]byte("123456"),
   644  				[]byte("789123456"),
   645  			},
   646  		},
   647  		{
   648  			desc:          "CHACHA20-POLY1305-SHA256 with padding",
   649  			ciphersuite:   commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
   650  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   651  			completedRecords: [][]byte{
   652  				testutil.Dehex("1703030021c947ffa4703043f063e7b6a0519fbd0956cf3a7c9730c13597eec17ec7e700f140"),
   653  			},
   654  			outPlaintexts: [][]byte{
   655  				[]byte("123456"),
   656  			},
   657  		},
   658  		{
   659  			desc:          "CHACHA20-POLY1305-SHA256 empty",
   660  			ciphersuite:   commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
   661  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   662  			completedRecords: [][]byte{
   663  				testutil.Dehex("1703030011ef8f7a428ddc84ee5968cd6306bf1d2d1b"),
   664  			},
   665  			outPlaintexts: [][]byte{
   666  				[]byte(""),
   667  			},
   668  		},
   669  		{
   670  			desc:          "AES-128-GCM-SHA256 split in first record",
   671  			ciphersuite:   commonpb.Ciphersuite_AES_128_GCM_SHA256,
   672  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   673  			completedRecords: [][]byte{
   674  				testutil.Dehex("1703030017f2e4e411ac6760"),
   675  				testutil.Dehex("e4e3f074a36574c45ee4c1906103db0d"),
   676  			},
   677  			outPlaintexts: [][]byte{
   678  				[]byte("123456"),
   679  			},
   680  		},
   681  		{
   682  			desc:          "AES-256-GCM-SHA384 split in first record",
   683  			ciphersuite:   commonpb.Ciphersuite_AES_256_GCM_SHA384,
   684  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   685  			completedRecords: [][]byte{
   686  				testutil.Dehex("170303001724efee5af1a6"),
   687  				testutil.Dehex("2170ad5a95f899d038b965386a1a7daed9"),
   688  			},
   689  			outPlaintexts: [][]byte{
   690  				[]byte("123456"),
   691  			},
   692  		},
   693  		{
   694  			desc:          "CHACHA20-POLY1305-SHA256 split in first record",
   695  			ciphersuite:   commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
   696  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   697  			completedRecords: [][]byte{
   698  				testutil.Dehex("1703030017c947ffa470"),
   699  				testutil.Dehex("304370338bb07ce468e6b8a0944a338ba402"),
   700  			},
   701  			outPlaintexts: [][]byte{
   702  				[]byte("123456"),
   703  			},
   704  		},
   705  		{
   706  			desc:          "AES-128-GCM-SHA256 split in first record header",
   707  			ciphersuite:   commonpb.Ciphersuite_AES_128_GCM_SHA256,
   708  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   709  			completedRecords: [][]byte{
   710  				testutil.Dehex("17"),
   711  				testutil.Dehex("03030017f2e4e411ac6760e4e3f074a36574c45ee4c1906103db0d"),
   712  			},
   713  			outPlaintexts: [][]byte{
   714  				[]byte("123456"),
   715  			},
   716  		},
   717  		{
   718  			desc:          "AES-256-GCM-SHA384 split in first record header",
   719  			ciphersuite:   commonpb.Ciphersuite_AES_256_GCM_SHA384,
   720  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   721  			completedRecords: [][]byte{
   722  				testutil.Dehex("17"),
   723  				testutil.Dehex("0303001724efee5af1a62170ad5a95f899d038b965386a1a7daed9"),
   724  			},
   725  			outPlaintexts: [][]byte{
   726  				[]byte("123456"),
   727  			},
   728  		},
   729  		{
   730  			desc:          "CHACHA20-POLY1305-SHA256 split in first record header",
   731  			ciphersuite:   commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
   732  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   733  			completedRecords: [][]byte{
   734  				testutil.Dehex("17"),
   735  				testutil.Dehex("03030017c947ffa470304370338bb07ce468e6b8a0944a338ba402"),
   736  			},
   737  			outPlaintexts: [][]byte{
   738  				[]byte("123456"),
   739  			},
   740  		},
   741  		{
   742  			desc:          "AES-128-GCM-SHA256 split in second record",
   743  			ciphersuite:   commonpb.Ciphersuite_AES_128_GCM_SHA256,
   744  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   745  			completedRecords: [][]byte{
   746  				testutil.Dehex("1703030017f2e4e411ac6760e4e3f074a36574c45ee4c1906103db0d170303001ad7"),
   747  				testutil.Dehex("853afd6d7ceaabab950a0b6707905d2b908894871c7c62021f"),
   748  			},
   749  			outPlaintexts: [][]byte{
   750  				[]byte("123456"),
   751  				[]byte("789123456"),
   752  			},
   753  		},
   754  		{
   755  			desc:          "AES-256-GCM-SHA384 split in second record",
   756  			ciphersuite:   commonpb.Ciphersuite_AES_256_GCM_SHA384,
   757  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   758  			completedRecords: [][]byte{
   759  				testutil.Dehex("170303001724efee5af1a62170ad5a95f899d038b965386a1a7daed9170303001a83"),
   760  				testutil.Dehex("2a5fd271b6442e74bc02111a8e8b52a74b14dd3eca8598b293"),
   761  			},
   762  			outPlaintexts: [][]byte{
   763  				[]byte("123456"),
   764  				[]byte("789123456"),
   765  			},
   766  		},
   767  		{
   768  			desc:          "CHACHA20-POLY1305-SHA256 split in second record",
   769  			ciphersuite:   commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
   770  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   771  			completedRecords: [][]byte{
   772  				testutil.Dehex("1703030017c947ffa470304370338bb07ce468e6b8a0944a338ba402170303001a0c"),
   773  				testutil.Dehex("edeb922170c110c172262542c67916b78fa0d1c1261709cd00"),
   774  			},
   775  			outPlaintexts: [][]byte{
   776  				[]byte("123456"),
   777  				[]byte("789123456"),
   778  			},
   779  		},
   780  		{
   781  			desc:          "AES-128-GCM-SHA256 split in second record header",
   782  			ciphersuite:   commonpb.Ciphersuite_AES_128_GCM_SHA256,
   783  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   784  			completedRecords: [][]byte{
   785  				testutil.Dehex("1703030017f2e4e411ac6760e4e3f074a36574c45ee4c1906103db0d17"),
   786  				testutil.Dehex("0303001ad7853afd6d7ceaabab950a0b6707905d2b908894871c7c62021f"),
   787  			},
   788  			outPlaintexts: [][]byte{
   789  				[]byte("123456"),
   790  				[]byte("789123456"),
   791  			},
   792  		},
   793  		{
   794  			desc:          "AES-256-GCM-SHA384 split in second record header",
   795  			ciphersuite:   commonpb.Ciphersuite_AES_256_GCM_SHA384,
   796  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   797  			completedRecords: [][]byte{
   798  				testutil.Dehex("170303001724efee5af1a62170ad5a95f899d038b965386a1a7daed917"),
   799  				testutil.Dehex("0303001a832a5fd271b6442e74bc02111a8e8b52a74b14dd3eca8598b293"),
   800  			},
   801  			outPlaintexts: [][]byte{
   802  				[]byte("123456"),
   803  				[]byte("789123456"),
   804  			},
   805  		},
   806  		{
   807  			desc:          "CHACHA20-POLY1305-SHA256 split in second record header",
   808  			ciphersuite:   commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
   809  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   810  			completedRecords: [][]byte{
   811  				testutil.Dehex("1703030017c947ffa470304370338bb07ce468e6b8a0944a338ba40217"),
   812  				testutil.Dehex("0303001a0cedeb922170c110c172262542c67916b78fa0d1c1261709cd00"),
   813  			},
   814  			outPlaintexts: [][]byte{
   815  				[]byte("123456"),
   816  				[]byte("789123456"),
   817  			},
   818  		},
   819  		{
   820  			desc:          "AES-128-GCM-SHA256 split randomly",
   821  			ciphersuite:   commonpb.Ciphersuite_AES_128_GCM_SHA256,
   822  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   823  			completedRecords: [][]byte{
   824  				testutil.Dehex("1703030017f2e4e411ac6760e4"),
   825  				testutil.Dehex("e3f074a36574c45ee4c1906103db0d17"),
   826  				testutil.Dehex("0303001ad7853afd6d7ceaab"),
   827  				testutil.Dehex("ab950a0b6707905d2b908894871c7c62021f"),
   828  			},
   829  			outPlaintexts: [][]byte{
   830  				[]byte("123456"),
   831  				[]byte("789123456"),
   832  			},
   833  		},
   834  		{
   835  			desc:          "AES-256-GCM-SHA384 split randomly",
   836  			ciphersuite:   commonpb.Ciphersuite_AES_256_GCM_SHA384,
   837  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   838  			completedRecords: [][]byte{
   839  				testutil.Dehex("170303001724efee"),
   840  				testutil.Dehex("5af1a62170ad5a95f899d038b965386a1a7daed917"),
   841  				testutil.Dehex("03"),
   842  				testutil.Dehex("03001a832a5fd271b6442e74bc02111a8e8b52a74b14dd3eca8598b293"),
   843  			},
   844  			outPlaintexts: [][]byte{
   845  				[]byte("123456"),
   846  				[]byte("789123456"),
   847  			},
   848  		},
   849  		{
   850  			desc:          "CHACHA20-POLY1305-SHA256 split randomly",
   851  			ciphersuite:   commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
   852  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   853  			completedRecords: [][]byte{
   854  				testutil.Dehex("17"),
   855  				testutil.Dehex("03030017c947ffa470304370338bb07ce468e6b8a0944a338ba40217"),
   856  				testutil.Dehex("0303001a0cedeb922170"),
   857  				testutil.Dehex("c110c172262542c67916b78fa0d1c1261709cd00"),
   858  			},
   859  			outPlaintexts: [][]byte{
   860  				[]byte("123456"),
   861  				[]byte("789123456"),
   862  			},
   863  		},
   864  	} {
   865  		t.Run(tc.desc, func(t *testing.T) {
   866  			c, err := NewConn(&ConnParameters{
   867  				NetConn:          &fakeConn{buf: tc.completedRecords},
   868  				Ciphersuite:      tc.ciphersuite,
   869  				TLSVersion:       commonpb.TLSVersion_TLS1_3,
   870  				InTrafficSecret:  tc.trafficSecret,
   871  				OutTrafficSecret: tc.trafficSecret,
   872  			})
   873  			if err != nil {
   874  				t.Fatalf("NewConn() failed: %v", err)
   875  			}
   876  			for _, outPlaintext := range tc.outPlaintexts {
   877  				plaintext := make([]byte, tlsRecordMaxPlaintextSize)
   878  				n, err := c.Read(plaintext)
   879  				if got, want := err == nil, !tc.outErr; got != want {
   880  					t.Errorf("c.Read(plaintext) = (err=nil) = %v, want %v", got, want)
   881  				}
   882  				if err != nil {
   883  					return
   884  				}
   885  				plaintext = plaintext[:n]
   886  				if got, want := plaintext, outPlaintext; !bytes.Equal(got, want) {
   887  					t.Errorf("c.Read(plaintext) = %v, want %v", got, want)
   888  				}
   889  			}
   890  		})
   891  	}
   892  }
   893  
   894  func TestConnReadAlert(t *testing.T) {
   895  	for _, tc := range []struct {
   896  		desc            string
   897  		ciphersuite     commonpb.Ciphersuite
   898  		trafficSecret   []byte
   899  		completedRecord []byte
   900  	}{
   901  		// The records below are TLS 1.3 records that hold the ciphertext
   902  		// obtained by encrypting (with or without padding) the close notify
   903  		// alert {0x01, 0x00} using the keys derived from the given traffic
   904  		// secrets and the sequence number zero.
   905  		{
   906  			desc:            "AES-128-GCM-SHA256 with no padding",
   907  			ciphersuite:     commonpb.Ciphersuite_AES_128_GCM_SHA256,
   908  			trafficSecret:   testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   909  			completedRecord: testutil.Dehex("1703030013c2d6c245fb80969de1dd9d14499261b67735b0"),
   910  		},
   911  		{
   912  			desc:            "AES-128-GCM-SHA256 with padding",
   913  			ciphersuite:     commonpb.Ciphersuite_AES_128_GCM_SHA256,
   914  			trafficSecret:   testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   915  			completedRecord: testutil.Dehex("170303001dc2d6c225995177e84726e4886d5ea79383e5d529cd8339fbbfcafe2418"),
   916  		},
   917  		{
   918  			desc:            "AES-256-GCM-SHA384 with no padding",
   919  			ciphersuite:     commonpb.Ciphersuite_AES_256_GCM_SHA384,
   920  			trafficSecret:   testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   921  			completedRecord: testutil.Dehex("170303001314ddc8f3b3856660bb5ac81533c157582f8b4c"),
   922  		},
   923  		{
   924  			desc:            "AES-256-GCM-SHA384 with padding",
   925  			ciphersuite:     commonpb.Ciphersuite_AES_256_GCM_SHA384,
   926  			trafficSecret:   testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   927  			completedRecord: testutil.Dehex("170303001d14ddc86ec49036e8a4d1f269933545f03b0fe9ffd8b02acd1e41f7139e"),
   928  		},
   929  		{
   930  			desc:            "CHACHA20-POLY1305-SHA256 with no padding",
   931  			ciphersuite:     commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
   932  			trafficSecret:   testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   933  			completedRecord: testutil.Dehex("1703030013f975d9cb2f116d85d4e3859f5288a9b013d778"),
   934  		},
   935  		{
   936  			desc:            "CHACHA20-POLY1305-SHA256 with padding",
   937  			ciphersuite:     commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
   938  			trafficSecret:   testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   939  			completedRecord: testutil.Dehex("170303001df975d990450654f063e7b6a0514c2714c9827e796071389802f451585a"),
   940  		},
   941  		// The records below are TLS 1.3 records that hold the ciphertext
   942  		// obtained by encrypting the alert {0x01, 0x2c} using the keys derived
   943  		// from the given traffic secrets and the sequence number zero.
   944  		{
   945  			desc:            "AES-128-GCM-SHA256 other alert",
   946  			ciphersuite:     commonpb.Ciphersuite_AES_128_GCM_SHA256,
   947  			trafficSecret:   testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   948  			completedRecord: testutil.Dehex("1703030013c2fac23f995cbe79a8d1e4c8f0353afefeaac9"),
   949  		},
   950  		{
   951  			desc:            "AES-256-GCM-SHA384 other alert",
   952  			ciphersuite:     commonpb.Ciphersuite_AES_256_GCM_SHA384,
   953  			trafficSecret:   testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   954  			completedRecord: testutil.Dehex("170303001314f1c80add85193c9598219ae9dc26f2479ccf"),
   955  		},
   956  		{
   957  			desc:            "CHACHA20-POLY1305-SHA256 other alert",
   958  			ciphersuite:     commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
   959  			trafficSecret:   testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   960  			completedRecord: testutil.Dehex("1703030013f959d96fed92bdc7e85e04e86c19eaf154b052"),
   961  		},
   962  		// The records below are TLS 1.3 records that hold the ciphertext
   963  		// obtained by encrypting the message {0x01} using the keys derived
   964  		// from the given traffic secrets and the sequence number zero. The
   965  		// first byte of this message indicates that it should be an alert
   966  		// message, but the length of the message is too small.
   967  		{
   968  			desc:            "AES-128-GCM-SHA256 invalid",
   969  			ciphersuite:     commonpb.Ciphersuite_AES_128_GCM_SHA256,
   970  			trafficSecret:   testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   971  			completedRecord: testutil.Dehex("1703030012c2c351fc48d9ac84fa165adcc9a26ffbc3c7"),
   972  		},
   973  		{
   974  			desc:            "AES-256-GCM-SHA384 invalid",
   975  			ciphersuite:     commonpb.Ciphersuite_AES_256_GCM_SHA384,
   976  			trafficSecret:   testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   977  			completedRecord: testutil.Dehex("170303001214c8476102a460b5cf9e9ba59e1726215ca9"),
   978  		},
   979  		{
   980  			desc:            "CHACHA20-POLY1305-SHA256 invalid",
   981  			ciphersuite:     commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
   982  			trafficSecret:   testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
   983  			completedRecord: testutil.Dehex("1703030012f9606a83ac17b165a51f3fe764da8560c706"),
   984  		},
   985  	} {
   986  		t.Run(tc.desc, func(t *testing.T) {
   987  			f := &fakeConn{buf: [][]byte{tc.completedRecord}}
   988  			c, err := NewConn(&ConnParameters{
   989  				NetConn:          f,
   990  				Ciphersuite:      tc.ciphersuite,
   991  				TLSVersion:       commonpb.TLSVersion_TLS1_3,
   992  				InTrafficSecret:  tc.trafficSecret,
   993  				OutTrafficSecret: tc.trafficSecret,
   994  			})
   995  			if err != nil {
   996  				t.Fatalf("NewConn() failed: %v", err)
   997  			}
   998  			plaintext := make([]byte, tlsRecordMaxPlaintextSize)
   999  			_, err = c.Read(plaintext)
  1000  			if got, want := err == nil, false; got != want {
  1001  				t.Errorf("c.Read(plaintext) = (err=nil) = %v, want %v", got, want)
  1002  			}
  1003  		})
  1004  	}
  1005  }
  1006  
  1007  func TestConnReadKeyUpdate(t *testing.T) {
  1008  	for _, tc := range []struct {
  1009  		desc             string
  1010  		ciphersuite      commonpb.Ciphersuite
  1011  		trafficSecret    []byte
  1012  		completedRecords [][]byte
  1013  		plaintexts       [][]byte
  1014  		outPlaintexts    [][]byte
  1015  		outWriteBuf      [][]byte
  1016  	}{
  1017  		{
  1018  			desc:          "AES-128-GCM-SHA256",
  1019  			ciphersuite:   commonpb.Ciphersuite_AES_128_GCM_SHA256,
  1020  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1021  			completedRecords: [][]byte{
  1022  				testutil.Dehex("1703030020dbd6d724994777e84726e4886d7432e311a73b42d0073f28ea60e30e8eb498fd"),
  1023  				testutil.Dehex("1703030017dd99ebef48292cd4c372a000740372d2ae9aad31cfd274"),
  1024  			},
  1025  			plaintexts: [][]byte{
  1026  				[]byte("123456"),
  1027  			},
  1028  			outPlaintexts: [][]byte{
  1029  				[]byte(""),
  1030  				[]byte("123456"),
  1031  			},
  1032  			outWriteBuf: [][]byte{
  1033  				testutil.Dehex("1703030017f2e4e411ac6760e4e3f074a36574c45ee4c1906103db0d"),
  1034  			},
  1035  		},
  1036  		{
  1037  			desc:          "AES-256-GCM-SHA384",
  1038  			ciphersuite:   commonpb.Ciphersuite_AES_256_GCM_SHA384,
  1039  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1040  			completedRecords: [][]byte{
  1041  				testutil.Dehex("17030300200ddddd6fc48636e8a4d1f269930e7835adc07e732ba7fd617ff9a65a51c36b6d"),
  1042  				testutil.Dehex("17030300179cd5972e76baf56af644c92235460301c0a013ad35be00"),
  1043  			},
  1044  			plaintexts: [][]byte{
  1045  				[]byte("123456"),
  1046  			},
  1047  			outPlaintexts: [][]byte{
  1048  				[]byte(""),
  1049  				[]byte("123456"),
  1050  			},
  1051  			outWriteBuf: [][]byte{
  1052  				testutil.Dehex("170303001724efee5af1a62170ad5a95f899d038b965386a1a7daed9"),
  1053  			},
  1054  		},
  1055  		{
  1056  			desc:          "CHACHA20-POLY1305-SHA256",
  1057  			ciphersuite:   commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
  1058  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1059  			completedRecords: [][]byte{
  1060  				testutil.Dehex("1703030020e075cc91451054f063e7b6a0519fbd098e83bda4b515bea5196cccc008556ad0"),
  1061  				testutil.Dehex("1703030017c4e48ccaf036bd9bc146bbc6192404f9a2d2da5d1afe78"),
  1062  			},
  1063  			plaintexts: [][]byte{
  1064  				[]byte("123456"),
  1065  			},
  1066  			outPlaintexts: [][]byte{
  1067  				[]byte(""),
  1068  				[]byte("123456"),
  1069  			},
  1070  			outWriteBuf: [][]byte{
  1071  				testutil.Dehex("1703030017c947ffa470304370338bb07ce468e6b8a0944a338ba402"),
  1072  			},
  1073  		},
  1074  		{
  1075  			desc:          "AES-128-GCM-SHA256 send key update request",
  1076  			ciphersuite:   commonpb.Ciphersuite_AES_128_GCM_SHA256,
  1077  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1078  			completedRecords: [][]byte{
  1079  				testutil.Dehex("1703030016dbd6d724984756cc7bd50502b024f94b489f1a943df5"),
  1080  				testutil.Dehex("1703030017dd99ebef48292cd4c372a000740372d2ae9aad31cfd274"),
  1081  			},
  1082  			plaintexts: [][]byte{
  1083  				[]byte("123456"),
  1084  			},
  1085  			outPlaintexts: [][]byte{
  1086  				[]byte(""),
  1087  				[]byte("123456"),
  1088  			},
  1089  			outWriteBuf: [][]byte{
  1090  				testutil.Dehex("1703030016dbd6d7249947cdda08655a3c2622891c1758fb0c0d0e"),
  1091  				testutil.Dehex("1703030017dd99ebef48292cd4c372a000740372d2ae9aad31cfd274"),
  1092  			},
  1093  		},
  1094  		{
  1095  			desc:          "AES-256-GCM-SHA384 send key update request",
  1096  			ciphersuite:   commonpb.Ciphersuite_AES_256_GCM_SHA384,
  1097  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1098  			completedRecords: [][]byte{
  1099  				testutil.Dehex("17030300160ddddd6fc5862e8275a95a35a9a43502a1da78f8a416"),
  1100  				testutil.Dehex("17030300179cd5972e76baf56af644c92235460301c0a013ad35be00"),
  1101  			},
  1102  			plaintexts: [][]byte{
  1103  				[]byte("123456"),
  1104  			},
  1105  			outPlaintexts: [][]byte{
  1106  				[]byte(""),
  1107  				[]byte("123456"),
  1108  			},
  1109  			outWriteBuf: [][]byte{
  1110  				testutil.Dehex("17030300160ddddd6fc486a82b55d4457e3dc846f77b6d3f24de45"),
  1111  				testutil.Dehex("17030300179cd5972e76baf56af644c92235460301c0a013ad35be00"),
  1112  			},
  1113  		},
  1114  		{
  1115  			desc:          "CHACHA20-POLY1305-SHA256 send key update request",
  1116  			ciphersuite:   commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
  1117  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1118  			completedRecords: [][]byte{
  1119  				testutil.Dehex("1703030016e075cc914410ffeb7e4d960f8e3b1e830c137cc69692"),
  1120  				testutil.Dehex("1703030017c4e48ccaf036bd9bc146bbc6192404f9a2d2da5d1afe78"),
  1121  			},
  1122  			plaintexts: [][]byte{
  1123  				[]byte("123456"),
  1124  			},
  1125  			outPlaintexts: [][]byte{
  1126  				[]byte(""),
  1127  				[]byte("123456"),
  1128  			},
  1129  			outWriteBuf: [][]byte{
  1130  				testutil.Dehex("1703030016e075cc914510bc0dbc87cfc12f394b235147042f42d0"),
  1131  				testutil.Dehex("1703030017c4e48ccaf036bd9bc146bbc6192404f9a2d2da5d1afe78"),
  1132  			},
  1133  		},
  1134  	} {
  1135  		t.Run(tc.desc, func(t *testing.T) {
  1136  			fConn := &fakeConn{buf: tc.completedRecords}
  1137  			c, err := NewConn(&ConnParameters{
  1138  				NetConn:          fConn,
  1139  				Ciphersuite:      tc.ciphersuite,
  1140  				TLSVersion:       commonpb.TLSVersion_TLS1_3,
  1141  				InTrafficSecret:  tc.trafficSecret,
  1142  				OutTrafficSecret: tc.trafficSecret,
  1143  			})
  1144  			if err != nil {
  1145  				t.Fatalf("NewConn() failed: %v", err)
  1146  			}
  1147  			for _, outPlaintext := range tc.outPlaintexts {
  1148  				plaintext := make([]byte, tlsRecordMaxPlaintextSize)
  1149  				n, err := c.Read(plaintext)
  1150  				if err != nil {
  1151  					t.Fatalf("c.Read(plaintext) failed: %v", err)
  1152  				}
  1153  				plaintext = plaintext[:n]
  1154  				if got, want := plaintext, outPlaintext; !bytes.Equal(got, want) {
  1155  					t.Errorf("c.Read(plaintext) = %v, want %v", got, want)
  1156  				}
  1157  			}
  1158  			// Check that the outbound traffic secret was updated properly. This
  1159  			// is done by writing plaintexts after the key update and verifying
  1160  			// the output.
  1161  			for _, plaintext := range tc.plaintexts {
  1162  				n, err := c.Write(plaintext)
  1163  				if err != nil {
  1164  					t.Fatalf("c.Write(plaintext) failed: %v", err)
  1165  				}
  1166  				if got, want := n, len(plaintext); got != want {
  1167  					t.Fatalf("c.Write(plaintext) = %v, want %v", got, want)
  1168  				}
  1169  			}
  1170  			if got, want := fConn.additionalBuf, tc.outWriteBuf; !cmp.Equal(fConn.additionalBuf, tc.outWriteBuf) {
  1171  				t.Errorf("fConn.additionalBuf = %x, want %x", got, want)
  1172  			}
  1173  			if got, want := len(c.(*conn).pendingApplicationData), 0; got != want {
  1174  				t.Errorf("len(c.(*conn).pendingApplicationData) = %v, want %v", got, want)
  1175  			}
  1176  			// If a key update message is produced on request, verify that it
  1177  			// can be decrypted properly by a new Conn object. Also, verify that
  1178  			// messages written by the original Conn object after the key update
  1179  			// can be decrypted properly by the new Conn object.
  1180  			fConn2 := &fakeConn{buf: tc.outWriteBuf}
  1181  			c2, err := NewConn(&ConnParameters{
  1182  				NetConn:          fConn2,
  1183  				Ciphersuite:      tc.ciphersuite,
  1184  				TLSVersion:       commonpb.TLSVersion_TLS1_3,
  1185  				InTrafficSecret:  tc.trafficSecret,
  1186  				OutTrafficSecret: tc.trafficSecret,
  1187  			})
  1188  			if err != nil {
  1189  				t.Fatalf("NewConn() failed: %v", err)
  1190  			}
  1191  			for range tc.outWriteBuf {
  1192  				plaintext := make([]byte, tlsRecordMaxPlaintextSize)
  1193  				_, err := c2.Read(plaintext)
  1194  				if err != nil {
  1195  					t.Fatalf("c.Read(plaintext) failed: %v", err)
  1196  				}
  1197  			}
  1198  		})
  1199  	}
  1200  }
  1201  
  1202  // buildSessionTicket builds a new session ticket with the given bytes.
  1203  func buildSessionTicket(msg []byte) []byte {
  1204  	b := make([]byte, tlsHandshakePrefixSize+len(msg))
  1205  	b[0] = tlsHandshakeNewSessionTicketType
  1206  	v := len(msg)
  1207  	b[1] = byte(v >> 16)
  1208  	b[2] = byte(v >> 8)
  1209  	b[3] = byte(v)
  1210  	copy(b[4:], msg)
  1211  	return b
  1212  }
  1213  
  1214  func TestConnNewSessionTicket(t *testing.T) {
  1215  	emptyTicket := []byte{4, 0, 0, 1, 0} // type(1) + length(3) + ticket(1)
  1216  	for _, tc := range []struct {
  1217  		desc              string
  1218  		ciphersuite       commonpb.Ciphersuite
  1219  		trafficSecret     []byte
  1220  		completedRecords  [][]byte
  1221  		outPlaintexts     [][]byte
  1222  		finalTicketState  sessionTicketState
  1223  		outSessionTickets [][]byte
  1224  		ticketsSent       bool
  1225  	}{
  1226  		// All the session tickets below are []byte{0}. This is not a valid
  1227  		// ticket, but is sufficient for testing since the client does not
  1228  		// care about the actual value of the ticket.
  1229  		{
  1230  			desc:          "AES-128-GCM-SHA256 new session ticket",
  1231  			ciphersuite:   commonpb.Ciphersuite_AES_128_GCM_SHA256,
  1232  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1233  			completedRecords: [][]byte{
  1234  				testutil.Dehex("1703030016c7d6d72499478b3d80281cae5b7c1a3e5cd553aae716"),
  1235  			},
  1236  			outPlaintexts: [][]byte{
  1237  				[]byte(""),
  1238  			},
  1239  			finalTicketState: receivingTickets,
  1240  			outSessionTickets: [][]byte{
  1241  				emptyTicket,
  1242  			},
  1243  		},
  1244  		{
  1245  			desc:          "AES-256-GCM-SHA384 new session ticket",
  1246  			ciphersuite:   commonpb.Ciphersuite_AES_256_GCM_SHA384,
  1247  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1248  			completedRecords: [][]byte{
  1249  				testutil.Dehex("170303001611dddd6fc4869be0e1c12a5a29db1aa2e5814e5894e5"),
  1250  			},
  1251  			outPlaintexts: [][]byte{
  1252  				[]byte(""),
  1253  			},
  1254  			finalTicketState: receivingTickets,
  1255  			outSessionTickets: [][]byte{
  1256  				emptyTicket,
  1257  			},
  1258  		},
  1259  		{
  1260  			desc:          "CHACHA20-POLY1305-SHA256 new session ticket",
  1261  			ciphersuite:   commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
  1262  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1263  			completedRecords: [][]byte{
  1264  				testutil.Dehex("1703030016fc75cc914510008c6B45bb46b1f030921006c3556882"),
  1265  			},
  1266  			outPlaintexts: [][]byte{
  1267  				[]byte(""),
  1268  			},
  1269  			finalTicketState: receivingTickets,
  1270  			outSessionTickets: [][]byte{
  1271  				emptyTicket,
  1272  			},
  1273  		},
  1274  		{
  1275  			desc:          "AES-128-GCM-SHA256 new session ticket followed by application data",
  1276  			ciphersuite:   commonpb.Ciphersuite_AES_128_GCM_SHA256,
  1277  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1278  			completedRecords: [][]byte{
  1279  				testutil.Dehex("1703030016c7d6d72499478b3d80281cae5b7c1a3e5cd553aae716"),
  1280  				testutil.Dehex("170303001ad7853afd6d7ceaabab950a0b6707905d2b908894871c7c62021f"),
  1281  			},
  1282  			outPlaintexts: [][]byte{
  1283  				[]byte(""),
  1284  				[]byte("789123456"),
  1285  			},
  1286  			finalTicketState: notReceivingTickets,
  1287  			outSessionTickets: [][]byte{
  1288  				emptyTicket,
  1289  			},
  1290  			ticketsSent: true,
  1291  		},
  1292  		{
  1293  			desc:          "AES-256-GCM-SHA384 new session ticket followed by application data",
  1294  			ciphersuite:   commonpb.Ciphersuite_AES_256_GCM_SHA384,
  1295  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1296  			completedRecords: [][]byte{
  1297  				testutil.Dehex("170303001611dddd6fc4869be0e1c12a5a29db1aa2e5814e5894e5"),
  1298  				testutil.Dehex("170303001a832a5fd271b6442e74bc02111a8e8b52a74b14dd3eca8598b293"),
  1299  			},
  1300  			outPlaintexts: [][]byte{
  1301  				[]byte(""),
  1302  				[]byte("789123456"),
  1303  			},
  1304  			finalTicketState: notReceivingTickets,
  1305  			outSessionTickets: [][]byte{
  1306  				emptyTicket,
  1307  			},
  1308  			ticketsSent: true,
  1309  		},
  1310  		{
  1311  			desc:          "CHACHA20-POLY1305-SHA256 new session ticket followed by application data",
  1312  			ciphersuite:   commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
  1313  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1314  			completedRecords: [][]byte{
  1315  				testutil.Dehex("1703030016fc75cc914510008c6B45bb46b1f030921006c3556882"),
  1316  				testutil.Dehex("170303001a0cedeb922170c110c172262542c67916b78fa0d1c1261709cd00"),
  1317  			},
  1318  			outPlaintexts: [][]byte{
  1319  				[]byte(""),
  1320  				[]byte("789123456"),
  1321  			},
  1322  			finalTicketState: notReceivingTickets,
  1323  			outSessionTickets: [][]byte{
  1324  				emptyTicket,
  1325  			},
  1326  			ticketsSent: true,
  1327  		},
  1328  		{
  1329  			desc:          "AES-128-GCM-SHA256 ticket, application data, then another ticket",
  1330  			ciphersuite:   commonpb.Ciphersuite_AES_128_GCM_SHA256,
  1331  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1332  			completedRecords: [][]byte{
  1333  				testutil.Dehex("1703030016c7d6d72499478b3d80281cae5b7c1a3e5cd553aae716"),
  1334  				testutil.Dehex("170303001ad7853afd6d7ceaabab950a0b6707905d2b908894871c7c62021f"),
  1335  				testutil.Dehex("17030300169c4fb23ec187cec7a8443ae3cd6f45e9dca53023e952"),
  1336  			},
  1337  			outPlaintexts: [][]byte{
  1338  				[]byte(""),
  1339  				[]byte("789123456"),
  1340  				[]byte(""),
  1341  			},
  1342  			finalTicketState: notReceivingTickets,
  1343  			outSessionTickets: [][]byte{
  1344  				emptyTicket,
  1345  			},
  1346  			ticketsSent: true,
  1347  		},
  1348  		{
  1349  			desc:          "AES-256-GCM-SHA384 ticket, application data, then another ticket",
  1350  			ciphersuite:   commonpb.Ciphersuite_AES_256_GCM_SHA384,
  1351  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1352  			completedRecords: [][]byte{
  1353  				testutil.Dehex("170303001611dddd6fc4869be0e1c12a5a29db1aa2e5814e5894e5"),
  1354  				testutil.Dehex("170303001a832a5fd271b6442e74bc02111a8e8b52a74b14dd3eca8598b293"),
  1355  				testutil.Dehex("1703030016a5f3bdfc4ab1cb73dca49bc86a7fde6396e83d9eb6ac"),
  1356  			},
  1357  			outPlaintexts: [][]byte{
  1358  				[]byte(""),
  1359  				[]byte("789123456"),
  1360  				[]byte(""),
  1361  			},
  1362  			finalTicketState: notReceivingTickets,
  1363  			outSessionTickets: [][]byte{
  1364  				emptyTicket,
  1365  			},
  1366  			ticketsSent: true,
  1367  		},
  1368  		{
  1369  			desc:          "CHACHA20-POLY1305-SHA256 ticket, application data, then another ticket",
  1370  			ciphersuite:   commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
  1371  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1372  			completedRecords: [][]byte{
  1373  				testutil.Dehex("1703030016fc75cc914510008c6B45bb46b1f030921006c3556882"),
  1374  				testutil.Dehex("170303001a0cedeb922170c110c172262542c67916b78fa0d1c1261709cd00"),
  1375  				testutil.Dehex("1703030016a1726a73d83b83e97018b7d4b9d33ec9528d7f10e8f2"),
  1376  			},
  1377  			outPlaintexts: [][]byte{
  1378  				[]byte(""),
  1379  				[]byte("789123456"),
  1380  				[]byte(""),
  1381  			},
  1382  			finalTicketState: notReceivingTickets,
  1383  			outSessionTickets: [][]byte{
  1384  				emptyTicket,
  1385  			},
  1386  			ticketsSent: true,
  1387  		},
  1388  	} {
  1389  		t.Run(tc.desc, func(t *testing.T) {
  1390  			c, err := NewConn(&ConnParameters{
  1391  				NetConn:          &fakeConn{buf: tc.completedRecords},
  1392  				Ciphersuite:      tc.ciphersuite,
  1393  				TLSVersion:       commonpb.TLSVersion_TLS1_3,
  1394  				InTrafficSecret:  tc.trafficSecret,
  1395  				OutTrafficSecret: tc.trafficSecret,
  1396  			})
  1397  			if err != nil {
  1398  				t.Fatalf("NewConn() failed: %v", err)
  1399  			}
  1400  			newConn := c.(*conn)
  1401  			// Replace the ticket sender with a fake.
  1402  			fakeTicketSender := &fakeTicketSender{}
  1403  			newConn.ticketSender = fakeTicketSender
  1404  			for _, outPlaintext := range tc.outPlaintexts {
  1405  				plaintext := make([]byte, tlsRecordMaxPlaintextSize)
  1406  				n, err := c.Read(plaintext)
  1407  				if err != nil {
  1408  					t.Fatalf("c.Read(plaintext) failed: %v", err)
  1409  				}
  1410  				plaintext = plaintext[:n]
  1411  				if got, want := plaintext, outPlaintext; !bytes.Equal(got, want) {
  1412  					t.Errorf("c.Read(plaintext) = %v, want %v", got, want)
  1413  				}
  1414  				if got, want := len(c.(*conn).pendingApplicationData), 0; got != want {
  1415  					t.Errorf("len(c.(*conn).pendingApplicationData) = %v, want %v", got, want)
  1416  				}
  1417  			}
  1418  			newConn.Close()
  1419  			if got, want := newConn.ticketState, tc.finalTicketState; got != want {
  1420  				t.Errorf("newConn.ticketState = %v, want %v", got, want)
  1421  			}
  1422  			if got, want := newConn.handshakeBuf, make([]byte, 0); !bytes.Equal(got, want) {
  1423  				t.Errorf("newConn.handshakeBuf = %v, want %v", got, want)
  1424  			}
  1425  			if got, want := newConn.sessionTickets, tc.outSessionTickets; !cmp.Equal(got, want) {
  1426  				t.Errorf("newConn.sessionTickets = %v, want %v", got, want)
  1427  			}
  1428  			if tc.ticketsSent {
  1429  				if got, want := fakeTicketSender.sessionTickets, tc.outSessionTickets; !cmp.Equal(got, want) {
  1430  					t.Errorf("fakeTicketSender.sessionTickets = %v, want %v", got, want)
  1431  				}
  1432  			}
  1433  		})
  1434  	}
  1435  }
  1436  
  1437  type handshakeMsg struct {
  1438  	msg         []byte
  1439  	isKeyUpdate bool
  1440  }
  1441  
  1442  func TestConnHandshakeWithHandshakeBuilder(t *testing.T) {
  1443  	dummyTicket := buildSessionTicket([]byte("abc"))
  1444  	dummyTicketFragment1 := buildSessionTicket(make([]byte, tlsRecordMaxPlaintextSize/2))
  1445  	dummyTicketFragment2 := buildSessionTicket(make([]byte, tlsRecordMaxPlaintextSize))
  1446  	dummyLargeTicket := buildSessionTicket(make([]byte, tlsRecordMaxPlaintextSize*2))
  1447  	dummyTicketSplitHeader1 := buildSessionTicket([]byte("abc"))[:2]
  1448  	dummyTicketSplitHeader2 := buildSessionTicket([]byte("abc"))[2:]
  1449  
  1450  	for _, tc := range []struct {
  1451  		desc              string
  1452  		ciphersuite       commonpb.Ciphersuite
  1453  		trafficSecret     []byte
  1454  		handshakeMsgs     []handshakeMsg
  1455  		finalTicketState  sessionTicketState
  1456  		outSessionTickets [][]byte
  1457  		ticketsSent       bool
  1458  		outErr            bool
  1459  	}{
  1460  		{
  1461  			desc:          "AES-128-GCM-SHA256 consecutive tickets",
  1462  			ciphersuite:   commonpb.Ciphersuite_AES_128_GCM_SHA256,
  1463  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1464  			handshakeMsgs: []handshakeMsg{
  1465  				{
  1466  					msg: dummyTicket,
  1467  				},
  1468  				{
  1469  					msg: dummyTicket,
  1470  				},
  1471  			},
  1472  			finalTicketState: receivingTickets,
  1473  			outSessionTickets: [][]byte{
  1474  				dummyTicket,
  1475  				dummyTicket,
  1476  			},
  1477  		},
  1478  		{
  1479  			desc:          "AES-256-GCM-SHA384 consecutive tickets",
  1480  			ciphersuite:   commonpb.Ciphersuite_AES_256_GCM_SHA384,
  1481  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1482  			handshakeMsgs: []handshakeMsg{
  1483  				{
  1484  					msg: dummyTicket,
  1485  				},
  1486  				{
  1487  					msg: dummyTicket,
  1488  				},
  1489  			},
  1490  			finalTicketState: receivingTickets,
  1491  			outSessionTickets: [][]byte{
  1492  				dummyTicket,
  1493  				dummyTicket,
  1494  			},
  1495  		},
  1496  		{
  1497  			desc:          "CHACHA20-POLY1305-SHA256 consecutive tickets",
  1498  			ciphersuite:   commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
  1499  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1500  			handshakeMsgs: []handshakeMsg{
  1501  				{
  1502  					msg: dummyTicket,
  1503  				},
  1504  				{
  1505  					msg: dummyTicket,
  1506  				},
  1507  			},
  1508  			finalTicketState: receivingTickets,
  1509  			outSessionTickets: [][]byte{
  1510  				dummyTicket,
  1511  				dummyTicket,
  1512  			},
  1513  		},
  1514  		{
  1515  			desc:          "AES-128-GCM-SHA256 multiple tickets in one record",
  1516  			ciphersuite:   commonpb.Ciphersuite_AES_128_GCM_SHA256,
  1517  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1518  			handshakeMsgs: []handshakeMsg{
  1519  				{
  1520  					msg: append(dummyTicket, dummyTicket...),
  1521  				},
  1522  			},
  1523  			finalTicketState: receivingTickets,
  1524  			outSessionTickets: [][]byte{
  1525  				dummyTicket,
  1526  				dummyTicket,
  1527  			},
  1528  		},
  1529  		{
  1530  			desc:          "AES-256-GCM-SHA384 multiple tickets in one record",
  1531  			ciphersuite:   commonpb.Ciphersuite_AES_256_GCM_SHA384,
  1532  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1533  			handshakeMsgs: []handshakeMsg{
  1534  				{
  1535  					msg: append(dummyTicket, dummyTicket...),
  1536  				},
  1537  			},
  1538  			finalTicketState: receivingTickets,
  1539  			outSessionTickets: [][]byte{
  1540  				dummyTicket,
  1541  				dummyTicket,
  1542  			},
  1543  		},
  1544  		{
  1545  			desc:          "CHACHA20-POLY1305-SHA256 multiple tickets in one record",
  1546  			ciphersuite:   commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
  1547  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1548  			handshakeMsgs: []handshakeMsg{
  1549  				{
  1550  					msg: append(dummyTicket, dummyTicket...),
  1551  				},
  1552  			},
  1553  			finalTicketState: receivingTickets,
  1554  			outSessionTickets: [][]byte{
  1555  				dummyTicket,
  1556  				dummyTicket,
  1557  			},
  1558  		},
  1559  		{
  1560  			desc:          "AES-128-GCM-SHA256 fragmented tickets",
  1561  			ciphersuite:   commonpb.Ciphersuite_AES_128_GCM_SHA256,
  1562  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1563  			handshakeMsgs: []handshakeMsg{
  1564  				{
  1565  					msg: append(dummyTicketFragment1, dummyTicketFragment2...),
  1566  				},
  1567  			},
  1568  			finalTicketState: receivingTickets,
  1569  			outSessionTickets: [][]byte{
  1570  				dummyTicketFragment1,
  1571  				dummyTicketFragment2,
  1572  			},
  1573  		},
  1574  		{
  1575  			desc:          "AES-256-GCM-SHA384 fragmented tickets",
  1576  			ciphersuite:   commonpb.Ciphersuite_AES_256_GCM_SHA384,
  1577  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1578  			handshakeMsgs: []handshakeMsg{
  1579  				{
  1580  					msg: append(dummyTicketFragment1, dummyTicketFragment2...),
  1581  				},
  1582  			},
  1583  			finalTicketState: receivingTickets,
  1584  			outSessionTickets: [][]byte{
  1585  				dummyTicketFragment1,
  1586  				dummyTicketFragment2,
  1587  			},
  1588  		},
  1589  		{
  1590  			desc:          "CHACHA20-POLY1305-SHA256 fragmented tickets",
  1591  			ciphersuite:   commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
  1592  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1593  			handshakeMsgs: []handshakeMsg{
  1594  				{
  1595  					msg: append(dummyTicketFragment1, dummyTicketFragment2...),
  1596  				},
  1597  			},
  1598  			finalTicketState: receivingTickets,
  1599  			outSessionTickets: [][]byte{
  1600  				dummyTicketFragment1,
  1601  				dummyTicketFragment2,
  1602  			},
  1603  		},
  1604  		{
  1605  			desc:          "AES-128-GCM-SHA256 large ticket",
  1606  			ciphersuite:   commonpb.Ciphersuite_AES_128_GCM_SHA256,
  1607  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1608  			handshakeMsgs: []handshakeMsg{
  1609  				{
  1610  					msg: dummyLargeTicket,
  1611  				},
  1612  			},
  1613  			finalTicketState: receivingTickets,
  1614  			outSessionTickets: [][]byte{
  1615  				dummyLargeTicket,
  1616  			},
  1617  		},
  1618  		{
  1619  			desc:          "AES-256-GCM-SHA384 large ticket",
  1620  			ciphersuite:   commonpb.Ciphersuite_AES_256_GCM_SHA384,
  1621  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1622  			handshakeMsgs: []handshakeMsg{
  1623  				{
  1624  					msg: dummyLargeTicket,
  1625  				},
  1626  			},
  1627  			finalTicketState: receivingTickets,
  1628  			outSessionTickets: [][]byte{
  1629  				dummyLargeTicket,
  1630  			},
  1631  		},
  1632  		{
  1633  			desc:          "CHACHA20-POLY1305-SHA256 large ticket",
  1634  			ciphersuite:   commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
  1635  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1636  			handshakeMsgs: []handshakeMsg{
  1637  				{
  1638  					msg: dummyLargeTicket,
  1639  				},
  1640  			},
  1641  			finalTicketState: receivingTickets,
  1642  			outSessionTickets: [][]byte{
  1643  				dummyLargeTicket,
  1644  			},
  1645  		},
  1646  		{
  1647  			desc:          "AES-128-GCM-SHA256 split in header",
  1648  			ciphersuite:   commonpb.Ciphersuite_AES_128_GCM_SHA256,
  1649  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1650  			handshakeMsgs: []handshakeMsg{
  1651  				{
  1652  					msg: dummyTicketSplitHeader1,
  1653  				},
  1654  				{
  1655  					msg: dummyTicketSplitHeader2,
  1656  				},
  1657  			},
  1658  			finalTicketState: receivingTickets,
  1659  			outSessionTickets: [][]byte{
  1660  				dummyTicket,
  1661  			},
  1662  		},
  1663  		{
  1664  			desc:          "AES-256-GCM-SHA384 split in header",
  1665  			ciphersuite:   commonpb.Ciphersuite_AES_256_GCM_SHA384,
  1666  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1667  			handshakeMsgs: []handshakeMsg{
  1668  				{
  1669  					msg: dummyTicketSplitHeader1,
  1670  				},
  1671  				{
  1672  					msg: dummyTicketSplitHeader2,
  1673  				},
  1674  			},
  1675  			finalTicketState: receivingTickets,
  1676  			outSessionTickets: [][]byte{
  1677  				dummyTicket,
  1678  			},
  1679  		},
  1680  		{
  1681  			desc:          "CHACHA20-POLY1305-SHA256 split in header",
  1682  			ciphersuite:   commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
  1683  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1684  			handshakeMsgs: []handshakeMsg{
  1685  				{
  1686  					msg: dummyTicketSplitHeader1,
  1687  				},
  1688  				{
  1689  					msg: dummyTicketSplitHeader2,
  1690  				},
  1691  			},
  1692  			finalTicketState: receivingTickets,
  1693  			outSessionTickets: [][]byte{
  1694  				dummyTicket,
  1695  			},
  1696  		},
  1697  		{
  1698  			desc:          "AES-128-GCM-SHA256 past max limit",
  1699  			ciphersuite:   commonpb.Ciphersuite_AES_128_GCM_SHA256,
  1700  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1701  			handshakeMsgs: []handshakeMsg{
  1702  				{
  1703  					msg: dummyTicket,
  1704  				},
  1705  				{
  1706  					msg: dummyTicket,
  1707  				},
  1708  				{
  1709  					msg: dummyTicket,
  1710  				},
  1711  				{
  1712  					msg: dummyTicket,
  1713  				},
  1714  				{
  1715  					msg: dummyTicket,
  1716  				},
  1717  				{
  1718  					msg: dummyTicket,
  1719  				},
  1720  			},
  1721  			finalTicketState: notReceivingTickets,
  1722  			outSessionTickets: [][]byte{
  1723  				dummyTicket,
  1724  				dummyTicket,
  1725  				dummyTicket,
  1726  				dummyTicket,
  1727  				dummyTicket,
  1728  			},
  1729  			ticketsSent: true,
  1730  		},
  1731  		{
  1732  			desc:          "AES-256-GCM-SHA384 past max limit",
  1733  			ciphersuite:   commonpb.Ciphersuite_AES_256_GCM_SHA384,
  1734  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1735  			handshakeMsgs: []handshakeMsg{
  1736  				{
  1737  					msg: dummyTicket,
  1738  				},
  1739  				{
  1740  					msg: dummyTicket,
  1741  				},
  1742  				{
  1743  					msg: dummyTicket,
  1744  				},
  1745  				{
  1746  					msg: dummyTicket,
  1747  				},
  1748  				{
  1749  					msg: dummyTicket,
  1750  				},
  1751  				{
  1752  					msg: dummyTicket,
  1753  				},
  1754  			},
  1755  			finalTicketState: notReceivingTickets,
  1756  			outSessionTickets: [][]byte{
  1757  				dummyTicket,
  1758  				dummyTicket,
  1759  				dummyTicket,
  1760  				dummyTicket,
  1761  				dummyTicket,
  1762  			},
  1763  			ticketsSent: true,
  1764  		},
  1765  		{
  1766  			desc:          "CHACHA20-POLY1305-SHA256 past max limit",
  1767  			ciphersuite:   commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
  1768  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1769  			handshakeMsgs: []handshakeMsg{
  1770  				{
  1771  					msg: dummyTicket,
  1772  				},
  1773  				{
  1774  					msg: dummyTicket,
  1775  				},
  1776  				{
  1777  					msg: dummyTicket,
  1778  				},
  1779  				{
  1780  					msg: dummyTicket,
  1781  				},
  1782  				{
  1783  					msg: dummyTicket,
  1784  				},
  1785  				{
  1786  					msg: dummyTicket,
  1787  				},
  1788  			},
  1789  			finalTicketState: notReceivingTickets,
  1790  			outSessionTickets: [][]byte{
  1791  				dummyTicket,
  1792  				dummyTicket,
  1793  				dummyTicket,
  1794  				dummyTicket,
  1795  				dummyTicket,
  1796  			},
  1797  			ticketsSent: true,
  1798  		},
  1799  		{
  1800  			desc:          "AES-128-GCM-SHA256 consecutive key updates",
  1801  			ciphersuite:   commonpb.Ciphersuite_AES_128_GCM_SHA256,
  1802  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1803  			handshakeMsgs: []handshakeMsg{
  1804  				{
  1805  					msg:         buildKeyUpdateRequest(),
  1806  					isKeyUpdate: true,
  1807  				},
  1808  				{
  1809  					msg:         buildKeyUpdateRequest(),
  1810  					isKeyUpdate: true,
  1811  				},
  1812  			},
  1813  		},
  1814  		{
  1815  			desc:          "AES-256-GCM-SHA384 consecutive key updates",
  1816  			ciphersuite:   commonpb.Ciphersuite_AES_256_GCM_SHA384,
  1817  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1818  			handshakeMsgs: []handshakeMsg{
  1819  				{
  1820  					msg:         buildKeyUpdateRequest(),
  1821  					isKeyUpdate: true,
  1822  				},
  1823  				{
  1824  					msg:         buildKeyUpdateRequest(),
  1825  					isKeyUpdate: true,
  1826  				},
  1827  			},
  1828  		},
  1829  		{
  1830  			desc:          "CHACHA20-POLY1305-SHA256 consecutive key updates",
  1831  			ciphersuite:   commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
  1832  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1833  			handshakeMsgs: []handshakeMsg{
  1834  				{
  1835  					msg:         buildKeyUpdateRequest(),
  1836  					isKeyUpdate: true,
  1837  				},
  1838  				{
  1839  					msg:         buildKeyUpdateRequest(),
  1840  					isKeyUpdate: true,
  1841  				},
  1842  			},
  1843  		},
  1844  		{
  1845  			desc:          "AES-128-GCM-SHA256 consecutive key updates in single record",
  1846  			ciphersuite:   commonpb.Ciphersuite_AES_128_GCM_SHA256,
  1847  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1848  			handshakeMsgs: []handshakeMsg{
  1849  				{
  1850  					msg:         append(buildKeyUpdateRequest(), buildKeyUpdateRequest()...),
  1851  					isKeyUpdate: true,
  1852  				},
  1853  			},
  1854  			outErr: true,
  1855  		},
  1856  		{
  1857  			desc:          "AES-256-GCM-SHA384 consecutive key updates in single record",
  1858  			ciphersuite:   commonpb.Ciphersuite_AES_256_GCM_SHA384,
  1859  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1860  			handshakeMsgs: []handshakeMsg{
  1861  				{
  1862  					msg:         append(buildKeyUpdateRequest(), buildKeyUpdateRequest()...),
  1863  					isKeyUpdate: true,
  1864  				},
  1865  			},
  1866  			outErr: true,
  1867  		},
  1868  		{
  1869  			desc:          "CHACHA20-POLY1305-SHA256 consecutive key updates in single record",
  1870  			ciphersuite:   commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
  1871  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1872  			handshakeMsgs: []handshakeMsg{
  1873  				{
  1874  					msg:         append(buildKeyUpdateRequest(), buildKeyUpdateRequest()...),
  1875  					isKeyUpdate: true,
  1876  				},
  1877  			},
  1878  			outErr: true,
  1879  		},
  1880  		{
  1881  			desc:          "AES-128-GCM-SHA256 fragmented key update",
  1882  			ciphersuite:   commonpb.Ciphersuite_AES_128_GCM_SHA256,
  1883  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1884  			handshakeMsgs: []handshakeMsg{
  1885  				{
  1886  					msg: buildKeyUpdateRequest()[:2],
  1887  				},
  1888  				{
  1889  					msg:         buildKeyUpdateRequest()[2:],
  1890  					isKeyUpdate: true,
  1891  				},
  1892  			},
  1893  		},
  1894  		{
  1895  			desc:          "AES-256-GCM-SHA384 fragmented key update",
  1896  			ciphersuite:   commonpb.Ciphersuite_AES_256_GCM_SHA384,
  1897  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1898  			handshakeMsgs: []handshakeMsg{
  1899  				{
  1900  					msg: buildKeyUpdateRequest()[:2],
  1901  				},
  1902  				{
  1903  					msg:         buildKeyUpdateRequest()[2:],
  1904  					isKeyUpdate: true,
  1905  				},
  1906  			},
  1907  		},
  1908  		{
  1909  			desc:          "CHACHA20-POLY1305-SHA256 fragmented key update",
  1910  			ciphersuite:   commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
  1911  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1912  			handshakeMsgs: []handshakeMsg{
  1913  				{
  1914  					msg: buildKeyUpdateRequest()[:2],
  1915  				},
  1916  				{
  1917  					msg:         buildKeyUpdateRequest()[2:],
  1918  					isKeyUpdate: true,
  1919  				},
  1920  			},
  1921  		},
  1922  		{
  1923  			desc:          "AES-128-GCM-SHA256 key update between session tickets",
  1924  			ciphersuite:   commonpb.Ciphersuite_AES_128_GCM_SHA256,
  1925  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1926  			handshakeMsgs: []handshakeMsg{
  1927  				{
  1928  					msg: dummyTicket,
  1929  				},
  1930  				{
  1931  					msg:         buildKeyUpdateRequest(),
  1932  					isKeyUpdate: true,
  1933  				},
  1934  				{
  1935  					msg: dummyTicket,
  1936  				},
  1937  			},
  1938  			finalTicketState: receivingTickets,
  1939  			outSessionTickets: [][]byte{
  1940  				dummyTicket,
  1941  				dummyTicket,
  1942  			},
  1943  		},
  1944  		{
  1945  			desc:          "AES-256-GCM-SHA384 key update between session tickets",
  1946  			ciphersuite:   commonpb.Ciphersuite_AES_256_GCM_SHA384,
  1947  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1948  			handshakeMsgs: []handshakeMsg{
  1949  				{
  1950  					msg: dummyTicket,
  1951  				},
  1952  				{
  1953  					msg:         buildKeyUpdateRequest(),
  1954  					isKeyUpdate: true,
  1955  				},
  1956  				{
  1957  					msg: dummyTicket,
  1958  				},
  1959  			},
  1960  			finalTicketState: receivingTickets,
  1961  			outSessionTickets: [][]byte{
  1962  				dummyTicket,
  1963  				dummyTicket,
  1964  			},
  1965  		},
  1966  		{
  1967  			desc:          "CHACHA20-POLY1305-SHA256 key update between session tickets",
  1968  			ciphersuite:   commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
  1969  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1970  			handshakeMsgs: []handshakeMsg{
  1971  				{
  1972  					msg: dummyTicket,
  1973  				},
  1974  				{
  1975  					msg:         buildKeyUpdateRequest(),
  1976  					isKeyUpdate: true,
  1977  				},
  1978  				{
  1979  					msg: dummyTicket,
  1980  				},
  1981  			},
  1982  			finalTicketState: receivingTickets,
  1983  			outSessionTickets: [][]byte{
  1984  				dummyTicket,
  1985  				dummyTicket,
  1986  			},
  1987  		},
  1988  		{
  1989  			desc:          "AES-128-GCM-SHA256 key update between session tickets in a single record",
  1990  			ciphersuite:   commonpb.Ciphersuite_AES_128_GCM_SHA256,
  1991  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  1992  			handshakeMsgs: []handshakeMsg{
  1993  				{
  1994  					msg: append(append(dummyTicket, buildKeyUpdateRequest()...), dummyTicket...),
  1995  				},
  1996  			},
  1997  			outErr: true,
  1998  		},
  1999  		{
  2000  			desc:          "AES-256-GCM-SHA384 key update between session tickets in a single record",
  2001  			ciphersuite:   commonpb.Ciphersuite_AES_256_GCM_SHA384,
  2002  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2003  			handshakeMsgs: []handshakeMsg{
  2004  				{
  2005  					msg: append(append(dummyTicket, buildKeyUpdateRequest()...), dummyTicket...),
  2006  				},
  2007  			},
  2008  			outErr: true,
  2009  		},
  2010  		{
  2011  			desc:          "CHACHA20-POLY1305-SHA256 key update between session tickets in a single record",
  2012  			ciphersuite:   commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
  2013  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2014  			handshakeMsgs: []handshakeMsg{
  2015  				{
  2016  					msg: append(append(dummyTicket, buildKeyUpdateRequest()...), dummyTicket...),
  2017  				},
  2018  			},
  2019  			outErr: true,
  2020  		},
  2021  	} {
  2022  		t.Run(tc.desc, func(t *testing.T) {
  2023  			fc := &fakeConn{}
  2024  			netConn, err := NewConn(&ConnParameters{
  2025  				NetConn:          fc,
  2026  				Ciphersuite:      tc.ciphersuite,
  2027  				TLSVersion:       commonpb.TLSVersion_TLS1_3,
  2028  				InTrafficSecret:  tc.trafficSecret,
  2029  				OutTrafficSecret: tc.trafficSecret,
  2030  			})
  2031  			if err != nil {
  2032  				t.Fatalf("NewConn() failed: %v", err)
  2033  			}
  2034  			c := netConn.(*conn)
  2035  			// Replace the ticket sender with a fake.
  2036  			fakeTicketSender := &fakeTicketSender{}
  2037  			c.ticketSender = fakeTicketSender
  2038  			for _, handshakeMsg := range tc.handshakeMsgs {
  2039  				_, err = c.writeTLSRecord(handshakeMsg.msg, byte(handshake))
  2040  				if err != nil {
  2041  					t.Fatalf("c.writeTLSRecord(hanshakeMsg, byte(handshake)) failed: %v", err)
  2042  				}
  2043  				if handshakeMsg.isKeyUpdate {
  2044  					if err := c.outConn.UpdateKey(); err != nil {
  2045  						t.Fatalf("c.outConn.UpdateKey() failed: %v", err)
  2046  					}
  2047  				}
  2048  			}
  2049  			fc.buf = fc.additionalBuf
  2050  			// Read until an EOF error occurs.
  2051  			for {
  2052  				plaintext := make([]byte, tlsRecordMaxPlaintextSize)
  2053  				n, err := c.Read(plaintext)
  2054  				if err != nil {
  2055  					if err == errFakeConnEOF {
  2056  						break
  2057  					}
  2058  					if !tc.outErr {
  2059  						t.Fatalf("c.Read(plaintext) failed: %v", err)
  2060  					}
  2061  					return
  2062  				}
  2063  				if got, want := n, 0; got != want {
  2064  					t.Errorf("c.Read(plaintext) = %v, want %v,", got, want)
  2065  				}
  2066  				if got, want := len(c.pendingApplicationData), 0; got != want {
  2067  					t.Errorf("len(c.(*conn).pendingApplicationData) = %v, want %v", got, want)
  2068  				}
  2069  			}
  2070  			netConn.Close()
  2071  			if got, want := c.ticketState, tc.finalTicketState; got != want {
  2072  				t.Errorf("newConn.ticketState = %v, want %v", got, want)
  2073  			}
  2074  			if got, want := c.handshakeBuf, make([]byte, 0); !bytes.Equal(got, want) {
  2075  				t.Errorf("newConn.handshakeBuf = %v, want %v", got, want)
  2076  			}
  2077  			if got, want := c.sessionTickets, tc.outSessionTickets; !cmp.Equal(got, want) {
  2078  				t.Errorf("newConn.sessionTickets = %v, want %v", got, want)
  2079  			}
  2080  			if tc.ticketsSent {
  2081  				if got, want := fakeTicketSender.sessionTickets, tc.outSessionTickets; !cmp.Equal(got, want) {
  2082  					t.Errorf("fakeTicketSender.sessionTickets = %v, want %v", got, want)
  2083  				}
  2084  			}
  2085  		})
  2086  	}
  2087  }
  2088  
  2089  func TestWrite(t *testing.T) {
  2090  	for _, tc := range []struct {
  2091  		desc            string
  2092  		ciphersuite     commonpb.Ciphersuite
  2093  		trafficSecret   []byte
  2094  		plaintexts      [][]byte
  2095  		outRecords      [][]byte
  2096  		outBytesWritten []int
  2097  		outErr          bool
  2098  	}{
  2099  		// The traffic secrets were chosen randomly and are equivalent to the
  2100  		// ones used in C++ and Java. The ciphertext was constructed using an
  2101  		// existing TLS library.
  2102  
  2103  		{
  2104  			desc:          "AES-128-GCM-SHA256",
  2105  			ciphersuite:   commonpb.Ciphersuite_AES_128_GCM_SHA256,
  2106  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2107  			plaintexts: [][]byte{
  2108  				[]byte("123456"),
  2109  				[]byte("789123456"),
  2110  			},
  2111  			outRecords: [][]byte{
  2112  				testutil.Dehex("1703030017f2e4e411ac6760e4e3f074a36574c45ee4c1906103db0d"),
  2113  				testutil.Dehex("170303001ad7853afd6d7ceaabab950a0b6707905d2b908894871c7c62021f"),
  2114  			},
  2115  			outBytesWritten: []int{6, 9},
  2116  		},
  2117  		{
  2118  			desc:          "AES-128-GCM-SHA256 empty",
  2119  			ciphersuite:   commonpb.Ciphersuite_AES_128_GCM_SHA256,
  2120  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2121  			plaintexts: [][]byte{
  2122  				[]byte(""),
  2123  			},
  2124  			outRecords: [][]byte{
  2125  				testutil.Dehex("1703030011d47cb2ec040f26cc8989330339c669dd4e"),
  2126  			},
  2127  			outBytesWritten: []int{0},
  2128  		},
  2129  		{
  2130  			desc:          "AES-256-GCM-SHA384",
  2131  			ciphersuite:   commonpb.Ciphersuite_AES_256_GCM_SHA384,
  2132  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2133  			plaintexts: [][]byte{
  2134  				[]byte("123456"),
  2135  				[]byte("789123456"),
  2136  			},
  2137  			outRecords: [][]byte{
  2138  				testutil.Dehex("170303001724efee5af1a62170ad5a95f899d038b965386a1a7daed9"),
  2139  				testutil.Dehex("170303001a832a5fd271b6442e74bc02111a8e8b52a74b14dd3eca8598b293"),
  2140  			},
  2141  			outBytesWritten: []int{6, 9},
  2142  		},
  2143  		{
  2144  			desc:          "AES-256-GCM-SHA384 empty",
  2145  			ciphersuite:   commonpb.Ciphersuite_AES_256_GCM_SHA384,
  2146  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2147  			plaintexts: [][]byte{
  2148  				[]byte(""),
  2149  			},
  2150  			outRecords: [][]byte{
  2151  				testutil.Dehex("170303001102a04134d38c1118f36b01d177c5d2dcf7"),
  2152  			},
  2153  			outBytesWritten: []int{0},
  2154  		},
  2155  		{
  2156  			desc:          "CHACHA20-POLY1305-SHA256",
  2157  			ciphersuite:   commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
  2158  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2159  			plaintexts: [][]byte{
  2160  				[]byte("123456"),
  2161  				[]byte("789123456"),
  2162  			},
  2163  			outRecords: [][]byte{
  2164  				testutil.Dehex("1703030017c947ffa470304370338bb07ce468e6b8a0944a338ba402"),
  2165  				testutil.Dehex("170303001a0cedeb922170c110c172262542c67916b78fa0d1c1261709cd00"),
  2166  			},
  2167  			outBytesWritten: []int{6, 9},
  2168  		},
  2169  		{
  2170  			desc:          "CHACHA20-POLY1305-SHA256 empty",
  2171  			ciphersuite:   commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
  2172  			trafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2173  			plaintexts: [][]byte{
  2174  				[]byte(""),
  2175  			},
  2176  			outRecords: [][]byte{
  2177  				testutil.Dehex("1703030011ef8f7a428ddc84ee5968cd6306bf1d2d1b"),
  2178  			},
  2179  			outBytesWritten: []int{0},
  2180  		},
  2181  	} {
  2182  		t.Run(tc.desc, func(t *testing.T) {
  2183  			fConn := &fakeConn{}
  2184  			newConn, err := NewConn(&ConnParameters{
  2185  				NetConn:          fConn,
  2186  				Ciphersuite:      tc.ciphersuite,
  2187  				TLSVersion:       commonpb.TLSVersion_TLS1_3,
  2188  				InTrafficSecret:  tc.trafficSecret,
  2189  				OutTrafficSecret: tc.trafficSecret,
  2190  			})
  2191  			c := newConn.(*conn)
  2192  			if err != nil {
  2193  				t.Fatalf("NewConn() failed: %v", err)
  2194  			}
  2195  			for i, plaintext := range tc.plaintexts {
  2196  				bytesWritten, err := c.writeTLSRecord(plaintext, tlsApplicationData)
  2197  				if got, want := err == nil, !tc.outErr; got != want {
  2198  					t.Errorf("c.Write(plaintext) = (err=nil) = %v, want %v", got, want)
  2199  				}
  2200  				if bytesWritten != tc.outBytesWritten[i] {
  2201  					t.Errorf("Incorrect number of bytes written: got: %v, want: %v", bytesWritten, tc.outBytesWritten[i])
  2202  				}
  2203  			}
  2204  			if !reflect.DeepEqual(fConn.additionalBuf, tc.outRecords) {
  2205  				t.Errorf("Incorrect Record: got: %v, want: %v", fConn.additionalBuf, tc.outRecords)
  2206  			}
  2207  		})
  2208  	}
  2209  }
  2210  
  2211  func TestWriteTwoRecords(t *testing.T) {
  2212  	for _, tc := range []struct {
  2213  		desc            string
  2214  		ciphersuite     commonpb.Ciphersuite
  2215  		trafficSecret   []byte
  2216  		plaintext       []byte
  2217  		numRecordBytes  int
  2218  		outBytesWritten int
  2219  		outErr          bool
  2220  	}{
  2221  		// The plaintext of size tlsRecordMaxPlaintextSize + 1 will be written
  2222  		// to the underlying connection in 2 TLS records: one containing 2^14
  2223  		// bytes of plaintext, and the other containing 1 byte of plaintext,
  2224  		// resulting in 23+tlsRecordMaxSize total record bytes written,
  2225  		// including the overheads.
  2226  		{
  2227  			desc:            "AES-128-GCM-SHA256",
  2228  			ciphersuite:     commonpb.Ciphersuite_AES_128_GCM_SHA256,
  2229  			trafficSecret:   testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2230  			plaintext:       make([]byte, 1+tlsRecordMaxPlaintextSize), // 2^14+1
  2231  			numRecordBytes:  23 + tlsRecordMaxSize,
  2232  			outBytesWritten: 1 + tlsRecordMaxPlaintextSize,
  2233  		},
  2234  		{
  2235  			desc:            "AES-256-GCM-SHA384",
  2236  			ciphersuite:     commonpb.Ciphersuite_AES_256_GCM_SHA384,
  2237  			trafficSecret:   testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2238  			plaintext:       make([]byte, 1+tlsRecordMaxPlaintextSize), // 2^14+1
  2239  			numRecordBytes:  23 + tlsRecordMaxSize,
  2240  			outBytesWritten: 1 + tlsRecordMaxPlaintextSize,
  2241  		},
  2242  		{
  2243  			desc:            "CHACHA20-POLY1305-SHA256",
  2244  			ciphersuite:     commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
  2245  			trafficSecret:   testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2246  			plaintext:       make([]byte, 1+tlsRecordMaxPlaintextSize), // 2^14+1
  2247  			numRecordBytes:  23 + tlsRecordMaxSize,
  2248  			outBytesWritten: 1 + tlsRecordMaxPlaintextSize,
  2249  		},
  2250  	} {
  2251  		t.Run(tc.desc, func(t *testing.T) {
  2252  			fConn := &fakeConn{}
  2253  			newConn, err := NewConn(&ConnParameters{
  2254  				NetConn:          fConn,
  2255  				Ciphersuite:      tc.ciphersuite,
  2256  				TLSVersion:       commonpb.TLSVersion_TLS1_3,
  2257  				InTrafficSecret:  tc.trafficSecret,
  2258  				OutTrafficSecret: tc.trafficSecret,
  2259  			})
  2260  			c := newConn.(*conn)
  2261  			if err != nil {
  2262  				t.Fatalf("NewConn() failed: %v", err)
  2263  			}
  2264  			bytesWritten, err := c.writeTLSRecord(tc.plaintext, tlsApplicationData)
  2265  			if got, want := err == nil, !tc.outErr; got != want {
  2266  				t.Errorf("c.Write(plaintext) = (err=nil) = %v, want %v", got, want)
  2267  			}
  2268  			if bytesWritten != tc.outBytesWritten {
  2269  				t.Errorf("Incorrect number of bytes written: got: %v, want: %v", bytesWritten, tc.outBytesWritten)
  2270  			}
  2271  			if len(fConn.additionalBuf[0]) != tc.numRecordBytes {
  2272  				t.Errorf("Incorrect number of bytes prepared: got: %v, want: %v", len(fConn.additionalBuf[0]), tc.numRecordBytes)
  2273  			}
  2274  		})
  2275  	}
  2276  }
  2277  
  2278  func TestExceedBufferSize(t *testing.T) {
  2279  	for _, tc := range []struct {
  2280  		desc                     string
  2281  		ciphersuite              commonpb.Ciphersuite
  2282  		trafficSecret            []byte
  2283  		plaintext                []byte
  2284  		expectedOutRecordBufSize int
  2285  		expectedNumWrites        int
  2286  		outErr                   bool
  2287  	}{
  2288  		// plaintext is set to 1+tlsRecordMaxPlaintextSize, 1 byte more than the maximum number of
  2289  		// plaintext bytes in a single record, expectedOutRecordBufSize is set
  2290  		// to 16406, as it is the maximum size of a single record.
  2291  
  2292  		{
  2293  			desc:                     "AES-128-GCM-SHA256",
  2294  			ciphersuite:              commonpb.Ciphersuite_AES_128_GCM_SHA256,
  2295  			trafficSecret:            testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2296  			plaintext:                make([]byte, 1+tlsRecordMaxPlaintextSize*outBufMaxRecords),
  2297  			expectedOutRecordBufSize: outBufMaxSize,
  2298  			expectedNumWrites:        2,
  2299  		},
  2300  		{
  2301  			desc:                     "AES-256-GCM-SHA384",
  2302  			ciphersuite:              commonpb.Ciphersuite_AES_256_GCM_SHA384,
  2303  			trafficSecret:            testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2304  			plaintext:                make([]byte, 1+tlsRecordMaxPlaintextSize*outBufMaxRecords),
  2305  			expectedOutRecordBufSize: outBufMaxSize,
  2306  			expectedNumWrites:        2,
  2307  		},
  2308  		{
  2309  			desc:                     "CHACHA20-POLY1305-SHA256",
  2310  			ciphersuite:              commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
  2311  			trafficSecret:            testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2312  			plaintext:                make([]byte, 1+tlsRecordMaxPlaintextSize*outBufMaxRecords),
  2313  			expectedOutRecordBufSize: outBufMaxSize,
  2314  			expectedNumWrites:        2,
  2315  		},
  2316  	} {
  2317  		t.Run(tc.desc, func(t *testing.T) {
  2318  			fConn := &fakeConn{}
  2319  			newConn, err := NewConn(&ConnParameters{
  2320  				NetConn:          fConn,
  2321  				Ciphersuite:      tc.ciphersuite,
  2322  				TLSVersion:       commonpb.TLSVersion_TLS1_3,
  2323  				InTrafficSecret:  tc.trafficSecret,
  2324  				OutTrafficSecret: tc.trafficSecret,
  2325  			})
  2326  			c := newConn.(*conn)
  2327  			if err != nil {
  2328  				t.Fatalf("NewConn() failed: %v", err)
  2329  			}
  2330  			bytesWritten, err := c.writeTLSRecord(tc.plaintext, tlsApplicationData)
  2331  			if got, want := err == nil, !tc.outErr; got != want {
  2332  				t.Errorf("c.Write(plaintext) = (err=nil) = %v, want %v", err, want)
  2333  			}
  2334  			if bytesWritten != len(tc.plaintext) {
  2335  				t.Errorf("Incorrect number of bytes written: got: %v, want: %v", bytesWritten, len(tc.plaintext))
  2336  			}
  2337  			if len(c.outRecordsBuf) != tc.expectedOutRecordBufSize {
  2338  				t.Errorf("Incorrect buf size: got: %v, want: %v", len(c.outRecordsBuf), tc.expectedOutRecordBufSize)
  2339  			}
  2340  			if len(fConn.additionalBuf) != tc.expectedNumWrites {
  2341  				t.Errorf("Inforrect number of records: got: %v, want: %v,", len(fConn.additionalBuf), tc.expectedNumWrites)
  2342  			}
  2343  		})
  2344  	}
  2345  }
  2346  
  2347  func TestRoundtrip(t *testing.T) {
  2348  	for _, tc := range []struct {
  2349  		desc                  string
  2350  		ciphersuite           commonpb.Ciphersuite
  2351  		inTrafficSecret       []byte
  2352  		outTrafficSecret      []byte
  2353  		plaintexts            [][]byte
  2354  		plaintextBytesWritten []int
  2355  		numRecordBytes        []int
  2356  	}{
  2357  		// numRecordBytes is calculated as
  2358  		// len(plaintext)+header(5)+tag(16)+record_type(1)
  2359  		{
  2360  			desc:             "AES-128-GCM-SHA256",
  2361  			ciphersuite:      commonpb.Ciphersuite_AES_128_GCM_SHA256,
  2362  			inTrafficSecret:  testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2363  			outTrafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2364  			plaintexts: [][]byte{
  2365  				[]byte("123456"),
  2366  				[]byte("789123456"),
  2367  			},
  2368  			plaintextBytesWritten: []int{6, 9},
  2369  			numRecordBytes:        []int{28, 31},
  2370  		},
  2371  		{
  2372  			desc:             "AES-128-GCM-SHA256 different traffic secrets",
  2373  			ciphersuite:      commonpb.Ciphersuite_AES_128_GCM_SHA256,
  2374  			inTrafficSecret:  testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2375  			outTrafficSecret: testutil.Dehex("1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b"),
  2376  			plaintexts: [][]byte{
  2377  				[]byte("123456"),
  2378  				[]byte("789123456"),
  2379  			},
  2380  			plaintextBytesWritten: []int{6, 9},
  2381  			numRecordBytes:        []int{28, 31},
  2382  		},
  2383  		{
  2384  			desc:             "AES-128-GCM-SHA256 empty",
  2385  			ciphersuite:      commonpb.Ciphersuite_AES_128_GCM_SHA256,
  2386  			inTrafficSecret:  testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2387  			outTrafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2388  			plaintexts: [][]byte{
  2389  				[]byte(""),
  2390  			},
  2391  			plaintextBytesWritten: []int{0},
  2392  			numRecordBytes:        []int{22},
  2393  		},
  2394  		{
  2395  			desc:             "AES-128-GCM-SHA256 max buffer size",
  2396  			ciphersuite:      commonpb.Ciphersuite_AES_128_GCM_SHA256,
  2397  			inTrafficSecret:  testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2398  			outTrafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2399  			plaintexts: [][]byte{
  2400  				make([]byte, tlsRecordMaxPlaintextSize*outBufMaxRecords),
  2401  			},
  2402  			plaintextBytesWritten: []int{tlsRecordMaxPlaintextSize * outBufMaxRecords},
  2403  			numRecordBytes:        []int{outBufMaxSize},
  2404  		},
  2405  		{
  2406  			desc:             "AES-128-GCM-SHA256 exceed buffer size",
  2407  			ciphersuite:      commonpb.Ciphersuite_AES_128_GCM_SHA256,
  2408  			inTrafficSecret:  testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2409  			outTrafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2410  			plaintexts: [][]byte{
  2411  				make([]byte, 1+tlsRecordMaxPlaintextSize*outBufMaxRecords),
  2412  			},
  2413  			plaintextBytesWritten: []int{1 + tlsRecordMaxPlaintextSize*outBufMaxRecords},
  2414  			numRecordBytes:        []int{outBufMaxSize, 23},
  2415  		},
  2416  		{
  2417  			desc:             "AES-256-GCM-SHA384",
  2418  			ciphersuite:      commonpb.Ciphersuite_AES_256_GCM_SHA384,
  2419  			inTrafficSecret:  testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2420  			outTrafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2421  			plaintexts: [][]byte{
  2422  				[]byte("123456"),
  2423  				[]byte("789123456"),
  2424  			},
  2425  			plaintextBytesWritten: []int{6, 9},
  2426  			numRecordBytes:        []int{28, 31},
  2427  		},
  2428  		{
  2429  			desc:             "AES-256-GCM-SHA384 different traffic secrets",
  2430  			ciphersuite:      commonpb.Ciphersuite_AES_256_GCM_SHA384,
  2431  			inTrafficSecret:  testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2432  			outTrafficSecret: testutil.Dehex("1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b"),
  2433  			plaintexts: [][]byte{
  2434  				[]byte("123456"),
  2435  				[]byte("789123456"),
  2436  			},
  2437  			plaintextBytesWritten: []int{6, 9},
  2438  			numRecordBytes:        []int{28, 31},
  2439  		},
  2440  		{
  2441  			desc:             "AES-256-GCM-SHA384 empty",
  2442  			ciphersuite:      commonpb.Ciphersuite_AES_256_GCM_SHA384,
  2443  			inTrafficSecret:  testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2444  			outTrafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2445  			plaintexts: [][]byte{
  2446  				[]byte(""),
  2447  			},
  2448  			plaintextBytesWritten: []int{0},
  2449  			numRecordBytes:        []int{22},
  2450  		},
  2451  		{
  2452  			desc:             "AES-256-GCM-SHA384 max buffer size",
  2453  			ciphersuite:      commonpb.Ciphersuite_AES_256_GCM_SHA384,
  2454  			inTrafficSecret:  testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2455  			outTrafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2456  			plaintexts: [][]byte{
  2457  				make([]byte, tlsRecordMaxPlaintextSize*outBufMaxRecords),
  2458  			},
  2459  			plaintextBytesWritten: []int{tlsRecordMaxPlaintextSize * outBufMaxRecords},
  2460  			numRecordBytes:        []int{outBufMaxSize},
  2461  		},
  2462  		{
  2463  			desc:             "AES-256-GCM-SHA384 exceed buffer size",
  2464  			ciphersuite:      commonpb.Ciphersuite_AES_256_GCM_SHA384,
  2465  			inTrafficSecret:  testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2466  			outTrafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2467  			plaintexts: [][]byte{
  2468  				make([]byte, 1+tlsRecordMaxPlaintextSize*outBufMaxRecords),
  2469  			},
  2470  			plaintextBytesWritten: []int{1 + tlsRecordMaxPlaintextSize*outBufMaxRecords},
  2471  			numRecordBytes:        []int{outBufMaxSize, 23},
  2472  		},
  2473  		{
  2474  			desc:             "CHACHA20-POLY1305-SHA256",
  2475  			ciphersuite:      commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
  2476  			inTrafficSecret:  testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2477  			outTrafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2478  			plaintexts: [][]byte{
  2479  				[]byte("123456"),
  2480  				[]byte("789123456"),
  2481  			},
  2482  			plaintextBytesWritten: []int{6, 9},
  2483  			numRecordBytes:        []int{28, 31},
  2484  		},
  2485  		{
  2486  			desc:             "CHACHA20-POLY1305-SHA256 different traffic secrets",
  2487  			ciphersuite:      commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
  2488  			inTrafficSecret:  testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2489  			outTrafficSecret: testutil.Dehex("1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b"),
  2490  			plaintexts: [][]byte{
  2491  				[]byte("123456"),
  2492  				[]byte("789123456"),
  2493  			},
  2494  			plaintextBytesWritten: []int{6, 9},
  2495  			numRecordBytes:        []int{28, 31},
  2496  		},
  2497  		{
  2498  			desc:             "CHACHA20-POLY1305-SHA256 empty",
  2499  			ciphersuite:      commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
  2500  			inTrafficSecret:  testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2501  			outTrafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2502  			plaintexts: [][]byte{
  2503  				[]byte(""),
  2504  			},
  2505  			plaintextBytesWritten: []int{0},
  2506  			numRecordBytes:        []int{22},
  2507  		},
  2508  		{
  2509  			desc:             "CHACHA20-POLY1305-SHA256 max buffer size",
  2510  			ciphersuite:      commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
  2511  			inTrafficSecret:  testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2512  			outTrafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2513  			plaintexts: [][]byte{
  2514  				make([]byte, tlsRecordMaxPlaintextSize*outBufMaxRecords),
  2515  			},
  2516  			plaintextBytesWritten: []int{tlsRecordMaxPlaintextSize * outBufMaxRecords},
  2517  			numRecordBytes:        []int{outBufMaxSize},
  2518  		},
  2519  		{
  2520  			desc:             "CHACHA20-POLY1305-SHA256 max buffer size",
  2521  			ciphersuite:      commonpb.Ciphersuite_CHACHA20_POLY1305_SHA256,
  2522  			inTrafficSecret:  testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2523  			outTrafficSecret: testutil.Dehex("6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b"),
  2524  			plaintexts: [][]byte{
  2525  				make([]byte, 1+tlsRecordMaxPlaintextSize*outBufMaxRecords),
  2526  			},
  2527  			plaintextBytesWritten: []int{1 + tlsRecordMaxPlaintextSize*outBufMaxRecords},
  2528  			numRecordBytes:        []int{outBufMaxSize, 23},
  2529  		},
  2530  	} {
  2531  		t.Run(tc.desc, func(t *testing.T) {
  2532  			fConnClient := &fakeConn{}
  2533  			client, err := NewConn(&ConnParameters{
  2534  				NetConn:          fConnClient,
  2535  				Ciphersuite:      tc.ciphersuite,
  2536  				TLSVersion:       commonpb.TLSVersion_TLS1_3,
  2537  				InTrafficSecret:  tc.inTrafficSecret,
  2538  				OutTrafficSecret: tc.outTrafficSecret,
  2539  			})
  2540  			if err != nil {
  2541  				t.Fatalf("NewConn() failed: %v", err)
  2542  			}
  2543  			fConnServer := &fakeConn{}
  2544  			server, err := NewConn(&ConnParameters{
  2545  				NetConn:          fConnServer,
  2546  				Ciphersuite:      tc.ciphersuite,
  2547  				TLSVersion:       commonpb.TLSVersion_TLS1_3,
  2548  				InTrafficSecret:  tc.outTrafficSecret,
  2549  				OutTrafficSecret: tc.inTrafficSecret,
  2550  			})
  2551  			if err != nil {
  2552  				t.Fatalf("NewConn() failed: %v", err)
  2553  			}
  2554  			err = sendRecordsRoundtrip(t, client, server, fConnClient, fConnServer, tc.plaintexts, tc.plaintextBytesWritten, tc.numRecordBytes)
  2555  			if err != nil {
  2556  				return
  2557  			}
  2558  			sendRecordsRoundtrip(t, server, client, fConnServer, fConnClient, tc.plaintexts, tc.plaintextBytesWritten, tc.numRecordBytes)
  2559  
  2560  		})
  2561  	}
  2562  }
  2563  
  2564  func sendRecordsRoundtrip(t *testing.T, src net.Conn, dst net.Conn, fConnSrc *fakeConn, fConnDst *fakeConn, plaintexts [][]byte, plaintextBytesWritten []int, recordBytes []int) error {
  2565  	for i, plaintext := range plaintexts {
  2566  		bytesWritten, err := src.Write(plaintext)
  2567  		if got, want := err == nil, true; got != want {
  2568  			t.Errorf("c.Write(plaintext) = (err=nil) = %v, want %v", err, want)
  2569  			return errors.New("Write returned unexpected output")
  2570  		}
  2571  
  2572  		if bytesWritten != plaintextBytesWritten[i] {
  2573  			t.Errorf("Incorrect number of bytes written: got: %v, want: %v", bytesWritten, plaintextBytesWritten[i])
  2574  			return errors.New("Write returned unexpected output")
  2575  		}
  2576  
  2577  		if len(fConnSrc.additionalBuf[i]) != recordBytes[i] {
  2578  			t.Errorf("Incorrect number of bytes prepared: got: %v, want: %v", len(fConnSrc.additionalBuf[i]), recordBytes[i])
  2579  			return errors.New("Write returned unexpected output")
  2580  		}
  2581  	}
  2582  	fConnDst.buf = fConnSrc.additionalBuf
  2583  	for _, outPlaintext := range plaintexts {
  2584  		n := 0
  2585  		for n < len(outPlaintext) {
  2586  			plaintext := make([]byte, tlsRecordMaxPlaintextSize)
  2587  			dn, err := dst.Read(plaintext)
  2588  			if got, want := err == nil, true; got != want {
  2589  				t.Errorf("c.Read(plaintext) = (err=nil) = %v, want %v", err, want)
  2590  				return errors.New("Read returned unexpected output")
  2591  			}
  2592  			if got, want := plaintext[:dn], outPlaintext[n:n+dn]; !bytes.Equal(got, want) {
  2593  				t.Errorf("c.Read(plaintext) = %v, want %v", len(got), len(want))
  2594  				return errors.New("Read returned unexpected output")
  2595  			}
  2596  			n += dn
  2597  		}
  2598  	}
  2599  	return nil
  2600  }
  2601  

View as plain text