From 7ab4dd7f4b67310a55d5e78284b283159a402809 Mon Sep 17 00:00:00 2001 From: zzz Date: Thu, 12 Sep 2013 20:22:30 +0000 Subject: [PATCH] KeyStoreUtil: - Overwrite check in createKeys() - New getCert(), getKey() SU3File: - Store generated keys in keystore - Get private key for signing from keystore --- .../java/src/net/i2p/crypto/KeyStoreUtil.java | 75 ++++++++++++++++--- core/java/src/net/i2p/crypto/SU3File.java | 71 ++++++++++-------- 2 files changed, 102 insertions(+), 44 deletions(-) diff --git a/core/java/src/net/i2p/crypto/KeyStoreUtil.java b/core/java/src/net/i2p/crypto/KeyStoreUtil.java index dd3fdd5db..e17cdf3b1 100644 --- a/core/java/src/net/i2p/crypto/KeyStoreUtil.java +++ b/core/java/src/net/i2p/crypto/KeyStoreUtil.java @@ -6,6 +6,7 @@ import java.io.InputStream; import java.io.IOException; import java.security.GeneralSecurityException; import java.security.KeyStore; +import java.security.PrivateKey; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateEncodingException; @@ -252,7 +253,7 @@ public class KeyStoreUtil { * @param alias the name of the key * @param cname e.g. randomstuff.console.i2p.net * @param ou e.g. console - * @param keqPW the key password + * @param keyPW the key password, must be at least 6 characters * * @return success * @since 0.8.3, consolidated from RouterConsoleRUnner and SSLClientListenerRunner in 0.9.9 @@ -276,16 +277,26 @@ public class KeyStoreUtil { * @param validDays e.g. 3652 (10 years) * @param keyAlg e.g. DSA , RSA, EC * @param keySize e.g. 1024 - * @param keqPW the key password + * @param keyPW the key password, must be at least 6 characters * * @return success * @since 0.8.3, consolidated from RouterConsoleRUnner and SSLClientListenerRunner in 0.9.9 */ public static boolean createKeys(File ks, String ksPW, String alias, String cname, String ou, int validDays, String keyAlg, int keySize, String keyPW) { - if (!ks.exists()) { + if (ks.exists()) { + try { + if (getCert(ks, ksPW, alias) != null) { + error("Not overwriting key " + alias + ", already exists in " + ks, null); + return false; + } + } catch (Exception e) { + error("Not overwriting key \"" + alias + "\", already exists in " + ks, e); + return false; + } + } else { File dir = ks.getParentFile(); - if (!dir.exists()) { + if (dir != null && !dir.exists()) { File sdir = new SecureDirectory(dir.getAbsolutePath()); if (!sdir.mkdir()) { error("Can't create directory " + dir, null); @@ -319,11 +330,57 @@ public class KeyStoreUtil { for (int i = 0; i < args.length; i++) { buf.append('"').append(args[i]).append("\" "); } - error("Failed to create SSL keystore using command line:" + buf, null); + error("Failed to create SSL keystore using command line: " + buf, null); } return success; } + /** + * Get a private key out of a keystore + * + * @param ks path to the keystore + * @param ksPW the keystore password, may be null + * @param alias the name of the key + * @param keyPW the key password, must be at least 6 characters + * @return the key or null if not found + */ + public static PrivateKey getPrivateKey(File ks, String ksPW, String alias, String keyPW) + throws GeneralSecurityException, IOException { + InputStream fis = null; + try { + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + fis = new FileInputStream(ks); + char[] pwchars = ksPW != null ? ksPW.toCharArray() : null; + keyStore.load(fis, pwchars); + char[] keypwchars = keyPW.toCharArray(); + return (PrivateKey) keyStore.getKey(alias, keypwchars); + } finally { + if (fis != null) try { fis.close(); } catch (IOException ioe) {} + } + } + + /** + * Get a cert out of a keystore + * + * @param ks path to the keystore + * @param ksPW the keystore password, may be null + * @param alias the name of the key + * @return the certificate or null if not found + */ + public static Certificate getCert(File ks, String ksPW, String alias) + throws GeneralSecurityException, IOException { + InputStream fis = null; + try { + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + fis = new FileInputStream(ks); + char[] pwchars = ksPW != null ? ksPW.toCharArray() : null; + keyStore.load(fis, pwchars); + return keyStore.getCertificate(alias); + } finally { + if (fis != null) try { fis.close(); } catch (IOException ioe) {} + } + } + /** * Pull the cert back OUT of the keystore and save it as ascii * so the clients can get to it. @@ -338,19 +395,13 @@ public class KeyStoreUtil { public static boolean exportCert(File ks, String ksPW, String alias, File certFile) { InputStream fis = null; try { - KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - fis = new FileInputStream(ks); - char[] pwchars = ksPW != null ? ksPW.toCharArray() : null; - keyStore.load(fis, pwchars); - Certificate cert = keyStore.getCertificate(alias); + Certificate cert = getCert(ks, ksPW, alias); if (cert != null) return CertUtil.saveCert(cert, certFile); } catch (GeneralSecurityException gse) { error("Error saving ASCII SSL keys", gse); } catch (IOException ioe) { error("Error saving ASCII SSL keys", ioe); - } finally { - if (fis != null) try { fis.close(); } catch (IOException ioe) {} } return false; } diff --git a/core/java/src/net/i2p/crypto/SU3File.java b/core/java/src/net/i2p/crypto/SU3File.java index 00f3905ca..1ce2a4654 100644 --- a/core/java/src/net/i2p/crypto/SU3File.java +++ b/core/java/src/net/i2p/crypto/SU3File.java @@ -503,8 +503,15 @@ public class SU3File { private static final boolean signCLI(SigType type, String inputFile, String signedFile, String privateKeyFile, String version, String signerName) { try { + String keypw = ""; + while (keypw.length() < 6) { + System.out.print("Enter password for key \"" + signerName + "\": "); + keypw = DataHelper.readLine(System.in).trim(); + if (keypw.length() > 0 && keypw.length() < 6) + System.out.println("Key password must be at least 6 characters"); + } File pkfile = new File(privateKeyFile); - PrivateKey pk = SigUtil.importJavaPrivateKey(pkfile, type); + PrivateKey pk = KeyStoreUtil.getPrivateKey(pkfile,KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD, signerName, keypw); SigningPrivateKey spk = SigUtil.fromJavaKey(pk, type); SU3File file = new SU3File(signedFile); file.write(new File(inputFile), CONTENT_ROUTER, version, signerName, spk); @@ -568,45 +575,45 @@ public class SU3File { */ private static final boolean genKeysCLI(SigType type, String publicKeyFile, String privateKeyFile) { File pubFile = new File(publicKeyFile); - File privFile = new File(privateKeyFile); if (pubFile.exists()) { System.out.println("Error: Not overwriting file " + publicKeyFile); return false; } - if (privFile.exists()) { - System.out.println("Error: Not overwriting file " + privateKeyFile); + File ksFile = new File(privateKeyFile); + String alias = ""; + String keypw = ""; + try { + while (alias.length() == 0) { + System.out.print("Enter key name (example@mail.i2p): "); + alias = DataHelper.readLine(System.in).trim(); + } + while (keypw.length() < 6) { + System.out.print("Enter new key password: "); + keypw = DataHelper.readLine(System.in).trim(); + if (keypw.length() > 0 && keypw.length() < 6) + System.out.println("Key password must be at least 6 characters"); + } + } catch (IOException ioe) { return false; } - FileOutputStream fileOutputStream = null; - I2PAppContext context = I2PAppContext.getGlobalContext(); - try { - // inefficiently go from Java to I2P to Java formats - SimpleDataStructure signingKeypair[] = context.keyGenerator().generateSigningKeys(type); - SigningPublicKey signingPublicKey = (SigningPublicKey) signingKeypair[0]; - SigningPrivateKey signingPrivateKey = (SigningPrivateKey) signingKeypair[1]; - PublicKey pubkey = SigUtil.toJavaKey(signingPublicKey); - PrivateKey privkey = SigUtil.toJavaKey(signingPrivateKey); - - fileOutputStream = new SecureFileOutputStream(pubFile); - fileOutputStream.write(pubkey.getEncoded()); - fileOutputStream.close(); - fileOutputStream = null; - - fileOutputStream = new SecureFileOutputStream(privFile); - fileOutputStream.write(privkey.getEncoded()); - - System.out.println("\r\n" + type + " Private key written to: " + privateKeyFile); - System.out.println(type + " Public key written to: " + publicKeyFile); - System.out.println("\r\nPublic key: " + signingPublicKey.toBase64() + "\r\n"); - } catch (Exception e) { + int keylen = type.getPubkeyLen() * 8; + if (type.getBaseAlgorithm() == SigAlgo.EC) { + keylen /= 2; + if (keylen == 528) + keylen = 521; + } + boolean success = KeyStoreUtil.createKeys(ksFile, KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD, alias, + "cn", "ou", 3652, type.getBaseAlgorithm().getName(), + keylen, keypw); + if (!success) { + System.err.println("Error writing keys:"); + return false; + } + File outfile = new File(publicKeyFile); + success = KeyStoreUtil.exportCert(ksFile, KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD, alias, outfile); + if (!success) { System.err.println("Error writing keys:"); - e.printStackTrace(); return false; - } finally { - if (fileOutputStream != null) - try { - fileOutputStream.close(); - } catch (IOException ioe) {} } return true; }