Reading an X.509 certificate with Java - java

I am trying to use Java to read a certificate that I received from an external party. The code is throwing the following error:
java.lang.RuntimeException: java.security.cert.CertificateException: Unable to initialize, java.io.IOException: extra data given to DerValue constructor
The code:
FileInputStream ksfis = new FileInputStream(this.getCertificateFile());
ksbufin = new BufferedInputStream(ksfis);
certificate = (X509Certificate)
CertificateFactory.getInstance("X.509").generateCertificate(ksbufin);
To make sure the problem was not in the code, I created a self-signed certificate and used it with the code, and it worked fine. I have installed both certificates in the system key chain, and they both are valid. I am using a Mac and Java 1.6.
Any idea why I get the above exception when I load the external Party certificate? Do you think it got corrupted during transfer? If it did, it should not show up as valid on the local system, right?

Try to type this using openssl, and then import the result:
openssl x509 -outform der -in certificate.pem -out certificate.der
or use the Java Bouncy Castle functionality in the lightweight API:
http://www.bouncycastle.org/docs/pkixdocs1.5on/org/bouncycastle/openssl/PEMReader.html
You may encode the result again and then use the "X509" CertificateBuilder in Java to get a JCE defined certificate, e.g.
ByteArrayInputStream certStream = new ByteArrayInputStream(binaryCert);
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) certFactory.generateCertificate(certStream);

Related

NewRelic java agent unable to identify .jks trust store

We are using a NewRelic java agent to monitor java application. The application uses a custom trust store with .jks extension. However the agent by default or by explicitly specifying the path to the trust store does not identify the trust store and throws an error.
How can we use this trust store without changing the extension as we need to use as it is.
INFO: Using ca_bundle_path:
D:\Java\jdk1.8.0_311\jre\lib\security\cacerts
2022-01-24T16:55:40,590+0530 [7048 1] com.newrelic ERROR: Unable to
generate ca_bundle_path certificate. Verify the certificate format.
Will not process further certs.
java.security.cert.CertificateException: Could not parse certificate:
java.io.IOException: Empty input
The Java agent relies on the default X.509 CertificateFactory that only accepts .pem files.
Relevant lines:
try (InputStream is = new BufferedInputStream(new FileInputStream(caBundlePath))) {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// ...
caCerts.add((X509Certificate) cf.generateCertificate(is));
// ...
}
https://github.com/newrelic/newrelic-java-agent/blob/f18215d145bd6992c0fe74a8c503459799e108ca/newrelic-agent/src/main/java/com/newrelic/agent/transport/apache/ApacheSSLManager.java#L54-L58
If you can override the SPI for the X.509 CertificateFactory for one that accepts .pks files you might be able to use your file.

How to connect to SSL Certificate Webservice without installing to keystore?

I'm trying to connect to a SSL webservice that requires a PKCS12 certificate.
Question: is it possible to not installing the certificate to the local keystore, but load it dynamically during runtime?
I tried as follows:
static {
KeyStore.getInstance("PKCS12").load(this.getClass().getClassLoader()
.getResourceAsStream("myfile.p12"), "password".toCharArray());
}
But the result:
sun.security.validator.ValidatorException: PKIX path building failed.
sun.security.provider.certpath.SunCertPathBuilderException: unable to
find valid certification path to requested target.
So obviously it does not work. But why?
Sidenote: the linked SO question does not answer my question, as it targets trustStore, but my question is about keystore.
The problem has nothing to do with this code. Your truststore doesn't trust the server's certificate. If it's self-signed, you'll have to import it. Better still, get it signed by a CA.
The problem is that although your keystore has been created and loaded with your client certificate (assuming that everything is good with it), the SSLContext is not configured to use it.
Try:
Keystore keystore = KeyStore.getInstance("PKCS12").load(this.getClass().getClassLoader()
.getResourceAsStream("myfile.p12"), "password".toCharArray());
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore,"password".toCharArray()).build();
SSLContext.setDefault(sslcontext);

Verifying that two apk files are signed with the same signature

