Tuesday, May 17, 2011

Signed Applets Running in Unrestricted Mode

Some context : Use a library of encryption and decryption of messages (not developed by me). The encryption/decryption must happen on the client and not on the server.

Solution : It was decided to use a non visual applet to make use of the library. The library uses a Bouncy Castle provided.
As soon as the Bouncy Castle  provider is added you'll get an error message like this :

java.security.AccessControlException: access denied (java.security.SecurityPermission insertProvider.BC)


As you can read the applet can't make use of
Security.addProvider(new BouncyCastleProvider());


The developer has several possibilities.

1. Make use of a policy file
The computer where the applet is executed can decide to grant permissions to the applet Java using a file named .java.policy in the user home directory.

example :
grant {
  permission java.security.SecurityPermission "insertProvider.*";
  permission java.util.logging.LoggingPermission "control";
};

grant {
  permission java.util.PropertyPermission "user.dir", "read";
  permission java.util.PropertyPermission "user.dir", "write";
  permission java.io.FilePermission "<<ALL FILES>>", "read";
  permission java.io.FilePermission "<<ALL FILES>>", "write";
};
This will solve the problem but it is rather not convenient because you have to ask every user that uses the applet  to copy the .java.policy file into his home directory and there are chances that your customer will not accept this solution.

2a. Signing the applet and run in unrestricted mode

If the applet is signed then the code will run unrestricted. Totally unrestricted ? You'll see. :-)
The procedure to sign the applet using a test certificate can be found here (a good example).

==>TestingWithRSA

As you can read into the title you have to sign using a RSA key.
keytool -genkey -keyalg RSA -keystore test_store -alias rsatest


But in the case of Bouncy Castle, it is NOT enough !

You have to embed your code into a special bloc of code.

        AccessController.doPrivileged(new PrivilegedAction() {
            public Object run() {
                // privileged code goes here, for example:
                Security.addProvider(new BouncyCastleProvider());
                return null; // nothing to return
            }
        });

This time it will be successful and you are in unrestricted mode.

Hope it helps.

-Rudy-

Pointers :

==>applet security basics
==>Can distribution of a .java.policy file be eliminated
==>How RSA Signed Applet Verification Works in Java Plug-in
==>How to Sign Applets Using RSA-Signed Certificates
==>Deploying RSA Signed Applets in Java Plug-in
==>How to Deploy RSA-Signed Applets in Java Plug-in
==>Signed applet getting access denied
==>How Can An Applet Read Files On The Local File System
==>Self Signed Applet Can it access Local File Systems

3 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Dear Eric, I got your comment by email that we can't read here :-)
    I had a problem to execute Security.addProvider method...
    So I had to put the statement into the following statements...

    AccessController.doPrivileged(new PrivilegedAction() {
    public Object run() {

    // privileged code goes here, for example:
    *** Security.addProvider(new BouncyCastleProvider()); ***

    return null; // nothing to return
    }
    });

    ReplyDelete
  3. Hi, I have a problem when i try to load the keystore from the bouncycaslte provider any idea ?

    Here is my code :
    KeyStore keyStore = null;

    switch (typeProvider) {
    case MSCAPI:
    keyStore = KeyStore.getInstance(KEYSTORE_TYPE_SUNMSCAPI);
    break;
    case PKCS12:
    Provider provider = Security.getProvider(KEYSTORE_PROVIDER_BOUNCYCASTLE);
    if (provider == null) {
    afficherMessage("Création d'un provider Bouncy Castle afin de traiter le fichier de certificat utilisé...");
    // ajout du code nécessitant les bon privilèges
    AccessController.doPrivileged(new PrivilegedAction() {
    public Object run() {
    Security.addProvider(new BouncyCastleProvider());
    return null;
    }
    });

    }
    keyStore = KeyStore.getInstance(KEYSTORE_TYPE_PKCS12, KEYSTORE_PROVIDER_BOUNCYCASTLE);
    break;
    }

    return keyStore;

    Here is the error that is throw :

    error constructing MAC: java.security.NoSuchProviderException: JCE cannot authenticate the provider BC
    java.io.IOException: error constructing MAC: java.security.NoSuchProviderException: JCE cannot authenticate the provider BC
    at org.bouncycastle.jce.provider.JDKPKCS12KeyStore.engineLoad(Unknown Source)
    at java.security.KeyStore.load(KeyStore.java:1185)
    at fr.atexo.signature.pades.crypto.provider.pkcs12.Pkcs12Handler.getKeyPair(Pkcs12Handler.java:42)
    at fr.atexo.signature.pades.applet.SignaturePadesApplet$3.doInBackground(SignaturePadesApplet.java:276)
    at fr.atexo.signature.pades.applet.SignaturePadesApplet$3.doInBackground(SignaturePadesApplet.java:268)
    at javax.swing.SwingWorker$1.call(SwingWorker.java:277)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at javax.swing.SwingWorker.run(SwingWorker.java:316)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)


    Thanks in advance,
    Louis

    ps:
    My applet is signed

    ReplyDelete