<commit_before>//
// Copyright (C) 2005-2006 SIPez LLC.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// Copyright (C) 2004-2006 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// Copyright (C) 2004-2006 Pingtel Corp.  All rights reserved.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// $$
///////////////////////////////////////////////////////////////////////////////

#if defined(HAVE_SSL)

#ifdef _WIN32
#  define WIN32_LEAN_AND_MEAN
#endif

// SYSTEM INCLUDES
#include <openssl/rand.h>
#include <openssl/x509v3.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

// APPLICATION INCLUDES
#include "os/OsDefs.h"
#include "os/OsSSL.h"
#include "os/OsLock.h"
#include "os/OsSysLog.h"
#include "utl/UtlString.h"
#include "utl/UtlSList.h"

#ifndef SIPX_CONFDIR
#  define SIPX_CONFDIR "."
#endif

// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
//#define TEST_DEBUG
const char* defaultPublicCertificateFile = SIPX_CONFDIR "/ssl/ssl.crt";
const char* defaultPrivateKeyFile        = SIPX_CONFDIR "/ssl/ssl.key";

const char* defaultAuthorityPath         = SIPX_CONFDIR "/ssl/authorities";

bool OsSSL::sInitialized = false;

OsBSem OsSSL::m_sInstanceLock(OsBSem::Q_PRIORITY, OsBSem::FULL);
OsSSL* OsSSL::m_spInstance = NULL;
UtlString OsSSL::m_sCaPath = NULL;
UtlString OsSSL::m_sCaFile = NULL;
UtlString OsSSL::m_sCertificateFile = NULL;
UtlString OsSSL::m_sPrivateKeyFile = NULL;
UtlString OsSSL::m_sPassword = NULL;

OsSSLDestructor OsSSLDestructor::m_sInstance;

/* //////////////////////////// PUBLIC //////////////////////////////////// */


/* ============================ CREATORS ================================== */

// Constructor

