How to load public certificate from pem file? - java

I was trying to extract RES public key from the file below
-----BEGIN CERTIFICATE-----
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
-----END CERTIFICATE-----
Here is the code i did..
public static PublicKey loadPublicKeyFromFile(File publicKeyFile) throws Exception {
FileReader file = new FileReader(publicKeyFile);
PemReader reader = new PemReader(file);
X509EncodedKeySpec caKeySpec = new X509EncodedKeySpec(reader.readPemObject().getContent());
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey caKey = kf.generatePublic(caKeySpec);
return caKey;
}
But It throws out
java.security.InvalidKeyException: IOException: ObjectIdentifier() -- data isn't an object ID
What's the appropriate way to extract RES Public key from a file..

An X.509 certificate and an X509EncodedKeySpec are quite different structures, and trying to parse a cert as a key won't work.
Java's X509EncodedKeySpec is actually SubjectPublicKeyInfo from X.509 or equivalent and more convenient PKIX also linked from Key, which is only a small part of a certificate.
What you need to do is read and parse the cert and then extract the pubkey from the cert.
Standard SunJCE CertificateFactory can do it
(and can read either PEM or DER to boot) like this:
CertificateFactory fact = CertificateFactory.getInstance("X.509");
FileInputStream is = new FileInputStream (args[0]);
X509Certificate cer = (X509Certificate) fact.generateCertificate(is);
PublicKey key = cer.getPublicKey();
is.close();
// add error handling as appropriate, try-with-resources is often good
If you have BouncyCastle you can use its provider the same way (just add a second argument to .getInstance or set the default provider list order), or you can use PEMParser with JcaX509CertificateConverter -- which effectively does the same thing, internally running the data through a CertificateFactory.

With Sun JVM it is also possible with
import java.security.cert.X509Certificate;
import sun.security.x509.X509CertImpl;
InputStream is = ...
X509Certificate crt = new X509CertImpl(is);
, although I'd prefer the accepted answer as JVM implementation-independent one.
Under the hood, in Sun JVM, CertificateFactory(more precisely, X509Factory) does instantiate X509CertImpl , but there is very subtle difference between the two approaches: CertificateFactory caches X509 Certificate instances by binary content of the input stream, the one that can be retrieved by cer.getEncoded().
The cache can be cleared by
fact.generateCertificate(null);

Related

Convert java cipher decrypt to python equivalent

I'm trying to convert the below java code to python:
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
serverCertificate = (X509Certificate) certFactory.generateCertificate(new FileInputStream(certFile));
Cipher decryptCipher = Cipher.getInstance("RSA");
decryptCipher.init(Cipher.DECRYPT_MODE, serverCertificate.getPublicKey());
byte[] decryptedClientChallengeBytes = decryptCipher.doFinal(encryptedClientChallengeBytes);
The first part I think it's resolved with this:
from cryptography import x509
from cryptography.hazmat.backends import default_backend
cert = x509.load_pem_x509_certificate(key,default_backend())
cert = cert.public_key()
But I can't convert the decrypt part. I´ve tried various methods like PKCS1_v1_5.
I'm trying to implement this https://docs.oracle.com/en/cloud/saas/marketing/responsys-rest-api/RequestUserAuthorization.html
And the step i'm stacked says: "You should receive the following response from the server. Decrypt (using the RSA algorithm) the encrypted clientChallenge using server certificate's public key (which you should have downloaded and stored on your system)."
The clientChallenge received is like this:
"hc8w8gElQJQa45WGofZwsOAi4wwEIaFClI1A2PvvCw4YUc4rbnOpedkBgrNsr0FpZ6DVV_vnZNsAGg_ph75VqeKD-R-cy_RkQIdvn0W_nb0RvPGZI7zA98_t9-rJTiTSsrJ6j8KzlWV_MLydUcBBR1iotL6kXXuFKuXtTAniPx_b6do4D5p9iI7yhTfxp9knRRG6XoItgNGJwm8AnGsThIoZw9lSgUm3Dy9yzYvhXQDYKAUNc3tqd8WcSswlb5coN18Gc-We2E0xE7xehq15Ns4QNwX6WdRrfehSgOObdckUYAx7MyLT-vyfJ-APVEVrZmC18wo-Qr2A-n1NT0ARVQ"
And the server certificate is a .CER with this format:
-----BEGIN CERTIFICATE-----
.....
-----END CERTIFICATE-----
Any help would be awesome!

