Add test coverage for session resumption with tickets.
The shim is now passed two file descriptors. In a session resumption test, the
second is used in an abbreviated handshake immediately after the first.
Change-Id: I1f348c05f1a8ff2881fb46fc9e869696f74071c6
Reviewed-on: https://boringssl-review.googlesource.com/1291
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index f8a84e6..f06ccd3 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -12,15 +12,22 @@
* 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 <netinet/in.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <sys/types.h>
#include <unistd.h>
-#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/bytestring.h>
+#include <openssl/ssl.h>
+
+static int usage(const char *program) {
+ fprintf(stderr, "Usage: %s (client|server) (normal|resume) [flags...]\n",
+ program);
+ return 1;
+}
static const char *expected_server_name = NULL;
static int early_callback_called = 0;
@@ -83,14 +90,12 @@
return SSL_TLSEXT_ERR_OK;
}
-static SSL *setup_test(int is_server) {
+static SSL_CTX *setup_ctx(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());
@@ -106,23 +111,38 @@
goto err;
}
+ SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_BOTH);
+
ssl_ctx->select_certificate_cb = select_certificate_callback;
SSL_CTX_set_next_protos_advertised_cb(
ssl_ctx, next_protos_advertised_callback, NULL);
+ return ssl_ctx;
+
+ err:
+ if (ssl_ctx != NULL) {
+ SSL_CTX_free(ssl_ctx);
+ }
+ return NULL;
+}
+
+static SSL *setup_ssl(SSL_CTX *ssl_ctx, int fd) {
+ SSL *ssl = NULL;
+ BIO *bio = NULL;
+
ssl = SSL_new(ssl_ctx);
if (ssl == NULL) {
goto err;
}
- bio = BIO_new_fd(3, 1 /* take ownership */);
+
+ bio = BIO_new_fd(fd, 1 /* take ownership */);
if (bio == NULL) {
goto err;
}
SSL_set_bio(ssl, bio, bio);
- SSL_CTX_free(ssl_ctx);
return ssl;
@@ -133,37 +153,30 @@
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;
+static int do_exchange(SSL_SESSION **out_session,
+ SSL_CTX *ssl_ctx,
+ int argc,
+ char **argv,
+ int is_server,
+ int is_resume,
+ int fd,
+ SSL_SESSION *session) {
const char *expected_certificate_types = NULL;
const char *expected_next_proto = NULL;
+ expected_server_name = NULL;
+ early_callback_called = 0;
+ advertise_npn = NULL;
- 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);
+ SSL *ssl = setup_ssl(ssl_ctx, fd);
if (ssl == NULL) {
BIO_print_errors_fp(stdout);
return 1;
}
- for (i = 2; i < argc; i++) {
+ for (int i = 0; i < argc; i++) {
if (strcmp(argv[i], "-fallback-scsv") == 0) {
if (!SSL_enable_fallback_scsv(ssl)) {
BIO_print_errors_fp(stdout);
@@ -227,6 +240,14 @@
}
}
+ if (session != NULL) {
+ if (SSL_set_session(ssl, session) != 1) {
+ fprintf(stderr, "failed to set session\n");
+ return 2;
+ }
+ }
+
+ int ret;
if (is_server) {
ret = SSL_accept(ssl);
} else {
@@ -238,6 +259,11 @@
return 2;
}
+ if (is_resume && !SSL_session_reused(ssl)) {
+ fprintf(stderr, "session was not reused\n");
+ return 2;
+ }
+
if (expected_server_name) {
const char *server_name =
SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
@@ -299,6 +325,68 @@
}
}
+ if (out_session) {
+ *out_session = SSL_get1_session(ssl);
+ }
+
+ SSL_shutdown(ssl);
SSL_free(ssl);
return 0;
}
+
+int main(int argc, char **argv) {
+ int is_server, resume;
+
+ signal(SIGPIPE, SIG_IGN);
+
+ if (argc < 3) {
+ return usage(argv[0]);
+ }
+
+ if (strcmp(argv[1], "client") == 0) {
+ is_server = 0;
+ } else if (strcmp(argv[1], "server") == 0) {
+ is_server = 1;
+ } else {
+ return usage(argv[0]);
+ }
+
+ if (strcmp(argv[2], "normal") == 0) {
+ resume = 0;
+ } else if (strcmp(argv[2], "resume") == 0) {
+ resume = 1;
+ } else {
+ return usage(argv[0]);
+ }
+
+ SSL_CTX *ssl_ctx = setup_ctx(is_server);
+ if (ssl_ctx == NULL) {
+ BIO_print_errors_fp(stdout);
+ return 1;
+ }
+
+ SSL_SESSION *session;
+ int ret = do_exchange(&session,
+ ssl_ctx,
+ argc - 3, argv + 3,
+ is_server, 0 /* is_resume */,
+ 3 /* fd */, NULL /* session */);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (resume) {
+ int ret = do_exchange(NULL,
+ ssl_ctx, argc - 3, argv + 3,
+ is_server, 1 /* is_resume */,
+ 4 /* fd */,
+ is_server ? NULL : session);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ SSL_SESSION_free(session);
+ SSL_CTX_free(ssl_ctx);
+ return 0;
+}
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 06ca860..539a746 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -76,6 +76,9 @@
certFile string
// keyFile is the path to the private key to use for the server.
keyFile string
+ // resumeSession controls whether a second connection should be tested
+ // which resumes the first session.
+ resumeSession bool
// flags, if not empty, contains a list of command-line flags that will
// be passed to the shim program.
flags []string
@@ -261,7 +264,15 @@
},
}
-func doExchange(tlsConn *Conn, messageLen int) error {
+func doExchange(testType testType, config *Config, conn net.Conn, messageLen int) error {
+ var tlsConn *Conn
+ if testType == clientTest {
+ tlsConn = Server(conn, config)
+ } else {
+ config.InsecureSkipVerify = true
+ tlsConn = Client(conn, config)
+ }
+
if err := tlsConn.Handshake(); err != nil {
return err
}
@@ -308,7 +319,7 @@
return exec.Command("xterm", xtermArgs...)
}
-func runTest(test *testCase) error {
+func openSocketPair() (shimEnd *os.File, conn net.Conn) {
socks, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
if err != nil {
panic(err)
@@ -316,13 +327,22 @@
syscall.CloseOnExec(socks[0])
syscall.CloseOnExec(socks[1])
- shimEnd := os.NewFile(uintptr(socks[0]), "shim end")
+ shimEnd = os.NewFile(uintptr(socks[0]), "shim end")
connFile := os.NewFile(uintptr(socks[1]), "our end")
- conn, err := net.FileConn(connFile)
+ conn, err = net.FileConn(connFile)
+ if err != nil {
+ panic(err)
+ }
connFile.Close()
if err != nil {
panic(err)
}
+ return shimEnd, conn
+}
+
+func runTest(test *testCase) error {
+ shimEnd, conn := openSocketPair()
+ shimEndResume, connResume := openSocketPair()
const shim_path = "../../../build/ssl/test/bssl_shim"
flags := []string{}
@@ -330,7 +350,15 @@
flags = append(flags, "client")
} else {
flags = append(flags, "server")
+ }
+ if test.resumeSession {
+ flags = append(flags, "resume")
+ } else {
+ flags = append(flags, "normal")
+ }
+
+ if test.testType == serverTest {
flags = append(flags, "-key-file")
if test.keyFile == "" {
flags = append(flags, rsaKeyFile)
@@ -354,7 +382,7 @@
shim = exec.Command(shim_path, flags...)
}
// shim = gdbOf(shim_path, flags...)
- shim.ExtraFiles = []*os.File{shimEnd}
+ shim.ExtraFiles = []*os.File{shimEnd, shimEndResume}
shim.Stdin = os.Stdin
var stdoutBuf, stderrBuf bytes.Buffer
shim.Stdout = &stdoutBuf
@@ -364,22 +392,23 @@
panic(err)
}
shimEnd.Close()
+ shimEndResume.Close()
config := test.config
-
- var tlsConn *Conn
+ config.ClientSessionCache = NewLRUClientSessionCache(1)
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)
+ err := doExchange(test.testType, &config, conn, test.messageLen)
conn.Close()
+ if err == nil && test.resumeSession {
+ err = doExchange(test.testType, &config, connResume, test.messageLen)
+ connResume.Close()
+ }
+
childErr := shim.Wait()
stdout := string(stdoutBuf.Bytes())
@@ -473,6 +502,11 @@
continue
}
+ // Go's TLS implementation only implements session
+ // resumption with tickets, so SSLv3 cannot resume
+ // sessions.
+ resumeSession := ver.version != VersionSSL30
+
testCases = append(testCases, testCase{
testType: clientTest,
name: ver.name + "-" + suite.name + "-client",
@@ -482,6 +516,7 @@
CipherSuites: []uint16{suite.id},
Certificates: []Certificate{cert},
},
+ resumeSession: resumeSession,
})
// Go's TLS implementation implements SSLv3 as a server,
@@ -499,8 +534,9 @@
CipherSuites: []uint16{suite.id},
Certificates: []Certificate{cert},
},
- certFile: certFile,
- keyFile: keyFile,
+ certFile: certFile,
+ keyFile: keyFile,
+ resumeSession: resumeSession,
})
}
}