688 lines
24 KiB
Go
688 lines
24 KiB
Go
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")
|
|
}
|