1 4 package org.ejbca.ui.cli; 5 6 import java.io.BufferedInputStream ; 7 import java.io.BufferedOutputStream ; 8 import java.io.BufferedReader ; 9 import java.io.ByteArrayInputStream ; 10 import java.io.ByteArrayOutputStream ; 11 import java.io.IOException ; 12 import java.io.InputStream ; 13 import java.io.InputStreamReader ; 14 import java.io.OutputStream ; 15 import java.lang.reflect.InvocationTargetException ; 16 import java.math.BigInteger ; 17 import java.security.InvalidKeyException ; 18 import java.security.Key ; 19 import java.security.KeyPair ; 20 import java.security.KeyPairGenerator ; 21 import java.security.KeyStore ; 22 import java.security.KeyStoreException ; 23 import java.security.NoSuchAlgorithmException ; 24 import java.security.NoSuchProviderException ; 25 import java.security.Provider ; 26 import java.security.Security ; 27 import java.security.SignatureException ; 28 import java.security.UnrecoverableKeyException ; 29 import java.security.cert.Certificate ; 30 import java.security.cert.CertificateException ; 31 import java.security.cert.X509Certificate ; 32 import java.util.Collection ; 33 import java.util.Date ; 34 import java.util.Enumeration ; 35 import java.util.Iterator ; 36 37 import javax.security.auth.x500.X500Principal ; 38 39 import org.bouncycastle.cms.CMSEnvelopedDataGenerator; 40 import org.bouncycastle.cms.CMSEnvelopedDataParser; 41 import org.bouncycastle.cms.CMSEnvelopedDataStreamGenerator; 42 import org.bouncycastle.cms.CMSTypedStream; 43 import org.bouncycastle.cms.RecipientInformation; 44 import org.bouncycastle.cms.RecipientInformationStore; 45 import org.bouncycastle.jce.provider.BouncyCastleProvider; 46 import org.bouncycastle.x509.X509V3CertificateGenerator; 47 48 public class KeyStoreContainer { 49 private void setPassWord(boolean isKeystoreException) throws IOException { 50 System.err.println((isKeystoreException ? "Setting key entry in keystore" : "Loading keystore")+". Give password of inserted card in slot:"); 51 final char result[] = passwordReader.readPassword(); 52 if ( isKeystoreException ) 53 this.passPhraseGetSetEntry = result; 54 else 55 this.passPhraseLoadSave = result; 56 } 57 private final KeyStore keyStore; 58 private final String providerName; 59 private final String ecryptProviderName; 60 private final PasswordReader passwordReader; 61 private char passPhraseLoadSave[] = null; 62 private char passPhraseGetSetEntry[] = null; 63 public KeyStoreContainer(final String keyStoreType, 64 final String providerClassName, 65 final String encryptProviderClassName, 66 final String sStoreID) throws NoSuchAlgorithmException , CertificateException , KeyStoreException , NoSuchProviderException , IOException , IllegalArgumentException , SecurityException , InstantiationException , IllegalAccessException , InvocationTargetException , NoSuchMethodException , ClassNotFoundException { 67 this( keyStoreType, 68 providerClassName, 69 encryptProviderClassName, 70 sStoreID, 71 null ); 72 } 73 public KeyStoreContainer(final String keyStoreType, 74 final String providerClassName, 75 final String encryptProviderClassName, 76 final String sStoreID, 77 final PasswordReader _passwordReader) throws NoSuchAlgorithmException , CertificateException , KeyStoreException , NoSuchProviderException , IOException , IllegalArgumentException , SecurityException , InstantiationException , IllegalAccessException , InvocationTargetException , NoSuchMethodException , ClassNotFoundException { 78 final byte storeID[] = sStoreID!=null ? sStoreID.getBytes():null; 79 Security.addProvider( new BouncyCastleProvider() ); 80 this.providerName = getProviderName(providerClassName); 81 this.ecryptProviderName = getProviderName(encryptProviderClassName); 82 this.passwordReader = _passwordReader!=null ? _passwordReader : new DefaultPasswordReader(); 83 System.err.println("Creating KeyStore of type "+keyStoreType+" with provider "+this.providerName+(storeID!=null ? (" with ID "+new String (storeID)) : "")+'.'); 84 this.keyStore = KeyStore.getInstance(keyStoreType, this.providerName); 85 try { 86 load(storeID); 87 } catch( IOException e ) { 88 setPassWord(false); 89 load(storeID); 90 } 91 } 92 public interface PasswordReader { 93 char[] readPassword() throws IOException ; 94 } 95 private class DefaultPasswordReader implements PasswordReader { 96 public char[] readPassword() throws IOException { 97 return new BufferedReader (new InputStreamReader (System.in)).readLine().toCharArray(); 98 } 99 } 100 String getProviderName() { 101 return this.providerName; 102 } 103 private void load(byte storeID[]) throws NoSuchAlgorithmException , CertificateException , IOException { 104 this.keyStore.load(storeID!=null ? new ByteArrayInputStream (storeID):null, this.passPhraseLoadSave); 105 } 106 public byte[] storeKeyStore() throws KeyStoreException , NoSuchAlgorithmException , CertificateException , IOException { 107 System.err.println("Next line will contain the identity identifying the keystore:"); 108 ByteArrayOutputStream baos = new ByteArrayOutputStream (); 109 this.keyStore.store(baos, this.passPhraseLoadSave); 110 System.out.print(new String (baos.toByteArray())); 111 System.out.flush(); 112 System.err.println(); 113 return baos.toByteArray(); 114 } 115 public KeyStore getKeyStore() { 116 return this.keyStore; 117 } 118 void setKeyEntry(String alias, Key key, Certificate chain[]) throws IOException , KeyStoreException { 119 try { 120 this.keyStore.setKeyEntry(alias, key, this.passPhraseGetSetEntry, chain); 121 } catch (KeyStoreException e) { 122 setPassWord(true); 123 this.keyStore.setKeyEntry(alias, key, this.passPhraseGetSetEntry, chain); 124 } 125 } 126 void deleteAlias(String alias) throws KeyStoreException { 127 this.keyStore.deleteEntry(alias); 128 System.err.println("Deleting certificate with alias "+alias+'.'); 129 } 130 public byte[] delete(final String alias) throws Exception { 131 if ( alias!=null ) 132 deleteAlias(alias); 133 else { 134 Enumeration e = this.keyStore.aliases(); 135 while( e.hasMoreElements() ) 136 deleteAlias( (String ) e.nextElement() ); 137 } 138 return storeKeyStore(); 139 } 140 public Key getKey(String alias) throws KeyStoreException , NoSuchAlgorithmException , UnrecoverableKeyException , IOException { 141 try { 142 return this.keyStore.getKey(alias, this.passPhraseGetSetEntry); 143 } catch (UnrecoverableKeyException e1) { 144 setPassWord(true); 145 return this.keyStore.getKey(alias, this.passPhraseGetSetEntry ); 146 } 147 } 148 private String getProviderName( String className ) throws IllegalArgumentException , SecurityException , InstantiationException , IllegalAccessException , InvocationTargetException , NoSuchMethodException , ClassNotFoundException { 149 Provider provider = (Provider )Class.forName(className).getConstructor(new Class [0]).newInstance(new Object [0]); 150 Security.addProvider(provider); 151 return provider.getName(); 152 } 153 private X509Certificate getSelfCertificate (String myname, 154 long validity, 155 String sigAlg, 156 KeyPair keyPair) throws CertificateException , InvalidKeyException , SignatureException , NoSuchAlgorithmException , NoSuchProviderException { 157 final long currentTime = new Date ().getTime(); 158 final Date firstDate = new Date (currentTime-24*60*60*1000); 159 final Date lastDate = new Date (currentTime + validity * 1000); 160 X509V3CertificateGenerator cg = new X509V3CertificateGenerator(); 161 cg.setSerialNumber(BigInteger.valueOf(firstDate.getTime())); 163 cg.setSignatureAlgorithm(sigAlg); 164 cg.setSubjectDN(new X500Principal (myname)); 165 cg.setPublicKey(keyPair.getPublic()); 166 cg.setNotBefore(firstDate); 167 cg.setNotAfter(lastDate); 168 cg.setIssuerDN(new X500Principal (myname)); 169 return cg.generate(keyPair.getPrivate(), this.providerName); 170 } 171 private KeyPair generate( final String provider, 172 final String algName, 173 final int size) throws NoSuchAlgorithmException , NoSuchProviderException { 174 KeyPairGenerator kpg = KeyPairGenerator.getInstance(algName, provider); 175 kpg.initialize(size); 176 return kpg.generateKeyPair(); 177 } 178 public byte[] generate( final int keySize, 179 final String keyEntryName) throws Exception { 180 final String keyAlgName = "RSA"; 182 final String sigAlgName = "SHA1withRSA"; 183 final KeyPair keyPair = generate(this.providerName, keyAlgName, keySize); 184 X509Certificate [] chain = new X509Certificate [1]; 185 chain[0] = getSelfCertificate("CN=some guy, L=around, C=US", 186 (long)30*24*60*60*365, sigAlgName, keyPair); 187 System.err.println("Creating certificate with entry "+keyEntryName+'.'); 188 setKeyEntry(keyEntryName, keyPair.getPrivate(), chain); 189 return storeKeyStore(); 190 } 191 public char[] getPassPhraseGetSetEntry() { 192 return passPhraseGetSetEntry; 193 } 194 public char[] getPassPhraseLoadSave() { 195 return passPhraseLoadSave; 196 } 197 static void move(final String providerClassName, 198 final String encryptProviderClassName, 199 final String keyStoreType, 200 final String fromID, 201 final String toID) throws IllegalArgumentException , SecurityException , InstantiationException , IllegalAccessException , InvocationTargetException , NoSuchMethodException , ClassNotFoundException , NoSuchAlgorithmException , CertificateException , KeyStoreException , NoSuchProviderException , IOException , UnrecoverableKeyException { 202 KeyStoreContainer fromKS = new KeyStoreContainer(keyStoreType, providerClassName, encryptProviderClassName, fromID); 203 KeyStoreContainer toKS = new KeyStoreContainer(keyStoreType, providerClassName, encryptProviderClassName, toID); 204 Enumeration e = fromKS.getKeyStore().aliases(); 205 while( e.hasMoreElements() ) { 206 String alias = (String ) e.nextElement(); 207 if (fromKS.getKeyStore().isKeyEntry(alias)) { 208 Key key=fromKS.getKey(alias); 209 Certificate chain[] = fromKS.getKeyStore().getCertificateChain(alias); 210 toKS.setKeyEntry(alias, key, chain); 211 } 212 fromKS.deleteAlias( alias ); 213 } 214 fromKS.storeKeyStore(); 215 toKS.storeKeyStore(); 216 } 217 abstract private class CodeStream { 218 void code(InputStream is, OutputStream os, String alias) throws Exception { 219 doCoding(is, os, alias); 220 os.flush(); 221 } 222 abstract void doCoding(final InputStream is, OutputStream os, String alias) throws Exception ; 223 } 224 private class EncryptStream extends CodeStream { 225 void doCoding(final InputStream is, OutputStream os, String alias) throws Exception { 226 final int bufferSize = 32*1024; 227 final InputStream bis = new BufferedInputStream (is, bufferSize); 228 final OutputStream bos = new BufferedOutputStream (os, bufferSize); 229 final CMSEnvelopedDataStreamGenerator edGen = new CMSEnvelopedDataStreamGenerator(); 230 final Certificate cert = keyStore.getCertificate(alias); 231 if ( cert==null ) 232 throw new ErrorAdminCommandException("Certificate alias "+alias+" not found in keystore."); 233 edGen.addKeyTransRecipient(cert.getPublicKey(), "hej".getBytes() ); 234 OutputStream out = edGen.open(bos, CMSEnvelopedDataGenerator.AES128_CBC, "BC"); 235 byte[] buf = new byte[bufferSize]; 236 while (true) { 237 int len = bis.read(buf); 238 if ( len<0 ) 239 break; 240 out.write(buf,0, len); 241 } 242 out.close(); 243 bos.close(); 244 os.close(); 245 } 246 } 247 private class DecryptStream extends CodeStream { 248 void doCoding(final InputStream is, OutputStream os, String alias) throws Exception { 249 final int bufferSize = 32*1024; 250 final InputStream bis = new BufferedInputStream (is, bufferSize); 251 final OutputStream bos = new BufferedOutputStream (os, bufferSize); 252 CMSEnvelopedDataParser ep = new CMSEnvelopedDataParser(bis); 253 RecipientInformationStore recipients = ep.getRecipientInfos(); 254 Collection c = recipients.getRecipients(); 255 Iterator it = c.iterator(); 256 if (it.hasNext()) { 257 RecipientInformation recipient = (RecipientInformation)it.next(); 258 Key key = getKey(alias); 259 if ( key==null ) 260 throw new ErrorAdminCommandException("Key alias "+alias+" not found in keystore."); 261 CMSTypedStream recData = recipient.getContentStream(key, KeyStoreContainer.this.ecryptProviderName); 262 InputStream ris = recData.getContentStream(); 263 byte[] buf = new byte[bufferSize]; 264 while (true) { 265 int len = ris.read(buf); 266 if ( len<0 ) 267 break; 268 bos.write(buf,0, len); 269 } 270 } 271 bos.close(); 272 os.close(); 273 } 274 } 275 public void decrypt(InputStream is, OutputStream os, String alias) throws Exception { 276 new DecryptStream().code(is, os, alias); 277 } 278 public void encrypt(InputStream is, OutputStream os, String alias) throws Exception { 279 new EncryptStream().code(is, os, alias); 280 } 281 } | Popular Tags |