debug tags in certificate functions
[public/netxms.git] / src / server / core / cert.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2007-2017 Victor Kirhenshtein
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** File: cert.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24 #include <nxcrypto.h>
25
26 #define DEBUG_TAG _T("crypto.cert")
27
28 #ifdef _WITH_ENCRYPTION
29
30 // WARNING! this hack works only for d2i_X509(); be careful when adding new code
31 #ifdef OPENSSL_CONST
32 # undef OPENSSL_CONST
33 #endif
34 #if OPENSSL_VERSION_NUMBER >= 0x0090800fL
35 # define OPENSSL_CONST const
36 #else
37 # define OPENSSL_CONST
38 #endif
39
40 #if OPENSSL_VERSION_NUMBER < 0x10000000L
41 inline int EVP_PKEY_id(EVP_PKEY *key)
42 {
43 return key->type;
44 }
45 #endif
46
47 #if OPENSSL_VERSION_NUMBER < 0x10100000L
48 inline ASN1_TIME *X509_getm_notBefore(const X509 *x)
49 {
50 return X509_get_notBefore(x);
51 }
52
53 inline ASN1_TIME *X509_getm_notAfter(const X509 *x)
54 {
55 return X509_get_notAfter(x);
56 }
57 #endif
58
59 /**
60 * Server certificate file information
61 */
62 TCHAR *g_serverCACertificatesPath = NULL;
63 TCHAR g_serverCertificatePath[MAX_PATH] = _T("");
64 TCHAR g_serverCertificateKeyPath[MAX_PATH] = _T("");
65 char g_serverCertificatePassword[MAX_PASSWORD] = "";
66
67 /**
68 * Server certificate
69 */
70 static ObjectRefArray<X509> s_serverCACertificates(8, 8);
71 static X509 *s_serverCertificate = NULL;
72 static EVP_PKEY *s_serverCertificateKey = NULL;
73
74 /**
75 * Trusted CA certificate store
76 */
77 static X509_STORE *s_trustedCertificateStore = NULL;
78 static Mutex s_certificateStoreLock;
79
80 /**
81 * Issue certificate signed with server's certificate
82 */
83 X509 *IssueCertificate(X509_REQ *request, const char *ou, const char *cn, int days)
84 {
85 nxlog_debug_tag(DEBUG_TAG, 4, _T("IssueCertificate: new certificate request (CN override: %hs, OU override: %hs)"),
86 (cn != NULL) ? cn : "<not set>", (ou != NULL) ? ou : "<not set>");
87
88 X509_NAME *requestSubject = X509_REQ_get_subject_name(request);
89 if (requestSubject == NULL)
90 {
91 nxlog_debug_tag(DEBUG_TAG, 4, _T("IssueCertificate: cannot get subject from certificate request"));
92 return NULL;
93 }
94
95 X509 *cert = X509_new();
96 if (cert == NULL)
97 {
98 nxlog_debug_tag(DEBUG_TAG, 4, _T("IssueCertificate: call to X509_new() failed"));
99 return NULL;
100 }
101
102 if (X509_set_version(cert, 2) != 1)
103 {
104 nxlog_debug_tag(DEBUG_TAG, 4, _T("IssueCertificate: call to X509_set_version() failed"));
105 X509_free(cert);
106 return NULL;
107 }
108
109 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
110 ASN1_INTEGER *serial = ASN1_INTEGER_new();
111 #else
112 ASN1_INTEGER *serial = M_ASN1_INTEGER_new();
113 #endif
114 ASN1_INTEGER_set(serial, 0);
115 int rc = X509_set_serialNumber(cert, serial);
116 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
117 ASN1_INTEGER_free(serial);
118 #else
119 M_ASN1_INTEGER_free(serial);
120 #endif
121 if (rc != 1)
122 {
123 nxlog_debug_tag(DEBUG_TAG, 4, _T("IssueCertificate: cannot set certificate serial number"));
124 X509_free(cert);
125 return NULL;
126 }
127
128 X509_NAME *subject;
129 if ((cn != NULL) || (ou != NULL))
130 {
131 subject = X509_NAME_dup(requestSubject);
132 if (subject != NULL)
133 {
134 if (ou != NULL)
135 {
136 int idx = X509_NAME_get_index_by_NID(subject, NID_organizationalUnitName, -1);
137 if (idx != -1)
138 X509_NAME_delete_entry(subject, idx);
139 if (!X509_NAME_add_entry_by_txt(subject, "OU", MBSTRING_UTF8, (const BYTE *)ou, -1, -1, 0))
140 nxlog_debug_tag(DEBUG_TAG, 4, _T("IssueCertificate: X509_NAME_add_entry_by_txt failed for OU=%hs"), ou);
141 }
142 if (cn != NULL)
143 {
144 int idx = X509_NAME_get_index_by_NID(subject, NID_commonName, -1);
145 if (idx != -1)
146 X509_NAME_delete_entry(subject, idx);
147 if (!X509_NAME_add_entry_by_txt(subject, "CN", MBSTRING_UTF8, (const BYTE *)cn, -1, -1, 0))
148 nxlog_debug_tag(DEBUG_TAG, 4, _T("IssueCertificate: X509_NAME_add_entry_by_txt failed for CN=%hs"), cn);
149 }
150 }
151 else
152 {
153 nxlog_debug_tag(DEBUG_TAG, 4, _T("IssueCertificate: call to X509_NAME_dup() failed"));
154 }
155 }
156 else
157 {
158 subject = requestSubject;
159 }
160
161 if (subject == NULL)
162 {
163 X509_free(cert);
164 return NULL;
165 }
166
167 rc = X509_set_subject_name(cert, subject);
168 if (subject != requestSubject)
169 X509_NAME_free(subject);
170 if (rc != 1)
171 {
172 nxlog_debug_tag(DEBUG_TAG, 4, _T("IssueCertificate: call to X509_set_subject_name() failed"));
173 X509_free(cert);
174 return NULL;
175 }
176
177 X509_NAME *issuerName = X509_get_subject_name(s_serverCertificate);
178 if (issuerName == NULL)
179 {
180 nxlog_debug_tag(DEBUG_TAG, 4, _T("IssueCertificate: cannot get CA subject name"));
181 X509_free(cert);
182 return NULL;
183 }
184
185 if (X509_set_issuer_name(cert, issuerName) != 1)
186 {
187 nxlog_debug_tag(DEBUG_TAG, 4, _T("IssueCertificate: call to X509_set_issuer_name() failed"));
188 X509_free(cert);
189 return NULL;
190 }
191
192 EVP_PKEY *pubkey = X509_REQ_get_pubkey(request);
193 if (pubkey == NULL)
194 {
195 nxlog_debug_tag(DEBUG_TAG, 4, _T("IssueCertificate: call to X509_REQ_get_pubkey() failed"));
196 X509_free(cert);
197 return NULL;
198 }
199
200 if (X509_REQ_verify(request, pubkey) != 1)
201 {
202 nxlog_debug_tag(DEBUG_TAG, 4, _T("IssueCertificate: certificate request verification failed"));
203 EVP_PKEY_free(pubkey);
204 X509_free(cert);
205 return NULL;
206 }
207
208 rc = X509_set_pubkey(cert, pubkey);
209 EVP_PKEY_free(pubkey);
210 if (rc != 1)
211 {
212 nxlog_debug_tag(DEBUG_TAG, 4, _T("IssueCertificate: call to X509_set_pubkey() failed"));
213 X509_free(cert);
214 return NULL;
215 }
216
217 if (X509_gmtime_adj(X509_getm_notBefore(cert), 0) == NULL)
218 {
219 nxlog_debug_tag(DEBUG_TAG, 4, _T("IssueCertificate: cannot set start time"));
220 X509_free(cert);
221 return NULL;
222 }
223
224 if (X509_gmtime_adj(X509_getm_notAfter(cert), days * 86400) == NULL)
225 {
226 nxlog_debug_tag(DEBUG_TAG, 4, _T("IssueCertificate: cannot set end time"));
227 X509_free(cert);
228 return NULL;
229 }
230
231 if (X509_sign(cert, s_serverCertificateKey, EVP_sha256()) == 0)
232 {
233 nxlog_debug_tag(DEBUG_TAG, 4, _T("IssueCertificate: call to X509_sign() failed"));
234 X509_free(cert);
235 return NULL;
236 }
237
238 char subjectName[1024];
239 X509_NAME_oneline(X509_get_subject_name(cert), subjectName, 1024);
240 nxlog_debug_tag(DEBUG_TAG, 4, _T("IssueCertificate: new certificate with subject \"%hs\" issued successfully"), subjectName);
241 return cert;
242 }
243
244 /**
245 * Get CN from certificate
246 */
247 bool GetCertificateSubjectField(X509 *cert, int nid, TCHAR *buffer, size_t size)
248 {
249 X509_NAME *subject = X509_get_subject_name(cert);
250 if (subject == NULL)
251 return false;
252
253 int idx = X509_NAME_get_index_by_NID(subject, nid, -1);
254 if (idx == -1)
255 return false;
256
257 X509_NAME_ENTRY *entry = X509_NAME_get_entry(subject, idx);
258 if (entry == NULL)
259 return false;
260
261 ASN1_STRING *data = X509_NAME_ENTRY_get_data(entry);
262 if (data == NULL)
263 return false;
264
265 unsigned char *text;
266 ASN1_STRING_to_UTF8(&text, data);
267 #ifdef UNICODE
268 MultiByteToWideChar(CP_UTF8, 0, (char *)text, -1, buffer, (int)size);
269 #else
270 utf8_to_mb((char *)text, -1, buffer, (int)size);
271 #endif
272 buffer[size - 1] = 0;
273 OPENSSL_free(text);
274 return true;
275 }
276
277 /**
278 * Get CN from certificate
279 */
280 bool GetCertificateCN(X509 *cert, TCHAR *buffer, size_t size)
281 {
282 return GetCertificateSubjectField(cert, NID_commonName, buffer, size);
283 }
284
285 /**
286 * Get OU from certificate
287 */
288 bool GetCertificateOU(X509 *cert, TCHAR *buffer, size_t size)
289 {
290 return GetCertificateSubjectField(cert, NID_organizationalUnitName, buffer, size);
291 }
292
293 /**
294 * Get country name from server certificate
295 */
296 bool GetServerCertificateCountry(TCHAR *buffer, size_t size)
297 {
298 if (s_serverCertificate == NULL)
299 return false;
300 return GetCertificateSubjectField(s_serverCertificate, NID_countryName, buffer, size);
301 }
302
303 /**
304 * Get organization name from server certificate
305 */
306 bool GetServerCertificateOrganization(TCHAR *buffer, size_t size)
307 {
308 if (s_serverCertificate == NULL)
309 return false;
310 return GetCertificateSubjectField(s_serverCertificate, NID_organizationName, buffer, size);
311 }
312
313 /**
314 * Create X509 certificate structure from login message
315 */
316 X509 *CertificateFromLoginMessage(NXCPMessage *msg)
317 {
318 X509 *cert = NULL;
319 size_t len;
320 const BYTE *data = msg->getBinaryFieldPtr(VID_CERTIFICATE, &len);
321 if ((data != NULL) && (len > 0))
322 {
323 OPENSSL_CONST BYTE *p = (OPENSSL_CONST BYTE *)data;
324 cert = d2i_X509(NULL, &p, (long)len);
325 }
326 return cert;
327 }
328
329 /**
330 * Check public key
331 */
332 static BOOL CheckPublicKey(EVP_PKEY *key, const TCHAR *mappingData)
333 {
334 int pkeyLen;
335 unsigned char *ucBuf, *uctempBuf;
336 TCHAR *pkeyText;
337 BOOL valid;
338
339 pkeyLen = i2d_PublicKey(key, NULL);
340 ucBuf = (unsigned char *)malloc(pkeyLen +1);
341 uctempBuf = ucBuf;
342 i2d_PublicKey(key, &uctempBuf);
343
344 pkeyText = (TCHAR *)malloc((pkeyLen * 2 + 1) * sizeof(TCHAR));
345 BinToStr(ucBuf, pkeyLen, pkeyText);
346
347 valid = !_tcscmp(pkeyText, mappingData);
348
349 free(ucBuf);
350 free(pkeyText);
351
352 return valid;
353 }
354
355 /**
356 * Check ciertificate's CN
357 */
358 static BOOL CheckCommonName(X509 *cert, const TCHAR *cn)
359 {
360 TCHAR certCn[256];
361 if (!GetCertificateCN(cert, certCn, 256))
362 return FALSE;
363
364 nxlog_debug_tag(DEBUG_TAG, 3, _T("Certificate CN=\"%s\", user CN=\"%s\""), certCn, cn);
365 return !_tcsicmp(certCn, cn);
366 }
367
368 /**
369 * Validate user's certificate
370 */
371 bool ValidateUserCertificate(X509 *cert, const TCHAR *login, const BYTE *challenge, const BYTE *signature,
372 size_t sigLen, int mappingMethod, const TCHAR *mappingData)
373 {
374 BOOL bValid = FALSE;
375
376 char subjectName[1024];
377 X509_NAME_oneline(X509_get_subject_name(cert), subjectName, 1024);
378 #ifdef UNICODE
379 WCHAR certSubject[1024];
380 MultiByteToWideChar(CP_UTF8, 0, subjectName, -1, certSubject, 1024);
381 #else
382 const char *certSubject = subjectName;
383 #endif
384
385 DbgPrintf(3, _T("Validating certificate \"%s\" for user %s"), certSubject, login);
386 s_certificateStoreLock.lock();
387
388 if (s_trustedCertificateStore == NULL)
389 {
390 DbgPrintf(3, _T("Cannot validate user certificate because certificate store is not initialized"));
391 s_certificateStoreLock.unlock();
392 return FALSE;
393 }
394
395 // Validate signature
396 EVP_PKEY *pKey = X509_get_pubkey(cert);
397 if (pKey != NULL)
398 {
399 BYTE hash[SHA1_DIGEST_SIZE];
400 CalculateSHA1Hash(challenge, CLIENT_CHALLENGE_SIZE, hash);
401 switch(EVP_PKEY_id(pKey))
402 {
403 case EVP_PKEY_RSA:
404 bValid = RSA_verify(NID_sha1, hash, SHA1_DIGEST_SIZE, signature, static_cast<unsigned int>(sigLen), EVP_PKEY_get1_RSA(pKey));
405 break;
406 default:
407 DbgPrintf(3, _T("Unknown key type %d in certificate \"%s\" for user %s"), EVP_PKEY_id(pKey), certSubject, login);
408 break;
409 }
410 }
411
412 // Validate certificate
413 if (bValid)
414 {
415 X509_STORE_CTX *pStore = X509_STORE_CTX_new();
416 if (pStore != NULL)
417 {
418 X509_STORE_CTX_init(pStore, s_trustedCertificateStore, cert, NULL);
419 bValid = X509_verify_cert(pStore);
420 X509_STORE_CTX_free(pStore);
421 DbgPrintf(3, _T("Certificate \"%s\" for user %s - validation %s"),
422 certSubject, login, bValid ? _T("successful") : _T("failed"));
423 }
424 else
425 {
426 TCHAR szBuffer[256];
427 DbgPrintf(3, _T("X509_STORE_CTX_new() failed: %s"), _ERR_error_tstring(ERR_get_error(), szBuffer));
428 bValid = FALSE;
429 }
430 }
431
432 // Check user mapping
433 if (bValid)
434 {
435 switch(mappingMethod)
436 {
437 case USER_MAP_CERT_BY_SUBJECT:
438 bValid = !_tcsicmp(certSubject, CHECK_NULL_EX(mappingData));
439 break;
440 case USER_MAP_CERT_BY_PUBKEY:
441 bValid = CheckPublicKey(pKey, CHECK_NULL_EX(mappingData));
442 break;
443 case USER_MAP_CERT_BY_CN:
444 bValid = CheckCommonName(cert, ((mappingData != NULL) && (*mappingData != 0)) ? mappingData : login);
445 break;
446 default:
447 DbgPrintf(3, _T("Invalid certificate mapping method %d for user %s"), mappingMethod, login);
448 bValid = FALSE;
449 break;
450 }
451 }
452
453 s_certificateStoreLock.unlock();
454 return bValid;
455 }
456
457 /**
458 * Validate agent certificate
459 */
460 bool ValidateAgentCertificate(X509 *cert)
461 {
462 X509_STORE *store = X509_STORE_new();
463 if (store == NULL)
464 {
465 nxlog_debug_tag(DEBUG_TAG, 3, _T("ValidateAgentCertificate: cannot create certificate store"));
466 }
467
468 for(int i = 0; i < s_serverCACertificates.size(); i++)
469 X509_STORE_add_cert(store, s_serverCACertificates.get(i));
470 X509_STORE_add_cert(store, s_serverCertificate);
471 bool valid = false;
472
473 X509_STORE_CTX *ctx = X509_STORE_CTX_new();
474 if (ctx != NULL)
475 {
476 X509_STORE_CTX_init(ctx, store, cert, NULL);
477 valid = (X509_verify_cert(ctx) == 1);
478 X509_STORE_CTX_free(ctx);
479 }
480 else
481 {
482 TCHAR buffer[256];
483 nxlog_debug_tag(DEBUG_TAG, 3, _T("ValidateAgentCertificate: X509_STORE_CTX_new() failed: %s"), _ERR_error_tstring(ERR_get_error(), buffer));
484 }
485
486 X509_STORE_free(store);
487 return valid;
488 }
489
490 /**
491 * Reload certificates from database
492 */
493 void ReloadCertificates()
494 {
495 s_certificateStoreLock.lock();
496
497 if (s_trustedCertificateStore != NULL)
498 X509_STORE_free(s_trustedCertificateStore);
499
500 s_trustedCertificateStore = X509_STORE_new();
501 if (s_trustedCertificateStore != NULL)
502 {
503 // Add server's certificate as trusted
504 if (s_serverCertificate != NULL)
505 X509_STORE_add_cert(s_trustedCertificateStore, s_serverCertificate);
506
507 // Add server's CA certificate as trusted
508 for(int i = 0; i < s_serverCACertificates.size(); i++)
509 X509_STORE_add_cert(s_trustedCertificateStore, s_serverCACertificates.get(i));
510
511 TCHAR szBuffer[256];
512 _sntprintf(szBuffer, 256, _T("SELECT cert_data,subject FROM certificates WHERE cert_type=%d"), CERT_TYPE_TRUSTED_CA);
513 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
514 DB_RESULT hResult = DBSelect(hdb, szBuffer);
515 if (hResult != NULL)
516 {
517 int loaded = 0;
518 int count = DBGetNumRows(hResult);
519 for(int i = 0; i < count; i++)
520 {
521 TCHAR *certData = DBGetField(hResult, i, 0, NULL, 0);
522 if (certData != NULL)
523 {
524 size_t len = _tcslen(certData);
525 BYTE *binCert = (BYTE *)malloc(len);
526 StrToBin(certData, binCert, len);
527 free(certData);
528 OPENSSL_CONST BYTE *p = binCert;
529 X509 *cert = d2i_X509(NULL, &p, (long)len);
530 free(binCert);
531 if (cert != NULL)
532 {
533 if (X509_STORE_add_cert(s_trustedCertificateStore, cert))
534 {
535 loaded++;
536 }
537 else
538 {
539 TCHAR subject[256];
540 nxlog_write(MSG_CANNOT_ADD_CERT, EVENTLOG_ERROR_TYPE,
541 "ss", DBGetField(hResult, i, 1, subject, 256),
542 _ERR_error_tstring(ERR_get_error(), szBuffer));
543 }
544 X509_free(cert); // X509_STORE_add_cert increments reference count
545 }
546 else
547 {
548 TCHAR subject[256];
549 nxlog_write(MSG_CANNOT_LOAD_CERT, EVENTLOG_ERROR_TYPE,
550 "ss", DBGetField(hResult, i, 1, subject, 256),
551 _ERR_error_tstring(ERR_get_error(), szBuffer));
552 }
553 }
554 }
555 DBFreeResult(hResult);
556
557 if (loaded > 0)
558 nxlog_write(MSG_CA_CERTIFICATES_LOADED, EVENTLOG_INFORMATION_TYPE, "d", loaded);
559 }
560 DBConnectionPoolReleaseConnection(hdb);
561 }
562 else
563 {
564 TCHAR buffer[256];
565 nxlog_write(MSG_CANNOT_INIT_CERT_STORE, EVENTLOG_ERROR_TYPE, "s", _ERR_error_tstring(ERR_get_error(), buffer));
566 }
567
568 s_certificateStoreLock.unlock();
569 }
570
571 /**
572 * Certificate stuff initialization
573 */
574 void InitCertificates()
575 {
576 ReloadCertificates();
577 }
578
579 /**
580 * Load server certificate
581 */
582 bool LoadServerCertificate(RSA **serverKey)
583 {
584 if (g_serverCertificatePath[0] == 0)
585 {
586 nxlog_write(MSG_SERVER_CERT_NOT_SET, NXLOG_INFO, NULL);
587 return false;
588 }
589
590 // Load server CA certificates
591 TCHAR *curr = g_serverCACertificatesPath;
592 TCHAR *next = _tcschr(curr, _T('\n'));
593 while(next != NULL)
594 {
595 *next = 0;
596
597 nxlog_debug_tag(DEBUG_TAG, 5, _T("Loading CA certificate from %s"), curr);
598 FILE *f = _tfopen(curr, _T("r"));
599 if (f == NULL)
600 {
601 nxlog_write(MSG_CANNOT_LOAD_SERVER_CERT, NXLOG_ERROR, "ss", curr, _tcserror(errno));
602 return false;
603 }
604 X509 *cert = PEM_read_X509(f, NULL, NULL, NULL);
605 fclose(f);
606 if (cert == NULL)
607 {
608 TCHAR buffer[1024];
609 nxlog_write(MSG_CANNOT_LOAD_SERVER_CERT, NXLOG_ERROR, "ss", curr, _ERR_error_tstring(ERR_get_error(), buffer));
610 return false;
611 }
612 s_serverCACertificates.add(cert);
613
614 curr = next + 1;
615 next = _tcschr(curr, _T('\n'));
616 }
617
618 // Load server certificate and private key
619 FILE *f = _tfopen(g_serverCertificatePath, _T("r"));
620 if (f == NULL)
621 {
622 nxlog_write(MSG_CANNOT_LOAD_SERVER_CERT, NXLOG_ERROR, "ss", g_serverCertificatePath, _tcserror(errno));
623 return false;
624 }
625
626 DecryptPasswordA("system", g_serverCertificatePassword, g_serverCertificatePassword, MAX_PASSWORD);
627 s_serverCertificate = PEM_read_X509(f, NULL, NULL, g_serverCertificatePassword);
628 if (g_serverCertificateKeyPath[0] != 0)
629 {
630 // Server key is in separate file
631 fclose(f);
632 f = _tfopen(g_serverCertificateKeyPath, _T("r"));
633 if (f == NULL)
634 {
635 nxlog_write(MSG_CANNOT_LOAD_SERVER_CERT, NXLOG_ERROR, "ss", g_serverCertificateKeyPath, _tcserror(errno));
636 return false;
637 }
638 }
639 s_serverCertificateKey = PEM_read_PrivateKey(f, NULL, NULL, g_serverCertificatePassword);
640 fclose(f);
641
642 if ((s_serverCertificate == NULL) || (s_serverCertificateKey == NULL))
643 {
644 TCHAR buffer[1024];
645 nxlog_write(MSG_CANNOT_LOAD_SERVER_CERT, NXLOG_ERROR, "ss", g_serverCertificatePath, _ERR_error_tstring(ERR_get_error(), buffer));
646 return false;
647 }
648
649 RSA *privKey = EVP_PKEY_get1_RSA(s_serverCertificateKey);
650 RSA *pubKey = EVP_PKEY_get1_RSA(X509_get_pubkey(s_serverCertificate));
651 if ((privKey != NULL) && (pubKey != NULL))
652 {
653 // Combine into one key
654 int len = i2d_RSAPublicKey(pubKey, NULL);
655 len += i2d_RSAPrivateKey(privKey, NULL);
656 BYTE *buffer = (BYTE *)malloc(len);
657
658 BYTE *pos = buffer;
659 i2d_RSAPublicKey(pubKey, &pos);
660 i2d_RSAPrivateKey(privKey, &pos);
661
662 *serverKey = RSAKeyFromData(buffer, len, true);
663 free(buffer);
664 }
665
666 return true;
667 }
668
669 #if HAVE_X509_STORE_SET_VERIFY_CB
670
671 /**
672 * Certificate verification callback
673 */
674 static int CertVerifyCallback(int success, X509_STORE_CTX *ctx)
675 {
676 if (!success)
677 {
678 X509 *cert = X509_STORE_CTX_get_current_cert(ctx);
679 int error = X509_STORE_CTX_get_error(ctx);
680 int depth = X509_STORE_CTX_get_error_depth(ctx);
681 char subjectName[1024];
682 X509_NAME_oneline(X509_get_subject_name(cert), subjectName, 1024);
683 nxlog_debug_tag(DEBUG_TAG, 4, _T("Certificate \"%hs\" verification error %d (%hs) at depth %d"),
684 subjectName, error, X509_verify_cert_error_string(error), depth);
685 }
686 return success;
687 }
688
689 #endif /* HAVE_X509_STORE_SET_VERIFY_CB */
690
691 /**
692 * Setup server-side TLS context
693 */
694 bool SetupServerTlsContext(SSL_CTX *context)
695 {
696 if ((s_serverCertificate == NULL) || (s_serverCertificateKey == NULL))
697 return false;
698
699 X509_STORE *store = X509_STORE_new();
700 if (store == NULL)
701 {
702 nxlog_debug_tag(DEBUG_TAG, 3, _T("SetupServerTlsContext: cannot create certificate store"));
703 return false;
704 }
705 #if HAVE_X509_STORE_SET_VERIFY_CB
706 X509_STORE_set_verify_cb(store, CertVerifyCallback);
707 #endif
708 X509_STORE_add_cert(store, s_serverCertificate);
709 for(int i = 0; i < s_serverCACertificates.size(); i++)
710 X509_STORE_add_cert(store, s_serverCACertificates.get(i));
711 SSL_CTX_set_cert_store(context, store);
712 SSL_CTX_use_certificate(context, s_serverCertificate);
713 SSL_CTX_use_PrivateKey(context, s_serverCertificateKey);
714 SSL_CTX_set_verify(context, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, NULL);
715 return true;
716 }
717
718 #else /* _WITH_ENCRYPTION */
719
720 /**
721 * Stub for certificate initialization
722 */
723 void InitCertificates()
724 {
725 }
726
727 #endif /* _WITH_ENCRYPTION */