Encryption between server and agent fully working
authorVictor Kirhenshtein <victor@netxms.org>
Sun, 19 Jun 2005 21:39:22 +0000 (21:39 +0000)
committerVictor Kirhenshtein <victor@netxms.org>
Sun, 19 Jun 2005 21:39:22 +0000 (21:39 +0000)
include/nms_agent.h
include/nxcscpapi.h
src/agent/core/session.cpp
src/server/core/admin.cpp
src/server/include/nxsrvapi.h
src/server/libnxsrv/agent.cpp
src/server/libnxsrv/main.cpp
src/server/tools/nxaction/nxaction.cpp
src/server/tools/nxget/nxget.cpp
src/server/tools/nxupload/nxupload.cpp

index 78628e3..6e3d082 100644 (file)
@@ -65,6 +65,7 @@
 #define ERR_NO_CIPHERS              ((DWORD)907)
 #define ERR_INVALID_PUBLIC_KEY      ((DWORD)908)
 #define ERR_INVALID_SESSION_KEY     ((DWORD)909)
+#define ERR_CONNECT_FAILED          ((DWORD)910)
 
 
 //
index 6fe3c11..cf2fbab 100644 (file)
@@ -178,13 +178,14 @@ extern "C" {
 
 int LIBNXCSCP_EXPORTABLE RecvCSCPMessage(SOCKET hSocket, CSCP_MESSAGE *pMsg,
                                          CSCP_BUFFER *pBuffer, DWORD dwMaxMsgSize,
-                                         CSCP_ENCRYPTION_CONTEXT *pCtx, 
+                                         CSCP_ENCRYPTION_CONTEXT **ppCtx,
                                          BYTE *pDecryptionBuffer);
 CSCP_MESSAGE LIBNXCSCP_EXPORTABLE *CreateRawCSCPMessage(WORD wCode, DWORD dwId,
                                                         DWORD dwDataSize, void *pData,
                                                         CSCP_MESSAGE *pBuffer);
 TCHAR LIBNXCSCP_EXPORTABLE *CSCPMessageCodeName(WORD wCode, TCHAR *pszBuffer);
-BOOL LIBNXCSCP_EXPORTABLE SendFileOverCSCP(SOCKET hSocket, DWORD dwId, TCHAR *pszFile);
+BOOL LIBNXCSCP_EXPORTABLE SendFileOverCSCP(SOCKET hSocket, DWORD dwId, TCHAR *pszFile,
+                                           CSCP_ENCRYPTION_CONTEXT *pCtx);
    
 BOOL LIBNXCSCP_EXPORTABLE InitCryptoLib(DWORD dwEnabledCiphers);
 CSCP_ENCRYPTED_MESSAGE LIBNXCSCP_EXPORTABLE 
index 8492922..b0b2f20 100644 (file)
@@ -149,7 +149,7 @@ void CommSession::ReadThread(void)
    while(1)
    {
       if ((iErr = RecvCSCPMessage(m_hSocket, pRawMsg, m_pMsgBuffer, RAW_MSG_SIZE,
-                                  m_pCtx, pDecryptionBuffer)) <= 0)
+                                  &m_pCtx, pDecryptionBuffer)) <= 0)
          break;
 
       // Check if message is too large
