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