I am inserting a client certificate into my servertruststore using following code
FileInputStream fileInputStream = new FileInputStream( "c:/server.jks" );
keyStore.load( fileInputStream, "keystore".toCharArray() );
fileInputStream.close();
keyStore.setCertificateEntry( alias, new X509Certificate( trustedCertificate ) );
FileOutputStream fileOutputStream = new FileOutputStream("c:/server.jks" );
keyStore.store( fileOutputStream, "keystore".toCharArray() );
fileOutputStream.close();
Now i see that certificate is entered into my truststore but the CA's certificate which signed client's certificate is not present in my truststore. So I want to know is there any way we can check whether the certificate of CA is available or not before entering a certificate into keystore?
I guess what you have to do is to verify if the certificate has been issued by a root authority or it has been self-signed. I presume you are using the default java keystore which is cacerts.
I haven't tested the code but I think this may be a solution to your problem:
Code taken and modified from the following link:
How can I get a list of trusted root certificates in Java?
String filename = System.getProperty("java.home") + "/lib/security/cacerts".replace('/', File.separatorChar);
Set<X509Certificate> additionalCerts = new HashSet<X509Certificate>();
FileInputStream is = new FileInputStream(filename);
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
String password = "changeit";
keystore.load(is, password.toCharArray());
// This class retrieves the most-trusted CAs from the keystore
PKIXParameters params = new PKIXParameters(keystore);
// Get the set of trust anchors, which contain the most-trusted CA certificates
Iterator it = params.getTrustAnchors().iterator();
while( it.hasNext() ) {
TrustAnchor ta = (TrustAnchor)it.next();
// Get certificate
X509Certificate cert = ta.getTrustedCert();
additionalCerts.add(cert);
}
Then you may use the following code to pass the client certificate and the Set containing all the root CAs to the verifyCertificate(X509Certificate cert, Set additionalCerts) method of the following code:
http://www.nakov.com/blog/2009/12/01/x509-certificate-validation-in-java-build-and-verify-chain-and-verify-clr-with-bouncy-castle/
Related
I'm trying to get my PKI material using KeyStore API. The content of my keystore is:
My code is:
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(this.getClass().getResourceAsStream(this.boConfiguration.getUiPortalAdminKeyStore()),
this.boConfiguration.getUiPortalAdminKeyPassword().toCharArray()
);
Enumeration<String> aliases = ks.aliases();
while (aliases.hasMoreElements()) {
LOG.debug(aliases.nextElement());
}
Key pK = ks.getKey(
"gestio",
this.boConfiguration.getUiPortalAdminKeyStorePassword().toCharArray()
);
Key pKey = ks.getKey("gestio", this.boConfiguration.getUiPortalAdminKeyStorePassword().toCharArray());
Certificate[] certs = ks.getCertificateChain("gestio");
Certificate cert = ks.getCertificate("gestio");
My problem is that all ks.get* returns me null. However, keystore is not empty. Also, getAlias method returns me an empty enumeration.
Any ideas?
This is the content according keystore explorer:
ACRA set up with standard options:
#ReportsCrashes(
formUri = "https://XXXXXXXXXX.php",
mode = ReportingInteractionMode.TOAST,
resToastText = R.string.str_acra_crash_report_info)
Tried to copy the server certificate to assets and create a custom KeyStore:
try {
KeyStore ksTrust = KeyStore.getInstance("BKS");
InputStream instream = new BufferedInputStream(getAssets().open("keystore.bks"));
ksTrust.load(instream, "ez24get".toCharArray());
ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(this);
configurationBuilder.setKeyStore(ksTrust);
final ACRAConfiguration config = configurationBuilder.build();
ACRA.init(this, config);
} catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException e) {
e.printStackTrace();
}
or another way:
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = new BufferedInputStream(getAssets().open("ssl-cert-snakeoil.pem"));
Certificate ca = cf.generateCertificate(caInput);
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
Unfortunately after hours of tests, still no luck, still getting an exception:
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
Any hints?
EDIT: Created another certificate, with CA:TRUE (standard ssl-cert-snakeoil.pem had CA:FALSE), but still no luck.
EDIT 2: Certificates made as they should be: main CA cert. + server cert., but still the same exception.
#Matthew you will need to use the head of the ACRA's master as it has this https://github.com/ACRA/acra/pull/388 pull request added.
We'll probably cut another release within a week or so.
I've been mixing and matching code, trying to learn by example for using KeyStores.
I have this createKeyStore method:
private static KeyStore createKeyStore(String fileName, String pw) throws Exception
{
File file = new File(fileName);
final KeyStore keyStore = KeyStore.getInstance("JCEKS");
if (file.exists())
{
// .keystore file already exists => load it
keyStore.load(new FileInputStream(file), pw.toCharArray());
}
else
{
// .keystore file not created yet => create it
keyStore.load(null, null);
keyStore.store(new FileOutputStream(fileName), pw.toCharArray());
}
return keyStore;
}`
It seems to work, no errors are thrown.
I am then trying to access the code by:
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(new FileInputStream(keystorePath), pass.toCharArray());
String alias = "alias";
char[] password = pass.toCharArray();
Certificate cert = keystore.getCertificate(alias);
keystore.setCertificateEntry(alias, cert);
// Save the new keystore contents
FileOutputStream out = new FileOutputStream(keystoreFile);
keystore.store(out, password);
out.close();
But my call to keystore.load throws an Invalid Keystore Format exception.
I tried to replace the FileInputStream with null, but it seems to throw an error setting the certificate.
TL;DR: I am only trying to store a few encryption keys in this keystore, but I can't seem to access it correctly.
Thanks for reading!
You have:
final KeyStore keyStore = KeyStore.getInstance("JCEKS");
and
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
Change these so they agree.
This:
Certificate cert = keystore.getCertificate(alias);
keystore.setCertificateEntry(alias, cert);
is pointless. If there wasn't such a certificate in the keystore, it will fail, and if there was, it will just replace it with itself. What's the point exactly?
I tried to replace the FileInputStream with null
I cannot imagine why. There's nothing in the Javadoc that suggests that will work.
If you look at the documentation it says to create an empty keystore call the load() method with null as the file input parameter but not the password parameter. Passing null as the password parameter in your else clause causes null pointer exceptions when loading the keystore from file later.
keystore.load(null, pass.toCharArray());
I'm trying to load a comodo Positive SSL Multi-Site cert into Java's HttpsServer. I'm not getting any errors from the code, but when I try and access the URL in a browser it tells me there is an SSL error. Neither Chrome nor FireFox give any additional information. This cert is working fine in Apache.
Below is the code I am using. I've made it fairly verbose. Does anything stand out as incorrect? I've converted the private key to pkcs8 for importing. The certificate and bundle I'm loading are PEM encoded.
serverHttps = HttpsServer.create(new InetSocketAddress(ports[port_selector]), 0);
SSLContext sslContext = SSLContext.getInstance("TLS");
String alias = "alias";
// Load Certificates
InputStream stream = MyClass.class.getResourceAsStream("/certs/mycert.crt");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate)cf.generateCertificate(stream);
stream.close();
stream = MyClass.class.getResourceAsStream("/certs/bundle.crt");
cf = CertificateFactory.getInstance("X.509");
Collection bundle = cf.generateCertificates(stream);
stream.close();
// Build cert chain
java.security.cert.Certificate[] chain = new Certificate[bundle.size()+1];
Iterator i = bundle.iterator();
int pos = 0;
while (i.hasNext()) {
chain[pos] = (Certificate)i.next();
pos++;
}
chain[chain.length-1] = cert;
// Load private key
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
stream = MyClass.class.getResourceAsStream("/certs/pkcs8_my_key");
PKCS8EncodedKeySpec pkcs8 = new PKCS8EncodedKeySpec(IOUtils.toByteArray(stream));
RSAPrivateKey privKey = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8);
stream.close();
stream = null;
KeyStore ks = KeyStore.getInstance("JKS");
char[] ksPassword = "mypass".toCharArray();
ks.load(null, ksPassword);
ks.setKeyEntry(alias, privKey, ksPassword, chain);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, ksPassword);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ks);
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
// serverHttps.setHttpsConfigurator(new HttpsConfigurator(sslContext));
serverHttps.setHttpsConfigurator ( new HttpsConfigurator( sslContext )
{
#Override
public void configure ( HttpsParameters params )
{
try
{
// initialise the SSL context
SSLContext c = SSLContext.getDefault ();
SSLEngine engine = c.createSSLEngine ();
params.setNeedClientAuth ( false );
params.setCipherSuites ( engine.getEnabledCipherSuites () );
params.setProtocols ( engine.getEnabledProtocols () );
// get the default parameters
SSLParameters defaultSSLParameters = c.getDefaultSSLParameters ();
params.setSSLParameters ( defaultSSLParameters );
}
catch ( Exception ex )
{
System.out.println( "Failed to configure HTTPS server: "+ex.getMessage() );
System.exit(100);
}
}
} );
Your server cert must be chain[0] in the keystore entry.
The remaining certs should be in upward order i.e. root last -- and when you use keytool it puts them in that order -- because JSSE server sends them in the keystore order and SSL/TLS protocol says they should be sent in upward order. However, in my experience (most?) browsers/clients will tolerate the rest of the chain being out of order as long as the server cert is first.
PS: I think everything in your configure overrride is unnecessary. You haven't done anything to make the parameters of your SSLContext different from the default one, and the SSLParameters of the default context are (and override) the CipherSuites and Protocols you just set individually. But I can't easily test.
I have a certificate chain as der encoded byte[][] array to verify. I also have a truststore file.
After I create X509Certificate[] from that byte array[][] and initializing trustmanager, how will I tell to TrustManager to verify that X509Certificate[]? What is the proper way to do it?
Thanks.
Sample code:
int certVerify(byte certChain[][])
{
CertificateFactory cf = CertificateFactory.getInstance("X509");
X509Certificate certx[] = new X509Certificate[10];
for(int i=0;i<certChain.length;i++)
{
certx[i] = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(certChain[i]));
}
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load( new FileInputStream("cacerts.jks"),"123456".toCharArray());
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
}
You'll need to enable OCSP with the necessary system properties, or obtain CRLs for each certificate in the chain, in order to check the revocation status. (Alternatively, you can disable revocation checking, with the attendant risks.)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
List<Certificate> certx = new ArrayList<>(certChain.length);
for (byte[] c : certChain)
certx.add(cf.generateCertificate(new ByteArrayInputStream(c)));
CertPath path = cf.generateCertPath(certx);
CertPathValidator validator = CertPathValidator.getInstance("PKIX");
KeyStore keystore = KeyStore.getInstance("JKS");
try (InputStream is = Files.newInputStream(Paths.get("cacerts.jks"))) {
keystore.load(is, "changeit".toCharArray());
}
Collection<? extends CRL> crls;
try (InputStream is = Files.newInputStream(Paths.get("crls.p7c"))) {
crls = cf.generateCRLs(is);
}
PKIXParameters params = new PKIXParameters(keystore);
CertStore store = CertStore.getInstance("Collection", new CollectionCertStoreParameters(crls));
/* If necessary, specify the certificate policy or other requirements
* with the appropriate params.setXXX() method. */
params.addCertStore(store);
/* Validate will throw an exception on invalid chains. */
PKIXCertPathValidatorResult r = (PKIXCertPathValidatorResult) validator.validate(path, params);
There is some good information on how to implement one here
Or you could use the BouncyCastle APIs as explained here