|
Packit |
3adb1e |
/* ====================================================================
|
|
Packit |
3adb1e |
* Licensed to the Apache Software Foundation (ASF) under one
|
|
Packit |
3adb1e |
* or more contributor license agreements. See the NOTICE file
|
|
Packit |
3adb1e |
* distributed with this work for additional information
|
|
Packit |
3adb1e |
* regarding copyright ownership. The ASF licenses this file
|
|
Packit |
3adb1e |
* to you under the Apache License, Version 2.0 (the
|
|
Packit |
3adb1e |
* "License"); you may not use this file except in compliance
|
|
Packit |
3adb1e |
* with the License. You may obtain a copy of the License at
|
|
Packit |
3adb1e |
*
|
|
Packit |
3adb1e |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
Packit |
3adb1e |
*
|
|
Packit |
3adb1e |
* Unless required by applicable law or agreed to in writing,
|
|
Packit |
3adb1e |
* software distributed under the License is distributed on an
|
|
Packit |
3adb1e |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
Packit |
3adb1e |
* KIND, either express or implied. See the License for the
|
|
Packit |
3adb1e |
* specific language governing permissions and limitations
|
|
Packit |
3adb1e |
* under the License.
|
|
Packit |
3adb1e |
* ====================================================================
|
|
Packit |
3adb1e |
*/
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
#include "serf.h"
|
|
Packit |
3adb1e |
#include "test_server.h"
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
#include "serf_private.h"
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
#include <openssl/bio.h>
|
|
Packit |
3adb1e |
#include <openssl/ssl.h>
|
|
Packit |
3adb1e |
#include <openssl/err.h>
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L
|
|
Packit |
3adb1e |
#define USE_OPENSSL_1_1_API
|
|
Packit |
3adb1e |
#endif
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
static int init_done = 0;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
typedef struct ssl_context_t {
|
|
Packit |
3adb1e |
int handshake_done;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
SSL_CTX* ctx;
|
|
Packit |
3adb1e |
SSL* ssl;
|
|
Packit |
3adb1e |
BIO *bio;
|
|
Packit |
3adb1e |
BIO_METHOD *biom;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
} ssl_context_t;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
static int pem_passwd_cb(char *buf, int size, int rwflag, void *userdata)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
strncpy(buf, "serftest", size);
|
|
Packit |
3adb1e |
buf[size - 1] = '\0';
|
|
Packit |
3adb1e |
return strlen(buf);
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
static void bio_set_data(BIO *bio, void *data)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
#ifdef USE_OPENSSL_1_1_API
|
|
Packit |
3adb1e |
BIO_set_data(bio, data);
|
|
Packit |
3adb1e |
#else
|
|
Packit |
3adb1e |
bio->ptr = data;
|
|
Packit |
3adb1e |
#endif
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
static void *bio_get_data(BIO *bio)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
#ifdef USE_OPENSSL_1_1_API
|
|
Packit |
3adb1e |
return BIO_get_data(bio);
|
|
Packit |
3adb1e |
#else
|
|
Packit |
3adb1e |
return bio->ptr;
|
|
Packit |
3adb1e |
#endif
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
static int bio_apr_socket_create(BIO *bio)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
#ifdef USE_OPENSSL_1_1_API
|
|
Packit |
3adb1e |
BIO_set_shutdown(bio, 1);
|
|
Packit |
3adb1e |
BIO_set_init(bio, 1);
|
|
Packit |
3adb1e |
BIO_set_data(bio, NULL);
|
|
Packit |
3adb1e |
#else
|
|
Packit |
3adb1e |
bio->shutdown = 1;
|
|
Packit |
3adb1e |
bio->init = 1;
|
|
Packit |
3adb1e |
bio->num = -1;
|
|
Packit |
3adb1e |
bio->ptr = NULL;
|
|
Packit |
3adb1e |
#endif
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
return 1;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
static int bio_apr_socket_destroy(BIO *bio)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
/* Did we already free this? */
|
|
Packit |
3adb1e |
if (bio == NULL) {
|
|
Packit |
3adb1e |
return 0;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
return 1;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
static long bio_apr_socket_ctrl(BIO *bio, int cmd, long num, void *ptr)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
long ret = 1;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
switch (cmd) {
|
|
Packit |
3adb1e |
default:
|
|
Packit |
3adb1e |
/* abort(); */
|
|
Packit |
3adb1e |
break;
|
|
Packit |
3adb1e |
case BIO_CTRL_FLUSH:
|
|
Packit |
3adb1e |
/* At this point we can't force a flush. */
|
|
Packit |
3adb1e |
break;
|
|
Packit |
3adb1e |
case BIO_CTRL_PUSH:
|
|
Packit |
3adb1e |
case BIO_CTRL_POP:
|
|
Packit |
3adb1e |
ret = 0;
|
|
Packit |
3adb1e |
break;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
return ret;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Returns the amount read. */
|
|
Packit |
3adb1e |
static int bio_apr_socket_read(BIO *bio, char *in, int inlen)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
apr_size_t len = inlen;
|
|
Packit |
3adb1e |
serv_ctx_t *serv_ctx = bio_get_data(bio);
|
|
Packit |
3adb1e |
apr_status_t status;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
BIO_clear_retry_flags(bio);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
status = apr_socket_recv(serv_ctx->client_sock, in, &len;;
|
|
Packit |
3adb1e |
serv_ctx->bio_read_status = status;
|
|
Packit |
3adb1e |
serf__log_skt(TEST_VERBOSE, __FILE__, serv_ctx->client_sock,
|
|
Packit |
3adb1e |
"Read %d bytes from socket with status %d.\n", len, status);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (status == APR_EAGAIN) {
|
|
Packit |
3adb1e |
BIO_set_retry_read(bio);
|
|
Packit |
3adb1e |
if (len == 0)
|
|
Packit |
3adb1e |
return -1;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (SERF_BUCKET_READ_ERROR(status))
|
|
Packit |
3adb1e |
return -1;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
return len;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Returns the amount written. */
|
|
Packit |
3adb1e |
static int bio_apr_socket_write(BIO *bio, const char *in, int inlen)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
apr_size_t len = inlen;
|
|
Packit |
3adb1e |
serv_ctx_t *serv_ctx = bio_get_data(bio);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
apr_status_t status = apr_socket_send(serv_ctx->client_sock, in, &len;;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
serf__log_skt(TEST_VERBOSE, __FILE__, serv_ctx->client_sock,
|
|
Packit |
3adb1e |
"Wrote %d of %d bytes to socket with status %d.\n",
|
|
Packit |
3adb1e |
len, inlen, status);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (SERF_BUCKET_READ_ERROR(status))
|
|
Packit |
3adb1e |
return -1;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
return len;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
#ifndef USE_OPENSSL_1_1_API
|
|
Packit |
3adb1e |
static BIO_METHOD bio_apr_socket_method = {
|
|
Packit |
3adb1e |
BIO_TYPE_SOCKET,
|
|
Packit |
3adb1e |
"APR sockets",
|
|
Packit |
3adb1e |
bio_apr_socket_write,
|
|
Packit |
3adb1e |
bio_apr_socket_read,
|
|
Packit |
3adb1e |
NULL, /* Is this called? */
|
|
Packit |
3adb1e |
NULL, /* Is this called? */
|
|
Packit |
3adb1e |
bio_apr_socket_ctrl,
|
|
Packit |
3adb1e |
bio_apr_socket_create,
|
|
Packit |
3adb1e |
bio_apr_socket_destroy,
|
|
Packit |
3adb1e |
#ifdef OPENSSL_VERSION_NUMBER
|
|
Packit |
3adb1e |
NULL /* sslc does not have the callback_ctrl field */
|
|
Packit |
3adb1e |
#endif
|
|
Packit |
3adb1e |
};
|
|
Packit |
3adb1e |
#endif
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
static BIO_METHOD *bio_meth_apr_socket_new(void)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
BIO_METHOD *biom = NULL;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
#ifdef USE_OPENSSL_1_1_API
|
|
Packit |
3adb1e |
biom = BIO_meth_new(BIO_TYPE_SOCKET, "APR sockets");
|
|
Packit |
3adb1e |
if (biom) {
|
|
Packit |
3adb1e |
BIO_meth_set_write(biom, bio_apr_socket_write);
|
|
Packit |
3adb1e |
BIO_meth_set_read(biom, bio_apr_socket_read);
|
|
Packit |
3adb1e |
BIO_meth_set_ctrl(biom, bio_apr_socket_ctrl);
|
|
Packit |
3adb1e |
BIO_meth_set_create(biom, bio_apr_socket_create);
|
|
Packit |
3adb1e |
BIO_meth_set_destroy(biom, bio_apr_socket_destroy);
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
#else
|
|
Packit |
3adb1e |
biom = &bio_apr_socket_method;
|
|
Packit |
3adb1e |
#endif
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
return biom;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
static int validate_client_certificate(int preverify_ok, X509_STORE_CTX *ctx)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
serf__log(TEST_VERBOSE, __FILE__, "validate_client_certificate called, "
|
|
Packit |
3adb1e |
"preverify code: %d.\n", preverify_ok);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
return preverify_ok;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
static apr_status_t init_ssl(serv_ctx_t *serv_ctx)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
ssl_context_t *ssl_ctx = serv_ctx->ssl_ctx;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
ssl_ctx->ssl = SSL_new(ssl_ctx->ctx);
|
|
Packit |
3adb1e |
SSL_set_cipher_list(ssl_ctx->ssl, "ALL");
|
|
Packit |
3adb1e |
SSL_set_bio(ssl_ctx->ssl, ssl_ctx->bio, ssl_ctx->bio);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
return APR_SUCCESS;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
static apr_status_t
|
|
Packit |
3adb1e |
init_ssl_context(serv_ctx_t *serv_ctx,
|
|
Packit |
3adb1e |
const char *keyfile,
|
|
Packit |
3adb1e |
const char **certfiles,
|
|
Packit |
3adb1e |
const char *client_cn)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
ssl_context_t *ssl_ctx = apr_pcalloc(serv_ctx->pool, sizeof(*ssl_ctx));
|
|
Packit |
3adb1e |
serv_ctx->ssl_ctx = ssl_ctx;
|
|
Packit |
3adb1e |
serv_ctx->client_cn = client_cn;
|
|
Packit |
3adb1e |
serv_ctx->bio_read_status = APR_SUCCESS;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Init OpenSSL globally */
|
|
Packit |
3adb1e |
if (!init_done)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
#ifdef USE_OPENSSL_1_1_API
|
|
Packit |
3adb1e |
OPENSSL_malloc_init();
|
|
Packit |
3adb1e |
#else
|
|
Packit |
3adb1e |
CRYPTO_malloc_init();
|
|
Packit |
3adb1e |
#endif
|
|
Packit |
3adb1e |
ERR_load_crypto_strings();
|
|
Packit |
3adb1e |
SSL_load_error_strings();
|
|
Packit |
3adb1e |
SSL_library_init();
|
|
Packit |
3adb1e |
OpenSSL_add_all_algorithms();
|
|
Packit |
3adb1e |
init_done = 1;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Init this connection */
|
|
Packit |
3adb1e |
if (!ssl_ctx->ctx) {
|
|
Packit |
3adb1e |
X509_STORE *store;
|
|
Packit |
3adb1e |
const char *certfile;
|
|
Packit |
3adb1e |
int i;
|
|
Packit |
3adb1e |
int rv;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
ssl_ctx->ctx = SSL_CTX_new(SSLv23_server_method());
|
|
Packit |
3adb1e |
SSL_CTX_set_default_passwd_cb(ssl_ctx->ctx, pem_passwd_cb);
|
|
Packit |
3adb1e |
rv = SSL_CTX_use_PrivateKey_file(ssl_ctx->ctx, keyfile,
|
|
Packit |
3adb1e |
SSL_FILETYPE_PEM);
|
|
Packit |
3adb1e |
if (rv != 1) {
|
|
Packit |
3adb1e |
fprintf(stderr, "Cannot load private key from file '%s'\n", keyfile);
|
|
Packit |
3adb1e |
exit(1);
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Set server certificate, add ca certificates if provided. */
|
|
Packit |
3adb1e |
certfile = certfiles[0];
|
|
Packit |
3adb1e |
rv = SSL_CTX_use_certificate_file(ssl_ctx->ctx, certfile, SSL_FILETYPE_PEM);
|
|
Packit |
3adb1e |
if (rv != 1) {
|
|
Packit |
3adb1e |
fprintf(stderr, "Cannot load certficate from file '%s'\n", certfile);
|
|
Packit |
3adb1e |
exit(1);
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
i = 1;
|
|
Packit |
3adb1e |
certfile = certfiles[i++];
|
|
Packit |
3adb1e |
store = SSL_CTX_get_cert_store(ssl_ctx->ctx);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
while(certfile) {
|
|
Packit |
3adb1e |
FILE *fp = fopen(certfile, "r");
|
|
Packit |
3adb1e |
if (fp) {
|
|
Packit |
3adb1e |
X509 *ssl_cert = PEM_read_X509(fp, NULL, NULL, NULL);
|
|
Packit |
3adb1e |
fclose(fp);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
SSL_CTX_add_extra_chain_cert(ssl_ctx->ctx, ssl_cert);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
X509_STORE_add_cert(store, ssl_cert);
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
certfile = certfiles[i++];
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* This makes the server send a client certificate request during
|
|
Packit |
3adb1e |
handshake. The client certificate is optional (most tests don't
|
|
Packit |
3adb1e |
send one) by default, but mandatory if client_cn was specified. */
|
|
Packit |
3adb1e |
SSL_CTX_set_verify(ssl_ctx->ctx, SSL_VERIFY_PEER,
|
|
Packit |
3adb1e |
validate_client_certificate);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
SSL_CTX_set_mode(ssl_ctx->ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
ssl_ctx->biom = bio_meth_apr_socket_new();
|
|
Packit |
3adb1e |
ssl_ctx->bio = BIO_new(ssl_ctx->biom);
|
|
Packit |
3adb1e |
bio_set_data(ssl_ctx->bio, serv_ctx);
|
|
Packit |
3adb1e |
init_ssl(serv_ctx);
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
return APR_SUCCESS;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
static apr_status_t ssl_reset(serv_ctx_t *serv_ctx)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
ssl_context_t *ssl_ctx = serv_ctx->ssl_ctx;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
serf__log(TEST_VERBOSE, __FILE__, "Reset ssl context.\n");
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
ssl_ctx->handshake_done = 0;
|
|
Packit |
3adb1e |
if (ssl_ctx)
|
|
Packit |
3adb1e |
SSL_clear(ssl_ctx->ssl);
|
|
Packit |
3adb1e |
init_ssl(serv_ctx);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
return APR_SUCCESS;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
static apr_status_t ssl_handshake(serv_ctx_t *serv_ctx)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
ssl_context_t *ssl_ctx = serv_ctx->ssl_ctx;
|
|
Packit |
3adb1e |
int result;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (ssl_ctx->handshake_done)
|
|
Packit |
3adb1e |
return APR_SUCCESS;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* SSL handshake */
|
|
Packit |
3adb1e |
result = SSL_accept(ssl_ctx->ssl);
|
|
Packit |
3adb1e |
if (result == 1) {
|
|
Packit |
3adb1e |
X509 *peer;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
serf__log(TEST_VERBOSE, __FILE__, "Handshake successful.\n");
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Check client certificate */
|
|
Packit |
3adb1e |
peer = SSL_get_peer_certificate(ssl_ctx->ssl);
|
|
Packit |
3adb1e |
if (peer)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
serf__log(TEST_VERBOSE, __FILE__, "Peer cert received.\n");
|
|
Packit |
3adb1e |
if (SSL_get_verify_result(ssl_ctx->ssl) == X509_V_OK)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
/* The client sent a certificate which verified OK */
|
|
Packit |
3adb1e |
char buf[1024];
|
|
Packit |
3adb1e |
int ret;
|
|
Packit |
3adb1e |
X509_NAME *subject = X509_get_subject_name(peer);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
ret = X509_NAME_get_text_by_NID(subject,
|
|
Packit |
3adb1e |
NID_commonName,
|
|
Packit |
3adb1e |
buf, 1024);
|
|
Packit |
3adb1e |
if (ret != -1 && strcmp(serv_ctx->client_cn, buf) != 0) {
|
|
Packit |
3adb1e |
serf__log(TEST_VERBOSE, __FILE__, "Client cert common name "
|
|
Packit |
3adb1e |
"\"%s\" doesn't match expected \"%s\".\n", buf,
|
|
Packit |
3adb1e |
serv_ctx->client_cn);
|
|
Packit |
3adb1e |
return SERF_ERROR_ISSUE_IN_TESTSUITE;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
} else {
|
|
Packit |
3adb1e |
if (serv_ctx->client_cn) {
|
|
Packit |
3adb1e |
serf__log(TEST_VERBOSE, __FILE__, "Client cert expected but not"
|
|
Packit |
3adb1e |
" received.\n");
|
|
Packit |
3adb1e |
return SERF_ERROR_ISSUE_IN_TESTSUITE;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
ssl_ctx->handshake_done = 1;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
else {
|
|
Packit |
3adb1e |
int ssl_err;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
ssl_err = SSL_get_error(ssl_ctx->ssl, result);
|
|
Packit |
3adb1e |
switch (ssl_err) {
|
|
Packit |
3adb1e |
case SSL_ERROR_WANT_READ:
|
|
Packit |
3adb1e |
case SSL_ERROR_WANT_WRITE:
|
|
Packit |
3adb1e |
return APR_EAGAIN;
|
|
Packit |
3adb1e |
case SSL_ERROR_SYSCALL:
|
|
Packit |
3adb1e |
return serv_ctx->bio_read_status; /* Usually APR_EAGAIN */
|
|
Packit |
3adb1e |
default:
|
|
Packit |
3adb1e |
serf__log(TEST_VERBOSE, __FILE__, "SSL Error %d: ", ssl_err);
|
|
Packit |
3adb1e |
ERR_print_errors_fp(stderr);
|
|
Packit |
3adb1e |
serf__log_nopref(TEST_VERBOSE, "\n");
|
|
Packit |
3adb1e |
return SERF_ERROR_ISSUE_IN_TESTSUITE;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
return APR_EAGAIN;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
static apr_status_t
|
|
Packit |
3adb1e |
ssl_socket_write(serv_ctx_t *serv_ctx, const char *data,
|
|
Packit |
3adb1e |
apr_size_t *len)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
ssl_context_t *ssl_ctx = serv_ctx->ssl_ctx;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
int result = SSL_write(ssl_ctx->ssl, data, *len);
|
|
Packit |
3adb1e |
if (result > 0) {
|
|
Packit |
3adb1e |
*len = result;
|
|
Packit |
3adb1e |
return APR_SUCCESS;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (result == 0)
|
|
Packit |
3adb1e |
return APR_EAGAIN;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
serf__log(TEST_VERBOSE, __FILE__, "ssl_socket_write: ssl error?\n");
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
return SERF_ERROR_ISSUE_IN_TESTSUITE;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
static apr_status_t
|
|
Packit |
3adb1e |
ssl_socket_read(serv_ctx_t *serv_ctx, char *data,
|
|
Packit |
3adb1e |
apr_size_t *len)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
ssl_context_t *ssl_ctx = serv_ctx->ssl_ctx;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
int result = SSL_read(ssl_ctx->ssl, data, *len);
|
|
Packit |
3adb1e |
if (result > 0) {
|
|
Packit |
3adb1e |
*len = result;
|
|
Packit |
3adb1e |
return APR_SUCCESS;
|
|
Packit |
3adb1e |
} else {
|
|
Packit |
3adb1e |
int ssl_err;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
ssl_err = SSL_get_error(ssl_ctx->ssl, result);
|
|
Packit |
3adb1e |
switch (ssl_err) {
|
|
Packit |
3adb1e |
case SSL_ERROR_SYSCALL:
|
|
Packit |
3adb1e |
/* error in bio_bucket_read, probably APR_EAGAIN or APR_EOF */
|
|
Packit |
3adb1e |
*len = 0;
|
|
Packit |
3adb1e |
return serv_ctx->bio_read_status;
|
|
Packit |
3adb1e |
case SSL_ERROR_WANT_READ:
|
|
Packit |
3adb1e |
*len = 0;
|
|
Packit |
3adb1e |
return APR_EAGAIN;
|
|
Packit |
3adb1e |
case SSL_ERROR_SSL:
|
|
Packit |
3adb1e |
default:
|
|
Packit |
3adb1e |
*len = 0;
|
|
Packit |
3adb1e |
serf__log(TEST_VERBOSE, __FILE__,
|
|
Packit |
3adb1e |
"ssl_socket_read SSL Error %d: ", ssl_err);
|
|
Packit |
3adb1e |
ERR_print_errors_fp(stderr);
|
|
Packit |
3adb1e |
serf__log_nopref(TEST_VERBOSE, "\n");
|
|
Packit |
3adb1e |
return SERF_ERROR_ISSUE_IN_TESTSUITE;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* not reachable */
|
|
Packit |
3adb1e |
return SERF_ERROR_ISSUE_IN_TESTSUITE;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
static apr_status_t cleanup_https_server(void *baton)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
serv_ctx_t *servctx = baton;
|
|
Packit |
3adb1e |
ssl_context_t *ssl_ctx = servctx->ssl_ctx;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
if (ssl_ctx) {
|
|
Packit |
3adb1e |
if (ssl_ctx->ssl) {
|
|
Packit |
3adb1e |
SSL_clear(ssl_ctx->ssl);
|
|
Packit |
3adb1e |
#ifdef USE_OPENSSL_1_1_API
|
|
Packit |
3adb1e |
BIO_meth_free(ssl_ctx->biom);
|
|
Packit |
3adb1e |
#endif
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
SSL_CTX_free(ssl_ctx->ctx);
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
return APR_SUCCESS;
|
|
Packit |
3adb1e |
}
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
void setup_https_test_server(serv_ctx_t **servctx_p,
|
|
Packit |
3adb1e |
apr_sockaddr_t *address,
|
|
Packit |
3adb1e |
test_server_message_t *message_list,
|
|
Packit |
3adb1e |
apr_size_t message_count,
|
|
Packit |
3adb1e |
test_server_action_t *action_list,
|
|
Packit |
3adb1e |
apr_size_t action_count,
|
|
Packit |
3adb1e |
apr_int32_t options,
|
|
Packit |
3adb1e |
const char *keyfile,
|
|
Packit |
3adb1e |
const char **certfiles,
|
|
Packit |
3adb1e |
const char *client_cn,
|
|
Packit |
3adb1e |
apr_pool_t *pool)
|
|
Packit |
3adb1e |
{
|
|
Packit |
3adb1e |
serv_ctx_t *servctx;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
setup_test_server(servctx_p, address, message_list,
|
|
Packit |
3adb1e |
message_count, action_list, action_count,
|
|
Packit |
3adb1e |
options, pool);
|
|
Packit |
3adb1e |
servctx = *servctx_p;
|
|
Packit |
3adb1e |
apr_pool_cleanup_register(pool, servctx,
|
|
Packit |
3adb1e |
cleanup_https_server,
|
|
Packit |
3adb1e |
apr_pool_cleanup_null);
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
servctx->handshake = ssl_handshake;
|
|
Packit |
3adb1e |
servctx->reset = ssl_reset;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
/* Override with SSL encrypt/decrypt functions */
|
|
Packit |
3adb1e |
servctx->read = ssl_socket_read;
|
|
Packit |
3adb1e |
servctx->send = ssl_socket_write;
|
|
Packit |
3adb1e |
|
|
Packit |
3adb1e |
init_ssl_context(servctx, keyfile, certfiles, client_cn);
|
|
Packit |
3adb1e |
}
|