Code:
String pkcs11cfg = "pkcs11.cfg";
Provider p = new SunPKCS11(pkcs11cfg);
Security.addProvider(p);
KeyStore ks = KeyStore.getInstance("PKCS11", p);
ks.load(null, pin);
System.out.println(ks.size()); // prints 0
cfg:
name = pkcs11Test
library = /usr/local/lib/libsofthsm.so
slot = 1
The problem is that I have some key pairs, I added them with pkcs11-tool.
The version of softhsm is 1.2.1
Why there aren't any aliases in the KeyStore? How to fix this?
We will release SoftHSM 1.3.0 soon. It has support for certificates and is tested with Java.
SoftHSM.java:
import java.io.*;
import java.math.*;
import java.util.*;
import java.security.*;
import java.security.interfaces.*;
import java.security.cert.*;
import sun.security.pkcs11.*;
import org.bouncycastle.x509.*;
import javax.security.auth.x500.X500Principal;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.x509.X509V3CertificateGenerator;
class SoftHSM
{
public static void main(String args[]) throws Exception {
// Set up the Sun PKCS 11 provider
String configName = "softhsm.cfg";
Provider p = new SunPKCS11(configName);
if (-1 == Security.addProvider(p)) {
throw new RuntimeException("could not add security provider");
}
// Load the key store
char[] pin = "1234".toCharArray();
KeyStore ks = KeyStore.getInstance("PKCS11", p);
ks.load(null, pin);
// Generate the key
SecureRandom sr = new SecureRandom();
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA", p);
keyGen.initialize(1024, sr);
KeyPair keyPair = keyGen.generateKeyPair();
PrivateKey pk = keyPair.getPrivate();
// Java API requires a certificate chain
X509Certificate[] chain = generateV3Certificate(keyPair);
ks.setKeyEntry("ALIAS-GOES-HERE", pk, "1234".toCharArray(), chain);
ks.store(null);
System.out.println("OK");
}
public static X509Certificate[] generateV3Certificate(KeyPair pair) throws InvalidKeyException, NoSuchProviderException, SignatureException {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
certGen.setIssuerDN(new X500Principal("CN=Test Certificate"));
certGen.setNotBefore(new Date(System.currentTimeMillis() - 10000));
certGen.setNotAfter(new Date(System.currentTimeMillis() + 10000));
certGen.setSubjectDN(new X500Principal("CN=Test Certificate"));
certGen.setPublicKey(pair.getPublic());
certGen.setSignatureAlgorithm("SHA256WithRSA");
certGen.addExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(false));
certGen.addExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment));
certGen.addExtension(X509Extensions.ExtendedKeyUsage, true, new ExtendedKeyUsage(KeyPurposeId.id_kp_serverAuth));
certGen.addExtension(X509Extensions.SubjectAlternativeName, false, new GeneralNames(new GeneralName(GeneralName.rfc822Name, "test#test.test")));
X509Certificate[] chain = new X509Certificate[1];
chain[0] = certGen.generateX509Certificate(pair.getPrivate(), "SunPKCS11-SoftHSM");
return chain;
}
}
softhsm.cfg:
name = SoftHSM
library = /usr/local/lib/libsofthsm.so
slot = 2
attributes(generate, *, *) = {
CKA_TOKEN = true
}
attributes(generate, CKO_CERTIFICATE, *) = {
CKA_PRIVATE = false
}
attributes(generate, CKO_PUBLIC_KEY, *) = {
CKA_PRIVATE = false
}
Related
Given an X509 certificate object of a person. (The object's type is sun.security.x509.X509CertImpl). This person signed a String with his private key. Given the signature that was made by this person, when he signed the above mentioned String object.
My task is to verify this signature, but have difficulties with it.
When I try to verify the signature with the below code:
...
X509Certificate x509Certificate = getCertificate(certificate);
Signature signature = Signature.getInstance("SHA256withECDSA");
signature.initVerify(x509Certificate.getPublicKey());
signature.update(unsignedData);
boolean bool = signature.verify(signatureToVerify);
System.out.println("The signature is " + (bool ? "" : "NOT") + " valid");
I get java.security.SignatureException: Could not verify signature
Do you have an idea, how can I make it working?
Edited:
At the end, I managed to make it working, but do not understand the reason yet:
Before passing the signature to the verify method, i needed to do the following modification on it:
byte[] rBytes = Arrays.copyOfRange(signatureHash, 0, 32);
byte[] sBytes = Arrays.copyOfRange(signatureHash, 32, 64);
BigInteger r = new BigInteger(1, rBytes);
BigInteger s = new BigInteger(1, sBytes);
ASN1Integer asn1R = new ASN1Integer(r);
ASN1Integer asn1S = new ASN1Integer(s);
DERSequence seq = new DERSequence(new ASN1Integer[]{asn1R, asn1S});
byte[] signatureToVerify2 = seq.getEncoded();
// verifying the signatureToVerify2 instead of the original brings success
boolean bool = signature.verify(signatureToVerify2);
Here is a (semi)working app for further reference that verifies a signature, when ECDSA is involved in the story:
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.DERSequence;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Arrays;
public class SignatureTest {
public static void main(String[] args) throws CertificateException, InvalidKeyException, SignatureException, NoSuchAlgorithmException, IOException {
byte[] certificateAsByteArray = ...;
byte[] dataToVerifyAsByteArray = ...;
byte[] signatureHashAsByteArray = ...;
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
InputStream in = new ByteArrayInputStream(certificateBytes);
X509Certificate x509Certificate = (X509Certificate) certFactory.generateCertificate(in);
Signature signature = Signature.getInstance("SHA256withECDSA");
signature.initVerify(x509Certificate.getPublicKey());
signature.update(dataToVerifyAsHexaString);
byte[] rBytes = Arrays.copyOfRange(signatureHash, 0, 32);
byte[] sBytes = Arrays.copyOfRange(signatureHash, 32, 64);
ASN1Integer asn1R = new ASN1Integer(rBytes);
ASN1Integer asn1S = new ASN1Integer(sBytes);
DERSequence seq = new DERSequence(new ASN1Integer[] {asn1R, asn1S});
boolean isSignatureOK = signature.verify(seq.getEncoded());
System.out.println("The signature is " + (isSignatureOK ? "" : "NOT ") + "VALID");
}
}
I'm trying to generate my own CSR for my keystore, but it didn't go well and that error is confusing me. Here is my code:
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.openssl.PEMWriter;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder;
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
public class CreateKeyTest {
public static void main(String[] args) throws OperatorCreationException, IOException, GeneralSecurityException {
KeyPairGenerator kpg;
KeyPair kp;
RSAPublicKey pubKey;
RSAPrivateKey privKey;
FileOutputStream out;
KeyStore ks;
FileInputStream in;
FileInputStream bFis;
try {
ks = KeyStore.getInstance("JKS");
kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
kp = kpg.generateKeyPair();
pubKey = (RSAPublicKey) kp.getPublic();
privKey = (RSAPrivateKey) kp.getPrivate();
// generate CSR
ContentSigner sign = new JcaContentSignerBuilder("SHA1withRSA").build(privKey);
X500NameBuilder nBuilder = new X500NameBuilder();
nBuilder.addRDN(BCStyle.CN, "TestCSR");
nBuilder.addRDN(BCStyle.C, "ER");
nBuilder.addRDN(BCStyle.E, "test#test.com");
X500Name name = nBuilder.build();
PKCS10CertificationRequestBuilder cerReq = new JcaPKCS10CertificationRequestBuilder(name, pubKey);
PKCS10CertificationRequest request = cerReq.build(sign);
PEMWriter pWr = new PEMWriter(new FileWriter(new File("D:\\test.csr")));
pWr.writeObject(request);
pWr.flush();
pWr.close();
bFis = new FileInputStream("D:\\test.csr");
BufferedInputStream ksbufin = new BufferedInputStream(bFis);
X509Certificate certificate = (X509Certificate) CertificateFactory.getInstance("X.509")
.generateCertificate(ksbufin);
ks.setKeyEntry("RSA_key", kp.getPrivate(), "changeit".toCharArray(),
new java.security.cert.Certificate[] { certificate });
out = new FileOutputStream("key.store");
ks.store(out, "changeit".toCharArray());
System.out.println("New Keystore Generated");
out.close();
} catch (KeyStoreException | IOException | CertificateException | NoSuchAlgorithmException
| OperatorCreationException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
When I execute it, it showed me the exception:X509.ObjectIdentifier() -- data isn't an object ID (tag = 49), and it could be back-traced to generateCertificate(ksbufin). But I checked test.cer and it do have certificate data in there, and that exception message confused me, don't even know what does that mean(object ID? tag = 49? I didn't see I generated an ID in my code.).
Can anyone help me out this mud?
The error message is correct, test.csr does not contain a certificate. You have built it using a PKCS10CertificationRequest, so it consenquently contains a Certificate Signing Request (CSR).
You have generated a key pair, private and public, and a CSR. The CSR is a request of a certificate to a Certification Authority (CA). It contains the public key and some expected attributes for the certificate (CN, C, OU, etc). CSR is signed with the private key and has to be sent to CA. The CA will extract the public key, generates a certificate and signs it. See Certificate enrollment process
If you want a Certificate, you need to get signed the certificate by the CA
I have a RSA Key and a X.509 Certificate which I use for SSL connections.
The key and certificate are stored in files in PEM format (generated by OpenSSL) and used in an Apache HTTP server environment.
Is there an easy way to validate if the key matches the certificate using only Java code (without executing the openssl binary and parsing the output), for example by using Java security and/or Bouncycastle library methods?
The following code compares the SHA-1 over the modulus within the public and private key. The modulus should be unique for each pair (unless you key pair generation mechanism or random generator is broken of course).
Note that the following code requires the key to be in unencrypted PKCS#8 format. It may be better to use PKCS#12 instead and load the binary PKCS#12 file in a KeyStore (providing the password).
openssl pkcs8 -topk8 -in key.pem -out keypk8.pem -nocrypt
And finally the Java code:
import static org.bouncycastle.util.encoders.Hex.toHexString;
import java.io.ByteArrayInputStream;
import java.io.FileReader;
import java.security.KeyFactory;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
public class CompareCertAndKey {
/**
* Checks if the certificate and RSA private key match.
*
* #param args the path to the certificate file in args[0] and that of the private key in args[1]
*/
public static void main(String[] args) {
try {
final PemReader certReader = new PemReader(new FileReader(args[0]));
final PemObject certAsPemObject = certReader.readPemObject();
if (!certAsPemObject.getType().equalsIgnoreCase("CERTIFICATE")) {
throw new IllegalArgumentException("Certificate file does not contain a certificate but a " + certAsPemObject.getType());
}
final byte[] x509Data = certAsPemObject.getContent();
final CertificateFactory fact = CertificateFactory.getInstance("X509");
final Certificate cert = fact.generateCertificate(new ByteArrayInputStream(x509Data));
if (!(cert instanceof X509Certificate)) {
throw new IllegalArgumentException("Certificate file does not contain an X509 certificate");
}
final PublicKey publicKey = cert.getPublicKey();
if (!(publicKey instanceof RSAPublicKey)) {
throw new IllegalArgumentException("Certificate file does not contain an RSA public key but a " + publicKey.getClass().getName());
}
final RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
final byte[] certModulusData = rsaPublicKey.getModulus().toByteArray();
final MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
final byte[] certID = sha1.digest(certModulusData);
final String certIDinHex = toHexString(certID);
final PemReader keyReader = new PemReader(new FileReader(args[1]));
final PemObject keyAsPemObject = keyReader.readPemObject();
if (!keyAsPemObject.getType().equalsIgnoreCase("PRIVATE KEY")) {
throw new IllegalArgumentException("Key file does not contain a private key but a " + keyAsPemObject.getType());
}
final byte[] privateKeyData = keyAsPemObject.getContent();
final KeyFactory keyFact = KeyFactory.getInstance("RSA");
final KeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyData);
final PrivateKey privateKey = keyFact.generatePrivate(keySpec);
if (!(privateKey instanceof RSAPrivateKey)) {
throw new IllegalArgumentException("Key file does not contain an X509 encoded private key");
}
final RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKey;
final byte[] keyModulusData = rsaPrivateKey.getModulus().toByteArray();
final byte[] keyID = sha1.digest(keyModulusData);
final String keyIDinHex = toHexString(keyID);
System.out.println(args[0] + " : " + certIDinHex);
System.out.println(args[1] + " : " + keyIDinHex);
if (certIDinHex.equalsIgnoreCase(keyIDinHex)) {
System.out.println("Match");
System.exit(0);
} else {
System.out.println("No match");
System.exit(-1);
}
} catch (Exception e) {
e.printStackTrace(System.err);
System.exit(-2);
}
}
}
Thank you very much for the above code snippet. Its working for me with bouncycastle version 1.51
<bcprov-jdk15on-version>1.51</bcprov-jdk15on-version>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>${bcprov-jdk15on-version}</version>
</dependency>
Many Thanks for your code snippet.
I've been scouring the internet for hours looking for a Java example for creating Elliptic Curve (EC) keys and self signed certificates. So far I've only found snippets and examples, many of which do not work.
UPDATE:
I've made some progress here, here's my code for anybody that might find it useful! Just need to work out how to self sign it now!
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.ContentVerifierProvider;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder;
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
import java.security.*;
/**
* A simple example showing generation and verification of a PKCS#10 request.
*/
public class genECKeyExample {
private static final String BC = BouncyCastleProvider.PROVIDER_NAME;
public static void main(String[] args)
throws Exception {
Security.addProvider(new BouncyCastleProvider());
// Create an eliptic curve key
ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec("prime192v1");
KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA", "BC");
g.initialize(ecSpec, new SecureRandom());
KeyPair pair = g.generateKeyPair();
System.out.println(pemUtils.toPem(pair.getPrivate()));
System.out.println(pemUtils.toPem(pair.getPublic()));
ContentSigner signer = new JcaContentSignerBuilder("SHA1withECDSA").setProvider(BC).build(pair.getPrivate());
PKCS10CertificationRequestBuilder reqBuilder = new JcaPKCS10CertificationRequestBuilder(new X500Name("CN=XXX"), pair.getPublic());
PKCS10CertificationRequest req = reqBuilder.build(signer);
ContentVerifierProvider verifier = new JcaContentVerifierProviderBuilder().setProvider(BC).build(pair.getPublic());
// System.out.println(verifier);
req = new PKCS10CertificationRequest(req.getEncoded());
System.out.println(pemUtils.toPem(req));
pemUtils.toFile("csr.pem", pemUtils.toPem(req));
pemUtils.toFile("pkey.pem", pemUtils.toPem(pair.getPrivate()));
}
}
This is the closest I've got but does not create the CSR or certificate. Also, it doesn't appear to allow different key sizes (I think they are curves) to be selected. Does anybody have some woking examples they can share?
import org.bouncycastle.openssl.PEMWriter;
import java.io.StringWriter;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.ECFieldFp;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.EllipticCurve;
import javax.crypto.KeyAgreement;
public class X509CertificateGenerator {
public static void main(String[] args) throws Exception {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ECDH", "BC");
EllipticCurve curve = new EllipticCurve(new ECFieldFp(new BigInteger(
"fffffffffffffffffffffffffffffffeffffffffffffffff", 16)), new BigInteger(
"fffffffffffffffffffffffffffffffefffffffffffffffc", 16), new BigInteger(
"fffffffffffffffffffffffffffffffefffffffffffffffc", 16));
ECParameterSpec ecSpec = new ECParameterSpec(curve, new ECPoint(new BigInteger(
"fffffffffffffffffffffffffffffffefffffffffffffffc", 16), new BigInteger(
"fffffffffffffffffffffffffffffffefffffffffffffffc", 16)), new BigInteger(
"fffffffffffffffffffffffffffffffefffffffffffffffc", 16), 1);
keyGen.initialize(ecSpec, new SecureRandom());
KeyAgreement aKeyAgree = KeyAgreement.getInstance("ECDH", "BC");
KeyPair aPair = keyGen.generateKeyPair();
KeyAgreement bKeyAgree = KeyAgreement.getInstance("ECDH", "BC");
KeyPair bPair = keyGen.generateKeyPair();
aKeyAgree.init(aPair.getPrivate());
bKeyAgree.init(bPair.getPrivate());
aKeyAgree.doPhase(bPair.getPublic(), true);
bKeyAgree.doPhase(aPair.getPublic(), true);
MessageDigest hash = MessageDigest.getInstance("SHA1", "BC");
System.out.println(new String(hash.digest(aKeyAgree.generateSecret())));
System.out.println(new String(hash.digest(bKeyAgree.generateSecret())));
System.out.println(aPair.getPrivate());
StringWriter pemWrtPublic = new StringWriter();
PEMWriter pubkey = new PEMWriter(pemWrtPublic);
pubkey.writeObject(aPair.getPublic());
pubkey.flush();
String pemPublicKey = pemWrtPublic.toString();
System.out.println(pemPublicKey);
StringWriter pemWrtPrivate = new StringWriter();
PEMWriter privkey = new PEMWriter(pemWrtPrivate);
privkey.writeObject(aPair.getPrivate());
privkey.flush();
String pemPrivateKey = pemWrtPrivate.toString();
System.out.println(pemPrivateKey);
}
}
Ive managed to create a CSR programatically following these steps (assuming you have a X509 Certificate stored in a keystore):
X509Certificate generatedCertificate = (X509Certificate)getKeystore().getCertificate(r.keystoreAlias);
PrivateKey privateRequestKey = (PrivateKey)getKeystore().getKey("alias", "password".toCharArray());
Signature signature = Signature.getInstance("MD5WithRSA");
signature.initSign(privateRequestKey);
X500NameBuilder x500NameBld = new X500NameBuilder(BCStyle.INSTANCE);
//possibly less or more of these, depending on your needs
x500NameBld.addRDN(BCStyle.C, "country");
x500NameBld.addRDN(BCStyle.O, "ORG");
x500NameBld.addRDN(BCStyle.E, "email");
x500NameBld.addRDN(BCStyle.CN, "SubjectName");
x500NameBld.addRDN(BCStyle.SN, "12345678");
X500Name subject = x500NameBld.build();
PKCS10CertificationRequest req = new PKCS10CertificationRequest("MD5WithRSA",X509Name.getInstance(subject),generatedCertificate.getPublicKey(),new DERSet(),privateRequestKey);
Please note that this code works for "regular" keypairs but should work for all public/private keypairs.
I have created mdm.pem,intermediate.pem , root.pem using the reference.
As a vendor action
openssl x509 -inform der -in mdm_identity.cer -out mdm.pem
openssl x509 -inform der -in AppleWWDRCA.cer -out intermediate.pem
openssl x509 -inform der -in AppleIncRootCertificate.cer -out root.pem
As a customer,
created a CSR using openssl :
openssl genrsa -des3 -out customerPrivateKey.pem 2048
openssl req -new -key customerPrivateKey.pem -out customer.csr
then convert customer.csr to der format :
openssl req -inform pem -outform der -in customer.csr -out customer.der
After that using the java sample code downloaded from the same reference ,I was trying to create plist.xml and plist_encoded. But I am getting the null key exception.
private PrivateKey extractPrivateKey(String path2keystore) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, UnrecoverableKeyException
{
String alias = "test";//Change to your alias
String password = "test";//Change to your password
KeyStore caKs = KeyStore.getInstance("PKCS12");
caKs.load(new FileInputStream(new File(path2keystore)), password.toCharArray());
//----------issue in the below line
Key key = caKs.getKey(alias, password.toCharArray());
//getting null key in the above line for "key" object
return (PrivateKey)key;
}
I am not able to understand what I am doing wrong. If someone else also faced similar type of problem please help me.
I am attaching full Test.java source code below:
package com.softhinker;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import sun.misc.BASE64Encoder;
/**
* This class is to generate encoded plist for iOS MDM signing request.
* Below files should be in the folder :
* - customer.der
* - intermediate.pem
* - mdm.pem
* - root.pem
* - vendor.p12
*
* Then upload 'plist_encoded' to https://identity.apple.com/pushcert/ to
* generate the certificate for your customer.
*
* [Author Introduction]
* Softhinker.com is a Singapore-based independent software vendor,
* focusing on J2EE, Android, iOS, Google Apps development and consultancy.
* Please visit us at http://www.softhinker.com for more details.
*
* #author Softhinker
*
*/
public class Test {
public static void main(String[] args) throws Exception {
URL dirUrl = Test.class.getResource(".");
URL keyUrl = new URL(dirUrl, "vendor.p12");
String keyPath = keyUrl.getPath().replaceAll("%20", " ");
System.out.println(keyPath);
BASE64Encoder b64en = new BASE64Encoder();
Test test = new Test();
PrivateKey privateKey = test.extractPrivateKey(keyPath);
URL csrUrl = new URL(dirUrl, "customer.der");
String csrPath = csrUrl.getPath().replace("%20", " ");
byte[] csrBytes = test.readCSR(csrPath);
String csr = b64en.encode(csrBytes);
byte[] sigBytes = test.signCSR(privateKey, csrBytes);
String signature = b64en.encode(sigBytes);
URL mdmUrl = new URL(dirUrl, "mdm.pem");
String mdmPath = mdmUrl.getPath().replace("%20", " ");
String mdm = test.readCertChain(mdmPath);
URL intermediateUrl = new URL(dirUrl, "intermediate.pem");
String intermediatePath = intermediateUrl.getPath().replace("%20", " ");
String intermediate = test.readCertChain(intermediatePath);
URL rootUrl = new URL(dirUrl, "root.pem");
String rootPath = rootUrl.getPath().replace("%20", " ");
String root = test.readCertChain(rootPath);
StringBuffer sb = new StringBuffer();
sb.append(mdm);
sb.append(intermediate);
sb.append(root);
test.generatePlist(csr, sb.toString(), signature);
}
private byte[] signCSR(PrivateKey privateKey, byte[] csr) throws Exception {
Signature sig = Signature.getInstance("SHA1WithRSA");
sig.initSign(privateKey);
sig.update(csr);
byte[] signatureBytes = sig.sign();
return signatureBytes;
}
private PrivateKey extractPrivateKey(String path2keystore) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, UnrecoverableKeyException
{
String alias = "test";//Change to your alias
String password = "test";//Change to your password
KeyStore caKs = KeyStore.getInstance("PKCS12");
caKs.load(new FileInputStream(new File(path2keystore)), password.toCharArray());
Key key = caKs.getKey(alias, password.toCharArray());
return (PrivateKey)key;
}
private byte[] readCSR(String path2csr) throws IOException
{
FileInputStream fis = new FileInputStream(path2csr);
byte[] csrBytes = new byte[fis.available()];
fis.read(csrBytes);
fis.close();
return csrBytes;
}
private String readCertChain(String path2certchain) throws IOException
{
FileInputStream fis = new FileInputStream(path2certchain);
byte[] csrBytes = new byte[fis.available()];
fis.read(csrBytes);
fis.close();
return new String(csrBytes);
}
private void generatePlist(String csr, String chain, String signature) throws IOException
{
Document document = DocumentHelper.createDocument();
document.addDocType("plist", "-//Apple//DTD PLIST 1.0//EN", "http://www.apple.com/DTDs/PropertyList-1.0.dtd");
Element plist = document.addElement("plist");
plist.addAttribute("version", "1.0");
Element dict = plist.addElement("dict");
Element csrKey = dict.addElement("key");
csrKey.addText("PushCertRequestCSR");
Element csrStr = dict.addElement("string");
csrStr.addText(csr);
Element chainKey = dict.addElement("key");
chainKey.addText("PushCertCertificateChain");
Element chainStr = dict.addElement("string");
chainStr.addText(chain);
Element sigKey = dict.addElement("key");
sigKey.addText("PushCertSignature");
Element sigStr = dict.addElement("string");
sigStr.addText(signature);
String plistxml = document.asXML();
BASE64Encoder b64en = new BASE64Encoder();
String encodedplist = b64en.encode(plistxml.getBytes());
FileWriter writer = new FileWriter("plist.xml");
document.write(writer);
writer.flush();
writer.close();
FileWriter out = new FileWriter("plist_encoded");
out.write(encodedplist);
out.flush();
out.close();
System.out.println("File is generated.");
}
}
Now I am able to solve the problem.Problem was wrong alias.I listed out the aliases for the vendor.p12 and I got the correct alias,which I passed in Key key = caKs.getKey(alias, password.toCharArray());
I solved the problem as per Chris' comment above.