Remove root ca from a chain (Signature) - java

I need to remove the root ca from a certificate chain. What is the best way to do that? I found a way to read the values but they can't be deleted.

You have not made it clear what you want, but here is a simple example to remove all certs that appear self-signed (same issuer and subject names -- it would better to actually verify the signature, feel free to add that code) from the special CMS structure used to convey certificate chains. This code uses the Bouncycastle PKIX library, but it's possible to do this with a few more lines of code using only the Bouncycastle core library.
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.util.CollectionStore;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.function.Predicate;
public class PKCS7Certs {
private static final String P7_CERT_FILENAME = "stackexchange-com-chain.p7b";
private static final String OUT_FILENAME = "stackexchange-com-chain-no-root.p7b";
public static void main(String[] args) throws Exception {
Path p7In = Paths.get(P7_CERT_FILENAME);
Path p7Out = Paths.get(OUT_FILENAME);
removeRoot(p7In, p7Out);
}
private static void removeRoot(Path p7In, Path p7Out) throws Exception{
CMSSignedData contentInfo = new CMSSignedData(Files.newInputStream(p7In));
Collection<X509CertificateHolder> certs = contentInfo.getCertificates().getMatches(null);
// Delete the root cert(s)
certs.removeIf(new Predicate<X509CertificateHolder>() {
#Override
public boolean test(X509CertificateHolder cert) {
return ! cert.getIssuer().equals(cert.getSubject());
}
});
// create a new SignedData ContentInfo with the non-root certs
CollectionStore newStore = new CollectionStore(certs);
CMSSignedData newCI = CMSSignedData.replaceCertificatesAndCRLs(
contentInfo,
newStore,
contentInfo.getAttributeCertificates(),
contentInfo.getCRLs()
);
Files.write(p7Out, newCI.getEncoded());
}
}

Other possibility to remove the root ca from a signature:
private byte[] removeRoot(byte[] b) throws CMSException, IOException {
CMSSignedData signature = new CMSSignedData(b);
Store<X509CertificateHolder> cs = signature.getCertificates();
Collection<X509CertificateHolder> certificates = cs.getMatches(new Selector<>() {
#Override
public boolean match(final X509CertificateHolder obj) {
return !Objects.equals(obj.getIssuer(), obj.getSubject());
}
#Override
public Object clone() {
return null;
}
});
final CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
generator.addSigners(signature.getSignerInfos());
generator.addAttributeCertificates(signature.getAttributeCertificates());
certificates.forEach(o -> {
try {
generator.addCertificate(o);
} catch (CMSException e) {
throw new RuntimeException(e);
}
});
CMSSignedData signedData = generator.generate(signature.getSignedContent(), true);
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (ASN1InputStream asn1 = new ASN1InputStream(signedData.getEncoded())) {
DEROutputStream dos = new DEROutputStream(out);
dos.writeObject(asn1.readObject());
}
return out.toByteArray();
}

Related

HTTPS Volley Invalid header issue

