additional cipher validation on startup; debug output in crypto functions
authorVictor Kirhenshtein <victor@netxms.org>
Sun, 29 Dec 2013 21:37:03 +0000 (23:37 +0200)
committerVictor Kirhenshtein <victor@netxms.org>
Sun, 29 Dec 2013 21:37:03 +0000 (23:37 +0200)
14 files changed:
include/nxcpapi.h
src/agent/core/nxagentd.cpp
src/agent/core/nxagentd.h
src/agent/core/tools.cpp
src/libnetxms/crypto.cpp
src/libnxcl/main.cpp
src/nxcproxy/nxcproxy.cpp
src/nxcproxy/nxcproxy.h
src/nxcproxy/tools.cpp
src/server/core/main.cpp
src/server/tools/nxaction/nxaction.cpp
src/server/tools/nxap/nxap.cpp
src/server/tools/nxget/nxget.cpp
src/server/tools/nxupload/nxupload.cpp

index 16b6c03..af57a8c 100644 (file)
@@ -235,7 +235,7 @@ BOOL LIBNETXMS_EXPORTABLE SendFileOverNXCP(SOCKET hSocket, UINT32 dwId, const TC
                                                                                                                 MUTEX mutex);
 BOOL LIBNETXMS_EXPORTABLE NXCPGetPeerProtocolVersion(SOCKET hSocket, int *pnVersion, MUTEX mutex);
    
-BOOL LIBNETXMS_EXPORTABLE InitCryptoLib(UINT32 dwEnabledCiphers);
+BOOL LIBNETXMS_EXPORTABLE InitCryptoLib(UINT32 dwEnabledCiphers, void (*debugCallback)(int, const TCHAR *, va_list args));
 UINT32 LIBNETXMS_EXPORTABLE CSCPGetSupportedCiphers();
 CSCP_ENCRYPTED_MESSAGE LIBNETXMS_EXPORTABLE *CSCPEncryptMessage(NXCPEncryptionContext *pCtx, CSCP_MESSAGE *pMsg);
 BOOL LIBNETXMS_EXPORTABLE CSCPDecryptMessage(NXCPEncryptionContext *pCtx,
index 93172c5..e4a22d4 100644 (file)
@@ -549,20 +549,6 @@ static bool SendFileToServer(void *session, UINT32 requestId, const TCHAR *file,
        return ((CommSession *)session)->sendFile(requestId, file, offset);
 }
 
-/**
- * Debug callback for DB library
- */
-static void DBLibraryDebugCallback(int level, const TCHAR *format, va_list args)
-{
-       if (level <= (int)g_debugLevel)
-       {
-      TCHAR buffer[4096];
-
-      _vsntprintf(buffer, 4096, format, args);
-      nxlog_write(MSG_DEBUG, EVENTLOG_DEBUG_TYPE, "s", buffer);
-       }
-}
-
 /**
  * Parser server list
  */
@@ -699,7 +685,7 @@ BOOL Initialize()
    DebugPrintf(INVALID_INDEX, 1, _T("Subagent API initialized"));
 
    // Initialize cryptografy
-   if (!InitCryptoLib(m_dwEnabledCiphers))
+   if (!InitCryptoLib(m_dwEnabledCiphers, DebugPrintfCallback))
    {
       nxlog_write(MSG_INIT_CRYPTO_FAILED, EVENTLOG_ERROR_TYPE, "e", WSAGetLastError());
       return FALSE;
@@ -742,7 +728,7 @@ BOOL Initialize()
              nxlog_write(MSG_WAITFORPROCESS_FAILED, EVENTLOG_ERROR_TYPE, "s", m_szProcessToWait);
        }
 
-       DBSetDebugPrintCallback(DBLibraryDebugCallback);
+       DBSetDebugPrintCallback(DebugPrintfCallback);
        DBInit(MSG_DB_LIBRARY, MSG_SQL_ERROR);
 
        // Load other subagents
index f1f8e26..4821ffd 100644 (file)
@@ -372,6 +372,7 @@ void Shutdown();
 void Main();
 void ConsolePrintf(const TCHAR *pszFormat, ...);
 void DebugPrintf(UINT32 dwSessionId, int level, const TCHAR *pszFormat, ...);
+void DebugPrintfCallback(int level, const TCHAR *pszFormat, va_list args);
 
 void BuildFullPath(TCHAR *pszFileName, TCHAR *pszFullPath);
 
index bccca90..23d1eb7 100644 (file)
@@ -59,6 +59,19 @@ void DebugPrintf(UINT32 dwSessionId, int level, const TCHAR *pszFormat, ...)
    }
 }
 
