/* * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "event2/util.h" #include #include #include "openssl-compat.h" #include "regress.h" #include "tinytest.h" #define TESTCASES_NAME openssl_testcases static void *ssl_test_setup(const struct testcase_t *testcase); static int ssl_test_cleanup(const struct testcase_t *testcase, void *ptr); static const struct testcase_setup_t ssl_setup = { ssl_test_setup, ssl_test_cleanup}; static X509 *the_cert; EVP_PKEY *the_key; #define SSL_IS_CLIENT #define SSL_IS_SERVER #define bufferevent_ssl_get_ssl bufferevent_openssl_get_ssl #define bufferevent_ssl_set_allow_dirty_shutdown \ bufferevent_openssl_set_allow_dirty_shutdown #define bufferevent_ssl_socket_new bufferevent_openssl_socket_new #define bufferevent_ssl_filter_new bufferevent_openssl_filter_new struct rwcount; static void BIO_setup(SSL *ssl, struct rwcount *rw); #include "regress_ssl.c" EVP_PKEY * ssl_getkey(void) { EVP_PKEY *key; BIO *bio; /* new read-only BIO backed by KEY. */ bio = BIO_new_mem_buf((char *)KEY, -1); tt_assert(bio); key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); BIO_free(bio); tt_assert(key); return key; end: return NULL; } X509 * ssl_getcert(EVP_PKEY *key) { /* Dummy code to make a quick-and-dirty valid certificate with OpenSSL. Don't copy this code into your own program! It does a number of things in a stupid and insecure way. */ X509 *x509 = NULL; X509_NAME *name = NULL; int nid; time_t now = time(NULL); tt_assert(key); x509 = X509_new(); tt_assert(x509); tt_assert(0 != X509_set_version(x509, 2)); tt_assert(0 != ASN1_INTEGER_set(X509_get_serialNumber(x509), (long)now)); name = X509_NAME_new(); tt_assert(name); nid = OBJ_txt2nid("commonName"); tt_assert(NID_undef != nid); tt_assert(0 != X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC, (unsigned char *)"example.com", -1, -1, 0)); X509_set_subject_name(x509, name); X509_set_issuer_name(x509, name); X509_NAME_free(name); X509_time_adj(X509_getm_notBefore(x509), 0, &now); now += 3600; X509_time_adj(X509_getm_notAfter(x509), 0, &now); X509_set_pubkey(x509, key); tt_assert(0 != X509_sign(x509, key, EVP_sha1())); return x509; end: X509_free(x509); X509_NAME_free(name); return NULL; } static SSL_CTX *the_ssl_ctx = NULL; SSL_CTX * get_ssl_ctx(void) { if (the_ssl_ctx) return the_ssl_ctx; the_ssl_ctx = SSL_CTX_new(SSLv23_method()); if (!the_ssl_ctx) return NULL; if (disable_tls_11_and_12) { #ifdef SSL_OP_NO_TLSv1_2 SSL_CTX_set_options(the_ssl_ctx, SSL_OP_NO_TLSv1_2); #endif #ifdef SSL_OP_NO_TLSv1_1 SSL_CTX_set_options(the_ssl_ctx, SSL_OP_NO_TLSv1_1); #endif } return the_ssl_ctx; } void init_ssl(void) { #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \ (defined(LIBRESSL_VERSION_NUMBER) && \ LIBRESSL_VERSION_NUMBER < 0x20700000L) SSL_library_init(); ERR_load_crypto_strings(); SSL_load_error_strings(); OpenSSL_add_all_algorithms(); if (SSLeay() != OPENSSL_VERSION_NUMBER) { TT_DECLARE("WARN", ("Version mismatch for openssl: compiled with %lx " "but running with %lx", (unsigned long)OPENSSL_VERSION_NUMBER, (unsigned long)SSLeay())); } #endif } static void * ssl_test_setup(const struct testcase_t *testcase) { init_ssl(); the_key = ssl_getkey(); EVUTIL_ASSERT(the_key); the_cert = ssl_getcert(the_key); EVUTIL_ASSERT(the_cert); disable_tls_11_and_12 = 0; return basic_test_setup(testcase); } static int ssl_test_cleanup(const struct testcase_t *testcase, void *ptr) { int ret = basic_test_cleanup(testcase, ptr); if (!ret) { return ret; } test_is_done = 0; n_connected = 0; got_close = 0; got_error = 0; got_timeout = 0; renegotiate_at = -1; stop_when_connected = 0; pending_connect_events = 0; exit_base = NULL; X509_free(the_cert); EVP_PKEY_free(the_key); SSL_CTX_free(the_ssl_ctx); the_ssl_ctx = NULL; return 1; } static int bio_rwcount_new(BIO *b) { BIO_set_init(b, 0); BIO_set_data(b, NULL); return 1; } static int bio_rwcount_free(BIO *b) { TT_BLATHER(("bio_rwcount_free: %p", b)); if (!b) return 0; if (BIO_get_shutdown(b)) { BIO_set_init(b, 0); BIO_set_data(b, NULL); } return 1; } static int bio_rwcount_read(BIO *b, char *out, int outlen) { struct rwcount *rw = BIO_get_data(b); ev_ssize_t ret = recv(rw->fd, out, outlen, 0); ++rw->read; if (ret == -1 && EVUTIL_ERR_RW_RETRIABLE(EVUTIL_SOCKET_ERROR())) { BIO_set_retry_read(b); } return ret; } static int bio_rwcount_write(BIO *b, const char *in, int inlen) { struct rwcount *rw = BIO_get_data(b); ev_ssize_t ret = send(rw->fd, in, inlen, 0); ++rw->write; if (ret == -1 && EVUTIL_ERR_RW_RETRIABLE(EVUTIL_SOCKET_ERROR())) { BIO_set_retry_write(b); } return ret; } static long bio_rwcount_ctrl(BIO *b, int cmd, long num, void *ptr) { struct rwcount *rw = BIO_get_data(b); long ret = 0; switch (cmd) { case BIO_C_GET_FD: ret = rw->fd; break; case BIO_CTRL_GET_CLOSE: ret = BIO_get_shutdown(b); break; case BIO_CTRL_SET_CLOSE: BIO_set_shutdown(b, (int)num); break; case BIO_CTRL_PENDING: ret = 0; break; case BIO_CTRL_WPENDING: ret = 0; break; case BIO_CTRL_DUP: case BIO_CTRL_FLUSH: ret = 1; break; } return ret; } static int bio_rwcount_puts(BIO *b, const char *s) { return bio_rwcount_write(b, s, strlen(s)); } #define BIO_TYPE_LIBEVENT_RWCOUNT 0xff1 static BIO_METHOD *methods_rwcount; static BIO_METHOD * BIO_s_rwcount(void) { if (methods_rwcount == NULL) { methods_rwcount = BIO_meth_new(BIO_TYPE_LIBEVENT_RWCOUNT, "rwcount"); if (methods_rwcount == NULL) return NULL; BIO_meth_set_write(methods_rwcount, bio_rwcount_write); BIO_meth_set_read(methods_rwcount, bio_rwcount_read); BIO_meth_set_puts(methods_rwcount, bio_rwcount_puts); BIO_meth_set_ctrl(methods_rwcount, bio_rwcount_ctrl); BIO_meth_set_create(methods_rwcount, bio_rwcount_new); BIO_meth_set_destroy(methods_rwcount, bio_rwcount_free); } return methods_rwcount; } static BIO * BIO_new_rwcount(int close_flag) { BIO *result; if (!(result = BIO_new(BIO_s_rwcount()))) return NULL; BIO_set_init(result, 1); BIO_set_data(result, NULL); BIO_set_shutdown(result, !!close_flag); return result; } static void BIO_setup(SSL *ssl, struct rwcount *rw) { BIO *bio; bio = BIO_new_rwcount(0); tt_assert(bio); BIO_set_data(bio, rw); SSL_set_bio(ssl, bio, bio); end: return; }