Patch, begin of signed applet support

Koos Vriezen koos.vriezen at xs4all.nl
Mon Feb 9 19:17:13 GMT 2004


On Sun, Feb 08, 2004 at 06:48:38PM -0500, George Staikos wrote:
> On Saturday 07 February 2004 20:07, Koos Vriezen wrote:
> > Signed applets is one major missing feature. Attached a patch that could
> > be a start of this. It asks the user in case a permission is not granted
> > by the security manager.
> > What needs to be done is a way to store granted permissions, eg. with
> > this patch for each applet the user must answer if it allows access to
> > the clipboard.
> 
>   Do you need any PKCS support from KSSL for this?

Don't know yet, maybe you can tell me :). The certificates are described here
http://java.sun.com/j2se/1.4.2/docs/api/java/security/cert/X509Certificate.html
Certificate is created with
   $JAVA_HOME/bin/keytool -genkey -keystore mystore -alias myalias
and signing of jar file is done with
    $JAVA_HOME/bin/jarsigner -keystore mystore myjar.jar myalias

Its the combination of a valid certificate and permission that should be stored
somewhere. Java itself has support for it, like
    $JAVA_HOME/bin/keytool -import -keystore mystore -alias myalias -file mycert
and policy file like
    keystore "file:mystore", "JKS"
    grant signedBy "myalias"
    {
         permission java.io.FilePermission "file:/home/koos/dir", "read"
    }

Anyway, lets make these applets work first. I've updated the patch, it saves
quite some 'Yes' clicking :-) by remembering which permission were granted
for which certificate.
It makes use of Object.getSigners() and SecurityManager.getClassContext()                          (which is an array of all classes in the calling stack).
Duplicates from http://bugs.kde.org/show_bug.cgi?id=65602 actually seem to
work (although some questions are really scary, one applet managed to make
a c:\temp\jts directory in my home dir)

Koos
-------------- next part --------------
Index: kjavaappletserver.cpp
===================================================================
RCS file: /home/kde/kdelibs/khtml/java/kjavaappletserver.cpp,v
retrieving revision 1.68
diff -u -3 -p -r1.68 kjavaappletserver.cpp
--- kjavaappletserver.cpp	29 Nov 2003 13:05:21 -0000	1.68
+++ kjavaappletserver.cpp	9 Feb 2004 18:29:21 -0000
@@ -40,6 +40,7 @@
 #include <qvaluelist.h>
 #include <qdir.h>
 #include <qeventloop.h>
+#include <qapplication.h>
 
 #include <stdlib.h>
 #include <assert.h>
@@ -71,6 +72,7 @@
 #define KJAS_DATA_COMMAND      (char)25
 #define KJAS_PUT_URLDATA       (char)26
 #define KJAS_PUT_DATA          (char)27
+#define KJAS_SECURITY_CONFIRM  (char)28
 
 
 class JSStackFrame;
@@ -589,6 +591,14 @@ void KJavaAppletServer::slotJavaRequest(
             kdDebug(6100) << "Applet " << args[0] << " Failed: " << args[1] << endl;
             cmd = QString::fromLatin1( "AppletFailed" );
             break;
+        case KJAS_SECURITY_CONFIRM: {
+            kdDebug(6100) << "Security confirm " << args[0] << endl;
+            QStringList sl;
+            sl.push_front( KMessageBox::warningYesNo(qApp->activeWindow(), args[0], i18n("Security alert")) == KMessageBox::Yes ? "1" : "0");
+            sl.push_front(QString::number(ID_num));
+            process->send( KJAS_SECURITY_CONFIRM, sl );
+            return;
+        }
         default:
             return;
             break;
Index: org/kde/kjas/server/KJASProtocolHandler.java
===================================================================
RCS file: /home/kde/kdelibs/khtml/java/org/kde/kjas/server/KJASProtocolHandler.java,v
retrieving revision 1.51
diff -u -3 -p -r1.51 KJASProtocolHandler.java
--- org/kde/kjas/server/KJASProtocolHandler.java	23 Jan 2004 12:18:53 -0000	1.51
+++ org/kde/kjas/server/KJASProtocolHandler.java	9 Feb 2004 18:29:21 -0000
@@ -42,6 +42,7 @@ public class KJASProtocolHandler
     private static final int DataCommand         = 25;
     private static final int PutURLDataCode      = 26;
     private static final int PutDataCode         = 27;
+    private static final int SecurityConfirmCode = 28;
 
     //Holds contexts in contextID-context pairs
     private Hashtable contexts;
@@ -332,6 +333,19 @@ public class KJASProtocolHandler
             if ( context != null )
                 context.derefObject(Integer.parseInt(objid));
             Main.debug( "DerefObject " + objid);
+        } else
+        if (cmd_code_value == SecurityConfirmCode)
+        {
+            String id = getArg( command );
+            String confirm = getArg( command );
+            Thread t = (Thread) KJASSecurityManager.confirmRequests.get(id);
+            Main.debug( "SecurityConfirmCode " + id + " confirm:" + confirm );
+            if (t != null) {
+                KJASSecurityManager.confirmRequests.put(id, confirm);
+                try {
+                    t.interrupt();
+                } catch (SecurityException se) {}
+            }
         }
         else
         {
@@ -830,6 +844,32 @@ public class KJASProtocolHandler
 
         signals.write( bytes, 0, bytes.length );
     }