Standard for X509 certificate sharing (java servlet)

I'm trying to develop a simple web service using servlets and Apache Tomcat, in which a client and a server exchange their public keys; this to send some signed data in a further stage of communication.
I've read over the internet that the best way to share public keys is through X509 certificates to prove their reliability / integrity, is that correct?
I have used Bouncy Castle and JCE to generate the keys and a self-signed X509 certificate, which has to be exchanged between the two parties. Here I got lost between different formats like PEM, DER and recommendations on sharing the bytes of the certificate (i.e. transferring the certificate's object via a ByteArrayOutputStream encapsulated in a ObjectOutputStream). Which is the correct way of doing this? How should I code it?
Side note: this software is intended for study purposes and not for real-world use, so it is okay to make big assumptions as "the connection is secure". This is why I preferred to keep it simple and not to implement SSL. However, if it proved to be really necessary I could try to use it.
Thanks.
EDIT: this is how I solved the problem, thanks to #Lothar
X509Certificate taCert = Certificates.getCertificate();
StringWriter sw = new StringWriter();
JcaPEMWriter pw = new JcaPEMWriter(sw);
pw.writeObject(taCert);
pw.flush();
String pemData = sw.toString();
pw.close();
out.println(pemCert);
The function getCertificate() generates a X509Certificate using BouncyCastle and the resulting pemData is something like this:
-----BEGIN CERTIFICATE-----
MIIBwDCCASmgAwIBAgIGAWIe66NnMA0GCSqGSIb3DQEBCwUAMBkxFzAVBgNVBAMT
DlRydXN0QXV0aG9yaXR5MB4XDTE4MDMxMjEwMzMwMloXDTE4MDMzMDExMTMzMFow
GTEXMBUGA1UEAxMOVHJ1c3RBdXRob3JpdHkwgZ8wDQYJKoZIhvcNAQEBBQADgY0A
MIGJAoGBAMT2Y7iU8dWrqDzciR64HPuXOTEsf/90cLF0hickYvJULHFJ90Z1PXxA
Um/WJ5vX4m6+ESmurrFmClyeLMfThgHBlYfBfKSNYzIB1M0NXoe8znaCP9U+WKy7
HdkRvvenJPRx8mqWCcWH1nBPI5SehppgWxWZzYD4BTIQ+ILwdm8fAgMBAAGjEzAR
MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADgYEATUmc3BfItRc3UObi
qxdzeN32ZEiLsoywan8qDZyxLFJWf8HhLFq2KOFht6+PatAh1SmcZ67Iw+2thb/0
ptuRE1MetpZnY3M++afv5HRrWm1k52sZYKkYtlfAXlzZuNDPm7lDQzSyS/0IhvjC
32bwhNiajLcc0mLqPQCEMd5oi5U=
-----END CERTIFICATE-----
which is sent with a Content-Type text/plain; charset=utf-8 through the PrintWriter provided by response.getWriter(). Client-side, the response is received through HttpURLConnection urlConnection, and read via InputStream in = urlConnection.getInputStream();. More specifically,
InputStream in = urlConnection.getInputStream();
Scanner scanner = new Scanner(in);
scanner.useDelimiter("\\A");
boolean hasInput = scanner.hasNext();
if (hasInput)
return scanner.next();
else
return null;
To create a X509Certificate, I use a CertificateFactory, considering contactServerResult as the string received from the server:
CertificateFactory fact = CertificateFactory.getInstance("X.509");
certificate = (X509Certificate) fact.generateCertificate(new ByteArrayInputStream(contactServerResult.getBytes(Charset.forName("UTF-8"))));
At the end I did not use a PEMParser when reconstructing the received certificate, because it returned a X509CertificateHolder rather than a X509Certificate, resulting in a ClassCastException.
The format most if not all cryptography libraries support is DER. If you have an X.509-instance you simply call getEncoded and you have it. PEM is also widely supported but you need a parser (PEMParser in BouncyCastle for example) to create the certificates from it again.
I can't recommend serializing the objects using DataOutputStream. The object you serialize is dependent on the cryptographic provider that was involved when the certificate was created. If the other side doesn't have this provider available the deserialization will fail. If the other side isn't Java-based the data stream is completely useless, because it's java specific.
To answer your question, how to code it if we're talking about DER as format:
Sending the certificate (assuming within a servlet):
response.getOutputStream().write(certificate.getEncoded());
Creating a certificate from received data (using BouncyCastle as provider):
byte[] data = getDataFromSomewhere();
CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
X509Certificate x509 = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(data));
And for the fun of it, doing the same for PEM:
Sending:
StringWriter sw = new StringWriter();
JcaPEMWriter pw = new JcaPEMWriter(sw);
pw.writeObject(cert);
pw.flush();
String pemData = sw.toString();
Receiving:
String data = getDataFromSomewhere();
PEMParser pr = new PEMParser(new StringReader(data));
X509Certificate x509 = (X509Certificate) pr.readObject();
All examples are simplyfied, e.g. assuming that there is data to read and that the data actually represent a X.509 certificate. There are other things that can be DER- or PEM-encoded so you might get an exception while parsing or when doing the cast because the returned object isn't a certificate but for example a CSR.

