1 /***************************************************************************
2 cssl.cpp - description
3 -------------------
4 begin : Sat Dec 7 2002
5 copyright : (C) 2002-2004 by Mathias Küster
6 email : mathen@users.berlios.de
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18 #include "cssl.h"
19
20 #include <stdio.h>
21 #include <string.h>
22
23 #include "cstring.h"
24 #include "cbase64.h"
25 #include "cbytearray.h"
26
27 /* cmutex.h includes <pthread.h> */
28 #include "cmutex.h"
29
30 /* init static members */
31 CMutex * CSSL::mutexes = NULL;
32
33 #if DCLIB_USES_OPENSSL == 1
34
35 /** free RSA */
~CSSLObject()36 CSSLObject::~CSSLObject()
37 {
38 if ( m_pRSA )
39 {
40 RSA_free(m_pRSA);
41 }
42 }
43
44
45 /** */
CSSL()46 CSSL::CSSL()
47 {
48 m_pRSA = 0;
49 m_pRandBuffer = 0;
50 }
51
52 /** */
~CSSL()53 CSSL::~CSSL()
54 {
55 if ( m_pRSA )
56 RSA_free(m_pRSA);
57 if ( m_pRandBuffer )
58 free(m_pRandBuffer);
59 }
60
61 /** */
InitSSLLibrary()62 void CSSL::InitSSLLibrary()
63 {
64 mutexes = new CMutex[ CRYPTO_num_locks() ];
65
66 #ifndef WIN32
67 CRYPTO_set_id_callback( &CSSL::thread_id );
68 #endif
69
70 CRYPTO_set_locking_callback( &CSSL::locking_callback );
71
72 SSL_load_error_strings();
73 SSL_library_init();
74 }
75
76 /** */
DeInitSSLLibrary()77 void CSSL::DeInitSSLLibrary()
78 {
79 CRYPTO_set_locking_callback( NULL );
80 delete[] mutexes;
81 mutexes = NULL;
82
83 ERR_free_strings();
84 }
85
86 /** */
InitClientCTX()87 SSL_CTX * CSSL::InitClientCTX()
88 {
89 const SSL_METHOD *method;
90 SSL_CTX *ctx = NULL;
91
92 method = SSLv23_client_method(); /* Create new client-method instance */
93
94 // sanity check
95 if ( method != NULL )
96 {
97 ctx = SSL_CTX_new(method); /* Create new context */
98 }
99
100 // sanity check
101 if ( ctx == NULL )
102 {
103 ERR_print_errors_fp(stderr);
104 }
105
106 return ctx;
107 }
108
109 /** */
InitServerCTX()110 SSL_CTX * CSSL::InitServerCTX()
111 {
112 const SSL_METHOD *method;
113 SSL_CTX *ctx = NULL;
114
115 method = SSLv23_server_method(); /* Create new client-method instance */
116
117 if ( method != NULL )
118 {
119 ctx = SSL_CTX_new(method); /* Create new context */
120 }
121
122 if ( ctx == NULL )
123 {
124 ERR_print_errors_fp(stderr);
125 }
126
127 return ctx;
128 }
129
130 /** */
NewTLSv1ClientCTX()131 SSL_CTX * CSSL::NewTLSv1ClientCTX()
132 {
133 const SSL_METHOD * method = TLSv1_client_method();
134 SSL_CTX * ctx = NULL;
135
136 if ( method != NULL )
137 {
138 ctx = SSL_CTX_new(method);
139 }
140
141 if ( ctx == NULL )
142 {
143 ERR_print_errors_fp(stderr);
144 }
145
146 return ctx;
147 }
148
149 /** */
NewTLSv1ServerCTX()150 SSL_CTX * CSSL::NewTLSv1ServerCTX()
151 {
152 const SSL_METHOD * method = TLSv1_server_method();
153 SSL_CTX * ctx = NULL;
154
155 if ( method != NULL )
156 {
157 ctx = SSL_CTX_new(method);
158 }
159
160 if ( ctx == NULL )
161 {
162 ERR_print_errors_fp(stderr);
163 }
164
165 return ctx;
166 }
167
168 /** */
LoadCertificates(SSL_CTX * ctx,char * CertFile,char * KeyFile)169 bool CSSL::LoadCertificates( SSL_CTX * ctx, char * CertFile, char * KeyFile )
170 {
171 bool res = false;
172
173 // check
174 if ( !ctx || !CertFile || !KeyFile )
175 {
176 return res;
177 }
178
179 // set the local certificate from CertFile
180 if ( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0 )
181 {
182 ERR_print_errors_fp(stderr);
183 }
184 // set the private key from KeyFile (may be the same as CertFile)
185 else if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 )
186 {
187 ERR_print_errors_fp(stderr);
188 }
189 // verify private key
190 else if ( !SSL_CTX_check_private_key(ctx) )
191 {
192 fprintf(stderr, "Private key does not match the public certificate\n");
193 }
194 // no error
195 else
196 {
197 res = true;
198 }
199
200 return res;
201 }
202
InitRand()203 void CSSL::InitRand()
204 {
205 if ( m_pRandBuffer )
206 {
207 free(m_pRandBuffer);
208 }
209
210 m_pRandBuffer = (int *) malloc(sizeof(int)*1000);
211
212 if ( !m_pRandBuffer )
213 {
214 perror("CSSL::InitRand: malloc");
215 return;
216 }
217
218 InitRandArray((unsigned char*)m_pRandBuffer,sizeof(int)*1000);
219
220 RAND_seed(m_pRandBuffer,sizeof(int)*1000);
221 }
222
223 /** */
GenerateRsaKey()224 bool CSSL::GenerateRsaKey()
225 {
226 bool res = false;
227
228 if ( m_pRSA == 0 )
229 {
230 InitRand();
231 m_pRSA = RSA_generate_key(2048,65537,NULL,NULL);
232
233 if ( m_pRSA )
234 {
235 if ( RSA_check_key(m_pRSA) == 1 )
236 res = true;
237 }
238 }
239
240 return res;
241 }
242
243 /** */
InitRandArray(unsigned char * a,int len)244 void CSSL::InitRandArray( unsigned char * a, int len )
245 {
246 int i;
247
248 // sanity check
249 if ( !a || (len <= 0) )
250 {
251 return;
252 }
253
254 if ( RAND_bytes(a,len) != 1 )
255 {
256 srand(time(NULL));
257
258 for(i=0;i<len;i++)
259 a[i]=(unsigned char)(rand()&0xff);
260 }
261 }
262
263 /** */
GetPublicRsaKey()264 CString CSSL::GetPublicRsaKey()
265 {
266 int i;
267 CByteArray bain,baout;
268 CString s;
269 unsigned char *buf;
270
271 // sanity check
272 if ( m_pRSA )
273 {
274 i = i2d_RSAPublicKey(m_pRSA,NULL);
275
276 // sanity check
277 if ( i > 0 )
278 {
279 bain.SetSize(i);
280
281 buf = bain.Data();
282
283 // sanity check
284 if ( buf )
285 {
286 i = i2d_RSAPublicKey(m_pRSA,&buf);
287
288 // sanity check
289 if ( i > 0 )
290 {
291 CBase64::Encode(&baout,&bain);
292 s.Set((const char*)baout.Data(),baout.Size());
293 }
294 }
295 }
296 }
297
298 return s;
299 }
300
301 /** */
SetPublicKey(CSSLObject * SSLObject,CString s)302 bool CSSL::SetPublicKey( CSSLObject * SSLObject, CString s )
303 {
304 bool res = false;
305 CByteArray bain,baout;
306 unsigned char *buf;
307
308 // sanity check
309 if ( !SSLObject || (s.IsEmpty()) )
310 {
311 return res;
312 }
313
314 bain.SetSize(0);
315 bain.Append(s.Data(),s.Length());
316
317 if ( CBase64::Decode(&baout,&bain) > 0 )
318 {
319 if ( SSLObject->m_pRSA )
320 RSA_free(SSLObject->m_pRSA);
321 buf = baout.Data();
322
323 #if OPENSSL_VERSION_NUMBER >= 0x00907000L
324 SSLObject->m_pRSA = d2i_RSAPublicKey(NULL,(const unsigned char**)&buf,baout.Size());
325 #else
326 SSLObject->m_pRSA = d2i_RSAPublicKey(NULL,(unsigned char**)&buf,baout.Size());
327 #endif
328 if ( SSLObject->m_pRSA )
329 res = true;
330 }
331
332 return res;
333 }
334
335 /** */
InitSessionKey(CSSLObject * SSLObject)336 void CSSL::InitSessionKey( CSSLObject * SSLObject )
337 {
338 // sanity check
339 if ( SSLObject )
340 {
341 InitRandArray( SSLObject->m_localkey, 16 );
342 InitRandArray( SSLObject->m_localiv, 8 );
343 }
344 }
345
346 /** */
GetSessionKey(CSSLObject * SSLObject)347 CString CSSL::GetSessionKey( CSSLObject * SSLObject )
348 {
349 int i;
350 CByteArray bain,baout;
351 CString s;
352
353 // sanity check
354 if ( !SSLObject )
355 {
356 return s;
357 }
358
359 bain.SetSize(0);
360 bain.Append( SSLObject->m_localkey, 16);
361 bain.Append( SSLObject->m_localiv, 8);
362
363 // printf("LOCAL\n");
364 // for(i=0;i<24;i++) printf("%02X ",bain.Data()[i]);
365 // printf("\n");
366
367 baout.SetSize(500);
368
369 i = RSA_public_encrypt(bain.Size(),bain.Data(),baout.Data(),SSLObject->m_pRSA,RSA_PKCS1_OAEP_PADDING);
370
371 if ( i != 0 )
372 {
373 bain.SetSize(0);
374 bain.Append(baout.Data(),i);
375 baout.SetSize(0);
376 CBase64::Encode(&baout,&bain);
377 s.Set((const char*)baout.Data(),baout.Size());
378 }
379 else
380 {
381 printf("LOCAL SK error %d\n",i);
382 }
383
384 return s;
385 }
386
387 /** */
SetSessionKey(CSSLObject * SSLObject,CString s)388 bool CSSL::SetSessionKey( CSSLObject * SSLObject, CString s )
389 {
390 bool res = false;
391 CByteArray bain,baout;
392 int i;
393
394 // sanity check
395 if ( !SSLObject || (s.IsEmpty()) )
396 {
397 return res;
398 }
399
400 bain.SetSize(0);
401 bain.Append(s.Data(),s.Length());
402
403 if ( CBase64::Decode(&baout,&bain) > 0 )
404 {
405 bain.SetSize(baout.Size());
406 i = RSA_private_decrypt(baout.Size(),baout.Data(),bain.Data(),m_pRSA,RSA_PKCS1_OAEP_PADDING);
407
408 if ( i == 24 )
409 {
410 // printf("REMOTE\n");
411 // for(i=0;i<24;i++) printf("%02X ",bain.Data()[i]);
412 // printf("\n");
413 memcpy( SSLObject->m_remotekey, bain.Data()+0, 16 );
414 memcpy( SSLObject->m_remoteiv, bain.Data()+16, 8 );
415 res = true;
416 }
417 else
418 {
419 printf("SK error %d\n",i);
420 }
421 }
422
423 return res;
424 }
425
426 /** */
EncryptData(CSSLObject * SSLObject,CString s)427 CString CSSL::EncryptData( CSSLObject * SSLObject, CString s )
428 {
429 CString res;
430 CByteArray bain,baout;
431 int i,tmplen;
432 EVP_CIPHER_CTX *ctx;
433
434 // sanity check
435 if ( !SSLObject || (s.IsEmpty()) )
436 {
437 return res;
438 }
439
440 ctx = EVP_CIPHER_CTX_new();
441 EVP_CIPHER_CTX_init(ctx);
442 EVP_EncryptInit(ctx, EVP_bf_cbc(), SSLObject->m_remotekey, SSLObject->m_remoteiv);
443
444 // init input array
445 bain.SetSize(2);
446 InitRandArray(bain.Data(),2);
447 bain.Append(s.Data(),s.Length());
448
449 // init output array
450 // input size + cipher_block_size for EVP_EncryptUpdate
451 // plus cipher_block_size for EVP_EncryptFinal
452 baout.SetSize( bain.Size() + ( 2 * EVP_CIPHER_CTX_block_size(ctx) ) );
453 //printf("CSSL::EncryptData: wrong old size=%lu new size=%lu\n",bain.Size()*2,baout.Size());
454 i = baout.Size();
455
456 if ( EVP_EncryptUpdate(ctx, baout.Data(), &i, bain.Data(), bain.Size() ) )
457 {
458 if ( EVP_EncryptFinal(ctx, baout.Data()+i, &tmplen) )
459 {
460 i+=tmplen;
461 bain.SetSize(0);
462 bain.Append(baout.Data(),i);
463 baout.SetSize(0);
464 CBase64::Encode(&baout,&bain);
465 res.Set((const char*)baout.Data(),baout.Size());
466 }
467 }
468
469 EVP_CIPHER_CTX_free(ctx);
470
471 return res;
472 }
473
474 /** */
DecryptData(CSSLObject * SSLObject,CString s)475 CString CSSL::DecryptData( CSSLObject * SSLObject, CString s )
476 {
477 CString res;
478 CByteArray bain,baout;
479 int i,tmplen;
480 EVP_CIPHER_CTX *ctx;
481
482 // sanity check
483 if ( !SSLObject || (s.IsEmpty()) )
484 {
485 return res;
486 }
487
488 ctx = EVP_CIPHER_CTX_new();
489 EVP_CIPHER_CTX_init(ctx);
490 EVP_DecryptInit(ctx, EVP_bf_cbc(), SSLObject->m_localkey, SSLObject->m_localiv);
491
492 bain.SetSize(0);
493 bain.Append(s.Data(),s.Length());
494
495 if ( CBase64::Decode(&baout,&bain) > 0 )
496 {
497 bain.SetSize( baout.Size() + ( 2 * EVP_CIPHER_CTX_block_size(ctx) ) );
498 //printf("CSSL::DecryptData: wrong old size=%lu new size=%lu\n",baout.Size()*2,bain.Size());
499 i = 0;
500
501 if ( EVP_DecryptUpdate(ctx, bain.Data(), &i, baout.Data(), (int)baout.Size() ) )
502 {
503 tmplen = 0;
504 if ( EVP_DecryptFinal(ctx, bain.Data()+i, &tmplen) )
505 {
506 i+=tmplen;
507 res.Set((const char*)bain.Data()+2,i-2);
508 }
509 }
510 }
511
512 EVP_CIPHER_CTX_free(ctx);
513
514 return res;
515 }
516
517 /** */
GetSSLVersionString()518 CString CSSL::GetSSLVersionString()
519 {
520 return CString(OPENSSL_VERSION_TEXT);
521 }
522
523 /** */
locking_callback(int mode,int type,const char *,int)524 void CSSL::locking_callback( int mode, int type, const char * /* file */, int /* line */ )
525 {
526 if ( mode & CRYPTO_LOCK )
527 {
528 mutexes[type].Lock();
529 }
530 else
531 {
532 mutexes[type].UnLock();
533 }
534 }
535
536 /*
537 * Alternative implementations using other SSL libraries may go here but should probably be
538 * moved into separate files.
539 */
540
541 #else // DCLIB_USES_OPENSSL
542
543 /*
544 * The without SSL implementation of each method does nothing / returns 0 or empty
545 * but will print a warning since they should not be used. Check for support with
546 * DCLIB_HAS_SSL at dclib compile time or dclibSupportsSSL() at valknut runtime.
547 */
548
549 /** */
~CSSLObject()550 CSSLObject::~CSSLObject()
551 {
552 // nothing
553 }
554
555 /** */
CSSL()556 CSSL::CSSL()
557 {
558 m_pRSA = 0;
559 m_pRandBuffer = 0;
560 }
561
562 /** */
~CSSL()563 CSSL::~CSSL()
564 {
565 // nothing
566 }
567
568 /** */
InitSSLLibrary()569 void CSSL::InitSSLLibrary()
570 {
571 // nothing
572 }
573
574 /** */
DeInitSSLLibrary()575 void CSSL::DeInitSSLLibrary()
576 {
577 // nothing
578 }
579
580 /** */
InitClientCTX()581 SSL_CTX * CSSL::InitClientCTX()
582 {
583 printf("dclib was compiled without SSL support so CSSL::InitClientCTX always returns 0\n");
584 return 0;
585 }
586
587 /** */
InitServerCTX()588 SSL_CTX * CSSL::InitServerCTX()
589 {
590 printf("dclib was compiled without SSL support so CSSL::InitServerCTX always returns 0\n");
591 return 0;
592 }
593
594 /** */
NewTLSv1ClientCTX()595 SSL_CTX * CSSL::NewTLSv1ClientCTX()
596 {
597 printf("dclib was compiled without SSL support so CSSL::NewTLSv1ClientCTX always returns 0\n");
598 return 0;
599 }
600
601 /** */
NewTLSv1ServerCTX()602 SSL_CTX * CSSL::NewTLSv1ServerCTX()
603 {
604 printf("dclib was compiled without SSL support so CSSL::NewTLSv1ServerCTX always returns 0\n");
605 return 0;
606 }
607
608 /** */
LoadCertificates(SSL_CTX *,char *,char *)609 bool CSSL::LoadCertificates( SSL_CTX * /* ctx */, char * /* certfile */, char * /* keyfile */ )
610 {
611 printf("dclib was compiled without SSL support so CSSL::LoadCertificates always returns false\n");
612 return false;
613 }
614
615 /** */
InitRand()616 void CSSL::InitRand()
617 {
618 printf("dclib was compiled without SSL support so CSSL::InitRand does nothing\n");
619 }
620
621 /** */
InitRandArray(unsigned char *,int)622 void CSSL::InitRandArray( unsigned char * /* a */, int /* len */ )
623 {
624 printf("dclib was compiled without SSL support so CSSL::InitRandArray does nothing\n");
625 }
626
627 /** */
GenerateRsaKey()628 bool CSSL::GenerateRsaKey()
629 {
630 printf("dclib was compiled without SSL support so CSSL::GenerateRsaKey always returns false\n");
631 return false;
632 }
633
634 /** */
GetPublicRsaKey()635 CString CSSL::GetPublicRsaKey()
636 {
637 printf("dclib was compiled without SSL support so CSSL::GetPublicRsaKey always returns an empty string\n");
638 return CString();
639 }
640
641 /** */
SetPublicKey(CSSLObject *,CString)642 bool CSSL::SetPublicKey( CSSLObject * /* SSLObject */, CString /* s */ )
643 {
644 printf("dclib was compiled without SSL support so CSSL::SetPublicKey always returns false\n");
645 return false;
646 }
647
648 /** */
InitSessionKey(CSSLObject *)649 void CSSL::InitSessionKey( CSSLObject * /* SSLObject */ )
650 {
651 printf("dclib was compiled without SSL support so CSSL::InitSessionKey does nothing\n");
652 }
653
654 /** */
GetSessionKey(CSSLObject *)655 CString CSSL::GetSessionKey( CSSLObject * /* SSLObject */ )
656 {
657 printf("dclib was compiled without SSL support so CSSL::GetSessionKey always returns an empty string\n");
658 return CString();
659 }
660
661 /** */
SetSessionKey(CSSLObject *,CString)662 bool CSSL::SetSessionKey( CSSLObject * /* SSLObject */, CString /* s */ )
663 {
664 printf("dclib was compiled without SSL support so CSSL::SetSessionKey always returns false\n");
665 return false;
666 }
667
668 /** */
EncryptData(CSSLObject *,CString)669 CString CSSL::EncryptData( CSSLObject * /* SSLObject */, CString /* s */ )
670 {
671 printf("dclib was compiled without SSL support so CSSL::EncryptData always returns an empty string\n");
672 return CString();
673 }
674
675 /** */
DecryptData(CSSLObject *,CString)676 CString CSSL::DecryptData( CSSLObject * /* SSLObject */, CString /* s */ )
677 {
678 printf("dclib was compiled without SSL support so CSSL::DecryptData always returns an empty string\n");
679 return CString();
680 }
681
682 /** */
GetSSLVersionString()683 CString CSSL::GetSSLVersionString()
684 {
685 return CString("None");
686 }
687
688 /** */
locking_callback(int,int,const char *,int)689 void CSSL::locking_callback( int /* mode */, int /* type */, const char * /* file */, int /* line */ )
690 {
691 return;
692 }
693
694 #endif // DCLIB_USES_OPENSSL
695
696 /** This function does not use OpenSSL */
697 #ifndef WIN32
thread_id()698 unsigned long CSSL::thread_id()
699 {
700 /*
701 * This is bad because we are not supposed to know
702 * or rely on what a pthread_t is, however it is an unsigned long,
703 * and the OpenSSL docs don't provide any other code.
704 */
705 return (unsigned long) pthread_self();
706 }
707 #endif
708