How to access certificate from eToken in java - java

I want to read certificate from eToken when it plugged-in, when I store that certificate on local machine I can read it through my java application but, I don't know how to read it from eToken.
RSAPublicKey pub;
String fileName = "C:\\myCert.cer";
InputStream inStream = new FileInputStream(fileName);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert =
(X509Certificate)cf.generateCertificate(inStream);
inStream.close();
pub = (RSAPublicKey) cert.getPublicKey();
System.out.println(cert.getIssuerDN());
System.out.println(cert.getSubjectDN());
System.out.println(cert.getSubjectAlternativeNames());
byte [] tempPub = pub.getEncoded();
String sPub = new String( tempPub );

One way to do this is by using the PKCS#11 provider. It comes with examples, too.

Related

How to extract PKCS12 keystore(containing a keypair of pkcs#8 and a certificate)

when the user provides keystore, usually the keystore contains a keypair(an RSA encrypted private key, x.509 certificate) and CA certificates.
I want to extract the contents of keystore and write them in a different file.
I am able to read the contents of certificates without any issue but when trying to read the key and write to file, the contents are in unecrypted form.
How to write the contents of private key file in encrypted from itself?
I have fetched the key and cert as below:
key = (PrivateKey)keyStore.getKey(keyAlias, password.toCharArray());
cert = keyStore.getCertificate(keyAlias);
I also tried using bouncycastle.
Using java libs:
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(key.getEncoded());
byte[] privatekey = encoder.encode(pkcs8EncodedKeySpec.getEncoded());
Using bouncycastle:
JceOpenSSLPKCS8EncryptorBuilder encryptorBuilder = new JceOpenSSLPKCS8EncryptorBuilder(PKCS8Generator.PBE_SHA1_RC2_128);
encryptorBuilder.setRandom(new SecureRandom());
encryptorBuilder.setPasssword("abcde".toCharArray()); // password
OutputEncryptor encryptor = encryptorBuilder.build();
JcaPKCS8Generator gen2 = new JcaPKCS8Generator(key, encryptor);
PemObject obj2 = gen2.generate();
StringWriter sw2 = new StringWriter();
try (JcaPEMWriter pw = new JcaPEMWriter(sw2)) {
pw.writeObject(obj2);
}
String pkcs8Key2 = sw2.toString();
FileOutputStream fos2 = new FileOutputStream(privateKeyLocation);
fos2.write(pkcs8Key2.getBytes());
fos2.flush();
fos2.close();
when used plain java libs the content is decrypted and I may want to append the header and footer tags.
When used bouncy castle, I got some data with in -----BEGIN ENCRYPTED PRIVATE KEY----- and -----END ENCRYPTED PRIVATE KEY----- but the content is not same as the original file. I also tried using different PKCS8Gnerator.algorithms to no use.

create PKCS7 with presigned data using bouncy castle

I would like to create a detached signature in a PDF file using a PKCS7 container. The data (hash) is being signed beforehand on a different device with the private key. I want to create a PKCS7 containing the signed data along with the certificate with the public key. I can't seem to create the PKCS7 with bouncy castle without supplying the private key and having the library signing the data. This doesn't seem to work:
InputStream inStream = new FileInputStream("1_public.pem");
BufferedInputStream bis = new BufferedInputStream( inStream );
CertificateFactory cf = CertificateFactory.getInstance("X.509");
List<Certificate> certList = new ArrayList<Certificate>();
Certificate certificate = cf.generateCertificate(bis);
certList.add(certificate);
Store certs = new JcaCertStore(certList);
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
gen.addCertificates( certs );
CMSProcessableInputStream msg = new CMSProcessableInputStream( new ByteArrayInputStream( "signedhash".getBytes() ) );
CMSSignedData signedData = gen.generate(msg, false);
byte[] pkcs7 = signedData.getEncoded() ) );
I managed to do this by providing a ContentSigner that doesn't sign, actually quite simple:
InputStream inStream = new FileInputStream("1_public.pem");
BufferedInputStream bis = new BufferedInputStream( inStream );
CertificateFactory cf = CertificateFactory.getInstance("X.509");
List<Certificate> certList = new ArrayList<Certificate>();
Certificate certificate = cf.generateCertificate(bis);
certList.add(certificate);
Store certs = new JcaCertStore(certList);
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
gen.addCertificates( certs );
final byte[] signedHash = "signedhash".getBytes();
ContentSigner nonSigner = new ContentSigner() {
#Override
public byte[] getSignature() {
return signedHash;
}
#Override
public OutputStream getOutputStream() {
return new ByteArrayOutputStream();
}
#Override
public AlgorithmIdentifier getAlgorithmIdentifier() {
return new DefaultSignatureAlgorithmIdentifierFinder().find( "SHA256WithRSA" );
}
};
org.bouncycastle.asn1.x509.Certificate cert = org.bouncycastle.asn1.x509.Certificate.getInstance(ASN1Primitive.fromByteArray(certificate.getEncoded()));
JcaSignerInfoGeneratorBuilder sigb = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build());
sigb.setDirectSignature( true );
gen.addSignerInfoGenerator(sigb.build(nonSigner, new X509CertificateHolder(cert)));
CMSProcessableInputStream msg = new CMSProcessableInputStream( new ByteArrayInputStream( "not used".getBytes() ) );
CMSSignedData signedData = gen.generate(msg, false);
byte[] pkcs7 = signedData.getEncoded();
In case the "external signature" is performed by a hardware device it is possible that it also contains "signed attributes". In this case the code must also contain:
AttributeTable signedAttributes = signer.getSignedAttributes();
signerInfoBuilder.setSignedAttributeGenerator(new SimpleAttributeTableGenerator(signedAttributes));
signatureGenerator.addSignerInfoGenerator(signerInfoBuilder.build(nonSigner, signCertificate));
you should also remove the
signatureGenerator.setDirectSignature(true)
a complete example can be found here https://www.len.ro/work/attach-payload-into-detached-pkcs7-signature/. Since I spend a lot of time searching for a solution and this post provided a vital clue I thought I should complete with the information I still missed in an article. Thanks.

