I want to retrieve certificate with password from personal my store by java programming.
I found some code of retrieving certificate but it shows all certificates. These certificates shown data didn't need to open with these related password.
I do not want to these style of showing certificate. I want to write the code format type is- choose certificate I want and I add password of this certificate on the browser and then show of this certificate information.
KeyStore ks = KeyStore.getInstance("Windows-MY");
ks.load(null, null) ;
Enumeration en = ks.aliases() ;
while (en.hasMoreElements()) {
String aliasKey = (String)en.nextElement() ;
Certificate c = ks.getCertificate(aliasKey) ;
System.out.println("---> alias : " + aliasKey) ;
if (ks.isKeyEntry(aliasKey)) {
Certificate[] chain = ks.getCertificateChain(aliasKey);
System.out.println("---> chain length: " + chain.length);
X509Certificate Cert = null;
for (Certificate cert: chain) {
System.out.println(cert);
}
}
}
How to repair this code? And I found some C# code for accessing certificate. I wanna also use just like this by java program. How to convert the following C# code to java code?
Access certificate by C#
X509Store store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection col = store.Certificates.Find(X509FindType.FindBySerialNumber, "{serial number no space}", true);
//service is the webservice that need to //be authenticated using X509 certificate
TestWebService service = new TestWebService();
//Note, we should find the certificate from the the
//root certificate store on local machine if the
//certificate is imported correctly and the serial
//number is correct
if (col.Count == 1)
{
//all we need to do is to add the certificate
//after that we can use the webservice as usual
service.ClientCertificates.Add(col[0]);
service.Test();
}
The password is not certificate specific. The password is for the keyestore. Its similar to the database where in the password is for a schema and not individual tables.
To answer other question of retrieving on a single certificate, for that you would need to know the alias beforehand and use that alias to retrieve the certificate.
in your code it would be ks.getCertifcate("alias")
Related
I know what a certificate chain is. In java when working with KeyStore objects we can add certificates and private keys to a keystore object.
for that we do:
KeyStore sourceKeystore = KeyStore.getInstance("jks");
try (InputStream stream = new BufferedInputStream(Files.newInputStream(sourceKeystorePath))) {
sourceKeystore.load(stream, sourceKeystorePassword);
}
KeyStore destKeystore = KeyStore.getInstance("jks");
destKeystore.load(null, destKeystorePassword);
Enumeration<String> aliasList = sourceKeystore.aliases();
while (aliasList.hasMoreElements()) {
String alias = aliasList.nextElement();
destKeystore.setCertificateEntry(alias, sourceKeystore.getCertificate(alias));
if(sourceKeystore.isKeyEntry(alias)) {
System.out.println(alias + " : is private key");
Key key = sourceKeystore.getKey(alias, "secret".toCharArray());
Certificate[] chain = new Certificate[1];
chain[0] = sourceKeystore.getCertificate(alias);
destKeystore.setKeyEntry(alias, key, "secret".toCharArray(), chain);
}
}
try (OutputStream stream = new BufferedOutputStream(Files.newOutputStream(destKeystorePath))) {
destKeystore.store(stream, destKeystorePassword);
}
What I want to undertstand is destKeystore.setKeyEntry(). When I give a cert chain as a parameter in this can I give an array of certs like this?
[rootCert, interCert, mainCert]
[mainCert, interCert, rootCert]
[mainCert]
First Question: what does these various ways of setting the chain mean?
Second question: Also if I have a JKS file. How do I find this exact value of certificate chain and in which order the certificate chain was set for a private key in this KeyStore? basically what I mean is I want to find out what was the Certificate[] parameter passed to KeyStore.setKeyEntry() in that JKS file
First, the basics of how the certificate chain is formed.
When you initially create a key pair by any means (keytool, openssl, etc,.), it basically consists of a private key associated with its self-signed certificate, where the self-signed certificate contains the public key. And then a PKCS#10 (certificate signing request) is created out of the key-pair, which is basically some identity information about the owner of the private key + public key, put together and signed by the private key. This CSR will be sent to a Certificate Authority to get signed certificate back. The CA signs it and responds with a certificate chain. This received certificate chain is then updated to the initially created private key, replacing the old self-signed certificate. Now, we call this key pair a signed key pair, it is not self-signed any more.
Now understanding what the CA sent. Basically a certificate chain sent by the CA looks like this:
CA Certificate (self-signed)
|
|__ 2. Sub CA Certificate (signed by the above CA)
|
|__ 1. Sub-sub CA Certificate (if any) (signed by the above Sub CA)
|
|__ 0. End Entity Certificate (your certificate, signed by the above cert)
If you look at the indexes of the certificates, they tell the following:
The most important certificate is the first certificate (aka, the user/peer certificate)
The least important certificate is the last certificate (aka, the CA certificate)
In coding terminology, the first (zeroth) element of the certificate array is the user certificate, and the last element of the certificate array is the CA certificate. Which means, the matching public key that belongs to your private key can be found in the first certificate.
99% of the time you don't have to deal with the order of the certificate chain yourself. When the CA responds with a certificate chain, it is usually in the correct order. All you have to do, is to update the certificate chain to your private key.
Now the answers to your questions:
Since you are in the java world, the first order of certificates is considered backwards (incorrect). The second option is correct. The third option is correct as well, but it is advisable to always include the entire certificate chain if you have it.
In you code where you are doing:
Certificate[] chain = new Certificate[1];
chain[0] = sourceKeystore.getCertificate(alias);
destKeystore.setKeyEntry(alias, key, "secret".toCharArray(), chain);
there is also a method available to return you the entire certificate chain that is associated with the private key getCertificateChain(). Where you can simple do:
Certificate[] chain = sourceKeystore.getCertificateChain(alias);
destKeystore.setKeyEntry(alias, key, "secret".toCharArray(), chain);
The order in which the getCertificateChain() returns the array is the way it was set in the first place.
We're trying to use SunMSCAPI to retrieve a certificate from the Windows certificate store. I've created a very simple example that loads the keystore and lists the available aliases. However, the code doesn't list anything, even though I see two personal certificates in the keystore.
On my own system it works fine by the way, but on the actual application server we will be using it doesn't list anything.
Below is the code I'm using
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance("Windows-MY");
ks.load(null, null);
Enumeration<String> aliases = ks.aliases();
System.out.println("Listing aliases " + ks.size());
while (aliases.hasMoreElements())
{
String ka = aliases.nextElement();
System.out.println(ka + " " + ks.isKeyEntry(ka));
}
And a screenshot of the certificate store on the application server. As you can see, I expected two aliases to be listed (but perhaps I'm looking in the wrong location?):
You are seeing the computer certificates, not user certificates. Windows-MY keystore only can use the personal user certificates.
You can explore the personal certificates using Manage user certificates (certmgr )from control panel instead of Manage computer certificates (certIm)
I´m trying to read out the certificate of an etoken. I´ve followed the answer from Keystore from digital signature e-token using java. It´s giving me the certificates installed in the token but after that the token isn´t reachable anymore. Did somebody got something similar while accessing a token?
// Create instance of SunPKCS11 provider
String pkcs11Config = "name=eToken\nlibrary=C:\\path\\to\\your\\pkcs11.dll";
java.io.ByteArrayInputStream pkcs11ConfigStream = new java.io.ByteArrayInputStream(pkcs11Config.getBytes());
sun.security.pkcs11.SunPKCS11 providerPKCS11 = new sun.security.pkcs11.SunPKCS11(pkcs11ConfigStream);
java.security.Security.addProvider(providerPKCS11); // Get provider KeyStore and login with PIN String pin = "11111111";
java.security.KeyStore keyStore = java.security.KeyStore.getInstance("PKCS11", providerPKCS11);
keyStore.load(null, pin.toCharArray()); // Enumerate items (certificates and private keys) in the KeyStore
java.util.Enumeration<String> aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
System.out.println(alias);
}
The problem persists, after plugging out/in the token is reachable again, but after running the code, the token seems to be locked again. OS Win2k8 Server.
Finally got this clear. After disconnecting other USB devices the Token responds as usual.
The Token should be plugged in to a fully powered port. Best on a separate Host- Bus.
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 6 years ago.
I have hit a dead end using the OpenSAML support for preparing a SAML Payload to accomplish a SSO transaction with another service that I am working with. I receive a NullPointerException that is thrown after I use the SecurityHelper.prepareSignatureParams() routine. I have a Stacktrace, but it wold be pretty ugly to append.
Let me first say what I was able to do...
For the purposes of learning the technology and to make sure it would work, I was able to successfully build a SAML payload, sign it using a Certificate and a Private Key that was stored in a Java Key Store file that I created locally on my workstation using the Keytool program with the -genkeypair option.
As I understand things, my JKS file contains a Self Signed Certificate and a Private Key. I was able to open the JKS file, gather the Certificate and the Private Key to build a Signing Certificate. The Signing Certificate was used to sign the SAML Payload that I created You'll see how I did this if you look at the code samples that I'll append.
What isn't working...
I want to use the same SAML support to sign my SAML Payload using a Trusted Certificate that I have for my website that I received from GoDaddy. To do this, I installed the Trusted Certificate into my webserver's keystore at: '\Program Files\Java\jre1.8.0_102\lib\security\cacerts'. I understand that the cacerts file is the KeyStore for our webserver. I installed the Trusted Certificate using the Keytool -importcert command. One big difference is that the Trusted Certificate DOESN'T have a Private Key. So when preparing the Signing Certificate using the Open SAML support, I am not able to add a Private Key to the Credential object (because I don't have one).
When attempting the above for the Trusted Certificate, I am able to get to the part where I am preparing the Signature Parms (SecurityHelper.prepareSignatureParams()). That's where I get the Null Pointer.
If you could take a look at the code that I am using. I am including the code (that signs my payload successfully) that reads from the local JKS file and also the code (that gets the Null Pointer Exception) when I try to using the Trusted Certificate on the server (both cases). There's not much different between the two cases:
// Signing process using OpenSAML
// Get instance of an OpenSAML 'KeyStore' object...
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
// Read KeyStore as File Input Stream. This is either the local JKS
// file or the server's cacerts file.
File ksFile = new File(keyStoreFileName);
// Open an Input Stream with the Key Store File
FileInputStream ksfInputStream = new FileInputStream(ksFile);
// Load KeyStore. The keyStorePassord is the password assigned to the keystore, Usually 'changeit'
// before being changed.
keyStore.load(ksfInputStream, keyStorePassword);
// Close InputFileStream. No longer needed.
ksfInputStream.close();
// Used to get Entry objects from the Key Store
KeyStore.PrivateKeyEntry pkEntry = null;
KeyStore.TrustedCertificateEntry tcEntry = null;
PrivateKey pk = null;
X509Certificate x509Certificate = null;
BasicX509Credential credential = null;
// The Java Key Store specific code...
// Get Key Entry From the Key Store. CertificateAliasName identifies the
// Entry in the KeyStore. KeyPassword is assigned to the Private Key.
pkEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(certificateAliasName, new KeyStore.PasswordProtection(keyPassword));
// Get the Private Key from the Entry
pk = pkEntry.getPrivateKey();
// Get the Certificate from the Entry
x509Certificate = (X509Certificate) pkEntry.getCertificate();
// Create the Credential. Assign the X509Certificate and the Privatekey
credential = new BasicX509Credential();
credential.setEntityCertificate(x509Certificate);
credential.setPrivateKey(pk);
// The Trusted Certificate specific code...
// Accessing a Certificate that was issued from a trusted source - like GoDaddy.com
//
// Get Certificate Entry From the Key Store. CertificateAliasName identifies the Entry in the KeyStore.
// There is NO password as there is no Private Key associate with this Certificate
tcEntry = (TrustedCertificateEntry) keyStore.getEntry(certificateAliasName, null);
// Get the Certificate from the Entry
x509Certificate = (X509Certificate) tcEntry.getTrustedCertificate();
// Create the Credential. There is no Provate Ley to assign into the Credential
credential = new BasicX509Credential();
credential.setEntityCertificate(x509Certificate);
// Back to code that is not specific to either method...
//
// Assign the X509Credential object into a Credential Object. The BasicX509Credential object
// that has a Certificate and a Private Key OR just a Certificate added to it is now saved as a
// Cendential object.
Credential signingCredential = credential;
// Use the OpenSAML builder to create a signature object.
Signature signingSignature = (Signature) Configuration.getBuilderFactory().getBuilder(Signature.DEFAULT_ELEMENT_NAME).build Object(Signature.DEFAULT_ELEMENT_NAME);
// Set the previously created signing credential
signingSignature.setSigningCredential(signingCredential);
// Get a Global Security Configuration object.
SecurityConfiguration secConfig = Configuration.getGlobalSecurityConfiguration();
// KeyInfoGenerator. Not sure what this is, but the example I am working from shows
// this being passed as null.
String keyInfoGeneratorProfile = "XMLSignature";
// Prepare the Signature Parameters.
//
// This works fine for the JKS version of the KeyStore, but gets a Null Pointer exception when I run to the cacerts file.
SecurityHelper.prepareSignatureParams(signingSignature, signingCredential, secConfig, keyInfoGeneratorProfile <or null>);
// I need to set into the SigningSignature object the signing algorithm. This is required when using the TrustedCertificate
signingSignature.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256);
// This is my code that builds a SAML Response. The SAML Payload contains data
// about the SSO session that I will be creating...
Response samlResponse = createSamlResponse.buildSamlResponseMessage();
// Sign the Response using the Certificate that was created earlier
samlResponse.setSignature(signingSignature);
// Get the marshaller factory to marshall the SamlResponse
MarshallerFactory marshallerFactory = Configuration.getMarshallerFactory();
Marshaller responseMarshaller = marshallerFactory.getMarshaller(samlResponse);
// Marshall the Response
Element responseElement = responseElement = responseMarshaller.marshall(samlResponse);
// Sign the Object...
Signer.signObject(signingSignature);
NOTE: My attempt to sign a SAML Payload was modeled after an OPENSAML example that I found here: https://narendrakadali.wordpress.com/2011/06/05/sign-assertion-using-opensaml/
Hoping that someone can show me the error of my ways or what I am missing.
Thanks for any suggestions.
EDIT (01/26/2016)
I was able to get past the NULL pointer I was receiving while preparing the Signature Params (SecurityHelper.prepareSignatureParams()). Code changes included updating my xmlsec.jar file to version 2.0.8 (xmlsec-2.0.8.jar) and I explicitly setting the signature algorithm to SHA256 when using the Trusted Certificate (from GoDaddy). See my code example for the use of:
signingSignature.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256);
The above changes allows the SAML payload to be built and sent to the connection endpoint.
However, I am still not establishing the SSO connection to my endpoint.
Here's what I see happening:
During processing while the SAML payload is being constructed and specifically, the SAML payload's Signature is being signed:
Signer.signObject(signature);
I get an an error message from SAML:
ERROR: org.opensaml.xml.signature.Signer - An error occured computing the digital signature
The stack trace (just the ending portion):
org.apache.xml.security.signature.XMLSignatureException: Sorry, you supplied the wrong key type for this operation! You supplied a null but a java.security.PrivateKey is needed.
at org.apache.xml.security.algorithms.implementations.SignatureBaseRSA.engineInitSign(SignatureBaseRSA.java:149)
at org.apache.xml.security.algorithms.implementations.SignatureBaseRSA.engineInitSign(SignatureBaseRSA.java:165)
at org.apache.xml.security.algorithms.SignatureAlgorithm.initSign(SignatureAlgorithm.java:238)
at org.apache.xml.security.signature.XMLSignature.sign(XMLSignature.java:631)
at org.opensaml.xml.signature.Signer.signObject(Signer.java:77)
I searched the error messages, but I am not coming up with much.
I don't understand the root of the error message - That the wrong key type was supplied (null) and that OpenSAML seems to be expecting a java.Security.PrivateKey.
When using the Trusted Certificate, I don't have a Private Key, Correct? How would I be able to provide a Private Key? In the case of the Trusted Certificate I read a Trusted Certificate (TrustedCertificateEntry) from the KeyStore. The TrustedCertificateEntry object allows me to access the Certificate, but there's no method for obtaining a Private Key (as well there shouldn't be).
However, when I use my Self Signed Certificate to perform the signing operation, I understand that I do have both the Certificate (the Public Key) and the Private Key contained in the JKS file (the KeyStore). I think that's why when I read from the JKS file, I am able to read a Private Key Entry (KeyStore.PrivateKeyEntry) that has methods for accessing both the Public Key (the Certificate) and the Private Key.
What am I missing about the Trusted Certificate case? The OpenSAML support seems to be expecting a Private key to be able to compute the Signature.
In the case of the Trusted Certificate, is there a way to package the original Private Key into my Key Store (along with the Trusted Certificate)? I am not sure if this is what is normally done or even possible.
Hopefully some guidance as to what I am doing here, Please!
EDIT (01/26/2017) - 2 to provide additional detail.
I'll share a portion of the SAML payload that gets sent...
In the case of the Self Signed Certificate, I see a SignatureValue tag and a X509Certificate tag. Both have binary data included within the begin and end of the tag.
In the case of the Trusted Certificate, I've got an empty Signature Value tag that looks like:
<ds:SignatureValue/>
The Certificate tag is still present and contains the certificate bytes.
So, looking at the error I see from OpenSAML, it is more obvious that it can't compute a Signature using the data that is available in the Trusted Certificate.
Ok, this quite a long question. As I understand the root of the problem is the message "Sorry, you supplied the wrong key type for this operation! You supplied a null but a java.security.PrivateKey is needed." You are trying to sign a message using a public key. This is not possible. Just looking logically on it, signing using a public key would not provide any proof that the signer is intended as it is available to everyone.
What you need to do is sign using a private key. in your case you have generated a public and private key on you computer, then sent CSR to the CA and recieved a certificate signed by the CA.
You should use the privat key from you local computer to sign the message and send the CA signed certificate to the recipient so they can use it to confirm your signature.
In this blog post of mine I explain how to obtain credentials, including the private key from a Java keystore.
I need to build a certificate chain on Windows, from an X.509 smart card cert through one or more intermediate CAs to a root CA. That's easy when the CA certs are in a JKS keystore, but I need to use the Windows keystores as well.
I can get the root CA cert from "Windows-ROOT", but I can't get to the "Intermediate Certification Authorities" keystore.
Has anyone done this?
Thanks!
The SunMSCAPI Cryptographic provider does only support two keystores: Windows-MY (personal certificate store) and Windows-ROOT (trusted authorities certificate store), thus I don't thinks it is possible to directly access to other windows certificate stores. However it may not be necessart since it seems that the Windows-MY keystore is able to build certificate chains with the certificates from other stores.
Here is a code snippet I use to test it:
KeyStore ks = KeyStore.getInstance("Windows-MY");
ks.load(null, null) ;
Enumeration en = ks.aliases() ;
while (en.hasMoreElements()) {
String aliasKey = (String)en.nextElement() ;
Certificate c = ks.getCertificate(aliasKey) ;
System.out.println("---> alias : " + aliasKey) ;
if (ks.isKeyEntry(aliasKey)) {
Certificate[] chain = ks.getCertificateChain(aliasKey);
System.out.println("---> chain length: " + chain.length);
for (Certificate cert: chain) {
System.out.println(cert);
}
}
If I add a single certificate with private key in the personal certificate store the chain length is 1. After adding the CA in the intermediate CA certificate store the I launch the program a second time and the chain length is now 2.
UPDATE (April, 2nd)
It is possible to programmatically add certificates in the Windows-MY and Windows-ROOT keystore with some limitations:
when adding a certificate in the Windows-ROOT the user is prompted for confirmation
all certificate added in the Windows-MY keystore is a TrustedCertificateEntry (from the keystore point of view, not the Windows point of view). The keystore seems to build the longest possible chain with all available certificates.
the certifcates with no associated private key are not visible in the Windows certificate store browser but it is possible to programmatically delete them.
Adding a certificate in a keystore is straightforward:
Certificate c = CertificateFactory.getInstance("X.509").generateCertificate(new FileInputStream("C:/Users/me/Downloads/myca.crt"));
KeyStore.TrustedCertificateEntry entry = new KeyStore.TrustedCertificateEntry(c);
ks.setEntry("CA1", entry , null);
Jcs had the answer, but I want to show some pseudocode so:
// load the Windows keystore
KeyStore winKeystore = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
winKeystore.load(null, null);
// add the user's smart card cert to the keystore
winKeystore.setCertificateEntry(myAlias, userCertificate);
// build the cert chain! this will include intermediate CAs
Certificate[] chain = winKeystore.getCertificateChain(myAlias);
Windows cert chains aren't validated as they're built, but now you can do the usual thing of creating a CertPath and PKIXParameters and using them to validate the chain.
CertPathValidator certPathValidator = CertPathValidator.getInstance(CertPathValidator.getDefaultType());
certPathValidator.validate(certPath, params);