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
|