I would like to verify that two APK files have been signed with the same certificate.
I have the whole Java SDK available but would like to it from Java code to make for cross-platform reasons.
Any ideas?
all about is to Comparing your app's signatures
a) get signature of both aps
b) check if sig.hashCode() == releaseSig.hashCode
1) by run-time check using android api:
Signature[] sigs = context.getPackageManager()
.getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES)
.signatures;
from file:
Signature releaseSig = context.getPackageManager()
.getPackageAchiveInfo("/path2apk/app.apk",PackageManager.GET_SIGNATURES)
.signatures[0];
2) getting signature outside android see:
http://androidcracking.blogspot.com/2010/12/getting-apk-signature-outside-of.html
you can use:
openssl pkcs7 -inform DER -in CERT.RSA -noout -print_certs -text
unzip -p application.apk META-INF/CERT.RSA | keytool -printcert
on-the-fly usage of openssl:
(unzip & pipe the cert instead of defining an -infile option):
unzip -p application.apk META-INF/CERT.RSA
| openssl pkcs7 -inform DER -noout -print_certs -text
additional resources:
How do I find out which keystore was used to sign an app?
How to get APK signing signature?
I can recommend you a good article in this thema by Scott Alexander-Bown (scottyab)
https://www.airpair.com/android/posts/adding-tampering-detection-to-your-android-app
Try this link here developer guide
And you can know if they are signed using same signatures or not using the validation of the certificate with creation date.
First navigate to the .apk containing folder in terminal
$ jarsigner -verify -verbose -certs my_application.apk
Android Application
Use the built-in API PackageManager.checkSignatures().
Java Application
The solution is a bit mess but still doable, just dig into PackageManager.checkSignatures() source code and port the implementation to Java. In PackageManager, the part for loading and checking signature is mainly base on Java API:
java.util.jar.JarEntry;
java.util.jar.JarFile;
java.security.PublicKey;
java.security.cert.Certificate;
java.security.cert.CertificateException;
java.security.cert.CertificateFactory;
General idea:
Borrow android.content.pm.Signature source code and port it into Java (need strip off Parcelable)
How to collect/load Signature from apk, check out collectCertificates() and loadCertificates() methods in android.content.pm.PackageParser.
How to check/compare 'Signature', check out checkSignatures() and compareSignatures() methods in android.server.pm.PackageManagerService.
Hope this make sense.

KeyStore error on java server: BKS not found

I get an error on this line:
final KeyStore keyStore = KeyStore.getInstance("BKS");
the error i get is:
java.security.KeyStoreException: BKS not found
at java.security.KeyStore.getInstance(Unknown Source)
at AppListen.<init>(AppListen.java:84)
i added bcprov-jdk16-146.jar to the "Referenced Libraries" but still no luck.
My overall program allows an android phone to be used as mouse and keyboard for a computer using an SSL socket connection. The android app has the same line with no errors.
What am i doing wrong?
EDIT:
Maybe this is common knowledge for most, but it wasn't for me, so for those like me this is what i did.
The reason i was using BKS was because that's the only format allowed by android, but i didnt know that you only needed it on the android side, you can use another format on the server and then make a copy of the key and convert it to BKS to use on the android, eliminating the need for BouncyCastle.
I used a JKS key for the server and than converted a copy of that key to BKS to use on the android using a program called portecle.
Include BouncyCastle library in the project and add provider in code
Security.addProvider(new BouncyCastleProvider());
KeyStore keyStore = KeyStore.getInstance("BKS");

PKCS#12 : DerInputStream.getLength() exception

