summaryrefslogtreecommitdiff
path: root/test/server/test_sslserver.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/server/test_sslserver.c')
-rw-r--r--test/server/test_sslserver.c252
1 files changed, 252 insertions, 0 deletions
diff --git a/test/server/test_sslserver.c b/test/server/test_sslserver.c
new file mode 100644
index 0000000..74492ec
--- /dev/null
+++ b/test/server/test_sslserver.c
@@ -0,0 +1,252 @@
+/* Copyright 2013 Justin Erenkrantz and Greg Stein
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "serf.h"
+#include "test_server.h"
+
+#include "serf_private.h"
+
+//#ifdef SERF_HAVE_OPENSSL
+
+#include <openssl/bio.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+#define TEST_VERBOSE 0
+
+static int init_done = 0;
+
+typedef struct ssl_context_t {
+ int handshake_done;
+
+ SSL_CTX* ctx;
+ SSL* ssl;
+ BIO *bio;
+
+} ssl_context_t;
+
+int pem_passwd_cb(char *buf, int size, int rwflag, void *userdata)
+{
+ strncpy(buf, "serftest", size);
+ buf[size - 1] = '\0';
+ return strlen(buf);
+}
+
+static int bio_apr_socket_create(BIO *bio)
+{
+ bio->shutdown = 1;
+ bio->init = 1;
+ bio->num = -1;
+ bio->ptr = NULL;
+
+ return 1;
+}
+
+static int bio_apr_socket_destroy(BIO *bio)
+{
+ /* Did we already free this? */
+ if (bio == NULL) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static long bio_apr_socket_ctrl(BIO *bio, int cmd, long num, void *ptr)
+{
+ long ret = 1;
+
+ switch (cmd) {
+ default:
+ /* abort(); */
+ break;
+ case BIO_CTRL_FLUSH:
+ /* At this point we can't force a flush. */
+ break;
+ case BIO_CTRL_PUSH:
+ case BIO_CTRL_POP:
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+/* Returns the amount read. */
+static int bio_apr_socket_read(BIO *bio, char *in, int inlen)
+{
+ apr_size_t len = inlen;
+ serv_ctx_t *serv_ctx = bio->ptr;
+ apr_status_t status;
+
+ BIO_clear_retry_flags(bio);
+
+ status = apr_socket_recv(serv_ctx->client_sock, in, &len);
+ if (status == APR_EAGAIN) {
+ BIO_set_retry_read(bio);
+ if (len == 0)
+ return -1;
+
+ }
+
+ if (SERF_BUCKET_READ_ERROR(status))
+ return -1;
+
+ serf__log(TEST_VERBOSE, __FILE__, "Read %d bytes from socket with status %d.\n",
+ len, status);
+
+ return len;
+}
+
+/* Returns the amount written. */
+static int bio_apr_socket_write(BIO *bio, const char *in, int inlen)
+{
+ apr_size_t len = inlen;
+ serv_ctx_t *serv_ctx = bio->ptr;
+
+ apr_status_t status = apr_socket_send(serv_ctx->client_sock, in, &len);
+
+ if (SERF_BUCKET_READ_ERROR(status))
+ return -1;
+
+ serf__log(TEST_VERBOSE, __FILE__, "Wrote %d of %d bytes to socket.\n",
+ len, inlen);
+
+ return len;
+}
+
+
+static BIO_METHOD bio_apr_socket_method = {
+ BIO_TYPE_SOCKET,
+ "APR sockets",
+ bio_apr_socket_write,
+ bio_apr_socket_read,
+ NULL, /* Is this called? */
+ NULL, /* Is this called? */
+ bio_apr_socket_ctrl,
+ bio_apr_socket_create,
+ bio_apr_socket_destroy,
+#ifdef OPENSSL_VERSION_NUMBER
+ NULL /* sslc does not have the callback_ctrl field */
+#endif
+};
+
+apr_status_t init_ssl_context(serv_ctx_t *serv_ctx,
+ const char *keyfile,
+ const char *certfile)
+{
+ ssl_context_t *ssl_ctx = apr_pcalloc(serv_ctx->pool, sizeof(*ssl_ctx));
+ serv_ctx->ssl_ctx = ssl_ctx;
+
+ /* Init OpenSSL globally */
+ if (!init_done)
+ {
+ CRYPTO_malloc_init();
+ ERR_load_crypto_strings();
+ SSL_load_error_strings();
+ SSL_library_init();
+ OpenSSL_add_all_algorithms();
+ init_done = 1;
+ }
+
+ /* Init this connection */
+ if (!ssl_ctx->ctx) {
+ ssl_ctx->ctx = SSL_CTX_new(SSLv23_server_method());
+ SSL_CTX_set_cipher_list(ssl_ctx->ctx, "ALL");
+ SSL_CTX_set_default_passwd_cb(ssl_ctx->ctx, pem_passwd_cb);
+
+ ssl_ctx->ssl = SSL_new(ssl_ctx->ctx);
+ SSL_use_PrivateKey_file(ssl_ctx->ssl, keyfile, SSL_FILETYPE_PEM);
+ SSL_use_certificate_file(ssl_ctx->ssl, certfile, SSL_FILETYPE_PEM);
+
+
+ ssl_ctx->bio = BIO_new(&bio_apr_socket_method);
+ ssl_ctx->bio->ptr = serv_ctx;
+ SSL_set_bio(ssl_ctx->ssl, ssl_ctx->bio, ssl_ctx->bio);
+ }
+
+ return APR_SUCCESS;
+}
+
+apr_status_t ssl_handshake(serv_ctx_t *serv_ctx)
+{
+ ssl_context_t *ssl_ctx = serv_ctx->ssl_ctx;
+ int result;
+
+ if (ssl_ctx->handshake_done)
+ return APR_SUCCESS;
+
+ /* SSL handshake */
+ result = SSL_accept(ssl_ctx->ssl);
+ if (result == 1) {
+ serf__log(TEST_VERBOSE, __FILE__, "Handshake successful.\n");
+ ssl_ctx->handshake_done = 1;
+ }
+ else {
+ int ssl_err;
+
+ ssl_err = SSL_get_error(ssl_ctx->ssl, result);
+ switch (ssl_err) {
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ return APR_EAGAIN;
+ default:
+ serf__log(TEST_VERBOSE, __FILE__, "SSL Error %d: ", ssl_err);
+ ERR_print_errors_fp(stderr);
+ serf__log_nopref(TEST_VERBOSE, "\n");
+ return APR_EGENERAL;
+ }
+ }
+
+ return APR_EAGAIN;
+}
+
+apr_status_t
+ssl_socket_write(serv_ctx_t *serv_ctx, const char *data,
+ apr_size_t *len)
+{
+ ssl_context_t *ssl_ctx = serv_ctx->ssl_ctx;
+
+ int result = SSL_write(ssl_ctx->ssl, data, *len);
+ if (result > 0) {
+ *len = result;
+ return APR_SUCCESS;
+ }
+
+ return APR_EGENERAL;
+}
+
+apr_status_t
+ssl_socket_read(serv_ctx_t *serv_ctx, char *data,
+ apr_size_t *len)
+{
+ ssl_context_t *ssl_ctx = serv_ctx->ssl_ctx;
+
+ int result = SSL_read(ssl_ctx->ssl, data, *len);
+ if (result > 0) {
+ *len = result;
+ return APR_SUCCESS;
+ }
+
+ return APR_EGENERAL;
+}
+
+void cleanup_ssl_context(serv_ctx_t *serv_ctx)
+{
+ ssl_context_t *ssl_ctx = serv_ctx->ssl_ctx;
+
+ SSL_clear(ssl_ctx->ssl);
+ SSL_CTX_free(ssl_ctx->ctx);
+}
+//#endif /* SERF_HAVE_OPENSSL */ \ No newline at end of file