OsSSL::OsSSL()
{
   if (!sInitialized)
   {
      sInitialized = true;

      // Initialize random number generator before using SSL

      // TODO: this is a bad way to do this - it may need to be fixed.
      //
      //       We should be using better randomness if possible, but at the very
      //       least we should be saving the current rand state in a file so that
      //       is not reset each time.  I think that on a modern Linux, this has
      //       no effect because OpenSSL will use /dev/urandom internally anyway?
      //
      // This needs to be examined.

      /* make a random number and set the top and bottom bits */
      int seed[32];
      for (unsigned int i = 0; i < sizeof(seed) / sizeof(int); i++)
      {
         seed[i] = rand();
      }

      RAND_seed(seed, sizeof(seed));
      int res = RAND_status();
      if (res)
      {
         // not enough randomness in PRNG
         OsSysLog::add(FAC_KERNEL, PRI_ERR, "OsSSL::_ Not enough randomness in PRNG");
      }

      SSLeay_add_ssl_algorithms();

      // It is suggested by the OpenSSL group that embedded systems
      // only enable loading of error strings when debugging.
      // Perhaps this should be conditional?
      SSL_load_error_strings();
      
      mCTX = SSL_CTX_new(SSLv23_method());

      if (mCTX)
      {
         // set password callback
         SSL_CTX_set_default_passwd_cb(mCTX, pem_passwd_cb);

         UtlString caPath = m_sCaPath.data() ? m_sCaPath.data() : defaultAuthorityPath;
         if (SSL_CTX_load_verify_locations(mCTX,
                                           m_sCaFile.data(),
                                           caPath.data()) > 0)
         {
            UtlString certFile = m_sCertificateFile.data() ? m_sCertificateFile.data() : defaultPublicCertificateFile;
            if (SSL_CTX_use_certificate_file(mCTX,
                                             certFile.data(),
                                             SSL_FILETYPE_PEM) > 0)
            {
               UtlString keyFile = m_sPrivateKeyFile.data() ? m_sPrivateKeyFile.data() : defaultPrivateKeyFile;
               if (SSL_CTX_use_PrivateKey_file(mCTX,
                                               keyFile.data(),
                                               SSL_FILETYPE_PEM) > 0)
               {
                  if (SSL_CTX_check_private_key(mCTX))
                  {
                     // check successful, private key ok
                     OsSysLog::add(FAC_KERNEL, PRI_INFO
                                   ,"OsSSL::_ %p CTX %p loaded key pair:\n"
                                   "   public  '%s'\n"
                                   "   private '%s'"
                                   ,this, mCTX,
                                   certFile.data(),
                                   keyFile.data());

                     // TODO: log our own certificate data

                     // Establish verification rules
                     SSL_CTX_set_verify(mCTX,
                                        SSL_VERIFY_PEER + SSL_VERIFY_CLIENT_ONCE,
                                        verifyCallback
                                        );
                     
                     // disable server connection caching
                     // TODO: Investigate turning this on...<commit_msg>Few fixes in OsSSL.<commit_after>//
// Copyright (C) 2005-2006 SIPez LLC.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// Copyright (C) 2004-2006 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// Copyright (C) 2004-2006 Pingtel Corp.  All rights reserved.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// $$
///////////////////////////////////////////////////////////////////////////////

#if defined(HAVE_SSL)

#ifdef _WIN32
#  define WIN32_LEAN_AND_MEAN
#endif

// SYSTEM INCLUDES
#include <openssl/rand.h>
#include <openssl/x509v3.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

// APPLICATION INCLUDES
#include "os/OsDefs.h"
#include "os/OsSSL.h"
#include "os/OsLock.h"
#include "os/OsSysLog.h"
#include "utl/UtlString.h"
#include "utl/UtlSList.h"

#ifndef SIPX_CONFDIR
#  define SIPX_CONFDIR "."
#endif

// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
//#define TEST_DEBUG
const char* defaultPublicCertificateFile = SIPX_CONFDIR "/ssl/ssl.crt";
const char* defaultPrivateKeyFile        = SIPX_CONFDIR "/ssl/ssl.key";

const char* defaultAuthorityPath         = SIPX_CONFDIR "/ssl/authorities";

bool OsSSL::sInitialized = false;

OsBSem OsSSL::m_sInstanceLock(OsBSem::Q_PRIORITY, OsBSem::FULL);
OsSSL* OsSSL::m_spInstance = NULL;
UtlString OsSSL::m_sCaPath = NULL;
UtlString OsSSL::m_sCaFile = NULL;
UtlString OsSSL::m_sCertificateFile = NULL;
UtlString OsSSL::m_sPrivateKeyFile = NULL;
UtlString OsSSL::m_sPassword = NULL;

OsSSLDestructor OsSSLDestructor::m_sInstance;

/* //////////////////////////// PUBLIC //////////////////////////////////// */


/* ============================ CREATORS ================================== */

// Constructor

OsSSL::OsSSL()
{
   if (!sInitialized)
   {
      sInitialized = true;

      // Initialize random number generator before using SSL

      // TODO: this is a bad way to do this - it may need to be fixed.
      //
      //       We should be using better randomness if possible, but at the very
      //       least we should be saving the current rand state in a file so that
      //       is not reset each time.  I think that on a modern Linux, this has
      //       no effect because OpenSSL will use /dev/urandom internally anyway?
      //
      // This needs to be examined.

      /* make a random number and set the top and bottom bits */
      int seed[32];
      for (unsigned int i = 0; i < sizeof(seed) / sizeof(int); i++)
      {
         seed[i] = rand();
      }

      RAND_seed(seed, sizeof(seed));
      int res = RAND_status();
      if (!res)
      {
         // not enough randomness in PRNG
         OsSysLog::add(FAC_KERNEL, PRI_ERR, "OsSSL::_ Not enough randomness in PRNG");
      }

      SSLeay_add_ssl_algorithms();

      // It is suggested by the OpenSSL group that embedded systems
      // only enable loading of error strings when debugging.
      // Perhaps this should be conditional?
      SSL_load_error_strings();
      
      mCTX = SSL_CTX_new(SSLv23_method());

      if (mCTX)
      {
         // set password callback
         SSL_CTX_set_default_passwd_cb(mCTX, pem_passwd_cb);

         UtlString caPath = !m_sCaPath.isNull() ? m_sCaPath.data() : defaultAuthorityPath;
         if (SSL_CTX_load_verify_locations(mCTX,
                                           !m_sCaFile.isNull() ? m_sCaFile.data() : NULL,
                                           caPath.data()) > 0)
         {
            UtlString certFile = !m_sCertificateFile.isNull() ? m_sCertificateFile.data() : defaultPublicCertificateFile;
            if (SSL_CTX_use_certificate_file(mCTX,
                                             certFile.data(),
                                             SSL_FILETYPE_PEM) > 0)
            {
               UtlString keyFile = !m_sPrivateKeyFile.isNull() ? m_sPrivateKeyFile.data() : defaultPrivateKeyFile;
               if (SSL_CTX_use_PrivateKey_file(mCTX,
                                               keyFile.data(),
                                               SSL_FILETYPE_PEM) > 0)
               {
                  if (SSL_CTX_check_private_key(mCTX))
                  {
                     // check successful, private key ok
                     OsSysLog::add(FAC_KERNEL, PRI_INFO
                                   ,"OsSSL::_ %p CTX %p loaded key pair:\n"
                                   "   public  '%s'\n"
                                   "   private '%s'"
                                   ,this, mCTX,
                                   certFile.data(),
                                   keyFile.data());

                     // TODO: log our own certificate data

                     // Establish verification rules
                     SSL_CTX_set_verify(mCTX,
                                        SSL_VERIFY_PEER + SSL_VERIFY_CLIENT_ONCE,
                                        verifyCallback
                                        );
                     
                     // disable server connection caching
                     // TODO: Investigate turning this on...
{'fraction_non_alphanumeric': 0.12935372471632955, 'fraction_numerical': 0.007893438579181056, 'mean_word_length': 1.5857142857142856, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 42, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2201963', 'n_tokens_mistral': 2938, 'n_tokens_neox': 2790, 'n_words': 728}