diff --git a/direct/src/p3d/coreapi.pdef b/direct/src/p3d/coreapi.pdef index 0a631b5743..dbb70fcade 100644 --- a/direct/src/p3d/coreapi.pdef +++ b/direct/src/p3d/coreapi.pdef @@ -64,6 +64,20 @@ class images(package): config(**configDict) +class certlist(package): + # This package holds any certificates that should be considered + # pre-approved by the plugin vendor. If you build and host your + # own version of the Panda3D plugin, you can add your own + # certificates to this list. The certificates in this package + # will be assumed to have been approved by the user when he/she + # installed the plugin. + + # They should be PEM-encoded and their filenames must end in the + # ".pem" or ".crt" extension, and they should be added with the + # extract = True flag so they will be extracted to disk. + file('/home/drose/mycertpub.pem', extract = True) + + class p3dcert(package): # This special application, used to pop up a dialog to prompt the # user to accept or deny unknown applications, is its own package. diff --git a/direct/src/plugin/p3dInstance.cxx b/direct/src/plugin/p3dInstance.cxx index edb64dd728..deeacf9586 100644 --- a/direct/src/plugin/p3dInstance.cxx +++ b/direct/src/plugin/p3dInstance.cxx @@ -88,6 +88,7 @@ P3DInstance(P3D_request_ready_func *func, _got_wparams = false; _p3d_trusted = false; _xpackage = NULL; + _certlist_package = NULL; _p3dcert_package = NULL; _fparams.set_tokens(tokens, num_tokens); @@ -102,7 +103,7 @@ P3DInstance(P3D_request_ready_func *func, _allow_python_dev = false; _keep_user_env = (_fparams.lookup_token_int("keep_user_env") != 0); _auto_start = (_fparams.lookup_token_int("auto_start") != 0); - _auth_button_approved = false; + _auth_button_clicked = false; _failed = false; _session = NULL; _auth_session = NULL; @@ -234,6 +235,11 @@ P3DInstance:: _image_package = NULL; } + if (_certlist_package != NULL) { + _certlist_package->remove_instance(this); + _certlist_package = NULL; + } + if (_p3dcert_package != NULL) { _p3dcert_package->remove_instance(this); _p3dcert_package = NULL; @@ -539,6 +545,10 @@ set_browser_script_object(P3D_object *browser_script_object) { P3D_OBJECT_DECREF(port); } + if (_origin_hostname.empty() && _origin_protocol == "file:") { + _origin_hostname = "localhost"; + } + if (_origin_port.empty()) { // Maybe the actual URL doesn't include the port, in which // case it is implicit. @@ -553,8 +563,11 @@ set_browser_script_object(P3D_object *browser_script_object) { } } - nout << "origin is " << _origin_protocol << "//" << _origin_hostname - << ":" << _origin_port << "\n"; + nout << "origin is " << _origin_protocol << "//" << _origin_hostname; + if (!_origin_port.empty()) { + nout << ":" << _origin_port; + } + nout << "\n"; } @@ -1244,20 +1257,14 @@ auth_finished_sub_thread() { //////////////////////////////////////////////////////////////////// void P3DInstance:: auth_finished_main_thread() { + // Set this flag to indicate that the user has clicked on the red + // "auth" button. This eliminates the need to click on the green + // "start" button. + _auth_button_clicked = true; + // After the authorization program has returned, check the signature // again. - if (check_p3d_signature()) { - // Set this flag to indicate that the user has clicked on the red - // "auth" button and successfully approved the application's - // certificate. This eliminates the need to click on the green - // "start" button. - _auth_button_approved = true; - mark_p3d_trusted(); - - } else { - // Still untrusted. - mark_p3d_untrusted(); - } + check_p3d_signature(); } //////////////////////////////////////////////////////////////////// @@ -1292,11 +1299,7 @@ priv_set_p3d_filename(const string &p3d_filename) { return; } - if (check_p3d_signature()) { - mark_p3d_trusted(); - } else { - mark_p3d_untrusted(); - } + check_p3d_signature(); } //////////////////////////////////////////////////////////////////// @@ -1505,18 +1508,21 @@ check_matches_component(const string &orig, const string &match) { // Function: P3DInstance::check_p3d_signature // Access: Private // Description: Checks the signature(s) encoded in the p3d file, and -// looks to see if any of them are recognized. Returns -// true if the signature is recognized and the file -// should be trusted, false otherwise. +// looks to see if any of them are recognized. +// +// If the signature is recognized, calls +// mark_p3d_trusted(); otherwise, calls +// mark_p3d_untrusted(). //////////////////////////////////////////////////////////////////// -bool P3DInstance:: +void P3DInstance:: check_p3d_signature() { P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); if (inst_mgr->get_trusted_environment()) { // If we're in a trusted environment (e.g. the panda3d command // line, where we've already downloaded the p3d file separately), // then everything is approved. - return true; + mark_p3d_trusted(); + return; } // See if we've previously approved the certificate--any @@ -1531,12 +1537,33 @@ check_p3d_signature() { // Look up the certificate to see if we've stored a copy in our // certs dir. if (inst_mgr->find_cert(cert)) { - return true; + mark_p3d_trusted(); + return; } } + // Check the list of pre-approved certificates. + if (_certlist_package == NULL) { + // We have to go download this package. + P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); + P3DHost *host = inst_mgr->get_host(inst_mgr->get_host_url()); + _certlist_package = host->get_package("certlist", ""); + if (_certlist_package != NULL) { + _certlist_package->add_instance(this); + } + + // When the package finishes downloading, we will come back here. + return; + } + + if (!_certlist_package->get_ready() && !_certlist_package->get_failed()) { + // Wait for it to finish downloading. + return; + } + // Couldn't find any approved certificates. - return false; + mark_p3d_untrusted(); + return; } //////////////////////////////////////////////////////////////////// @@ -1714,7 +1741,7 @@ scan_app_desc_file(TiXmlDocument *doc) { _matches_script_origin = true; } - if (_auth_button_approved) { + if (_auth_button_clicked) { // But finally, if the user has already clicked through the red // "auth" button, no need to present him/her with another green // "play" button as well. @@ -2279,15 +2306,21 @@ set_button_image(ImageType image_type) { //////////////////////////////////////////////////////////////////// void P3DInstance:: report_package_info_ready(P3DPackage *package) { - if (package == _image_package || package == _p3dcert_package) { - // A special case: the image package and the p3dcert package get - // immediately downloaded, without waiting for anything else. - if (package == _p3dcert_package) { - // If we're downloading p3dcert, though, put up a progress bar. + if (package == _image_package || package == _certlist_package || + package == _p3dcert_package) { + // A special case: these packages get immediately downloaded, + // without waiting for anything else. + if (package == _certlist_package || package == _p3dcert_package) { + // If we're downloading one of the two cert packages, though, + // put up a progress bar. make_splash_window(); if (_splash_window != NULL) { _splash_window->set_install_progress(0.0); - _splash_window->set_install_label("Getting Authorization Dialog"); + if (package == _certlist_package) { + _splash_window->set_install_label("Getting Certificates"); + } else { + _splash_window->set_install_label("Getting Authorization Dialog"); + } } } @@ -2503,7 +2536,7 @@ report_package_progress(P3DPackage *package, double progress) { // Ignore this. return; } - if (package == _p3dcert_package) { + if (package == _certlist_package || package == _p3dcert_package) { // This gets its own progress bar. if (_splash_window != NULL) { _splash_window->set_install_progress(progress); @@ -2591,6 +2624,23 @@ report_package_done(P3DPackage *package, bool success) { return; } + if (package == _certlist_package) { + // Another special case: successfully downloading certlist (or + // failing to download it) means we can finish checking the + // authenticity of the p3d file. + + // Take down the download progress. + if (_splash_window != NULL) { + _splash_window->set_install_progress(0.0); + _splash_window->set_install_label(""); + } + + P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); + inst_mgr->read_certlist(package); + check_p3d_signature(); + return; + } + if (package == _p3dcert_package) { // Another special case: successfully downloading p3dcert means we // can enable the auth button. diff --git a/direct/src/plugin/p3dInstance.h b/direct/src/plugin/p3dInstance.h index cec981736f..3627399620 100644 --- a/direct/src/plugin/p3dInstance.h +++ b/direct/src/plugin/p3dInstance.h @@ -165,7 +165,7 @@ private: void separate_components(vector &components, const string &str); bool check_matches_component(const string &orig, const string &match); - bool check_p3d_signature(); + void check_p3d_signature(); void mark_p3d_untrusted(); void mark_p3d_trusted(); void scan_app_desc_file(TiXmlDocument *doc); @@ -238,6 +238,10 @@ private: bool _p3d_trusted; TiXmlElement *_xpackage; + + // Holds the list of certificates that are pre-approved by the + // plugin vendor. + P3DPackage *_certlist_package; // For downloading the p3dcert authorization program. P3DPackage *_p3dcert_package; @@ -252,7 +256,7 @@ private: bool _allow_python_dev; bool _keep_user_env; bool _auto_start; - bool _auth_button_approved; + bool _auth_button_clicked; bool _failed; P3DSession *_session; diff --git a/direct/src/plugin/p3dInstanceManager.cxx b/direct/src/plugin/p3dInstanceManager.cxx index 9469b016fa..5c873d7d92 100644 --- a/direct/src/plugin/p3dInstanceManager.cxx +++ b/direct/src/plugin/p3dInstanceManager.cxx @@ -22,6 +22,7 @@ #include "p3dUndefinedObject.h" #include "p3dNoneObject.h" #include "p3dBoolObject.h" +#include "p3dPackage.h" #include "find_root_dir.h" #include "fileSpec.h" #include "get_tinyxml.h" @@ -873,6 +874,42 @@ find_cert(X509 *cert) { return false; } +//////////////////////////////////////////////////////////////////// +// Function: P3DInstanceManager::read_certlist +// Access: Public +// Description: Reads the pre-approved certificates in the certlist +// package and adds them to the in-memory cache. +//////////////////////////////////////////////////////////////////// +void P3DInstanceManager:: +read_certlist(P3DPackage *package) { + nout << "reading certlist in " << package->get_package_dir() << "\n"; + + vector contents; + scan_directory(package->get_package_dir(), contents); + + vector::iterator si; + for (si = contents.begin(); si != contents.end(); ++si) { + const string &basename = (*si); + if (basename.length() > 4) { + string suffix = basename.substr(basename.length() - 4); + if (suffix == ".pem" || suffix == ".crt") { + string filename = package->get_package_dir() + "/" + basename; + X509 *x509 = NULL; + FILE *fp = fopen(filename.c_str(), "r"); + if (fp != NULL) { + x509 = PEM_read_X509(fp, NULL, NULL, (void *)""); + fclose(fp); + } + + if (x509 != NULL) { + string der2 = cert_to_der(x509); + _approved_certs.insert(der2); + } + } + } + } +} + //////////////////////////////////////////////////////////////////// // Function: P3DInstanceManager::get_cert_dir // Access: Public diff --git a/direct/src/plugin/p3dInstanceManager.h b/direct/src/plugin/p3dInstanceManager.h index 8b750a4122..4635f10e05 100644 --- a/direct/src/plugin/p3dInstanceManager.h +++ b/direct/src/plugin/p3dInstanceManager.h @@ -35,6 +35,7 @@ class P3DInstance; class P3DSession; class P3DAuthSession; class P3DHost; +class P3DPackage; class FileSpec; class TiXmlElement; @@ -120,6 +121,7 @@ public: void release_temp_filename(const string &filename); bool find_cert(X509 *cert); + void read_certlist(P3DPackage *package); string get_cert_dir(X509 *cert); static string cert_to_der(X509 *cert);