Creating a Key Pair Certificate and Signing It with External CA using BouncyCastle

Here what I have so far generating a Certificate for a User
try {
Security.addProvider(new BouncyCastleProvider()); // adding provider
// to
String pathtoSave = "D://sureshtest.cer";
KeyPair keyPair = generateKeypair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
X509Certificate trustCert = createCertificate(null, "CN=CompanyName",
"CN=Owner", publicKey, privateKey);
java.security.cert.Certificate[] outChain = { trustCert, };
trustCert.checkValidity();
KeyStore outStore = KeyStore.getInstance("PKCS12");
outStore.load(null, null);
outStore.setKeyEntry("my own certificate", privateKey,
"admin123".toCharArray(), outChain);
OutputStream outputStream = new FileOutputStream(pathtoSave);
outStore.store(outputStream, "admin123".toCharArray());
outputStream.flush();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
The above code generate a certificate with a private and public key.
Now I want to sign that certificate with a signing certificate I've been issued by a certificate authority (CA). After that I'll grant that certificate to user.
I got some input from here and it seems that is not the required answer with my case.
No need for a full implementation, just a valid procedure or some hints will greatly help.
You need to generate a CSR so you can invoke the code from Sign CSR using Bouncy Castle which is using the BC API. Add this to your code above:
final PKCS10 request = new PKCS10(publicKey);
final String sigAlgName = "SHA1WithRSA"; // change this to SHA1WithDSA if it's a DSA key
final Signature signature = Signature.getInstance(sigAlgName);
signature.initSign(privateKey);
final X500Name subject = new X500Name(trustCert.getSubjectDN().toString());
final X500Signer signer = new X500Signer(signature, subject);
// Sign the request and base-64 encode it
request.encodeAndSign(signer);
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final PrintStream writer = new PrintStream(baos);
request.print(writer);
// Remove -----BEGIN NEW CERTIFICATE REQUEST----- and -----END NEW CERTIFICATE REQUEST-----
final String requestBase64 = new String(baos.toByteArray());
String withoutTags = requestBase64.substring(41);
withoutTags = withoutTags.substring(0, withoutTags.length() - 39);
// org.bouncycastle.pkcs.PKCS10CertificationRequestHolder
final PKCS10CertificationRequest holder = new PKCS10CertificationRequest(Base64.decode(withoutTags));
// Feed this into https://stackoverflow.com/questions/7230330/sign-csr-using-bouncy-castle

Extracting private key in java

I have certificate created using java class CertAndKeyGen and X500Name and I am able to generate the certificate which is in byte array. Now I want the private key I used in certificate and convert it into readable format. Below is the code I used to create the certificate,
CertAndKeyGen keypair = new CertAndKeyGen("RSA", "SHA1WithRSA", null);
X500Name x500Name = new X500Name(commonName, organizationalUnit, organization, city, state, country);
keypair.generate(keysize);
PrivateKey privKey = keypair.getPrivateKey();
PKCS10 certReq = keypair.getCertRequest(x500Name);
X509Certificate[] chain = new X509Certificate[1];
chain[0] = keypair.getSelfCertificate(x500Name, new Date(), (long) validity * 24 * 60 * 60);
keyStore.setKeyEntry(alias, privKey, keyStorePassword.toCharArray(), chain);
ByteArrayOutputStream bs = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(bs);
certReq.print(ps);
byte[] certReqPrintable = bs.toByteArray();
I have got no clues, please help me to go in right direction to get private key and convert it into readable format. Thanks in advance.
If you want to save the private key to a file use
byte[] privateKeyBytes = privKey.getEncoded();
This returns the key in DER encoded (binary) format.
In case you want just to display the contained values on the console just print it using toString():
System.out.println(privKey);
BouncyCastle has the useful PEMWriter class that you can use to write the private key to a file in PEM format (this is what tools like OpenSSH and curl expect).
PEMWriter privatepemWriter = new PEMWriter(new FileWriter(filename)));
privatepemWriter.writeObject(privKey);
privatepemWriter.close();
Otherwise you can just save the byte array from the private key which is the DER format also used by many tools.
Finally you can write it to a JKS keystore used by other java programs using this:
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(null);
keyStore.setKeyEntry("some alias", privKey, somePassword.toCharArray(), chain[0]));
FileOutputStream fos = new FileOutputStream(filename);
keyStore.store(fos, somePassword.toCharArray());
fos.close();

