I'm attempting to port JXTA to run on App Engine. Given that the BouncyCastle "BC" provider is not yet supported on App Engine, I have to port the existing JXTA code to generate a X509Certificate using white-listed classes. My knowledge of Crypto is minimal and i'm not certain that what i'm trying to accomplish is even possible. Here is the original code from PSEUtils.java from the JXTA project:
There's a helper class which contains the java.security.cert.X509Certificate:
public static class IssuerInfo {
public X509Certificate cert; // subject Cert
public PrivateKey subjectPkey; // subject private key
public X509Certificate issuer; // issuer Cert
public PrivateKey issuerPkey; // issuer private key
}
In the method:
public static IssuerInfo genCert(X500Principal subject, KeyPair keypair, IssuerInfo issuerinfo)
I'm passing in subject as:
new X500Principal("CN="+useCN)
keypair as (from original code):
KeyPairGenerator g = KeyPairGenerator.getInstance("RSA");
g.initialize(1024, UTILS.srng);
KeyPair keypair = g.generateKeyPair();
and the jxta coded IssuerInfo.
Now since I can't pull in the bouncycastle.jce packages, I've had to remove the X509Principal and X509V3CertificateGenerator code that JXTA uses and attempt to replace it with an implementation that complies with the GAE restrictions. Here is what I currently have for the genCert method using org.bouncycastle.X509.X509v3CertificateBuilder.
SubjectPublicKeyInfo subPubKeyInfo = SubjectPublicKeyInfo.getInstance(keypair.getPublic().getEncoded());
X509v3CertificateBuilder v3CertGen = new X509v3CertificateBuilder(
new X500Name(issuer.getName()),
BigInteger.ONE,
today, until,
new X500Name(subject.getName()),
subPubKeyInfo);
The problem is that I can't get keypair.getPublic().getEncoded()
to work with the SubjectPublicKeyInfo.getInstance()
method. Throws java.lang.IllegalArgumentException: unknown object in factory: [B
Public Key appears to be populated upon inspection:
Sun RSA public key, 1024 bits
modulus: 117521430893506212334140912845641570591161279468597426442875306202350445904550279678434051874985419676760802566018092318362676224355315431299979507080364677679613392086245588766565617009250512996843008784370448997729071786062596049780632058501646041736216482596596901215941577208285499619376322050871534546271
public exponent: 65537
I've found the following SO link which demonstrates this code working:
My attempt to convert genCert is below but for some reason, I can't get past creating SubjectPublicKeyInfo from the encoded public key?
Any help is greatly appreciated.
public static IssuerInfo genCert(X500Principal subject, KeyPair keypair, IssuerInfo issuerinfo) {
IssuerInfo info = new IssuerInfo();
try {
// set up issuer
PrivateKey signer;
X500Principal issuer;
if (null == issuerinfo) { // self-signed root cert
signer = keypair.getPrivate();
issuer = new X500Principal(subject.getEncoded());
} else { // issuer signed service sert
signer = issuerinfo.subjectPkey;
X500Principal issuer_subject = issuerinfo.cert.getSubjectX500Principal();
issuer = new X500Principal(issuer_subject.getEncoded());
}
// set validity 10 years from today
Date today = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(today);
cal.add(Calendar.YEAR, 10);
Date until = cal.getTime();
SubjectPublicKeyInfo subPubKeyInfo = SubjectPublicKeyInfo.getInstance(keypair.getPublic().getEncoded());
//**Can't get here so i'm not sure if the rest of this works?**
AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1withRSA");
AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
RSAPrivateCrtKeyParameters cps = (RSAPrivateCrtKeyParameters) keypair.getPrivate();
ContentSigner sigGen = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(cps);
X509CertificateHolder certHolder = v3CertGen.build(sigGen);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// Read user Certificate
InputStream is1 = new ByteArrayInputStream(certHolder.getEncoded());
X509Certificate eeCert = (X509Certificate) cf.generateCertificate(is1);
is1.close();
I was able to accomplish this with help from Rene Mayrhofer's code. I've provided my implementation which has only be tested in a local testing environment but it appears to work: