calls to functions deprecated in OpenSSL 1.1 replaced with compatible ones
[public/netxms.git] / src / libnetxms / crypto.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** NetXMS Foundation Library
4 ** Copyright (C) 2003-2017 Victor Kirhenshtein
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU Lesser General Public License as published
8 ** by the Free Software Foundation; either version 3 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU Lesser General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 **
20 ** File: crypto.cpp
21 **
22 **/
23
24 #include "libnetxms.h"
25 #include "ice.h"
26 #include <nxcpapi.h>
27
28 /**
29 * Constants
30 */
31 #define KEY_BUFFER_SIZE 4096
32
33 /**
34 * Supported ciphers. By default, we support all ciphers compiled
35 * into OpenSSL library.
36 */
37 static UINT32 s_supportedCiphers =
38 #ifdef _WITH_ENCRYPTION
39 #ifndef OPENSSL_NO_AES
40 NXCP_SUPPORT_AES_256 |
41 NXCP_SUPPORT_AES_128 |
42 #endif
43 #ifndef OPENSSL_NO_BF
44 NXCP_SUPPORT_BLOWFISH_256 |
45 NXCP_SUPPORT_BLOWFISH_128 |
46 #endif
47 #ifndef OPENSSL_NO_IDEA
48 NXCP_SUPPORT_IDEA |
49 #endif
50 #ifndef OPENSSL_NO_DES
51 NXCP_SUPPORT_3DES |
52 #endif
53 #endif /* _WITH_ENCRYPTION */
54 0;
55
56 /**
57 * Static data
58 */
59 static WORD s_noEncryptionFlag = 0;
60 static const TCHAR *s_cipherNames[NETXMS_MAX_CIPHERS] = { _T("AES-256"), _T("Blowfish-256"), _T("IDEA"), _T("3DES"), _T("AES-128"), _T("Blowfish-128") };
61
62 #if defined(_WITH_ENCRYPTION) && WITH_OPENSSL
63
64 extern "C" typedef OPENSSL_CONST EVP_CIPHER * (*CIPHER_FUNC)();
65 static CIPHER_FUNC s_ciphers[NETXMS_MAX_CIPHERS] =
66 {
67 #ifndef OPENSSL_NO_AES
68 EVP_aes_256_cbc,
69 #else
70 NULL,
71 #endif
72 #ifndef OPENSSL_NO_BF
73 EVP_bf_cbc,
74 #else
75 NULL,
76 #endif
77 #ifndef OPENSSL_NO_IDEA
78 EVP_idea_cbc,
79 #else
80 NULL,
81 #endif
82 #ifndef OPENSSL_NO_DES
83 EVP_des_ede3_cbc,
84 #else
85 NULL,
86 #endif
87 #ifndef OPENSSL_NO_AES
88 EVP_aes_128_cbc,
89 #else
90 NULL,
91 #endif
92 #ifndef OPENSSL_NO_BF
93 EVP_bf_cbc
94 #else
95 NULL
96 #endif
97 };
98
99 #if OPENSSL_VERSION_NUMBER < 0x10100000L
100 static MUTEX *s_cryptoMutexList = NULL;
101
102 /**
103 * Locking callback for CRYPTO library
104 */
105 #if defined(__SUNPRO_CC)
106 extern "C"
107 #endif
108 static void CryptoLockingCallback(int nMode, int nLock, const char *pszFile, int nLine)
109 {
110 if (nMode & CRYPTO_LOCK)
111 MutexLock(s_cryptoMutexList[nLock]);
112 else
113 MutexUnlock(s_cryptoMutexList[nLock]);
114 }
115
116 #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
117
118 /**
119 * ID callback for CRYPTO library
120 */
121 #ifndef _WIN32
122
123 #if defined(__SUNPRO_CC)
124 extern "C"
125 #endif
126 static unsigned long CryptoIdCallback()
127 {
128 return (unsigned long)GetCurrentThreadId();
129 }
130
131 #endif
132
133 /**
134 * Create RSA key from binary representation
135 */
136 RSA LIBNETXMS_EXPORTABLE *RSAKeyFromData(const BYTE *data, size_t size, bool withPrivate)
137 {
138 const BYTE *bp = data;
139 RSA *key = d2i_RSAPublicKey(NULL, (OPENSSL_CONST BYTE **)&bp, (int)size);
140 if ((key != NULL) && withPrivate)
141 {
142 if (d2i_RSAPrivateKey(&key, (OPENSSL_CONST BYTE **)&bp, (int)(size - CAST_FROM_POINTER((bp - data), size_t))) == NULL)
143 {
144 RSA_free(key);
145 key = NULL;
146 }
147 }
148 return key;
149 }
150
151 /**
152 * Destroy RSA key
153 */
154 void LIBNETXMS_EXPORTABLE RSAFree(RSA *key)
155 {
156 RSA_free(key);
157 }
158
159 /**
160 * Generate random RSA key
161 */
162 RSA LIBNETXMS_EXPORTABLE *RSAGenerateKey(int bits)
163 {
164 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
165 BIGNUM *bne = BN_new();
166 if (!BN_set_word(bne, RSA_F4))
167 return NULL;
168 RSA *key = RSA_new();
169 if (!RSA_generate_key_ex(key, NETXMS_RSA_KEYLEN, bne, NULL))
170 {
171 RSA_free(key);
172 BN_free(bne);
173 return NULL;
174 }
175 BN_free(bne);
176 return key;
177 #else
178 return RSA_generate_key(bits, RSA_F4, NULL, NULL);
179 #endif
180 }
181
182 #endif /* _WITH_ENCRYPTION */
183
184 #if defined(_WITH_ENCRYPTION) && WITH_COMMONCRYPTO
185
186 /**
187 * Create RSA key from binary representation
188 */
189 RSA LIBNETXMS_EXPORTABLE *RSAKeyFromData(const BYTE *data, size_t size, bool withPrivate)
190 {
191 SecKeyCreateWithData(keyData, keyAttr);
192 return NULL;
193 }
194
195 /**
196 * Destroy RSA key
197 */
198 void LIBNETXMS_EXPORTABLE RSAFree(RSA *key)
199 {
200 free(key);
201 }
202
203 #endif
204
205 /**
206 * Initialize OpenSSL library
207 */
208 bool LIBNETXMS_EXPORTABLE InitCryptoLib(UINT32 dwEnabledCiphers)
209 {
210 s_noEncryptionFlag = htons(MF_DONT_ENCRYPT);
211
212 #if _WITH_ENCRYPTION && WITH_OPENSSL
213 BYTE random[8192];
214 int i;
215
216 #if OPENSSL_VERSION_NUMBER < 0x10100000L
217 CRYPTO_malloc_init();
218 OpenSSL_add_all_algorithms();
219 #endif
220
221 ERR_load_CRYPTO_strings();
222 RAND_seed(random, 8192);
223
224 #if OPENSSL_VERSION_NUMBER < 0x10100000L
225 s_cryptoMutexList = (MUTEX *)malloc(sizeof(MUTEX) * CRYPTO_num_locks());
226 for(i = 0; i < CRYPTO_num_locks(); i++)
227 s_cryptoMutexList[i] = MutexCreate();
228 CRYPTO_set_locking_callback(CryptoLockingCallback);
229 #endif
230
231 #ifndef _WIN32
232 CRYPTO_set_id_callback(CryptoIdCallback);
233 #endif /* _WIN32 */
234
235 // validate supported ciphers
236 nxlog_debug(1, _T("Validating ciphers"));
237 s_supportedCiphers &= dwEnabledCiphers;
238 UINT32 cipherBit = 1;
239 for(i = 0; i < NETXMS_MAX_CIPHERS; i++, cipherBit = cipherBit << 1)
240 {
241 if ((s_supportedCiphers & cipherBit) == 0)
242 {
243 nxlog_debug(1, _T(" %s disabled (config)"), s_cipherNames[i]);
244 continue;
245 }
246 NXCPEncryptionContext *ctx = NXCPEncryptionContext::create(cipherBit);
247 if (ctx != NULL)
248 {
249 delete ctx;
250 nxlog_debug(1, _T(" %s enabled"), s_cipherNames[i]);
251 }
252 else
253 {
254 s_supportedCiphers &= ~cipherBit;
255 nxlog_debug(1, _T(" %s disabled (validation failed)"), s_cipherNames[i]);
256 }
257 }
258
259 nxlog_debug(1, _T("Crypto library initialized"));
260 #elif _WITH_ENCRYPTION && WITH_COMMONCRYPTO
261 nxlog_debug(1, _T("Crypto library initialized"));
262 #else
263 nxlog_debug(1, _T("Crypto library will not be initialized because libnetxms was built without encryption support"));
264 #endif /* _WITH_ENCRYPTION */
265 return true;
266 }
267
268 /**
269 * Get supported ciphers
270 */
271 UINT32 LIBNETXMS_EXPORTABLE NXCPGetSupportedCiphers()
272 {
273 return s_supportedCiphers;
274 }
275
276 /**
277 * Get supported ciphers as text
278 */
279 String LIBNETXMS_EXPORTABLE NXCPGetSupportedCiphersAsText()
280 {
281 String s;
282 #ifdef _WITH_ENCRYPTION
283 UINT32 cipherBit = 1;
284 for(int i = 0; i < NETXMS_MAX_CIPHERS; i++, cipherBit = cipherBit << 1)
285 {
286 if ((s_supportedCiphers & cipherBit) == 0)
287 {
288 continue;
289 }
290 NXCPEncryptionContext *ctx = NXCPEncryptionContext::create(cipherBit);
291 if (ctx != NULL)
292 {
293 delete ctx;
294 if (s.length() > 0)
295 s.append(_T(", "));
296 s.append(s_cipherNames[i]);
297 }
298 }
299 #endif
300 return s;
301 }
302
303 /**
304 * Encrypt message
305 */
306 NXCP_ENCRYPTED_MESSAGE LIBNETXMS_EXPORTABLE *NXCPEncryptMessage(NXCPEncryptionContext *pCtx, NXCP_MESSAGE *msg)
307 {
308 return (pCtx != NULL) ? pCtx->encryptMessage(msg) : NULL;
309 }
310
311 /**
312 * Decrypt message
313 */
314 bool LIBNETXMS_EXPORTABLE NXCPDecryptMessage(NXCPEncryptionContext *pCtx, NXCP_ENCRYPTED_MESSAGE *msg, BYTE *pDecryptionBuffer)
315 {
316 return (pCtx != NULL) ? pCtx->decryptMessage(msg, pDecryptionBuffer) : false;
317 }
318
319 /**
320 * Setup encryption context
321 * Function will determine is it called on initiator or responder side
322 * by message code. Initiator should provide it's private key,
323 * and responder should provide pointer to response message.
324 */
325 UINT32 LIBNETXMS_EXPORTABLE SetupEncryptionContext(NXCPMessage *msg,
326 NXCPEncryptionContext **ppCtx,
327 NXCPMessage **ppResponse,
328 RSA *pPrivateKey, int nNXCPVersion)
329 {
330 UINT32 dwResult = RCC_NOT_IMPLEMENTED;
331
332 *ppCtx = NULL;
333 #ifdef _WITH_ENCRYPTION
334 if (msg->getCode() == CMD_REQUEST_SESSION_KEY)
335 {
336 UINT32 dwCiphers;
337
338 *ppResponse = new NXCPMessage(nNXCPVersion);
339 (*ppResponse)->setCode(CMD_SESSION_KEY);
340 (*ppResponse)->setId(msg->getId());
341 (*ppResponse)->disableEncryption();
342
343 dwCiphers = msg->getFieldAsUInt32(VID_SUPPORTED_ENCRYPTION) & s_supportedCiphers;
344 if (dwCiphers == 0)
345 {
346 (*ppResponse)->setField(VID_RCC, RCC_NO_CIPHERS);
347 dwResult = RCC_NO_CIPHERS;
348 }
349 else
350 {
351 BYTE ucKeyBuffer[KEY_BUFFER_SIZE];
352 RSA *pServerKey;
353
354 *ppCtx = NXCPEncryptionContext::create(dwCiphers);
355 if (*ppCtx != NULL)
356 {
357 // Encrypt key
358 size_t size = msg->getFieldAsBinary(VID_PUBLIC_KEY, ucKeyBuffer, KEY_BUFFER_SIZE);
359 pServerKey = RSAKeyFromData(ucKeyBuffer, size, false);
360 if (pServerKey != NULL)
361 {
362 (*ppResponse)->setField(VID_RCC, RCC_SUCCESS);
363
364 size = RSA_public_encrypt((*ppCtx)->getKeyLength(), (*ppCtx)->getSessionKey(), ucKeyBuffer, pServerKey, RSA_PKCS1_OAEP_PADDING);
365 (*ppResponse)->setField(VID_SESSION_KEY, ucKeyBuffer, (UINT32)size);
366 (*ppResponse)->setField(VID_KEY_LENGTH, (WORD)(*ppCtx)->getKeyLength());
367
368 int ivLength = EVP_CIPHER_iv_length(s_ciphers[(*ppCtx)->getCipher()]());
369 if ((ivLength <= 0) || (ivLength > EVP_MAX_IV_LENGTH))
370 ivLength = EVP_MAX_IV_LENGTH;
371 size = RSA_public_encrypt(ivLength, (*ppCtx)->getIV(), ucKeyBuffer, pServerKey, RSA_PKCS1_OAEP_PADDING);
372 (*ppResponse)->setField(VID_SESSION_IV, ucKeyBuffer, (UINT32)size);
373 (*ppResponse)->setField(VID_IV_LENGTH, (WORD)ivLength);
374
375 (*ppResponse)->setField(VID_CIPHER, (WORD)(*ppCtx)->getCipher());
376 RSA_free(pServerKey);
377 dwResult = RCC_SUCCESS;
378 }
379 else
380 {
381 (*ppResponse)->setField(VID_RCC, RCC_INVALID_PUBLIC_KEY);
382 dwResult = RCC_INVALID_PUBLIC_KEY;
383 }
384 }
385 else
386 {
387 (*ppResponse)->setField(VID_RCC, RCC_ENCRYPTION_ERROR);
388 dwResult = RCC_ENCRYPTION_ERROR;
389 }
390 }
391 }
392 else if (msg->getCode() == CMD_SESSION_KEY)
393 {
394 dwResult = msg->getFieldAsUInt32(VID_RCC);
395 if (dwResult == RCC_SUCCESS)
396 {
397 *ppCtx = NXCPEncryptionContext::create(msg, pPrivateKey);
398 if (*ppCtx == NULL)
399 {
400 dwResult = RCC_INVALID_SESSION_KEY;
401 }
402 }
403 }
404
405 if ((dwResult != RCC_SUCCESS) && (*ppCtx != NULL))
406 {
407 delete *ppCtx;
408 *ppCtx = NULL;
409 }
410 #else
411 if (msg->getCode() == CMD_REQUEST_SESSION_KEY)
412 {
413 *ppResponse = new NXCPMessage(nNXCPVersion);
414 (*ppResponse)->setCode(CMD_SESSION_KEY);
415 (*ppResponse)->setId(msg->getId());
416 (*ppResponse)->disableEncryption();
417 (*ppResponse)->setField(VID_RCC, dwResult);
418 }
419 #endif
420
421 return dwResult;
422 }
423
424 /**
425 * Prepare session key request message
426 */
427 void LIBNETXMS_EXPORTABLE PrepareKeyRequestMsg(NXCPMessage *msg, RSA *pServerKey, bool useX509Format)
428 {
429 #ifdef _WITH_ENCRYPTION
430 int iLen;
431 BYTE *pKeyBuffer, *pBufPos;
432
433 msg->setCode(CMD_REQUEST_SESSION_KEY);
434 msg->setField(VID_SUPPORTED_ENCRYPTION, s_supportedCiphers);
435
436 if (useX509Format)
437 {
438 iLen = i2d_RSA_PUBKEY(pServerKey, NULL);
439 pKeyBuffer = (BYTE *)malloc(iLen);
440 pBufPos = pKeyBuffer;
441 i2d_RSA_PUBKEY(pServerKey, &pBufPos);
442 }
443 else
444 {
445 iLen = i2d_RSAPublicKey(pServerKey, NULL);
446 pKeyBuffer = (BYTE *)malloc(iLen);
447 pBufPos = pKeyBuffer;
448 i2d_RSAPublicKey(pServerKey, &pBufPos);
449 }
450 msg->setField(VID_PUBLIC_KEY, pKeyBuffer, iLen);
451 free(pKeyBuffer);
452 #endif
453 }
454
455 /**
456 * Load RSA key(s) from file
457 */
458 RSA LIBNETXMS_EXPORTABLE *LoadRSAKeys(const TCHAR *pszKeyFile)
459 {
460 #ifdef _WITH_ENCRYPTION
461 RSA *pKey = NULL;
462 FILE *fp = _tfopen(pszKeyFile, _T("rb"));
463 if (fp != NULL)
464 {
465 UINT32 dwLen;
466 if (fread(&dwLen, 1, sizeof(UINT32), fp) == sizeof(UINT32) && dwLen < 10 * 1024)
467 {
468 BYTE *pKeyBuffer = (BYTE *)malloc(dwLen);
469 if (fread(pKeyBuffer, 1, dwLen, fp) == dwLen)
470 {
471 BYTE hash[SHA1_DIGEST_SIZE];
472 if (fread(hash, 1, SHA1_DIGEST_SIZE, fp) == SHA1_DIGEST_SIZE)
473 {
474 BYTE hash2[SHA1_DIGEST_SIZE];
475 CalculateSHA1Hash(pKeyBuffer, dwLen, hash2);
476 if (!memcmp(hash, hash2, SHA1_DIGEST_SIZE))
477 {
478 pKey = RSAKeyFromData(pKeyBuffer, dwLen, true);
479 }
480 }
481 }
482 free(pKeyBuffer);
483 }
484 fclose(fp);
485 }
486 return pKey;
487 #else
488 return NULL;
489 #endif
490 }
491
492 /**
493 * Create signature for message using certificate (MS CAPI version)
494 * Paraeters:
495 * msg and dwMsgLen - message to sign and it's length
496 * pCert - certificate
497 * pBuffer - output buffer
498 * dwBufSize - buffer size
499 * pdwSigLen - actual signature size
500 */
501 #ifdef _WIN32
502
503 BOOL LIBNETXMS_EXPORTABLE SignMessageWithCAPI(BYTE *msg, UINT32 dwMsgLen, const CERT_CONTEXT *pCert,
504 BYTE *pBuffer, UINT32 dwBufSize, UINT32 *pdwSigLen)
505 {
506 BOOL bFreeProv, bRet = FALSE;
507 DWORD i, j, dwLen, dwKeySpec;
508 HCRYPTPROV hProv;
509 HCRYPTHASH hHash;
510 BYTE *pTemp;
511
512 if (CryptAcquireCertificatePrivateKey(pCert, CRYPT_ACQUIRE_COMPARE_KEY_FLAG, NULL, &hProv, &dwKeySpec, &bFreeProv))
513 {
514 if (CryptCreateHash(hProv, CALG_SHA1, NULL, 0, &hHash))
515 {
516 if (CryptHashData(hHash, msg, dwMsgLen, 0))
517 {
518 dwLen = dwBufSize;
519 pTemp = (BYTE *)malloc(dwBufSize);;
520 bRet = CryptSignHash(hHash, dwKeySpec, NULL, 0, pTemp, &dwLen);
521 *pdwSigLen = dwLen;
522 // we have to reverse the byte-order in the result from CryptSignHash()
523 for(i = 0, j = dwLen - 1; i < dwLen; i++, j--)
524 pBuffer[i] = pTemp[j];
525 }
526 CryptDestroyHash(hHash);
527 }
528
529 if (bFreeProv)
530 CryptReleaseContext(hProv, 0);
531 }
532 return bRet;
533 }
534
535 #endif
536
537 /**
538 * Encrypt data block with ICE
539 */
540 void LIBNETXMS_EXPORTABLE ICEEncryptData(const BYTE *in, int inLen, BYTE *out, const BYTE *key)
541 {
542 ICE_KEY *ice = ice_key_create(1);
543 ice_key_set(ice, key);
544
545 int stopPos = inLen - (inLen % 8);
546 for(int pos = 0; pos < stopPos; pos += 8)
547 ice_key_encrypt(ice, &in[pos], &out[pos]);
548
549 if (stopPos < inLen)
550 {
551 BYTE plainText[8], encrypted[8];
552
553 memcpy(plainText, &in[stopPos], inLen - stopPos);
554 ice_key_encrypt(ice, plainText, encrypted);
555 memcpy(&out[stopPos], encrypted, inLen - stopPos);
556 }
557
558 ice_key_destroy(ice);
559 }
560
561 /**
562 * Decrypt data block with ICE
563 */
564 void LIBNETXMS_EXPORTABLE ICEDecryptData(const BYTE *in, int inLen, BYTE *out, const BYTE *key)
565 {
566 ICE_KEY *ice = ice_key_create(1);
567 ice_key_set(ice, key);
568
569 int stopPos = inLen - (inLen % 8);
570 for(int pos = 0; pos < stopPos; pos += 8)
571 ice_key_decrypt(ice, &in[pos], &out[pos]);
572
573 if (stopPos < inLen)
574 {
575 BYTE plainText[8], encrypted[8];
576
577 memcpy(encrypted, &in[stopPos], inLen - stopPos);
578 ice_key_decrypt(ice, encrypted, plainText);
579 memcpy(&out[stopPos], plainText, inLen - stopPos);
580 }
581
582 ice_key_destroy(ice);
583 }
584
585 /**
586 * Encryption context constructor
587 */
588 NXCPEncryptionContext::NXCPEncryptionContext()
589 {
590 m_sessionKey = NULL;
591 m_keyLength = 0;
592 m_cipher = -1;
593 #ifdef _WITH_ENCRYPTION
594 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
595 m_encryptor = EVP_CIPHER_CTX_new();
596 m_decryptor = EVP_CIPHER_CTX_new();
597 #else
598 m_encryptor = (EVP_CIPHER_CTX *)malloc(sizeof(EVP_CIPHER_CTX));
599 m_decryptor = (EVP_CIPHER_CTX *)malloc(sizeof(EVP_CIPHER_CTX));
600 EVP_CIPHER_CTX_init(m_encryptor);
601 EVP_CIPHER_CTX_init(m_decryptor);
602 #endif
603 m_encryptorLock = MutexCreate();
604 #endif
605 }
606
607 /**
608 * Encryption context destructor
609 */
610 NXCPEncryptionContext::~NXCPEncryptionContext()
611 {
612 free(m_sessionKey);
613 #ifdef _WITH_ENCRYPTION
614 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
615 EVP_CIPHER_CTX_free(m_encryptor);
616 EVP_CIPHER_CTX_free(m_decryptor);
617 #else
618 EVP_CIPHER_CTX_cleanup(m_encryptor);
619 EVP_CIPHER_CTX_cleanup(m_decryptor);
620 free(m_encryptor);
621 free(m_decryptor);
622 #endif
623 MutexDestroy(m_encryptorLock);
624 #endif
625 }
626
627 /**
628 * Create encryption context from CMD_SESSION_KEY NXCP message
629 */
630 NXCPEncryptionContext *NXCPEncryptionContext::create(NXCPMessage *msg, RSA *privateKey)
631 {
632 #ifdef _WITH_ENCRYPTION
633 BYTE ucKeyBuffer[KEY_BUFFER_SIZE], ucSessionKey[KEY_BUFFER_SIZE];
634 int nSize;
635 NXCPEncryptionContext *ctx = new NXCPEncryptionContext;
636
637 int cipher = (int)msg->getFieldAsUInt16(VID_CIPHER);
638 if (ctx->initCipher(cipher))
639 {
640 if (ctx->m_keyLength == (int)msg->getFieldAsUInt16(VID_KEY_LENGTH))
641 {
642 ctx->m_sessionKey = (BYTE *)malloc(ctx->m_keyLength);
643
644 // Decrypt session key
645 int keySize = (int)msg->getFieldAsBinary(VID_SESSION_KEY, ucKeyBuffer, KEY_BUFFER_SIZE);
646 nSize = RSA_private_decrypt(keySize, ucKeyBuffer, ucSessionKey, privateKey, RSA_PKCS1_OAEP_PADDING);
647 if (nSize == ctx->m_keyLength)
648 {
649 memcpy(ctx->m_sessionKey, ucSessionKey, nSize);
650
651 // Decrypt session IV
652 int nIVLen = msg->getFieldAsUInt16(VID_IV_LENGTH);
653 if (nIVLen == 0) // Versions prior to 0.2.13 don't send IV length, assume 16
654 nIVLen = 16;
655 keySize = (int)msg->getFieldAsBinary(VID_SESSION_IV, ucKeyBuffer, KEY_BUFFER_SIZE);
656 nSize = RSA_private_decrypt(keySize, ucKeyBuffer, ucSessionKey, privateKey, RSA_PKCS1_OAEP_PADDING);
657 if ((nSize == nIVLen) &&
658 (nIVLen <= EVP_CIPHER_iv_length(s_ciphers[ctx->m_cipher]())))
659 {
660 memcpy(ctx->m_iv, ucSessionKey, std::min(EVP_MAX_IV_LENGTH, nIVLen));
661 }
662 else
663 {
664 nxlog_debug(6, _T("NXCPEncryptionContext::create: IV decryption failed"));
665 delete_and_null(ctx);
666 }
667 }
668 else
669 {
670 nxlog_debug(6, _T("NXCPEncryptionContext::create: session key decryption failed"));
671 delete_and_null(ctx);
672 }
673 }
674 else
675 {
676 nxlog_debug(6, _T("NXCPEncryptionContext::create: key length mismatch (remote: %d local: %d)"), (int)msg->getFieldAsUInt16(VID_KEY_LENGTH), ctx->m_keyLength);
677 delete_and_null(ctx);
678 }
679 }
680 else
681 {
682 nxlog_debug(6, _T("NXCPEncryptionContext::create: initCipher(%d) call failed"), cipher);
683 delete_and_null(ctx);
684 }
685 return ctx;
686 #else
687 return new NXCPEncryptionContext;
688 #endif
689 }
690
691 /**
692 * Initialize cipher
693 */
694 bool NXCPEncryptionContext::initCipher(int cipher)
695 {
696 #ifdef _WITH_ENCRYPTION
697 if (s_ciphers[cipher] == NULL)
698 return false; // Unsupported cipher
699
700 if (!EVP_EncryptInit_ex(m_encryptor, s_ciphers[cipher](), NULL, NULL, NULL))
701 return false;
702 if (!EVP_DecryptInit_ex(m_decryptor, s_ciphers[cipher](), NULL, NULL, NULL))
703 return false;
704
705 switch(cipher)
706 {
707 case NXCP_CIPHER_AES_256:
708 m_keyLength = 32;
709 break;
710 case NXCP_CIPHER_AES_128:
711 m_keyLength = 16;
712 break;
713 case NXCP_CIPHER_BLOWFISH_256:
714 m_keyLength = 32;
715 break;
716 case NXCP_CIPHER_BLOWFISH_128:
717 m_keyLength = 16;
718 break;
719 case NXCP_CIPHER_IDEA:
720 m_keyLength = 16;
721 break;
722 case NXCP_CIPHER_3DES:
723 m_keyLength = 24;
724 break;
725 default:
726 return false;
727 }
728
729 if (!EVP_CIPHER_CTX_set_key_length(m_encryptor, m_keyLength) || !EVP_CIPHER_CTX_set_key_length(m_decryptor, m_keyLength))
730 return false;
731
732 // This check is needed because at least some OpenSSL versions return no error
733 // from EVP_CIPHER_CTX_set_key_length but still not change key length
734 if ((EVP_CIPHER_CTX_key_length(m_encryptor) != m_keyLength) || (EVP_CIPHER_CTX_key_length(m_decryptor) != m_keyLength))
735 return false;
736
737 m_cipher = cipher;
738 return true;
739 #else
740 return false;
741 #endif
742 }
743
744 /**
745 * Create encryption context from CMD_REQUEST_SESSION_KEY NXCP message
746 */
747 NXCPEncryptionContext *NXCPEncryptionContext::create(UINT32 ciphers)
748 {
749 NXCPEncryptionContext *ctx = new NXCPEncryptionContext;
750
751 #ifdef _WITH_ENCRYPTION
752 // Select cipher
753 bool selected = false;
754
755 if (ciphers & NXCP_SUPPORT_AES_256)
756 {
757 selected = ctx->initCipher(NXCP_CIPHER_AES_256);
758 }
759
760 if (!selected && (ciphers & NXCP_SUPPORT_BLOWFISH_256))
761 {
762 selected = ctx->initCipher(NXCP_CIPHER_BLOWFISH_256);
763 }
764
765 if (!selected && (ciphers & NXCP_SUPPORT_AES_128))
766 {
767 selected = ctx->initCipher(NXCP_CIPHER_AES_128);
768 }
769
770 if (!selected && (ciphers & NXCP_SUPPORT_BLOWFISH_128))
771 {
772 selected = ctx->initCipher(NXCP_CIPHER_BLOWFISH_128);
773 }
774
775 if (!selected && (ciphers & NXCP_SUPPORT_IDEA))
776 {
777 selected = ctx->initCipher(NXCP_CIPHER_IDEA);
778 }
779
780 if (!selected && (ciphers & NXCP_SUPPORT_3DES))
781 {
782 selected = ctx->initCipher(NXCP_CIPHER_3DES);
783 }
784
785 if (!selected)
786 {
787 delete ctx;
788 return NULL;
789 }
790
791 // Generate key
792 ctx->m_sessionKey = (BYTE *)malloc(ctx->m_keyLength);
793 RAND_bytes(ctx->m_sessionKey, ctx->m_keyLength);
794 RAND_bytes(ctx->m_iv, EVP_MAX_IV_LENGTH);
795 #endif
796
797 return ctx;
798 }
799
800 /**
801 * Encrypt message
802 */
803 NXCP_ENCRYPTED_MESSAGE *NXCPEncryptionContext::encryptMessage(NXCP_MESSAGE *msg)
804 {
805 if (msg->flags & s_noEncryptionFlag)
806 return (NXCP_ENCRYPTED_MESSAGE *)nx_memdup(msg, ntohl(msg->size));
807
808 #ifdef _WITH_ENCRYPTION
809 MutexLock(m_encryptorLock);
810
811 if (!EVP_EncryptInit_ex(m_encryptor, NULL, NULL, m_sessionKey, m_iv))
812 {
813 MutexUnlock(m_encryptorLock);
814 return NULL;
815 }
816
817 UINT32 msgSize = ntohl(msg->size);
818 NXCP_ENCRYPTED_MESSAGE *emsg =
819 (NXCP_ENCRYPTED_MESSAGE *)malloc(msgSize + NXCP_ENCRYPTION_HEADER_SIZE + EVP_CIPHER_block_size(EVP_CIPHER_CTX_cipher(m_encryptor)) + 8);
820 emsg->code = htons(CMD_ENCRYPTED_MESSAGE);
821 emsg->reserved = 0;
822
823 NXCP_ENCRYPTED_PAYLOAD_HEADER header;
824 header.dwChecksum = htonl(CalculateCRC32((BYTE *)msg, msgSize, 0));
825 header.dwReserved = 0;
826
827 int dataSize;
828 EVP_EncryptUpdate(m_encryptor, emsg->data, &dataSize, (BYTE *)&header, NXCP_EH_ENCRYPTED_BYTES);
829 msgSize = dataSize;
830 EVP_EncryptUpdate(m_encryptor, emsg->data + msgSize, &dataSize, (BYTE *)msg, ntohl(msg->size));
831 msgSize += dataSize;
832 EVP_EncryptFinal_ex(m_encryptor, emsg->data + msgSize, &dataSize);
833 msgSize += dataSize + NXCP_EH_UNENCRYPTED_BYTES;
834
835 MutexUnlock(m_encryptorLock);
836
837 if (msgSize % 8 != 0)
838 {
839 emsg->padding = (BYTE)(8 - (msgSize % 8));
840 msgSize += emsg->padding;
841 }
842 else
843 {
844 emsg->padding = 0;
845 }
846 emsg->size = htonl(msgSize);
847
848 return emsg;
849 #else /* _WITH_ENCRYPTION */
850 return NULL;
851 #endif
852 }
853
854 /**
855 * Decrypt message
856 */
857 bool NXCPEncryptionContext::decryptMessage(NXCP_ENCRYPTED_MESSAGE *msg, BYTE *decryptionBuffer)
858 {
859 #ifdef _WITH_ENCRYPTION
860 if (!EVP_DecryptInit_ex(m_decryptor, NULL, NULL, m_sessionKey, m_iv))
861 return false;
862
863 msg->size = ntohl(msg->size);
864 int dataSize;
865 EVP_DecryptUpdate(m_decryptor, decryptionBuffer, &dataSize, msg->data,
866 msg->size - NXCP_EH_UNENCRYPTED_BYTES - msg->padding);
867 EVP_DecryptFinal(m_decryptor, decryptionBuffer + dataSize, &dataSize);
868
869 NXCP_MESSAGE *clearMsg = (NXCP_MESSAGE *)(decryptionBuffer + NXCP_EH_ENCRYPTED_BYTES);
870 UINT32 msgSize = ntohl(clearMsg->size);
871 if (msgSize > msg->size)
872 return false; // Message decrypted incorrectly, because it can't be larger than encrypted
873 UINT32 crc32 = CalculateCRC32((BYTE *)clearMsg, msgSize, 0);
874 if (crc32 != ntohl(((NXCP_ENCRYPTED_PAYLOAD_HEADER *)decryptionBuffer)->dwChecksum))
875 return false; // Bad checksum
876
877 memcpy(msg, clearMsg, msgSize);
878 return true;
879 #else /* _WITH_ENCRYPTION */
880 return false;
881 #endif
882 }
883
884 /**
885 * Generate random bytes
886 */
887 void LIBNETXMS_EXPORTABLE GenerateRandomBytes(BYTE *buffer, size_t size)
888 {
889 #ifdef _WITH_ENCRYPTION
890 RAND_bytes(buffer, (int)size);
891 #else
892 srand((unsigned int)time(NULL));
893 for(size_t i = 0; i < size; i++)
894 buffer[i] = (BYTE)(rand() % 256);
895 #endif
896 }
897
898 /**
899 * Log OpenSSL error stack
900 */
901 void LIBNETXMS_EXPORTABLE LogOpenSSLErrorStack(int level)
902 {
903 #if defined(_WITH_ENCRYPTION) && WITH_OPENSSL
904 nxlog_debug(level, _T("OpenSSL error stack:"));
905 long err;
906 char buffer[128];
907 while((err = ERR_get_error()) != 0)
908 nxlog_debug(level, _T(" %hs"), ERR_error_string(err, buffer));
909 #endif
910 }