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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2