calls to functions deprecated in OpenSSL 1.1 replaced with compatible ones
[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 #ifdef _WITH_ENCRYPTION
27
28 // WARNING! this hack works only for d2i_X509(); be careful when adding new code
29 #ifdef OPENSSL_CONST
30 # undef OPENSSL_CONST
31 #endif
32 #if OPENSSL_VERSION_NUMBER >= 0x0090800fL
33 # define OPENSSL_CONST const
34 #else
35 # define OPENSSL_CONST
36 #endif
37
38 #if OPENSSL_VERSION_NUMBER < 0x10000000L
39 inline int EVP_PKEY_id(EVP_PKEY *key)
40 {
41 return key->type;
42 }
43 #endif
44
45 #if OPENSSL_VERSION_NUMBER < 0x10100000L
46 inline ASN1_TIME *X509_getm_notBefore(const X509 *x)
47 {
48 return X509_get_notBefore(x);
49 }
50
51 inline ASN1_TIME *X509_getm_notAfter(const X509 *x)
52 {
53 return X509_get_notAfter(x);
54 }
55 #endif
56
57 /**
58 * Server certificate file information
59 */
60 TCHAR *g_serverCACertificatesPath = NULL;
61 TCHAR g_serverCertificatePath[MAX_PATH] = _T("");
62 TCHAR g_serverCertificateKeyPath[MAX_PATH] = _T("");
63 char g_serverCertificatePassword[MAX_PASSWORD] = "";
64
65 /**
66 * Server certificate
67 */
68 static ObjectRefArray<X509> s_serverCACertificates(8, 8);
69 static X509 *s_serverCertificate = NULL;
70 static EVP_PKEY *s_serverCertificateKey = NULL;
71
72 /**
73 * Trusted CA certificate store
74 */
75 static X509_STORE *s_trustedCertificateStore = NULL;
76 static Mutex s_certificateStoreLock;
77
78 /**
79 * Issue certificate signed with server's certificate
80 */
81 X509 *IssueCertificate(X509_REQ *request, const char *ou, const char *cn, int days)
82 {
83 nxlog_debug(4, _T("IssueCertificate: new certificate request (CN override: %hs, OU override: %hs)"),
84 (cn != NULL) ? cn : "<not set>", (ou != NULL) ? ou : "<not set>");
85
86 X509_NAME *requestSubject = X509_REQ_get_subject_name(request);
87 if (requestSubject == NULL)
88 {
89 nxlog_debug(4, _T("IssueCertificate: cannot get subject from certificate request"));
90 return NULL;
91 }
92
93 X509 *cert = X509_new();
94 if (cert == NULL)
95 {
96 nxlog_debug(4, _T("IssueCertificate: call to X509_new() failed"));
97 return NULL;
98 }
99
100 if (X509_set_version(cert, 2) != 1)
101 {
102 nxlog_debug(4, _T("IssueCertificate: call to X509_set_version() failed"));
103 X509_free(cert);
104 return NULL;
105 }
106
107 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
108 ASN1_INTEGER *serial = ASN1_INTEGER_new();
109 #else
110 ASN1_INTEGER *serial = M_ASN1_INTEGER_new();
111 #endif
112 ASN1_INTEGER_set(serial, 0);
113 int rc = X509_set_serialNumber(cert, serial);
114 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
115 ASN1_INTEGER_free(serial);
116 #else
117 M_ASN1_INTEGER_free(serial);
118 #endif
119 if (rc != 1)
120 {
121 nxlog_debug(4, _T("IssueCertificate: cannot set certificate serial number"));
122 X509_free(cert);
123 return NULL;
124 }
125
126 X509_NAME *subject;
127 if ((cn != NULL) || (ou != NULL))
128 {
129 subject = X509_NAME_dup(requestSubject);
130 if (subject != NULL)
131 {
132 if (ou != NULL)
133 {
134 int idx = X509_NAME_get_index_by_NID(subject, NID_organizationalUnitName, -1);
135 if (idx != -1)
136 X509_NAME_delete_entry(subject, idx);
137 if (!X509_NAME_add_entry_by_txt(subject, "OU", MBSTRING_UTF8, (const BYTE *)ou, -1, -1, 0))
138 nxlog_debug(4, _T("IssueCertificate: X509_NAME_add_entry_by_txt failed for OU=%hs"), ou);
139 }
140 if (cn != NULL)
141 {
142 int idx = X509_NAME_get_index_by_NID(subject, NID_commonName, -1);
143 if (idx != -1)
144 X509_NAME_delete_entry(subject, idx);
145 if (!X509_NAME_add_entry_by_txt(subject, "CN", MBSTRING_UTF8, (const BYTE *)cn, -1, -1, 0))
146 nxlog_debug(4, _T("IssueCertificate: X509_NAME_add_entry_by_txt failed for CN=%hs"), cn);
147 }
148 }
149 else
150 {
151 nxlog_debug(4, _T("IssueCertificate: call to X509_NAME_dup() failed"));
152 }
153 }
154 else
155 {
156 subject = requestSubject;
157 }
158
159 if (subject == NULL)
160 {
161 X509_free(cert);
162 return NULL;
163 }
164
165 rc = X509_set_subject_name(cert, subject);
166 if (subject != requestSubject)
167 X509_NAME_free(subject);
168 if (rc != 1)
169 {
170 nxlog_debug(4, _T("IssueCertificate: call to X509_set_subject_name() failed"));
171 X509_free(cert);
172 return NULL;
173 }
174
175 X509_NAME *issuerName = X509_get_subject_name(s_serverCertificate);
176 if (issuerName == NULL)
177 {
178 nxlog_debug(4, _T("IssueCertificate: cannot get CA subject name"));
179 X509_free(cert);
180 return NULL;
181 }
182
183 if (X509_set_issuer_name(cert, issuerName) != 1)
184 {
185 nxlog_debug(4, _T("IssueCertificate: call to X509_set_issuer_name() failed"));
186 X509_free(cert);
187 return NULL;
188 }
189
190 EVP_PKEY *pubkey = X509_REQ_get_pubkey(request);
191 if (pubkey == NULL)
192 {
193 nxlog_debug(4, _T("IssueCertificate: call to X509_REQ_get_pubkey() failed"));
194 X509_free(cert);
195 return NULL;
196 }
197
198 if (X509_REQ_verify(request, pubkey) != 1)
199 {
200 nxlog_debug(4, _T("IssueCertificate: certificate request verification failed"));
201 EVP_PKEY_free(pubkey);
202 X509_free(cert);
203 return NULL;
204 }
205
206 rc = X509_set_pubkey(cert, pubkey);
207 EVP_PKEY_free(pubkey);
208 if (rc != 1)
209 {
210 nxlog_debug(4, _T("IssueCertificate: call to X509_set_pubkey() failed"));
211 X509_free(cert);
212 return NULL;
213 }
214
215 if (X509_gmtime_adj(X509_getm_notBefore(cert), 0) == NULL)
216 {
217 nxlog_debug(4, _T("IssueCertificate: cannot set start time"));
218 X509_free(cert);
219 return NULL;
220 }
221
222 if (X509_gmtime_adj(X509_getm_notAfter(cert), days * 86400) == NULL)
223 {
224 nxlog_debug(4, _T("IssueCertificate: cannot set end time"));
225 X509_free(cert);
226 return NULL;
227 }
228
229 if (X509_sign(cert, s_serverCertificateKey, EVP_sha256()) == 0)
230 {
231 nxlog_debug(4, _T("IssueCertificate: call to X509_sign() failed"));
232 X509_free(cert);
233 return NULL;
234 }
235
236 char subjectName[1024];
237 X509_NAME_oneline(X509_get_subject_name(cert), subjectName, 1024);
238 nxlog_debug(4, _T("IssueCertificate: new certificate with subject \"%hs\" issued successfully"), subjectName);
239 return cert;
240 }
241
242 /**
243 * Get CN from certificate
244 */
245 bool GetCertificateSubjectField(X509 *cert, int nid, TCHAR *buffer, size_t size)
246 {
247 X509_NAME *subject = X509_get_subject_name(cert);
248 if (subject == NULL)
249 return false;
250
251 int idx = X509_NAME_get_index_by_NID(subject, nid, -1);
252 if (idx == -1)
253 return false;
254
255 X509_NAME_ENTRY *entry = X509_NAME_get_entry(subject, idx);
256 if (entry == NULL)
257 return false;
258
259 ASN1_STRING *data = X509_NAME_ENTRY_get_data(entry);
260 if (data == NULL)
261 return false;
262
263 unsigned char *text;
264 ASN1_STRING_to_UTF8(&text, data);
265 #ifdef UNICODE
266 MultiByteToWideChar(CP_UTF8, 0, (char *)text, -1, buffer, (int)size);
267 #else
268 utf8_to_mb((char *)text, -1, buffer, (int)size);
269 #endif
270 buffer[size - 1] = 0;
271 OPENSSL_free(text);
272 return true;
273 }
274
275 /**
276 * Get CN from certificate
277 */
278 bool GetCertificateCN(X509 *cert, TCHAR *buffer, size_t size)
279 {
280 return GetCertificateSubjectField(cert, NID_commonName, buffer, size);
281 }
282
283 /**
284 * Get OU from certificate
285 */
286 bool GetCertificateOU(X509 *cert, TCHAR *buffer, size_t size)
287 {
288 return GetCertificateSubjectField(cert, NID_organizationalUnitName, buffer, size);
289 }
290
291 /**
292 * Get country name from server certificate
293 */
294 bool GetServerCertificateCountry(TCHAR *buffer, size_t size)
295 {
296 if (s_serverCertificate == NULL)
297 return false;
298 return GetCertificateSubjectField(s_serverCertificate, NID_countryName, buffer, size);
299 }
300
301 /**
302 * Get organization name from server certificate
303 */
304 bool GetServerCertificateOrganization(TCHAR *buffer, size_t size)
305 {
306 if (s_serverCertificate == NULL)
307 return false;
308 return GetCertificateSubjectField(s_serverCertificate, NID_organizationName, buffer, size);
309 }
310
311 /**
312 * Create X509 certificate structure from login message
313 */
314 X509 *CertificateFromLoginMessage(NXCPMessage *msg)
315 {
316 X509 *cert = NULL;
317 size_t len;
318 const BYTE *data = msg->getBinaryFieldPtr(VID_CERTIFICATE, &len);
319 if ((data != NULL) && (len > 0))
320 {
321 OPENSSL_CONST BYTE *p = (OPENSSL_CONST BYTE *)data;
322 cert = d2i_X509(NULL, &p, (long)len);
323 }
324 return cert;
325 }
326
327 /**
328 * Check public key
329 */
330 static BOOL CheckPublicKey(EVP_PKEY *key, const TCHAR *mappingData)
331 {
332 int pkeyLen;
333 unsigned char *ucBuf, *uctempBuf;
334 TCHAR *pkeyText;
335 BOOL valid;
336
337 pkeyLen = i2d_PublicKey(key, NULL);
338 ucBuf = (unsigned char *)malloc(pkeyLen +1);
339 uctempBuf = ucBuf;
340 i2d_PublicKey(key, &uctempBuf);
341
342 pkeyText = (TCHAR *)malloc((pkeyLen * 2 + 1) * sizeof(TCHAR));
343 BinToStr(ucBuf, pkeyLen, pkeyText);
344
345 valid = !_tcscmp(pkeyText, mappingData);
346
347 free(ucBuf);
348 free(pkeyText);
349
350 return valid;
351 }
352
353 /**
354 * Check ciertificate's CN
355 */
356 static BOOL CheckCommonName(X509 *cert, const TCHAR *cn)
357 {
358 TCHAR certCn[256];
359 if (!GetCertificateCN(cert, certCn, 256))
360 return FALSE;
361
362 nxlog_debug(3, _T("Certificate CN=\"%s\", user CN=\"%s\""), certCn, cn);
363 return !_tcsicmp(certCn, cn);
364 }
365
366 /**
367 * Validate user's certificate
368 */
369 BOOL ValidateUserCertificate(X509 *pCert, const TCHAR *pszLogin, BYTE *pChallenge, BYTE *pSignature,
370 UINT32 dwSigLen, int nMappingMethod, const TCHAR *pszMappingData)
371 {
372 BOOL bValid = FALSE;
373
374 char subjectName[1024];
375 X509_NAME_oneline(X509_get_subject_name(pCert), subjectName, 1024);
376 #ifdef UNICODE
377 WCHAR certSubject[1024];
378 MultiByteToWideChar(CP_UTF8, 0, subjectName, -1, certSubject, 1024);
379 #else
380 const char *certSubject = subjectName;
381 #endif
382
383 DbgPrintf(3, _T("Validating certificate \"%s\" for user %s"), certSubject, pszLogin);
384 s_certificateStoreLock.lock();
385
386 if (s_trustedCertificateStore == NULL)
387 {
388 DbgPrintf(3, _T("Cannot validate user certificate because certificate store is not initialized"));
389 s_certificateStoreLock.unlock();
390 return FALSE;
391 }
392
393 // Validate signature
394 EVP_PKEY *pKey = X509_get_pubkey(pCert);
395 if (pKey != NULL)
396 {
397 BYTE hash[SHA1_DIGEST_SIZE];
398 CalculateSHA1Hash(pChallenge, CLIENT_CHALLENGE_SIZE, hash);
399 switch(EVP_PKEY_id(pKey))
400 {
401 case EVP_PKEY_RSA:
402 bValid = RSA_verify(NID_sha1, hash, SHA1_DIGEST_SIZE, pSignature, dwSigLen, EVP_PKEY_get1_RSA(pKey));
403 break;
404 default:
405 DbgPrintf(3, _T("Unknown key type %d in certificate \"%s\" for user %s"), EVP_PKEY_id(pKey), certSubject, pszLogin);
406 break;
407 }
408 }
409
410 // Validate certificate
411 if (bValid)
412 {
413 X509_STORE_CTX *pStore = X509_STORE_CTX_new();
414 if (pStore != NULL)
415 {
416 X509_STORE_CTX_init(pStore, s_trustedCertificateStore, pCert, NULL);
417 bValid = X509_verify_cert(pStore);
418 X509_STORE_CTX_free(pStore);
419 DbgPrintf(3, _T("Certificate \"%s\" for user %s - validation %s"),
420 certSubject, pszLogin, bValid ? _T("successful") : _T("failed"));
421 }
422 else
423 {
424 TCHAR szBuffer[256];
425
426 DbgPrintf(3, _T("X509_STORE_CTX_new() failed: %s"), _ERR_error_tstring(ERR_get_error(), szBuffer));
427 bValid = FALSE;
428 }
429 }
430
431 // Check user mapping
432 if (bValid)
433 {
434 switch(nMappingMethod)
435 {
436 case USER_MAP_CERT_BY_SUBJECT:
437 bValid = !_tcsicmp(certSubject, CHECK_NULL_EX(pszMappingData));
438 break;
439 case USER_MAP_CERT_BY_PUBKEY:
440 bValid = CheckPublicKey(pKey, CHECK_NULL_EX(pszMappingData));
441 break;
442 case USER_MAP_CERT_BY_CN:
443 bValid = CheckCommonName(pCert, ((pszMappingData != NULL) && (*pszMappingData != 0)) ? pszMappingData : pszLogin);
444 break;
445 default:
446 DbgPrintf(3, _T("Invalid certificate mapping method %d for user %s"), nMappingMethod, pszLogin);
447 bValid = FALSE;
448 break;
449 }
450 }
451
452 s_certificateStoreLock.unlock();
453
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(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(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 FILE *f = _tfopen(curr, _T("r"));
598 if (f == NULL)
599 {
600 nxlog_write(MSG_CANNOT_LOAD_SERVER_CERT, NXLOG_ERROR, "ss", curr, _tcserror(errno));
601 return false;
602 }
603 X509 *cert = PEM_read_X509(f, NULL, NULL, NULL);
604 fclose(f);
605 if (cert == NULL)
606 {
607 TCHAR buffer[1024];
608 nxlog_write(MSG_CANNOT_LOAD_SERVER_CERT, NXLOG_ERROR, "ss", curr, _ERR_error_tstring(ERR_get_error(), buffer));
609 return false;
610 }
611 s_serverCACertificates.add(cert);
612
613 curr = next + 1;
614 next = _tcschr(curr, _T('\n'));
615 }
616
617 // Load server certificate and private key
618 FILE *f = _tfopen(g_serverCertificatePath, _T("r"));
619 if (f == NULL)
620 {
621 nxlog_write(MSG_CANNOT_LOAD_SERVER_CERT, NXLOG_ERROR, "ss", g_serverCertificatePath, _tcserror(errno));
622 return false;
623 }
624
625 DecryptPasswordA("system", g_serverCertificatePassword, g_serverCertificatePassword, MAX_PASSWORD);
626 s_serverCertificate = PEM_read_X509(f, NULL, NULL, g_serverCertificatePassword);
627 if (g_serverCertificateKeyPath[0] != 0)
628 {
629 // Server key is in separate file
630 fclose(f);
631 f = _tfopen(g_serverCertificateKeyPath, _T("r"));
632 if (f == NULL)
633 {
634 nxlog_write(MSG_CANNOT_LOAD_SERVER_CERT, NXLOG_ERROR, "ss", g_serverCertificateKeyPath, _tcserror(errno));
635 return false;
636 }
637 }
638 s_serverCertificateKey = PEM_read_PrivateKey(f, NULL, NULL, g_serverCertificatePassword);
639 fclose(f);
640
641 if ((s_serverCertificate == NULL) || (s_serverCertificateKey == NULL))
642 {
643 TCHAR buffer[1024];
644 nxlog_write(MSG_CANNOT_LOAD_SERVER_CERT, NXLOG_ERROR, "ss", g_serverCertificatePath, _ERR_error_tstring(ERR_get_error(), buffer));
645 return false;
646 }
647
648 RSA *privKey = EVP_PKEY_get1_RSA(s_serverCertificateKey);
649 RSA *pubKey = EVP_PKEY_get1_RSA(X509_get_pubkey(s_serverCertificate));
650 if ((privKey != NULL) && (pubKey != NULL))
651 {
652 // Combine into one key
653 int len = i2d_RSAPublicKey(pubKey, NULL);
654 len += i2d_RSAPrivateKey(privKey, NULL);
655 BYTE *buffer = (BYTE *)malloc(len);
656
657 BYTE *pos = buffer;
658 i2d_RSAPublicKey(pubKey, &pos);
659 i2d_RSAPrivateKey(privKey, &pos);
660
661 *serverKey = RSAKeyFromData(buffer, len, true);
662 free(buffer);
663 }
664
665 return true;
666 }
667
668 #if HAVE_X509_STORE_SET_VERIFY_CB
669
670 /**
671 * Certificate verification callback
672 */
673 static int CertVerifyCallback(int success, X509_STORE_CTX *ctx)
674 {
675 if (!success)
676 {
677 X509 *cert = X509_STORE_CTX_get_current_cert(ctx);
678 int error = X509_STORE_CTX_get_error(ctx);
679 int depth = X509_STORE_CTX_get_error_depth(ctx);
680 char subjectName[1024];
681 X509_NAME_oneline(X509_get_subject_name(cert), subjectName, 1024);
682 nxlog_debug(4, _T("Certificate \"%hs\" verification error %d (%hs) at depth %d"),
683 subjectName, error, X509_verify_cert_error_string(error), depth);
684 }
685 return success;
686 }
687
688 #endif /* HAVE_X509_STORE_SET_VERIFY_CB */
689
690 /**
691 * Setup server-side TLS context
692 */
693 bool SetupServerTlsContext(SSL_CTX *context)
694 {
695 if ((s_serverCertificate == NULL) || (s_serverCertificateKey == NULL))
696 return false;
697
698 X509_STORE *store = X509_STORE_new();
699 if (store == NULL)
700 {
701 nxlog_debug(3, _T("SetupServerTlsContext: cannot create certificate store"));
702 return false;
703 }
704 #if HAVE_X509_STORE_SET_VERIFY_CB
705 X509_STORE_set_verify_cb(store, CertVerifyCallback);
706 #endif
707 X509_STORE_add_cert(store, s_serverCertificate);
708 for(int i = 0; i < s_serverCACertificates.size(); i++)
709 X509_STORE_add_cert(store, s_serverCACertificates.get(i));
710 SSL_CTX_set_cert_store(context, store);
711 SSL_CTX_use_certificate(context, s_serverCertificate);
712 SSL_CTX_use_PrivateKey(context, s_serverCertificateKey);
713 SSL_CTX_set_verify(context, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, NULL);
714 return true;
715 }
716
717 #else /* _WITH_ENCRYPTION */
718
719 /**
720 * Stub for certificate initialization
721 */
722 void InitCertificates()
723 {
724 }
725
726 #endif /* _WITH_ENCRYPTION */