diff options
Diffstat (limited to 'test/server/test_sslserver.c')
-rw-r--r-- | test/server/test_sslserver.c | 252 |
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 |