Keystore loading all certificates

Asked

Viewed 897 times

0

I’m creating a webservice which connects to the eSocial, requiring mutual authentication.

When I have only one certificate on the machine, no problem at all, but when it has 2+ certificates, I can’t get the user to choose the certificate that made the mutual connection, it simply creates the connection to the first certificate on the list.

I would like the user to choose the certificate that he will perform the connection.

When I give a simple no Keystore, it loads with all certificates

KeyStore ks = KeyStore.getInstance("Windows-MY");
        InputStream io = tokenAladdin();
        try {
            ks.load(null, "@Techne".toCharArray());
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (CertificateException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

I would like to know why the certificate choice dialog does not open.

Someone can help me?

  • I am also working with eSocial, but I am developing in C#/VB.NET. No . NET there is a ready-made method that displays the dialog for the user to choose the desired certificate: > X509certificate2ui.Selectfromcollection I did a quick search and found this solution for Java: https://stackoverflow.com/questions/23080214/windows-security-dialog-for-selecting-a-Certificate-in-java I hope it helps.

2 answers

0

I ended up solving via msm code, but I present a simple combo box, and I get the certificate alias, then I implement only it in a "Key Repository" (Keymanager Array);

 KeyStore ksPrivate = KeyStore.getInstance("JKS");
 KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) ks.getEntry(alias, new KeyStore.PasswordProtection("tEHCNE@".toCharArray()));

 ksPrivate.load(null, null);
 X509Certificate cert = (X509Certificate) keyEntry.getCertificate();
 //keySotre2.setKeyEntry("key1", (Key)keyEntry.getPrivateKey(), "tECHNE@".toCharArray(), certChain);  
 //keySotre2.setEntry(alias, keyEntry, protParam);

 HSKeyManager hsKey = new HSKeyManager(cert, keyEntry.getPrivateKey());  

 KeyManager[] keysManager = new KeyManager[]{hsKey};

Then I just need to set this key repository on the connection

sslContext.init(keysManager, tmf.getTrustManagers(), new SecureRandom());

Hskeymanager object.

import java.net.Socket;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;

import javax.net.ssl.X509KeyManager;

public class HSKeyManager implements X509KeyManager {

    private X509Certificate certificate;  
        private PrivateKey privateKey;  

        public HSKeyManager(X509Certificate certificate, PrivateKey privateKey) {  
            this.certificate = certificate;  
            this.privateKey = privateKey;  
        }  

        public String chooseClientAlias(String[] arg0, Principal[] arg1,  
                Socket arg2) {  
            return certificate.getIssuerDN().getName();  
        }  

        public String chooseServerAlias(String arg0, Principal[] arg1,  
                Socket arg2) {  
            return null;  
        }  

        public X509Certificate[] getCertificateChain(String arg0) {  
            return new X509Certificate[]{certificate};  
        }  

        public String[] getClientAliases(String arg0, Principal[] arg1) {  
            return new String[]{certificate.getIssuerDN().getName()};  
        }  

        public PrivateKey getPrivateKey(String arg0) {  
            return privateKey;  
        }  

        public String[] getServerAliases(String arg0, Principal[] arg1) {  
            return null;  
        } 
}

Then I’ll try your solution

0

user101666, I am also working with eSocial, but I am developing in C#/VB.NET. No . NET there is a ready method that displays the dialog for the user to choose the certificate desired:

X509Certificate2UI.SelectFromCollection

Your code does not open a certificate choice window because you have not written anything to make it happen. Your code:

KeyStore ks = KeyStore.getInstance("Windows-MY");
ks.load(null, "@Techne".toCharArray());

only loads all certificates stored in that Windows repository.

I did a quick search on this feature in Java and found this post on Stackoverflow global:

https://stackoverflow.com/q/23080214/8133067

There user Florian says that this functionality does not exist ready in Java, but that he wrote a solution in Java to display the Windows dialog for choice of certificate. He put the project on Github:

https://github.com/FlorianSW/org.droidwiki.certtest

And to get to that solution, he relied on this other post, by Tech Junkie:

https://stackoverflow.com/a/42088543/8133067

But basically what they did was directly access the function CryptUIDlgSelectCertificateFromStore library Cryptui.dll, windows native:

https://msdn.microsoft.com/en-us/library/windows/desktop/aa380288.aspx

I will replicate here the code posted by the user Tech Junkie, which is easier to post if the links no longer work:

NativeLibrary cryptUI = NativeLibrary.getInstance("Cryptui");
NativeLibrary crypt32 = NativeLibrary.getInstance("Crypt32");

Function functionCertOpenSystemStore = crypt32.getFunction("CertOpenSystemStoreA");
Object[] argsCertOpenSystemStore = new Object[] { 0, "CA"};
HANDLE h = (HANDLE) functionCertOpenSystemStore.invoke(HANDLE.class, argsCertOpenSystemStore);

Function functionCryptUIDlgSelectCertificateFromStore = cryptUI.getFunction("CryptUIDlgSelectCertificateFromStore");
System.out.println(functionCryptUIDlgSelectCertificateFromStore.getName());
Object[] argsCryptUIDlgSelectCertificateFromStore = new Object[] { h, 0, 0, 0, 16, 0, 0};
Pointer ptrCertContext = (Pointer) functionCryptUIDlgSelectCertificateFromStore.invoke(Pointer.class, argsCryptUIDlgSelectCertificateFromStore);

Function functionCertGetNameString = crypt32.getFunction("CertGetNameStringW");
char[] ptrName = new char[128];
Object[] argsCertGetNameString = new Object[] { ptrCertContext, 5, 0, 0, ptrName, 128};
functionCertGetNameString.invoke(argsCertGetNameString);
System.out.println("Selected certificate is " + new String(ptrName));

Function functionCertFreeCertificateContext = crypt32.getFunction("CertFreeCertificateContext");
Object[] argsCertFreeCertificateContext = new Object[] { ptrCertContext};
functionCertFreeCertificateContext.invoke(argsCertFreeCertificateContext);

Function functionCertCloseStore = crypt32.getFunction("CertCloseStore");
Object[] argsCertCloseStore = new Object[] { h, 0};
functionCertCloseStore.invoke(argsCertCloseStore);

I hope it helps.

  • As much as the link may help, your post does not answer the question. In the future you will have enough reputation to comment on the questions and answers.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.