+/**
+ * Print debug messages - callback for libraries
+ */
+void DebugPrintfCallback(int level, const TCHAR *pszFormat, va_list args)
+{
+   if (level <= (int)g_debugLevel)
+   {
+      TCHAR szBuffer[4096];
+      _vsntprintf(szBuffer, 4096, pszFormat, args);
+      nxlog_write(MSG_DEBUG, EVENTLOG_DEBUG_TYPE, "s", szBuffer);
+   }
+}
+
 /**
  * Build full path for file in file store
  */
index 4ddd543..aac91fc 100644 (file)
@@ -58,7 +58,7 @@ static UINT32 m_dwSupportedCiphers =
 #ifdef _WITH_ENCRYPTION
 
 typedef OPENSSL_CONST EVP_CIPHER * (*CIPHER_FUNC)();
-static CIPHER_FUNC m_pfCipherList[NETXMS_MAX_CIPHERS] =
+static CIPHER_FUNC s_ciphers[NETXMS_MAX_CIPHERS] =
 {
 #ifndef OPENSSL_NO_AES
    EVP_aes_256_cbc,
@@ -91,8 +91,10 @@ static CIPHER_FUNC m_pfCipherList[NETXMS_MAX_CIPHERS] =
    NULL
 #endif
 };
-static WORD m_wNoEncryptionFlag = 0;
-static MUTEX *m_pCryptoMutexList = NULL;
+static const TCHAR *s_cipherNames[NETXMS_MAX_CIPHERS] = { _T("AES-256"), _T("Blowfish-256"), _T("IDEA"), _T("3DES"), _T("AES-128"), _T("Blowfish-128") };
+static WORD s_noEncryptionFlag = 0;
+static MUTEX *s_cryptoMutexList = NULL;
+static void (*s_debugCallback)(int, const TCHAR *, va_list args) = NULL;
 
 /**
  * Locking callback for CRYPTO library
@@ -100,9 +102,9 @@ static MUTEX *m_pCryptoMutexList = NULL;
 static void CryptoLockingCallback(int nMode, int nLock, const char *pszFile, int nLine)
 {
    if (nMode & CRYPTO_LOCK)
-      MutexLock(m_pCryptoMutexList[nLock]);
+      MutexLock(s_cryptoMutexList[nLock]);
    else
-      MutexUnlock(m_pCryptoMutexList[nLock]);
+      MutexUnlock(s_cryptoMutexList[nLock]);
 }
 
 /**
@@ -119,11 +121,27 @@ static unsigned long CryptoIdCallback()
 
 #endif   /* _WITH_ENCRYPTION */
 
+/**
+ * Debug output
+ */
+static void CryptoDbgPrintf(int level, const TCHAR *format, ...)
+{
+   if (s_debugCallback == NULL)
+      return;
+
+   va_list args;
+   va_start(args, format);
+   s_debugCallback(level, format, args);
+   va_end(args);
+}
+
 /**
  * Initialize OpenSSL library
  */
