/** * Create a keypair and store it in the keystore at ks, creating it if necessary. * * <p>Warning, may take a long time. * * @param ks path to the keystore * @param ksPW the keystore password * @param alias the name of the key * @param cname e.g. randomstuff.console.i2p.net * @param ou e.g. console * @param validDays e.g. 3652 (10 years) * @param keyAlg e.g. DSA , RSA, EC * @param keySize e.g. 1024 * @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()) { 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 != null && !dir.exists()) { File sdir = new SecureDirectory(dir.getAbsolutePath()); if (!sdir.mkdir()) { error("Can't create directory " + dir, null); return false; } } } String keytool = (new File(System.getProperty("java.home"), "bin/keytool")).getAbsolutePath(); String[] args = new String[] { keytool, "-genkey", // -genkeypair preferred in newer keytools, but this works with more "-storetype", KeyStore.getDefaultType(), "-keystore", ks.getAbsolutePath(), "-storepass", ksPW, "-alias", alias, "-dname", "CN=" + cname + ",OU=" + ou + ",O=I2P Anonymous Network,L=XX,ST=XX,C=XX", "-validity", Integer.toString(validDays), // 10 years "-keyalg", keyAlg, "-sigalg", getSigAlg(keySize, keyAlg), "-keysize", Integer.toString(keySize), "-keypass", keyPW }; // TODO pipe key password to process; requires ShellCommand enhancements boolean success = (new ShellCommand()).executeSilentAndWaitTimed(args, 240); if (success) { success = ks.exists(); if (success) { try { success = getPrivateKey(ks, ksPW, alias, keyPW) != null; if (!success) error("Key gen failed to get private key", null); } catch (Exception e) { error("Key gen failed to get private key", e); success = false; } } if (!success) error("Key gen failed for unknown reasons", null); } if (success) { SecureFileOutputStream.setPerms(ks); info( "Created self-signed certificate for " + cname + " in keystore: " + ks.getAbsolutePath()); } else { StringBuilder buf = new StringBuilder(256); for (int i = 0; i < args.length; i++) { buf.append('"').append(args[i]).append("\" "); } error("Failed to generate keys using command line: " + buf, null); } return success; }
/** * Call out to keytool to create a new keystore with a keypair in it. Trying to do this * programatically is a nightmare, requiring either BouncyCastle libs or using proprietary Sun * libs, and it's a huge mess. * * @return success * @since 0.8.3 */ private boolean createKeyStore(File ks) { // make a random 48 character password (30 * 8 / 5) byte[] rand = new byte[30]; _context.random().nextBytes(rand); String keyPassword = Base32.encode(rand); // and one for the cname _context.random().nextBytes(rand); String cname = Base32.encode(rand) + ".console.i2p.net"; String keytool = (new File(System.getProperty("java.home"), "bin/keytool")).getAbsolutePath(); String[] args = new String[] { keytool, "-genkey", // -genkeypair preferred in newer keytools, but this works with more "-storetype", KeyStore.getDefaultType(), "-keystore", ks.getAbsolutePath(), "-storepass", DEFAULT_KEYSTORE_PASSWORD, "-alias", "console", "-dname", "CN=" + cname + ",OU=Console,O=I2P Anonymous Network,L=XX,ST=XX,C=XX", "-validity", "3652", // 10 years "-keyalg", "DSA", "-keysize", "1024", "-keypass", keyPassword }; boolean success = (new ShellCommand()).executeSilentAndWaitTimed(args, 30); // 30 secs if (success) { success = ks.exists(); if (success) { SecureFileOutputStream.setPerms(ks); try { Map<String, String> changes = new HashMap(); changes.put(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD); changes.put(PROP_KEY_PASSWORD, keyPassword); _context.router().saveConfig(changes, null); } catch (Exception e) { } // class cast exception } } if (success) { System.err.println( "Created self-signed certificate for " + cname + " in keystore: " + ks.getAbsolutePath() + "\n" + "The certificate name was generated randomly, and is not associated with your " + "IP address, host name, router identity, or destination keys."); } else { System.err.println("Failed to create console SSL keystore using command line:"); StringBuilder buf = new StringBuilder(256); for (int i = 0; i < args.length; i++) { buf.append('"').append(args[i]).append("\" "); } System.err.println(buf.toString()); System.err.println( "This is for the Sun/Oracle keytool, others may be incompatible.\n" + "If you create the keystore manually, you must add " + PROP_KEYSTORE_PASSWORD + " and " + PROP_KEY_PASSWORD + " to " + (new File(_context.getConfigDir(), "router.config")).getAbsolutePath()); } return success; }