+    public void sendSecurityConfirm( String text, String id )
+    {
+        Main.debug("sendSecurityConfirm, ID = " + id + " text = " + text);
+
+        byte [] id_bytes = id.getBytes();
+        byte [] text_bytes = text.getBytes();
+        int length = text_bytes.length + id_bytes.length + 4;
+        byte [] bytes = new byte[ length + 8 ]; //for length of message
+        byte [] tmp_bytes = getPaddedLengthBytes( length );
+        int index = 0;
+
+        System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length );
+        index += tmp_bytes.length;
+        bytes[index++] = (byte) SecurityConfirmCode;
+        bytes[index++] = sep;
+
+        System.arraycopy( id_bytes, 0, bytes, index, id_bytes.length );
+        index += id_bytes.length;
+        bytes[index++] = sep;
+
+        System.arraycopy( text_bytes, 0, bytes, index, text_bytes.length );
+        index += text_bytes.length;
+        bytes[index++] = sep;
+
+        signals.write( bytes, 0, bytes.length );
+    }
     /**************************************************************
      *****  Utility functions for parsing commands ****************
      **************************************************************/
Index: org/kde/kjas/server/KJASSecurityManager.java
===================================================================
RCS file: /home/kde/kdelibs/khtml/java/org/kde/kjas/server/KJASSecurityManager.java,v
retrieving revision 1.4
diff -u -3 -p -r1.4 KJASSecurityManager.java
--- org/kde/kjas/server/KJASSecurityManager.java	16 May 2002 23:55:32 -0000	1.4
+++ org/kde/kjas/server/KJASSecurityManager.java	9 Feb 2004 18:29:21 -0000
@@ -1,11 +1,17 @@
 package org.kde.kjas.server;
 
 import java.security.*;
+import java.security.cert.*;
 import java.net.*;
+import java.util.*;
 
 
 public class KJASSecurityManager extends SecurityManager
 {
+    static Hashtable confirmRequests = new Hashtable();
+    static int confirmId = 0;
+    Hashtable grantedPermissions = new Hashtable();
+
     public KJASSecurityManager()
     {
     }
@@ -15,6 +21,66 @@ public class KJASSecurityManager extends
      * applet cannot connect to any other but the host, where it comes from.
      * Anything else seems to be handled automagically
      */
+    public void checkPermission(Permission perm) throws SecurityException, NullPointerException {
+        try {
+            super.checkPermission(perm);
+        } catch (SecurityException se) {
+            HashSet set = new HashSet();
+            Class [] cls = getClassContext();
+            for (int i = 1; i < cls.length; i++) {
+                Object[] objs = cls[i].getSigners();
+                if (objs != null && objs.length > 0)
+                    for (int j = 0; j < objs.length; j++)
+                        set.add(objs[j]);
+            }
+            Main.debug("Certificates " + set.size() + " for " + perm);
+            if (set.size() == 0)
+                throw se;
+            String text = new String();
+            for (Iterator i = set.iterator(); i.hasNext(); ) {
+                Object cert = i.next();
+                HashSet permset = (HashSet) grantedPermissions.get(cert);
+                if (permset != null) {
+                    for (Iterator j = permset.iterator(); j.hasNext(); ) {
+                        Permission p = (Permission) j.next();
+                        if (p.equals(perm) || p.implies(perm))
+                            return;
+                    }
+                }
+                if (cert instanceof X509Certificate)
+                    text += ((X509Certificate) cert).getIssuerDN().getName();
+                else
+                    text += cert.toString();
+                text += "\n";
+            }
+            String id = "" + confirmId++;
+            confirmRequests.put(id, Thread.currentThread());
+            Main.protocol.sendSecurityConfirm(text + perm, id);
+            boolean ok = false;
+            try {
+                Thread.currentThread().sleep(300000);
+            } catch (InterruptedException ie) {
+                if (((String) confirmRequests.get(id)).equals("1")) {
+                    for (Iterator it = set.iterator(); it.hasNext(); ) {
+                        Object cert = it.next();
+                        HashSet permset = (HashSet) grantedPermissions.get(cert);
+                        if (permset == null) {
+                            permset = new HashSet();
+                            grantedPermissions.put(cert, permset);
+                        }
+                        permset.add(perm);
+                    }
+                    ok = true;
+                }
+            } finally {
+                confirmRequests.remove(id);
+            }
+            if (!ok) {
+                Main.debug("Permission denied" + perm);
+                throw se;
+            }
+        }
+    }
     public void disabled___checkPermission(Permission perm) throws SecurityException, NullPointerException
     {
         // does not seem to work as expected, Problems with proxy - and it seems that the default


More information about the kfm-devel mailing list