Before all : if you don't know the exact answer so just give me advice how to check. Thanks
I have alreary tried a lot of different way how to implement ssl to my volley request but without success.
I can not understand way I get this error
ResponseJsonString = <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Bad Request</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Bad Request - Invalid Header</h2>
<hr><p>HTTP Error 400. The request has an invalid header name.</p>
</BODY></HTML>
So step by step my code implementation
This is how I get the volley queue
mRequestQueue = Volley.newRequestQueue(this, new SslHurlStuck(SslUtils.KEYSTORE, SslUtils.PASSWORD_SSL, this));
there is my SslHurlStuck
package utils.ssl;
import android.content.Context;
import android.util.Log;
import com.android.volley.toolbox.HurlStack;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
import utils.global.AppUtils;
public class SslHurlStuck extends HurlStack
{
private final static String TAG = SslHurlStuck.class.getSimpleName();
private String mTrustStoreAssetName;
private String mTrustStorePassword;
private Context mContext;
public SslHurlStuck(final String iTrustStoreAssetName, final String iTrustStorePassword, Context iContext)
{
super();
mTrustStoreAssetName = iTrustStoreAssetName;
mTrustStorePassword = iTrustStorePassword;
mContext = iContext;
}
#Override
protected HttpURLConnection createConnection(URL url) throws IOException
{
HttpsURLConnection urlConnection = null;
try
{
urlConnection = new PinnedCertificateHttpsURLConnectionFactory(mContext).createHttpsURLConnection(url.toString(), mTrustStoreAssetName, mTrustStorePassword);
}
catch (Throwable iThrowable)
{
AppUtils.printLog(Log.ERROR, TAG, iThrowable.getMessage());
}
return urlConnection;
}
}
And eventually there is my PinnedCertificateHttpsURLConnectionFactory
package utils.ssl;
import android.content.Context;
import android.util.Log;
import java.net.URL;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import utils.global.AppUtils;
import webServices.global.RequestStringBuilder;
public class PinnedCertificateHttpsURLConnectionFactory
{
private final static String TAG = PinnedCertificateHttpsURLConnectionFactory.class.getSimpleName();
private final Context mContext;
public PinnedCertificateHttpsURLConnectionFactory(Context iContext)
{
mContext = iContext;
}
HttpsURLConnection createHttpsURLConnection(String urlString, final String iTrustStoreAssetName, final String iTrustStorePassword) throws Throwable
{
// Initialize the trust manager factory instance with our trust store
// as source of certificate authorities and trust material.
KeyStore trustStore = new TrustStoreFactory(iTrustStoreAssetName, iTrustStorePassword, mContext).createTrustStore();
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(tmfAlgorithm);
trustManagerFactory.init(trustStore);
// Initialize the SSL context.
TrustManager[] wrappedTrustManagers = getWrappedTrustManagers(trustManagerFactory.getTrustManagers());
SSLContext sslContext = SSLContext.getInstance(SslUtils.PROTOCOL_TLS);
sslContext.init(null, wrappedTrustManagers, null);
// Create the https URL connection.
URL url = new URL(urlString);
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());
urlConnection.setHostnameVerifier(getHostnameVerifier());
return urlConnection;
}
// Let's assume your server app is hosting inside a server machine
// which has a server certificate in which "Issued to" is "localhost",for example.
// Then, inside verify method you can verify "localhost".
// If not, you can temporarily return true
private HostnameVerifier getHostnameVerifier()
{
return new HostnameVerifier()
{
#Override
public boolean verify(String hostname, SSLSession session)
{
HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
String localHost = SslUtils.SSL_LOCAL_HOST_DEV;
if (RequestStringBuilder.isEnvironmentProd())
{
localHost = SslUtils.SSL_LOCAL_HOST_PROD;
}
return hv.verify(localHost, session);
// return hv.verify("localhost", session);
// return true;
}
};
}
private TrustManager[] getWrappedTrustManagers(TrustManager[] trustManagers)
{
final X509TrustManager originalTrustManager = (X509TrustManager) trustManagers[0];
final X509TrustManager x509TrustManager = new X509TrustManager()
{
public X509Certificate[] getAcceptedIssuers()
{
return originalTrustManager.getAcceptedIssuers();
}
public void checkClientTrusted(X509Certificate[] certs, String authType)
{
try
{
if (certs != null && certs.length > 0)
{
for (X509Certificate cer : certs)
{
cer.checkValidity();
}
}
else
{
originalTrustManager.checkClientTrusted(certs, authType);
}
}
catch (CertificateException e)
{
AppUtils.printLog(Log.ERROR, TAG, "checkClientTrusted" + e.toString());
}
}
public void checkServerTrusted(X509Certificate[] certs, String authType)
{
try
{
if (certs != null && certs.length > 0)
{
for (X509Certificate cer : certs)
{
cer.checkValidity();
}
}
else
{
originalTrustManager.checkServerTrusted(certs, authType);
}
}
catch (CertificateException e)
{
AppUtils.printLog(Log.ERROR, TAG, "checkServerTrusted" + e.toString());
}
}
};
return new TrustManager[] {x509TrustManager};
}
}
And last one TrustStoreFactory
public class TrustStoreFactory
{
private String mTrustStoreAssetName;
private String mTrustStorePassword;
private Context mContext;
public TrustStoreFactory(final String iTrustStoreAssetName, final String iTrustStorePassword, final Context iContext)
{
mTrustStoreAssetName = iTrustStoreAssetName;
mTrustStorePassword = iTrustStorePassword;
mContext = iContext;
}
KeyStore createTrustStore() throws Throwable
{
// Retrieve the trust store file from the assets.
InputStream inputStream = mContext.getAssets().open(mTrustStoreAssetName);
try
{
// Create a key store with the retrieved input stream.
KeyStore trustStore = KeyStore.getInstance(SslUtils.KEYSTORE_EXTENSION_BKS);
trustStore.load(inputStream, mTrustStorePassword.toCharArray());
return trustStore;
}
finally
{
inputStream.close();
}
}
}
So, question is , what am I doing wrong?
My keystore consist 2 cer files, I tried different combinations to add the cer to the keystore... but nothing was changed.
Actually I don't think that there is a problems with a code, I think some issue with certificates , but I can not understand what exactly, and how to fix it
And also what is intresting that in iOS the same ssl checking work in another way, we just need to get certificate from response and then getPublicKey() on it, and compare if public key from response certificate equal to certificate public key that consist within app... But in android it is much more difficult...
Feel free to ask
So eventyally in my case, I don't know why , but I just deleted Content-type header with the value from the response, and all is ok.
My answer was found here
Android Volley gives me 400 error
The Content-Type header is not treated the same way as other headers by Volley. In particular, overriding getHeaders() to change the content type does not always work. Check this ans for more information
Try this
headers.put("Content-Type", "application/json");

