Java Exception x509Certificate - "ResourceReader" missing / cannot load cert - java

Java NetBeans - New to Java and I'm trying to make an old app work so I can mirror it in C# (my lang of choice) ... Trying to import a cert... not sure what I'm missing... Where can I find "ResourceReader"? as I cannot seem to figure out if that is something I need ? also... I get an errror reading the file (likely related to ResourceReader?) I searched here, but not sure which one is the one I'm after (if any). I'm recreating this with NetBeans on "Windows 7".
package doccentertestingencryption;
/**
*
*/
import java.security.*;
import java.io.*;
import java.net.*;
import java.util.*;
import java.security.cert.*;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.DESedeKeySpec;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import doccentertestingencryption.CryptoConstants.*;
//import doccentertestingencryption.sLinksBC;
import doccentertestingencryption.SignData;
import doccentertestingencryption.FileLoader;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
//import ResourceReader;
public class EncryptData
{
private String certFile = null;
private String encString = null;
private String encryptMode = null;
private X509Certificate cert = null;
private SecretKey symmKey = null;
CryptoConstants crypto = null;
public EncryptData() throws Exception
{
try
{
crypto = new CryptoConstants();
certFile = crypto.getCertFileName();
if (certFile != null)
try
{
initSecurity();
}
catch ( ExceptionInInitializerError e )
{
throw e;
}
}
catch(ExceptionInInitializerError ex )
{
throw ex;
}
} // end contructor EncryptData
public EncryptData(String vendorAcro) throws Exception
{
crypto = new CryptoConstants();
certFile = crypto.getCertFileName(vendorAcro);
if (certFile != null)
try
{
initSecurity();
}
catch ( Exception e )
{
throw e;
}
else
throw new Exception(vendorAcro+"certFile not found in CryptoConstants class") ;
}// end contructor EncryptData
private void initSecurity() throws CertificateException, Exception
{
try
{
Security.addProvider(new BouncyCastleProvider());
CertificateFactory cf = CertificateFactory.getInstance(CryptoConstants.certType);
//InputStream inStream = this.getClass().getResourceAsStream(certFile);
InputStream inStream = this.getClass().getResourceAsStream(certFile);
// ByteArrayOutputStream baos = new ByteArrayOutputStream();
//cert = (X509Certificate) cf.generateCertificate(inStream);
cert = (X509Certificate) cf.generateCertificate(inStream);
if (cert == null)
throw new Exception("in EncryptData.init: cert = null");
KeyGenerator keyGen = KeyGenerator.getInstance(CryptoConstants.symmEncryptMode);
symmKey = keyGen.generateKey();
}
catch(ExceptionInInitializerError ex)
{
throw ex;
}
}
#SuppressWarnings("null")
public String encrypt(String strToEncrypt) throws InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException
{
try
{
//String encString= null;
byte dataToEncrypt[] = strToEncrypt.getBytes();
Cipher symmCipher = null;
try {
symmCipher = Cipher.getInstance(CryptoConstants.symmEncryptMode);
} catch (NoSuchAlgorithmException | NoSuchPaddingException ex) {
Logger.getLogger(EncryptData.class.getName()).log(Level.SEVERE, null, ex);
}
symmCipher.init(Cipher.ENCRYPT_MODE, symmKey);
byte[] encrypted = symmCipher.doFinal(dataToEncrypt);
encString= new String(Base64.encode(encrypted));
encString = URLEncoder.encode(encString, "UTF-8");
return(encString);
}
catch (ExceptionInInitializerError ei )
{
throw ei;
}
} //end method create Signature
public String encryptSymmKey() throws Exception
{
Cipher asymmCipher = Cipher.getInstance(CryptoConstants.asymmEncryptCipher, "BC");
asymmCipher.init(Cipher.ENCRYPT_MODE, cert.getPublicKey());
byte[] encSymmKeyBytes = asymmCipher.doFinal(symmKey.getEncoded());
String encSymmKeyString= new String(Base64.encode(encSymmKeyBytes));
encSymmKeyString = URLEncoder.encode(encSymmKeyString, "UTF-8");
return(encSymmKeyString);
} //end method create Signature
public String encryptQSValues(String unencryptedQS) throws Exception
{
String encryptedQS = null;
String nameNequals = null;
String value = null;
String nameValuePair = null;
int i = 0;
try
{
encryptedQS = "ENCQS="+ encrypt(unencryptedQS);
encryptedQS = encryptedQS +"&KS="+ encryptSymmKey();
}
catch (Exception e)
{
throw e;
}
return(encryptedQS);
} //end method encryptQSValues
/**
* Returns the signature
* #return String
*/
public String getEncString()
{
return encString;
}
public Provider[] getProviders()
{
Provider provs[] = Security.getProviders();
return provs;
}
public static void dumpProviders()
{
Provider provs[] = Security.getProviders();
for (int i=0; i< provs.length;i++)
System.out.println("providers["+i+"]= "+provs[i].getName());
}
} // end EncryptData
My error is:
Exception in thread "main" java.security.cert.CertificateException: Missing input stream
at sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:93)
at java.security.cert.CertificateFactory.generateCertificate(CertificateFactory.java:339)
at doccentertestingencryption.EncryptData.initSecurity(EncryptData.java:103)
at doccentertestingencryption.EncryptData.<init>(EncryptData.java:82)
at doccentertestingencryption.DocCenterTestingEncryption.main(DocCenterTestingEncryption.java:31)
C:\Users\dbarry\AppData\Local\NetBeans\Cache\8.2\executor-snippets\run.xml:53: Java returned: 1
BUILD FAILED (total time: 1 second)

Related

How to generate ECDSA signature using secp256k1 curve and SHA256 algorithm for XML document in java

