This discussion is archived
10 Replies Latest reply: Sep 24, 2012 1:29 AM by 944800 RSS

SunMSCAPI Access was denied because of a security violation.

944800 Newbie
Currently Being Moderated
In a signed applet with the following source:
public class AppletTest extends JApplet {

    @Override
    public void init() {
        log("init() OS="+System.getProperty("os.name")+", Java="+System.getProperty("java.version"));
        Container content = getContentPane();        JTextArea t = new JTextArea("Hello!");        t.setLineWrap(true);        content.add(t);

        KeyStore aKeyStore;
        PrivateKey privateKey;
        X509Certificate certificate;
        String alias = "Chave de Assinatura";
        //String alias = "Chave de Autenticação";
        char[] password = "xxxx".toCharArray();
        byte[] data = "Data to be signed!".getBytes();
        String aliasCode = null;

        try {
            aKeyStore = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
            log("ks provider=" + aKeyStore.getProvider().getInfo());
            aKeyStore.load(null);
            Enumeration<String> aliases = aKeyStore.aliases();
            while (aliases.hasMoreElements()) {
                String a = aliases.nextElement(); log("keystore alias: " + a);
                if (alias.equals(a)) {
                    log(" selected " + a);
                    aliasCode = a;
                }
            }

            final PrivateKey key = (PrivateKey) aKeyStore.getKey(alias, password);
            final java.security.cert.Certificate[] chain = aKeyStore.getCertificateChain(alias);

            final Signature sign = Signature.getInstance("SHA1withRSA");
            sign.initSign(key);
            sign.update(data);

            byte[] ba = sign.sign();
            display("Sig0:",ba);
                        
            privateKey = (PrivateKey) aKeyStore.getKey(aliasCode, password);
            certificate = (X509Certificate) aKeyStore.getCertificate(aliasCode);
            //privateKey = key;
            //certificate = (X509Certificate)chain[0];
            aKeyStore.load(null); // Why do I need this ?
            
            Signature signature = sign;
            //Signature signature = Signature.getInstance("SHA1withRSA");
            //signature.initSign(privateKey);
            signature.update(data);

            // Error occurs when signing
            byte[] sig = signature.sign(); // STOPS HERE
            display("Sig1:", ba);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void display(String aLabel, byte[] ba) {
        StringBuffer sb = new StringBuffer();
        for (byte b : ba) {
            sb.append(String.format("%02x", b)).append(" ");
        }
        log(aLabel+" "+sb);
    }
    public static void log(String aMsg) {
        System.out.println(aMsg);
    }
}
the console displays the following exception (line marked with "STOPS HERE"):
init() OS=Windows 7 Java=1.7.0_07
...
ks provider=Sun's Microsoft Crypto API provider
keystore alias: Chave de Autenticação
keystore alias: Chave de Assinatura
 selected Chave de Assinatura
...
Sig0: 3a 4b 19...
java.security.SignatureException: Access was denied because of a security violation.
     at sun.security.mscapi.RSASignature.signHash(Native Method)
     at sun.security.mscapi.RSASignature.engineSign(RSASignature.java:390)
     at java.security.Signature$Delegate.engineSign(Unknown Source)
     at java.security.Signature.sign(Unknown Source)
     at org.itij.applet.AppletTest.init(AppletTest.java:81)
     at com.sun.deploy.uitoolkit.impl.awt.AWTAppletAdapter.init(Unknown Source)
     at sun.plugin2.applet.Plugin2Manager$AppletExecutionRunnable.run(Unknown Source)
     at java.lang.Thread.run(Unknown Source)
The code was supposed to perform 2 signatures, but fails on the second signature.
The certificates are being stored in a smartcard.

The problems occurs every once in a while (and I don't know exactly what causes it or what makes it go away).

Any ideia what is causing it ?

Thanx for any help.

Regards,
Joao
  • 1. Re: SunMSCAPI Access was denied because of a security violation.
    sabre150 Expert
    Currently Being Moderated
    I don't understand why the first signature should be generated OK but not the second but I'm pretty sure I can see one problem area. The private key obtained from the "Windows-MY" keystore can only be used to sign using a Signature object obtained from the "SunMSCAPI" provider but you use it with a Signature object obtained from the default provider. I would expect to see :-
        final Signature sign = Signature.getInstance("SHA1withRSA",  "SunMSCAPI");
    Note - the public key obtained from the "SunMSCAPI" keystore can be used to verify the signature using a Signature object from any provider that supports "SHA1withRSA".
  • 2. Re: SunMSCAPI Access was denied because of a security violation.
    944800 Newbie
    Currently Being Moderated
    I have applied the change you mentioned, but the problem persists exactly the same way as I reported originally.

    But thank your for the help attempt anyway.

    Joao
  • 3. Re: SunMSCAPI Access was denied because of a security violation.
    sabre150 Expert
    Currently Being Moderated
    I have never tried re-using a Signature object. I wouldn't expect there to be a problem but, just in case Signature objects are not re-usable, have you tried using a new Signature object to generate the second signature.
  • 4. Re: SunMSCAPI Access was denied because of a security violation.
    944800 Newbie
    Currently Being Moderated
    Thanks for the suggestion. I tryed it again (just in case) - the changed code looks like this:
    ...
                final PrivateKey key = (PrivateKey) aKeyStore.getKey(alias, password);
                final java.security.cert.Certificate[] chain = aKeyStore.getCertificateChain(alias);
    
                final Signature sign = Signature.getInstance("SHA1withRSA",aKeyStore.getProvider());
                sign.initSign(key);
                sign.update(data);
    
                byte[] ba = sign.sign();
                display("Sig0:",ba);
                            
                privateKey = (PrivateKey) aKeyStore.getKey(aliasCode, password);
                certificate = (X509Certificate) aKeyStore.getCertificate(aliasCode);
                aKeyStore.load(null); // without this, I get more errors...why ?
                
                //Signature signature = sign;
                Signature signature = Signature.getInstance("SHA1withRSA",aKeyStore.getProvider());
                signature.initSign(privateKey);
                signature.update(data);
    
                // Error occurs when signing
                byte[] sig = signature.sign(); // sometimes breaks here with java.security.SignatureException: Access was denied because of a security violation.
                display("Sig1:", sig);
    ...
    Now, it worked once, then never worked again. Sometimes it works, sometimes gives the same exception (same stack trace) at the second .sign() invocation.
    I feel like I am changing ghosts... I cannot just say that the Windows SmartCard drivers are broken as there are other native Windows uses that work (although not like this 2-signatures-in-a-row) - and saying that would just be as helpful as saying that the Java stack is broken.
  • 5. Re: SunMSCAPI Access was denied because of a security violation.
    sabre150 Expert
    Currently Being Moderated
    If I were doing this I would create a method that takes as input the data to be signed and returns the signature. This could make sure that every component used in the signature generation is created anew each time it is needed. This would also allow one to create a simple SSCCE that could be used when raising a bug report.
  • 6. Re: SunMSCAPI Access was denied because of a security violation.
    944800 Newbie
    Currently Being Moderated
    Could you please give me some pointers/guidelines/link to examples on how to refactor de code for such SSCE (?) bug report purpose ?
    (I think I did not understood this last remark. The code in the real-project is already isolated in methods and classes. This was the almost the shortest listing I could write to reproduce the problem - within a signed applet- and with comments ilustrating several other possibilites that I have attempted (but that always fail). Do you think it would help to re-write it for a command-line class with a main() method project ?)
  • 7. Re: SunMSCAPI Access was denied because of a security violation.
    sabre150 Expert
    Currently Being Moderated
    As it stands it is difficult using your current code to isolate the problem because objects and references are being re-used. Also, you say the code is part of an Applet so setting up a test environment is significantly more difficult than setting up an simple application. An SSCCE (Google will help you with what this is) as a Java application that concentrates the actual signing into one method that can be called many time will make easy to find the conditions under which the signing fails.

    If, using your SSCCE, you can show that calling the method once works but calling twice or more doesn't then you have the starting point for submitting a bug report to Oracle. If your application SSCCE does not exhibit the problem then the security exception could be exhibited only when using an Applet. At this point you will need to create a signed Applet version of the SSCCE.

    Without these SSCCE you can demonstrate nothing.
  • 8. Re: SunMSCAPI Access was denied because of a security violation.
    944800 Newbie
    Currently Being Moderated
    Just to post an update, that, using the above code in a command-line main() application, the problem persists in the same manner.
    As such, the error "java.security.SignatureException: Access was denied because of a security violation." appears not to be applet-related.
  • 9. Re: SunMSCAPI Access was denied because of a security violation.
    944800 Newbie
    Currently Being Moderated
    Regarding the SSCCE sugestion, I guess that this is the smallest it can get is:
    import java.security.*;
    public class TestSunMSCAPIReUse {
        public static void main(String[] args) throws Exception {
            System.out.println("init() OS=" + System.getProperty("os.name")+" java="+System.getProperty("java.version"));
            final String alias = "Chave de Assinatura"; // "Joao Luis";
            final byte[] data = "Data to be signed!".getBytes();
            final KeyStore aKeyStore = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
            aKeyStore.load(null);
            final PrivateKey key = (PrivateKey) aKeyStore.getKey(alias, null);
            final Signature sign = Signature.getInstance("SHA1withRSA", aKeyStore.getProvider());
            sign.initSign(key);
            int i = 0;
            do {
                sign.update(data);
                byte[] ba = sign.sign(); // this is line 15
                i++;
                System.out.print("\nSig" + i + ": ");
                for (byte b : ba) {
                    System.out.print(String.format("%02x", b));
                }
            } while (i < 100);
        }
    }
    And the simplest execution example (under Windows) and error stack trace is:
    C:\Users\jpsl>java -classpath g:\TestSunMSCAPI\bin\ TestSunMSCAPIReUse
    init() OS=Windows 7 java=1.7.0_07
    
    Sig1: 3a4b...(seems ok)...
    Exception in thread "main" java.security.SignatureException: Access was denied because of a security violation.
    
            at sun.security.mscapi.RSASignature.signHash(Native Method)
            at sun.security.mscapi.RSASignature.engineSign(RSASignature.java:390)
            at java.security.Signature$Delegate.engineSign(Unknown Source)
            at java.security.Signature.sign(Unknown Source)
            at TestSunMSCAPIReUse.main(TestSunMSCAPIReUse.java:15)
    A few remarks:
    - I cannot provide the smartcard token (the actual drivers are version 1.24.1 for the citizen's ID card - http://www.cartaodecidadao.pt/) for anyone else to test, as it is my own citizen ID card.
    - if I choose (change the alias in the code) to select a self-signed software certificate (not in the smartcard), the code works fine (performs 100 signatures).

    So, it "feels" like a smartcard driver bug.

    So, to summarize my questions to this forum are:

    1 - Can I work around this by I forcing some kind unload/reload/session close/re-open ? (If it works once, there should be a way to reset it to work twice. The changes shown above in post Sep 22, 2012 3:51 PM to create a new Signature object suffer from the same problem).

    2 - How can I report/proove that it is a smartcard driver bug (and not a Java stack bug) ? (PS: I had no suggestions yet on the PKCS11 thread SunPKCS11 sun.security.pkcs11.wrapper.PKCS11Exception: CKR_ARGUMENTS_BAD but I don't know enough about PKCS11 if I am asking non-sense ).

    But I am also open to other suggestions ...
    (And thanks to everyone for all the tips so far).
  • 10. Re: SunMSCAPI Access was denied because of a security violation.
    944800 Newbie
    Currently Being Moderated
    Just to post an update that, adding a
    Thread.sleep(2000);
    between signatures helped to avoid the problem (at least on my computer). (A Thread.sleep(1000); did not help).
    This is being tested on more computers, and if successful, I will mark this thread as answered hoping it helps anyone googling out for the same problem (even if I don't understand what is going on behind the scenes).

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points