package mint import ( "bytes" "crypto/x509" "encoding/hex" "testing" ) const ( fixedClientHelloBodyLen = 39 fixedServerHelloBodyLen = 36 maxCipherSuites = 1 << 15 maxExtensionDataLen = (1 << 16) - 1 maxCertRequestContextLen = 255 maxTicketLen = (1 << 16) - 1 ) var ( supportedVersionHex = hex.EncodeToString([]byte{ byte(supportedVersion >> 8), byte(supportedVersion & 0xff), }) tls12VersionHex = hex.EncodeToString([]byte{ byte(tls12Version >> 8), byte(tls12Version & 0xff), }) // ClientHello test cases // NB: Borrowing some values from extensions_test.go helloRandom = [32]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37} chCipherSuites = []CipherSuite{0x0001, 0x0002, 0x0003} chValidIn = ClientHelloBody{ LegacyVersion: tls12Version, Random: helloRandom, CipherSuites: chCipherSuites, Extensions: extListValidIn, LegacySessionID: []byte{}, } chValidHex = "0303" + hex.EncodeToString(helloRandom[:]) + "00" + "0006000100020003" + "0100" + extListValidHex chOverflowHex = "0303" + hex.EncodeToString(helloRandom[:]) + "00" + "0006000100020003" + "0100" + extListOverflowOuterHex // ClientHello truncation test cases chTruncPSKData = unhex(pskClientHex) chTruncHex = "01000062" + "0303" + hex.EncodeToString(helloRandom[:]) + "00" + "0006000100020003" + "0100" + "00330029002f000a00040102030405060708" chTruncValid = ClientHelloBody{ LegacyVersion: tls12Version, Random: helloRandom, CipherSuites: chCipherSuites, Extensions: []Extension{ { ExtensionType: ExtensionTypePreSharedKey, ExtensionData: chTruncPSKData, }, }, } chTruncInvalid = ClientHelloBody{} chTruncNoExt = ClientHelloBody{ LegacyVersion: tls12Version, Random: helloRandom, CipherSuites: chCipherSuites, Extensions: []Extension{}, } chTruncNoPSK = ClientHelloBody{ LegacyVersion: tls12Version, Random: helloRandom, CipherSuites: chCipherSuites, Extensions: []Extension{ {ExtensionType: ExtensionTypeEarlyData}, }, } chTruncBadPSK = ClientHelloBody{ LegacyVersion: tls12Version, Random: helloRandom, CipherSuites: chCipherSuites, Extensions: []Extension{ {ExtensionType: ExtensionTypePreSharedKey}, }, } // ServerHello test cases shValidIn = ServerHelloBody{ Version: tls12Version, Random: helloRandom, LegacySessionID: []byte{}, CipherSuite: CipherSuite(0x0001), Extensions: extListValidIn, } shEmptyIn = ServerHelloBody{ Version: tls12Version, Random: helloRandom, CipherSuite: CipherSuite(0x0001), } shValidHex = tls12VersionHex + hex.EncodeToString(helloRandom[:]) + "00" + "0001" + "00" + extListValidHex shEmptyHex = tls12VersionHex + hex.EncodeToString(helloRandom[:]) + "00" + "0001" + "00" + "0000" shOverflowHex = tls12VersionHex + hex.EncodeToString(helloRandom[:]) + "0001" + extListOverflowOuterHex // Finished test cases finValidIn = FinishedBody{ VerifyDataLen: len(helloRandom), VerifyData: helloRandom[:], } finValidHex = hex.EncodeToString(helloRandom[:]) // EncryptedExtensions test cases encExtValidIn = EncryptedExtensionsBody{extListValidIn} encExtValidHex = extListValidHex // Certificate test cases cert1Hex = "308201653082010ba003020102020500a0a0a0a0300a0608" + "2a8648ce3d0403023017311530130603550403130c657861" + "6d706c65312e636f6d3022180f3030303130313031303030" + "3030305a180f30303031303130313030303030305a301731" + "1530130603550403130c6578616d706c65312e636f6d3059" + "301306072a8648ce3d020106082a8648ce3d030107034200" + "044460e6de2a170e0c7c8d1306c82386db31980bd76647bd" + "e9b96055d075fc64ea7d8d3864afcf0ff16da73c68df6880" + "a597303243410016ef2e36f5962584d187a340303e300e06" + "03551d0f0101ff0404030203a830130603551d25040c300a" + "06082b0601050507030130170603551d110410300e820c65" + "78616d706c65312e636f6d300a06082a8648ce3d04030203" + "48003045022005937d0bf7a7cb4589715bb83dddd2505335" + "829e6305b75cfeae6f2dcc2230b6022100f6f0e75436cd59" + "b94ceedffb18bcf5bb2f161260a282f7b63d1376e5805c51" + "b6" cert2Hex = "308201643082010ba003020102020500a0a0a0a0300a0608" + "2a8648ce3d0403043017311530130603550403130c657861" + "6d706c65322e636f6d3022180f3030303130313031303030" + "3030305a180f30303031303130313030303030305a301731" + "1530130603550403130c6578616d706c65322e636f6d3059" + "301306072a8648ce3d020106082a8648ce3d030107034200" + "044460e6de2a170e0c7c8d1306c82386db31980bd76647bd" + "e9b96055d075fc64ea7d8d3864afcf0ff16da73c68df6880" + "a597303243410016ef2e36f5962584d187a340303e300e06" + "03551d0f0101ff0404030203a830130603551d25040c300a" + "06082b0601050507030130170603551d110410300e820c65" + "78616d706c65322e636f6d300a06082a8648ce3d04030403" + "470030440220718254f2b3c1cc0fa4c53bf43182f8acbc19" + "04e45ee1a3abdc8bc50a155712b4022010664cc29b80fae9" + "150027726da5b144df764a76007eee2a52b6ae0c995395fb" cert1Bytes = unhex(cert1Hex) cert2Bytes = unhex(cert2Hex) cert1, _ = x509.ParseCertificate(cert1Bytes) cert2, _ = x509.ParseCertificate(cert2Bytes) certValidIn = CertificateBody{ CertificateRequestContext: []byte{0, 0, 0, 0}, CertificateList: []CertificateEntry{ { CertData: cert1, Extensions: extListValidIn, }, { CertData: cert2, Extensions: extListValidIn, }, }, } certOverflowIn = CertificateBody{ CertificateRequestContext: []byte{0, 0, 0, 0}, CertificateList: []CertificateEntry{ { CertData: cert1, Extensions: extListSingleTooLongIn, }, }, } certValidHex = "0400000000" + "0002f5" + "000169" + cert1Hex + extListValidHex + "000168" + cert2Hex + extListValidHex certTooShortHex = "000000023081" // CertificateVerify test cases certVerifyValidIn = CertificateVerifyBody{ Algorithm: ECDSA_P256_SHA256, Signature: []byte{0, 0, 0, 0}, } certVerifyValidHex = "0403000400000000" certVerifyCipherSuite = TLS_AES_128_GCM_SHA256 // CertificateRequest test cases certReqValidIn = CertificateRequestBody{ CertificateRequestContext: []byte{0, 1, 2, 3, 4, 5, 6, 7}, Extensions: []Extension{ { ExtensionType: ExtensionTypeSignatureAlgorithms, ExtensionData: unhex("000404030503"), }, }, } certReqValidHex = "080001020304050607" + // context "000a000d0006000404030503" // extensions // NewSessionTicket test cases ticketValidHex = "00010203" + "04050607" + "0408090a0b" + "00040c0d0e0f" + "0006eeff00021122" ticketValidIn = NewSessionTicketBody{ TicketLifetime: 0x00010203, TicketAgeAdd: 0x04050607, TicketNonce: []byte{0x08, 0x09, 0x0a, 0x0b}, Ticket: []byte{0x0c, 0x0d, 0x0e, 0x0f}, Extensions: []Extension{ { ExtensionType: 0xeeff, ExtensionData: []byte{0x11, 0x22}, }, }, } ticketTooBigIn = NewSessionTicketBody{ TicketLifetime: 0x00010203, Ticket: make([]byte, maxTicketLen+1), } ticketExtensionsTooBigIn = NewSessionTicketBody{ Extensions: extListSingleTooLongIn, } // KeyUpdate test cases keyUpdateValidHex = "01" keyUpdateValidIn = KeyUpdateBody{ KeyUpdateRequest: KeyUpdateRequested, } // EndOfEarlyData test cases endOfEarlyDataValidHex = "" endOfEarlyDataValidIn = EndOfEarlyDataBody{} ) func TestHandshakeMessageTypes(t *testing.T) { assertEquals(t, ClientHelloBody{}.Type(), HandshakeTypeClientHello) assertEquals(t, ServerHelloBody{}.Type(), HandshakeTypeServerHello) assertEquals(t, FinishedBody{}.Type(), HandshakeTypeFinished) assertEquals(t, EncryptedExtensionsBody{}.Type(), HandshakeTypeEncryptedExtensions) assertEquals(t, CertificateBody{}.Type(), HandshakeTypeCertificate) assertEquals(t, CertificateVerifyBody{}.Type(), HandshakeTypeCertificateVerify) } func TestClientHelloMarshalUnmarshal(t *testing.T) { chValid := unhex(chValidHex) chOverflow := unhex(chOverflowHex) // Test correctness of handshake type assertEquals(t, (ClientHelloBody{}).Type(), HandshakeTypeClientHello) // Test successful marshal out, err := chValidIn.Marshal() assertNotError(t, err, "Failed to marshal a valid ClientHello") assertByteEquals(t, out, chValid) // Test marshal failure on empty ciphersuites chValidIn.CipherSuites = []CipherSuite{} out, err = chValidIn.Marshal() assertError(t, err, "Marshaled a ClientHello with no CipherSuites") chValidIn.CipherSuites = chCipherSuites // Test marshal failure on too many ciphersuites tooManyCipherSuites := make([]CipherSuite, maxCipherSuites+1) for i := range tooManyCipherSuites { tooManyCipherSuites[i] = CipherSuite(0x0001) } chValidIn.CipherSuites = tooManyCipherSuites out, err = chValidIn.Marshal() assertError(t, err, "Marshaled a ClientHello with too many CipherSuites") chValidIn.CipherSuites = chCipherSuites // Test marshal failure on extension list marshal failure chValidIn.Extensions = extListTooLongIn out, err = chValidIn.Marshal() assertError(t, err, "Marshaled a ClientHello with bad extensions") chValidIn.Extensions = extListValidIn // Test successful unmarshal var ch ClientHelloBody read, err := ch.Unmarshal(chValid) assertNotError(t, err, "Failed to unmarshal a valid ClientHello") assertEquals(t, read, len(chValid)) assertDeepEquals(t, ch, chValidIn) // Test unmarshal failure on too-short ClientHello _, err = ch.Unmarshal(chValid[:fixedClientHelloBodyLen-1]) assertError(t, err, "Unmarshaled a ClientHello below the min length") // Test unmarshal failure on ciphersuite size overflow chValid[35] = 0xFF _, err = ch.Unmarshal(chValid) assertError(t, err, "Unmarshaled a ClientHello an overflowing cipherSuite list") chValid[35] = 0x00 // Test unmarshal failure on odd ciphersuite size chValid[36] ^= 0x01 _, err = ch.Unmarshal(chValid) assertError(t, err, "Unmarshaled a ClientHello an odd cipherSuite list length") chValid[36] ^= 0x01 // Test unmarshal failure on missing compression methods _, err = ch.Unmarshal(chValid[:37+6]) assertError(t, err, "Unmarshaled a ClientHello truncated before the compression methods") // Test unmarshal failure on incorrect compression methods chValid[37+6] = 0x03 _, err = ch.Unmarshal(chValid) assertError(t, err, "Unmarshaled a ClientHello more than one compression method") chValid[37+6] = 0x01 chValid[37+7] = 0x01 _, err = ch.Unmarshal(chValid) assertError(t, err, "Unmarshaled a ClientHello the wrong compression method") chValid[37+7] = 0x00 // Test unmarshal failure on extension list unmarshal failure _, err = ch.Unmarshal(chOverflow) assertError(t, err, "Unmarshaled a ClientHello with invalid extensions") } func TestClientHelloTruncate(t *testing.T) { chTrunc := unhex(chTruncHex) // Test success trunc, err := chTruncValid.Truncated() assertNotError(t, err, "Error truncating valid ClientHello") assertByteEquals(t, trunc, chTrunc) // Test failure on marshal failure _, err = chTruncInvalid.Truncated() assertError(t, err, "Truncated a ClientHello that should not have marshaled") // Test failure on no extensions _, err = chTruncNoExt.Truncated() assertError(t, err, "Truncated a ClientHello with no extensions") // Test failure on last extension not PSK _, err = chTruncNoPSK.Truncated() assertError(t, err, "Truncated a ClientHello whose last extension was not a PSK") // Test failiure on last extension malformed PSK _, err = chTruncBadPSK.Truncated() assertError(t, err, "Truncated a ClientHello with a mal-formed PSK") } func TestServerHelloMarshalUnmarshal(t *testing.T) { shValid := unhex(shValidHex) shEmpty := unhex(shEmptyHex) shOverflow := unhex(shOverflowHex) // Test correctness of handshake type assertEquals(t, (ServerHelloBody{}).Type(), HandshakeTypeServerHello) // Test successful marshal out, err := shValidIn.Marshal() assertNotError(t, err, "Failed to marshal a valid ServerHello") assertByteEquals(t, out, shValid) // Test successful marshal with no extensions present out, err = shEmptyIn.Marshal() assertNotError(t, err, "Failed to marshal a valid ServerHello with no extensions") assertByteEquals(t, out, shEmpty) // Test marshal failure on extension list marshal failure shValidIn.Extensions = extListTooLongIn out, err = shValidIn.Marshal() assertError(t, err, "Marshaled a ServerHello with bad extensions") shValidIn.Extensions = extListValidIn // Test successful unmarshal var sh ServerHelloBody read, err := sh.Unmarshal(shValid) assertNotError(t, err, "Failed to unmarshal a valid ServerHello") assertEquals(t, read, len(shValid)) assertDeepEquals(t, sh, shValidIn) // Test successful unmarshal with no extensions present read, err = sh.Unmarshal(shEmpty) assertNotError(t, err, "Failed to unmarshal a valid ServerHello") assertEquals(t, read, len(shEmpty)) assertByteEquals(t, sh.Random[:], shEmptyIn.Random[:]) assertEquals(t, sh.CipherSuite, shEmptyIn.CipherSuite) assertEquals(t, len(sh.Extensions), 0) // Test unmarshal failure on too-short ServerHello _, err = sh.Unmarshal(shValid[:fixedServerHelloBodyLen-1]) assertError(t, err, "Unmarshaled a too-short ServerHello") // Test unmarshal failure on extension list unmarshal failure _, err = sh.Unmarshal(shOverflow) assertError(t, err, "Unmarshaled a ServerHello with invalid extensions") } func TestFinishedMarshalUnmarshal(t *testing.T) { finValid := unhex(finValidHex) // Test correctness of handshake type assertEquals(t, (FinishedBody{}).Type(), HandshakeTypeFinished) // Test successful marshal out, err := finValidIn.Marshal() assertNotError(t, err, "Failed to marshal a valid Finished") assertByteEquals(t, out, finValid) // Test marshal failure on incorrect data length finValidIn.VerifyDataLen-- out, err = finValidIn.Marshal() assertError(t, err, "Marshaled a Finished with the wrong data length") finValidIn.VerifyDataLen++ // Test successful unmarshal var fin FinishedBody fin.VerifyDataLen = len(finValid) read, err := fin.Unmarshal(finValid) assertNotError(t, err, "Failed to unmarshal a valid Finished") assertEquals(t, read, len(finValid)) assertDeepEquals(t, fin, finValidIn) // Test unmarshal failure on insufficient data fin.VerifyDataLen++ _, err = fin.Unmarshal(finValid) assertError(t, err, "Unmarshaled a Finished with too little data") fin.VerifyDataLen-- } // This one is a little brief because it is just an extensionList func TestEncrypteExtensionsMarshalUnmarshal(t *testing.T) { encExtValid := unhex(encExtValidHex) // Test correctness of handshake type assertEquals(t, (EncryptedExtensionsBody{}).Type(), HandshakeTypeEncryptedExtensions) // Test successful marshal out, err := encExtValidIn.Marshal() assertNotError(t, err, "Failed to marshal a valid EncryptedExtensions") assertByteEquals(t, out, encExtValid) // Test successful unmarshal var ee EncryptedExtensionsBody read, err := ee.Unmarshal(encExtValid) assertNotError(t, err, "Failed to unmarshal a valid EncryptedExtensions") assertEquals(t, read, len(encExtValid)) assertDeepEquals(t, ee, encExtValidIn) } func TestCertificateMarshalUnmarshal(t *testing.T) { // Create a couple of certificates and manually encode certValid := unhex(certValidHex) certTooShort := unhex(certTooShortHex) // Test correctness of handshake type assertEquals(t, (CertificateBody{}).Type(), HandshakeTypeCertificate) // Test successful marshal out, err := certValidIn.Marshal() assertNotError(t, err, "Failed to marshal valid Certificate") assertByteEquals(t, out, certValid) // Test marshal failure on context too long originalContext := certValidIn.CertificateRequestContext certValidIn.CertificateRequestContext = bytes.Repeat([]byte{0}, maxCertRequestContextLen+1) out, err = certValidIn.Marshal() assertError(t, err, "Marshaled a Certificate with a too-long context") certValidIn.CertificateRequestContext = originalContext // Test marshal failure on no raw certa originalRaw := cert1.Raw cert1.Raw = []byte{} out, err = certValidIn.Marshal() assertError(t, err, "Marshaled a Certificate with an empty cert") cert1.Raw = originalRaw // Test marshal failure on extension list marshal failure out, err = certOverflowIn.Marshal() assertError(t, err, "Marshaled a Certificate with an too-long extension list") // Test successful unmarshal cert := CertificateBody{} read, err := cert.Unmarshal(certValid) assertNotError(t, err, "Failed to unmarshal valid Certificate") assertEquals(t, read, len(certValid)) assertDeepEquals(t, cert, certValidIn) // Test unmarshal failure on truncated header _, err = cert.Unmarshal(certValid[:0]) assertError(t, err, "Unmarshaled a Certificate with a truncated header") // Test unmarshal failure on truncated context _, err = cert.Unmarshal(certValid[:7]) assertError(t, err, "Unmarshaled a Certificate with a truncated context") // Test unmarshal failure on truncated certificates _, err = cert.Unmarshal(certValid[:12]) assertError(t, err, "Unmarshaled a Certificate with truncated certificates") // Test unmarshal failure on a too-short certificates field _, err = cert.Unmarshal(certTooShort) assertError(t, err, "Unmarshaled a Certificate with truncated certificate length") // Test unmarshal failure on truncated certificate certValid[8] ^= 0xFF // Make length of first cert huge _, err = cert.Unmarshal(certValid) assertError(t, err, "Unmarshaled a Certificate with truncated certificates") certValid[8] ^= 0xFF // Test unmarshal failure on malformed certificate certValid[11] ^= 0xFF // Clobber first octet of first cert _, err = cert.Unmarshal(certValid) assertError(t, err, "Unmarshaled a Certificate with truncated certificates") certValid[11] ^= 0xFF } func TestCertificateVerifyMarshalUnmarshal(t *testing.T) { certVerifyValid := unhex(certVerifyValidHex) handshakeHash := []byte{0, 1, 2, 3} privRSA, err := newSigningKey(RSA_PSS_SHA256) assertNotError(t, err, "failed to generate RSA private key") // Test correctness of handshake type assertEquals(t, (CertificateVerifyBody{}).Type(), HandshakeTypeCertificateVerify) // Test successful marshal out, err := certVerifyValidIn.Marshal() assertNotError(t, err, "Failed to marshal a valid CertificateVerify") assertByteEquals(t, out, certVerifyValid) // Test successful unmarshal var cv CertificateVerifyBody read, err := cv.Unmarshal(certVerifyValid) assertNotError(t, err, "Failed to unmarshal a valid CertificateVerify") assertEquals(t, read, len(certVerifyValid)) assertDeepEquals(t, cv, certVerifyValidIn) // Test unmarshal failure on truncated header _, err = cv.Unmarshal(certVerifyValid[:1]) assertError(t, err, "Unmarshaled a CertificateVerify with no header") // Test unmarshal failure on truncated signature _, err = cv.Unmarshal(certVerifyValid[:5]) assertError(t, err, "Unmarshaled a CertificateVerify with no header") // Test successful sign / verify round-trip certVerifyValidIn.Algorithm = RSA_PSS_SHA256 err = certVerifyValidIn.Sign(privRSA, handshakeHash) assertNotError(t, err, "Failed to sign CertificateVerify") // Test sign failure on algorithm originalAlg := certVerifyValidIn.Algorithm certVerifyValidIn.Algorithm = SignatureScheme(0) err = certVerifyValidIn.Sign(privRSA, handshakeHash) assertError(t, err, "Signed CertificateVerify despite bad algorithm") certVerifyValidIn.Algorithm = originalAlg // Test successful verify certVerifyValidIn = CertificateVerifyBody{Algorithm: RSA_PSS_SHA256} err = certVerifyValidIn.Sign(privRSA, handshakeHash) assertNotError(t, err, "Failed to sign CertificateVerify") err = certVerifyValidIn.Verify(privRSA.Public(), handshakeHash) assertNotError(t, err, "Failed to verify CertificateVerify") // Test verify failure on bad algorithm originalAlg = certVerifyValidIn.Algorithm certVerifyValidIn.Algorithm = SignatureScheme(0) err = certVerifyValidIn.Verify(privRSA.Public(), handshakeHash) assertError(t, err, "Verified CertificateVerify despite bad hash algorithm") certVerifyValidIn.Algorithm = originalAlg } func TestCertificateRequestMarshalUnmarshal(t *testing.T) { certReqValid := unhex(certReqValidHex) // Test correctness of handshake type assertEquals(t, (CertificateRequestBody{}).Type(), HandshakeTypeCertificateRequest) // Test successful marshal out, err := certReqValidIn.Marshal() assertNotError(t, err, "Failed to marshal a valid CertificateRequest") assertByteEquals(t, out, certReqValid) // Test successful unmarshal var cv CertificateRequestBody read, err := cv.Unmarshal(certReqValid) assertNotError(t, err, "Failed to unmarshal a valid CertificateRequest") assertEquals(t, read, len(certReqValid)) assertDeepEquals(t, cv, certReqValidIn) } func TestNewSessionTicketMarshalUnmarshal(t *testing.T) { ticketValid := unhex(ticketValidHex) // Test correctness of handshake type assertEquals(t, (NewSessionTicketBody{}).Type(), HandshakeTypeNewSessionTicket) // Test creation of a new random ticket tkt, err := NewSessionTicket(16, 3) assertNotError(t, err, "Failed to create session ticket") assertEquals(t, tkt.TicketLifetime, uint32(3)) assertEquals(t, len(tkt.Ticket), 16) // Test successful marshal out, err := ticketValidIn.Marshal() assertNotError(t, err, "Failed to marshal a valid NewSessionTicket") assertByteEquals(t, out, ticketValid) // Test marshal failure on a ticket that's too large out, err = ticketTooBigIn.Marshal() assertError(t, err, "Marshaled a NewSessionTicket with an invalid data length") // Test marshal failure on extensions too large out, err = ticketExtensionsTooBigIn.Marshal() assertError(t, err, "Marshaled a NewSessionTicket with extensions that are too big") // Test successful unmarshal read, err := tkt.Unmarshal(ticketValid) assertNotError(t, err, "Failed to unmarshal a valid NewSessionTicket") assertEquals(t, read, len(ticketValid)) assertDeepEquals(t, *tkt, ticketValidIn) // Test unmarshal failure on insufficient data _, err = tkt.Unmarshal(ticketValid[:4]) assertError(t, err, "Unmarshaled a NewSessionTicket with an incomplete header") _, err = tkt.Unmarshal(ticketValid[:13]) assertError(t, err, "Unmarshaled a NewSessionTicket with an incomplete ticket") _, err = tkt.Unmarshal(ticketValid[:20]) assertError(t, err, "Unmarshaled a NewSessionTicket with incomplete extensions") } func TestKeyUpdateMarshalUnmarshal(t *testing.T) { keyUpdateValid := unhex(keyUpdateValidHex) // Test correctness of handshake type assertEquals(t, (KeyUpdateBody{}).Type(), HandshakeTypeKeyUpdate) // Test successful marshal out, err := keyUpdateValidIn.Marshal() assertNotError(t, err, "Failed to marshal a valid KeyUpdate") assertByteEquals(t, out, keyUpdateValid) // Test successful unmarshal var ku KeyUpdateBody read, err := ku.Unmarshal(keyUpdateValid) assertNotError(t, err, "Failed to unmarshal a valid KeyUpdate") assertEquals(t, read, len(keyUpdateValid)) assertDeepEquals(t, ku, keyUpdateValidIn) } func TestEndOfEarlyDataMarshalUnmarshal(t *testing.T) { endOfEarlyDataValid := unhex(endOfEarlyDataValidHex) // Test correctness of handshake type assertEquals(t, (EndOfEarlyDataBody{}).Type(), HandshakeTypeEndOfEarlyData) // Test successful marshal out, err := endOfEarlyDataValidIn.Marshal() assertNotError(t, err, "Failed to marshal a valid KeyUpdate") assertByteEquals(t, out, endOfEarlyDataValid) // Test successful unmarshal var eoed EndOfEarlyDataBody read, err := eoed.Unmarshal(endOfEarlyDataValid) assertNotError(t, err, "Failed to unmarshal a valid KeyUpdate") assertEquals(t, read, len(endOfEarlyDataValid)) assertDeepEquals(t, eoed, endOfEarlyDataValidIn) } func TestsafeUnmarshal(t *testing.T) { chValid := unhex(chValidHex) tooLong := append(chValid, 0) var ch ClientHelloBody // Check that safeUnmarshal works normally err := safeUnmarshal(&ch, chValid) assertNotError(t, err, "Failed to unmarshal ClientHello") // Test successful unmarshal read, err := ch.Unmarshal(tooLong) assertNotError(t, err, "Failed to unmarshal a too long ClientHello") assertEquals(t, read, len(chValid)) assertDeepEquals(t, ch, chValidIn) // Now test that safeUnmarshal barfs err = safeUnmarshal(&ch, tooLong) assertError(t, err, "Unmarshalled something too long") }