I generate a certificate using the keytool command:
keytool -genkeypair -alias myRSAKey -keyalg RSA -keysize 1024 -keystore test.p12 -storepass test -storetype pkcs12
Then if I try to load it using java security API, after getting the file as a byte[] :
KeyStore ks = KeyStore.getInstance("PKCS12");
try{
ks.load(new ByteArrayInputStream(data), "test".toCharArray())
} catch (Exception e){
...
}
I get a DerInputStream.getLength(): lengthTag=127, too big exception.
What is wrong?
I had this problem and I've searched the depths of google and still couldn't find the answer. After some days battling with a terrible quality legacy code, I found what was causing this error.
KeyStore.load(InputStream is, String pass);
this method takes an InputStream and if there's any problem with such InputStream, this exception is thrown, some problems that I've encountered:
The InputStream points to the wrong / blank / just created file
The InputStream is already open or something else is holding the resource
The InputStream was already used and read, thus the position of the next byte of InputStream is it's end
The last one was the responsible for my problem. The code was creating an InputStream from a certificate, and proceeding to use it in two KeyStore.load() calls, the first one was successful, the second one always got me this error.
For others with a similar problem:
"keystore load: DerInputStream.getLength(): lengthTag=109, too big."
For me solution was to remove the param: -storetype pkcs12
since the standard type is jks
Probably the certificate you create has an extra character at the end which is misinterpreted to be another certificate.
Use one or more blank lines at the end.
Refer: Java Certificate Parsing
My issue (lengthTag=109, too big) was the .p12 file actually is JKS format and not PKCS # 12 format. Someone renamed the file extension. By regenerating in proper PKCS format resolved the issue.
java.io.IOException: DerInputStream.getLength(): lengthTag=109, too big.
at sun.security.util.DerInputStream.getLength(DerInputStream.java:599)
at sun.security.util.DerValue.init(DerValue.java:365)
at sun.security.util.DerValue.<init>(DerValue.java:320)
at sun.security.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:1914)
at java.security.KeyStore.load(KeyStore.java:1445)
To check the format of a security file, may use KeyStore Explorer to open the file. The left bottom bar shows the actual format.
Specify the type of certificate in the code
for eg:
System.setProperty("javax.net.ssl.trustStoreType", "jks");
System.setProperty("javax.net.ssl.keyStoreType", "pkcs12");
This happened to me in Android Studio after AndroidX migration and using the new testing framework. Even deleting the existing ~/.android/debug.keystore was failing for me
The solution was regenerate it manually (accept all questions as empty and say yes at the last one)
$ keytool -genkey -v -keystore debug.keystore -storepass android -alias androiddebugkey -keypass android -keyalg RSA -keysize 2048 -validity 10000
And copy it
$ rm ~/.android/debug.keystore
$ cp debug.keystore ~/.android/debug.keystore
This happened to me because I had copy and pasted the .p12 file locally on my windows 10 machine. No clue how/why this is a problem, but when I clone a project that has .p12 files and point my code to them, the files work. However, copy and pasting the files in windows file explorer to somewhere else on the harddrive causes this error!!!!
I had the same issue.
My solution is to replace PKCS12 with jceks in the line below because I was apparently using the wrong type.
KeyStore clientStore = KeyStore.getInstance("PKCS12");
You are doing something wrong.
I tried your command and then loaded the p12 just fine.
The following code works:
FileInputStream fin = new FileInputStream("..\\test.p12");
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(fin, "123456".toCharArray());
System.out.println(ks.getCertificate("myrsakey"));
I was wondering if you put the command as is you get an error from keytool that the password must be at least 6 characters.
You did not get that error? What version of java are you using?
Note:if you need to create certificates you can also look into this tool.
http://sourceforge.net/projects/certhelper/
Make sure the scope of the inputstream variable is only to the method where you’re declaring it but not as static/class variable.This way this exception can be avoided.
Reason : Inputstream is not getting closed after the first time of loading certificate or data in it while it is declared as class variable.so make it available only to method.
This happened to me because the following command:
openssl pkcs12 -export -in import.pem -inkey myhost.key.pem -name shared > server.p12 (from https://docs.oracle.com/en/database/other-databases/nosql-database/12.2.4.5/security/import-key-pair-java-keystore.html)
generated a wrongly formatted pkcs12 file. Using the following corrected the problem:
openssl pkcs12 -export -in import.pem -inkey myhost.key.pem -name shared -out server.p12
This error has multpile causes... The log can be realy confusing.
One main cause can be maven filtering.
According to maven official documentation
Warning: Do not filter files with binary content like images! This will most likely result in corrupt output.
Our .jks was corrupted by maven during packaging stage.
This thread helped me to figure it out.
We can exclude some directories or file extensions from filtering directly in concerned pom.xml :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>${maven-resources-plugin.version}</version>
<configuration>
<nonFilteredFileExtensions>
<nonFilteredFileExtension>jks</nonFilteredFileExtension>
<nonFilteredFileExtension>p12</nonFilteredFileExtension>
</nonFilteredFileExtensions>
</configuration>
</plugin>

Categories