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