1 kumpf 1.1 //%/////////////////////////////////////////////////////////////////////////////
2 //
|
3 kumpf 1.2 // Copyright (c) 2000, 2001, 2002 BMC Software, Hewlett-Packard Company, IBM,
|
4 kumpf 1.1 // The Open Group, Tivoli Systems
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
|
7 kumpf 1.2 // of this software and associated documentation files (the "Software"), to
8 // deal in the Software without restriction, including without limitation the
9 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
10 kumpf 1.1 // sell copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
|
13 kumpf 1.2 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
|
14 kumpf 1.1 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
15 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
16 kumpf 1.2 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
17 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
18 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
19 kumpf 1.1 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 //
22 //==============================================================================
23 //
24 // Author: Markus Mueller (sedgewick_de@yahoo.de)
25 //
|
26 kumpf 1.9 // Modified By: Nag Boranna, Hewlett-Packard Company (nagaraja_boranna@hp.com)
27 // Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com)
|
28 kumpf 1.15 // Sushma Fernandes,
29 // Hewlett-Packard Company (sushma_fernandes@hp.com)
|
30 kumpf 1.1 //
31 //%/////////////////////////////////////////////////////////////////////////////
32
33 #ifdef PEGASUS_HAS_SSL
|
34 mday 1.19 #define OPENSSL_NO_KRB5 1
|
35 kumpf 1.1 #include <openssl/err.h>
36 #include <openssl/ssl.h>
37 #include <openssl/rand.h>
38 #else
39 #define SSL_CTX void
40 #endif // end of PEGASUS_HAS_SSL
41 #include <Pegasus/Common/Destroyer.h>
42 #include <Pegasus/Common/Socket.h>
43 #include <Pegasus/Common/Tracer.h>
|
44 kumpf 1.14 #include <Pegasus/Common/FileSystem.h>
|
45 kumpf 1.16 #include <time.h>
|
46 humberto 1.18 #include <Pegasus/Common/MessageLoader.h> //l10n
|
47 kumpf 1.1
48 #include "SSLContext.h"
49 #include "SSLContextRep.h"
50
|
51 kumpf 1.16 typedef struct Timestamp
52 {
53 char year[4];
54 char month[2];
55 char day[2];
56 char hour[2];
57 char minutes[2];
58 char seconds[2];
59 char dot;
60 char microSeconds[6];
61 char plusOrMinus;
62 char utcOffset[3];
63 char padding[3];
64 } Timestamp_t;
65
|
66 kumpf 1.1 PEGASUS_USING_STD;
67
68 PEGASUS_NAMESPACE_BEGIN
69
70 //
71 // use the following definitions only if SSL is available
72 //
|
73 kumpf 1.3 #ifdef PEGASUS_HAS_SSL
|
74 kumpf 1.1
75 //
76 // certificate handling routine
77 //
78
|
79 kumpf 1.9 // ATTN-RK-20020905: This global variable is unsafe with multiple SSL contexts
80 SSLCertificateVerifyFunction* verify_certificate;
|
81 kumpf 1.1
|
82 kumpf 1.15 // Mutex for SSL locks.
83 Mutex* SSLContextRep::_sslLocks = 0;
84
85 // Mutex for _countRep.
86 Mutex SSLContextRep::_countRepMutex;
87
88 // Initialise _count for SSLContextRep objects.
89 int SSLContextRep::_countRep = 0;
90
|
91 kumpf 1.16
92 //
93 // Convert ASN1_UTCTIME to CIMDateTime
94 //
95 CIMDateTime getDateTime(const ASN1_UTCTIME *utcTime)
96 {
97 struct tm time;
98 int offset;
99 Timestamp_t timeStamp;
100 char tempString[80];
101 char plusOrMinus = '+';
102
103 memset(&time, '\0', sizeof(time));
104
105 #define g2(p) ( ( (p)[0] - '0' ) * 10 + (p)[1] - '0' )
106
107 time.tm_year = g2(utcTime->data);
108
109 if(time.tm_year < 50)
110 {
111 time.tm_year += 100;
112 kumpf 1.16 }
113 time.tm_mon = g2(utcTime->data + 2) - 1;
114 time.tm_mday = g2(utcTime->data + 4);
115 time.tm_hour = g2(utcTime->data + 6);
116 time.tm_min = g2(utcTime->data + 8);
117 time.tm_sec = g2(utcTime->data + 10);
118
119 if(utcTime->data[12] == 'Z')
120 {
121 offset = 0;
122 }
123 else
124 {
125 offset = g2(utcTime->data + 13) * 60 + g2(utcTime->data + 15);
126 if(utcTime->data[12] == '-')
127 {
128 plusOrMinus = '-';
129 }
130 }
131 #undef g2
132
133 kumpf 1.16 int year = 1900;
134 memset((void *)&timeStamp, 0, sizeof(Timestamp_t));
135
136 // Format the date.
137 sprintf((char *) &timeStamp,"%04d%02d%02d%02d%02d%02d.%06d%04d",
138 year + time.tm_year,
139 time.tm_mon + 1,
140 time.tm_mday,
141 time.tm_hour,
142 time.tm_min,
143 time.tm_sec,
144 0,
145 offset);
146
147 timeStamp.plusOrMinus = plusOrMinus;
148
149 CIMDateTime dateTime;
150
151 dateTime.clear();
152 strcpy(tempString, (char *)&timeStamp);
153 dateTime.set(tempString);
154 kumpf 1.16
155 return (dateTime);
156 }
157
158 //
159 // Callback function that is called by the OpenSSL library. This function
160 // extracts X509 certficate information and pass that on to client application
161 // callback function.
162 //
163 int prepareForCallback(int preVerifyOk, X509_STORE_CTX *ctx)
|
164 kumpf 1.1 {
|
165 kumpf 1.3 PEG_METHOD_ENTER(TRC_SSL, "prepareForCallback()");
|
166 kumpf 1.1
167 char buf[256];
|
168 kumpf 1.16 X509 *currentCert;
169 int verifyError = X509_V_OK;
|
170 kumpf 1.1
|
171 kumpf 1.16 //
172 // get the current certificate
173 //
174 currentCert = X509_STORE_CTX_get_current_cert(ctx);
|
175 kumpf 1.1
|
176 kumpf 1.16 //
177 // get the default verification error code
178 //
179 int errorCode = X509_STORE_CTX_get_error(ctx);
180
181 //
182 // get the depth of certificate chain
183 //
184 int depth = X509_STORE_CTX_get_error_depth(ctx);
|
185 kumpf 1.1
186 //FUTURE: Not sure what to do with these...?
187 //ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
188 //mydata = SSL_get_ex_data(ssl, mydata_index);
189
|
190 kumpf 1.16 //
191 // get the version on the certificate
192 //
193 long version = X509_get_version(currentCert);
|
194 kumpf 1.1
|
195 kumpf 1.16 //
196 // get the serial number of the certificate
197 //
198 long serialNumber = ASN1_INTEGER_get(X509_get_serialNumber(currentCert));
199
200 //
201 // get the validity of the certificate
202 //
203 CIMDateTime notBefore = getDateTime(X509_get_notBefore(currentCert));
204
205 CIMDateTime notAfter = getDateTime(X509_get_notAfter(currentCert));
206
207 //
208 // get the subject name on the certificate
209 //
210 X509_NAME_oneline(X509_get_subject_name(currentCert), buf, 256);
211 String subjectName = String(buf);
212
213 //
214 // get the default verification error string
215 //
216 kumpf 1.16 String errorStr = String(X509_verify_cert_error_string(errorCode));
|
217 kumpf 1.1
|
218 kumpf 1.16 //
219 // log the error string if the default verification was failed
220 //
221 if (!preVerifyOk)
|
222 kumpf 1.1 {
|
223 kumpf 1.3 PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4,
|
224 kumpf 1.16 "---> SSL: certificate default verification error: " + errorStr);
|
225 kumpf 1.1 }
226
|
227 kumpf 1.16 //
228 // get the issuer name on the certificate
229 //
230 if (!preVerifyOk && (errorCode == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT))
|
231 kumpf 1.1 {
232 X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256);
233 }
234 else
235 {
|
236 kumpf 1.16 X509_NAME_oneline(X509_get_issuer_name(currentCert), buf, 256);
|
237 kumpf 1.1 }
|
238 kumpf 1.16 String issuerName = String(buf);
|
239 kumpf 1.1
240 //
|
241 kumpf 1.16 // Call the verify_certificate() application callback
|
242 kumpf 1.1 //
|
243 kumpf 1.16 SSLCertificateInfo certInfo(subjectName, issuerName, version, serialNumber,
244 notBefore, notAfter, depth, errorCode, errorStr, preVerifyOk);
|
245 kumpf 1.1
246 if (verify_certificate(certInfo))
247 {
|
248 kumpf 1.16 verifyError = X509_V_OK;
249 preVerifyOk = 1;
250 Tracer::trace(TRC_SSL, Tracer::LEVEL4,
251 "--> SSL: verify_certificate() returned X509_V_OK");
252 }
253 else
254 {
255 verifyError = certInfo.getErrorCode();
256 preVerifyOk = 0;
257 Tracer::trace(TRC_SSL, Tracer::LEVEL4,
258 "--> SSL: verify_certificate() returned error %d", verifyError);
|
259 kumpf 1.1 }
260
|
261 kumpf 1.16 //
262 // Reset the error. It is logically not required to reset the error code, but
263 // openSSL code does not take just the return value on a failed certificate
264 // verification.
265 //
266 X509_STORE_CTX_set_error(ctx, verifyError);
267
|
268 kumpf 1.1 PEG_METHOD_EXIT();
|
269 kumpf 1.16
270 return(preVerifyOk);
|
271 kumpf 1.1 }
272
|
273 kumpf 1.15 //
274 // Implement OpenSSL locking callback.
275 //
276 void pegasus_locking_callback( int mode,
277 int type,
278 const char* file,
279 int line)
280 {
281 // Check whether the mode is lock or unlock.
282
283 if ( mode & CRYPTO_LOCK )
284 {
285 Tracer::trace(TRC_SSL, Tracer::LEVEL4,
286 "Now locking for %d", pegasus_thread_self());
287 SSLContextRep::_sslLocks[type].lock( pegasus_thread_self() );
288 }
289 else
290 {
291 Tracer::trace(TRC_SSL, Tracer::LEVEL4,
292 "Now unlocking for %d", pegasus_thread_self());
293 SSLContextRep::_sslLocks[type].unlock( );
294 kumpf 1.15 }
295 }
296
297 //
298 // Initialize OpenSSL Locking and id callbacks.
299 //
300 void SSLContextRep::init_ssl()
301 {
302 // Allocate Memory for _sslLocks. SSL locks needs to be able to handle
303 // up to CRYPTO_num_locks() different mutex locks.
304 PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4,
305 "Initialized SSL callback.");
306
307 _sslLocks= new Mutex[CRYPTO_num_locks()];
308
309 // Set the ID callback. The ID callback returns a thread ID.
310
311 CRYPTO_set_id_callback((unsigned long (*)())pegasus_thread_self);
312
313 // Set the locking callback to pegasus_locking_callback.
314
315 kumpf 1.15 CRYPTO_set_locking_callback((void (*)(int,int,const char *,int))pegasus_locking_callback);
316
317 }
318
319 // Free OpenSSL Locking and id callbacks.
320 void SSLContextRep::free_ssl()
321 {
322 // Cleanup _sslLocks and set locking & id callback to NULL.
323
324 CRYPTO_set_locking_callback(NULL);
325 CRYPTO_set_id_callback (NULL);
326 PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4,
327 "Freed SSL callback.");
328
329 delete []_sslLocks;
330 }
331
|
332 kumpf 1.1
333 //
334 // SSL context area
335 //
336 // For the OSs that don't have /dev/random device file,
337 // must enable PEGASUS_SSL_RANDOMFILE flag.
338 //
|
339 kumpf 1.16 SSLContextRep::SSLContextRep(const String& trustPath,
340 const String& certPath,
341 const String& keyPath,
|
342 kumpf 1.9 SSLCertificateVerifyFunction* verifyCert,
|
343 kumpf 1.13 const String& randomFile)
|
344 kumpf 1.1 {
|
345 kumpf 1.3 PEG_METHOD_ENTER(TRC_SSL, "SSLContextRep::SSLContextRep()");
|
346 kumpf 1.1
|
347 kumpf 1.16 _trustPath = trustPath.getCString();
348
|
349 kumpf 1.7 _certPath = certPath.getCString();
|
350 kumpf 1.1
|
351 kumpf 1.16 _keyPath = keyPath.getCString();
|
352 kumpf 1.14
|
353 kumpf 1.1 verify_certificate = verifyCert;
354
|
355 kumpf 1.15
356 // Initialiaze SSL callbacks and increment the SSLContextRep object _counter.
357 _countRepMutex.lock(pegasus_thread_self());
358
359 try
360 {
361 Tracer::trace(TRC_SSL, Tracer::LEVEL4,
362 "Value of Countrep in constructor %d", _countRep);
363 if ( _countRep == 0 )
364 {
365 init_ssl();
366
367 //
368 // load SSL library
369 //
370 Tracer::trace(TRC_SSL, Tracer::LEVEL4,
371 "Before calling SSL_load_error_strings %d", pegasus_thread_self());
372
373 SSL_load_error_strings();
374
375 Tracer::trace(TRC_SSL, Tracer::LEVEL4,
376 kumpf 1.15 "After calling SSL_load_error_strings %d", pegasus_thread_self());
377
378 Tracer::trace(TRC_SSL, Tracer::LEVEL4,
379 "Before calling SSL_library_init %d", pegasus_thread_self());
380
381 SSL_library_init();
382
383 Tracer::trace(TRC_SSL, Tracer::LEVEL4,
384 "After calling SSL_library_init %d", pegasus_thread_self());
385
386 }
387 }
388 catch(...)
389 {
390 _countRepMutex.unlock();
391 throw;
392 }
393 _countRep++;
394 _countRepMutex.unlock();
|
395 kumpf 1.1
|
396 kumpf 1.14 _randomInit(randomFile);
|
397 kumpf 1.1
|
398 kumpf 1.9 _sslContext = _makeSSLContext();
399
400 PEG_METHOD_EXIT();
401 }
402
403 SSLContextRep::SSLContextRep(const SSLContextRep& sslContextRep)
404 {
405 PEG_METHOD_ENTER(TRC_SSL, "SSLContextRep::SSLContextRep()");
406
|
407 kumpf 1.16 _trustPath = sslContextRep._trustPath;
|
408 kumpf 1.9 _certPath = sslContextRep._certPath;
|
409 kumpf 1.16 _keyPath = sslContextRep._keyPath;
|
410 kumpf 1.9 // ATTN: verify_certificate is set implicitly in global variable
411 _randomFile = sslContextRep._randomFile;
|
412 kumpf 1.15
413 // Initialiaze SSL callbacks and increment the SSLContextRep object _counter.
414 _countRepMutex.lock(pegasus_thread_self());
415 try
416 {
417 Tracer::trace(TRC_SSL, Tracer::LEVEL4,
418 "Value of Countrep in copy constructor %d", _countRep);
419 if ( _countRep == 0 )
420 {
421 init_ssl();
422 }
423 }
424 catch(...)
425 {
426 _countRepMutex.unlock();
427 throw;
428 }
429 _countRep++;
430 _countRepMutex.unlock();
431
|
432 kumpf 1.9 _sslContext = _makeSSLContext();
433 PEG_METHOD_EXIT();
434 }
|
435 kumpf 1.11
|
436 kumpf 1.9 //
437 // Destructor
438 //
439
440 SSLContextRep::~SSLContextRep()
441 {
442 PEG_METHOD_ENTER(TRC_SSL, "SSLContextRep::~SSLContextRep()");
443
444 SSL_CTX_free(_sslContext);
445
|
446 kumpf 1.15 // Decrement the SSLContextRep object _counter.
447 _countRepMutex.lock(pegasus_thread_self());
448 _countRep--;
449 // Free SSL locks if no instances of SSLContextRep exist.
450 try
451 {
452 Tracer::trace(TRC_SSL, Tracer::LEVEL4,
453 "Value of Countrep in destructor %d", _countRep);
454 if ( _countRep == 0 )
455 {
456 free_ssl();
457 }
458 }
459 catch(...)
460 {
461 _countRepMutex.unlock();
462 throw;
463 }
464 _countRepMutex.unlock();
|
465 kumpf 1.9 PEG_METHOD_EXIT();
466 }
467
|
468 kumpf 1.14 //
469 // initialize OpenSSL's PRNG
470 //
471 void SSLContextRep::_randomInit(const String& randomFile)
472 {
473 PEG_METHOD_ENTER(TRC_SSL, "SSLContextRep::_randomInit()");
474
475 Boolean ret;
476 int retVal = 0;
477
|
478 kumpf 1.15 const int DEV_RANDOM_BYTES = 64; /* how many bytes to read */
|
479 kumpf 1.14 const String devRandom = "/dev/random"; /* random device name */
480 const String devUrandom = "/dev/urandom"; /* pseudo-random device name */
481
482 #ifdef PEGASUS_SSL_DEVRANDOM
483
484 if ( FileSystem::exists(devRandom) )
485 {
486 while ( RAND_status() == 0 )
487 {
488 //
|
489 kumpf 1.15 // Always attempt to seed from good entropy sources, first
|
490 kumpf 1.14 // try /dev/random
491 //
492 retVal = RAND_load_file(devRandom.getCString(), DEV_RANDOM_BYTES);
|
493 kumpf 1.15 if (retVal <= 0)
|
494 kumpf 1.14 {
495 break;
496 }
497 }
498 }
499
500 if ( FileSystem::exists(devUrandom) )
501 {
502 while ( RAND_status() == 0 )
503 {
504 //
505 // If there isn't /dev/random try /dev/urandom
506 //
507 retVal = RAND_load_file(devUrandom.getCString(), DEV_RANDOM_BYTES);
|
508 kumpf 1.15 if (retVal <= 0)
|
509 kumpf 1.14 {
510 break;
511 }
512 }
513 }
514 #endif /* PEGASUS_SSL_DEVRANDOM */
515
516
517 #ifdef PEGASUS_SSL_RANDOMFILE
518 if ( RAND_status() == 0 )
519 {
520 //
521 // Initialise OpenSSL random number generator.
522 //
523 if ( randomFile == String::EMPTY )
524 {
525 PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4,
526 "Random seed file is required.");
527 PEG_METHOD_EXIT();
|
528 humberto 1.18 //l10n
529 //throw( SSLException("Random seed file required"));
530 MessageLoaderParms parms("Common.SSLContext.RANDOM_SEED_FILE_REQUIRED",
531 "Random seed file required");
532 throw( SSLException(parms));
|
533 kumpf 1.14 }
534
535 //
536 // Try the given random seed file
537 //
538 ret = FileSystem::exists(randomFile);
539 if( ret )
540 {
|
541 kumpf 1.15 retVal = RAND_load_file(randomFile.getCString(), -1);
|
542 kumpf 1.14 if ( retVal < 0 )
543 {
544 PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4,
545 "Not enough seed data in seed file: " + randomFile);
546 PEG_METHOD_EXIT();
|
547 humberto 1.18 //l10n
|
548 humberto 1.22 // do not put in $0 in default message, but pass in filename for bundle message
|
549 humberto 1.18 //throw( SSLException("Not enough seed data in random seed file."));
550 MessageLoaderParms parms("Common.SSLContext.NOT_ENOUGH_SEED_DATA_IN_FILE",
|
551 humberto 1.21 "Not enough seed data in random seed file.",
552 randomFile);
|
553 humberto 1.18 throw( SSLException(parms));
|
554 kumpf 1.14 }
555 }
|
556 kumpf 1.16 else
557 {
558 PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4,
559 "seed file - " + randomFile + " does not exist.");
560 PEG_METHOD_EXIT();
|
561 humberto 1.18 //l10n
562 //throw( SSLException("Seed file '" + randomFile + "' does not exist."));
563 MessageLoaderParms parms("Common.SSLContext.SEED_FILE_DOES_NOT_EXIST",
564 "Seed file '$0' does not exist.",
565 randomFile);
566 throw( SSLException(parms));
|
567 kumpf 1.16 }
|
568 kumpf 1.14
569 if ( RAND_status() == 0 )
570 {
571 //
572 // Try to do more seeding
573 //
574 long seedNumber;
575 srandom((unsigned int)time(NULL)); // Initialize
576 seedNumber = random();
577 RAND_seed((unsigned char *) &seedNumber, sizeof(seedNumber));
578
579 int seedRet = RAND_status();
580 if ( seedRet == 0 )
581 {
582 PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4,
|
583 kumpf 1.15 "Not enough seed data in random seed file, RAND_status = " +
584 seedRet);
|
585 kumpf 1.14 PEG_METHOD_EXIT();
|
586 humberto 1.22 //l10n 485
587 // do not put in $0 in default message, but pass in filename for bundle message
|
588 humberto 1.18 //throw( SSLException("Not enough seed data in random seed file."));
589 MessageLoaderParms parms("Common.SSLContext.NOT_ENOUGH_SEED_DATA_IN_FILE",
|
590 humberto 1.22 "Not enough seed data in random seed file.",
591 randomFile);
|
592 humberto 1.18 throw( SSLException(parms));
|
593 kumpf 1.14 }
594 }
595 }
596 #endif /* PEGASUS_SSL_RANDOMFILE */
597
598 int seedRet = RAND_status();
599 if ( seedRet == 0 )
600 {
601 PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4,
602 "Not enough seed data , RAND_status = " + seedRet );
603 PEG_METHOD_EXIT();
|
604 humberto 1.18 //l10n
605 //throw( SSLException("Not enough seed data."));
606 MessageLoaderParms parms("Common.SSLContext.NOT_ENOUGH_SEED_DATA",
607 "Not enough seed data.");
608 throw( SSLException(parms));
|
609 kumpf 1.14 }
610
611 PEG_METHOD_EXIT();
612 }
613
|
614 kumpf 1.9 SSL_CTX * SSLContextRep::_makeSSLContext()
615 {
616 PEG_METHOD_ENTER(TRC_SSL, "SSLContextRep::_makeSSLContext()");
617
618 SSL_CTX * sslContext = 0;
619
|
620 kumpf 1.1 //
621 // create SSL Context Area
622 //
623
|
624 kumpf 1.9 if (!( sslContext = SSL_CTX_new(SSLv23_method()) ))
|
625 kumpf 1.3 {
626 PEG_METHOD_EXIT();
|
627 humberto 1.18 //l10n
628 //throw( SSLException("Could not get SSL CTX"));
629 MessageLoaderParms parms("Common.SSLContext.COULD_NOT_GET",
|
630 humberto 1.20 "Could not get SSL CTX");
|
631 humberto 1.18 throw( SSLException(parms));
|
632 kumpf 1.3 }
633
|
634 kumpf 1.14 #ifdef PEGASUS_SSL_WEAKENCRYPTION
|
635 humberto 1.18 if (!(SSL_CTX_set_cipher_list(sslContext, SSL_TXT_EXP40))){
636 //l10n
637 //throw( SSLException("Could not set the cipher list"));
638 MessageLoaderParms parms("Common.SSLContext.COULD_NOT_SET_CIPHER_LIST",
639 "Could not set the cipher list");
640 throw( SSLException(parms));
641 }
|
642 kumpf 1.3 #endif
|
643 kumpf 1.1
644 //
645 // set overall SSL Context flags
646 //
647
|
648 kumpf 1.9 SSL_CTX_set_quiet_shutdown(sslContext, 1);
649 SSL_CTX_set_mode(sslContext, SSL_MODE_AUTO_RETRY);
650 SSL_CTX_set_options(sslContext,SSL_OP_ALL);
|
651 kumpf 1.14 SSL_CTX_set_session_cache_mode(sslContext, SSL_SESS_CACHE_OFF);
|
652 kumpf 1.1
|
653 kumpf 1.10 if (verify_certificate != NULL)
|
654 kumpf 1.1 {
|
655 kumpf 1.9 SSL_CTX_set_verify(sslContext,
|
656 kumpf 1.16 SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, prepareForCallback);
|
657 kumpf 1.1 }
|
658 kumpf 1.14 else
659 {
|
660 kumpf 1.15 SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, NULL);
|
661 kumpf 1.14 }
|
662 kumpf 1.1
663 //
|
664 kumpf 1.14 // Check if there is CA certificate file specified. If specified,
665 // load the certificates from the file in to the CA trust store.
666 //
|
667 kumpf 1.16 if (strncmp(_trustPath, "", 1) != 0)
|
668 kumpf 1.14 {
669 //
670 // load certificates in to trust store
671 //
672
|
673 kumpf 1.16 if ((!SSL_CTX_load_verify_locations(sslContext, _trustPath, NULL)) ||
|
674 kumpf 1.14 (!SSL_CTX_set_default_verify_paths(sslContext)))
675 {
676 PEG_METHOD_EXIT();
|
677 humberto 1.18 //l10n
678 //throw( SSLException("Could not load certificates in to trust store."));
679 MessageLoaderParms parms("Common.SSLContext.COULD_NOT_LOAD_CERTIFICATES",
680 "Could not load certificates in to trust store.");
681 throw( SSLException(parms));
|
682 kumpf 1.14 }
683 }
684
|
685 kumpf 1.17 Boolean keyLoaded = false;
|
686 kumpf 1.1 //
|
687 kumpf 1.16 // Check if there is a certificate file (file containing server
688 // certificate) specified. If specified, validate and load the
689 // certificate.
|
690 kumpf 1.14 //
|
691 kumpf 1.16 if (strncmp(_certPath, "", 1) != 0)
|
692 kumpf 1.14 {
693 //
694 // load the specified server certificates
695 //
|
696 kumpf 1.1
|
697 kumpf 1.14 if (SSL_CTX_use_certificate_file(sslContext,
|
698 kumpf 1.16 _certPath, SSL_FILETYPE_PEM) <=0)
|
699 kumpf 1.14 {
700 PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4,
|
701 kumpf 1.16 "---> SSL: no certificate found in " + String(_certPath));
|
702 kumpf 1.14 PEG_METHOD_EXIT();
|
703 humberto 1.18 //l10n
704 //throw( SSLException("Could not get server certificate."));
705 MessageLoaderParms parms("Common.SSLContext.COULD_NOT_GET_SERVER_CERTIFICATE",
706 "Could not get server certificate.");
707 throw( SSLException(parms));
|
708 kumpf 1.14 }
|
709 kumpf 1.17
|
710 kumpf 1.16 //
711 // If there is no key file (file containing server
|
712 kumpf 1.17 // private key) specified or the specified file does not exist,
713 // then try loading the key from the certificate file.
|
714 kumpf 1.16 //
|
715 kumpf 1.17 if ( strncmp(_keyPath, "", 1) == 0 ||
716 !FileSystem::exists(String(_keyPath)) )
|
717 kumpf 1.16 {
|
718 kumpf 1.17 PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL3,
719 "---> SSL: loading key from" + String(_certPath));
|
720 kumpf 1.16 //
721 // load the private key and check for validity
722 //
723 if (!_verifyPrivateKey(sslContext, _certPath))
724 {
725 PEG_METHOD_EXIT();
|
726 humberto 1.18 //l10n
727 //throw( SSLException("Could not get private key."));
728 MessageLoaderParms parms("Common.SSLContext.COULD_NOT_GET_PRIVATE_KEY",
729 "Could not get private key.");
730 throw( SSLException(parms));
|
731 kumpf 1.16 }
|
732 kumpf 1.17 keyLoaded = true;
|
733 kumpf 1.16 }
734 }
|
735 kumpf 1.14
|
736 kumpf 1.16 //
|
737 kumpf 1.17 // Check if there is a key file (file containing server
738 // private key) specified and the key was not already loaded.
739 // If specified, validate and load the key.
|
740 kumpf 1.16 //
|
741 kumpf 1.17 if (strncmp(_keyPath, "", 1) != 0 && !keyLoaded)
|
742 kumpf 1.16 {
|
743 kumpf 1.17 PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL3,
744 "---> SSL: loading key from" + String(_keyPath));
|
745 kumpf 1.14 //
746 // load given private key and check for validity
747 //
|
748 kumpf 1.16 if (!_verifyPrivateKey(sslContext, _keyPath))
|
749 kumpf 1.14 {
750 PEG_METHOD_EXIT();
|
751 humberto 1.18 //l10n
752 //throw( SSLException("Could not get private key."));
753 MessageLoaderParms parms("Common.SSLContext.COULD_NOT_GET_PRIVATE_KEY",
754 "Could not get private key.");
755 throw( SSLException(parms));
|
756 kumpf 1.14 }
|
757 kumpf 1.17 keyLoaded = true;
|
758 kumpf 1.14 }
759
760 PEG_METHOD_EXIT();
761 return sslContext;
762 }
763
|
764 kumpf 1.16 Boolean SSLContextRep::_verifyPrivateKey(SSL_CTX *ctx, const char *keyPath)
|
765 kumpf 1.14 {
766 PEG_METHOD_ENTER(TRC_SSL, "_verifyPrivateKey()");
767
|
768 kumpf 1.16 if (SSL_CTX_use_PrivateKey_file(ctx, keyPath, SSL_FILETYPE_PEM) <= 0)
|
769 kumpf 1.3 {
|
770 kumpf 1.14 PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4,
|
771 kumpf 1.16 "---> SSL: no private key found in " + String(keyPath));
|
772 kumpf 1.3 PEG_METHOD_EXIT();
|
773 kumpf 1.14 return false;
774 }
775
776 if (!SSL_CTX_check_private_key(ctx))
777 {
778 PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4,
779 "---> SSL: Private and public key do not match");
780 PEG_METHOD_EXIT();
781 return false;
|
782 kumpf 1.3 }
|
783 kumpf 1.1
|
784 kumpf 1.3 PEG_METHOD_EXIT();
|
785 kumpf 1.14 return true;
|
786 kumpf 1.1 }
787
788 SSL_CTX * SSLContextRep::getContext() const
789 {
|
790 kumpf 1.9 return _sslContext;
|
791 kumpf 1.1 }
792 #else
793
794 //
|
795 kumpf 1.9 // these definitions are used if ssl is not available
|
796 kumpf 1.1 //
797
|
798 kumpf 1.16 SSLContextRep::SSLContextRep(const String& trustPath,
799 const String& certPath,
800 const String& keyPath,
|
801 kumpf 1.9 SSLCertificateVerifyFunction* verifyCert,
|
802 kumpf 1.13 const String& randomFile) {}
|
803 kumpf 1.1
|
804 kumpf 1.9 SSLContextRep::SSLContextRep(const SSLContextRep& sslContextRep) {}
805
|
806 kumpf 1.1 SSLContextRep::~SSLContextRep() {}
807
|
808 kumpf 1.9 SSL_CTX * SSLContextRep::_makeSSLContext() { return 0; }
809
|
810 kumpf 1.14 Boolean SSLContextRep::_verifyPrivateKey(SSL_CTX *ctx,
|
811 kumpf 1.16 const char *keyPath) { return false; }
|
812 kumpf 1.14
|
813 kumpf 1.9 SSL_CTX * SSLContextRep::getContext() const { return 0; }
|
814 kumpf 1.15
815 void SSLContextRep::init_ssl() {}
816
817 void SSLContextRep::free_ssl() {}
|
818 kumpf 1.1
819 #endif // end of PEGASUS_HAS_SSL
820
821 ///////////////////////////////////////////////////////////////////////////////
822 //
823 // SSLContext
824 //
825 ///////////////////////////////////////////////////////////////////////////////
826
827
828 SSLContext::SSLContext(
|
829 kumpf 1.16 const String& trustPath,
|
830 kumpf 1.9 SSLCertificateVerifyFunction* verifyCert,
|
831 kumpf 1.13 const String& randomFile)
832 {
|
833 kumpf 1.16 _rep = new SSLContextRep(trustPath, String::EMPTY, String::EMPTY, verifyCert, randomFile);
|
834 kumpf 1.13 }
835
836 #ifndef PEGASUS_REMOVE_DEPRECATED
837 SSLContext::SSLContext(
838 const String& certPath,
839 SSLCertificateVerifyFunction* verifyCert,
|
840 kumpf 1.1 const String& randomFile,
|
841 kumpf 1.6 Boolean isCIMClient)
|
842 kumpf 1.1 {
|
843 kumpf 1.16 _rep = new SSLContextRep(certPath, String::EMPTY, String::EMPTY, verifyCert, randomFile);
844 }
845
846 SSLContext::SSLContext(
847 const String& certPath,
848 const String& certKeyPath,
849 SSLCertificateVerifyFunction* verifyCert,
850 const String& randomFile)
851 {
852 _rep = new SSLContextRep(certPath, certKeyPath, String::EMPTY, verifyCert, randomFile);
|
853 kumpf 1.1 }
|
854 kumpf 1.13 #endif
|
855 kumpf 1.1
|
856 kumpf 1.14 SSLContext::SSLContext(
|
857 kumpf 1.16 const String& trustPath,
|
858 kumpf 1.14 const String& certPath,
|
859 kumpf 1.16 const String& keyPath,
|
860 kumpf 1.14 SSLCertificateVerifyFunction* verifyCert,
861 const String& randomFile)
862 {
|
863 kumpf 1.16 _rep = new SSLContextRep(trustPath, certPath, keyPath, verifyCert, randomFile);
|
864 kumpf 1.14 }
865
|
866 kumpf 1.9 SSLContext::SSLContext(const SSLContext& sslContext)
867 {
868 _rep = new SSLContextRep(*sslContext._rep);
|
869 kumpf 1.12 }
870
871 // Dummy constructor made private to disallow default construction
872 SSLContext::SSLContext()
873 {
|
874 kumpf 1.9 }
875
|
876 kumpf 1.1 SSLContext::~SSLContext()
877 {
878 delete _rep;
879 }
880
881
882 ///////////////////////////////////////////////////////////////////////////////
883 //
|
884 kumpf 1.9 // SSLCertificateInfo
|
885 kumpf 1.1 //
886 ///////////////////////////////////////////////////////////////////////////////
|
887 kumpf 1.16 //
888 // Certificate validation result codes.
889 //
890 const int SSLCertificateInfo::V_OK = 0;
891
892 const int SSLCertificateInfo::V_ERR_UNABLE_TO_GET_ISSUER_CERT = 2;
893 const int SSLCertificateInfo::V_ERR_UNABLE_TO_GET_CRL = 3;
894 const int SSLCertificateInfo::V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE = 4;
895 const int SSLCertificateInfo::V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE = 5;
896 const int SSLCertificateInfo::V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY = 6;
897 const int SSLCertificateInfo::V_ERR_CERT_SIGNATURE_FAILURE = 7;
898 const int SSLCertificateInfo::V_ERR_CRL_SIGNATURE_FAILURE = 8;
899 const int SSLCertificateInfo::V_ERR_CERT_NOT_YET_VALID = 9;
900 const int SSLCertificateInfo::V_ERR_CERT_HAS_EXPIRED = 10;
901 const int SSLCertificateInfo::V_ERR_CRL_NOT_YET_VALID = 11;
902 const int SSLCertificateInfo::V_ERR_CRL_HAS_EXPIRED = 12;
903 const int SSLCertificateInfo::V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD = 13;
904 const int SSLCertificateInfo::V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD = 14;
905 const int SSLCertificateInfo::V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD = 15;
906 const int SSLCertificateInfo::V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD = 16;
907 const int SSLCertificateInfo::V_ERR_OUT_OF_MEM = 17;
908 kumpf 1.16 const int SSLCertificateInfo::V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT = 18;
909 const int SSLCertificateInfo::V_ERR_SELF_SIGNED_CERT_IN_CHAIN = 19;
910 const int SSLCertificateInfo::V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY = 20;
911 const int SSLCertificateInfo::V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE = 21;
912 const int SSLCertificateInfo::V_ERR_CERT_CHAIN_TOO_LONG = 22;
913 const int SSLCertificateInfo::V_ERR_CERT_REVOKED = 23;
914 const int SSLCertificateInfo::V_ERR_INVALID_CA = 24;
915 const int SSLCertificateInfo::V_ERR_PATH_LENGTH_EXCEEDED = 25;
916 const int SSLCertificateInfo::V_ERR_INVALID_PURPOSE = 26;
917 const int SSLCertificateInfo::V_ERR_CERT_UNTRUSTED = 27;
918 const int SSLCertificateInfo::V_ERR_CERT_REJECTED = 28;
919 const int SSLCertificateInfo::V_ERR_SUBJECT_ISSUER_MISMATCH = 29;
920 const int SSLCertificateInfo::V_ERR_AKID_SKID_MISMATCH = 30;
921 const int SSLCertificateInfo::V_ERR_AKID_ISSUER_SERIAL_MISMATCH = 31;
922 const int SSLCertificateInfo::V_ERR_KEYUSAGE_NO_CERTSIGN = 32;
923
924 const int SSLCertificateInfo::V_ERR_APPLICATION_VERIFICATION = 50;
|
925 kumpf 1.1
|
926 kumpf 1.9 class SSLCertificateInfoRep
927 {
928 public:
|
929 kumpf 1.16 String subjectName;
930 String issuerName;
931 Uint32 depth;
932 Uint32 errorCode;
933 Uint32 respCode;
934 String errorString;
935 Uint32 versionNumber;
936 long serialNumber;
937 CIMDateTime notBefore;
938 CIMDateTime notAfter;
|
939 kumpf 1.9 };
940
941
942 SSLCertificateInfo::SSLCertificateInfo(
|
943 kumpf 1.1 const String subjectName,
944 const String issuerName,
945 const int errorDepth,
|
946 kumpf 1.14 const int errorCode,
947 const int respCode)
|
948 kumpf 1.1 {
|
949 kumpf 1.9 _rep = new SSLCertificateInfoRep();
950 _rep->subjectName = subjectName;
951 _rep->issuerName = issuerName;
|
952 kumpf 1.16 _rep->versionNumber = 0;
953 _rep->serialNumber = 0;
954 _rep->notBefore = CIMDateTime(String::EMPTY);
955 _rep->notAfter = CIMDateTime(String::EMPTY);
956 _rep->depth = errorDepth;
|
957 kumpf 1.9 _rep->errorCode = errorCode;
|
958 kumpf 1.16 _rep->errorString = String::EMPTY;
959 _rep->respCode = respCode;
960 }
961
962 SSLCertificateInfo::SSLCertificateInfo(
963 const String subjectName,
964 const String issuerName,
965 const Uint32 versionNumber,
966 const long serialNumber,
967 const CIMDateTime notBefore,
968 const CIMDateTime notAfter,
969 const Uint32 depth,
970 const Uint32 errorCode,
971 const String errorString,
972 const Uint32 respCode)
973 {
974 _rep = new SSLCertificateInfoRep();
975 _rep->subjectName = subjectName;
976 _rep->issuerName = issuerName;
977 _rep->versionNumber = versionNumber;
978 _rep->serialNumber = serialNumber;
979 kumpf 1.16 _rep->notBefore = notBefore;
980 _rep->notAfter = notAfter;
981 _rep->depth = depth;
982 _rep->errorCode = errorCode;
983 _rep->errorString = errorString;
|
984 kumpf 1.14 _rep->respCode = respCode;
|
985 kumpf 1.9 }
986
987 SSLCertificateInfo::SSLCertificateInfo(
988 const SSLCertificateInfo& certificateInfo)
989 {
990 _rep = new SSLCertificateInfoRep();
991 _rep->subjectName = certificateInfo._rep->subjectName;
992 _rep->issuerName = certificateInfo._rep->issuerName;
|
993 kumpf 1.16 _rep->versionNumber = certificateInfo._rep->versionNumber;
994 _rep->serialNumber = certificateInfo._rep->serialNumber;
995 _rep->notBefore = certificateInfo._rep->notBefore;
996 _rep->notAfter = certificateInfo._rep->notAfter;
997 _rep->depth = certificateInfo._rep->depth;
|
998 kumpf 1.9 _rep->errorCode = certificateInfo._rep->errorCode;
|
999 kumpf 1.16 _rep->errorString = certificateInfo._rep->errorString;
|
1000 kumpf 1.9 _rep->respCode = certificateInfo._rep->respCode;
|
1001 kumpf 1.11 }
1002
1003 // Dummy constructor made private to disallow default construction
1004 SSLCertificateInfo::SSLCertificateInfo()
1005 {
|
1006 kumpf 1.1 }
1007
|
1008 kumpf 1.9 SSLCertificateInfo::~SSLCertificateInfo()
|
1009 kumpf 1.1 {
|
1010 kumpf 1.9 delete _rep;
|
1011 kumpf 1.1 }
1012
|
1013 kumpf 1.9 String SSLCertificateInfo::getSubjectName() const
|
1014 kumpf 1.1 {
|
1015 kumpf 1.9 return (_rep->subjectName);
|
1016 kumpf 1.1 }
1017
|
1018 kumpf 1.9 String SSLCertificateInfo::getIssuerName() const
|
1019 kumpf 1.1 {
|
1020 kumpf 1.9 return (_rep->issuerName);
|
1021 kumpf 1.1 }
1022
|
1023 kumpf 1.16 Uint32 SSLCertificateInfo::getVersionNumber() const
1024 {
1025 return (_rep->versionNumber);
1026 }
1027
1028 long SSLCertificateInfo::getSerialNumber() const
|
1029 kumpf 1.1 {
|
1030 kumpf 1.16 return (_rep->serialNumber);
|
1031 kumpf 1.1 }
1032
|
1033 kumpf 1.16 CIMDateTime SSLCertificateInfo::getNotBefore() const
1034 {
1035 return (_rep->notBefore);
1036 }
1037
1038 CIMDateTime SSLCertificateInfo::getNotAfter() const
1039 {
1040 return (_rep->notAfter);
1041 }
1042
1043 Uint32 SSLCertificateInfo::getErrorDepth() const
1044 {
1045 return (_rep->depth);
1046 }
1047
1048 Uint32 SSLCertificateInfo::getErrorCode() const
|
1049 kumpf 1.1 {
|
1050 kumpf 1.9 return (_rep->errorCode);
|
1051 kumpf 1.14 }
1052
|
1053 kumpf 1.16 void SSLCertificateInfo::setErrorCode(const int errorCode)
1054 {
1055 _rep->errorCode = errorCode;
1056 }
1057
1058 String SSLCertificateInfo::getErrorString() const
1059 {
1060 return (_rep->errorString);
1061 }
1062
1063 Uint32 SSLCertificateInfo::getResponseCode() const
|
1064 kumpf 1.14 {
1065 return (_rep->respCode);
|
1066 kumpf 1.1 }
1067
|
1068 kumpf 1.9 void SSLCertificateInfo::setResponseCode(const int respCode)
|
1069 kumpf 1.1 {
|
1070 kumpf 1.9 _rep->respCode = respCode;
|
1071 kumpf 1.1 }
1072
1073 PEGASUS_NAMESPACE_END
1074
|