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