new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / os_auth / ssl.c
old mode 100755 (executable)
new mode 100644 (file)
index 9841861..c9b017c
@@ -1,6 +1,3 @@
-/* @(#) $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 */