#include <string.h>
#include <assert.h>
#include <C:\ocamlms\lib\caml/alloc.h>
#include <C:\ocamlms\lib\caml/callback.h>
#include <C:\ocamlms\lib\caml/custom.h>
#include <C:\ocamlms\lib\caml/fail.h>
#include <C:\ocamlms\lib\caml/memory.h>
#include <C:\ocamlms\lib\caml/mlvalues.h>
#include <C:\ocamlms\lib\caml/signals.h>
#include <C:\ocamlms\lib\caml/unixsupport.h>
#include <C:\OpenSSL-Win32\include\openssl/ssl.h>
#include <C:\OpenSSL-Win32\include\openssl/pem.h>
#include <C:\OpenSSL-Win32\include\openssl/err.h>
#include <C:\OpenSSL-Win32\include\openssl/crypto.h>
#include <windows.h>
static int client_verify_callback(int, X509_STORE_CTX *);
/*******************
* Data structures *
*******************/
/* Contexts */
#define Ctx_val(v) (*((SSL_CTX**)Data_custom_val(v)))
static void finalize_ctx(value block)
{
SSL_CTX *ctx = Ctx_val(block);
SSL_CTX_free(ctx);
}
static struct custom_operations ctx_ops =
{
"ocaml_ssl_ctx",
finalize_ctx,
custom_compare_default,
custom_hash_default,
custom_serialize_default,
custom_deserialize_default
};
/* Sockets */
#define SSL_val(v) (*((SSL**)Data_custom_val(v)))
static void finalize_ssl_socket(value block)
{
SSL *ssl = SSL_val(block);
SSL_free(ssl);
}
static struct custom_operations socket_ops =
{
"ocaml_ssl_socket",
finalize_ssl_socket,
custom_compare_default,
custom_hash_default,
custom_serialize_default,
custom_deserialize_default
};
/******************
* Initialization *
******************/
struct CRYPTO_dynlock_value
{
HANDLE mutex;
};
static HANDLE *mutex_buf = NULL;
static void locking_function(int mode, int n, const char *file, int line)
{
if (mode & CRYPTO_LOCK)
WaitForSingleObject(mutex_buf[n], INFINITE);
else
ReleaseMutex(mutex_buf[n]);
}
static struct CRYPTO_dynlock_value *dyn_create_function(const char *file, int line)
{
struct CRYPTO_dynlock_value *value;
value = malloc(sizeof(struct CRYPTO_dynlock_value));
if (!value)
return NULL;
if (!(value->mutex = CreateMutex(NULL, FALSE, NULL)))
{
free(value);
return NULL;
}
return value;
}
static void dyn_lock_function(int mode, struct CRYPTO_dynlock_value *l, const char *file, int line)
{
if (mode & CRYPTO_LOCK)
WaitForSingleObject(l->mutex, INFINITE);
else
ReleaseMutex(l->mutex);
}
//static void dyn_destroy_function(struct CRYPTO_dynlock_value *l, const char *file, int line)
//{
// CloseHandle(l->mutex);
// free(l);
//};
//struct CRYPTO_dynlock_value
//{
// pthread_mutex_t mutex;
//};
//static pthread_mutex_t *mutex_buf = NULL;
static unsigned long id_function(void)
{
return ((unsigned long) pthread_self());
}
static void dyn_destroy_function(struct CRYPTO_dynlock_value *l, const char *file, int line)
{
pthread_mutex_destroy(&l->mutex);
free(l);
}
CAMLprim value ocaml_ssl_init(value use_threads)
{
int i;
SSL_library_init();
SSL_load_error_strings();
if(Int_val(use_threads))
{
mutex_buf = malloc(CRYPTO_num_locks() * sizeof(HANDLE));
assert(mutex_buf);
for (i = 0; i < CRYPTO_num_locks(); i++)
mutex_buf[i] = CreateMutex(NULL, FALSE, NULL);
CRYPTO_set_locking_callback(locking_function);
CRYPTO_set_dynlock_create_callback(dyn_create_function);
CRYPTO_set_dynlock_lock_callback(dyn_lock_function);
CRYPTO_set_dynlock_destroy_callback(dyn_destroy_function);
}
return Val_unit;
}
CAMLprim value ocaml_ssl_get_error_string(value unit)
{
char buf[256];
ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
return caml_copy_string(buf);
}
/*****************************
* Context-related functions *
*****************************/
static const SSL_METHOD *get_method(int protocol, int type)
{
const SSL_METHOD *method = NULL;
caml_enter_blocking_section();
switch (protocol)
{
case 0:
switch (type)
{
case 0:
method = SSLv23_client_method();
break;
case 1:
method = SSLv23_server_method();
break;
case 2:
method = SSLv23_method();
break;
}
break;
case 1:
switch (type)
{
case 0:
method = SSLv3_client_method();
break;
case 1:
method = SSLv3_server_method();
break;
case 2:
method = SSLv3_method();
break;
}
break;
case 2:
switch (type)
{
case 0:
method = TLSv1_client_method();
break;
case 1:
method = TLSv1_server_method();
break;
case 2:
method = TLSv1_method();
break;
}
break;
default:
caml_leave_blocking_section();
caml_invalid_argument("Unknown method (this should not have happened, please report).");
break;
}
caml_leave_blocking_section();
if (method == NULL)
caml_raise_constant(*caml_named_value("ssl_exn_method_error"));
return method;
}
CAMLprim value ocaml_ssl_create_context(value protocol, value type)
{
value block;
SSL_CTX *ctx;
const SSL_METHOD *method = get_method(Int_val(protocol), Int_val(type));
caml_enter_blocking_section();
ctx = SSL_CTX_new(method);
if (!ctx)
{
caml_leave_blocking_section();
caml_raise_constant(*caml_named_value("ssl_exn_context_error"));
}
/* In non-blocking mode, accept a buffer with a different address on
a write retry (since the GC may need to move it). In blocking
mode, hide SSL_ERROR_WANT_(READ|WRITE) from us. */
SSL_CTX_set_mode(ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_AUTO_RETRY);
caml_leave_blocking_section();
block = caml_alloc_custom(&ctx_ops, sizeof(SSL_CTX*), 0, 1);
Ctx_val(block) = ctx;
return block;
}
CAMLprim value ocaml_ssl_ctx_use_certificate(value context, value cert, value privkey)
{
CAMLparam3(context, cert, privkey);
SSL_CTX *ctx = Ctx_val(context);
char *cert_name = String_val(cert);
char *privkey_name = String_val(privkey);
caml_enter_blocking_section();
if (SSL_CTX_use_certificate_chain_file(ctx, cert_name) <= 0)
{
caml_leave_blocking_section();
caml_raise_constant(*caml_named_value("ssl_exn_certificate_error"));
}
if (SSL_CTX_use_PrivateKey_file(ctx, privkey_name, SSL_FILETYPE_PEM) <= 0)
{
caml_leave_blocking_section();
caml_raise_constant(*caml_named_value("ssl_exn_private_key_error"));
}
if (!SSL_CTX_check_private_key(ctx))
{
caml_leave_blocking_section();
caml_raise_constant(*caml_named_value("ssl_exn_unmatching_keys"));
}
caml_leave_blocking_section();
CAMLreturn(Val_unit);
}
CAMLprim value ocaml_ssl_get_verify_result(value socket)
{
CAMLparam1(socket);
int ans;
SSL *ssl = SSL_val(socket);
caml_enter_blocking_section();
ans = SSL_get_verify_result(ssl);
caml_leave_blocking_section();
CAMLreturn(Val_int(ans));
}
CAMLprim value ocaml_ssl_get_client_verify_callback_ptr(value unit)
{
return (value)client_verify_callback;
}
CAMLprim value ocaml_ssl_ctx_set_verify(value context, value vmode, value vcallback)
{
CAMLparam3(context, vmode, vcallback);
SSL_CTX *ctx = Ctx_val(context);
int mode = 0;
value mode_tl = vmode;
int (*callback) (int, X509_STORE_CTX*) = NULL;
if (Is_long(vmode))
mode = SSL_VERIFY_NONE;
while (Is_block(mode_tl))
{
switch(Int_val(Field(mode_tl, 0)))
{
case 0:
mode |= SSL_VERIFY_PEER;
break;
case 1:
mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT | SSL_VERIFY_PEER;
break;
case 2:
mode |= SSL_VERIFY_CLIENT_ONCE | SSL_VERIFY_PEER;
break;
default:
caml_invalid_argument("mode");
}
mode_tl = Field(mode_tl, 1);
}
if (Is_block(vcallback))
callback = (int(*) (int, X509_STORE_CTX*))Field(vcallback, 0);
caml_enter_blocking_section();
SSL_CTX_set_verify(ctx, mode, callback);
caml_leave_blocking_section();
CAMLreturn(Val_unit);
}
CAMLprim value ocaml_ssl_ctx_set_verify_depth(value context, value vdepth)
{
SSL_CTX *ctx = Ctx_val(context);
int depth = Int_val(vdepth);
if (depth < 0)
caml_invalid_argument("depth");
caml_enter_blocking_section();
SSL_CTX_set_verify_depth(ctx, depth);
caml_leave_blocking_section();
return Val_unit;
}
CAMLprim value ocaml_ssl_ctx_set_client_CA_list_from_file(value context, value vfilename)
{
CAMLparam2(context, vfilename);
SSL_CTX *ctx = Ctx_val(context);
char *filename = String_val(vfilename);
STACK_OF(X509_NAME) *cert_names;
caml_enter_blocking_section();
cert_names = SSL_load_client_CA_file(filename);
if (cert_names != 0)
SSL_CTX_set_client_CA_list(ctx, cert_names);
else
{
caml_leave_blocking_section();
caml_raise_constant(*caml_named_value("ssl_exn_certificate_error"));
}
caml_leave_blocking_section();
CAMLreturn(Val_unit);
}
static int pem_passwd_cb(char *buf, int size, int rwflag, void *userdata)
{
value s;
int len;
caml_leave_blocking_section();
s = caml_callback(*((value*)userdata), Val_int(rwflag));
len = caml_string_length(s);
assert(len <= size);
memcpy(buf, String_val(s), len);
caml_enter_blocking_section();
return len;
}
CAMLprim value ocaml_ssl_ctx_set_default_passwd_cb(value context, value cb)
{
CAMLparam2(context, cb);
SSL_CTX *ctx = Ctx_val(context);
value *pcb;
/* TODO: this never gets freed or even unregistered */
pcb = malloc(sizeof(value));
*pcb = cb;
caml_register_global_root(pcb);
caml_enter_blocking_section();
SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb);
SSL_CTX_set_default_passwd_cb_userdata(ctx, pcb);
caml_leave_blocking_section();
CAMLreturn(Val_unit);
}
/****************************
* Cipher-related functions *
****************************/
CAMLprim value ocaml_ssl_ctx_set_cipher_list(value context, value ciphers_string)
{
CAMLparam2(context, ciphers_string);
SSL_CTX *ctx = Ctx_val(context);
char *ciphers = String_val(ciphers_string);
if(*ciphers == 0)
caml_raise_constant(*caml_named_value("ssl_exn_cipher_error"));
caml_enter_blocking_section();
if(SSL_CTX_set_cipher_list(ctx, ciphers) != 1)
{
caml_leave_blocking_section();
caml_raise_constant(*caml_named_value("ssl_exn_cipher_error"));
}
caml_leave_blocking_section();
CAMLreturn(Val_unit);
}
SSL_CIPHER *cipher;
CAMLprim value ocaml_ssl_get_current_cipher(value socket)
{
CAMLparam1(socket);
SSL *ssl = SSL_val(socket);
caml_enter_blocking_section();
cipher = (SSL_CIPHER*)SSL_get_current_cipher(ssl);
caml_leave_blocking_section();
if (!cipher)
caml_raise_constant(*caml_named_value("ssl_exn_cipher_error"));
CAMLreturn((value)cipher);
}
CAMLprim value ocaml_ssl_get_cipher_description(value vcipher)
{
char buf[1024];
SSL_CIPHER *cipher = (SSL_CIPHER*)vcipher;
caml_enter_blocking_section();
SSL_CIPHER_description(cipher, buf, 1024);
caml_leave_blocking_section();
return caml_copy_string(buf);
}
CAMLprim value ocaml_ssl_get_cipher_name(value vcipher)
{
const char *name;
SSL_CIPHER *cipher = (SSL_CIPHER*)vcipher;
caml_enter_blocking_section();
name = SSL_CIPHER_get_name(cipher);
caml_leave_blocking_section();
return caml_copy_string(name);
}
CAMLprim value ocaml_ssl_get_cipher_version(value vcipher)
{
char *version;
SSL_CIPHER *cipher = (SSL_CIPHER*)vcipher;
caml_enter_blocking_section();
version = SSL_CIPHER_get_version(cipher);
caml_leave_blocking_section();
return caml_copy_string(version);
}
/*********************************
* Certificate-related functions *
*********************************/
#define Cert_val(v) (*((X509**)Data_custom_val(v)))
static void finalize_cert(value block)
{
X509 *cert = Cert_val(block);
X509_free(cert);
}
static struct custom_operations cert_ops =
{
"ocaml_ssl_cert",
finalize_cert,
custom_compare_default,
custom_hash_default,
custom_serialize_default,
custom_deserialize_default
};
CAMLprim value ocaml_ssl_read_certificate(value vfilename)
{
value block;
char *filename = String_val(vfilename);
X509 *cert = NULL;
FILE *fh = NULL;
if((fh = fopen(filename, "r")) == NULL)
caml_raise_constant(*caml_named_value("ssl_exn_certificate_error"));
caml_enter_blocking_section();
if((PEM_read_X509(fh, &cert, 0, 0)) == NULL)
{
fclose(fh);
caml_leave_blocking_section();
caml_raise_constant(*caml_named_value("ssl_exn_certificate_error"));
}
fclose(fh);
caml_leave_blocking_section();
block = caml_alloc_custom(&cert_ops, sizeof(X509*), 0, 1);
Cert_val(block) = cert;
return block;
}
CAMLprim value ocaml_ssl_write_certificate(value vfilename, value certificate)
{
CAMLparam2(vfilename, certificate);
char *filename = String_val(vfilename);
X509 *cert = Cert_val(certificate);
FILE *fh = NULL;
if((fh = fopen(filename, "w")) == NULL)
caml_raise_constant(*caml_named_value("ssl_exn_certificate_error"));
caml_enter_blocking_section();
if(PEM_write_X509(fh, cert) == 0)
{
fclose(fh);
caml_leave_blocking_section();
caml_raise_constant(*caml_named_value("ssl_exn_certificate_error"));
}
fclose(fh);
caml_leave_blocking_section();
CAMLreturn(Val_unit);
}
X509 *cert;
CAMLprim value ocaml_ssl_get_certificate(value socket)
{
CAMLparam1(socket);
SSL *ssl = SSL_val(socket);
caml_enter_blocking_section();
cert = SSL_get_peer_certificate(ssl);
caml_leave_blocking_section();
if (!cert)
caml_raise_constant(*caml_named_value("ssl_exn_certificate_error"));
CAMLlocal1(block);
block = caml_alloc_final(2, finalize_cert, 0, 1);
(*((X509 **) Data_custom_val(block))) = cert;
CAMLreturn(block);
}
CAMLprim value ocaml_ssl_get_issuer(value certificate)
{
CAMLparam1(certificate);
X509 *cert = Cert_val(certificate);
caml_enter_blocking_section();
char *issuer = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
caml_leave_blocking_section();
if (!issuer) caml_raise_not_found ();
CAMLreturn(caml_copy_string(issuer));
}
CAMLprim value ocaml_ssl_get_subject(value certificate)
{
CAMLparam1(certificate);
X509 *cert = Cert_val(certificate);
caml_enter_blocking_section();
char *subject = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
caml_leave_blocking_section();
if (subject == NULL) caml_raise_not_found ();
CAMLreturn(caml_copy_string(subject));
}
CAMLprim value ocaml_ssl_ctx_load_verify_locations(value context, value ca_file, value ca_path)
{
CAMLparam3(context, ca_file, ca_path);
SSL_CTX *ctx = Ctx_val(context);
char *CAfile = String_val(ca_file);
char *CApath = String_val(ca_path);
if(*CAfile == 0)
CAfile = NULL;
if(*CApath == 0)
CApath = NULL;
caml_enter_blocking_section();
if(SSL_CTX_load_verify_locations(ctx, CAfile, CApath) != 1)
{
caml_leave_blocking_section();
caml_invalid_argument("cafile or capath");
}
caml_leave_blocking_section();
CAMLreturn(Val_unit);
}
/*************************
* Operations on sockets *
*************************/
CAMLprim value ocaml_ssl_get_file_descr(value socket)
{
CAMLparam1(socket);
SSL *ssl = SSL_val(socket);
int fd;
caml_enter_blocking_section();
fd = SSL_get_fd(ssl);
caml_leave_blocking_section();
CAMLreturn(Val_int(fd));
}
CAMLprim value ocaml_ssl_embed_socket(value socket_, value context)
{
CAMLparam1(context);
CAMLlocal1(block);
SOCKET socket = Socket_val(socket_);
SSL_CTX *ctx = Ctx_val(context);
SSL *ssl;
block = caml_alloc_custom(&socket_ops, sizeof(SSL*), 0, 1);
if (socket < 0)
caml_raise_constant(*caml_named_value("ssl_exn_invalid_socket"));
caml_enter_blocking_section();
ssl = SSL_new(ctx);
if (!ssl)
{
caml_leave_blocking_section();
caml_raise_constant(*caml_named_value("ssl_exn_handler_error"));
}
SSL_set_fd(ssl, socket);
caml_leave_blocking_section();
SSL_val(block) = ssl;
CAMLreturn(block);
}
CAMLprim value ocaml_ssl_connect(value socket)
{
CAMLparam1(socket);
int ret, err;
SSL *ssl = SSL_val(socket);
caml_enter_blocking_section();
ret = SSL_connect(ssl);
err = SSL_get_error(ssl, ret);
caml_leave_blocking_section();
if (err != SSL_ERROR_NONE)
caml_raise_with_arg(*caml_named_value("ssl_exn_connection_error"), Val_int(err));
CAMLreturn(Val_unit);
}
CAMLprim value ocaml_ssl_verify(value socket)
{
CAMLparam1(socket);
SSL *ssl = SSL_val(socket);
long ans;
caml_enter_blocking_section();
ans = SSL_get_verify_result(ssl);
caml_leave_blocking_section();
if (ans != 0)
{
if (2 <= ans && ans <= 32)
caml_raise_with_arg(*caml_named_value("ssl_exn_verify_error"), Val_int(ans - 2)); /* Not very nice, but simple */
else
caml_raise_with_arg(*caml_named_value("ssl_exn_verify_error"), Val_int(31));
}
CAMLreturn(Val_unit);
}
CAMLprim value ocaml_ssl_write(value socket, value buffer, value start, value length)
{
CAMLparam2(socket, buffer);
int ret, err;
int buflen = Int_val(length);
char *buf = malloc(buflen);
SSL *ssl = SSL_val(socket);
if (Int_val(start) + Int_val(length) > caml_string_length(buffer))
caml_invalid_argument("Buffer too short.");
memmove(buf, (char*)String_val(buffer) + Int_val(start), buflen);
caml_enter_blocking_section();
ERR_clear_error();
ret = SSL_write(ssl, buf, buflen);
err = SSL_get_error(ssl, ret);
caml_leave_blocking_section();
free(buf);
if (err != SSL_ERROR_NONE)
caml_raise_with_arg(*caml_named_value("ssl_exn_write_error"), Val_int(err));
CAMLreturn(Val_int(ret));
}
CAMLprim value ocaml_ssl_read(value socket, value buffer, value start, value length)
{
CAMLparam2(socket, buffer);
int ret, err;
int buflen = Int_val(length);
char *buf = malloc(buflen);
SSL *ssl = SSL_val(socket);
if (Int_val(start) + Int_val(length) > caml_string_length(buffer))
caml_invalid_argument("Buffer too short.");
caml_enter_blocking_section();
ERR_clear_error();
ret = SSL_read(ssl, buf, buflen);
err = SSL_get_error(ssl, ret);
caml_leave_blocking_section();
memmove(((char*)String_val(buffer)) + Int_val(start), buf, buflen);
free(buf);
if (err != SSL_ERROR_NONE)
caml_raise_with_arg(*caml_named_value("ssl_exn_read_error"), Val_int(err));
CAMLreturn(Val_int(ret));
}
CAMLprim value ocaml_ssl_accept(value socket)
{
CAMLparam1(socket);
SSL *ssl = SSL_val(socket);
int ret, err;
caml_enter_blocking_section();
ERR_clear_error();
ret = SSL_accept(ssl);
err = SSL_get_error(ssl, ret);
caml_leave_blocking_section();
if (err != SSL_ERROR_NONE)
caml_raise_with_arg(*caml_named_value("ssl_exn_accept_error"), Val_int(err));
caml_leave_blocking_section();
CAMLreturn(Val_unit);
}
CAMLprim value ocaml_ssl_flush(value socket)
{
CAMLparam1(socket);
SSL *ssl = SSL_val(socket);
BIO *bio;
caml_enter_blocking_section();
bio = SSL_get_wbio(ssl);
if(bio)
{
/* TODO: raise an error */
assert(BIO_flush(bio) == 1);
}
caml_leave_blocking_section();
CAMLreturn(Val_unit);
}
CAMLprim value ocaml_ssl_shutdown(value socket)
{
CAMLparam1(socket);
SSL *ssl = SSL_val(socket);
int ret;
caml_enter_blocking_section();
ret = SSL_shutdown(ssl);
if (!ret)
SSL_shutdown(ssl);
caml_leave_blocking_section();
/* close(SSL_get_fd(SSL_val(socket))); */
CAMLreturn(Val_unit);
}
/* ======================================================== */
/*
T.F.:
Here, we steal the client_verify_callback function from
netkit-telnet-ssl-0.17.24+0.1/libtelnet/ssl.c
From the original file header:
The modifications to support SSLeay were done by Tim Hudson
[email protected]
You can do whatever you like with these patches except pretend that
you wrote them.
Email [email protected] to get instructions on how to
join the mailing list that discusses SSLeay and also these patches.
*/
#define ONELINE_NAME(X) X509_NAME_oneline(X, 0, 0)
/* Quick translation ... */
#ifndef VERIFY_ERR_UNABLE_TO_GET_ISSUER
#define VERIFY_ERR_UNABLE_TO_GET_ISSUER X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT
#endif
#ifndef VERIFY_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
#define VERIFY_ERR_DEPTH_ZERO_SELF_SIGNED_CERT X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
#endif
#ifndef VERIFY_OK
#define VERIFY_OK X509_V_OK
#endif
#ifndef VERIFY_ERR_UNABLE_TO_GET_ISSUER
#define VERIFY_ERR_UNABLE_TO_GET_ISSUER X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT
#endif
/* Need to think about this mapping in terms of what the real
* equivalent of this actually is.
*/
#ifndef VERIFY_ROOT_OK
#define VERIFY_ROOT_OK VERIFY_OK
#endif
static int client_verify_callback(int ok, X509_STORE_CTX *ctx)
{
char *subject, *issuer;
int depth, error;
char *xs;
depth = ctx->error_depth;
error = ctx->error;
xs = (char *)X509_STORE_CTX_get_current_cert(ctx);
subject = issuer = NULL;
/* First thing is to have a meaningful name for the current
* certificate that is being verified ... and if we cannot
* determine that then something is seriously wrong!
*/
subject=(char*)ONELINE_NAME(X509_get_subject_name((X509*)xs));
if (subject == NULL)
{
ERR_print_errors_fp(stderr);
ok = 0;
goto return_time;
}
issuer = (char*)ONELINE_NAME(X509_get_issuer_name((X509*)xs));
if (issuer == NULL)
{
ERR_print_errors_fp(stderr);
ok = 0;
goto return_time;
}
/* If the user wants us to be chatty about things then this
* is a good time to wizz the certificate chain past quickly :-)
*/
if (1)
{
fprintf(stderr, "Certificate[%d] subject=%s\n", depth, subject);
fprintf(stderr, "Certificate[%d] issuer =%s\n", depth, issuer);
fflush(stderr);
}
/* If the server is using a self signed certificate then
* we need to decide if that is good enough for us to
* accept ...
*/
if (error == VERIFY_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
{
if (1)
{
/* Make 100% sure that in secure more we drop the
* connection if the server does not have a
* real certificate!
*/
fprintf(stderr,"SSL: rejecting connection - server has a self-signed certificate\n");
fflush(stderr);
/* Sometimes it is really handy to be able to debug things
* and still get a connection!
*/
ok = 0;
goto return_time;
}
else
{
ok = 1;
goto return_time;
}
}
/* If we have any form of error in secure mode we reject the connection. */
if (!((error == VERIFY_OK) || (error == VERIFY_ROOT_OK)))
{
if (1)
{
fprintf(stderr, "SSL: rejecting connection - error=%d\n", error);
if (error == VERIFY_ERR_UNABLE_TO_GET_ISSUER)
{
fprintf(stderr, "unknown issuer: %s\n", issuer);
}
else
{
ERR_print_errors_fp(stderr);
}
fflush(stderr);
ok = 0;
goto return_time;
}
else
{
/* Be nice and display a lot more meaningful stuff
* so that we know which issuer is unknown no matter
* what the callers options are ...
*/
if (error == VERIFY_ERR_UNABLE_TO_GET_ISSUER)
{
fprintf(stderr, "SSL: unknown issuer: %s\n", issuer);
fflush(stderr);
}
}
}
return_time:
/* Clean up things. */
if (subject)
free(subject);
if (issuer)
free(issuer);
return ok;
}