We can create XML Digital Signature using RSA keys. But how do I use elliptic curve keys to sign xml files ? I get exception at this line xmlSignature.sign(domSignCtx) as -
javax.xml.crypto.MarshalException: Invalid ECParameterSpec
at java.xml.crypto/org.jcp.xml.dsig.internal.dom.DOMKeyValue$EC.marshalPublicKey(DOMKeyValue.java:493)
at java.xml.crypto/org.jcp.xml.dsig.internal.dom.DOMKeyValue.marshal(DOMKeyValue.java:121)
at java.xml.crypto/org.jcp.xml.dsig.internal.dom.DOMKeyInfo.marshal(DOMKeyInfo.java:207)
at java.xml.crypto/org.jcp.xml.dsig.internal.dom.DOMKeyInfo.marshal(DOMKeyInfo.java:197)
at java.xml.crypto/org.jcp.xml.dsig.internal.dom.DOMXMLSignature.marshal(DOMXMLSignature.java:233)
at java.xml.crypto/org.jcp.xml.dsig.internal.dom.DOMXMLSignature.sign(DOMXMLSignature.java:333)
at com.test.GenerateXMLSignature.generateXMLDigitalSignature(GenerateXMLSignature.java:117)
at com.test.GenerateXMLSignature.main(GenerateXMLSignature.java:60)
I am trying to add digital signature to the existing xml document. I am reading private key and public key from .pem file. And I can generate and verify same for SignatureMethod.RSA_SHA256. But for ECDSA_SHA256 I am getting Invalid ECParameterSpec exception. Please suggest how to generate XML Signature for secp256k1 curve using SHA256WithECDSA algorithm in java.
using:
java version "15.0.1" 2020-10-20
Java(TM) SE Runtime Environment (build 15.0.1+9-18)
Java HotSpot(TM) 64-Bit Server VM (build 15.0.1+9-18, mixed mode, sharing)
Below is my source code:
package com.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.Key;
import java.security.KeyException;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.cert.CertificateException;
import java.util.Arrays;
import java.util.Collections;
import javax.xml.crypto.dsig.CanonicalizationMethod;
import javax.xml.crypto.dsig.DigestMethod;
import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.SignatureMethod;
import javax.xml.crypto.dsig.SignedInfo;
import javax.xml.crypto.dsig.Transform;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
import javax.xml.crypto.dsig.keyinfo.KeyValue;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
public class GenerateXMLSignature {
public static final String INPUT_FILE_NAME = "D:\\XML\\staff-dom.xml";
public static final String OUTPUT_FILE_NAME = "D:\\XML\\sample.xml";
public static final String CERT_FILE_PATH = "D:\\XML\\openssl-0.9.8k_X64\\bin\\cert.pem";
public static final String PRIVATE_KEY_FILE_PATH = "D:\\XML\\openssl-0.9.8k_X64\\bin\\pkcs8file.pem";
public static final String PUBLIC_KEY_FILE_PATH = "D:\\XML\\openssl-0.9.8k_X64\\bin\\PublicKey.pem";
public static void main(String[] args) throws Exception {
generateXMLDigitalSignature(INPUT_FILE_NAME, OUTPUT_FILE_NAME, PRIVATE_KEY_FILE_PATH, PUBLIC_KEY_FILE_PATH);
}
/**
* Method used to attach a generated digital signature to the existing document
*
* #param originalXmlFilePath
* #param destnSignedXmlFilePath
* #param privateKeyFilePath
* #param publicKeyFilePath
* #throws Exception
*/
public static void generateXMLDigitalSignature(String originalXmlFilePath, String destnSignedXmlFilePath,
String privateKeyFilePath, String publicKeyFilePath) throws Exception {
int addProvider = Security.addProvider(new BouncyCastleProvider());
System.out.println(addProvider);
String[] curves = Security.getProvider("SunEC").getProperty("AlgorithmParameters.EC SupportedCurves").split("\\|");
System.out.println(Arrays.toString(curves));
// Get the XML Document object
Document doc = getXmlDocument(originalXmlFilePath);
// Create XML Signature Factory
XMLSignatureFactory xmlSigFactory = XMLSignatureFactory.getInstance("DOM");
PrivateKey privateKey = new KryptoUtil().readECPrivateKey(privateKeyFilePath);
System.out.println("Private Key===="+ privateKey);
DOMSignContext domSignCtx = new DOMSignContext((Key) privateKey, doc.getDocumentElement());
Reference ref = null;
SignedInfo signedInfo = null;
try {
ref = xmlSigFactory.newReference("", xmlSigFactory.newDigestMethod(DigestMethod.SHA256, null),
Collections.singletonList(
xmlSigFactory.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)),
null, null);
signedInfo = xmlSigFactory.newSignedInfo(
xmlSigFactory.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE,
(C14NMethodParameterSpec) null),
xmlSigFactory.newSignatureMethod(SignatureMethod.ECDSA_SHA256, null), Collections.singletonList(ref));
System.out.println(signedInfo.getSignatureMethod().getAlgorithm());
} catch (NoSuchAlgorithmException ex) {
ex.printStackTrace();
} catch (InvalidAlgorithmParameterException ex) {
ex.printStackTrace();
}
// Pass the Public Key File Path
KeyInfo keyInfo = null;
try {
keyInfo = getKeyInfo(xmlSigFactory, publicKeyFilePath);
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// Create a new XML Signature
XMLSignature xmlSignature = xmlSigFactory.newXMLSignature(signedInfo, keyInfo);
try {
// Sign the document
xmlSignature.sign(domSignCtx);
} catch (Exception ex) {
ex.printStackTrace();
}
// Store the digitally signed document int0 a location
storeSignedDoc(doc, destnSignedXmlFilePath);
}
/**
* Method used to get the KeyInfo
*
* #param xmlSigFactory
* #param publicKeyPath
* #return KeyInfo
* #throws Exception
* #throws CertificateException
*/
private static KeyInfo getKeyInfo(XMLSignatureFactory xmlSigFactory, String publicKeyPath) throws CertificateException, Exception {
KeyInfo keyInfo = null;
KeyValue keyValue = null;
PublicKey publicKey = new KryptoUtil().readECPublicKey(publicKeyPath);
System.out.println("Public Key===="+ publicKey);
KeyInfoFactory keyInfoFact = xmlSigFactory.getKeyInfoFactory();
try {
keyValue = keyInfoFact.newKeyValue(publicKey);
} catch (KeyException ex) {
ex.printStackTrace();
}
keyInfo = keyInfoFact.newKeyInfo(Collections.singletonList(keyValue));
return keyInfo;
}
private static Document getXmlDocument(String originalXmlFilePath) {
Document doc = null;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
try {
System.out.println(originalXmlFilePath);
doc = dbf.newDocumentBuilder().parse(new FileInputStream(originalXmlFilePath));
} catch (ParserConfigurationException ex) {
ex.printStackTrace();
} catch (FileNotFoundException ex) {
ex.printStackTrace();
} catch (SAXException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
return doc;
}
/*
* Method used to store the signed XMl document
*/
private static void storeSignedDoc(Document doc, String destnSignedXmlFilePath) {
TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer trans = null;
try {
trans = transFactory.newTransformer();
} catch (TransformerConfigurationException ex) {
ex.printStackTrace();
}
try {
StreamResult streamRes = new StreamResult(new File(destnSignedXmlFilePath));
trans.transform(new DOMSource(doc), streamRes);
} catch (TransformerException ex) {
ex.printStackTrace();
}
System.out.println("XML file with attached digital signature generated successfully ...");
}
}
/**
* Method used to get the generated Private Key
*
* #param filePath of the PrivateKey file
* #return PrivateKey
* #throws Exception
* #throws GeneralSecurityException
*/
public PrivateKey readECPrivateKey(String filePath) throws Exception {
Security.addProvider(new BouncyCastleProvider());
File f = new File(filePath);
FileInputStream fis = new FileInputStream(f);
DataInputStream dis = new DataInputStream(fis);
byte[] keyBytes = new byte[(int) f.length()];
dis.readFully(keyBytes);
dis.close();
String temp = new String(keyBytes);
String privatePem = temp.replace("-----BEGIN PRIVATE KEY-----\n", "");
privatePem = privatePem.replace("-----END PRIVATE KEY-----", "");
org.bouncycastle.util.encoders.Base64 b64 = new org.bouncycastle.util.encoders.Base64();
byte[] decoded = b64.decode(privatePem);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decoded);
KeyFactory factory = KeyFactory.getInstance("EC");
PrivateKey privateKey = factory.generatePrivate(spec);
System.out.println("PrivateKey===="+ privateKey);
return privateKey;
}
/**
* Method used to get the generated Public Key
*
* #param filePath of the PublicKey file
* #return PublicKey
* #throws IOException
* #throws NoSuchProviderException
* #throws InvalidKeySpecException
* #throws NoSuchAlgorithmException
*/
public PublicKey readECPublicKey(String filePath) throws IOException, NoSuchProviderException, Exception {
Security.addProvider(new BouncyCastleProvider());
File f = new File(filePath);
FileInputStream fis = new FileInputStream(f);
DataInputStream dis = new DataInputStream(fis);
byte[] keyBytes = new byte[(int) f.length()];
dis.readFully(keyBytes);
dis.close();
String temp = new String(keyBytes);
String publicKeyPEM = temp.replace("-----BEGIN PUBLIC KEY-----\n", "");
publicKeyPEM = publicKeyPEM.replace("-----END PUBLIC KEY-----", "");
org.bouncycastle.util.encoders.Base64 b64 = new org.bouncycastle.util.encoders.Base64();
byte[] decoded = b64.decode(publicKeyPEM);
X509EncodedKeySpec spec = new X509EncodedKeySpec(decoded);
KeyFactory kf = KeyFactory.getInstance("EC", "BC");
return kf.generatePublic(spec);
}

