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
|