-/* @(#) $Id: ./src/os_auth/ssl.c, 2011/09/08 dcid Exp $
- */
-
/* Copyright (C) 2010 Trend Micro Inc.
* All rights reserved.
*
*
*/
-
-#ifdef USE_OPENSSL
+#ifdef LIBOPENSSL_ENABLED
#include "shared.h"
#include "auth.h"
+/* Global variables */
+BIO *bio_err;
+
+
+/* Create an SSL context. If certificate verification is requested
+ * then load the file containing the CA chain and verify the certificate
+ * sent by the peer.
+ */
+SSL_CTX *os_ssl_keys(int is_server, const char *os_dir, const char *ciphers, const char *cert, const char *key, const char *ca_cert)
+{
+ SSL_CTX *ctx = NULL;
+
+ if (!(ctx = get_ssl_context(ciphers))) {
+ goto SSL_ERROR;
+ }
+
+ /* If a CA certificate has been specified then load it and verify the peer */
+ if (ca_cert) {
+ debug1("%s: DEBUG: Peer verification requested.", ARGV0);
+
+ if (!load_ca_cert(ctx, ca_cert)) {
+ goto SSL_ERROR;
+ }
+
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback);
+ }
+
+ /* Loading a certificate and key is mandatory for the server and optional for clients */
+ if (is_server) {
+ char default_cert[PATH_MAX + 1];
+ char default_key[PATH_MAX + 1];
+
+ if (!cert) {
+ snprintf(default_cert, PATH_MAX + 1, "%s%s", os_dir, CERTFILE);
+ cert = default_cert;
+ }
+
+ if (!key) {
+ snprintf(default_key, PATH_MAX + 1, "%s%s", os_dir, KEYFILE);
+ key = default_key;
+ }
+
+ if (!load_cert_and_key(ctx, cert, key)) {
+ goto SSL_ERROR;
+ }
+
+ debug1("%s: DEBUG: Returning CTX for server.", ARGV0);
+ } else {
+ if (cert && key) {
+ if (!load_cert_and_key(ctx, cert, key)) {
+ goto SSL_ERROR;
+ }
+ }
+
+ debug1("%s: DEBUG: Returning CTX for client.", ARGV0);
+ }
-void *os_ssl_keys(int isclient, char *dir)
+ return ctx;
+
+SSL_ERROR:
+ if (ctx) {
+ SSL_CTX_free(ctx);
+ }
+
+ return (SSL_CTX *)NULL;
+}
+
+SSL_CTX *get_ssl_context(const char *ciphers)
{
- SSL_METHOD *sslmeth;
- SSL_CTX *ctx;
- char certf[1024 +1];
- char keyf[1024 +1];
+ const SSL_METHOD *sslmeth = NULL;
+ SSL_CTX *ctx = NULL;
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
- bio_err = BIO_new_fp(stderr,BIO_NOCLOSE);
-
/* Create our context */
- sslmeth = (SSL_METHOD *)SSLv23_method();
- ctx = SSL_CTX_new(sslmeth);
-
- if(isclient)
- {
- debug1("%s: DEBUG: Returning CTX for client.", ARGV0);
- return(ctx);
+ sslmeth = TLSv1_2_method();
+ if (!(ctx = SSL_CTX_new(sslmeth))) {
+ goto CONTEXT_ERR;
}
- if(!dir)
- {
- return(NULL);
+ /* Explicitly set options and cipher list */
+ SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
+ if (!(SSL_CTX_set_cipher_list(ctx, ciphers))) {
+ goto CONTEXT_ERR;
}
+ return ctx;
- /* Setting final cert/key files */
- certf[1024] = '\0';
- keyf[1024] = '\0';
- snprintf(certf, 1023, "%s%s", dir, CERTFILE);
- snprintf(keyf, 1023, "%s%s", dir, KEYFILE);
+CONTEXT_ERR:
+ if (ctx) {
+ SSL_CTX_free(ctx);
+ }
+ return (SSL_CTX *)NULL;
+}
- if(File_DateofChange(certf) <= 0)
- {
- merror("%s: ERROR: Unable to read certificate file (not found): %s", ARGV0, certf);
- return(NULL);
+int load_cert_and_key(SSL_CTX *ctx, const char *cert, const char *key)
+{
+ if (File_DateofChange(cert) <= 0) {
+ merror("%s: ERROR: Unable to read certificate file (not found): %s", ARGV0, cert);
+ return 0;
}
- /* Load our keys and certificates*/
- if(!(SSL_CTX_use_certificate_chain_file(ctx, certf)))
- {
- merror("%s: ERROR: Unable to read certificate file: %s", ARGV0, certf);
+ if (!(SSL_CTX_use_certificate_chain_file(ctx, cert))) {
+ merror("%s: ERROR: Unable to read certificate file: %s", ARGV0, cert);
ERR_print_errors_fp(stderr);
- return(NULL);
+ return 0;
}
- if(!(SSL_CTX_use_PrivateKey_file(ctx, keyf, SSL_FILETYPE_PEM)))
- {
- merror("%s: ERROR: Unable to read private key file: %s", ARGV0, keyf);
- return(NULL);
+ if (!(SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM))) {
+ merror("%s: ERROR: Unable to read private key file: %s", ARGV0, key);
+ ERR_print_errors_fp(stderr);
+ return 0;
}
- if (!SSL_CTX_check_private_key(ctx))
- {
+ if (!SSL_CTX_check_private_key(ctx)) {
merror("%s: ERROR: Unable to verify private key file", ARGV0);
- return(NULL);
+ ERR_print_errors_fp(stderr);
+ return 0;
}
+#if(OPENSSL_VERSION_NUMBER < 0x00905100L)
+ SSL_CTX_set_verify_depth(ctx, 1);
+#endif
- #if(OPENSSL_VERSION_NUMBER < 0x00905100L)
- SSL_CTX_set_verify_depth(ctx,1);
- #endif
+ return 1;
+}
- return ctx;
+int load_ca_cert(SSL_CTX *ctx, const char *ca_cert)
+{
+ if (!ca_cert) {
+ merror("%s: ERROR: Verification requested but no CA certificate file specified", ARGV0);
+ return 0;
+ }
+
+ if (SSL_CTX_load_verify_locations(ctx, ca_cert, NULL) != 1) {
+ merror("%s: ERROR: Unable to read CA certificate file \"%s\"", ARGV0, ca_cert);
+ return 0;
+ }
+
+ return 1;
}
+/* No extra verification is done here. This function provides more
+ * information in the case that certificate verification fails
+ * for any reason.
+ */
+int verify_callback(int ok, X509_STORE_CTX *store)
+{
+ char data[256];
+
+ if (!ok) {
+ X509 *cert = X509_STORE_CTX_get_current_cert(store);
+ int depth = X509_STORE_CTX_get_error_depth(store);
+ int err = X509_STORE_CTX_get_error(store);
-#endif
+ merror("%s: ERROR: Problem with certificate at depth %i", ARGV0, depth);
+
+ X509_NAME_oneline(X509_get_issuer_name(cert), data, 256);
+ merror("%s: ERROR: issuer = %s", ARGV0, data);
+
+ X509_NAME_oneline(X509_get_subject_name(cert), data, 256);
+ merror("%s: ERROR: subject = %s", ARGV0, data);
+
+ merror("%s: ERROR: %i:%s", ARGV0, err, X509_verify_cert_error_string(err));
+ }
+
+ return ok;
+}
+
+#endif /* LIBOPENSSL_ENABLED */
-/* EOF */