org/objectweb/proactive/ext/security/KeyTools.java

00001 /* 
00002  * ################################################################
00003  * 
00004  * ProActive: The Java(TM) library for Parallel, Distributed, 
00005  *            Concurrent computing with Security and Mobility
00006  * 
00007  * Copyright (C) 1997-2007 INRIA/University of Nice-Sophia Antipolis
00008  * Contact: proactive@objectweb.org
00009  * 
00010  * This library is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU Lesser General Public
00012  * License as published by the Free Software Foundation; either
00013  * version 2.1 of the License, or any later version.
00014  *  
00015  * This library is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018  * Lesser General Public License for more details.
00019  * 
00020  * You should have received a copy of the GNU Lesser General Public
00021  * License along with this library; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
00023  * USA
00024  *  
00025  *  Initial developer(s):               The ProActive Team
00026  *                        http://www.inria.fr/oasis/ProActive/contacts.html
00027  *  Contributor(s): 
00028  * 
00029  * ################################################################
00030  */ 
00031 package org.objectweb.proactive.ext.security;
00032 
00033 import java.io.*;
00034 import java.security.KeyFactory;
00035 import java.security.KeyPair;
00036 import java.security.KeyPairGenerator;
00037 import java.security.KeyStore;
00038 import java.security.KeyStoreException;
00039 import java.security.NoSuchAlgorithmException;
00040 import java.security.NoSuchProviderException;
00041 import java.security.PrivateKey;
00042 import java.security.PublicKey;
00043 import java.security.cert.*;
00044 import java.security.interfaces.*;
00045 import java.security.spec.*;
00046 import java.util.*;
00047 
00048 import org.apache.log4j.Logger;
00049 import org.bouncycastle.asn1.*;
00050 import org.bouncycastle.asn1.pkcs.*;
00051 import org.bouncycastle.asn1.x509.*;
00052 import org.bouncycastle.jce.interfaces.*;
00053 import org.objectweb.proactive.core.util.log.Loggers;
00054 import org.objectweb.proactive.core.util.log.ProActiveLogger;
00055 
00056 
00061 public class KeyTools {
00062     static Logger log = ProActiveLogger.getLogger(Loggers.SECURITY);
00063 
00067     private KeyTools() {
00068     }
00069 
00077     public static KeyPair genKeys(int keysize)
00078         throws NoSuchAlgorithmException, NoSuchProviderException {
00079         log.debug(">genKeys()");
00080 
00081         KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA", "BC");
00082         keygen.initialize(keysize);
00083 
00084         KeyPair rsaKeys = keygen.generateKeyPair();
00085 
00086         log.debug("Generated " + rsaKeys.getPublic().getAlgorithm() +
00087             " keys with length " +
00088             ((RSAPrivateKey) rsaKeys.getPrivate()).getPrivateExponent()
00089              .bitLength());
00090 
00091         log.debug("<genKeys()");
00092 
00093         return rsaKeys;
00094     } // genKeys
00095 
00109     public static KeyStore createP12(String alias, PrivateKey privKey,
00110         X509Certificate cert, X509Certificate cacert) throws Exception {
00111         Certificate[] chain;
00112 
00113         if (cacert == null) {
00114             chain = null;
00115         } else {
00116             chain = new Certificate[1];
00117             chain[0] = cacert;
00118         }
00119 
00120         return createP12(alias, privKey, cert, chain);
00121     } // createP12
00122 
00133     static public KeyStore createP12(String alias, PrivateKey privKey,
00134         X509Certificate cert, Collection<Certificate> cacerts) throws Exception {
00135         Certificate[] chain;
00136         if (cacerts == null) {
00137             chain = null;
00138         } else {
00139             chain = new Certificate[cacerts.size()];
00140             chain = (Certificate[]) cacerts.toArray(chain);
00141         }
00142         return createP12(alias, privKey, cert, chain);
00143     } // createP12
00144 
00156     public static KeyStore createP12(String alias, PrivateKey privKey,
00157         X509Certificate cert, Certificate[] cachain) throws Exception {
00158         log.debug(">createP12: alias=" + alias + ", privKey, cert=" +
00159             CertTools.getSubjectDN(cert) + ", cachain.length=" +
00160             ((cachain == null) ? 0 : cachain.length));
00161 
00162         // Certificate chain
00163         if (cert == null) {
00164             throw new IllegalArgumentException("Parameter cert cannot be null.");
00165         }
00166         int len = 1;
00167         if (cachain != null) {
00168             len += cachain.length;
00169         }
00170         Certificate[] chain = new Certificate[len];
00171 
00172         // To not get a ClassCastException we need to genereate a real new certificate with BC
00173         CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
00174         chain[0] = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(
00175                     cert.getEncoded()));
00176 
00177         if (cachain != null) {
00178             for (int i = 0; i < cachain.length; i++) {
00179                 X509Certificate tmpcert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(
00180                             cachain[i].getEncoded()));
00181                 chain[i + 1] = tmpcert;
00182             }
00183         }
00184         if (chain.length > 1) {
00185             for (int i = 1; i < chain.length; i++) {
00186                 X509Certificate cacert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(
00187                             chain[i].getEncoded()));
00188 
00189                 // Set attributes on CA-cert
00190                 PKCS12BagAttributeCarrier caBagAttr = (PKCS12BagAttributeCarrier) chain[i];
00191 
00192                 // We constuct a friendly name for the CA, and try with some parts from the DN if they exist.
00193                 String cafriendly = CertTools.getPartFromDN(CertTools.getSubjectDN(
00194                             cacert), "CN");
00195 
00196                 // On the ones below we +i to make it unique, O might not be otherwise
00197                 if (cafriendly == null) {
00198                     cafriendly = CertTools.getPartFromDN(CertTools.getSubjectDN(
00199                                 cacert), "O") + i;
00200                 }
00201                 if (cafriendly == null) {
00202                     cafriendly = CertTools.getPartFromDN(CertTools.getSubjectDN(
00203                                 cacert), "OU" + i);
00204                 }
00205                 if (cafriendly == null) {
00206                     cafriendly = "CA_unknown" + i;
00207                 }
00208                 caBagAttr.setBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName,
00209                     new DERBMPString(cafriendly));
00210             }
00211         }
00212 
00213         // Set attributes on user-cert
00214         PKCS12BagAttributeCarrier certBagAttr = (PKCS12BagAttributeCarrier) chain[0];
00215         certBagAttr.setBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName,
00216             new DERBMPString(alias));
00217         // in this case we just set the local key id to that of the public key
00218         certBagAttr.setBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId,
00219             createSubjectKeyId(chain[0].getPublicKey()));
00220         // "Clean" private key, i.e. remove any old attributes
00221         KeyFactory keyfact = KeyFactory.getInstance(privKey.getAlgorithm(), "BC");
00222         PrivateKey pk = keyfact.generatePrivate(new PKCS8EncodedKeySpec(
00223                     privKey.getEncoded()));
00224 
00225         // Set attributes for private key
00226         PKCS12BagAttributeCarrier keyBagAttr = (PKCS12BagAttributeCarrier) pk;
00227 
00228         // in this case we just set the local key id to that of the public key
00229         keyBagAttr.setBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName,
00230             new DERBMPString(alias));
00231         keyBagAttr.setBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId,
00232             createSubjectKeyId(chain[0].getPublicKey()));
00233         // store the key and the certificate chain
00234         KeyStore store = KeyStore.getInstance("PKCS12", "BC");
00235         store.load(null, null);
00236         store.setKeyEntry(alias, pk, null, chain);
00237         log.debug("<createP12: alias=" + alias + ", privKey, cert=" +
00238             CertTools.getSubjectDN(cert) + ", cachain.length=" +
00239             ((cachain == null) ? 0 : cachain.length));
00240 
00241         return store;
00242     } // createP12
00243 
00259     public static KeyStore createJKS(String alias, PrivateKey privKey,
00260         String password, X509Certificate cert, Certificate[] cachain)
00261         throws Exception {
00262         log.debug(">createJKS: alias=" + alias + ", privKey, cert=" +
00263             CertTools.getSubjectDN(cert) + ", cachain.length=" +
00264             ((cachain == null) ? 0 : cachain.length));
00265 
00266         String caAlias = "cacert";
00267 
00268         // Certificate chain
00269         if (cert == null) {
00270             throw new IllegalArgumentException("Parameter cert cannot be null.");
00271         }
00272         int len = 1;
00273         if (cachain != null) {
00274             len += cachain.length;
00275         }
00276         Certificate[] chain = new Certificate[len];
00277         chain[0] = cert;
00278         if (cachain != null) {
00279             for (int i = 0; i < cachain.length; i++) {
00280                 chain[i + 1] = cachain[i];
00281             }
00282         }
00283 
00284         // store the key and the certificate chain
00285         KeyStore store = KeyStore.getInstance("JKS");
00286         store.load(null, null);
00287 
00288         // First load the key entry
00289         X509Certificate[] usercert = new X509Certificate[1];
00290         usercert[0] = cert;
00291         store.setKeyEntry(alias, privKey, password.toCharArray(), usercert);
00292 
00293         // Add the root cert as trusted
00294         if (cachain != null) {
00295             if (!CertTools.isSelfSigned(
00296                         (X509Certificate) cachain[cachain.length - 1])) {
00297                 throw new IllegalArgumentException(
00298                     "Root cert is not self-signed.");
00299             }
00300             store.setCertificateEntry(caAlias, cachain[cachain.length - 1]);
00301         }
00302 
00303         // Set the complete chain
00304         log.debug("Storing cert chain of length " + chain.length);
00305         store.setKeyEntry(alias, privKey, password.toCharArray(), chain);
00306         log.debug("<createJKS: alias=" + alias + ", privKey, cert=" +
00307             CertTools.getSubjectDN(cert) + ", cachain.length=" +
00308             ((cachain == null) ? 0 : cachain.length));
00309 
00310         return store;
00311     } // createJKS
00312 
00321     public static Certificate[] getCertChain(KeyStore keyStore,
00322         String privateKeyAlias) throws KeyStoreException {
00323         System.out.println(">getCertChain: alias='" + privateKeyAlias + "'");
00324 
00325         Certificate[] certchain = keyStore.getCertificateChain(privateKeyAlias);
00326         System.out.println("Certchain retrieved from alias '" +
00327             privateKeyAlias + "' has length " + certchain.length);
00328 
00329         if (certchain.length < 1) {
00330             log.error("Cannot load certificate chain with alias '" +
00331                 privateKeyAlias + "' from keystore.");
00332             System.out.println("<getCertChain: alias='" + privateKeyAlias +
00333                 "', retlength=" + certchain.length);
00334 
00335             return certchain;
00336         } else if (certchain.length > 0) {
00337             if (CertTools.isSelfSigned(
00338                         (X509Certificate) certchain[certchain.length - 1])) {
00339                 System.out.println("Issuer='" +
00340                     CertTools.getIssuerDN(
00341                         (X509Certificate) certchain[certchain.length - 1]) +
00342                     "'.");
00343                 System.out.println("Subject='" +
00344                     CertTools.getSubjectDN(
00345                         (X509Certificate) certchain[certchain.length - 1]) +
00346                     "'.");
00347                 System.out.println("<getCertChain: alias='" + privateKeyAlias +
00348                     "', retlength=" + certchain.length);
00349 
00350                 return certchain;
00351             }
00352         }
00353 
00354         // If we came here, we have a cert which is not root cert in 'cert'
00355         ArrayList<Certificate> array = new ArrayList<Certificate>();
00356 
00357         for (int i = 0; i < certchain.length; i++) {
00358             array.add(certchain[i]);
00359         }
00360 
00361         boolean stop = false;
00362 
00363         while (!stop) {
00364             X509Certificate cert = (X509Certificate) array.get(array.size() -
00365                     1);
00366             String ialias = CertTools.getPartFromDN(CertTools.getIssuerDN(cert),
00367                     "CN");
00368             Certificate[] chain1 = keyStore.getCertificateChain(ialias);
00369 
00370             if (chain1 == null) {
00371                 stop = true;
00372             } else {
00373                 System.out.println("Loaded certificate chain with length " +
00374                     chain1.length + " with alias '" + ialias + "'.");
00375 
00376                 if (chain1.length == 0) {
00377                     log.error("No RootCA certificate found!");
00378                     stop = true;
00379                 }
00380 
00381                 for (int j = 0; j < chain1.length; j++) {
00382                     array.add(chain1[j]);
00383 
00384                     // If one cert is slefsigned, we have found a root certificate, we don't need to go on anymore
00385                     if (CertTools.isSelfSigned((X509Certificate) chain1[j])) {
00386                         stop = true;
00387                     }
00388                 }
00389             }
00390         }
00391 
00392         Certificate[] ret = new Certificate[array.size()];
00393 
00394         for (int i = 0; i < ret.length; i++) {
00395             ret[i] = (X509Certificate) array.get(i);
00396             System.out.println("Issuer='" +
00397                 CertTools.getIssuerDN((X509Certificate) ret[i]) + "'.");
00398             System.out.println("Subject='" +
00399                 CertTools.getSubjectDN((X509Certificate) ret[i]) + "'.");
00400         }
00401 
00402         System.out.println("<getCertChain: alias='" + privateKeyAlias +
00403             "', retlength=" + ret.length);
00404 
00405         return ret;
00406     } // getCertChain
00407 
00415     public static SubjectKeyIdentifier createSubjectKeyId(PublicKey pubKey) {
00416         try {
00417             ByteArrayInputStream bIn = new ByteArrayInputStream(pubKey.getEncoded());
00418             SubjectPublicKeyInfo info = new SubjectPublicKeyInfo((ASN1Sequence) new ASN1InputStream(
00419                         bIn).readObject());
00420 
00421             return new SubjectKeyIdentifier(info);
00422         } catch (Exception e) {
00423             throw new RuntimeException("error creating key");
00424         }
00425     } // createSubjectKeyId
00426 } // KeyTools

Generated on Mon Jan 22 15:16:11 2007 for ProActive by  doxygen 1.5.1