Java 8 cannot load its cacerts in FIPS. Exception "no such provider: SunEC"

My server was using java 7 and is running fine in FIPS mode. Now we are upgrading to jre8 and the following exception is coming during the startup while loading cacerts.
java.lang.RuntimeException: java.security.NoSuchProviderException: no such provider: SunEC
at sun.security.util.ECUtil.getKeyFactory(ECUtil.java:96)
at sun.security.util.ECUtil.decodeX509ECPublicKey(ECUtil.java:102)
at sun.security.pkcs11.P11ECKeyFactory.engineGeneratePublic(P11ECKeyFactory.java:170)
at java.security.KeyFactory.generatePublic(KeyFactory.java:334)
at sun.security.x509.X509Key.buildX509Key(X509Key.java:223)
at sun.security.x509.X509Key.parse(X509Key.java:170)
at sun.security.x509.CertificateX509Key.<init>(CertificateX509Key.java:75)
at sun.security.x509.X509CertInfo.parse(X509CertInfo.java:667)
at sun.security.x509.X509CertInfo.<init>(X509CertInfo.java:167)
at sun.security.x509.X509CertImpl.parse(X509CertImpl.java:1806)
at sun.security.x509.X509CertImpl.<init>(X509CertImpl.java:195)
at sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:99)
at java.security.cert.CertificateFactory.generateCertificate(CertificateFactory.java:339)
at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:747)
at sun.security.provider.JavaKeyStore$JKS.engineLoad(JavaKeyStore.java:55)
at java.security.KeyStore.load(KeyStore.java:1433)
at org.apache.commons.ssl.KeyStoreBuilder.tryJKS(KeyStoreBuilder.java:476)
at org.apache.commons.ssl.KeyStoreBuilder.parse(KeyStoreBuilder.java:383)
at org.apache.commons.ssl.TrustMaterial.<init>(TrustMaterial.java:212)
at org.apache.commons.ssl.TrustMaterial.<init>(TrustMaterial.java:165)
at org.apache.commons.ssl.TrustMaterial.<init>(TrustMaterial.java:170)
at org.apache.commons.ssl.TrustMaterial.<init>(TrustMaterial.java:175)
at org.apache.commons.ssl.TrustMaterial.<clinit>(TrustMaterial.java:88)
at org.opensaml.xml.security.x509.X509Util.decodeCertificate(X509Util.java:317)
Caused by: java.security.NoSuchProviderException: no such provider: SunEC
at sun.security.jca.GetInstance.getService(GetInstance.java:83)
at sun.security.jca.GetInstance.getInstance(GetInstance.java:206)
at java.security.KeyFactory.getInstance(KeyFactory.java:211)
at sun.security.util.ECUtil.getKeyFactory(ECUtil.java:94)
The only modification i made is to add TLSv1.2 to jdk.tls.disabledAlgorithms=SSLv3,TLSv1.2 since NSS is not supporting TLSv1.2.
I was able to load the same in jre7u72 builds and i see that the sunpkcs11.jar is modified in java 8. It shouldnt be a cacerts issue since i copied the java7 cacerts to java8 and the problem still remains.
Has anyone seen this issue before? Should it be a java bug?
=== EDIT ===
Opened a java 8 bug. I wrote a tool which ran against jre7 with success and failed with jre8.
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.Provider;
import java.security.Security;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import sun.security.provider.Sun;
import sun.security.rsa.SunRsaSign;
/**
* Before running the tool run the following in your Linux box.
*
1. export LD_LIBRARY_PATH=/usr/lib64
2. mkdir /tmp/fips/nssdb
3. modutil -create -dbdir /tmp/fips/nssdb/
4. modutil -fips true -dbdir /tmp/fips/nssdb
5. modutil -changepw "NSS FIPS 140-2 Certificate DB" -dbdir /tmp/fips/nssdb
(Give a strong password like password1!)
* #author atulsm#gmail.com
*
*/
public class TestKeyStoreFIPS {
public static final String NSS_LIB_DIR_PROP = "nss.lib";
public static final String NSS_DB_DIR_PROP = "nss.db";
public static final String SUN_JSSE = "SunJSSE";
public static List<String> disabledAlgs = new ArrayList<String>();
private static final Logger logger = Logger.getLogger(TestKeyStoreFIPS.class.getName());
/**
* #param args
*/
public static void main(String[] args) throws Exception{
if(args.length != 2){
System.out.println("Usage eg: java -Dnss.lib=/usr/lib64 -Dnss.db=/tmp/fips/nssdb -Djavax.net.ssl.keyStorePassword=password1! TestKeyStoreFIPS /tmp/jre8/lib/security/cacerts changeit");
System.exit(1);
}
enablePkcs11Jsse(System.getProperty(NSS_LIB_DIR_PROP), System.getProperty(NSS_DB_DIR_PROP));
testFips();
String file = args[0];
char[] keystorePassword = args[1].toCharArray();
FileInputStream keystoreStream = new FileInputStream(file);
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(keystoreStream, keystorePassword);
Enumeration<String> aliases = keyStore.aliases();
while(aliases.hasMoreElements()){
String alias = aliases.nextElement();
System.out.println(alias + " : " + keyStore.getCertificate(alias).getType());
}
}
private static void testFips(){
String keyPass = System.getProperty("javax.net.ssl.keyStorePassword");
KeyStore store;
try {
store = KeyStore.getInstance("PKCS11");
if (keyPass != null) {
store.load(null, keyPass.toCharArray());
} else {
store.load(null, null);
}
System.out.println("FIPS test success");
} catch (Throwable e) {
e.printStackTrace();
store = null;
System.out.println("FIPS test failed");
}
}
public static void enablePkcs11Jsse( String libDir, String dbDir) throws Exception {
removeAllProviders();
Provider nss = getNSSFIPSProvider( libDir, dbDir);
removeDisabledAlgos(nss);
Security.insertProviderAt(nss, 1);
Provider sunJsse = new com.sun.net.ssl.internal.ssl.Provider(nss);
removeDisabledAlgos(sunJsse);
Security.insertProviderAt(sunJsse,2);
Sun sun = new Sun();
removeDisabledAlgos(sun);
Security.insertProviderAt(sun,3);
SunRsaSign sunrsa = new SunRsaSign();
removeDisabledAlgos(sunrsa);
Security.insertProviderAt(sunrsa,4);
}
private static Provider getNSSFIPSProvider( String libDir, String dbDir) throws Exception {
if(libDir == null || dbDir == null) {
throw new Exception(NSS_LIB_DIR_PROP + " or " + NSS_DB_DIR_PROP + " not set.");
}
Properties props = new Properties();
props.put("name", "NSSfips");
props.put("nssLibraryDirectory", libDir);
props.put("nssSecmodDirectory", dbDir);
props.put("nssModule", "fips");
props.put("nssDbMode", "readWrite");
return createProvider(props);
}
private static Provider createProvider(Properties props) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
props.store(out, null);
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
Provider ret = new sun.security.pkcs11.SunPKCS11(in);
if (logger.isLoggable(Level.FINE)) {
// Log all of the registered services
for (Map.Entry<Object, Object> entry : ret.entrySet()) {
logger.log(Level.FINE, "{0} = {1}", new Object[]{entry.getKey(), entry.getValue()});
}
}
return ret;
}
private static void removeAllProviders(){
Provider[] providers = Security.getProviders();
for(Provider prov : providers){
Security.removeProvider(prov.getName());
}
}
private static void removeDisabledAlgos(Provider provider){
for(String alg : disabledAlgs){
if(provider.getProperty(alg) != null){
logger.info("Removing algorithm " + alg + " from provider " + provider);
provider.remove(alg);
}
}
}
}
While i explore other options, one approach which worked is to copy one of my truststores as jre/lib/security/jssecacerts. I see that the code is giving precedence to jssecacerts than cacerts and its working fine for now.

Java: Overriding function to disable SSL certificate check

The web service is rest over SSL and it has self signed certificate, hosted in remote system.I have already created a client accessing that web service. This is done by adding the certificate to the key store programatically.
Now I heard that, it is not necessary to add certificate to key store for accesing a self signed web service. Instead we can disable the certificate check by overriding some methods. Is this true? Which are those methods? Please help.
This should be sufficient. I use this when testing code against testing and staging servers where we don't have properly signed certificates. However, you should really really strongly consider getting a valid SSL certificate on your production server. Nobody wants to be wiretapped and have their privacy violated.
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, new TrustManager[] { new TrustAllX509TrustManager() }, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier( new HostnameVerifier(){
public boolean verify(String string,SSLSession ssls) {
return true;
}
});
And this.
import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;
/**
* DO NOT USE IN PRODUCTION!!!!
*
* This class will simply trust everything that comes along.
*
* #author frank
*
*/
public class TrustAllX509TrustManager implements X509TrustManager {
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkClientTrusted(java.security.cert.X509Certificate[] certs,
String authType) {
}
public void checkServerTrusted(java.security.cert.X509Certificate[] certs,
String authType) {
}
}
Best of luck!
===UPDATE===
I just wanted to point out that there's a service called Let's Encrypt which automates the process of generating and setting up SSL/TLS certificates recognised by virtually everybody, and it's absolutely free!
Ignoring certs on a per-connection basis is much safer since any other code will still use the secure defaults.
The following code:
Overrides the trust manager and hostname verifier on a per-connection basis.
Reuses the SSLSocketFactory in order to support persistent connections, bypassing the expensive SSL handshake for repeated requests to the same server.
As others have stated, this should only be used for testing, and/or for internal systems communicating with other internal systems.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class TestPersistentConnection
{
private static SSLSocketFactory sslSocketFactory = null;
/**
* Use the VM argument <code>-Djavax.net.debug=ssl</code> for SSL specific debugging;
* the SSL handshake will appear a single time when connections are re-used, and multiple
* times when they are not.
*
* Use the VM <code>-Djavax.net.debug=all</code> for all network related debugging, but
* note that it is verbose.
*
* #throws Exception
*/
public static void main(String[] args) throws Exception
{
//URL url = new URL("https://google.com/");
URL url = new URL("https://localhost:8443/");
// Disable first
request(url, false);
// Enable; verifies our previous disable isn't still in effect.
request(url, true);
}
public static void request(URL url, boolean enableCertCheck) throws Exception {
BufferedReader reader = null;
// Repeat several times to check persistence.
System.out.println("Cert checking=["+(enableCertCheck?"enabled":"disabled")+"]");
for (int i = 0; i < 5; ++i) {
try {
HttpURLConnection httpConnection = (HttpsURLConnection) url.openConnection();
// Normally, instanceof would also be used to check the type.
if( ! enableCertCheck ) {
setAcceptAllVerifier((HttpsURLConnection)httpConnection);
}
reader = new BufferedReader(new InputStreamReader(httpConnection.getInputStream()), 1);
char[] buf = new char[1024];
StringBuilder sb = new StringBuilder();
int count = 0;
while( -1 < (count = reader.read(buf)) ) {
sb.append(buf, 0, count);
}
System.out.println(sb.toString());
reader.close();
} catch (IOException ex) {
System.out.println(ex);
if( null != reader ) {
reader.close();
}
}
}
}
/**
* Overrides the SSL TrustManager and HostnameVerifier to allow
* all certs and hostnames.
* WARNING: This should only be used for testing, or in a "safe" (i.e. firewalled)
* environment.
*
* #throws NoSuchAlgorithmException
* #throws KeyManagementException
*/
protected static void setAcceptAllVerifier(HttpsURLConnection connection) throws NoSuchAlgorithmException, KeyManagementException {
// Create the socket factory.
// Reusing the same socket factory allows sockets to be
// reused, supporting persistent connections.
if( null == sslSocketFactory) {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, ALL_TRUSTING_TRUST_MANAGER, new java.security.SecureRandom());
sslSocketFactory = sc.getSocketFactory();
}
connection.setSSLSocketFactory(sslSocketFactory);
// Since we may be using a cert with a different name, we need to ignore
// the hostname as well.
connection.setHostnameVerifier(ALL_TRUSTING_HOSTNAME_VERIFIER);
}
private static final TrustManager[] ALL_TRUSTING_TRUST_MANAGER = new TrustManager[] {
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
}
};
private static final HostnameVerifier ALL_TRUSTING_HOSTNAME_VERIFIER = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
}
Many thanks to:
http://runtime32.blogspot.com/2008/11/let-java-ssl-trust-all-certificates.html
TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
GetCustomerPhone http = new GetCustomerPhone();
System.out.println("Processing..");
try{
http.sendPost();
}
catch(Exception e){
e.printStackTrace();
}
}
I think it will working fine.because it fine of me...