Having trouble converting a X509 Certificate to Base64

I have a X509 Certificate and I want to store it in a MySQL DB instead of saving the file. Therefore, I thought it is better to convert the certificate to base64 and store it. I have done the forward and reverse of this conversion however, I did not get true results.
I'm using javax.security.cert.X509Certificate and import org.apache.commons.codec.binary.Base64 as follows:
X509Certificate cert = X509Certificate.getInstance(new FileInputStream(certFile));
System.out.println("Vigencia: "+cert.getNotAfter());
System.out.println("Inicio: "+cert.getNotBefore());
String cert64 = bytes2String(Base64.encodeBase64(cert.toString().getBytes("UTF-8")));
System.out.println("Cert 64: "+ cert64);
String certRegreso = bytes2String(Base64.decodeBase64(cert64.getBytes()));
System.out.println("Cert Regreso: "+ certRegreso);
X509Certificate certNuevo = X509Certificate.getInstance(certRegreso.getBytes());
According to the javadocs X509Certificate implements Serializable so why not use the much simpler solution and store it as a byte array? Something like:
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutput out = new ObjectOutputStream(bos);
out.writeObject(certificate);
byte[] data = bos.toByteArray();
bos.close();
And now just store the byte array as a blob. To recreate it you can just use:
ByteArrayIntputSream bis = new ByteArrayInputStream(byteData);
ObjectInput in = new ObjectInputStream(bis);
X509Certificate cert = (X509Certificate) in.readObject();
bis.close();

Categories

Resources