(file) Return to SSLContext.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

  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.1 //
 29           //%/////////////////////////////////////////////////////////////////////////////
 30           
 31           #ifdef PEGASUS_HAS_SSL
 32           #include <openssl/err.h>
 33           #include <openssl/ssl.h>
 34           #include <openssl/rand.h>
 35           #else
 36           #define SSL_CTX void
 37           #endif // end of PEGASUS_HAS_SSL
 38           #include <Pegasus/Common/Destroyer.h>
 39           #include <Pegasus/Common/Socket.h>
 40           #include <Pegasus/Common/Tracer.h>
 41           
 42           #include "SSLContext.h"
 43           #include "SSLContextRep.h"
 44           
 45           PEGASUS_USING_STD;
 46           
 47           PEGASUS_NAMESPACE_BEGIN
 48           
 49 kumpf 1.4 // switch on if 'server needs certified client'
 50           //#define CLIENT_CERTIFY
 51 kumpf 1.1 
 52           //
 53           // use the following definitions only if SSL is available
 54           // 
 55 kumpf 1.3 #ifdef PEGASUS_HAS_SSL
 56 kumpf 1.1 
 57           //
 58           // certificate handling routine
 59           //
 60           
 61 kumpf 1.9 // ATTN-RK-20020905: This global variable is unsafe with multiple SSL contexts
 62           SSLCertificateVerifyFunction* verify_certificate;
 63 kumpf 1.1 
 64 kumpf 1.8 static int cert_verify(SSL_CTX *ctx, const char *cert_file, const char *key_file)
 65 kumpf 1.1 {
 66 kumpf 1.3     PEG_METHOD_ENTER(TRC_SSL, "cert_verify()");
 67 kumpf 1.1 
 68 kumpf 1.3     if (cert_file != NULL)
 69               {
 70                   if (SSL_CTX_use_certificate_file(ctx,cert_file,SSL_FILETYPE_PEM) <=0)
 71                   {
 72                       PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4, 
 73                           "---> SSL: no certificate found in " + String(cert_file));
 74                       PEG_METHOD_EXIT();
 75                       return 0;
 76                   }
 77                   if (key_file == NULL) key_file=cert_file;
 78                   if (SSL_CTX_use_PrivateKey_file(ctx,key_file,SSL_FILETYPE_PEM) <= 0)
 79                   {
 80                       PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4, 
 81                           "---> SSL: no private key found in " + String(key_file));
 82                       PEG_METHOD_EXIT();
 83                       return 0;
 84                   }
 85           
 86                   if (!SSL_CTX_check_private_key(ctx)) 
 87                   {
 88                       PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4, 
 89 kumpf 1.3                 "---> SSL: Private and public key do not match");
 90                       PEG_METHOD_EXIT();
 91                       return 0;
 92                   }
 93               }
 94               PEG_METHOD_EXIT();
 95               return -1;
 96 kumpf 1.1 }
 97           
 98           static int prepareForCallback(int preverifyOk, X509_STORE_CTX *ctx)
 99           {
100 kumpf 1.3     PEG_METHOD_ENTER(TRC_SSL, "prepareForCallback()");
101 kumpf 1.1 
102               char   buf[256];
103               X509   *err_cert;
104               int    err; 
105               int    depth;
106               String subjectName;
107               String issuerName;
108               int    verify_depth = 0;
109               int    verify_error = X509_V_OK;
110           
111               err_cert = X509_STORE_CTX_get_current_cert(ctx);
112               err = X509_STORE_CTX_get_error(ctx);
113           
114               depth = X509_STORE_CTX_get_error_depth(ctx);
115           
116               //FUTURE: Not sure what to do with these...?
117               //ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
118               //mydata = SSL_get_ex_data(ssl, mydata_index);
119           
120               X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
121               subjectName = String(buf);
122 kumpf 1.1 
123               if (verify_depth >= depth)
124               {
125                   preverifyOk = 1;
126                   verify_error = X509_V_OK;
127               }
128               else
129               {
130                   preverifyOk = 0;
131                   verify_error = X509_V_ERR_CERT_CHAIN_TOO_LONG;
132                   X509_STORE_CTX_set_error(ctx, verify_error);
133               }
134           
135               if (!preverifyOk)
136               {
137 kumpf 1.3         PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4, 
138                       "---> SSL: verify error: " + String(X509_verify_cert_error_string(err)));
139 kumpf 1.1     }
140           
141               if (!preverifyOk && (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT))
142               {
143                   X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256);
144                   issuerName = String(buf);
145               }
146               else
147               {
148                   X509_NAME_oneline(X509_get_issuer_name(err_cert), buf, 256);
149                   issuerName = String(buf);
150               }
151           
152               //
153               // Call the verify_certificate() callback
154               //
155 kumpf 1.9     SSLCertificateInfo certInfo(subjectName, issuerName, depth, err);
156 kumpf 1.1 
157               if (verify_certificate(certInfo))
158               {
159                   preverifyOk = 1;
160               }
161           
162               //delete certInfo;
163           
164               // ATTN-NB-03-05102002: Overriding the default verification result, may
165               // need to be changed to make it more generic.
166               if (preverifyOk)
167               {
168                   X509_STORE_CTX_set_error(ctx, verify_error);
169               }
170           
171               PEG_METHOD_EXIT();
172               return(preverifyOk);
173           }
174           
175           
176           //
177 kumpf 1.1 // SSL context area
178           //
179           // For the OSs that don't have /dev/random device file,
180           // must enable PEGASUS_SSL_RANDOMFILE flag.
181           //
182           // CIM clients must specify a SSL random file and also
183           // set isCIMClient to true. However, CIMserver does not
184           // seem to care the Random seed and /dev/random. 
185           //
186           //
187           SSLContextRep::SSLContextRep(const String& certPath,
188 kumpf 1.9                        SSLCertificateVerifyFunction* verifyCert,
189 kumpf 1.1                        const String& randomFile,
190                                  Boolean isCIMClient)
191           {
192 kumpf 1.3     PEG_METHOD_ENTER(TRC_SSL, "SSLContextRep::SSLContextRep()");
193 kumpf 1.1 
194 kumpf 1.7     _certPath = certPath.getCString();
195 kumpf 1.1 
196               verify_certificate = verifyCert;
197           
198               //
199               // load SSL library
200               //
201               SSL_load_error_strings();
202               SSL_library_init();
203           
204           #ifdef PEGASUS_SSL_RANDOMFILE
205               
206               //
207               // We will only need SSL Random Seed for CIM Clients
208               // 
209               if (isCIMClient) 
210               {
211                  long  seedNumber;
212                  //
213                  // Initialise OpenSSL 0.9.5 random number generator.
214                  //
215                  if ( randomFile != String::EMPTY )
216 kumpf 1.1        {
217 kumpf 1.7           int ret = RAND_load_file(randomFile.getCString(), -1);
218 kumpf 1.1           if ( ret < 0 )
219                     {
220 kumpf 1.3             PEG_METHOD_EXIT();
221 kumpf 1.5             throw( SSLException("RAND_load_file - failed"));
222 kumpf 1.1           }
223           
224                     //
225                     // Will do more seeding
226                     //
227                     srandom((unsigned int)time(NULL)); // Initialize
228                     seedNumber = random();
229                     RAND_seed((unsigned char *) &seedNumber, sizeof(seedNumber));
230           
231                     int  seedRet = RAND_status();
232                     if ( seedRet == 0 )
233                     {
234 kumpf 1.3               PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4, 
235                             "Not enough data , RAND_status = " + seedRet );
236                         PEG_METHOD_EXIT();
237 kumpf 1.5               throw( SSLException("RAND_seed - Not enough seed data "));
238 kumpf 1.1           }
239                  }
240                  else
241                  {
242 kumpf 1.3            PEG_METHOD_EXIT();
243 kumpf 1.5            throw( SSLException("Random seed file required"));
244 kumpf 1.1        }
245            
246                }
247           
248           #endif // end of PEGASUS_SSL_RANDOMFILE
249           
250 kumpf 1.9     _sslContext = _makeSSLContext();
251           
252               PEG_METHOD_EXIT();
253           }
254           
255           SSLContextRep::SSLContextRep(const SSLContextRep& sslContextRep)
256           {
257               PEG_METHOD_ENTER(TRC_SSL, "SSLContextRep::SSLContextRep()");
258           
259               _certPath = sslContextRep._certPath;
260               // ATTN: verify_certificate is set implicitly in global variable
261               _randomFile = sslContextRep._randomFile;
262               _isCIMClient = sslContextRep._isCIMClient;
263               _sslContext = _makeSSLContext();
264           
265               PEG_METHOD_EXIT();
266           }
267 kumpf 1.11 
268            // Dummy constructor made private to disallow default construction
269            SSLContextRep::SSLContextRep()
270            {
271            }
272            
273 kumpf 1.9  //
274            // Destructor
275            //
276            
277            SSLContextRep::~SSLContextRep()
278            {
279                PEG_METHOD_ENTER(TRC_SSL, "SSLContextRep::~SSLContextRep()");
280            
281                SSL_CTX_free(_sslContext);
282            
283                PEG_METHOD_EXIT();
284            }
285            
286            SSL_CTX * SSLContextRep::_makeSSLContext()
287            {
288                PEG_METHOD_ENTER(TRC_SSL, "SSLContextRep::_makeSSLContext()");
289            
290                SSL_CTX * sslContext = 0;
291            
292 kumpf 1.1      //
293                // create SSL Context Area
294                //
295            
296 kumpf 1.9      if (!( sslContext = SSL_CTX_new(SSLv23_method()) ))
297 kumpf 1.3      {
298                    PEG_METHOD_EXIT();
299 kumpf 1.5          throw( SSLException("Could not get SSL CTX"));
300 kumpf 1.3      }
301            
302            #ifdef PEGASUS_OS_HPUX
303 kumpf 1.9      if (!(SSL_CTX_set_cipher_list(sslContext, SSL_TXT_EXP40)))
304 kumpf 1.5          throw( SSLException("Could not set the cipher list"));
305 kumpf 1.3  #endif
306 kumpf 1.1  
307                //
308                // set overall SSL Context flags
309                //
310            
311 kumpf 1.9      SSL_CTX_set_quiet_shutdown(sslContext, 1);
312                SSL_CTX_set_mode(sslContext, SSL_MODE_AUTO_RETRY);
313                SSL_CTX_set_options(sslContext,SSL_OP_ALL);
314 kumpf 1.1  
315 kumpf 1.4  #ifdef CLIENT_CERTIFY
316 kumpf 1.9      SSL_CTX_set_verify(sslContext, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, 
317 kumpf 1.4          prepareForCallback);
318            #else
319 kumpf 1.10     if (verify_certificate != NULL)
320 kumpf 1.1      {
321 kumpf 1.9          SSL_CTX_set_verify(sslContext, 
322 kumpf 1.4              SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, prepareForCallback);
323 kumpf 1.1      }
324 kumpf 1.4  #endif
325 kumpf 1.1  
326                //
327                // check certificate given to me
328                //
329            
330 kumpf 1.9      if (!cert_verify(sslContext, _certPath, _certPath))
331 kumpf 1.3      {
332                    PEG_METHOD_EXIT();
333 kumpf 1.5          throw( SSLException("Could not get certificate and/or private key"));
334 kumpf 1.3      }
335 kumpf 1.1  
336 kumpf 1.3      PEG_METHOD_EXIT();
337 kumpf 1.9      return sslContext;
338 kumpf 1.1  }
339            
340            SSL_CTX * SSLContextRep::getContext() const 
341            {
342 kumpf 1.9      return _sslContext;
343 kumpf 1.1  }
344            #else 
345            
346            //
347 kumpf 1.9  // these definitions are used if ssl is not available
348 kumpf 1.1  //
349            
350            SSLContextRep::SSLContextRep(const String& certPath,
351 kumpf 1.9                         SSLCertificateVerifyFunction* verifyCert,
352 kumpf 1.1                         const String& randomFile,
353 kumpf 1.6                         Boolean isCIMClient) {}
354 kumpf 1.1  
355 kumpf 1.9  SSLContextRep::SSLContextRep(const SSLContextRep& sslContextRep) {}
356            
357 kumpf 1.1  SSLContextRep::~SSLContextRep() {}
358            
359 kumpf 1.9  SSL_CTX * SSLContextRep::_makeSSLContext() { return 0; }
360            
361            SSL_CTX * SSLContextRep::getContext() const { return 0; }
362 kumpf 1.1  
363            #endif // end of PEGASUS_HAS_SSL
364            
365            ///////////////////////////////////////////////////////////////////////////////
366            //
367            // SSLContext
368            //
369            ///////////////////////////////////////////////////////////////////////////////
370            
371            
372            SSLContext::SSLContext(
373                const String& certPath,
374 kumpf 1.9      SSLCertificateVerifyFunction* verifyCert,
375 kumpf 1.1      const String& randomFile,
376 kumpf 1.6      Boolean isCIMClient)
377 kumpf 1.1  {
378                _rep = new SSLContextRep(certPath, verifyCert, randomFile, isCIMClient);
379            }
380            
381 kumpf 1.9  SSLContext::SSLContext(const SSLContext& sslContext)
382            {
383                _rep = new SSLContextRep(*sslContext._rep);
384            }
385            
386 kumpf 1.1  SSLContext::~SSLContext() 
387            {
388                delete _rep;
389            }
390            
391            
392            ///////////////////////////////////////////////////////////////////////////////
393            //
394 kumpf 1.9  // SSLCertificateInfo
395 kumpf 1.1  //
396            ///////////////////////////////////////////////////////////////////////////////
397            
398 kumpf 1.9  class SSLCertificateInfoRep
399            {
400            public:
401                String subjectName;
402                String issuerName;
403                int    errorDepth;
404                int    errorCode;
405                int    respCode;
406            };
407            
408            
409            SSLCertificateInfo::SSLCertificateInfo(
410 kumpf 1.1      const String subjectName,
411                const String issuerName,
412                const int errorDepth,
413                const int errorCode)
414            {
415 kumpf 1.9      _rep = new SSLCertificateInfoRep();
416                _rep->subjectName = subjectName;
417                _rep->issuerName = issuerName;
418                _rep->errorDepth = errorDepth;
419                _rep->errorCode = errorCode;
420                _rep->respCode = 0;
421            }
422            
423            SSLCertificateInfo::SSLCertificateInfo(
424                const SSLCertificateInfo& certificateInfo)
425            {
426                _rep = new SSLCertificateInfoRep();
427                _rep->subjectName = certificateInfo._rep->subjectName;
428                _rep->issuerName = certificateInfo._rep->issuerName;
429                _rep->errorDepth = certificateInfo._rep->errorDepth;
430                _rep->errorCode = certificateInfo._rep->errorCode;
431                _rep->respCode = certificateInfo._rep->respCode;
432 kumpf 1.11 }
433            
434            // Dummy constructor made private to disallow default construction
435            SSLCertificateInfo::SSLCertificateInfo()
436            {
437 kumpf 1.1  }
438            
439 kumpf 1.9  SSLCertificateInfo::~SSLCertificateInfo()
440 kumpf 1.1  {
441 kumpf 1.9      delete _rep;
442 kumpf 1.1  }
443            
444 kumpf 1.9  String SSLCertificateInfo::getSubjectName() const
445 kumpf 1.1  {
446 kumpf 1.9      return (_rep->subjectName);
447 kumpf 1.1  }
448            
449 kumpf 1.9  String SSLCertificateInfo::getIssuerName() const
450 kumpf 1.1  {
451 kumpf 1.9      return (_rep->issuerName);
452 kumpf 1.1  }
453            
454 kumpf 1.9  int SSLCertificateInfo::getErrorDepth() const
455 kumpf 1.1  {
456 kumpf 1.9      return (_rep->errorDepth);
457 kumpf 1.1  }
458            
459 kumpf 1.9  int SSLCertificateInfo::getErrorCode() const
460 kumpf 1.1  {
461 kumpf 1.9      return (_rep->errorCode);
462 kumpf 1.1  }
463            
464 kumpf 1.9  void SSLCertificateInfo::setResponseCode(const int respCode)
465 kumpf 1.1  {
466 kumpf 1.9      _rep->respCode = respCode;
467 kumpf 1.1  }
468            
469            PEGASUS_NAMESPACE_END
470            

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2