Verify if a PDF is digitally signed with iText

As the title says I want to know if a given PDF file is already digitally signed.
I used iText to sign it but I'm not able to know if it is already signed to eventually resign it or perform other actions.
Is there a way to do it simply (possibly using iText)?
Using iText:
PdfReader reader = new PdfReader(...);
AcroFields acroFields = reader.getAcroFields();
List<String> signatureNames = acroFields.getSignatureNames();
Now signatureNames contains the names of all reachable signature fields containing signatures, cf. the JavaDoc:
/**
* Gets the field names that have signatures and are signed.
*
* #return the field names that have signatures and are signed
*/
public ArrayList<String> getSignatureNames()
If you are using newer iText version like 5.5.x here is a full working example how you can check a digitally signed PDF (a lot of useful development and changes have been done in iText since version 2.1.7):
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.security.PdfPKCS7;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.Principal;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DigitalSignatureCheck {
private static final Logger LOGGER = LoggerFactory.getLogger(DigitalSignatureCheck.class);
public static final boolean verifySignature(PdfReader pdfReader)
throws GeneralSecurityException, IOException {
boolean valid = false;
AcroFields acroFields = pdfReader.getAcroFields();
List<String> signatureNames = acroFields.getSignatureNames();
if (!signatureNames.isEmpty()) {
for (String name : signatureNames) {
if (acroFields.signatureCoversWholeDocument(name)) {
PdfPKCS7 pkcs7 = acroFields.verifySignature(name);
valid = pkcs7.verify();
String reason = pkcs7.getReason();
Calendar signedAt = pkcs7.getSignDate();
X509Certificate signingCertificate = pkcs7.getSigningCertificate();
Principal issuerDN = signingCertificate.getIssuerDN();
Principal subjectDN = signingCertificate.getSubjectDN();
LOGGER.info("valid = {}, date = {}, reason = '{}', issuer = '{}', subject = '{}'",
valid, signedAt.getTime(), reason, issuerDN, subjectDN);
break;
}
}
}
return valid;
}
private static void validate(String name)
throws IOException, GeneralSecurityException {
InputStream is = DigitalSignatureCheck.class.getClassLoader()
.getResourceAsStream(name);
PdfReader reader = new PdfReader(is);
boolean ok = verifySignature(reader);
LOGGER.info("'{}' is {}signed", name, ok ? "" : "NOT ");
}
public static void main(String[] args) throws Exception {
validate("any.pdf"); // if placed in resources' root
}
}
Using the LOGGER is just for displaying the result.
I had similar problem but I'm using itext 7 and there is no
PdfReader reader = new PdfReader(...);
AcroFields acroFields = reader.getAcroFields();
in current version.
So I have used this solution [UPDATED]
private boolean hasSignatures(final PdfDocument pdfDocument) {
final List<String> signatureNames = new SignatureUtil(pdfDocument).getSignatureNames();
return !signatureNames.isEmpty();
}
One example here
public static final String verifSign(PdfReader pdfReader)
{
KeyStore kall = PdfPKCS7.loadCacertsKeyStore();
AcroFields acroFields = pdfReader.getAcroFields();
List<String> signatureNames = acroFields.getSignatureNames();
if (signatureNames.isEmpty())
{
return ("El documento no tiene ni una firma registrada");
}
for(String name : signatureNames)
{
if (!acroFields.signatureCoversWholeDocument(name))
{
return ("la firma: "+name+" does not covers the whole document.");
}
PdfPKCS7 pk = acroFields.verifySignature(name);
Certificate[] certificates = pk.getCertificates();
Calendar cal = pk.getSignDate();
//System.out.println("Document modified: " + !pk.verify());
Object fails[] = PdfPKCS7.verifyCertificates(certificates, kall, null, cal);
if (fails == null)
{
// Documento PDF firmado correctamente
}
else
{
return ("Firma no vĂ¡lida");
}
}
// Todo firmado correctamente
return null;
}
http://www.berthou.com/us/2009/07/01/verify-pdf-signature-with-itext/