-BOOL LIBNETXMS_EXPORTABLE InitCryptoLib(UINT32 dwEnabledCiphers)
+BOOL LIBNETXMS_EXPORTABLE InitCryptoLib(UINT32 dwEnabledCiphers, void (*debugCallback)(int, const TCHAR *, va_list args))
 {
+   s_debugCallback = debugCallback;
+
 #ifdef _WITH_ENCRYPTION
    BYTE random[8192];
    int i;
@@ -132,15 +150,38 @@ BOOL LIBNETXMS_EXPORTABLE InitCryptoLib(UINT32 dwEnabledCiphers)
    ERR_load_CRYPTO_strings();
    OpenSSL_add_all_algorithms();
    RAND_seed(random, 8192);
-   m_dwSupportedCiphers &= dwEnabledCiphers;
-   m_wNoEncryptionFlag = htons(MF_DONT_ENCRYPT);
-   m_pCryptoMutexList = (MUTEX *)malloc(sizeof(MUTEX) * CRYPTO_num_locks());
+   s_noEncryptionFlag = htons(MF_DONT_ENCRYPT);
+   s_cryptoMutexList = (MUTEX *)malloc(sizeof(MUTEX) * CRYPTO_num_locks());
    for(i = 0; i < CRYPTO_num_locks(); i++)
-      m_pCryptoMutexList[i] = MutexCreate();
+      s_cryptoMutexList[i] = MutexCreate();
    CRYPTO_set_locking_callback(CryptoLockingCallback);
 #ifndef _WIN32
    CRYPTO_set_id_callback(CryptoIdCallback);
 #endif   /* _WIN32 */
+
+   // validate supported ciphers
+   m_dwSupportedCiphers &= dwEnabledCiphers;
+   UINT32 cipherBit = 1;
+   for(i = 0; i < NETXMS_MAX_CIPHERS; i++, cipherBit = cipherBit << 1)
+   {
+      if ((m_dwSupportedCiphers & cipherBit) == 0)
+         continue;
+      NXCPEncryptionContext *ctx = NXCPEncryptionContext::create(cipherBit);
+      if (ctx != NULL)
+      {
+         delete ctx;
+      }
+      else
+      {
+         m_dwSupportedCiphers &= ~cipherBit;
+         CryptoDbgPrintf(1, _T("Cipher %s disabled"), s_cipherNames[i]);
+      }
+   }
+
+   CryptoDbgPrintf(1, _T("Crypto library initialized"));
+
+#else
+   CryptoDbgPrintf(1, _T("Crypto library will not be initialized because libnetxms was built without encryption support"));
 #endif   /* _WITH_ENCRYPTION */
    return TRUE;
 }
