1/*++ 2/* NAME 3/* tls_certkey 3 4/* SUMMARY 5/* public key certificate and private key loader 6/* SYNOPSIS 7/* #define TLS_INTERNAL 8/* #include <tls.h> 9/* 10/* int tls_set_ca_certificate_info(ctx, CAfile, CApath) 11/* SSL_CTX *ctx; 12/* const char *CAfile; 13/* const char *CApath; 14/* 15/* int tls_set_my_certificate_key_info(ctx, cert_file, key_file, 16/* dcert_file, dkey_file, 17/* eccert_file, eckey_file) 18/* SSL_CTX *ctx; 19/* const char *cert_file; 20/* const char *key_file; 21/* const char *dcert_file; 22/* const char *dkey_file; 23/* const char *eccert_file; 24/* const char *eckey_file; 25/* DESCRIPTION 26/* OpenSSL supports two options to specify CA certificates: 27/* either one file CAfile that contains all CA certificates, 28/* or a directory CApath with separate files for each 29/* individual CA, with symbolic links named after the hash 30/* values of the certificates. The second option is not 31/* convenient with a chrooted process. 32/* 33/* tls_set_ca_certificate_info() loads the CA certificate 34/* information for the specified TLS server or client context. 35/* The result is -1 on failure, 0 on success. 36/* 37/* tls_set_my_certificate_key_info() loads the public key 38/* certificates and private keys for the specified TLS server 39/* or client context. Up to 3 pairs of key pairs (RSA, DSA and 40/* ECDSA) may be specified; each certificate and key pair must 41/* match. The result is -1 on failure, 0 on success. 42/* LICENSE 43/* .ad 44/* .fi 45/* This software is free. You can do with it whatever you want. 46/* The original author kindly requests that you acknowledge 47/* the use of his software. 48/* AUTHOR(S) 49/* Originally written by: 50/* Lutz Jaenicke 51/* BTU Cottbus 52/* Allgemeine Elektrotechnik 53/* Universitaetsplatz 3-4 54/* D-03044 Cottbus, Germany 55/* 56/* Updated by: 57/* Wietse Venema 58/* IBM T.J. Watson Research 59/* P.O. Box 704 60/* Yorktown Heights, NY 10598, USA 61/*--*/ 62 63/* System library. */ 64 65#include <sys_defs.h> 66 67#ifdef USE_TLS 68 69/* Utility library. */ 70 71#include <msg.h> 72 73/* Global library. */ 74 75#include <mail_params.h> 76 77#ifdef __APPLE_OS_X_SERVER__ 78#include <stdio.h> 79#include <sys/types.h> 80#include <sys/stat.h> 81 82#include <Security/SecKeychain.h> 83#include <Security/SecKeychainItem.h> 84 85typedef struct 86{ 87 int len; 88 char key[ FILENAME_MAX ]; 89 int reserved; 90} CallbackUserData; 91 92int apple_password_callback ( char *in_buf, int in_size, int in_rwflag, void *in_user_data ); 93 94static CallbackUserData *s_user_data = NULL; 95 96static const char cert_admin_path[] = "/Applications/Server.app/Contents/ServerRoot/usr/sbin/certadmin"; 97#endif 98 99/* TLS library. */ 100 101#define TLS_INTERNAL 102#include <tls.h> 103 104#ifdef __APPLE_OS_X_SERVER__ 105/* ----------------------------------------------------------------- 106 apple_password_callback () 107 ----------------------------------------------------------------- */ 108 109int apple_password_callback ( char *in_buf, int in_size, int in_rwflag, void *in_user_data ) 110{ 111 int status; 112 char *buf = NULL; 113 ssize_t len = 0; 114 int fd[ 2 ]; 115 char *args[ 4 ]; 116 CallbackUserData *cb_data = (CallbackUserData *)in_user_data; 117 118 if ( (cb_data == NULL) || strlen( cb_data->key ) == 0 || 119 (cb_data->len >= FILENAME_MAX) || (cb_data->len == 0) || !in_buf ) { 120 msg_error("invalid arguments in callback" ); 121 return( 0 ); 122 } 123 124 /* open a pipe */ 125 pipe( fd ); 126 127 /* fork the child */ 128 pid_t pid = fork(); 129 if ( pid == 0 ) { 130 /* child: exec certadmin tool */ 131 close(0); 132 close(1); 133 134 dup2( fd[1], 1 ); 135 136 /* set up the args list */ 137 args[ 0 ] = cert_admin_path; 138 args[ 1 ] = "--get-private-key-passphrase"; 139 args[ 2 ] = cb_data->key; 140 args[ 3 ] = NULL; 141 142 /* get the passphrase */ 143 execv(cert_admin_path, args); 144 exit( 1 ); 145 } else if ( pid > 0 ) { 146 /* parent: wait for the child to terminate */ 147 wait( &status ); 148 if ( !NORMAL_EXIT_STATUS(status) ) { 149 if ( WIFEXITED(status) ) 150 msg_warn("command: %s exit status %d", 151 cert_admin_path, WEXITSTATUS(status) ); 152 if ( WIFSIGNALED(status) ) 153 msg_warn("command: %s killed by signal %d", 154 cert_admin_path, WTERMSIG(status) ); 155 156 return( 0 ); 157 } 158 159 /* parent: read passphrase */ 160 len = 0; 161 buf = malloc( in_size ); 162 if ( buf == NULL ) { 163 msg_error( "memory allocation error" ); 164 return( 0 ); 165 } 166 167 len = read( fd[0], buf, in_size); 168 if ( len != 0 ) { 169 /* copy passphrase into buffer & strip off /n */ 170 strncpy( in_buf, buf, len - 1 ); 171 in_buf[ len - 1 ] = '\0'; 172 } 173 } 174 175 return( strlen(in_buf ) ); 176} /* apple_password_callback */ 177 178#endif 179 180 181/* tls_set_ca_certificate_info - load certificate authority certificates */ 182 183int tls_set_ca_certificate_info(SSL_CTX *ctx, const char *CAfile, 184 const char *CApath) 185{ 186 if (*CAfile == 0) 187 CAfile = 0; 188 if (*CApath == 0) 189 CApath = 0; 190 if (CAfile || CApath) { 191 if (!SSL_CTX_load_verify_locations(ctx, CAfile, CApath)) { 192 msg_info("cannot load Certificate Authority data: " 193 "disabling TLS support"); 194 tls_print_errors(); 195 return (-1); 196 } 197 if (var_tls_append_def_CA && !SSL_CTX_set_default_verify_paths(ctx)) { 198 msg_info("cannot set certificate verification paths: " 199 "disabling TLS support"); 200 tls_print_errors(); 201 return (-1); 202 } 203 } 204 return (0); 205} 206 207/* set_cert_stuff - specify certificate and key information */ 208 209static int set_cert_stuff(SSL_CTX *ctx, const char *cert_type, 210 const char *cert_file, 211 const char *key_file) 212{ 213 214 /* 215 * We need both the private key (in key_file) and the public key 216 * certificate (in cert_file). Both may specify the same file. 217 * 218 * Code adapted from OpenSSL apps/s_cb.c. 219 */ 220 ERR_clear_error(); 221 if (SSL_CTX_use_certificate_chain_file(ctx, cert_file) <= 0) { 222 msg_warn("cannot get %s certificate from file %s: " 223 "disabling TLS support", cert_type, cert_file); 224 tls_print_errors(); 225 return (0); 226 } 227 228#ifdef __APPLE_OS_X_SERVER__ 229 struct stat st; 230 if ( stat(cert_admin_path, &st) == 0 ) { 231 if ( strlen( key_file ) < FILENAME_MAX ) { 232 if ( s_user_data == NULL ) { 233 s_user_data = malloc( sizeof(CallbackUserData) ); 234 if ( s_user_data != NULL ) 235 memset( s_user_data, 0, sizeof(CallbackUserData) ); 236 } 237 238 if ( s_user_data != NULL ) { 239 snprintf( s_user_data->key, FILENAME_MAX, "%s", key_file ); 240 s_user_data->len = strlen( s_user_data->key ); 241 242 SSL_CTX_set_default_passwd_cb_userdata( ctx, (void *)s_user_data ); 243 SSL_CTX_set_default_passwd_cb( ctx, &apple_password_callback ); 244 } else 245 msg_info( "Could not allocate memory for custom callback: %s", key_file ); 246 } else 247 msg_info( "Key file path too big for custom callback: %s", key_file ); 248 } 249#endif 250 251 if (SSL_CTX_use_PrivateKey_file(ctx, key_file, SSL_FILETYPE_PEM) <= 0) { 252 msg_warn("cannot get %s private key from file %s: " 253 "disabling TLS support", cert_type, key_file); 254 tls_print_errors(); 255 return (0); 256 } 257 258 /* 259 * Sanity check. 260 */ 261 if (!SSL_CTX_check_private_key(ctx)) { 262 msg_warn("%s private key in %s does not match public key in %s: " 263 "disabling TLS support", cert_type, key_file, cert_file); 264 return (0); 265 } 266 return (1); 267} 268 269/* tls_set_my_certificate_key_info - load client or server certificates/keys */ 270 271int tls_set_my_certificate_key_info(SSL_CTX *ctx, 272 const char *cert_file, 273 const char *key_file, 274 const char *dcert_file, 275 const char *dkey_file, 276 const char *eccert_file, 277 const char *eckey_file) 278{ 279 280 /* 281 * Lack of certificates is fine so long as we are prepared to use 282 * anonymous ciphers. 283 */ 284 if (*cert_file && !set_cert_stuff(ctx, "RSA", cert_file, key_file)) 285 return (-1); /* logged */ 286 if (*dcert_file && !set_cert_stuff(ctx, "DSA", dcert_file, dkey_file)) 287 return (-1); /* logged */ 288#if OPENSSL_VERSION_NUMBER >= 0x1000000fL && !defined(OPENSSL_NO_ECDH) 289 if (*eccert_file && !set_cert_stuff(ctx, "ECDSA", eccert_file, eckey_file)) 290 return (-1); /* logged */ 291#else 292 if (*eccert_file) 293 msg_warn("ECDSA not supported. Ignoring ECDSA certificate file \"%s\"", 294 eccert_file); 295#endif 296 return (0); 297} 298 299#endif 300