Add initial DTLS tests.

Change-Id: I7407261bdb2d788c879f2e67e617a615d9ff8f8b
Reviewed-on: https://boringssl-review.googlesource.com/1505
Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
David Benjamin
2014-08-14 16:55:45 +00:00
committed by Adam Langley
parent c10dde465e
commit 6fd297bb62
10 changed files with 540 additions and 123 deletions
+1
View File
@@ -5,6 +5,7 @@ add_executable(
async_bio.cc
bssl_shim.cc
packeted_bio.cc
test_config.cc
)
+26 -10
View File
@@ -22,6 +22,7 @@ namespace {
extern const BIO_METHOD async_bio_method;
struct async_bio {
bool datagram;
size_t read_quota;
size_t write_quota;
};
@@ -39,6 +40,12 @@ static int async_write(BIO *bio, const char *in, int inl) {
return 0;
}
if (a->datagram) {
// Perform writes synchronously; the DTLS implementation drops any packets
// that failed to send.
return BIO_write(bio->next_bio, in, inl);
}
BIO_clear_retry_flags(bio);
if (a->write_quota == 0) {
@@ -47,7 +54,7 @@ static int async_write(BIO *bio, const char *in, int inl) {
return -1;
}
if ((size_t)inl > a->write_quota) {
if (!a->datagram && (size_t)inl > a->write_quota) {
inl = a->write_quota;
}
int ret = BIO_write(bio->next_bio, in, inl);
@@ -73,14 +80,14 @@ static int async_read(BIO *bio, char *out, int outl) {
return -1;
}
if ((size_t)outl > a->read_quota) {
if (!a->datagram && (size_t)outl > a->read_quota) {
outl = a->read_quota;
}
int ret = BIO_read(bio->next_bio, out, outl);
if (ret <= 0) {
BIO_copy_next_retry(bio);
} else {
a->read_quota -= ret;
a->read_quota -= (a->datagram ? 1 : ret);
}
return ret;
}
@@ -144,18 +151,27 @@ BIO *async_bio_create() {
return BIO_new(&async_bio_method);
}
void async_bio_allow_read(BIO *bio, size_t bytes) {
async_bio *a = get_data(bio);
if (a == NULL) {
return;
BIO *async_bio_create_datagram() {
BIO *ret = BIO_new(&async_bio_method);
if (!ret) {
return NULL;
}
a->read_quota += bytes;
get_data(ret)->datagram = true;
return ret;
}
void async_bio_allow_write(BIO *bio, size_t bytes) {
void async_bio_allow_read(BIO *bio, size_t count) {
async_bio *a = get_data(bio);
if (a == NULL) {
return;
}
a->write_quota += bytes;
a->read_quota += count;
}
void async_bio_allow_write(BIO *bio, size_t count) {
async_bio *a = get_data(bio);
if (a == NULL) {
return;
}
a->write_quota += count;
}
+14 -9
View File
@@ -18,18 +18,23 @@
#include <openssl/bio.h>
// async_bio_create creates a filter BIO for testing asynchronous
// state machines. Reads and writes will fail and return EAGAIN unless
// explicitly allowed. Each async BIO has a read quota and a write
// quota. Initially both are zero. As each is incremented, bytes are
// allowed to flow through the BIO.
// async_bio_create creates a filter BIO for testing asynchronous state
// machines which consume a stream socket. Reads and writes will fail
// and return EAGAIN unless explicitly allowed. Each async BIO has a
// read quota and a write quota. Initially both are zero. As each is
// incremented, bytes are allowed to flow through the BIO.
BIO *async_bio_create();
// async_bio_allow_read increments |bio|'s read quota by |bytes|.
void async_bio_allow_read(BIO *bio, size_t bytes);
// async_bio_create_datagram creates a filter BIO for testing for
// asynchronous state machines which consume datagram sockets. The read
// and write quota count in packets rather than bytes.
BIO *async_bio_create_datagram();
// async_bio_allow_write increments |bio|'s write quota by |bytes|.
void async_bio_allow_write(BIO *bio, size_t bytes);
// async_bio_allow_read increments |bio|'s read quota by |count|.
void async_bio_allow_read(BIO *bio, size_t count);
// async_bio_allow_write increments |bio|'s write quota by |count|.
void async_bio_allow_write(BIO *bio, size_t count);
#endif // HEADER_ASYNC_BIO
+65 -3
View File
@@ -29,6 +29,7 @@
#include <openssl/ssl.h>
#include "async_bio.h"
#include "packeted_bio.h"
#include "test_config.h"
static int usage(const char *program) {
@@ -124,16 +125,61 @@ static int next_proto_select_callback(SSL* ssl,
return SSL_TLSEXT_ERR_OK;
}
static int cookie_generate_callback(SSL *ssl, uint8_t *cookie, unsigned *cookie_len) {
*cookie_len = 32;
memset(cookie, 42, *cookie_len);
return 1;
}
static int cookie_verify_callback(SSL *ssl, uint8_t *cookie, unsigned cookie_len) {
if (cookie_len != 32) {
fprintf(stderr, "Cookie length mismatch.\n");
return 0;
}
for (size_t i = 0; i < cookie_len; i++) {
if (cookie[i] != 42) {
fprintf(stderr, "Cookie mismatch.\n");
return 0;
}
}
return 1;
}
static SSL_CTX *setup_ctx(const TestConfig *config) {
SSL_CTX *ssl_ctx = NULL;
DH *dh = NULL;
ssl_ctx = SSL_CTX_new(
config->is_server ? SSLv23_server_method() : SSLv23_client_method());
const SSL_METHOD *method;
if (config->is_dtls) {
// TODO(davidben): Get DTLS 1.2 working and test the version negotiation
// codepath. This doesn't currently work because
// - Session resumption is broken: https://crbug.com/403378
// - DTLS hasn't been updated for EVP_AEAD.
if (config->is_server) {
method = DTLSv1_server_method();
} else {
method = DTLSv1_client_method();
}
} else {
if (config->is_server) {
method = SSLv23_server_method();
} else {
method = SSLv23_client_method();
}
}
ssl_ctx = SSL_CTX_new(method);
if (ssl_ctx == NULL) {
goto err;
}
if (config->is_dtls) {
// DTLS needs read-ahead to function on a datagram BIO.
//
// TODO(davidben): this should not be necessary. DTLS code should only
// expect a datagram BIO.
SSL_CTX_set_read_ahead(ssl_ctx, 1);
}
if (!SSL_CTX_set_ecdh_auto(ssl_ctx, 1)) {
goto err;
}
@@ -156,6 +202,9 @@ static SSL_CTX *setup_ctx(const TestConfig *config) {
SSL_CTX_set_next_proto_select_cb(
ssl_ctx, next_proto_select_callback, NULL);
SSL_CTX_set_cookie_generate_cb(ssl_ctx, cookie_generate_callback);
SSL_CTX_set_cookie_verify_cb(ssl_ctx, cookie_verify_callback);
DH_free(dh);
return ssl_ctx;
@@ -248,14 +297,23 @@ static int do_exchange(SSL_SESSION **out_session,
if (config->no_ssl3) {
SSL_set_options(ssl, SSL_OP_NO_SSLv3);
}
if (config->cookie_exchange) {
SSL_set_options(ssl, SSL_OP_COOKIE_EXCHANGE);
}
BIO *bio = BIO_new_fd(fd, 1 /* take ownership */);
if (bio == NULL) {
BIO_print_errors_fp(stdout);
return 1;
}
if (config->is_dtls) {
BIO *packeted = packeted_bio_create();
BIO_push(packeted, bio);
bio = packeted;
}
if (config->async) {
BIO *async = async_bio_create();
BIO *async =
config->is_dtls ? async_bio_create_datagram() : async_bio_create();
BIO_push(async, bio);
bio = async;
}
@@ -329,6 +387,10 @@ static int do_exchange(SSL_SESSION **out_session,
}
if (config->write_different_record_sizes) {
if (config->is_dtls) {
fprintf(stderr, "write_different_record_sizes not supported for DTLS\n");
return 6;
}
// This mode writes a number of different record sizes in an attempt to
// trip up the CBC record splitting code.
uint8_t buf[32769];
+130
View File
@@ -0,0 +1,130 @@
/* Copyright (c) 2014, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#include "packeted_bio.h"
#include <assert.h>
#include <errno.h>
#include <openssl/mem.h>
namespace {
extern const BIO_METHOD packeted_bio_method;
static int packeted_write(BIO *bio, const char *in, int inl) {
if (bio->next_bio == NULL) {
return 0;
}
BIO_clear_retry_flags(bio);
// Write the length prefix.
uint8_t len_bytes[4];
len_bytes[0] = (inl >> 24) & 0xff;
len_bytes[1] = (inl >> 16) & 0xff;
len_bytes[2] = (inl >> 8) & 0xff;
len_bytes[3] = inl & 0xff;
int ret = BIO_write(bio->next_bio, len_bytes, sizeof(len_bytes));
if (ret <= 0) {
BIO_copy_next_retry(bio);
return ret;
}
// Write the buffer. BIOs for which this operation fails are not supported.
ret = BIO_write(bio->next_bio, in, inl);
assert(ret == inl);
return ret;
}
static int packeted_read(BIO *bio, char *out, int outl) {
if (bio->next_bio == NULL) {
return 0;
}
BIO_clear_retry_flags(bio);
// Read the length prefix.
uint8_t len_bytes[4];
int ret = BIO_read(bio->next_bio, &len_bytes, sizeof(len_bytes));
if (ret <= 0) {
BIO_copy_next_retry(bio);
return ret;
}
// BIOs for which a partial length comes back are not supported.
assert(ret == 4);
uint32_t len = (len_bytes[0] << 24) | (len_bytes[1] << 16) |
(len_bytes[2] << 8) | len_bytes[3];
char *buf = (char *)OPENSSL_malloc(len);
assert(buf != NULL);
ret = BIO_read(bio->next_bio, buf, len);
assert(ret == (int)len);
if (outl > (int)len) {
outl = len;
}
memcpy(out, buf, outl);
OPENSSL_free(buf);
return outl;
}
static long packeted_ctrl(BIO *bio, int cmd, long num, void *ptr) {
if (bio->next_bio == NULL) {
return 0;
}
BIO_clear_retry_flags(bio);
int ret = BIO_ctrl(bio->next_bio, cmd, num, ptr);
BIO_copy_next_retry(bio);
return ret;
}
static int packeted_new(BIO *bio) {
bio->init = 1;
return 1;
}
static int packeted_free(BIO *bio) {
if (bio == NULL) {
return 0;
}
bio->init = 0;
return 1;
}
static long packeted_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) {
if (bio->next_bio == NULL) {
return 0;
}
return BIO_callback_ctrl(bio->next_bio, cmd, fp);
}
const BIO_METHOD packeted_bio_method = {
BIO_TYPE_FILTER,
"packeted bio",
packeted_write,
packeted_read,
NULL /* puts */,
NULL /* gets */,
packeted_ctrl,
packeted_new,
packeted_free,
packeted_callback_ctrl,
};
} // namespace
BIO *packeted_bio_create() {
return BIO_new(&packeted_bio_method);
}
+32
View File
@@ -0,0 +1,32 @@
/* Copyright (c) 2014, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#ifndef HEADER_PACKETED_BIO
#define HEADER_PACKETED_BIO
#include <openssl/bio.h>
// packeted_bio_create creates a filter BIO for testing protocols which expect
// datagram BIOs. It implements a reliable datagram socket and reads and writes
// packets by prefixing each packet with a big-endian 32-bit length. It must be
// layered over a reliable blocking stream BIO.
//
// Note: packeted_bio_create exists because a SOCK_DGRAM socketpair on OS X is
// does not block the caller, unlike on Linux. Writes simply fail with
// ENOBUFS. POSIX also does not guarantee that such sockets are reliable.
BIO *packeted_bio_create();
#endif // HEADER_PACKETED_BIO
+50
View File
@@ -0,0 +1,50 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"encoding/binary"
"errors"
"net"
)
type packetAdaptor struct {
net.Conn
}
func newPacketAdaptor(conn net.Conn) net.Conn {
return &packetAdaptor{conn}
}
func (p *packetAdaptor) Read(b []byte) (int, error) {
var length uint32
if err := binary.Read(p.Conn, binary.BigEndian, &length); err != nil {
return 0, err
}
out := make([]byte, length)
n, err := p.Conn.Read(out)
if err != nil {
return 0, err
}
if n != int(length) {
return 0, errors.New("internal error: length mismatch!")
}
return copy(b, out), nil
}
func (p *packetAdaptor) Write(b []byte) (int, error) {
length := uint32(len(b))
if err := binary.Write(p.Conn, binary.BigEndian, length); err != nil {
return 0, err
}
n, err := p.Conn.Write(b)
if err != nil {
return 0, err
}
if n != len(b) {
return 0, errors.New("internal error: length mismatch!")
}
return len(b), nil
}
+215 -100
View File
@@ -63,8 +63,16 @@ const (
serverTest
)
type protocol int
const (
tls protocol = iota
dtls
)
type testCase struct {
testType testType
protocol protocol
name string
config Config
shouldFail bool
@@ -340,18 +348,6 @@ var testCases = []testCase{
shouldFail: true,
expectedError: ":CCS_RECEIVED_EARLY:",
},
{
name: "FalseStart-SessionTicketsDisabled",
config: Config{
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
NextProtos: []string{"foo"},
SessionTicketsDisabled: true,
},
flags: []string{
"-false-start",
"-select-next-proto", "foo",
},
},
{
testType: serverTest,
name: "FallbackSCSV",
@@ -454,16 +450,30 @@ var testCases = []testCase{
}
func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int) error {
if _, err := conn.Write([]byte(test.sendPrefix)); err != nil {
return err
if test.protocol == dtls {
conn = newPacketAdaptor(conn)
}
if test.sendPrefix != "" {
if _, err := conn.Write([]byte(test.sendPrefix)); err != nil {
return err
}
}
var tlsConn *Conn
if test.testType == clientTest {
tlsConn = Server(conn, config)
if test.protocol == dtls {
tlsConn = DTLSServer(conn, config)
} else {
tlsConn = Server(conn, config)
}
} else {
config.InsecureSkipVerify = true
tlsConn = Client(conn, config)
if test.protocol == dtls {
tlsConn = DTLSClient(conn, config)
} else {
tlsConn = Client(conn, config)
}
}
if err := tlsConn.Handshake(); err != nil {
@@ -475,6 +485,9 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int) e
}
if messageLen < 0 {
if test.protocol == dtls {
return fmt.Errorf("messageLen < 0 not supported for DTLS tests")
}
// Read until EOF.
_, err := io.Copy(ioutil.Discard, tlsConn)
return err
@@ -490,9 +503,21 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int) e
tlsConn.Write(testMessage)
buf := make([]byte, len(testMessage))
_, err := io.ReadFull(tlsConn, buf)
if err != nil {
return err
if test.protocol == dtls {
bufTmp := make([]byte, len(buf)+1)
n, err := tlsConn.Read(bufTmp)
if err != nil {
return err
}
if n != len(buf) {
return fmt.Errorf("bad reply; length mismatch (%d vs %d)", n, len(buf))
}
copy(buf, bufTmp)
} else {
_, err := io.ReadFull(tlsConn, buf)
if err != nil {
return err
}
}
for i, v := range buf {
@@ -568,6 +593,10 @@ func runTest(test *testCase, buildDir string) error {
}
}
if test.protocol == dtls {
flags = append(flags, "-dtls")
}
if test.resumeSession {
flags = append(flags, "-resume")
}
@@ -746,6 +775,36 @@ func addCipherSuiteTests() {
resumeSession: resumeSession,
})
}
// TODO(davidben): Fix DTLS 1.2 support and test that.
if ver.version == VersionTLS10 && strings.Index(suite.name, "RC4") == -1 {
testCases = append(testCases, testCase{
testType: clientTest,
protocol: dtls,
name: "D" + ver.name + "-" + suite.name + "-client",
config: Config{
MinVersion: ver.version,
MaxVersion: ver.version,
CipherSuites: []uint16{suite.id},
Certificates: []Certificate{cert},
},
resumeSession: resumeSession,
})
testCases = append(testCases, testCase{
testType: serverTest,
protocol: dtls,
name: "D" + ver.name + "-" + suite.name + "-server",
config: Config{
MinVersion: ver.version,
MaxVersion: ver.version,
CipherSuites: []uint16{suite.id},
Certificates: []Certificate{cert},
},
certFile: certFile,
keyFile: keyFile,
resumeSession: resumeSession,
})
}
}
}
}
@@ -918,15 +977,18 @@ func addClientAuthTests() {
// Adds tests that try to cover the range of the handshake state machine, under
// various conditions. Some of these are redundant with other tests, but they
// only cover the synchronous case.
func addStateMachineCoverageTests(async bool, splitHandshake bool) {
func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) {
var suffix string
var flags []string
var maxHandshakeRecordLength int
if protocol == dtls {
suffix = "-DTLS"
}
if async {
suffix = "-Async"
suffix += "-Async"
flags = append(flags, "-async")
} else {
suffix = "-Sync"
suffix += "-Sync"
}
if splitHandshake {
suffix += "-SplitHandshakeRecords"
@@ -935,7 +997,8 @@ func addStateMachineCoverageTests(async bool, splitHandshake bool) {
// Basic handshake, with resumption. Client and server.
testCases = append(testCases, testCase{
name: "Basic-Client" + suffix,
protocol: protocol,
name: "Basic-Client" + suffix,
config: Config{
Bugs: ProtocolBugs{
MaxHandshakeRecordLength: maxHandshakeRecordLength,
@@ -945,7 +1008,8 @@ func addStateMachineCoverageTests(async bool, splitHandshake bool) {
resumeSession: true,
})
testCases = append(testCases, testCase{
name: "Basic-Client-RenewTicket" + suffix,
protocol: protocol,
name: "Basic-Client-RenewTicket" + suffix,
config: Config{
Bugs: ProtocolBugs{
MaxHandshakeRecordLength: maxHandshakeRecordLength,
@@ -956,6 +1020,7 @@ func addStateMachineCoverageTests(async bool, splitHandshake bool) {
resumeSession: true,
})
testCases = append(testCases, testCase{
protocol: protocol,
testType: serverTest,
name: "Basic-Server" + suffix,
config: Config{
@@ -967,9 +1032,36 @@ func addStateMachineCoverageTests(async bool, splitHandshake bool) {
resumeSession: true,
})
// TLS client auth.
testCases = append(testCases, testCase{
protocol: protocol,
testType: clientTest,
name: "ClientAuth-Client" + suffix,
config: Config{
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
ClientAuth: RequireAnyClientCert,
Bugs: ProtocolBugs{
MaxHandshakeRecordLength: maxHandshakeRecordLength,
},
},
flags: append(flags,
"-cert-file", rsaCertificateFile,
"-key-file", rsaKeyFile),
})
testCases = append(testCases, testCase{
protocol: protocol,
testType: serverTest,
name: "ClientAuth-Server" + suffix,
config: Config{
Certificates: []Certificate{rsaCertificate},
},
flags: append(flags, "-require-any-client-certificate"),
})
// No session ticket support; server doesn't send NewSessionTicket.
testCases = append(testCases, testCase{
name: "SessionTicketsDisabled-Client" + suffix,
protocol: protocol,
name: "SessionTicketsDisabled-Client" + suffix,
config: Config{
SessionTicketsDisabled: true,
Bugs: ProtocolBugs{
@@ -979,6 +1071,7 @@ func addStateMachineCoverageTests(async bool, splitHandshake bool) {
flags: flags,
})
testCases = append(testCases, testCase{
protocol: protocol,
testType: serverTest,
name: "SessionTicketsDisabled-Server" + suffix,
config: Config{
@@ -990,88 +1083,108 @@ func addStateMachineCoverageTests(async bool, splitHandshake bool) {
flags: flags,
})
// NPN on client and server; results in post-handshake message.
testCases = append(testCases, testCase{
name: "NPN-Client" + suffix,
config: Config{
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
NextProtos: []string{"foo"},
Bugs: ProtocolBugs{
MaxHandshakeRecordLength: maxHandshakeRecordLength,
if protocol == tls {
// NPN on client and server; results in post-handshake message.
testCases = append(testCases, testCase{
protocol: protocol,
name: "NPN-Client" + suffix,
config: Config{
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
NextProtos: []string{"foo"},
Bugs: ProtocolBugs{
MaxHandshakeRecordLength: maxHandshakeRecordLength,
},
},
},
flags: append(flags, "-select-next-proto", "foo"),
})
testCases = append(testCases, testCase{
testType: serverTest,
name: "NPN-Server" + suffix,
config: Config{
NextProtos: []string{"bar"},
Bugs: ProtocolBugs{
MaxHandshakeRecordLength: maxHandshakeRecordLength,
flags: append(flags, "-select-next-proto", "foo"),
})
testCases = append(testCases, testCase{
protocol: protocol,
testType: serverTest,
name: "NPN-Server" + suffix,
config: Config{
NextProtos: []string{"bar"},
Bugs: ProtocolBugs{
MaxHandshakeRecordLength: maxHandshakeRecordLength,
},
},
},
flags: append(flags,
"-advertise-npn", "\x03foo\x03bar\x03baz",
"-expect-next-proto", "bar"),
})
flags: append(flags,
"-advertise-npn", "\x03foo\x03bar\x03baz",
"-expect-next-proto", "bar"),
})
// Client does False Start and negotiates NPN.
testCases = append(testCases, testCase{
name: "FalseStart" + suffix,
config: Config{
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
NextProtos: []string{"foo"},
Bugs: ProtocolBugs{
MaxHandshakeRecordLength: maxHandshakeRecordLength,
// Client does False Start and negotiates NPN.
testCases = append(testCases, testCase{
protocol: protocol,
name: "FalseStart" + suffix,
config: Config{
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
NextProtos: []string{"foo"},
Bugs: ProtocolBugs{
MaxHandshakeRecordLength: maxHandshakeRecordLength,
},
},
},
flags: append(flags,
"-false-start",
"-select-next-proto", "foo"),
resumeSession: true,
})
flags: append(flags,
"-false-start",
"-select-next-proto", "foo"),
resumeSession: true,
})
// TLS client auth.
testCases = append(testCases, testCase{
testType: clientTest,
name: "ClientAuth-Client" + suffix,
config: Config{
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
ClientAuth: RequireAnyClientCert,
Bugs: ProtocolBugs{
MaxHandshakeRecordLength: maxHandshakeRecordLength,
// False Start without session tickets.
testCases = append(testCases, testCase{
name: "FalseStart-SessionTicketsDisabled",
config: Config{
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
NextProtos: []string{"foo"},
SessionTicketsDisabled: true,
},
},
flags: append(flags,
"-cert-file", rsaCertificateFile,
"-key-file", rsaKeyFile),
})
testCases = append(testCases, testCase{
testType: serverTest,
name: "ClientAuth-Server" + suffix,
config: Config{
Certificates: []Certificate{rsaCertificate},
},
flags: append(flags, "-require-any-client-certificate"),
})
flags: []string{
"-false-start",
"-select-next-proto", "foo",
},
})
// Client sends a V2ClientHello.
testCases = append(testCases, testCase{
testType: serverTest,
name: "SendV2ClientHello" + suffix,
config: Config{
// Choose a cipher suite that does not involve
// elliptic curves, so no extensions are
// involved.
CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
Bugs: ProtocolBugs{
MaxHandshakeRecordLength: maxHandshakeRecordLength,
SendV2ClientHello: true,
// Client sends a V2ClientHello.
testCases = append(testCases, testCase{
protocol: protocol,
testType: serverTest,
name: "SendV2ClientHello" + suffix,
config: Config{
// Choose a cipher suite that does not involve
// elliptic curves, so no extensions are
// involved.
CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
Bugs: ProtocolBugs{
MaxHandshakeRecordLength: maxHandshakeRecordLength,
SendV2ClientHello: true,
},
},
},
flags: flags,
})
flags: flags,
})
} else {
testCases = append(testCases, testCase{
protocol: protocol,
name: "SkipHelloVerifyRequest" + suffix,
config: Config{
Bugs: ProtocolBugs{
MaxHandshakeRecordLength: maxHandshakeRecordLength,
SkipHelloVerifyRequest: true,
},
},
flags: flags,
})
testCases = append(testCases, testCase{
testType: serverTest,
protocol: protocol,
name: "CookieExchange" + suffix,
config: Config{
Bugs: ProtocolBugs{
MaxHandshakeRecordLength: maxHandshakeRecordLength,
},
},
flags: append(flags, "-cookie-exchange"),
})
}
}
func addVersionNegotiationTests() {
@@ -1169,7 +1282,9 @@ func main() {
addVersionNegotiationTests()
for _, async := range []bool{false, true} {
for _, splitHandshake := range []bool{false, true} {
addStateMachineCoverageTests(async, splitHandshake)
for _, protocol := range []protocol{tls, dtls} {
addStateMachineCoverageTests(async, splitHandshake, protocol)
}
}
}
+5 -1
View File
@@ -34,6 +34,7 @@ struct StringFlag {
const BoolFlag kBoolFlags[] = {
{ "-server", &TestConfig::is_server },
{ "-dtls", &TestConfig::is_dtls },
{ "-resume", &TestConfig::resume },
{ "-fallback-scsv", &TestConfig::fallback_scsv },
{ "-require-any-client-certificate",
@@ -48,6 +49,7 @@ const BoolFlag kBoolFlags[] = {
{ "-no-tls11", &TestConfig::no_tls11 },
{ "-no-tls1", &TestConfig::no_tls1 },
{ "-no-ssl3", &TestConfig::no_ssl3 },
{ "-cookie-exchange", &TestConfig::cookie_exchange },
};
const size_t kNumBoolFlags = sizeof(kBoolFlags) / sizeof(kBoolFlags[0]);
@@ -71,6 +73,7 @@ const size_t kNumStringFlags = sizeof(kStringFlags) / sizeof(kStringFlags[0]);
TestConfig::TestConfig()
: is_server(false),
is_dtls(false),
resume(false),
fallback_scsv(false),
require_any_client_certificate(false),
@@ -82,7 +85,8 @@ TestConfig::TestConfig()
no_tls12(false),
no_tls11(false),
no_tls1(false),
no_ssl3(false) {
no_ssl3(false),
cookie_exchange(false) {
}
bool ParseConfig(int argc, char **argv, TestConfig *out_config) {
+2
View File
@@ -22,6 +22,7 @@ struct TestConfig {
TestConfig();
bool is_server;
bool is_dtls;
bool resume;
bool fallback_scsv;
std::string key_file;
@@ -41,6 +42,7 @@ struct TestConfig {
bool no_tls11;
bool no_tls1;
bool no_ssl3;
bool cookie_exchange;
};
bool ParseConfig(int argc, char **argv, TestConfig *out_config);