@@ -218,7 +259,7 @@ UINT32 LIBNETXMS_EXPORTABLE SetupEncryptionContext(CSCPMessage *pMsg,
             (*ppResponse)->SetVariable(VID_SESSION_KEY, ucKeyBuffer, (UINT32)size);
             (*ppResponse)->SetVariable(VID_KEY_LENGTH, (WORD)(*ppCtx)->getKeyLength());
             
-            int ivLength = EVP_CIPHER_iv_length(m_pfCipherList[(*ppCtx)->getCipher()]());
+            int ivLength = EVP_CIPHER_iv_length(s_ciphers[(*ppCtx)->getCipher()]());
             if ((ivLength <= 0) || (ivLength > EVP_MAX_IV_LENGTH))
                ivLength = EVP_MAX_IV_LENGTH;
             size = RSA_public_encrypt(ivLength, (*ppCtx)->getIV(), ucKeyBuffer, pServerKey, RSA_PKCS1_OAEP_PADDING);
@@ -370,8 +411,7 @@ BOOL LIBNETXMS_EXPORTABLE SignMessageWithCAPI(BYTE *pMsg, UINT32 dwMsgLen, const
        HCRYPTHASH hHash;
        BYTE *pTemp;
 
-       if (CryptAcquireCertificatePrivateKey(pCert, CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
-                                                  NULL, &hProv, &dwKeySpec, &bFreeProv))
+       if (CryptAcquireCertificatePrivateKey(pCert, CRYPT_ACQUIRE_COMPARE_KEY_FLAG, NULL, &hProv, &dwKeySpec, &bFreeProv))
        {
                if (CryptCreateHash(hProv, CALG_SHA1, NULL, 0, &hHash))
                {
@@ -496,27 +536,31 @@ NXCPEncryptionContext *NXCPEncryptionContext::create(CSCPMessage *msg, RSA *priv
             dwKeySize = msg->GetVariableBinary(VID_SESSION_IV, ucKeyBuffer, KEY_BUFFER_SIZE);
             nSize = RSA_private_decrypt(dwKeySize, ucKeyBuffer, ucSessionKey, privateKey, RSA_PKCS1_OAEP_PADDING);
             if ((nSize == nIVLen) &&
-                (nIVLen <= EVP_CIPHER_iv_length(m_pfCipherList[ctx->m_cipher]())))
+                (nIVLen <= EVP_CIPHER_iv_length(s_ciphers[ctx->m_cipher]())))
             {
                memcpy(ctx->m_iv, ucSessionKey, min(EVP_MAX_IV_LENGTH, nIVLen));
             }
             else
             {
+               CryptoDbgPrintf(6, _T("NXCPEncryptionContext::create: IV decryption failed"));
                delete_and_null(ctx);
             }
          }
          else
          {
+            CryptoDbgPrintf(6, _T("NXCPEncryptionContext::create: session key decryption failed"));
             delete_and_null(ctx);
          }
       }
       else
       {
+         CryptoDbgPrintf(6, _T("NXCPEncryptionContext::create: key length mismatch (remote: %d local: %d)"), (int)msg->GetVariableShort(VID_KEY_LENGTH), ctx->m_keyLength);
          delete_and_null(ctx);
       }
    }
    else
    {
+      CryptoDbgPrintf(6, _T("NXCPEncryptionContext::create: initCipher(%d) call failed"), cipher);
       delete_and_null(ctx);
    }
        return ctx;
@@ -531,12 +575,12 @@ NXCPEncryptionContext *NXCPEncryptionContext::create(CSCPMessage *msg, RSA *priv
 bool NXCPEncryptionContext::initCipher(int cipher)
 {
 #ifdef _WITH_ENCRYPTION
-   if (m_pfCipherList[cipher] == NULL)
+   if (s_ciphers[cipher] == NULL)
       return false;   // Unsupported cipher
 
-   if (!EVP_EncryptInit_ex(&m_encryptor, m_pfCipherList[cipher](), NULL, NULL, NULL))
+   if (!EVP_EncryptInit_ex(&m_encryptor, s_ciphers[cipher](), NULL, NULL, NULL))
       return false;
-   if (!EVP_DecryptInit_ex(&m_decryptor, m_pfCipherList[cipher](), NULL, NULL, NULL))
+   if (!EVP_DecryptInit_ex(&m_decryptor, s_ciphers[cipher](), NULL, NULL, NULL))
       return false;
 
    switch(cipher)
@@ -566,6 +610,11 @@ bool NXCPEncryptionContext::initCipher(int cipher)
    if (!EVP_CIPHER_CTX_set_key_length(&m_encryptor, m_keyLength) || !EVP_CIPHER_CTX_set_key_length(&m_decryptor, m_keyLength))
       return false;
 
+   // This check is needed because at least some OpenSSL versions return no error
+   // from EVP_CIPHER_CTX_set_key_length but still not change key length
+   if ((EVP_CIPHER_CTX_key_length(&m_encryptor) != m_keyLength) || (EVP_CIPHER_CTX_key_length(&m_decryptor) != m_keyLength))
+      return false;
+
    m_cipher = cipher;
    return true;
 #else
@@ -634,7 +683,7 @@ NXCPEncryptionContext *NXCPEncryptionContext::create(UINT32 ciphers)
  */
 CSCP_ENCRYPTED_MESSAGE *NXCPEncryptionContext::encryptMessage(CSCP_MESSAGE *msg)
 {
-   if (msg->wFlags & m_wNoEncryptionFlag)
+   if (msg->wFlags & s_noEncryptionFlag)
       return (CSCP_ENCRYPTED_MESSAGE *)nx_memdup(msg, ntohl(msg->dwSize));
 
 #ifdef _WITH_ENCRYPTION
index 438e1a8..848c4bb 100644 (file)
@@ -33,15 +33,28 @@ NXC_DEBUG_CALLBACK g_pDebugCallBack = NULL;
  */
 void DebugPrintf(const TCHAR *format, ...)
 {
+   if (g_pDebugCallBack == NULL)
+      return;
+
    va_list args;
    TCHAR buffer[4096];
 
+   va_start(args, format);
+   _vsntprintf(buffer, 4096, format, args);
+   va_end(args);
+   g_pDebugCallBack(buffer);
+}
+
+/**
+ * Debug callback for crypto lib
+ */
+static void CryptoLibDebugCallback(int level, const TCHAR *format, va_list args)
+{
    if (g_pDebugCallBack == NULL)
       return;
 
-   va_start(args, format);
+   TCHAR buffer[4096];
    _vsntprintf(buffer, 4096, format, args);
-   va_end(args);
    g_pDebugCallBack(buffer);
 }
 
@@ -50,7 +63,7 @@ void DebugPrintf(const TCHAR *format, ...)
  */
 BOOL LIBNXCL_EXPORTABLE NXCInitialize()
 {
-   return InitCryptoLib(0xFFFF);
+   return InitCryptoLib(0xFFFF, CryptoLibDebugCallback);
 }
 
 /**
index d39eae9..f0f48eb 100644 (file)
@@ -232,7 +232,7 @@ bool Initialize()
 #endif
 
    // Initialize cryptografy
-   if (!InitCryptoLib(0xFFFF))
+   if (!InitCryptoLib(0xFFFF, DebugPrintf2))
    {
       nxlog_write(MSG_INIT_CRYPTO_FAILED, EVENTLOG_ERROR_TYPE, "e", WSAGetLastError());
       return false;
index 6b77aae..f2cae7f 100644 (file)
@@ -96,6 +96,7 @@ void Shutdown();
 
 void ConsolePrintf(const TCHAR *pszFormat, ...);
 void DebugPrintf(int level, const TCHAR *pszFormat, ...);
+void DebugPrintf2(int level, const TCHAR *pszFormat, va_list args);
 
 #ifdef _WIN32
 
index 62b3c77..55d9b35 100644 (file)
@@ -54,3 +54,16 @@ void DebugPrintf(int level, const TCHAR *pszFormat, ...)
       nxlog_write(MSG_DEBUG, EVENTLOG_DEBUG_TYPE, "s", szBuffer);
    }
 }
+
+/**
+ * Print debug messages
+ */
+void DebugPrintf2(int level, const TCHAR *pszFormat, va_list args)
+{
+   if (level <= (int)g_debugLevel)
+   {
+      TCHAR szBuffer[4096];
+      _vsntprintf(szBuffer, 4096, pszFormat, args);
+      nxlog_write(MSG_DEBUG, EVENTLOG_DEBUG_TYPE, "s", szBuffer);
+   }
+}
index c28ea5b..80e2679 100644 (file)
@@ -370,7 +370,7 @@ static BOOL InitCryptografy()
        UINT32 dwLen;
        BYTE *pBufPos, *pKeyBuffer, hash[SHA1_DIGEST_SIZE];
 
-       if (!InitCryptoLib(ConfigReadULong(_T("AllowedCiphers"), 0x1F)))
+   if (!InitCryptoLib(ConfigReadULong(_T("AllowedCiphers"), 0x7F), DbgPrintf2))
                return FALSE;
 
    SSL_library_init();
index 63ff9c9..1033904 100644 (file)
@@ -205,7 +205,7 @@ int main(int argc, char *argv[])
 #ifdef _WITH_ENCRYPTION
       if ((iEncryptionPolicy != ENCRYPTION_DISABLED) && bStart)
       {
-         if (InitCryptoLib(0xFFFF))
+         if (InitCryptoLib(0xFFFF, NULL))
          {
             pServerKey = LoadRSAKeys(szKeyFile);
             if (pServerKey == NULL)
index 83b7f3a..9612f83 100644 (file)
@@ -275,7 +275,7 @@ int main(int argc, char *argv[])
 #ifdef _WITH_ENCRYPTION
       if ((iEncryptionPolicy != ENCRYPTION_DISABLED) && bStart)
       {
-         if (InitCryptoLib(0xFFFF))
+         if (InitCryptoLib(0xFFFF, NULL))
          {
             pServerKey = LoadRSAKeys(szKeyFile);
             if (pServerKey == NULL)
index 7a3b8e1..878dca9 100644 (file)
@@ -555,7 +555,7 @@ int main(int argc, char *argv[])
 #ifdef _WITH_ENCRYPTION
       if ((iEncryptionPolicy != ENCRYPTION_DISABLED) && bStart)
       {
-         if (InitCryptoLib(0xFFFF))
+         if (InitCryptoLib(0xFFFF, NULL))
          {
             pServerKey = LoadRSAKeys(szKeyFile);
             if (pServerKey == NULL)
index d8f8e83..12fb4d2 100644 (file)
@@ -307,7 +307,7 @@ int main(int argc, char *argv[])
 #ifdef _WITH_ENCRYPTION
       if ((iEncryptionPolicy != ENCRYPTION_DISABLED) && bStart)
       {
-         if (InitCryptoLib(0xFFFF))
+         if (InitCryptoLib(0xFFFF, NULL))
          {
             pServerKey = LoadRSAKeys(szKeyFile);
             if (pServerKey == NULL)