What Is The Best Keystore to use?

I want to use Keystore in my upcoming project. I saw that there is an Keystore API in Java. But that seems to be very complicated.
Are there any other good keystore available that work well with Java/Groovy?
Not that I know of. From my perspective, the API is relatively as minimal as possible give the things that it needs to supply.
KeyStore keyStore = keyStore.getInstance(KeyStore.getDefaultType());
keyStore.load( inputStream, storePassword.getBytes() );
// Get a key
if ( keyStore.isKeyEntry(alias) ) {
Key key = keyStore.getKey(alias, keyPassword.getBytes());
}
// Store a new key
KeyFactory keyFactory = KeyFactory.getInstance(KeyStore.getDefaultType());
KeySpec keySpec ...; // depends on what kind of key you want to create (ie. rsa, etc..)
Key key = keyFactory.generatePrivate(keySpec);
// sign the key here
Certificate certChain[] = ...; // get the cert chain
keyStore.setKeyEntry(newAlias, newKey, newKeyPassword.getBytes(), certChain);
keyStore.store(outputStream, storePassword.getBytes());
This is relatively minimal code to handle what a keystore needs to do.

loading a certificate from keystore

Load a certificate and keys from keystore which is password protected and then use it for cert verification and digital signing
To read the certificate is really trivial.
CertificateFactory factory = CertificateFactory.getInstance("X.509");
X509Certificate certificate = (X509Certificate) factory.generateCertificate(new FileInputStream("file.pem"));
This is with standard APIs (in try/catch) etc and you have loaded your certificate.
Now the toString method of certificate is not suitable for you since it just captures the "user's" view of the certificate e.g. you would use it for println for instance
Can't you send the certificate object itself?
Not sure what your server expects so you can look into the various methods of certificate
X509Certificate
I use this code
PEMReader pr=new PEMReader(new StringReader(trust_certs));
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
Object o;
int i=0;
while((o=pr.readObject())!=null){
if(o instanceof X509Certificate){
i++;
X509Certificate c=(X509Certificate)o;
trustStore.setCertificateEntry(Integer.toString(i), c);
}
}
http://www.bouncycastle.org/docs/docs1.6/org/bouncycastle/openssl/PEMReader.html
A pem file is read as any other text file. Read the Java tutorial about IO (and concentrate on character streams, since a pem file contains text, and on File IO, since this is what you want to do)

How to verify PEM format certificate in Java

I have PEM format file, How can verify the signature in Java, as I followed http://download.oracle.com/javase/tutorial/security/apisign/versig.html but found that Java doesnt support PEM
You can read a certificate in a PEM file using BouncyCastle's PEMReader. If the content is an X.509 certificate, you should get an instance of X509Certificate and verify it as you want from there.
EDIT: Here is what the code should look like (not tried):
// The key with which you want to verify the cert.
// This is probably a CA certificate's public key.
PublicKey publicKey = ...;
PEMReader reader = new PEMReader(new FileReader("/path/to/file.pem"));
Object pemObject = reader.readObject();
if (pemObject instanceof X509Certificate) {
X509Certificate cert = (X509Certificate)pemObject;
cert.checkValidity(); // to check it's valid in time
cert.verify(publicKey); // verify the sig. using the issuer's public key
}
(Of course, as with any I/O operations, you'll need to close the reader perhaps with try/finally.)
Note that checkValidity and verify don't return anything: instead, they throw exceptions if when they fail.

Categories