My problem is linked to this topic Calling Java from PLSQL causing oracle.aurora.vm.ReadOnlyObjectException
All of a sudden since today we are getting an error in our Production when a Java code is being executed from PLSQL, note that we have this error sometimes and don't know why, in past by deleting all classes and reloads them solved the issue but this time not :
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
java.version = 1.6.0_71
sonic_Client = 8.6.0
PROCEDURE LOG_AND_SEND_TO_QUEUE_PR(
msg VARCHAR2,
clientID VARCHAR2,
typeMessage VARCHAR2,
providerUrl VARCHAR2,
destination VARCHAR2,
usr VARCHAR2,
pwd VARCHAR2,
isTopic VARCHAR2,
ENABLED_HTTPS_ALGORITHM VARCHAR2 )
AS
LANGUAGE JAVA NAME 'jms.cxmessenger.SonicSender.doSend(java.lang.String, java.lang.String,java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)';
jms.cxmessenger.SecureTrustManager is set by System property used by SonicMQ client.
package jms.cxmessenger;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.List;
import java.util.NoSuchElementException;
import javax.naming.InvalidNameException;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
public class SecureTrustManager implements X509TrustManager {
private static final X509Certificate[] EMPTY_X509CERTIFICATE_ARRAY = new X509Certificate[0];
private CustomDefaultHostnameVerifier verifier = new CustomDefaultHostnameVerifier();
private TrustManager[] trustManagers;
{
try {
TrustManagerFactory trustManagerFactory = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init((KeyStore) null);
trustManagers = trustManagerFactory.getTrustManagers();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void check(X509Certificate[] chain, String authType) throws CertificateException {
boolean trusted = false;
if (chain.length > 0) {
for (TrustManager trustManager : trustManagers) {
try {
if (trustManager instanceof X509TrustManager) {
/* line 43 */ ((X509TrustManager) trustManager).checkServerTrusted(chain, authType);//line 43
trusted = true;
}
} catch (CertificateException e) {
}
}
}
if (!trusted && !Boolean.getBoolean("DEACTIVATE_HOSTNAME_VALIDATION")) {
checkCN(chain);
}
}
public X509Certificate[] getValidCertificates(X509Certificate[] chain, String peerHost) {
return verifier.getValidCertificates(chain, peerHost);
}
private void checkCN(X509Certificate[] chains) throws CertificateException {
if (Boolean.getBoolean("DEBUG")) {
System.out.println("checkCN(X509Certificate[] chains) : " + Arrays.toString(chains));
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < chains.length; i++) {
String cn = extractCN(chains[i].getIssuerX500Principal().getName());
if (cn == null) {
sb.append("\n\tFailed to authenticate Server CA : Name = "
+ chains[i].getIssuerX500Principal().getName());
} else {
return;
}
}
if (Boolean.getBoolean("DEBUG")) {
System.out.println("sb.toString : " + sb.toString());
}
throw new CertificateException(sb.toString());
}
private String extractCN(final String subjectPrincipal) {
if (subjectPrincipal == null) {
return null;
}
try {
final LdapName subjectDN = new LdapName(subjectPrincipal);
final List<Rdn> rdns = subjectDN.getRdns();
for (int i = rdns.size() - 1; i >= 0; i--) {
final Rdn rds = rdns.get(i);
final Attributes attributes = rds.toAttributes();
final Attribute cn = attributes.get("cn");
if (cn != null) {
try {
final Object value = cn.get();
if (value != null) {
return value.toString();
}
} catch (final NoSuchElementException ignore) {
} catch (final NamingException ignore) {
}
}
}
} catch (final InvalidNameException e) {
}
return null;
}
#Override
public void checkClientTrusted(X509Certificate[] certificates, String paramString) throws CertificateException {
for (X509Certificate certificate : certificates) {
certificate.checkValidity();
}
check(certificates, paramString);
}
#Override
public void checkServerTrusted(X509Certificate[] certificates, String paramString) throws CertificateException {
for (X509Certificate certificate : certificates) {
certificate.checkValidity();
}
check(certificates, paramString);
}
#Override
public X509Certificate[] getAcceptedIssuers() {
return trustManagers != null && trustManagers.length > 0 && trustManagers[0] instanceof X509TrustManager
? ((X509TrustManager) trustManagers[0]).getAcceptedIssuers() : EMPTY_X509CERTIFICATE_ARRAY;
}
}
javax.net.ssl.SSLException: oracle.aurora.vm.ReadOnlyObjectException
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java) at
com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java)
at
com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java)
at
com.sun.net.ssl.internal.ssl.SSLSocketImpl.handleException(SSLSocketImpl.java)
at
com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java)
at
com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java)
at jms.cxmessenger.JSSESSLImpl.createSSLSocket(JSSESSLImpl.java) at
jms.cxmessenger.JSSESSLImpl.createSSLSocket(JSSESSLImpl.java:69) at
progress.message.net.ssl.ProgressSslSocket.(ProgressSslSocket.java)
at
progress.message.net.ssl.ProgressSslSocket.(ProgressSslSocket.java:163)
at
progress.message.net.ssl.ProgressSslSocketFactory.createProgressSocket(ProgressSslSocketFactory.java:172)
at
progress.message.net.ProgressSocketFactory.createProgressSocket(ProgressSocketFactory.java:180)
at
progress.message.zclient.Connection.openSocket(Connection.java:3660)
at
progress.message.zclient.Connection.connectWithRecoveryOpt(Connection.java)
at
progress.message.zclient.ReconnectHelper.connectAndChaseSingleFailoverRedirect(ReconnectHelper.java:534)
at
progress.message.zclient.ReconnectHelper.connect(ReconnectHelper.java)
at progress.message.zclient.Connection.connect(Connection.java:1585)
at progress.message.jimpl.Connection.(Connection.java:886) at
progress.message.jclient.ConnectionFactory.createConnection(ConnectionFactory.java:2316)
at jms.cxmessenger.SonicSender.doSend(SonicSender.java:73)
Caused by:
oracle.aurora.vm.ReadOnlyObjectException at
jms.cxmessenger.SecureTrustManager.check(SecureTrustManager.java:43)
at
jms.cxmessenger.SecureTrustManager.checkServerTrusted(SecureTrustManager.java)
at
com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java)
at
com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java)
at
com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java)
at
com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java)
at
com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java)
at
com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java)
... 16 more
Can some one help
Are you sure you got the right jar version?
I wouldn't expect jms.cxmessenger.* until cx messenger or sonic 2015(not sure).
cxmessenger is the latest version.
the problem was that there is some SYS Java classes missing !!
the public synonyms was there but there is no classes behind.
The solution was to reinstall the SYS Java classes and everything goes well!
Related
I implemented a custom key manager, in order to choose which alias use when i need a ssl handshake.
The problem is that none of the methods of my custom key manager gets called, although it's correctly instantiated.
With a keystore containing just ONE alias, communication is fine and the code works, but the aim here is to have the possibility to change aliases during runtime.
Here is the full code of my implementation. Any Help is appreciated.
package ssl;
import java.net.Socket;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.X509ExtendedKeyManager;
import javax.net.ssl.X509KeyManager;
public class AliasSelectorKeyManager extends X509ExtendedKeyManager {
private X509KeyManager sourceKeyManager = null;
private String alias;
public AliasSelectorKeyManager(X509KeyManager keyManager, String alias) {
this.sourceKeyManager = keyManager;
this.alias = alias;
}
#Override
public String chooseEngineClientAlias(String[] paramArrayOfString, Principal[] paramArrayOfPrincipal, SSLEngine paramSSLEngine) {
return chooseClientAlias(paramArrayOfString, paramArrayOfPrincipal, null);
}
#Override
public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
boolean aliasFound = false;
//Get all aliases from the key manager. If any matches with the managed alias,
//then return it.
//If the alias has not been found, return null (and let the API to handle it,
//causing the handshake to fail).
for (int i = 0; i < keyType.length && !aliasFound; i++) {
String[] validAliases = sourceKeyManager.getClientAliases(keyType[i], issuers);
if (validAliases != null) {
for (int j = 0; j < validAliases.length && !aliasFound; j++) {
if (validAliases[j].equals(alias)) {
aliasFound = true;
}
}
}
}
if (aliasFound) {
return alias;
} else {
return null;
}
}
}
All this does is simply override each method calling the specific sourceKeyManager implementation. The customization comes into the two methods:
chooseEngineClientAlias;
chooseClientAlias
This is my SSL client main:
package ssl;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager;
public class SSLClientV2 {
public static void main(String[] args) {
String keyStoreType = "PKCS12";
String keyManagementAlgorithm = "SunX509";
String keyStorePassword = "password";
String keyStoreFileName = "C:/keystore.p12";
String protocolVersion = "TLSv1.2";
System.out.println("Key store File name.......: " + keyStoreFileName);
System.out.println("Key store type............: " + keyStoreType);
System.out.println("Key store Password........: " + keyStorePassword);
System.out.println("SSL Protocol..............: " + protocolVersion);
System.out.println("Key Management Algorithm..: " + keyManagementAlgorithm);
System.out.println(System.lineSeparator());
KeyStore keyStore = null;
KeyManagerFactory keyManagerFactory = null;
SSLContext sslContext = null;
try (FileInputStream keyStoreFile = new FileInputStream(keyStoreFileName)) {
System.out.println("Loading keystore...");
keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(keyStoreFile, keyStorePassword.toCharArray());
System.out.println("Keystore loaded successfully.");
} catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) {
System.out.println("ERROR: Could not load keystore.");
e.printStackTrace();
}
System.out.print(System.lineSeparator());
if (keyStore != null) {
try {
System.out.println("Initializing Key Manager Factory...");
keyManagerFactory = KeyManagerFactory.getInstance(keyManagementAlgorithm);
keyManagerFactory.init(keyStore, keyStorePassword.toCharArray());
System.out.println("Key Manager Factory initialized successfully.");
} catch (NoSuchAlgorithmException | UnrecoverableKeyException | KeyStoreException e) {
System.out.println("ERROR: Could not initialize Key Manager Factory.");
e.printStackTrace();
}
}
System.out.print(System.lineSeparator());
if (keyManagerFactory != null) {
try {
System.out.println("Initializing SSL Context...");
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
TrustManager[] trustManagers = new TrustManager[] {
new X509TrustManager() {
#Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
#Override
public void checkServerTrusted(X509Certificate[] paramArrayOfX509Certificate, String paramString) throws CertificateException {
}
#Override
public void checkClientTrusted(X509Certificate[] paramArrayOfX509Certificate, String paramString) throws CertificateException {
}
}
};
for (int i = 0; i < keyManagers.length; i++) {
if (keyManagers[i] instanceof X509KeyManager) {
keyManagers[i] = new AliasSelectorKeyManager((X509KeyManager) keyManagers[i], "my.custom.alias");
System.out.println("Custom Key Manager loaded (#" + (i + 1) + ", class: " + keyManagers[i].getClass().getName() + ")");
}
}
sslContext = SSLContext.getInstance(protocolVersion);
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextInt();
sslContext.init(keyManagers, trustManagers, secureRandom);
System.out.println("SSL Context initialized successfully.");
} catch (KeyManagementException | NoSuchAlgorithmException e) {
System.out.println("ERROR: Could not initialize SSL Context.");
e.printStackTrace();
}
}
System.out.print(System.lineSeparator());
if (sslContext != null) {
try (SSLSocket socket = (SSLSocket) sslContext.getSocketFactory().createSocket("192.168.10.10", 1443)) {
System.out.println("Communication initialized, starting handshake...");
socket.startHandshake();
System.out.println("Handshake completed successfully.");
BufferedWriter w = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
BufferedReader r = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String m = null;
System.out.print(System.lineSeparator());
String content = "Hello World";
System.out.println("Sending: " + content);
w.write(content);
w.flush();
System.out.println("Message received: ");
while ((m = r.readLine()) != null) {
System.out.println(m);
}
w.close();
r.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
please override also this method:
X509KeyManager::getClientAliases(String keyType, Principal[] issuers)
Has the needClientAuth flag been turned on the server side?
https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLEngine.html#setNeedClientAuth(boolean)
The server asks the client’s authentication during the handshake only if the flag is turned on.
In my java application I need to send POST requests to a server sitting behind https. On the machine where my java application is running there is a java trust store in: /usr/local/comp.jks that contains the certificate for the server I need to interact with (its already imported).
The problem is that I cannot control how the JVM is started that will run my java application - e.g. by adding:
-Djavax.net.ssl.trustStore=/usr/local/comp.jks to the VM arguments.
Is it possible to load the trust store in the above path at runtime from my application after the JVM has started so I can authenticate against the https site?
I have only found guides on how to import certificates at runtime but that I cannot use - also since I don't have the password for /usr/local/comp.jks
Below my current implementation (in groovy):
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import java.util.Base64;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class HttpsClientImpl extends AbstractHttpClient {
private String username = null;
private String password = null;
public HttpsClientImpl (String username, String password) {
this.username=username;
this.password=password;
}
#Override
public String sendRequest(String request, String method) {
System.setProperty( "javax.net.ssl.trustStore", "/usr/local/comp.jks" );
URL url = new URL(request);
HttpsURLConnection con = (HttpsURLConnection) url.openConnection()
// Set auth
byte[] name = (username + ":" + password).getBytes();
String authStr = Base64.getEncoder().encodeToString(name);
con.setRequestProperty("Authorization", "Basic " + authStr)
con.setRequestMethod(method);
writeResult(con);
return con.getResponseCode();
}
private void writeResult(HttpsURLConnection con) throws IOException {
if(con!=null){
BufferedReader br = null;
if (200 <= con.getResponseCode() && con.getResponseCode() <= 299) {
br = new BufferedReader(new InputStreamReader(con.getInputStream()));
} else {
br = new BufferedReader(new InputStreamReader(con.getErrorStream()));
}
try {
String input;
while ((input = br.readLine()) != null){
System.out.println(input);
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
When I run that I get:
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
Caused: sun.security.validator.ValidatorException: PKIX path building failed
Assuming you haven't instantiated any SSL connections yet, you can simply call
System.setProperty( "javax.net.ssl.trustStore", "/usr/local/comp.jks" );
You'll probably also need to set javax.net.ssl.trustStorePassword and maybe javax.net.ssl.trustStoreType.
If the default SSL infrastructure has alredy been instantiated, you'll probably have to create your own SSLContext and SSLSocketFactory using your keystore.
You can load the truststore in you class. What I would suggest is to use both your truststore and load the JDK truststore and use both.
Here I am giving and example regarding how you can do it.
public class TrustManagerComposite implements X509TrustManager {
private final List<X509TrustManager> compositeTrustmanager;
public TrustManagerComposite() {
List<X509TrustManager> trustManagers = new ArrayList<>();
try (InputStream truststoreInput = PATH_TO_YOUR_TRUSTSTORE) {
trustManagers.add(getCustomTrustmanager(truststoreInput));
trustManagers.add(getDefaultTrustmanager());
} catch (Exception e) {
//log it
}
compositeTrustmanager = trustManagers;
}
private static X509TrustManager getCustomTrustmanager(InputStream trustStream) throws Exception {
return createTrustManager(trustStream);
}
private static X509TrustManager getDefaultTrustmanager() throws Exception {
return createTrustManager(null);
}
private static X509TrustManager createTrustManager(InputStream trustStream) throws Exception {
// Now get trustStore
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
// load the stream to your store
trustStore.load(trustStream, null);
// initialize a trust manager factory with the trusted store
TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustFactory.init(trustStore);
// get the trust managers from the factory
TrustManager[] trustManagers = trustFactory.getTrustManagers();
for (TrustManager trustManager : trustManagers) {
if (trustManager instanceof X509TrustManager) {
return (X509TrustManager) trustManager;
}
}
return null;
}
#Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
for (X509TrustManager trustManager : compositeTrustmanager) {
try {
trustManager.checkClientTrusted(chain, authType);
return;
} catch (CertificateException e) {
// maybe the next trust manager will trust it, don't break the loop
}
}
throw new CertificateException("None of the TrustManagers trust this certificate chain");
}
#Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
for (X509TrustManager trustManager : compositeTrustmanager) {
try {
trustManager.checkServerTrusted(chain, authType);
return;
} catch (CertificateException e) {
// maybe the next trust manager will trust it, don't break the loop
}
}
throw new CertificateException("None of the TrustManagers trust this certificate chain");
}
#Override
public X509Certificate[] getAcceptedIssuers() {
List<X509Certificate> certs = new ArrayList<>();
for (X509TrustManager trustManager : compositeTrustmanager) {
for (X509Certificate cert : trustManager.getAcceptedIssuers()) {
certs.add(cert);
}
}
return certs.toArray(new X509Certificate[0]);
}
}
I have combined client-certificate-with-com-sun-net-httpserver-httpsserver
with simple-java-https-server but I always get the error message
SSL-Peer could not be verified.
I call setWantClientAuth(true) and verify Authentification by calling
Certificate[] peerCerts = pHttpsExchange.getSSLSession().getPeerCertificates();
The server is running with JDK 1.8 and the client is running on Android. The server Code is:
package de.org.vnetz;
import java.io.*;
import java.net.InetSocketAddress;
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;
import com.sun.net.httpserver.*;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;
import javax.net.ssl.SSLContext;
import javax.security.auth.x500.X500Principal;
import java.security.cert.Certificate;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class clsHTTPSServer {
final static String SERVER_PWD = "xxxxxx";
final static String KST_SERVER = "server.jks";
final static String TST_SERVER = "servertrust.jks";
private static final int PORT = 9999;
public static class MyHandler implements HttpHandler {
// whether to use client cert authentication
private final boolean useClientCertAuth = true;
private List<LdapName> allowedPrincipals = new ArrayList<LdapName>();
private final boolean extendedClientCheck = true;
private static final String CLIENTAUTH_OID = "1.3.6.1.5.5.7.3.2";
#Override
public void handle(HttpExchange t) throws IOException {
String response = "Hallo Natalie!";
HttpsExchange httpsExchange = (HttpsExchange) t;
boolean auth;
try
{
checkAuthentication(httpsExchange);
auth = true;
}
catch (Exception ex)
{
response = ex.getMessage();
auth = false;
}
boolean res = httpsExchange.getSSLSession().isValid();
if (res) {
String qry = httpsExchange.getRequestURI().getQuery();
if (qry!=null && qry.startsWith("qry=")) {
httpsExchange.getResponseHeaders().add("Access-Control-Allow-Origin", "*");
httpsExchange.sendResponseHeaders(200, response.length());
OutputStream os = t.getResponseBody();
os.write(response.getBytes());
os.close();
}
else
{
httpsExchange.getResponseHeaders().add("Access-Control-Allow-Origin", "*");
httpsExchange.sendResponseHeaders(200, response.length());
OutputStream os = t.getResponseBody();
os.write((response + " no query!").getBytes());
os.close();
}
}
}
// Verify https certs if its Https request and we have SSL auth enabled. Will be called before
// handling the request
protected void checkAuthentication(HttpExchange pHttpExchange) throws SecurityException {
// Cast will always work since this handler is only used for Http
HttpsExchange httpsExchange = (HttpsExchange) pHttpExchange;
if (useClientCertAuth) {
checkCertForClientUsage(httpsExchange);
checkCertForAllowedPrincipals(httpsExchange);
}
}
// Check the cert's principal against the list of given allowedPrincipals.
// If no allowedPrincipals are given than every principal is allowed.
// If an empty list as allowedPrincipals is given, no one is allowed to access
private void checkCertForClientUsage(HttpsExchange pHttpsExchange) {
try {
String host = pHttpsExchange.getSSLSession().getPeerHost();
//Principal p = pHttpsExchange.getSSLSession().getPeerPrincipal();
String pr = pHttpsExchange.getSSLSession().getProtocol();
Certificate[] peerCerts = pHttpsExchange.getSSLSession().getPeerCertificates();
if (peerCerts != null && peerCerts.length > 0) {
X509Certificate clientCert = (X509Certificate) peerCerts[0];
// We required that the extended key usage must be present if we are using
// client cert authentication
if (extendedClientCheck &&
(clientCert.getExtendedKeyUsage() == null || !clientCert.getExtendedKeyUsage().contains(CLIENTAUTH_OID))) {
throw new SecurityException("No extended key usage available");
}
}
} catch (ClassCastException e) {
throw new SecurityException("No X509 client certificate");
} catch (CertificateParsingException e) {
throw new SecurityException("Can't parse client cert");
} catch (SSLPeerUnverifiedException e) {
throw new SecurityException("SSL Peer couldn't be verified");
}
}
private void checkCertForAllowedPrincipals(HttpsExchange pHttpsExchange) {
if (allowedPrincipals != null) {
X500Principal certPrincipal;
try {
certPrincipal = (X500Principal) pHttpsExchange.getSSLSession().getPeerPrincipal();
Set<Rdn> certPrincipalRdns = getPrincipalRdns(certPrincipal);
for (LdapName principal : allowedPrincipals) {
for (Rdn rdn : principal.getRdns()) {
if (!certPrincipalRdns.contains(rdn)) {
throw new SecurityException("Principal " + certPrincipal + " not allowed");
}
}
}
} catch (SSLPeerUnverifiedException e) {
throw new SecurityException("SSLPeer unverified");
} catch (ClassCastException e) {
throw new SecurityException("Internal: Invalid Principal class provided " + e);
}
}
}
private Set<Rdn> getPrincipalRdns(X500Principal principal) {
try {
LdapName certAsLdapName =new LdapName(principal.getName());
return new HashSet<Rdn>(certAsLdapName.getRdns());
} catch (InvalidNameException e) {
throw new SecurityException("Cannot parse '" + principal + "' as LDAP name");
}
}
}
/**
* #param args
*/
public static void main(String[] args) throws Exception {
try {
// setup the socket address
InetSocketAddress address = new InetSocketAddress(PORT);
// initialise the HTTPS server
HttpsServer httpsServer = HttpsServer.create(address, 0);
SSLContext sslContext = SSLContext.getInstance("TLS");
// initialise the keystore
// char[] password = "password".toCharArray();
KeyStore ks = KeyStore.getInstance("JKS");
FileInputStream fis = new FileInputStream(KST_SERVER);// ("testkey.jks");
ks.load(fis, SERVER_PWD.toCharArray());// password);
// setup the key manager factory
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, SERVER_PWD.toCharArray());
// setup the trust manager factory
// TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
// tmf.init(ks);
KeyStore ts = KeyStore.getInstance("JKS");
ts.load(new FileInputStream(TST_SERVER), SERVER_PWD.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ts);
// setup the HTTPS context and parameters
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
SSLParameters sslp = sslContext.getSupportedSSLParameters();
//sslp.setNeedClientAuth(true);
sslp.setWantClientAuth(true);
httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslContext) {
public void configure(HttpsParameters params) {
try {
// initialise the SSL context
SSLContext c = SSLContext.getDefault();
SSLEngine engine = c.createSSLEngine();
//params.setNeedClientAuth(true);
params.setWantClientAuth(true);
params.setCipherSuites(engine.getEnabledCipherSuites());
params.setProtocols(engine.getEnabledProtocols());
// get the default parameters
SSLParameters defaultSSLParameters = c.getDefaultSSLParameters();
SSLParameters sslParams = sslContext.getDefaultSSLParameters();
//sslParams.setNeedClientAuth(true);
sslParams.setWantClientAuth(true);
params.setSSLParameters(defaultSSLParameters);
} catch (Exception ex) {
System.out.println("Failed to create HTTPS port");
}
}
});
httpsServer.createContext("/test", new MyHandler());
httpsServer.setExecutor(
new ThreadPoolExecutor(4, 80, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1000))); // creates
// a
// default
// executor
httpsServer.start();
} catch (Exception exception) {
System.out.println("Failed to create HTTPS server on port " + 62112 + " of localhost");
exception.printStackTrace();
}
}
}
The client code is:
package vnetz.de.org.vnetz;
import android.content.Context;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.net.SocketException;
import java.net.URL;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
public class clsHTTPS {
private static final String MYURL = "https://localhost:9999/test?qry=test";
static String NO_KEYSTORE = "";
static String UNAUTH_KEYSTORE = "unauthclient.bks"; // Doesn't exist in server trust store, should fail authentication.
static String AUTH_KEYSTORE = "authclient.bks"; // Exists in server trust store, should pass authentication.
static String TRUSTSTORE = "clienttrust.bks";
static String CLIENT_PWD = "xxxxxx";
private static Context context = null;
public clsHTTPS(Context context) {
this.context = context;
}
public static void main(String[] args) throws Exception {
}
public String connect(String jksFile) {
try {
String https_url = MYURL;
URL url;
url = new URL(https_url);
HttpsURLConnection.setDefaultHostnameVerifier(new NullHostNameVerifier());
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(getSSLFactory(jksFile));
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setUseCaches(false);
// Print response
//SSLContext context = SSLContext.getInstance("TLS");
//context.init(null, new X509TrustManager[]{new NullX509TrustManager()}, new SecureRandom());
//HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
BufferedReader bir = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder sbline = new StringBuilder();
String line;
while ((line = bir.readLine()) != null) {
System.out.println(line);
sbline.append(line);
}
bir.close();
conn.disconnect();
return sbline.toString();
} catch (SSLHandshakeException | SocketException e) {
System.out.println(e.getMessage());
System.out.println("");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static SSLSocketFactory getSSLFactory(String jksFile) throws Exception {
// Create key store
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
KeyManager[] kmfs = null;
if (jksFile.length() > 0) {
keyStore.load(context.getAssets().open(jksFile), CLIENT_PWD.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(
KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, CLIENT_PWD.toCharArray());
kmfs = kmf.getKeyManagers();
}
// create trust store (validates the self-signed server!)
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(context.getAssets().open(TRUSTSTORE), CLIENT_PWD.toCharArray());
TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
trustFactory.init(trustStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmfs, trustFactory.getTrustManagers(), null);
return sslContext.getSocketFactory();
}
private class NullHostNameVerifier implements HostnameVerifier
{
#Override
public boolean verify(String s, SSLSession sslSession)
{
return s.equalsIgnoreCase("localhost");
}
}
private class NullX509TrustManager implements X509TrustManager
{
#Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException
{
}
#Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException
{
}
#Override
public X509Certificate[] getAcceptedIssuers()
{
return new X509Certificate[0];
}
}
}
'Peer not verified' in a server means that the client didn't send a certificate, which probably means that its signer isn't in your server's truststore. When the server requests the client certificate, it supplies a list of acceptable signers, and the client must not send a certificate that isn't signed by one of those.
Or else the server didn't ask for a client certificate at all. Doesn't apply in this case.
In your case it would be a lot simpler to use needClientAuth, as that will just fail the handshake without you having to get as a far as getPeerCertificates().
NB:
The SSLSession is valid, otherwise you wouldn't have an SSL connection. The only way it becomes invalid is if you call invalidate(), which causes a full re-handshake on the next I/O. You're testing the wrong thing.
Checking for allowed principals is authorization, not authentication.
I have a X509Certificate in java and I want to get the value of the Policy Identifier which there exists in the Certificate Policies field, as depicted in the following picture:
Also, I want to get the value of the Subject Type in Basic Constraints field, as depicted in the following picture:
My code:
public static void main(String[] args) throws Exception {
CertificateFactory cf = CertificateFactory.getInstance("X509");
InputStream in = new FileInputStream(new File("E:\\myCert.crt"));
X509Certificate cert = (X509Certificate) cf.generateCertificate(in);
int length = cert.getCertificateExtensionOIDs().size();
String oid;
for(int i = 0; i < length; i++){
oid = cert.getCertificateExtensionOIDs().iterator().next();
byte[] UID = cert.getExtensionValue(oid);
DERObject derObject = toDERObject(UID);
if(derObject instanceof DEROctetString){
DEROctetString derOctetString = (DEROctetString) derObject;
derObject = toDERObject(derOctetString.getOctets());
}
// here I think, I should use derObject to retrieve cert info but I don't know how!?
}
public static DERObject toDERObject(byte[] data) throws IOException {
ByteArrayInputStream inStream = new ByteArrayInputStream(data);
ASN1InputStream DIS = new ASN1InputStream(inStream);
return DIS.readObject();
}
Look at that code. A little more data validation code may be needed and you have to be careful checking basic constraints, because the condition below may not be enough in some cases.
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.x509.CertificatePolicies;
import org.bouncycastle.asn1.x509.PolicyInformation;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.SignatureException;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
/**
* 2016 krzysiek
*/
public class App {
private static final String CERTIFICATE_POLICY_OID = "2.5.29.32";
private static final String FILENAME = "/test.cer";
public static void main(String[] args) {
try {
X509Certificate cert = loadCertificate();
String policyIdentifier = getCertificatePolicyId(cert, 0, 0);
System.out.println("Policy Identifier: " + policyIdentifier);
String subjectType = getSubjectType(cert);
System.out.println("Subject Type: " + subjectType);
} catch (Exception e) {
System.out.println("Problem with certificate: " + e.getMessage());
}
}
private static String getSubjectType(X509Certificate cert) {
int pathLen = cert.getBasicConstraints();
if (pathLen == -1) {
if (cert.getKeyUsage()[5] || cert.getKeyUsage()[6]) { //simple check, there my be needed more key usage and extended key usage verification
return "Service";
} else {
return "EndEntity";
}
} else {
try {
cert.verify(cert.getPublicKey());
return "RootCA";
} catch (SignatureException | InvalidKeyException e) {
return "SubCA";
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
private static X509Certificate loadCertificate() {
try (InputStream in = new FileInputStream(App.class.getResource(FILENAME).getFile())) {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate certificate = cf.generateCertificate(in);
X509Certificate cert = (X509Certificate) certificate;
return cert;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static String getCertificatePolicyId(X509Certificate cert, int certificatePolicyPos, int policyIdentifierPos)
throws IOException {
byte[] extPolicyBytes = cert.getExtensionValue(CERTIFICATE_POLICY_OID);
if (extPolicyBytes == null) {
return null;
}
DEROctetString oct = (DEROctetString) (new ASN1InputStream(new ByteArrayInputStream(extPolicyBytes)).readObject());
ASN1Sequence seq = (ASN1Sequence) new ASN1InputStream(new ByteArrayInputStream(oct.getOctets())).readObject();
if (seq.size() <= (certificatePolicyPos)) {
return null;
}
CertificatePolicies certificatePolicies = new CertificatePolicies(PolicyInformation.getInstance(seq.getObjectAt(certificatePolicyPos)));
if (certificatePolicies.getPolicyInformation().length <= policyIdentifierPos) {
return null;
}
PolicyInformation[] policyInformation = certificatePolicies.getPolicyInformation();
return policyInformation[policyIdentifierPos].getPolicyIdentifier().getId();
}
}
pom.xml:
<properties>
<bouncycastle.version>1.54</bouncycastle.version>
</properties>
<dependencies>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcmail-jdk15on</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
</dependencies>
I need to verify a signed xml document. As a part of the verification I need to check whether the certificate passed with the signed certificate is a trusted certificate.
All the trusted certificates are added to a keystore called trusted.keystore.
How can I check whether the certificate passed is a valid certificate?
I've wrote the following KeySelector, but it is not working
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import java.util.Iterator;
import javax.xml.crypto.AlgorithmMethod;
import javax.xml.crypto.KeySelector;
import javax.xml.crypto.KeySelectorException;
import javax.xml.crypto.KeySelectorResult;
import javax.xml.crypto.XMLCryptoContext;
import javax.xml.crypto.XMLStructure;
import javax.xml.crypto.dsig.SignatureMethod;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.keyinfo.X509Data;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class X509KeySelector extends KeySelector {
private static Log log = LogFactory.getLog(X509KeySelector.class);
private KeyStore trustedStore;
public void setTrustedStore(KeyStore trustedStore) {
this.trustedStore = trustedStore;
}
#SuppressWarnings("rawtypes")
public KeySelectorResult select(KeyInfo keyInfo,
KeySelector.Purpose purpose, AlgorithmMethod method,
XMLCryptoContext context) throws KeySelectorException {
if (log.isDebugEnabled()) {
log.debug("Selecting key for algorithm: " + method.getAlgorithm());
}
Iterator ki = keyInfo.getContent().iterator();
while (ki.hasNext()) {
XMLStructure info = (XMLStructure) ki.next();
if (log.isDebugEnabled()) {
log.debug("Found xml structure: " + info.toString());
}
if (!(info instanceof X509Data)) {
if (log.isTraceEnabled()) {
log.trace("Ignoring xml structure since it is not a X509Data.");
}
continue;
}
X509Data x509Data = (X509Data) info;
Iterator xi = x509Data.getContent().iterator();
if (log.isDebugEnabled()) {
log.debug("Iterating X509Data: Size: "
+ x509Data.getContent().size());
}
while (xi.hasNext()) {
Object o = xi.next();
if (log.isDebugEnabled()) {
log.debug("Found object: " + o);
}
if (!(o instanceof X509Certificate)) {
if (log.isTraceEnabled()) {
log.trace("Ignoring object since it is not a X509Certificate");
}
continue;
}
X509Certificate cert = (X509Certificate) o;
if (!isTrustedCertificate(cert)) {
log.warn("Ignoring certificate since it is not a valid certificate. Certificate: "
+ cert);
continue;
}
final PublicKey key = cert.getPublicKey();
// Make sure the algorithm is compatible
// with the method.
if (algEquals(method.getAlgorithm(), key.getAlgorithm())) {
KeySelectorResult keySelectorResult = new KeySelectorResult() {
public Key getKey() {
return key;
}
};
return keySelectorResult;
} else {
log.warn("Ignoring certificate since the algorithms "
+ method.getAlgorithm() + " and "
+ key.getAlgorithm() + " does not match.");
}
}
}
log.error("Unable to find a valid certificate.");
throw new KeySelectorException("No key found!");
}
private boolean isTrustedCertificate(X509Certificate cert) {
if (trustedStore == null) {
return true;
}
boolean trusted = false;
try {
Enumeration<String> aliases = trustedStore.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
Certificate[] certificates = this.trustedStore
.getCertificateChain(alias);
if (certificates == null) {
Certificate certificate = this.trustedStore
.getCertificate(alias);
if (certificate != null) {
certificates = new Certificate[] { certificate };
}
}
if (certificates != null) {
for (Certificate certificate : certificates) {
if (!(certificate instanceof X509Certificate)) {
continue;
}
if (cert.getSignature().equals(
((X509Certificate) certificate).getSignature())) {
trusted = true;
break;
}
}
if (trusted) {
break;
}
}
}
} catch (KeyStoreException e) {
log.error(e.toString(), e);
}
return trusted;
}
static boolean algEquals(String algURI, String algName) {
if ((algName.equalsIgnoreCase("DSA") && algURI
.equalsIgnoreCase(SignatureMethod.DSA_SHA1))
|| (algName.equalsIgnoreCase("RSA") && algURI
.equalsIgnoreCase(SignatureMethod.RSA_SHA1))) {
return true;
} else {
return false;
}
}
}
The problem lies in the method isTrustedCertificate. Where I'm iterating through all the aliases in the keystore and check where it is the same as the passed certificate.
As the class name suggests it deals with only X509 type certificates.
Thank you
There is a simpler way to check this using a method that might not be obvious to use at first. The KeyStore class has a method called getCertificateAlias(Certificate cert). If you pass in the certificate you are trying to check for and you do not get a null return, then that certificate is in the KeyStore.
Try something like this:
private boolean isTrustedCertificate(X509Certificate cert) {
if (trustedStore == null) {
return true;
}
boolean trusted = false;
try {
if (cert != null) {
// Only returns null if cert is NOT in keystore.
String alias = trustedStore.getCertificateAlias(cert);
if (alias != null) {
trusted = true;
}
}
} catch (KeyStoreException e) {
log.error(e.toString(), e);
}
return trusted;
}
I think I was going the wrong way,
I found the verify(PublicKey) method in Certificate object, which will java.security.SignatureException: Signature does not match. exception if the certificates does not match.