@@ -220,6 +220,7 @@ void CommSession::ReadThread(void)
          pMsg = new CSCPMessage(pRawMsg);
          if (pMsg->GetCode() == CMD_REQUEST_SESSION_KEY)
          {
+            DebugPrintf("Received message %s", CSCPMessageCodeName(pMsg->GetCode(), szBuffer));
             if (m_pCtx == NULL)
             {
                CSCPMessage *pResponce;
index 60df1d9..05e6280 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: admin.cpp,v 1.10 2005-06-19 19:20:40 victor Exp $ */
+/* $Id: admin.cpp,v 1.11 2005-06-19 21:39:20 victor Exp $ */
 
 /* 
 ** NetXMS - Network Management System
@@ -46,6 +46,7 @@ static THREAD_RESULT THREAD_CALL ProcessingThread(void *pArg)
    CSCPMessage *pRequest, responce;
    TCHAR szCmd[256];
    struct __console_ctx ctx;
+   static CSCP_ENCRYPTION_CONTEXT *pDummyCtx = NULL;
 
    pRawMsg = (CSCP_MESSAGE *)malloc(MAX_MSG_SIZE);
    pRecvBuffer = (CSCP_BUFFER *)malloc(sizeof(CSCP_BUFFER));
@@ -55,7 +56,7 @@ static THREAD_RESULT THREAD_CALL ProcessingThread(void *pArg)
 
    while(1)
    {
-      iError = RecvCSCPMessage(sock, pRawMsg, pRecvBuffer, MAX_MSG_SIZE, NULL, NULL);
+      iError = RecvCSCPMessage(sock, pRawMsg, pRecvBuffer, MAX_MSG_SIZE, &pDummyCtx, NULL);
       if (iError <= 0)
          break;   // Communication error or closed connection
 
@@ -163,6 +164,10 @@ THREAD_RESULT THREAD_CALL LocalAdminListener(void *pArg)
 /*
 
 $Log: not supported by cvs2svn $
+Revision 1.10  2005/06/19 19:20:40  victor
+- Added encryption foundation
+- Encryption between server and agent almost working
+
 Revision 1.9  2005/04/07 15:50:58  victor
 - Implemented save and restore for DCI graph windows
 - More commands added to server console
index d1cde5f..b3ed87a 100644 (file)
@@ -201,7 +201,7 @@ public:
    AgentConnection(DWORD dwAddr, WORD wPort = AGENT_LISTEN_PORT, int iAuthMethod = AUTH_NONE, TCHAR *szSecret = NULL);
    ~AgentConnection();
 
-   BOOL Connect(RSA *pServerKey = NULL, BOOL bVerbose = FALSE);
+   BOOL Connect(RSA *pServerKey = NULL, BOOL bVerbose = FALSE, DWORD *pdwError = NULL);
    void Disconnect(void);
    BOOL IsConnected(void) { return m_bIsConnected; }
 
index 127de0b..564563f 100644 (file)
@@ -172,7 +172,7 @@ void AgentConnection::ReceiverThread(void)
    {
       // Receive raw message
       if ((iErr = RecvCSCPMessage(m_hSocket, pRawMsg, pMsgBuffer, RECEIVER_BUFFER_SIZE,
-                                  m_pCtx, pDecryptionBuffer)) <= 0)
+                                  &m_pCtx, pDecryptionBuffer)) <= 0)
          break;
 
       // Check if we get too large message
@@ -229,13 +229,16 @@ void AgentConnection::ReceiverThread(void)
 // Connect to agent
 //
 
-BOOL AgentConnection::Connect(RSA *pServerKey, BOOL bVerbose)
+BOOL AgentConnection::Connect(RSA *pServerKey, BOOL bVerbose, DWORD *pdwError)
 {
    struct sockaddr_in sa;
    TCHAR szBuffer[256];
    BOOL bSuccess = FALSE;
    DWORD dwError;
 
+   if (pdwError != NULL)
+      *pdwError = ERR_INTERNAL_ERROR;
+
    // Check if already connected
    if (m_bIsConnected)
       return FALSE;
@@ -267,6 +270,7 @@ BOOL AgentConnection::Connect(RSA *pServerKey, BOOL bVerbose)
    {
       if (bVerbose)
          PrintMsg(_T("Cannot establish connection with agent %s"), IpToStr(ntohl(m_dwAddr), szBuffer));
+      dwError = ERR_CONNECT_FAILED;
       goto connect_cleanup;
    }
 
@@ -298,6 +302,7 @@ BOOL AgentConnection::Connect(RSA *pServerKey, BOOL bVerbose)
    }
 
    bSuccess = TRUE;
+   dwError = ERR_SUCCESS;
 
 connect_cleanup:
    if (!bSuccess)
@@ -314,6 +319,8 @@ connect_cleanup:
       m_pCtx = NULL;
    }
    m_bIsConnected = bSuccess;
+   if (pdwError != NULL)
+      *pdwError = dwError;
    return bSuccess;
 }
 
@@ -781,7 +788,7 @@ DWORD AgentConnection::UploadFile(TCHAR *pszFile)
 
    if (dwResult == ERR_SUCCESS)
    {
-      if (SendFileOverCSCP(m_hSocket, dwRqId, pszFile))
+      if (SendFileOverCSCP(m_hSocket, dwRqId, pszFile, m_pCtx))
          dwResult = WaitForRCC(dwRqId, m_dwCommandTimeout);
       else
          dwResult = ERR_IO_FAILURE;
index a5ad116..40232e1 100644 (file)
@@ -53,6 +53,10 @@ static struct
    { ERR_RESOURCE_BUSY, _T("Resource busy") },
    { ERR_EXEC_FAILED, _T("External program execution failed") },
    { ERR_ENCRYPTION_REQUIRED, _T("Encryption required") },
+   { ERR_NO_CIPHERS, _T("No acceptable ciphers") },
+   { ERR_INVALID_PUBLIC_KEY, _T("Invalid public key") },
+   { ERR_INVALID_SESSION_KEY, _T("Invalid session key") },
+   { ERR_CONNECT_FAILED, _T("Connect failed") },
    { -1, NULL }
 };
 
index c6434ba..f544d12 100644 (file)
 int main(int argc, char *argv[])
 {
    char *eptr;
-   BOOL bStart = TRUE, bVerbose = TRUE;
+   BOOL bStart = TRUE, bVerbose = TRUE, bEncrypt = FALSE;
    int i, ch, iExitCode = 3;
    int iAuthMethod = AUTH_NONE;
    WORD wPort = AGENT_LISTEN_PORT;
-   DWORD dwAddr, dwTimeout = 3000;
+   DWORD dwAddr, dwTimeout = 3000, dwError;
    char szSecret[MAX_SECRET_LENGTH] = "";
+   char szKeyFile[MAX_PATH] = DEFAULT_DATA_DIR DFILE_KEYS;
+   RSA *pServerKey = NULL;
 
    // Parse command line
    opterr = 1;
-   while((ch = getopt(argc, argv, "a:hp:qs:vw:")) != -1)
+   while((ch = getopt(argc, argv, "a:ehK:p:qs:vw:")) != -1)
    {
       switch(ch)
       {
@@ -57,7 +59,14 @@ int main(int argc, char *argv[])
                    "Valid options are:\n"
                    "   -a <auth>    : Authentication method. Valid methods are \"none\",\n"
                    "                  \"plain\", \"md5\" and \"sha1\". Default is \"none\".\n"
+#ifdef _WITH_ENCRYPTION
+                   "   -e           : Encrypt connection.\n"
+#endif
                    "   -h           : Display help and exit.\n"
+#ifdef _WITH_ENCRYPTION
+                   "   -K <file>    : Specify server's key file\n"
+                   "                  (default is " DEFAULT_DATA_DIR DFILE_KEYS ").\n"
+#endif
                    "   -p <port>    : Specify agent's port number. Default is %d.\n"
                    "   -q           : Quiet mode.\n"
                    "   -s <secret>  : Specify shared secret for authentication.\n"
@@ -115,6 +124,20 @@ int main(int argc, char *argv[])
                dwTimeout = (DWORD)i * 1000;  // Convert to milliseconds
             }
             break;
+#ifdef _WITH_ENCRYPTION
+         case 'e':
+            bEncrypt = TRUE;
+            break;
+         case 'K':
+            strncpy(szKeyFile, optarg, MAX_PATH);
+            break;
+#else
+         case 'e':
+         case 'K':
+            printf("ERROR: This tool was compiled without encryption support\n");
+            bStart = FALSE;
+            break;
+#endif
          case '?':
             bStart = FALSE;
             break;
@@ -137,6 +160,27 @@ int main(int argc, char *argv[])
          bStart = FALSE;
       }
 
+      // Load server key if requested
+#ifdef _WITH_ENCRYPTION
+      if (bEncrypt && bStart)
+      {
+         if (InitCryptoLib(0xFFFF))
+         {
+            pServerKey = LoadRSAKeys(szKeyFile);
+            if (pServerKey == NULL)
+            {
+               printf("Error loading RSA keys from \"%s\"\n", szKeyFile);
+               bStart = FALSE;
+            }
+         }
+         else
+         {
+            printf("Error initializing cryptografy module\n");
+            bStart = FALSE;
+         }
+      }
+#endif
+
       // If everything is ok, start communications
       if (bStart)
       {
@@ -167,7 +211,7 @@ int main(int argc, char *argv[])
             AgentConnection conn(dwAddr, wPort, iAuthMethod, szSecret);
 
             conn.SetCommandTimeout(dwTimeout);
-            if (conn.Connect(bVerbose))
+            if (conn.Connect(pServerKey, bVerbose, &dwError))
             {
                DWORD dwError;
 
@@ -184,6 +228,7 @@ int main(int argc, char *argv[])
             }
             else
             {
+               printf("%d: %s\n", dwError, AgentErrorCodeToText(dwError));
                iExitCode = 2;
             }
          }
index 7376949..b15165a 100644 (file)
@@ -163,7 +163,7 @@ int main(int argc, char *argv[])
    int i, ch, iPos, iExitCode = 3, iCommand = CMD_GET, iInterval = 0;
    int iAuthMethod = AUTH_NONE, iServiceType = NETSRV_SSH;
    WORD wAgentPort = AGENT_LISTEN_PORT, wServicePort = 0, wServiceProto = 0;
-   DWORD dwTimeout = 3000, dwServiceAddr = 0;
+   DWORD dwTimeout = 3000, dwServiceAddr = 0, dwError;
    char szSecret[MAX_SECRET_LENGTH] = "", szRequest[MAX_DB_STRING] = "";
    char szKeyFile[MAX_PATH] = DEFAULT_DATA_DIR DFILE_KEYS, szResponce[MAX_DB_STRING] = "";
    RSA *pServerKey = NULL;
@@ -358,10 +358,18 @@ int main(int argc, char *argv[])
 #ifdef _WITH_ENCRYPTION
       if (bEncrypt && bStart)
       {
-         pServerKey = LoadRSAKeys(szKeyFile);
-         if (pServerKey == NULL)
+         if (InitCryptoLib(0xFFFF))
          {
-            printf("Error loading RSA keys from \"%s\"\n", szKeyFile);
+            pServerKey = LoadRSAKeys(szKeyFile);
+            if (pServerKey == NULL)
+            {
+               printf("Error loading RSA keys from \"%s\"\n", szKeyFile);
+               bStart = FALSE;
+            }
+         }
+         else
+         {
+            printf("Error initializing cryptografy module\n");
             bStart = FALSE;
          }
       }
@@ -385,7 +393,7 @@ int main(int argc, char *argv[])
             AgentConnection conn(m_dwAddr, wAgentPort, iAuthMethod, szSecret);
 
             conn.SetCommandTimeout(dwTimeout);
-            if (conn.Connect(pServerKey, m_bVerbose))
+            if (conn.Connect(pServerKey, m_bVerbose, &dwError))
             {
                do
                {
@@ -418,6 +426,7 @@ int main(int argc, char *argv[])
             }
             else
             {
+               printf("%d: %s\n", dwError, AgentErrorCodeToText(dwError));
                iExitCode = 2;
             }
          }
index 36736bf..abab7a1 100644 (file)
@@ -35,7 +35,7 @@
 // Do agent upgrade
 //
 
-static int UpgradeAgent(AgentConnection &conn, TCHAR *pszPkgName, BOOL bVerbose)
+static int UpgradeAgent(AgentConnection &conn, TCHAR *pszPkgName, BOOL bVerbose, RSA *pServerKey)
 {
    DWORD dwError;
    int i;
@@ -58,7 +58,7 @@ static int UpgradeAgent(AgentConnection &conn, TCHAR *pszPkgName, BOOL bVerbose)
             fflush(stdout);
             if ((i % 20 == 0) && (i > 30))
             {
-               if (conn.Connect(FALSE))
+               if (conn.Connect(pServerKey, FALSE))
                {
                   bConnected = TRUE;
                   break;   // Connected successfully
@@ -73,7 +73,7 @@ static int UpgradeAgent(AgentConnection &conn, TCHAR *pszPkgName, BOOL bVerbose)
          for(i = 20; i < 120; i += 20)
          {
             ThreadSleep(20);
-            if (conn.Connect(FALSE))
+            if (conn.Connect(pServerKey, FALSE))
             {
                bConnected = TRUE;
                break;   // Connected successfully
@@ -83,7 +83,7 @@ static int UpgradeAgent(AgentConnection &conn, TCHAR *pszPkgName, BOOL bVerbose)
 
       // Last attempt to reconnect
       if (!bConnected)
-         bConnected = conn.Connect(bVerbose);
+         bConnected = conn.Connect(pServerKey, FALSE);
 
       if (bConnected && bVerbose)
       {
@@ -111,17 +111,19 @@ static int UpgradeAgent(AgentConnection &conn, TCHAR *pszPkgName, BOOL bVerbose)
 int main(int argc, char *argv[])
 {
    char *eptr;
-   BOOL bStart = TRUE, bVerbose = TRUE, bUpgrade = FALSE;
+   BOOL bStart = TRUE, bVerbose = TRUE, bUpgrade = FALSE, bEncrypt = FALSE;
    int i, ch, iExitCode = 3;
    int iAuthMethod = AUTH_NONE;
    WORD wPort = AGENT_LISTEN_PORT;
-   DWORD dwAddr, dwTimeout = 3000;
-   char szSecret[MAX_SECRET_LENGTH] = "";
+   DWORD dwAddr, dwTimeout = 3000, dwError;
    INT64 nElapsedTime;
+   char szSecret[MAX_SECRET_LENGTH] = "";
+   char szKeyFile[MAX_PATH] = DEFAULT_DATA_DIR DFILE_KEYS;
+   RSA *pServerKey = NULL;
 
    // Parse command line
    opterr = 1;
-   while((ch = getopt(argc, argv, "a:hp:qs:uvw:")) != -1)
+   while((ch = getopt(argc, argv, "a:ehK:p:qs:uvw:")) != -1)
    {
       switch(ch)
       {
@@ -130,7 +132,14 @@ int main(int argc, char *argv[])
                    "Valid options are:\n"
                    "   -a <auth>    : Authentication method. Valid methods are \"none\",\n"
                    "                  \"plain\", \"md5\" and \"sha1\". Default is \"none\".\n"
+#ifdef _WITH_ENCRYPTION
+                   "   -e           : Encrypt connection.\n"
+#endif
                    "   -h           : Display help and exit.\n"
+#ifdef _WITH_ENCRYPTION
+                   "   -K <file>    : Specify server's key file\n"
+                   "                  (default is " DEFAULT_DATA_DIR DFILE_KEYS ").\n"
+#endif
                    "   -p <port>    : Specify agent's port number. Default is %d.\n"
                    "   -q           : Quiet mode.\n"
                    "   -s <secret>  : Specify shared secret for authentication.\n"
@@ -192,6 +201,21 @@ int main(int argc, char *argv[])
                dwTimeout = (DWORD)i * 1000;  // Convert to milliseconds
             }
             break;
+#ifdef _WITH_ENCRYPTION
+         case 'e':
+            bEncrypt = TRUE;
+            break;
+         case 'K':
+            strncpy(szKeyFile, optarg, MAX_PATH);
+            break;
+#else
+         case 'e':
+         case 'K':
+            if (bVerbose)
+               fprintf(stderr, "ERROR: This tool was compiled without encryption support\n");
+            bStart = FALSE;
+            break;
+#endif
          case '?':
             bStart = FALSE;
             break;
@@ -216,6 +240,29 @@ int main(int argc, char *argv[])
          bStart = FALSE;
       }
 
+      // Load server key if requested
+#ifdef _WITH_ENCRYPTION
+      if (bEncrypt && bStart)
+      {
+         if (InitCryptoLib(0xFFFF))
+         {
+            pServerKey = LoadRSAKeys(szKeyFile);
+            if (pServerKey == NULL)
+            {
+               if (bVerbose)
+                  fprintf(stderr, "Error loading RSA keys from \"%s\"\n", szKeyFile);
+               bStart = FALSE;
+            }
+         }
+         else
+         {
+            if (bVerbose)
+               fprintf(stderr, "Error initializing cryptografy module\n");
+            bStart = FALSE;
+         }
+      }
+#endif
+
       // If everything is ok, start communications
       if (bStart)
       {
@@ -247,7 +294,7 @@ int main(int argc, char *argv[])
             AgentConnection conn(dwAddr, wPort, iAuthMethod, szSecret);
 
             conn.SetCommandTimeout(dwTimeout);
-            if (conn.Connect(bVerbose))
+            if (conn.Connect(pServerKey, bVerbose, &dwError))
             {
                DWORD dwError;
 
@@ -280,7 +327,7 @@ int main(int argc, char *argv[])
 
                if (bUpgrade && (dwError == RCC_SUCCESS))
                {
-                  iExitCode = UpgradeAgent(conn, argv[optind + 1], bVerbose);
+                  iExitCode = UpgradeAgent(conn, argv[optind + 1], bVerbose, pServerKey);
                }
                else
                {
@@ -290,6 +337,8 @@ int main(int argc, char *argv[])
             }
             else
             {
+               if (bVerbose)
+                  fprintf(stderr, "%d: %s\n", dwError, AgentErrorCodeToText(dwError));
                iExitCode = 2;
             }
          }