JAVA - SSL Client - Key managers not used

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.

CXF- HTTPS, Unable to connect to self signed server

I am currently developing a SOAP-Server/Client using CXF rev 3.1.10.
Everything is set up and works quite fine as long as I don't try to use https.
I am not using any xml-files/beans, except the ones that might be used 'behind the scenes' by the framework.
I would actually like to leave it that way.
I am using a self signed certificate and its extracted keys, just in case this might be necessary.
Server Class
public class Server extends Thread {
private static final Logger LOG = Logger.getLogger(Server.class);
#WebService(name = "SoapService", serviceName = "SoapService", endpointInterface = "playground.mstahl.cxf_soap.SoapServiceDefinition")
private static final class ServerImpl implements SoapServiceDefinition {
#Override
public boolean handleStateDataRecipience(String user, String pass, String restri) throws Exception {
return true;
}
}
private final int usedPort;
private final String ksPath;
private final String ksPass;
private final boolean sslEnabled;
public Server(int port, boolean sslEnabled, String ksPath, String ksPass) {
super("CXF-SOAP-Playground");
setDaemon(true);
usedPort = port;
this.sslEnabled = sslEnabled;
this.ksPath = ksPath;
this.ksPass = ksPass;
start();
}
#Override
public void run() {
JaxWsServerFactoryBean sf = new JaxWsServerFactoryBean();
sf.setAddress(String.format("http" + (sslEnabled ? "s" : "") + "://localhost:%d/signtest/", Integer.valueOf(usedPort))); // <- Yah, pretty ugly, but its just for testing purposes ;)
sf.setServiceClass(ServerImpl.class);
ServerImpl serviceBean = new ServerImpl();
sf.setServiceBean(serviceBean);
if (sslEnabled) {
try {
JettyHTTPServerEngineFactory factory = sf.getBus().getExtension(JettyHTTPServerEngineFactory.class);
factory.setTLSServerParametersForPort(usedPort, getTLSServerParameters(ksPath, ksPass));
} catch (Exception e) {
e.printStackTrace();
}
}
org.apache.cxf.endpoint.Server server = sf.create();
if (!server.isStarted()) {
return;
}
LOG.debug("... done.");
while (!IsInterrupted()) {
try {
Thread.sleep(100);
} catch (Exception e) {
//meh, just a test
}
}
server.stop();
server.destroy();
}
private final TLSServerParameters getTLSServerParameters(final String ksPath, final String ksPass) {
TLSServerParameters tlsParams = null;
try {
tlsParams = new TLSServerParameters();
File truststore = new File(ksPath);
LOG.info("Try to load file " + truststore.getCanonicalPath());
final KeyStore keyStore = KeyStore.getInstance("JKS");
FileInputStream stream = new FileInputStream(truststore);
final char[] keyStorePassphraseAsChar = ksPass.toCharArray();
keyStore.load(stream, keyStorePassphraseAsChar);
stream.close();
final KeyManagerFactory keyFactory = KeyManagerFactory.getInstance("PKIX");
keyFactory.init(keyStore, keyStorePassphraseAsChar);
final KeyManager[] km = keyFactory.getKeyManagers();
tlsParams.setKeyManagers(km);
truststore = new File(ksPath);
stream = new FileInputStream(truststore);
keyStore.load(stream, keyStorePassphraseAsChar);
stream.close();
final TrustManagerFactory trustFactory = TrustManagerFactory.getInstance("PKIX");
trustFactory.init(keyStore);
final TrustManager[] tm = trustFactory.getTrustManagers();
tlsParams.setTrustManagers(tm);
final SSLContext context = SSLContext.getDefault();
final SSLSocketFactory sf = context.getSocketFactory();
final List<String> cipherSuites = Arrays.asList(sf.getSupportedCipherSuites());
LOG.info(String.format("Suppored cipher suites : %s", cipherSuites.toString()));
final FiltersType filter = new FiltersType();
final List<String> include = filter.getInclude();
include.add(".*_EXPORT_.*");
include.add(".*_EXPORT1024_.*");
include.add(".*_WITH_DES_.*");
include.add(".*_WITH_AES_.*");
include.add(".*_WITH_NULL_.*");
include.add(".*_RSA_WITH_AES_.*");
include.add(".*_DH_anon_.*");
tlsParams.setCipherSuitesFilter(filter);
final ClientAuthentication ca = new ClientAuthentication();
ca.setRequired(false);
ca.setWant(false);
tlsParams.setClientAuthentication(ca);
} catch (final Exception e) {
LOG.error("Security configuration failed with the following: " + e.getMessage() + " " + e.getCause());
tlsParams = null;
}
return tlsParams;
}
}
My Server currently starts up quite fine. (At least no errors gets thrown...)
I can also access the given soap method as long as I am using http...
Client class
public class Client {
private static final Logger LOG = Logger.getLogger(Client.class);
private static SoapServiceDefinition client;
public Client(String address, boolean sslEnabled, String ksFile, String ksPass) {
// set keystore setting for plain httpclient
if (sslEnabled) {
LOG.debug(" ... collecting keystore file and passphrase due to enabled ssl.");
System.setProperty("javax.net.ssl.keyStore", ksFile);
System.setProperty("javax.net.ssl.trustStore", ksFile);
System.setProperty("javax.net.ssl.keyStorePassword", ksPass);
System.setProperty("javax.net.ssl.trustStorePassword", ksPass);
}
LOG.debug(" ... creating service factory.");
final JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(SoapServiceDefinition.class);
LOG.debug(" ... setting host address to '" + address + "'.");
factory.setAddress(address);
LOG.debug(" ... creating actual SOAP-client.");
client = (SoapServiceDefinition) factory.create();
final HTTPConduit httpConduit = (HTTPConduit) ClientProxy.getClient(client).getConduit();
if (sslEnabled) {
LOG.debug(" ... configuring SSL.");
configureClientSideSSL(httpConduit, ksFile, ksPass);
LOG.debug(" ... done.");
}
LOG.debug(" ... setting timeouts.");
final HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
httpClientPolicy.setConnectionTimeout(0);
httpClientPolicy.setReceiveTimeout(0);
httpClientPolicy.setContentType("application/soap+xml");
httpConduit.setClient(httpClientPolicy);
retrieveAndStoreWSDL(address);
}
private void configureClientSideSSL(final HTTPConduit conduit, final String keyStorePath, final String trustpass) {
try {
final TLSClientParameters tlsParams = new TLSClientParameters();
tlsParams.setDisableCNCheck(true);
final KeyStore keyStore = KeyStore.getInstance("jceks");
final File truststore = new File(keyStorePath);
final FileInputStream stream = new FileInputStream(truststore);
keyStore.load(stream, trustpass.toCharArray());
final TrustManagerFactory trustFactory = TrustManagerFactory.getInstance("PKIX");
trustFactory.init(keyStore);
final TrustManager[] tm = trustFactory.getTrustManagers();
tlsParams.setTrustManagers(tm);
final KeyManagerFactory keyFactory = KeyManagerFactory.getInstance("PKIX");
keyFactory.init(keyStore, trustpass.toCharArray());
final KeyManager[] km = keyFactory.getKeyManagers();
tlsParams.setKeyManagers(km);
final FiltersType filter = new FiltersType();
final List<String> include = filter.getInclude();
include.add(".*");
include.add(".*_EXPORT_.*");
include.add(".*_EXPORT1024_.*");
include.add(".*_WITH_DES_.*");
include.add(".*_WITH_AES_.*");
include.add(".*_WITH_NULL_.*");
include.add(".*_RSA_WITH_AES_.*");
include.add(".*_DH_anon_.*");
tlsParams.setCipherSuitesFilter(filter);
conduit.setTlsClientParameters(tlsParams);
stream.close();
} catch (final Exception e) {
System.out.println("Security configuration failed with the following: " + e.getCause());
}
}
private void retrieveAndStoreWSDL(final String address) {
LOG.info(" ... retrieving the WSDL-file.");
final HttpClient httpclient = new HttpClient();
httpclient.getParams().setSoTimeout(0); // No timeout at all...in case of big wsdls
final GetMethod get = new GetMethod(address);
get.setQueryString("?wsdl");
try {
final int result = httpclient.executeMethod(get);
final String str = IOUtils.toString(get.getResponseBodyAsStream(), "UTF-8");
LOG.debug(" ... Response status code: " + result);
} catch (final Throwable e) {
LOG.debug("-", e);
LOG.error(e.getClass().getSimpleName() + " occurred during WSDL-retrieval. Won't store current WSDL.");
} finally {
get.releaseConnection();
}
}
public String helloReturn() throws Exception {
return "haha:" + client.handleStateDataRecipience("", "", "");
}
}
The Client is siarting up as well , however, the moment the client tries to retrieve the WSDL and/or tries to execute any of its methods i get:
javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
...
As I previously mentioned, everything works fine as long as I use http instead of https.
I don't think that the problem are the keystores as I can finally read them and get their keys by using e.g.
private static void displayKeys(String ksForm, String alias, char[] ksPass, char[] kePass, String keystore) throws Exception {
System.out
.println("---------------------------------------------------------------------------------------------------------------------------");
KeyStore keyStore = KeyStore.getInstance(ksForm);
keyStore.load(new FileInputStream(keystore), ksPass);
Key key = keyStore.getKey(alias, kePass);
if (key instanceof PrivateKey) {
System.out.println("Get private key : ");
System.out.println(key.toString());
java.security.cert.Certificate[] certs = keyStore.getCertificateChain(alias);
System.out.println("Certificate chain length : " + certs.length);
for (Certificate cert : certs) {
System.out.println(cert.toString());
}
} else {
System.out.println("Get public key : ");
System.out.println(key.toString());
}
System.out
.println("---------------------------------------------------------------------------------------------------------------------------");
}
Caused by: java.io.EOFException: SSL peer shut down incorrectly
Thanks in advance and kind regards.
So, I was finally able to figure it out.
Actually there were several Problems at hand
The created keystore itself was fine, the extracted (for client use) cert wasn't
Loading keystore and truststore in both, server and client, was a huge mistake, especially since I've used the same store/certs for both (for this I think WSS4J Interceptors and CallBackHandlers are necessary)
During several trial and error periods I also seems to have mixed up entry and store password.
Below I will give you the code for all the classes that I've used to get a fully running example.
Key And Cert Generation
As I always had problems with the SunAPI and its code examples for certificate creation I decided to use BouncyCastle instead.
Even though I previously decided to not use a 3rd party tool, I changed my mind due to the fact that I use this only for keystore/cert creation.
The class you are about to see is a slightly modified version of the answer from 'Maarten Bodewes' to this question:
How to store and reuse keypair in Java?
The class is pretty straight forward, hence no method comments were added...
package playground.TEST.cxf_soap;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStore.Entry;
import java.security.KeyStore.PrivateKeyEntry;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.UnrecoverableEntryException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Calendar;
import java.util.Date;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
public class BCCertUtils {
public static KeyPair generateKeyPair(int keySize, String keyAlgo, String secureAlgo) throws Exception {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(keyAlgo != null && !keyAlgo.trim().isEmpty() ? keyAlgo : "RSA");
keyGen.initialize(keySize, secureAlgo != null && !secureAlgo.trim().isEmpty() ? SecureRandom.getInstance(secureAlgo) : new SecureRandom());
KeyPair pair = keyGen.generateKeyPair();
return pair;
}
public static Certificate generateSelfSignedCertificate(KeyPair keyPair, String dn, String sigAlg, Date endDate)
throws OperatorCreationException, CertificateException {
// Setting bouncy castle provider to be able to create certs at all...
Provider bcProvider = new BouncyCastleProvider();
Security.addProvider(bcProvider);
X500Name dnName = new X500Name(dn);
// Using the current timestamp as the certificate serial number
BigInteger certSerialNum = new BigInteger(String.valueOf(System.currentTimeMillis()));
// Setting start date
Date startDate = Calendar.getInstance().getTime();
// Use appropriate signature algorithm based on your keyPair algorithm.
String sigAlgorithm = sigAlg == null || sigAlg.trim().isEmpty() ? "SHA256WithRSA" : sigAlg;
SubjectPublicKeyInfo certPubKey = SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded());
X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder(dnName, certSerialNum, startDate, endDate, dnName, certPubKey);
ContentSigner contentSigner = new JcaContentSignerBuilder(sigAlgorithm).setProvider(bcProvider).build(keyPair.getPrivate());
X509CertificateHolder certificateHolder = certBuilder.build(contentSigner);
return new JcaX509CertificateConverter().getCertificate(certificateHolder);
}
public static void storeToPKCS12File(String alias, Certificate selfCert, String filename, char[] ksPass, char[] kePass, PrivateKey privKey)
throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, OperatorCreationException {
KeyStore p12Store = createP12Store(alias, selfCert, privKey, kePass);
try (FileOutputStream fos = new FileOutputStream(filename)) {
p12Store.store(fos, ksPass);
}
}
public static byte[] storeToPKCS12ByteArray(String alias, Certificate selfCert, char[] ksPass, char[] kePass, PrivateKey privKey)
throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, OperatorCreationException {
KeyStore p12Store = createP12Store(alias, selfCert, privKey, kePass);
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
p12Store.store(bos, ksPass);
return bos.toByteArray();
}
}
private static KeyStore createP12Store(String alias, Certificate selfCert, PrivateKey privKey, char[] kePass)
throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
KeyStore p12KeyStore = KeyStore.getInstance("PKCS12");
p12KeyStore.load(null, null);
KeyStore.Entry entry = new PrivateKeyEntry(privKey, new Certificate[] { selfCert });
KeyStore.ProtectionParameter param = new KeyStore.PasswordProtection(kePass);
p12KeyStore.setEntry(alias, entry, param);
return p12KeyStore;
}
public static boolean moduliMatch(PublicKey originPubKey, PrivateKey certPrivKey) {
return ((RSAPublicKey) originPubKey).getModulus().equals(((RSAPrivateKey) certPrivKey).getModulus());
}
public static KeyPair loadKeysFromPKCS12File(String alias, String filename, char[] storePass, char[] entryPass) throws KeyStoreException,
NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, UnrecoverableEntryException {
KeyStore pkcs12KeyStore = KeyStore.getInstance("PKCS12");
try (FileInputStream fis = new FileInputStream(filename);) {
pkcs12KeyStore.load(fis, storePass);
}
return loadKeyPair(pkcs12KeyStore, alias, entryPass);
}
public static KeyPair loadKeysFromPKCS12ByteArray(String alias, byte[] storeBytes, char[] storePass, char[] entryPass) throws KeyStoreException,
NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, UnrecoverableEntryException {
KeyStore pkcs12KeyStore = KeyStore.getInstance("PKCS12");
try (ByteArrayInputStream bis = new ByteArrayInputStream(storeBytes);) {
pkcs12KeyStore.load(bis, storePass);
}
return loadKeyPair(pkcs12KeyStore, alias, entryPass);
}
private static KeyPair loadKeyPair(KeyStore ks, String alias, char[] entryPass)
throws NoSuchAlgorithmException, UnrecoverableEntryException, KeyStoreException {
KeyStore.ProtectionParameter param = new KeyStore.PasswordProtection(entryPass);
Entry entry = ks.getEntry(alias, param);
if (!(entry instanceof PrivateKeyEntry)) {
throw new KeyStoreException("That's not a private key!");
}
PrivateKeyEntry privKeyEntry = (PrivateKeyEntry) entry;
PublicKey publicKey = privKeyEntry.getCertificate().getPublicKey();
PrivateKey privateKey = privKeyEntry.getPrivateKey();
return new KeyPair(publicKey, privateKey);
}
public static Certificate loadCertFromPKCS12File(String alias, String filename, char[] storePass, char[] entryPass) throws KeyStoreException,
NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, UnrecoverableEntryException {
KeyStore pkcs12KeyStore = KeyStore.getInstance("PKCS12");
try (FileInputStream fis = new FileInputStream(filename);) {
pkcs12KeyStore.load(fis, storePass);
}
return loadCert(pkcs12KeyStore, alias, entryPass);
}
public static Certificate loadCertFromPKCS12ByteArray(String alias, byte[] storeBytes, char[] storePass, char[] entryPass)
throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException,
UnrecoverableEntryException {
KeyStore pkcs12KeyStore = KeyStore.getInstance("PKCS12");
try (ByteArrayInputStream bis = new ByteArrayInputStream(storeBytes);) {
pkcs12KeyStore.load(bis, storePass);
}
return loadCert(pkcs12KeyStore, alias, entryPass);
}
private static Certificate loadCert(KeyStore ks, String alias, char[] entryPass)
throws NoSuchAlgorithmException, UnrecoverableEntryException, KeyStoreException {
KeyStore.ProtectionParameter param = new KeyStore.PasswordProtection(entryPass);
Entry entry = ks.getEntry(alias, param);
if (!(entry instanceof PrivateKeyEntry)) {
throw new KeyStoreException("That's not a private key!");
}
PrivateKeyEntry privKeyEntry = (PrivateKeyEntry) entry;
return privKeyEntry.getCertificate();
}
public static void storeToPEMFile(Certificate pubCert, String certPath) throws IOException {
JcaPEMWriter pw = new JcaPEMWriter(new FileWriter(certPath));
pw.writeObject(pubCert);
pw.flush();
pw.close();
}
public static byte[] storeToPEMByteArray(Certificate pubCert) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(baos));
JcaPEMWriter pw = new JcaPEMWriter(writer);
pw.writeObject(pubCert);
pw.flush();
pw.close();
return baos.toByteArray();
}
}
Starter Class
This is the code in which I will actually generate the keys and startup the server and the client, as well as using the clients' methods.
package playground.test.cxf_soap;
import java.security.KeyPair;
import java.security.cert.Certificate;
import java.util.Calendar;
public class Starter {
public static void main(String[] args) {
try {
boolean enableSSL = true;
char[] entryPass = "entryPass".toCharArray();
char[] storePass = "storePass".toCharArray();
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.YEAR, 100);
// Server Store and Client cert.
KeyPair srvKeyPair = BCCertUtils.generateKeyPair(2048, "RSA", "SHA1PRNG");
Certificate srvPrivCert = BCCertUtils.generateSelfSignedCertificate(srvKeyPair, "CN=Test", "SHA256WithRSA", calendar.getTime());
byte[] srvStoreBytes = BCCertUtils.storeToPKCS12ByteArray("alias", srvPrivCert, storePass, entryPass, srvKeyPair.getPrivate());
KeyPair SvrCertKeys = BCCertUtils.loadKeysFromPKCS12ByteArray("alias", srvStoreBytes, storePass, entryPass);
if (!BCCertUtils.moduliMatch(srvKeyPair.getPublic(), SvrCertKeys.getPrivate())) {
System.err.println("ARRGL");
return;
}
Certificate clientCert = BCCertUtils.loadCertFromPKCS12ByteArray("alias", srvStoreBytes, storePass, entryPass);
byte[] clientCertBytes = BCCertUtils.storeToPEMByteArray(clientCert);
Server server = new Server(443, enableSSL, srvStoreBytes, storePass, entryPass);
while (!server.isRunning()) {
Thread.sleep(10);
}
Client client = new Client("https://localhost:" + 443 + "/signtest/", enableSSL, clientCertBytes);
System.out.println("Hello SOAP-Server :)");
System.out.println(" -> " + client.helloReturn("Stahler"));
System.out.println("Could you tell me if it is working?");
System.out.println(" -> " + client.isItWorking());
System.out.println("Awww finally, thank you server and goodbye.");
System.out.println(" -> " + client.gbyeReturn("Stahler"));
System.exit(0);
} catch (Throwable t) {
t.printStackTrace();
}
}
}
Server class
Following now I will show you my Server class In which I import the previously created PKCS12 store and adjust TLS Settings to work with the client.
package playground.mstahl.cxf_soap;
import java.io.ByteArrayInputStream;
import java.security.KeyStore;
import java.util.Arrays;
import java.util.List;
import javax.jws.WebService;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import org.apache.cxf.configuration.jsse.TLSServerParameters;
import org.apache.cxf.configuration.security.ClientAuthentication;
import org.apache.cxf.configuration.security.FiltersType;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
import org.apache.cxf.transport.http_jetty.JettyHTTPServerEngineFactory;
public class Server extends Thread {
private boolean isRunning = false;
#WebService(name = "SoapService", serviceName = "SoapService", endpointInterface = "playground.mstahl.cxf_soap.SoapServiceDefinition")
private static final class ServerImpl implements SoapServiceDefinition {
#Override
public String sayHelloToMe(String caller) throws Exception {
return "oh Hello " + caller + ".";
}
#Override
public String askFunctionality() throws Exception {
return "Well, as I am answering I guess its working...duh";
}
#Override
public String sayGoodbyeToMe(String caller) throws Exception {
return "Goodbye doucheb...i mean..." + caller + ".";
}
}
private final int usedPort;
private final byte[] storeBytes;
private final char[] storePass;
private final char[] entryPass;
private final boolean sslEnabled;
public Server(int port, boolean sslEnabled, byte[] storeBytes, char[] storePass, char[] entryPass) {
super("CXF-SOAP-Playground");
setDaemon(true);
usedPort = port;
this.sslEnabled = sslEnabled;
this.storeBytes = storeBytes;
this.storePass = storePass;
this.entryPass = entryPass;
start();
}
#Override
public void run() {
System.out.println(" ... creating factory.");
JaxWsServerFactoryBean sf = new JaxWsServerFactoryBean();
System.out.println(" ... setting address and implementing service.");
sf.setAddress(String.format("http" + (sslEnabled ? "s" : "") + "://localhost:%d/signtest/", Integer.valueOf(usedPort)));
sf.setServiceClass(ServerImpl.class);
System.out.println(" ... setting up service bean.");
ServerImpl serviceBean = new ServerImpl();
sf.setServiceBean(serviceBean);
if (sslEnabled) {
try {
JettyHTTPServerEngineFactory factory = sf.getBus().getExtension(JettyHTTPServerEngineFactory.class);
factory.setTLSServerParametersForPort(usedPort, getTLSServerParameters());
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println(" ... starting actual SOAP-server.");
org.apache.cxf.endpoint.Server server = sf.create();
Endpoint endpoint = server.getEndpoint();
String endpointAddr = endpoint.getEndpointInfo().getAddress();
System.out.println("Server started at " + endpointAddr);
if (!server.isStarted()) {
return;
}
isRunning = true;
System.out.println("... done.");
while (!isInterrupted()) {
try {
Thread.sleep(100);
} catch (Exception e) {
}
}
System.out.println("... stopping actual SOAP-server.");
server.stop();
System.out.println("... destroying its remnants.");
server.destroy();
}
public boolean isRunning() {
return isRunning;
}
private final TLSServerParameters getTLSServerParameters() {
TLSServerParameters tlsParams = null;
try {
// 1 - Load key store
KeyStore localKeyStore = KeyStore.getInstance("PKCS12");
localKeyStore.load(new ByteArrayInputStream(storeBytes), storePass);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(localKeyStore, entryPass);
// 2 - Add the new keyManager to the tls settings.
tlsParams = new TLSServerParameters();
tlsParams.setKeyManagers(kmf.getKeyManagers());
// 3 - Adjust cipher suite filters
final List<String> cipherSuites = Arrays.asList(SSLContext.getDefault().getSocketFactory().getSupportedCipherSuites());
System.out.println(String.format("Suppored cipher suites : %s", cipherSuites.toString()));
final FiltersType filter = new FiltersType();
final List<String> include = filter.getInclude();
include.add(".*");
include.add(".*_EXPORT1024_.*");
include.add(".*_WITH_DES_.*");
include.add(".*_WITH_AES_.*");
include.add(".*_WITH_NULL_.*");
include.add(".*_RSA_WITH_AES_.*");
include.add(".*_DH_anon_.*");
tlsParams.setCipherSuitesFilter(filter);
// 4 - Disable client authentication
final ClientAuthentication ca = new ClientAuthentication();
ca.setRequired(false);
ca.setWant(false);
tlsParams.setClientAuthentication(ca);
} catch (final Exception e) {
e.printStackTrace();
System.err.println("Security configuration failed with the following: " + e.getMessage() + " " + e.getCause());
tlsParams = null;
}
return tlsParams;
}
}
Client Class
Last but not least, a small client class in which I imported the certificate which I previously exported from the servers keystore.
package playground.mstahl.cxf_soap;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.security.KeyStore;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.List;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManagerFactory;
import org.apache.commons.io.IOUtils;
import org.apache.cxf.configuration.jsse.TLSClientParameters;
import org.apache.cxf.configuration.security.FiltersType;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.apache.System.out.println4j.System.out.printlnger;
public class Client {
private static SoapServiceDefinition client;
public Client(String address, boolean sslEnabled, byte[] remoteCertBytes) {
System.out.println(" ... creating service factory.");
final JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(SoapServiceDefinition.class);
System.out.println(" ... setting host address to '" + address + "'.");
factory.setAddress(address);
System.out.println(" ... creating actual SOAP-client.");
client = (SoapServiceDefinition) factory.create();
final HTTPConduit httpConduit = (HTTPConduit) ClientProxy.getClient(client).getConduit();
if (sslEnabled) {
System.out.println(" ... configuring SSL.");
configureClientSideSSL(httpConduit, remoteCertBytes);
System.out.println(" ... done.");
}
System.out.println(" ... setting timeouts.");
final HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
httpClientPolicy.setConnectionTimeout(0);
httpClientPolicy.setReceiveTimeout(0);
httpClientPolicy.setContentType("application/soap+xml");
httpConduit.setClient(httpClientPolicy);
try {
retrieveAndStoreWSDL(sslEnabled, address);
} catch (Exception e) {
e.printStackTrace();
}
}
private void configureClientSideSSL(final HTTPConduit conduit, byte[] remoteCertBytes) {
TLSClientParameters tlsParams = null;
try {
// 1 - Load the remote certificate
ByteArrayInputStream bis = new ByteArrayInputStream(remoteCertBytes);
X509Certificate remoteCert = (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(new BufferedInputStream(bis));
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null, null);
ks.setCertificateEntry(Integer.toString(1), remoteCert);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
// 2 - Add the new trustmanager to the tls settings.
tlsParams = new TLSClientParameters();
tlsParams.setTrustManagers(tmf.getTrustManagers());
// 3 - Disable CN check
tlsParams.setDisableCNCheck(true);
// 4 - Set default SSL-context (necessary for e.g. the wsdl retrieval)
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
SSLContext.setDefault(context);
final FiltersType filter = new FiltersType();
final List<String> include = filter.getInclude();
include.add(".*");
include.add(".*_EXPORT_.*");
include.add(".*_EXPORT1024_.*");
include.add(".*_WITH_DES_.*");
include.add(".*_WITH_AES_.*");
include.add(".*_WITH_NULL_.*");
include.add(".*_RSA_WITH_AES_.*");
include.add(".*_DH_anon_.*");
tlsParams.setCipherSuitesFilter(filter);
conduit.setTlsClientParameters(tlsParams);
} catch (final Exception e) {
e.printStackTrace();
System.out.println("Security configuration failed with the following: " + e.getCause());
}
}
private void retrieveAndStoreWSDL(boolean sslEnabled, final String address) throws Exception {
System.out.println(" ... retrieving the WSDL-file."); // TODO ssl enabled check (Necessary if we do this beforehand?)
URL wsdlUrl = new URL(address + "?wsdl");
URLConnection connection = wsdlUrl.openConnection();
HttpsURLConnection conn = (HttpsURLConnection) connection;
if (sslEnabled) {
conn.setHostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
}
conn.setRequestMethod("GET");
conn.connect();
String wsdl = IOUtils.toString(conn.getInputStream(), Charset.defaultCharset());
System.err.println(wsdl);
conn.disconnect();
}
public String helloReturn(String caller) throws Exception {
return client.sayHelloToMe(caller);
}
public String isItWorking() throws Exception {
return client.askFunctionality();
}
public String gbyeReturn(String caller) throws Exception {
return client.sayGoodbyeToMe(caller);
}
}
Thanks to everyone who read my question and thought of a possible solution.
Hopefully this can help others .
Kind regards

How to get the Policy Identifier and the Subject Type of Basic Constraints in a X509Certificate of java

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>

GPG decryptor doesn't work properly

I'm trying to write gpg encryptor/decryptor (code below). In first step program encrypts "#data1\n#data2\n#data3\n" string and in next step decrypts the array of bytes that decryptor returns. But... why text from decryptor is not the same as "#data1\n#data2\n#data3\n" ? Where did I missed something ? Thanks for your help.
package tests.crypto;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.util.Iterator;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.bouncycastle.openpgp.PGPUtil;
import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder;
import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyConverter;
import Decoder.BASE64Encoder;
public class GPGTest {
char[] pass = { 'p', 'a', 's', 's' };
public static void main(String[] args) throws Exception {
GPGTest gTest = new GPGTest();
gTest.setUpCipher();
}
public void setUpCipher() throws NoSuchAlgorithmException,
InvalidKeyException, IllegalBlockSizeException,
NoSuchProviderException, BadPaddingException,
NoSuchPaddingException {
System.out.println("--- setup cipher ---");
// public key
String publicKeyFilePath = "E:/Programs/Keys/GPG/Public/public.key";
File publicKeyFile = new File(publicKeyFilePath);
// secret key
String secretKeyFilePath = "E:/Programs/Keys/GPG/Secret/private.key";
File secretKeyFile = new File(secretKeyFilePath);
// security provider
Security.addProvider(new BouncyCastleProvider());
try {
// Read the public key
FileInputStream pubIn = new FileInputStream(publicKeyFile);
PGPPublicKey pgpPubKey = readPublicKey(pubIn);
PublicKey pubKey = new JcaPGPKeyConverter().getPublicKey(pgpPubKey);
// Read the private key
FileInputStream secretIn = new FileInputStream(secretKeyFile);
PGPSecretKey pgpSecretKey = readSecretKey(secretIn);
PGPPrivateKey pgpPrivKey = pgpSecretKey
.extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(
new BcPGPDigestCalculatorProvider()).build(pass));
PrivateKey privKey = new JcaPGPKeyConverter()
.getPrivateKey(pgpPrivKey);
Cipher cipher = Cipher.getInstance("RSA");
// Encrypt data
byte[] encData = encryptData(cipher, pubKey, new String(
"#data1\n#data2\n#data3\n").getBytes());
String cryptString = new BASE64Encoder().encode(encData);
System.out.println("\n\nEncrypted data=" + cryptString);
// Decrypt data
byte[] decData = decryptData(cipher, privKey, encData);
String decryptString = new BASE64Encoder().encode(decData);
System.out.println("\n\nDecrypted data=" + decryptString);
} catch (Exception e) {
System.out.println("Setup cipher exception");
System.out.println(e.toString());
}
}
public byte[] encryptData(Cipher cipher, PublicKey pubKey, byte[] clearText) {
byte[] encryptedBytes = null;
try {
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
encryptedBytes = cipher.doFinal(clearText);
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return encryptedBytes;
}
public byte[] decryptData(Cipher cipher, PrivateKey privKey, byte[] encryptedText) {
byte[] decryptedBytes = null;
try {
cipher.init(Cipher.DECRYPT_MODE, privKey);
decryptedBytes = cipher.doFinal(encryptedText);
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return decryptedBytes;
}
private static PGPPublicKey readPublicKey(InputStream input) throws IOException, PGPException {
PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(input));
Iterator<?> keyRingIter = pgpPub.getKeyRings();
while (keyRingIter.hasNext()) {
PGPPublicKeyRing keyRing = (PGPPublicKeyRing) keyRingIter.next();
Iterator<?> keyIter = keyRing.getPublicKeys();
while (keyIter.hasNext()) {
PGPPublicKey key = (PGPPublicKey) keyIter.next();
if (key.isEncryptionKey()) {
return key;
}
}
}
throw new IllegalArgumentException(
"Can't find encryption key in key ring.");
}
private static PGPSecretKey readSecretKey(InputStream input) throws IOException, PGPException {
PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(input));
Iterator<?> keyRingIter = pgpSec.getKeyRings();
while (keyRingIter.hasNext()) {
PGPSecretKeyRing keyRing = (PGPSecretKeyRing) keyRingIter.next();
Iterator<?> keyIter = keyRing.getSecretKeys();
while (keyIter.hasNext()) {
PGPSecretKey key = (PGPSecretKey) keyIter.next();
if (key.isSigningKey()) {
return key;
}
}
}
throw new IllegalArgumentException(
"Can't find signing key in key ring.");
}
}
They aren't the same because you are base-64 encoding the results of the decryption, rather than decoding it as text. Do this instead:
byte[] decData = decryptData(cipher, privKey, encData);
System.out.println("\n\nDecrypted data=" + new String(decData));
It is poor practice to use the platform default character encoding. Instead, you should convert text to bytes with with specific encoding, and use the same coding when decoding the bytes.
byte[] plaintext = "#data1\n#data2\n#data3\n").getBytes(StandardCharsets.UTF_8);
...
String recovered = new String(decData, StandardCharsets.UTF_8);

Categories