Panda3D
|
00001 // Filename: openSSLWrapper.cxx 00002 // Created by: drose (05Sep09) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "openSSLWrapper.h" 00016 00017 #ifdef HAVE_OPENSSL 00018 00019 #include "virtualFileSystem.h" 00020 #include "ca_bundle_data_src.c" 00021 00022 OpenSSLWrapper *OpenSSLWrapper::_global_ptr = NULL; 00023 00024 //////////////////////////////////////////////////////////////////// 00025 // Function: OpenSSLWrapper::Constructor 00026 // Access: Private 00027 // Description: 00028 //////////////////////////////////////////////////////////////////// 00029 OpenSSLWrapper:: 00030 OpenSSLWrapper() { 00031 // It is necessary to call this before making any other OpenSSL 00032 // call, per the docs. Also, the docs say that making this call 00033 // will seed the random number generator. Apparently you can get 00034 // away with not calling it in versions prior to 0.9.8, however. 00035 SSL_library_init(); 00036 00037 OpenSSL_add_all_algorithms(); 00038 00039 _x509_store = X509_STORE_new(); 00040 X509_STORE_set_default_paths(_x509_store); 00041 00042 // Load in the well-known certificate authorities compiled into this 00043 // program. 00044 load_certificates_from_der_ram((const char *)ca_bundle_data, ca_bundle_data_len); 00045 00046 // Load in any default certificates listed in the Config.prc file. 00047 ConfigVariableFilename ca_bundle_filename 00048 ("ca-bundle-filename", "", 00049 PRC_DESC("This names the certificate authority file for OpenSSL " 00050 "to use to verify whether SSL certificates are trusted or not. " 00051 "The file named by this setting should contain one or more " 00052 "PEM-formatted certificates from trusted certificate " 00053 "authorities. This is a fairly standard file; a copy of " 00054 "ca-bundle.crt is included in the OpenSSL distribution, and " 00055 "is also included with Panda.")); 00056 00057 if (!ca_bundle_filename.empty()) { 00058 load_certificates(ca_bundle_filename); 00059 } 00060 00061 ConfigVariableList ssl_certificates 00062 ("ssl-certificates", 00063 PRC_DESC("This variable lists additional filenames, on top of the file " 00064 "named by ca-bundle-filename, that contain trusted SSL " 00065 "certificates or certificate authorities.")); 00066 00067 int num_certs = ssl_certificates.get_num_unique_values(); 00068 for (int ci = 0; ci < num_certs; ci++) { 00069 string cert_file = ssl_certificates.get_unique_value(ci); 00070 Filename filename = Filename::expand_from(cert_file); 00071 load_certificates(filename); 00072 } 00073 } 00074 00075 //////////////////////////////////////////////////////////////////// 00076 // Function: OpenSSLWrapper::Destructor 00077 // Access: Private 00078 // Description: 00079 //////////////////////////////////////////////////////////////////// 00080 OpenSSLWrapper:: 00081 ~OpenSSLWrapper() { 00082 // Actually, the destructor is never called. 00083 X509_STORE_free(_x509_store); 00084 } 00085 00086 //////////////////////////////////////////////////////////////////// 00087 // Function: OpenSSLWrapper::clear_certificates 00088 // Access: Public 00089 // Description: Removes all the certificates from the global store, 00090 // including the compiled-in certificates loaded from 00091 // ca_bundle_data.c. You can add new certificates by 00092 // calling load_certificates(). 00093 //////////////////////////////////////////////////////////////////// 00094 void OpenSSLWrapper:: 00095 clear_certificates() { 00096 // We do this by deleting the store and creating a new one. 00097 X509_STORE_free(_x509_store); 00098 _x509_store = X509_STORE_new(); 00099 00100 // We don't set the default path either. We want a squeaky-clean store. 00101 //X509_STORE_set_default_paths(_x509_store); 00102 } 00103 00104 //////////////////////////////////////////////////////////////////// 00105 // Function: OpenSSLWrapper::load_certificates 00106 // Access: Public 00107 // Description: Reads the PEM-formatted certificate(s) (delimited by 00108 // -----BEGIN CERTIFICATE----- and -----END 00109 // CERTIFICATE-----) from the indicated file and adds 00110 // them to the global store object, retrieved via 00111 // get_x509_store(). 00112 // 00113 // Returns the number of certificates read on success, 00114 // or 0 on failure. 00115 // 00116 // You should call this only with trusted, 00117 // locally-stored certificates; not with certificates 00118 // received from an untrusted source. 00119 //////////////////////////////////////////////////////////////////// 00120 int OpenSSLWrapper:: 00121 load_certificates(const Filename &filename) { 00122 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); 00123 00124 // First, read the complete file into memory. 00125 string data; 00126 if (!vfs->read_file(filename, data, true)) { 00127 // Could not find or read file. 00128 express_cat.info() 00129 << "Could not read " << filename << ".\n"; 00130 return 0; 00131 } 00132 00133 int result = load_certificates_from_pem_ram(data.data(), data.size()); 00134 00135 if (result <= 0) { 00136 express_cat.info() 00137 << "Could not load certificates from " << filename << ".\n"; 00138 notify_ssl_errors(); 00139 return 0; 00140 } 00141 00142 if (express_cat.is_debug()) { 00143 express_cat.debug() 00144 << "Appending " << result << " SSL certificates from " 00145 << filename << "\n"; 00146 } 00147 00148 return result; 00149 } 00150 00151 //////////////////////////////////////////////////////////////////// 00152 // Function: OpenSSLWrapper::load_certificates_from_pem_ram 00153 // Access: Public 00154 // Description: Reads a chain of trusted certificates from the 00155 // indicated data buffer and adds them to the X509_STORE 00156 // object. The data buffer should be PEM-formatted. 00157 // Returns the number of certificates read on success, 00158 // or 0 on failure. 00159 // 00160 // You should call this only with trusted, 00161 // locally-stored certificates; not with certificates 00162 // received from an untrusted source. 00163 //////////////////////////////////////////////////////////////////// 00164 int OpenSSLWrapper:: 00165 load_certificates_from_pem_ram(const char *data, size_t data_size) { 00166 STACK_OF(X509_INFO) *inf; 00167 00168 // Create an in-memory BIO to read the "file" from the buffer, and 00169 // call the low-level routines to read the certificates from the 00170 // BIO. 00171 BIO *mbio = BIO_new_mem_buf((void *)data, data_size); 00172 00173 // We have to be sure and clear the OpenSSL error state before we 00174 // call this function, or it will get confused. 00175 ERR_clear_error(); 00176 inf = PEM_X509_INFO_read_bio(mbio, NULL, NULL, NULL); 00177 BIO_free(mbio); 00178 00179 if (!inf) { 00180 // Could not scan certificates. 00181 express_cat.info() 00182 << "PEM_X509_INFO_read_bio() returned NULL.\n"; 00183 notify_ssl_errors(); 00184 return 0; 00185 } 00186 00187 if (express_cat.is_spam()) { 00188 express_cat.spam() 00189 << "PEM_X509_INFO_read_bio() found " << sk_X509_INFO_num(inf) 00190 << " entries.\n"; 00191 } 00192 00193 // Now add the certificates to the store. 00194 00195 int count = 0; 00196 int num_entries = sk_X509_INFO_num(inf); 00197 for (int i = 0; i < num_entries; i++) { 00198 X509_INFO *itmp = sk_X509_INFO_value(inf, i); 00199 00200 if (itmp->x509) { 00201 int result = X509_STORE_add_cert(_x509_store, itmp->x509); 00202 if (result == 0) { 00203 notify_debug_ssl_errors(); 00204 } else { 00205 ++count; 00206 } 00207 00208 if (express_cat.is_spam()) { 00209 express_cat.spam() 00210 << "Entry " << i << " is x509\n"; 00211 } 00212 00213 } else if (itmp->crl) { 00214 int result = X509_STORE_add_crl(_x509_store, itmp->crl); 00215 if (result == 0) { 00216 notify_debug_ssl_errors(); 00217 } else { 00218 ++count; 00219 } 00220 00221 if (express_cat.is_spam()) { 00222 express_cat.spam() 00223 << "Entry " << i << " is crl\n"; 00224 } 00225 00226 } else if (itmp->x_pkey) { 00227 if (express_cat.is_spam()) { 00228 express_cat.spam() 00229 << "Entry " << i << " is pkey\n"; 00230 } 00231 00232 } else { 00233 if (express_cat.is_spam()) { 00234 express_cat.spam() 00235 << "Entry " << i << " is unknown type\n"; 00236 } 00237 } 00238 } 00239 sk_X509_INFO_pop_free(inf, X509_INFO_free); 00240 00241 if (express_cat.is_spam()) { 00242 express_cat.spam() 00243 << "successfully loaded " << count << " entries.\n"; 00244 } 00245 00246 return count; 00247 } 00248 00249 //////////////////////////////////////////////////////////////////// 00250 // Function: OpenSSLWrapper::load_certificates_from_der_ram 00251 // Access: Public 00252 // Description: Reads a chain of trusted certificates from the 00253 // indicated data buffer and adds them to the X509_STORE 00254 // object. The data buffer should be DER-formatted. 00255 // Returns the number of certificates read on success, 00256 // or 0 on failure. 00257 // 00258 // You should call this only with trusted, 00259 // locally-stored certificates; not with certificates 00260 // received from an untrusted source. 00261 //////////////////////////////////////////////////////////////////// 00262 int OpenSSLWrapper:: 00263 load_certificates_from_der_ram(const char *data, size_t data_size) { 00264 if (express_cat.is_spam()) { 00265 express_cat.spam() 00266 << "load_certificates_from_der_ram(" << (void *)data 00267 << ", " << data_size << ")\n"; 00268 } 00269 00270 int count = 0; 00271 00272 #if OPENSSL_VERSION_NUMBER >= 0x00908000L 00273 // Beginning in 0.9.8, d2i_X509() accepted a const unsigned char **. 00274 const unsigned char *bp, *bp_end; 00275 #else 00276 // Prior to 0.9.8, d2i_X509() accepted an unsigned char **. 00277 unsigned char *bp, *bp_end; 00278 #endif 00279 00280 bp = (unsigned char *)data; 00281 bp_end = bp + data_size; 00282 while (bp < bp_end) { 00283 X509 *x509 = d2i_X509(NULL, &bp, bp_end - bp); 00284 if (x509 == NULL) { 00285 notify_ssl_errors(); 00286 break; 00287 } 00288 00289 int result = X509_STORE_add_cert(_x509_store, x509); 00290 if (result == 0) { 00291 notify_debug_ssl_errors(); 00292 } else { 00293 ++count; 00294 } 00295 } 00296 00297 00298 if (express_cat.is_spam()) { 00299 express_cat.spam() 00300 << "loaded " << count << " certificates\n"; 00301 } 00302 00303 return count; 00304 } 00305 00306 //////////////////////////////////////////////////////////////////// 00307 // Function: OpenSSLWrapper::get_x509_store 00308 // Access: Public 00309 // Description: Returns the global X509_STORE object. 00310 // 00311 // It has to be a global object, because OpenSSL seems 00312 // to store some global pointers associated with this 00313 // object whether you want it to or not, and keeping 00314 // independent copies of a local X509_STORE object 00315 // doesn't seem to work that well. So, we have one 00316 // store that keeps all certificates the application 00317 // might need. 00318 //////////////////////////////////////////////////////////////////// 00319 X509_STORE *OpenSSLWrapper:: 00320 get_x509_store() { 00321 return _x509_store; 00322 } 00323 00324 //////////////////////////////////////////////////////////////////// 00325 // Function: OpenSSLWrapper::notify_ssl_errors 00326 // Access: Public 00327 // Description: A convenience function that is itself a wrapper 00328 // around the OpenSSL convenience function to output the 00329 // recent OpenSSL errors. This function sends the error 00330 // string to express_cat.warning(). If 00331 // REPORT_OPENSSL_ERRORS is not defined, the function 00332 // does nothing. 00333 //////////////////////////////////////////////////////////////////// 00334 void OpenSSLWrapper:: 00335 notify_ssl_errors() { 00336 #ifdef REPORT_OPENSSL_ERRORS 00337 static bool strings_loaded = false; 00338 if (!strings_loaded) { 00339 SSL_load_error_strings(); 00340 strings_loaded = true; 00341 } 00342 00343 unsigned long e = ERR_get_error(); 00344 while (e != 0) { 00345 static const size_t buffer_len = 256; 00346 char buffer[buffer_len]; 00347 ERR_error_string_n(e, buffer, buffer_len); 00348 express_cat.warning() << buffer << "\n"; 00349 e = ERR_get_error(); 00350 } 00351 #endif // REPORT_OPENSSL_ERRORS 00352 } 00353 00354 //////////////////////////////////////////////////////////////////// 00355 // Function: OpenSSLWrapper::notify_debug_ssl_errors 00356 // Access: Public 00357 // Description: As notify_ssl_errors(), but sends the output to debug 00358 // instead of warning. 00359 //////////////////////////////////////////////////////////////////// 00360 void OpenSSLWrapper:: 00361 notify_debug_ssl_errors() { 00362 #ifdef REPORT_OPENSSL_ERRORS 00363 static bool strings_loaded = false; 00364 if (!strings_loaded) { 00365 SSL_load_error_strings(); 00366 strings_loaded = true; 00367 } 00368 00369 unsigned long e = ERR_get_error(); 00370 while (e != 0) { 00371 if (express_cat.is_debug()) { 00372 static const size_t buffer_len = 256; 00373 char buffer[buffer_len]; 00374 ERR_error_string_n(e, buffer, buffer_len); 00375 express_cat.debug() << buffer << "\n"; 00376 } 00377 e = ERR_get_error(); 00378 } 00379 #endif // REPORT_OPENSSL_ERRORS 00380 } 00381 00382 //////////////////////////////////////////////////////////////////// 00383 // Function: OpenSSLWrapper::get_global_ptr 00384 // Access: Public, Static 00385 // Description: 00386 //////////////////////////////////////////////////////////////////// 00387 OpenSSLWrapper *OpenSSLWrapper:: 00388 get_global_ptr() { 00389 if (_global_ptr == NULL) { 00390 _global_ptr = new OpenSSLWrapper; 00391 } 00392 return _global_ptr; 00393 } 00394 00395 #endif // HAVE_OPENSSL