#include <sys_defs.h>
#ifdef USE_TLS
#include <msg.h>
#ifdef __APPLE_OS_X_SERVER__
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <Security/SecKeychain.h>
#include <Security/SecKeychainItem.h>
typedef struct
{
int len;
char key[ FILENAME_MAX ];
int reserved;
} CallbackUserData;
int apple_password_callback ( char *in_buf, int in_size, int in_rwflag, void *in_user_data );
static CallbackUserData *s_user_data = NULL;
#endif
#define TLS_INTERNAL
#include <tls.h>
#ifdef __APPLE_OS_X_SERVER__
int apple_password_callback ( char *in_buf, int in_size, int in_rwflag, void *in_user_data )
{
char *buf = NULL;
ssize_t len = 0;
int fd[ 2 ];
char *args[ 4 ];
CallbackUserData *cb_data = (CallbackUserData *)in_user_data;
if ( (cb_data == NULL) || strlen( cb_data->key ) == 0 ||
(cb_data->len >= FILENAME_MAX) || (cb_data->len == 0) || !in_buf )
{
msg_error("invalid arguments in callback" );
return( 0 );
}
pipe( fd );
pid_t pid = fork();
if ( pid == 0 )
{
close(0);
close(1);
dup2( fd[1], 1 );
args[ 0 ] = "/usr/sbin/certadmin";
args[ 1 ] = "--get-private-key-passphrase";
args[ 2 ] = cb_data->key;
args[ 3 ] = NULL;
execv("/usr/sbin/certadmin", args);
exit( 0 );
}
else if ( pid > 0 )
{
len = 0;
buf = malloc( in_size );
if ( buf == NULL )
{
msg_error( "memory allocation error" );
return( 0 );
}
len = read( fd[0], buf, in_size);
if ( len != 0 )
{
strncpy( in_buf, buf, len - 1 );
in_buf[ len - 1 ] = '\0';
}
}
return( strlen(in_buf ) );
}
#endif
int tls_set_ca_certificate_info(SSL_CTX *ctx, const char *CAfile,
const char *CApath)
{
if (*CAfile == 0)
CAfile = 0;
if (*CApath == 0)
CApath = 0;
if (CAfile || CApath) {
if (!SSL_CTX_load_verify_locations(ctx, CAfile, CApath)) {
msg_info("cannot load Certificate Authority data");
tls_print_errors();
return (-1);
}
if (!SSL_CTX_set_default_verify_paths(ctx)) {
msg_info("cannot set certificate verification paths");
tls_print_errors();
return (-1);
}
}
return (0);
}
static int set_cert_stuff(SSL_CTX *ctx, const char *cert_file,
const char *key_file)
{
if (SSL_CTX_use_certificate_chain_file(ctx, cert_file) <= 0) {
msg_warn("cannot get certificate from file %s", cert_file);
tls_print_errors();
return (0);
}
#ifdef __APPLE_OS_X_SERVER__
if ( strlen( key_file ) < FILENAME_MAX )
{
if ( s_user_data == NULL )
{
s_user_data = malloc( sizeof(CallbackUserData) );
if ( s_user_data != NULL )
{
memset( s_user_data, 0, sizeof(CallbackUserData) );
}
}
if ( s_user_data != NULL )
{
snprintf( s_user_data->key, FILENAME_MAX, "%s", key_file );
s_user_data->len = strlen( s_user_data->key );
SSL_CTX_set_default_passwd_cb_userdata( ctx, (void *)s_user_data );
SSL_CTX_set_default_passwd_cb( ctx, &apple_password_callback );
}
else
{
msg_info( "Could not allocate memory for custom callback: %s", key_file );
}
}
else
{
msg_info( "Key file path too big for custom callback: %s", key_file );
}
#endif
if (SSL_CTX_use_PrivateKey_file(ctx, key_file, SSL_FILETYPE_PEM) <= 0) {
msg_warn("cannot get private key from file %s", key_file);
tls_print_errors();
return (0);
}
if (!SSL_CTX_check_private_key(ctx)) {
msg_warn("private key in %s does not match public key certificate in %s",
key_file, cert_file);
return (0);
}
return (1);
}
int tls_set_my_certificate_key_info(SSL_CTX *ctx,
const char *cert_file, const char *key_file,
const char *dcert_file, const char *dkey_file)
{
#if 0
if (*cert_file == 0 && *dcert_file == 0) {
msg_warn("need an RSA or DSA certificate/key pair");
return (-1);
}
#endif
if (*cert_file) {
if (!set_cert_stuff(ctx, cert_file, *key_file ? key_file : cert_file)) {
msg_info("cannot load RSA certificate and key data");
tls_print_errors();
return (-1);
}
}
if (*dcert_file) {
if (!set_cert_stuff(ctx, dcert_file, *dkey_file ? dkey_file : dcert_file)) {
msg_info("cannot load DSA certificate and key data");
tls_print_errors();
return (-1);
}
}
return (0);
}
#endif