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 SSLContextRep::SSLContextRep(const String& certPath,
|
183 kumpf 1.9 SSLCertificateVerifyFunction* verifyCert,
|
184 kumpf 1.13 const String& randomFile)
|
185 kumpf 1.1 {
|
186 kumpf 1.3 PEG_METHOD_ENTER(TRC_SSL, "SSLContextRep::SSLContextRep()");
|
187 kumpf 1.1
|
188 kumpf 1.7 _certPath = certPath.getCString();
|
189 kumpf 1.1
190 verify_certificate = verifyCert;
191
192 //
193 // load SSL library
194 //
195 SSL_load_error_strings();
196 SSL_library_init();
197
198 #ifdef PEGASUS_SSL_RANDOMFILE
199
200 //
|
201 kumpf 1.13 // Initialise OpenSSL 0.9.5 random number generator.
202 //
203 if ( randomFile == String::EMPTY )
204 {
205 PEG_METHOD_EXIT();
206 throw( SSLException("Random seed file required"));
207 }
208
209 int ret = RAND_load_file(randomFile.getCString(), -1);
210 if ( ret < 0 )
211 {
212 PEG_METHOD_EXIT();
213 throw( SSLException("RAND_load_file - failed"));
214 }
215
216 //
217 // Will do more seeding
218 //
219 long seedNumber;
220 srandom((unsigned int)time(NULL)); // Initialize
221 seedNumber = random();
222 kumpf 1.13 RAND_seed((unsigned char *) &seedNumber, sizeof(seedNumber));
223
224 int seedRet = RAND_status();
225 if ( seedRet == 0 )
226 {
227 PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4,
228 "Not enough data , RAND_status = " + seedRet );
229 PEG_METHOD_EXIT();
230 throw( SSLException("RAND_seed - Not enough seed data "));
231 }
|
232 kumpf 1.1
233 #endif // end of PEGASUS_SSL_RANDOMFILE
234
|
235 kumpf 1.9 _sslContext = _makeSSLContext();
236
237 PEG_METHOD_EXIT();
238 }
239
240 SSLContextRep::SSLContextRep(const SSLContextRep& sslContextRep)
241 {
242 PEG_METHOD_ENTER(TRC_SSL, "SSLContextRep::SSLContextRep()");
243
244 _certPath = sslContextRep._certPath;
245 // ATTN: verify_certificate is set implicitly in global variable
246 _randomFile = sslContextRep._randomFile;
247 _sslContext = _makeSSLContext();
248
249 PEG_METHOD_EXIT();
250 }
|
251 kumpf 1.11
|
252 kumpf 1.9 //
253 // Destructor
254 //
255
256 SSLContextRep::~SSLContextRep()
257 {
258 PEG_METHOD_ENTER(TRC_SSL, "SSLContextRep::~SSLContextRep()");
259
260 SSL_CTX_free(_sslContext);
261
262 PEG_METHOD_EXIT();
263 }
264
265 SSL_CTX * SSLContextRep::_makeSSLContext()
266 {
267 PEG_METHOD_ENTER(TRC_SSL, "SSLContextRep::_makeSSLContext()");
268
269 SSL_CTX * sslContext = 0;
270
|
271 kumpf 1.1 //
272 // create SSL Context Area
273 //
274
|
275 kumpf 1.9 if (!( sslContext = SSL_CTX_new(SSLv23_method()) ))
|
276 kumpf 1.3 {
277 PEG_METHOD_EXIT();
|
278 kumpf 1.5 throw( SSLException("Could not get SSL CTX"));
|
279 kumpf 1.3 }
280
281 #ifdef PEGASUS_OS_HPUX
|
282 kumpf 1.9 if (!(SSL_CTX_set_cipher_list(sslContext, SSL_TXT_EXP40)))
|
283 kumpf 1.5 throw( SSLException("Could not set the cipher list"));
|
284 kumpf 1.3 #endif
|
285 kumpf 1.1
286 //
287 // set overall SSL Context flags
288 //
289
|
290 kumpf 1.9 SSL_CTX_set_quiet_shutdown(sslContext, 1);
291 SSL_CTX_set_mode(sslContext, SSL_MODE_AUTO_RETRY);
292 SSL_CTX_set_options(sslContext,SSL_OP_ALL);
|
293 kumpf 1.1
|
294 kumpf 1.4 #ifdef CLIENT_CERTIFY
|
295 kumpf 1.9 SSL_CTX_set_verify(sslContext, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE,
|
296 kumpf 1.4 prepareForCallback);
297 #else
|
298 kumpf 1.10 if (verify_certificate != NULL)
|
299 kumpf 1.1 {
|
300 kumpf 1.9 SSL_CTX_set_verify(sslContext,
|
301 kumpf 1.4 SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, prepareForCallback);
|
302 kumpf 1.1 }
|
303 kumpf 1.4 #endif
|
304 kumpf 1.1
305 //
306 // check certificate given to me
307 //
308
|
309 kumpf 1.9 if (!cert_verify(sslContext, _certPath, _certPath))
|
310 kumpf 1.3 {
311 PEG_METHOD_EXIT();
|
312 kumpf 1.5 throw( SSLException("Could not get certificate and/or private key"));
|
313 kumpf 1.3 }
|
314 kumpf 1.1
|
315 kumpf 1.3 PEG_METHOD_EXIT();
|
316 kumpf 1.9 return sslContext;
|
317 kumpf 1.1 }
318
319 SSL_CTX * SSLContextRep::getContext() const
320 {
|
321 kumpf 1.9 return _sslContext;
|
322 kumpf 1.1 }
323 #else
324
325 //
|
326 kumpf 1.9 // these definitions are used if ssl is not available
|
327 kumpf 1.1 //
328
329 SSLContextRep::SSLContextRep(const String& certPath,
|
330 kumpf 1.9 SSLCertificateVerifyFunction* verifyCert,
|
331 kumpf 1.13 const String& randomFile) {}
|
332 kumpf 1.1
|
333 kumpf 1.9 SSLContextRep::SSLContextRep(const SSLContextRep& sslContextRep) {}
334
|
335 kumpf 1.1 SSLContextRep::~SSLContextRep() {}
336
|
337 kumpf 1.9 SSL_CTX * SSLContextRep::_makeSSLContext() { return 0; }
338
339 SSL_CTX * SSLContextRep::getContext() const { return 0; }
|
340 kumpf 1.1
341 #endif // end of PEGASUS_HAS_SSL
342
343 ///////////////////////////////////////////////////////////////////////////////
344 //
345 // SSLContext
346 //
347 ///////////////////////////////////////////////////////////////////////////////
348
349
350 SSLContext::SSLContext(
351 const String& certPath,
|
352 kumpf 1.9 SSLCertificateVerifyFunction* verifyCert,
|
353 kumpf 1.13 const String& randomFile)
354 {
355 _rep = new SSLContextRep(certPath, verifyCert, randomFile);
356 }
357
358 #ifndef PEGASUS_REMOVE_DEPRECATED
359 SSLContext::SSLContext(
360 const String& certPath,
361 SSLCertificateVerifyFunction* verifyCert,
|
362 kumpf 1.1 const String& randomFile,
|
363 kumpf 1.6 Boolean isCIMClient)
|
364 kumpf 1.1 {
|
365 kumpf 1.13 _rep = new SSLContextRep(certPath, verifyCert, randomFile);
|
366 kumpf 1.1 }
|
367 kumpf 1.13 #endif
|
368 kumpf 1.1
|
369 kumpf 1.9 SSLContext::SSLContext(const SSLContext& sslContext)
370 {
371 _rep = new SSLContextRep(*sslContext._rep);
|
372 kumpf 1.12 }
373
374 // Dummy constructor made private to disallow default construction
375 SSLContext::SSLContext()
376 {
|
377 kumpf 1.9 }
378
|
379 kumpf 1.1 SSLContext::~SSLContext()
380 {
381 delete _rep;
382 }
383
384
385 ///////////////////////////////////////////////////////////////////////////////
386 //
|
387 kumpf 1.9 // SSLCertificateInfo
|
388 kumpf 1.1 //
389 ///////////////////////////////////////////////////////////////////////////////
390
|
391 kumpf 1.9 class SSLCertificateInfoRep
392 {
393 public:
394 String subjectName;
395 String issuerName;
396 int errorDepth;
397 int errorCode;
398 int respCode;
399 };
400
401
402 SSLCertificateInfo::SSLCertificateInfo(
|
403 kumpf 1.1 const String subjectName,
404 const String issuerName,
405 const int errorDepth,
406 const int errorCode)
407 {
|
408 kumpf 1.9 _rep = new SSLCertificateInfoRep();
409 _rep->subjectName = subjectName;
410 _rep->issuerName = issuerName;
411 _rep->errorDepth = errorDepth;
412 _rep->errorCode = errorCode;
413 _rep->respCode = 0;
414 }
415
416 SSLCertificateInfo::SSLCertificateInfo(
417 const SSLCertificateInfo& certificateInfo)
418 {
419 _rep = new SSLCertificateInfoRep();
420 _rep->subjectName = certificateInfo._rep->subjectName;
421 _rep->issuerName = certificateInfo._rep->issuerName;
422 _rep->errorDepth = certificateInfo._rep->errorDepth;
423 _rep->errorCode = certificateInfo._rep->errorCode;
424 _rep->respCode = certificateInfo._rep->respCode;
|
425 kumpf 1.11 }
426
427 // Dummy constructor made private to disallow default construction
428 SSLCertificateInfo::SSLCertificateInfo()
429 {
|
430 kumpf 1.1 }
431
|
432 kumpf 1.9 SSLCertificateInfo::~SSLCertificateInfo()
|
433 kumpf 1.1 {
|
434 kumpf 1.9 delete _rep;
|
435 kumpf 1.1 }
436
|
437 kumpf 1.9 String SSLCertificateInfo::getSubjectName() const
|
438 kumpf 1.1 {
|
439 kumpf 1.9 return (_rep->subjectName);
|
440 kumpf 1.1 }
441
|
442 kumpf 1.9 String SSLCertificateInfo::getIssuerName() const
|
443 kumpf 1.1 {
|
444 kumpf 1.9 return (_rep->issuerName);
|
445 kumpf 1.1 }
446
|
447 kumpf 1.9 int SSLCertificateInfo::getErrorDepth() const
|
448 kumpf 1.1 {
|
449 kumpf 1.9 return (_rep->errorDepth);
|
450 kumpf 1.1 }
451
|
452 kumpf 1.9 int SSLCertificateInfo::getErrorCode() const
|
453 kumpf 1.1 {
|
454 kumpf 1.9 return (_rep->errorCode);
|
455 kumpf 1.1 }
456
|
457 kumpf 1.9 void SSLCertificateInfo::setResponseCode(const int respCode)
|
458 kumpf 1.1 {
|
459 kumpf 1.9 _rep->respCode = respCode;
|
460 kumpf 1.1 }
461
462 PEGASUS_NAMESPACE_END
463
|