Browse Source

add certlist package for pre-approved certificates

David Rose 16 years ago
parent
commit
a784d86581

+ 14 - 0
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.

+ 85 - 35
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.

+ 6 - 2
direct/src/plugin/p3dInstance.h

@@ -165,7 +165,7 @@ private:
   void separate_components(vector<string> &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;

+ 37 - 0
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<string> contents;
+  scan_directory(package->get_package_dir(), contents);
+
+  vector<string>::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

+ 2 - 0
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);