Add some basic server tests to runner.go.
client_shim.cc and runner.go are generalized to handle both ends. Plumb a bit
through the test case to control which and add server versions of all the
cipher suite tests.
Change-Id: Iab2640b390f7ed7160c9a9bf6bb34b8bec761b2e
Reviewed-on: https://boringssl-review.googlesource.com/1091
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/test/CMakeLists.txt b/ssl/test/CMakeLists.txt
index 7d073c1..1b70e99 100644
--- a/ssl/test/CMakeLists.txt
+++ b/ssl/test/CMakeLists.txt
@@ -1,9 +1,9 @@
include_directories(../../include)
add_executable(
- client_shim
+ bssl_shim
- client_shim.cc
+ bssl_shim.cc
)
-target_link_libraries(client_shim ssl crypto)
+target_link_libraries(bssl_shim ssl crypto)
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
new file mode 100644
index 0000000..e8cca12
--- /dev/null
+++ b/ssl/test/bssl_shim.cc
@@ -0,0 +1,164 @@
+/* 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 <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <openssl/ssl.h>
+#include <openssl/bio.h>
+
+
+SSL *setup_test(int is_server) {
+ if (!SSL_library_init()) {
+ return NULL;
+ }
+
+ SSL_CTX *ssl_ctx = NULL;
+ SSL *ssl = NULL;
+ BIO *bio = NULL;
+
+ ssl_ctx = SSL_CTX_new(
+ is_server ? SSLv23_server_method() : SSLv23_client_method());
+ if (ssl_ctx == NULL) {
+ goto err;
+ }
+
+ if (!SSL_CTX_set_ecdh_auto(ssl_ctx, 1)) {
+ goto err;
+ }
+
+ if (!SSL_CTX_set_cipher_list(ssl_ctx, "ALL")) {
+ goto err;
+ }
+
+ ssl = SSL_new(ssl_ctx);
+ if (ssl == NULL) {
+ goto err;
+ }
+
+ bio = BIO_new_fd(3, 1 /* take ownership */);
+ if (bio == NULL) {
+ goto err;
+ }
+
+ SSL_set_bio(ssl, bio, bio);
+ SSL_CTX_free(ssl_ctx);
+
+ return ssl;
+
+err:
+ if (bio != NULL) {
+ BIO_free(bio);
+ }
+ if (ssl != NULL) {
+ SSL_free(ssl);
+ }
+ if (ssl_ctx != NULL) {
+ SSL_CTX_free(ssl_ctx);
+ }
+ return NULL;
+}
+
+int main(int argc, char **argv) {
+ int i, is_server, ret;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s (client|server) [flags...]\n", argv[0]);
+ return 1;
+ }
+ if (strcmp(argv[1], "client") == 0) {
+ is_server = 0;
+ } else if (strcmp(argv[1], "server") == 0) {
+ is_server = 1;
+ } else {
+ fprintf(stderr, "Usage: %s (client|server) [flags...]\n", argv[0]);
+ return 1;
+ }
+
+ SSL *ssl = setup_test(is_server);
+ if (ssl == NULL) {
+ BIO_print_errors_fp(stdout);
+ return 1;
+ }
+
+ for (i = 2; i < argc; i++) {
+ if (strcmp(argv[i], "-fallback-scsv") == 0) {
+ if (!SSL_enable_fallback_scsv(ssl)) {
+ BIO_print_errors_fp(stdout);
+ return 1;
+ }
+ } else if (strcmp(argv[i], "-key-file") == 0) {
+ i++;
+ if (i >= argc) {
+ fprintf(stderr, "Missing parameter\n");
+ return 1;
+ }
+ if (!SSL_use_PrivateKey_file(ssl, argv[i], SSL_FILETYPE_PEM)) {
+ BIO_print_errors_fp(stdout);
+ return 1;
+ }
+ } else if (strcmp(argv[i], "-cert-file") == 0) {
+ i++;
+ if (i >= argc) {
+ fprintf(stderr, "Missing parameter\n");
+ return 1;
+ }
+ if (!SSL_use_certificate_file(ssl, argv[i], SSL_FILETYPE_PEM)) {
+ BIO_print_errors_fp(stdout);
+ return 1;
+ }
+ } else {
+ fprintf(stderr, "Unknown argument: %s\n", argv[i]);
+ return 1;
+ }
+ }
+
+ if (is_server) {
+ ret = SSL_accept(ssl);
+ } else {
+ ret = SSL_connect(ssl);
+ }
+ if (ret != 1) {
+ SSL_free(ssl);
+ BIO_print_errors_fp(stdout);
+ return 2;
+ }
+
+ for (;;) {
+ uint8_t buf[512];
+ int n = SSL_read(ssl, buf, sizeof(buf));
+ if (n < 0) {
+ SSL_free(ssl);
+ BIO_print_errors_fp(stdout);
+ return 3;
+ } else if (n == 0) {
+ break;
+ } else {
+ for (int i = 0; i < n; i++) {
+ buf[i] ^= 0xff;
+ }
+ int w = SSL_write(ssl, buf, n);
+ if (w != n) {
+ SSL_free(ssl);
+ BIO_print_errors_fp(stdout);
+ return 4;
+ }
+ }
+ }
+
+ SSL_free(ssl);
+ return 0;
+}
diff --git a/ssl/test/client_shim.cc b/ssl/test/client_shim.cc
deleted file mode 100644
index 0087a77..0000000
--- a/ssl/test/client_shim.cc
+++ /dev/null
@@ -1,118 +0,0 @@
-/* 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 <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <openssl/ssl.h>
-#include <openssl/bio.h>
-
-
-SSL *setup_test() {
- if (!SSL_library_init()) {
- return NULL;
- }
-
- SSL_CTX *client_ctx = NULL;
- SSL *client = NULL;
- BIO *bio = NULL;
-
- client_ctx = SSL_CTX_new(SSLv23_client_method());
- if (client_ctx == NULL) {
- goto err;
- }
-
- if (!SSL_CTX_set_cipher_list(client_ctx, "ALL")) {
- goto err;
- }
-
- client = SSL_new(client_ctx);
- if (client == NULL) {
- goto err;
- }
-
- bio = BIO_new_fd(3, 1 /* take ownership */);
- if (bio == NULL) {
- goto err;
- }
-
- SSL_set_bio(client, bio, bio);
- SSL_CTX_free(client_ctx);
-
- return client;
-
-err:
- if (bio != NULL) {
- BIO_free(bio);
- }
- if (client != NULL) {
- SSL_free(client);
- }
- if (client_ctx != NULL) {
- SSL_CTX_free(client_ctx);
- }
- return NULL;
-}
-
-int main(int argc, char **argv) {
- int i;
-
- SSL *client = setup_test();
- if (client == NULL) {
- BIO_print_errors_fp(stdout);
- return 1;
- }
-
- for (i = 1; i < argc; i++) {
- if (strcmp(argv[i], "-fallback-scsv") == 0) {
- SSL_enable_fallback_scsv(client);
- } else {
- fprintf(stderr, "Unknown argument: %s\n", argv[i]);
- return 1;
- }
- }
-
- if (SSL_connect(client) != 1) {
- SSL_free(client);
- BIO_print_errors_fp(stdout);
- return 2;
- }
-
- for (;;) {
- uint8_t buf[512];
- int n = SSL_read(client, buf, sizeof(buf));
- if (n < 0) {
- SSL_free(client);
- BIO_print_errors_fp(stdout);
- return 3;
- } else if (n == 0) {
- break;
- } else {
- for (int i = 0; i < n; i++) {
- buf[i] ^= 0xff;
- }
- int w = SSL_write(client, buf, n);
- if (w != n) {
- SSL_free(client);
- BIO_print_errors_fp(stdout);
- return 4;
- }
- }
- }
-
- SSL_free(client);
- return 0;
-}
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 1b86a95..2cda660 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -15,16 +15,26 @@
var useValgrind = flag.Bool("valgrind", false, "If true, run code under valgrind")
+const (
+ rsaCertificateFile = "cert.pem"
+ ecdsaCertificateFile = "ecdsa_cert.pem"
+)
+
+const (
+ rsaKeyFile = "key.pem"
+ ecdsaKeyFile = "ecdsa_key.pem"
+)
+
var rsaCertificate, ecdsaCertificate Certificate
func initCertificates() {
var err error
- rsaCertificate, err = LoadX509KeyPair("cert.pem", "key.pem")
+ rsaCertificate, err = LoadX509KeyPair(rsaCertificateFile, rsaKeyFile)
if err != nil {
panic(err)
}
- ecdsaCertificate, err = LoadX509KeyPair("ecdsa_cert.pem", "ecdsa_key.pem")
+ ecdsaCertificate, err = LoadX509KeyPair(ecdsaCertificateFile, ecdsaKeyFile)
if err != nil {
panic(err)
}
@@ -42,7 +52,15 @@
return ecdsaCertificate
}
+type testType int
+
+const (
+ clientTest testType = iota
+ serverTest
+)
+
type testCase struct {
+ testType testType
name string
config Config
shouldFail bool
@@ -53,12 +71,16 @@
// messageLen is the length, in bytes, of the test message that will be
// sent.
messageLen int
+ // certFile is the path to the certificate to use for the server.
+ certFile string
+ // keyFile is the path to the private key to use for the server.
+ keyFile string
// flags, if not empty, contains a list of command-line flags that will
// be passed to the shim program.
flags []string
}
-var clientTests = []testCase{
+var testCases = []testCase{
{
name: "BadRSASignature",
config: Config{
@@ -170,7 +192,7 @@
syscall.CloseOnExec(socks[0])
syscall.CloseOnExec(socks[1])
- clientEnd := os.NewFile(uintptr(socks[0]), "client end")
+ shimEnd := os.NewFile(uintptr(socks[0]), "shim end")
connFile := os.NewFile(uintptr(socks[1]), "our end")
conn, err := net.FileConn(connFile)
connFile.Close()
@@ -178,35 +200,63 @@
panic(err)
}
- const shim_path = "../../../build/ssl/test/client_shim"
- var client *exec.Cmd
- if *useValgrind {
- client = valgrindOf(false, shim_path, test.flags...)
+ const shim_path = "../../../build/ssl/test/bssl_shim"
+ flags := []string{}
+ if test.testType == clientTest {
+ flags = append(flags, "client")
} else {
- client = exec.Command(shim_path, test.flags...)
- }
- //client := gdbOf(shim_path)
- client.ExtraFiles = []*os.File{clientEnd}
- client.Stdin = os.Stdin
- var stdoutBuf, stderrBuf bytes.Buffer
- client.Stdout = &stdoutBuf
- client.Stderr = &stderrBuf
+ flags = append(flags, "server")
- if err := client.Start(); err != nil {
+ flags = append(flags, "-key-file")
+ if test.keyFile == "" {
+ flags = append(flags, rsaKeyFile)
+ } else {
+ flags = append(flags, test.keyFile)
+ }
+
+ flags = append(flags, "-cert-file")
+ if test.certFile == "" {
+ flags = append(flags, rsaCertificateFile)
+ } else {
+ flags = append(flags, test.certFile)
+ }
+ }
+ flags = append(flags, test.flags...)
+
+ var shim *exec.Cmd
+ if *useValgrind {
+ shim = valgrindOf(false, shim_path, flags...)
+ } else {
+ shim = exec.Command(shim_path, flags...)
+ }
+ // shim = gdbOf(shim_path, flags...)
+ shim.ExtraFiles = []*os.File{shimEnd}
+ shim.Stdin = os.Stdin
+ var stdoutBuf, stderrBuf bytes.Buffer
+ shim.Stdout = &stdoutBuf
+ shim.Stderr = &stderrBuf
+
+ if err := shim.Start(); err != nil {
panic(err)
}
- clientEnd.Close()
+ shimEnd.Close()
config := test.config
- if len(config.Certificates) == 0 {
- config.Certificates = []Certificate{getRSACertificate()}
- }
- tlsConn := Server(conn, &config)
+ var tlsConn *Conn
+ if test.testType == clientTest {
+ if len(config.Certificates) == 0 {
+ config.Certificates = []Certificate{getRSACertificate()}
+ }
+ tlsConn = Server(conn, &config)
+ } else {
+ config.InsecureSkipVerify = true
+ tlsConn = Client(conn, &config)
+ }
err = doExchange(tlsConn, test.messageLen)
conn.Close()
- childErr := client.Wait()
+ childErr := shim.Wait()
stdout := string(stdoutBuf.Bytes())
stderr := string(stderrBuf.Bytes())
@@ -282,10 +332,16 @@
func addCipherSuiteTests() {
for _, suite := range testCipherSuites {
var cert Certificate
+ var certFile string
+ var keyFile string
if strings.Contains(suite.name, "ECDSA") {
cert = getECDSACertificate()
+ certFile = ecdsaCertificateFile
+ keyFile = ecdsaKeyFile
} else {
cert = getRSACertificate()
+ certFile = rsaCertificateFile
+ keyFile = rsaKeyFile
}
for _, ver := range tlsVersions {
@@ -293,8 +349,9 @@
continue
}
- clientTests = append(clientTests, testCase{
- name: ver.name + "-" + suite.name,
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: ver.name + "-" + suite.name + "-client",
config: Config{
MinVersion: ver.version,
MaxVersion: ver.version,
@@ -302,6 +359,26 @@
Certificates: []Certificate{cert},
},
})
+
+ // Go's TLS implementation implements SSLv3 as a server,
+ // but not as a client.
+ //
+ // TODO(davidben): Implement SSLv3 as a client too to
+ // exercise that code.
+ if ver.version != VersionSSL30 {
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: ver.name + "-" + suite.name + "-server",
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ CipherSuites: []uint16{suite.id},
+ Certificates: []Certificate{cert},
+ },
+ certFile: certFile,
+ keyFile: keyFile,
+ })
+ }
}
}
}
@@ -309,7 +386,7 @@
func addBadECDSASignatureTests() {
for badR := BadValue(1); badR < NumBadValues; badR++ {
for badS := BadValue(1); badS < NumBadValues; badS++ {
- clientTests = append(clientTests, testCase{
+ testCases = append(testCases, testCase{
name: fmt.Sprintf("BadECDSA-%d-%d", badR, badS),
config: Config{
CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
@@ -327,7 +404,7 @@
}
func addCBCPaddingTests() {
- clientTests = append(clientTests, testCase{
+ testCases = append(testCases, testCase{
name: "MaxCBCPadding",
config: Config{
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
@@ -337,7 +414,7 @@
},
messageLen: 12, // 20 bytes of SHA-1 + 12 == 0 % block size
})
- clientTests = append(clientTests, testCase{
+ testCases = append(testCases, testCase{
name: "BadCBCPadding",
config: Config{
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
@@ -350,7 +427,7 @@
})
// OpenSSL previously had an issue where the first byte of padding in
// 255 bytes of padding wasn't checked.
- clientTests = append(clientTests, testCase{
+ testCases = append(testCases, testCase{
name: "BadCBCPadding255",
config: Config{
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
@@ -421,16 +498,16 @@
testChan := make(chan *testCase, numWorkers)
doneChan := make(chan struct{})
- go statusPrinter(doneChan, statusChan, len(clientTests))
+ go statusPrinter(doneChan, statusChan, len(testCases))
for i := 0; i < numWorkers; i++ {
wg.Add(1)
go worker(statusChan, testChan, &wg)
}
- for i := range clientTests {
- if len(*flagTest) == 0 || *flagTest == clientTests[i].name {
- testChan <- &clientTests[i]
+ for i := range testCases {
+ if len(*flagTest) == 0 || *flagTest == testCases[i].name {
+ testChan <- &testCases[i]
}
}