1
votes

I'm actually developing an app that allows users to sign with their smartcard. On Windows OS, I have this :

ArrayList<String> lstErrors = new ArrayList<String>();
String AliasToUse = "test";
String strToSign = "My Clean String";

String strSigned = AccessController.doPrivileged(new PrivilegedAction<String>()
        {
            public String run()
            {
                KeyStore ks = null;
                ks = KeyStore.getInstance("Windows-MY");
                ks.load(null, null);

                try
                {
                    Enumeration<String> en = ks.aliases();

                    if (en.hasMoreElements() == false)
                    {
                        lstErrors.add("No Certificate found");
                        return null;
                    }

                    ArrayList<String> lstAlias = Collections.list(en);

                    lstErrors.add(lstAlias.size() + " elements found");

                    for (String aliasKey : lstAlias)
                    {

                        if(!aliasKey.equalsIgnoreCase(AliasToUse))
                        {
                            continue;
                        }

                        Provider p = ks.getProvider();

                        Signature sig = Signature.getInstance("SHA256withRSA", p);

                        PrivateKey key = (PrivateKey) ks.getKey(aliasKey, "1234".toCharArray());

                        if (key == null)
                        {
                            lstErrors.add("The Private Key could not be instanciated");
                            continue;
                        } 

                        sig.initSign(key);
                        String strBase64Decoded = Base64Coder.decodeString(strToSign);
                        byte[] btToSign = strBase64Decoded.getBytes(Charset.forName("UTF-8"));
                        sig.update(btToSign);
                        byte[] res = sig.sign();

                        return Base64Coder.encodeBase64String(res);
                    }

                } catch (Exception e)
                {
                    lstErrors.add("Error signing : " + e.getMessage());
                    return null;
                }

                return null;
            }
        }

This code works fine, no problem. When I try to do the same with Apple, I'm trying this :

ks = KeyStore.getInstance("KeyChainStore");

This allows me to get all the certificates but when I try to sign my data, I get the following error :

no such algorithm: SHA256WithRSA for provider Apple

It happens on the following line :

Signature sig = Signature.getInstance("SHA256withRSA", p);

I tried "SHA-256" or even "SHA-1" but the error still remains.

How can I use the KeyChainStore to sign like I do in Windows Certificate Store ?

Thanks in advance.

Addendum

I tried another method to gather more informations about each alias on my KeyChainStore, and know if the entry contains a certificate and/or a private key :

public void GetInformationsFromKeyChainStore() {

        AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
            public Boolean run() {

                try {
                    KeyStore keyStore = KeyStore.getInstance("KeychainStore",
                            "Apple");
                    keyStore.load(null, null);

                    System.out
                            .println("List of the aliases present in the keystore ("
                                    + keyStore.getType() + ")");
                    Enumeration<String> aliases = keyStore.aliases();

                    ArrayList<String> lstAlias = Collections.list(aliases);

                    for (String alias : lstAlias) {

                        System.out.println(" - Alias: " + alias);
                        System.out.println("     isKeyEntry? "
                                + keyStore.isKeyEntry(alias));
                        System.out.println("     isCertificateEntry?"
                                + keyStore.isCertificateEntry(alias));
                        if (keyStore.isKeyEntry(alias)) {
                            try {
                                PrivateKey key = (PrivateKey) keyStore.getKey(
                                        alias, "-".toCharArray());
                                System.out
                                        .println("    Key loaded successfully. Type: "
                                                + key.getFormat());
                            } catch (RuntimeException e) {
                                System.out.println("    Key failed to load ("
                                        + e.getMessage() + ")");
                            }
                            Certificate certificate = keyStore
                                    .getCertificate(alias);
                            String subject = "";
                            if ((certificate != null)
                                    && (certificate instanceof X509Certificate)) {
                                subject = ((X509Certificate) certificate)
                                        .getSubjectX500Principal().getName();
                            }
                            System.out.println("  Does getCertificate work on this key entry? "
                                    + ((keyStore.getCertificate(alias) != null) ? "Yes "
                                            + subject
                                            : "No"));
                        }
                        if (keyStore.isCertificateEntry(alias)) {
                            Certificate certificate = keyStore
                                    .getCertificate(alias);

                            if (certificate instanceof X509Certificate) {
                                X509Certificate x509certificate = (X509Certificate) certificate;
                                System.out.println("    Subject DN: "
                                        + x509certificate
                                                .getSubjectX500Principal()
                                                .getName());
                            } else {
                                System.out
                                        .println("    Unknown format certificate.");
                            }
                            System.out
                                    .println("  Does getKey work on this certificate entry as well? "
                                            + (keyStore.getKey(alias,
                                                    "-".toCharArray()) != null));

                        }
                    }

                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    return false;
                }
                return true;

            }
        });

    }

But even this method call, all my entries seem to be certificates and don't contain any private key.

The problem is that for some certificates, there is a private key (I can also view it from my KeyChainStore).

1
Hi, did you figure anything out for this? I am having the same problem where keyStore.isKeyEntry(alias) is incorrectly returning false on Mac - making it look like a certificate.Amber

1 Answers

0
votes

Try getting the Signature object via the default provider instead of your "Apple" provider.

In other words, remove the ", p" from the method call, and do this instead:

Signature sig = Signature.getInstance("SHA256withRSA");