How to correctly encode DH parameters using BouncyCastle in Java?

I am trying to reproduce the output of "openssl dhparam -out dh1024.pem 1024" command programatically in Java. The code snippet is following:-
DHParametersGenerator generator = new DHParametersGenerator();
generator.init(1024, 0, new SecureRandom());
DHParameters params = generator.generateParameters();
// Generator G is set as random in params, but it has to be 2 to conform to openssl
DHParameters realParams = new DHParameters(params.getP(), BigInteger.valueOf(2));
byte[] p = realParams.getP().toByteArray();
byte[] g = realParams.getG().toByteArray();
byte[] l = new byte[(byte) realParams.getL()];
byte[] pgl = new byte[p.length+g.length+l.length];
System.arraycopy(p, 0, pgl, 0, p.length);
System.arraycopy(g, 0, pgl, p.length, g.length);
System.arraycopy(l, 0, pgl, p.length+g.length, l.length);
So basically I am concatenating the values of P,G and L parameters in a byte array "pgl" and then saving it in a file using the PEMWriter class from BC. But when I try to use it via openssl, I get the following error:-
Cannot load DH parameters from
/etc/openvpn/easy-rsa/keys/dh1024.pem:
error:0D07207B:asn1 encoding
routines:ASN1_get_object:header too
long: error:0D068066:asn1 encoding
routines:ASN1_CHECK_TLEN:bad object
header: error:0D07803A:asn1 encoding
routines:ASN1_ITEM_EX_D2I:nested asn1
error: error:0906700D:PEM
routines:PEM_ASN1_read_bio:ASN1 lib
.... which leads me to believe that I am encoding the DH Parameters wrongly, but I cannot find anywhere the correct way to encode this. Can anyone help me in this? I've been bouncing my head against the castle wall fro many days now but to no avail .... please help :(
Here is an example. Note that you cannot set the certainty argument to 0 in generator.init() or you won't get a prime! Most of this code I figured out just by looking at the Bouncycastle source code, for example look at the PEMWriter class.
import java.math.BigInteger;
import java.security.SecureRandom;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.DERInteger;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.crypto.generators.DHParametersGenerator;
import org.bouncycastle.crypto.params.DHParameters;
import org.bouncycastle.util.encoders.Base64;
public class OpenSSLDHParamClone
{
public static void main(String[] args) throws Exception
{
DHParametersGenerator generator = new DHParametersGenerator();
generator.init(1024, 80, new SecureRandom());
DHParameters params = generator.generateParameters();
// Generator G is set as random in params, but it has to be 2 to conform to openssl
DHParameters realParams = new DHParameters(params.getP(), BigInteger.valueOf(2));
ASN1EncodableVector seq = new ASN1EncodableVector();
seq.add(new DERInteger(realParams.getP()));
seq.add(new DERInteger(realParams.getG()));
byte [] derEncoded = new DERSequence(seq).getDEREncoded();
System.out.println("-----BEGIN DH PARAMETERS-----");
String b64Encoded = new String(Base64.encode(derEncoded), "US-ASCII");
while (b64Encoded.length() > 0) {
int subStringLength = Math.min(64, b64Encoded.length());
System.out.println(b64Encoded.substring(0, subStringLength));
b64Encoded = b64Encoded.substring(subStringLength);
}
System.out.println("-----END DH PARAMETERS-----");
}
}
Thanks GregS, your solution works but I eventually solved it using standard Java plus PemWriter from BC, although you cannot set the Generator G = 2 with this approach, but its still works both with openssl and Java, which was my initial purpose anyway :)
import java.io.FileWriter;
import java.io.IOException;
import java.security.AlgorithmParameterGenerator;
import java.security.AlgorithmParameters;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemWriter;
public class DHCredentials {
public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchProviderException, IOException
{
DHCredentials dhc = new DHCredentials();
System.out.println("This may take a long time ...");
dhc.saveDHParams("C:\\xxxDH.txt", dhc.genDHParams());
System.out.println("Done");
}
public byte[] genDHParams() throws IOException
{
AlgorithmParameterGenerator paramGen = null;
try
{
paramGen = AlgorithmParameterGenerator.getInstance("DH");
paramGen.init(1024, new SecureRandom());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
AlgorithmParameters params = paramGen.generateParameters();
return params.getEncoded();
}
public void saveDHParams(String filePath, byte[] DEREncodedDHParams)
{
PemWriter pemWrt;
try {
pemWrt = new PemWriter(new FileWriter(filePath));
pemWrt.writeObject(new PemObject("DH PARAMETERS", DEREncodedDHParams));
pemWrt.flush();
pemWrt.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

Categories

Resources