KeyStoreUtil:

- Overwrite check in createKeys()
  - New getCert(), getKey()
  SU3File:
  - Store generated keys in keystore
  - Get private key for signing from keystore
This commit is contained in:
zzz
2013-09-12 20:22:30 +00:00
parent 71c0104236
commit 7ab4dd7f4b
2 changed files with 102 additions and 44 deletions

View File

@@ -6,6 +6,7 @@ import java.io.InputStream;
import java.io.IOException; import java.io.IOException;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.security.KeyStore; import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateEncodingException;
@@ -252,7 +253,7 @@ public class KeyStoreUtil {
* @param alias the name of the key * @param alias the name of the key
* @param cname e.g. randomstuff.console.i2p.net * @param cname e.g. randomstuff.console.i2p.net
* @param ou e.g. console * @param ou e.g. console
* @param keqPW the key password * @param keyPW the key password, must be at least 6 characters
* *
* @return success * @return success
* @since 0.8.3, consolidated from RouterConsoleRUnner and SSLClientListenerRunner in 0.9.9 * @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 validDays e.g. 3652 (10 years)
* @param keyAlg e.g. DSA , RSA, EC * @param keyAlg e.g. DSA , RSA, EC
* @param keySize e.g. 1024 * @param keySize e.g. 1024
* @param keqPW the key password * @param keyPW the key password, must be at least 6 characters
* *
* @return success * @return success
* @since 0.8.3, consolidated from RouterConsoleRUnner and SSLClientListenerRunner in 0.9.9 * @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, public static boolean createKeys(File ks, String ksPW, String alias, String cname, String ou,
int validDays, String keyAlg, int keySize, String keyPW) { 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(); File dir = ks.getParentFile();
if (!dir.exists()) { if (dir != null && !dir.exists()) {
File sdir = new SecureDirectory(dir.getAbsolutePath()); File sdir = new SecureDirectory(dir.getAbsolutePath());
if (!sdir.mkdir()) { if (!sdir.mkdir()) {
error("Can't create directory " + dir, null); error("Can't create directory " + dir, null);
@@ -324,6 +335,52 @@ public class KeyStoreUtil {
return success; 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 * Pull the cert back OUT of the keystore and save it as ascii
* so the clients can get to it. * 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) { public static boolean exportCert(File ks, String ksPW, String alias, File certFile) {
InputStream fis = null; InputStream fis = null;
try { try {
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); Certificate cert = getCert(ks, ksPW, alias);
fis = new FileInputStream(ks);
char[] pwchars = ksPW != null ? ksPW.toCharArray() : null;
keyStore.load(fis, pwchars);
Certificate cert = keyStore.getCertificate(alias);
if (cert != null) if (cert != null)
return CertUtil.saveCert(cert, certFile); return CertUtil.saveCert(cert, certFile);
} catch (GeneralSecurityException gse) { } catch (GeneralSecurityException gse) {
error("Error saving ASCII SSL keys", gse); error("Error saving ASCII SSL keys", gse);
} catch (IOException ioe) { } catch (IOException ioe) {
error("Error saving ASCII SSL keys", ioe); error("Error saving ASCII SSL keys", ioe);
} finally {
if (fis != null) try { fis.close(); } catch (IOException ioe) {}
} }
return false; return false;
} }

View File

@@ -503,8 +503,15 @@ public class SU3File {
private static final boolean signCLI(SigType type, String inputFile, String signedFile, private static final boolean signCLI(SigType type, String inputFile, String signedFile,
String privateKeyFile, String version, String signerName) { String privateKeyFile, String version, String signerName) {
try { 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); 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); SigningPrivateKey spk = SigUtil.fromJavaKey(pk, type);
SU3File file = new SU3File(signedFile); SU3File file = new SU3File(signedFile);
file.write(new File(inputFile), CONTENT_ROUTER, version, signerName, spk); 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) { private static final boolean genKeysCLI(SigType type, String publicKeyFile, String privateKeyFile) {
File pubFile = new File(publicKeyFile); File pubFile = new File(publicKeyFile);
File privFile = new File(privateKeyFile);
if (pubFile.exists()) { if (pubFile.exists()) {
System.out.println("Error: Not overwriting file " + publicKeyFile); System.out.println("Error: Not overwriting file " + publicKeyFile);
return false; return false;
} }
if (privFile.exists()) { File ksFile = new File(privateKeyFile);
System.out.println("Error: Not overwriting 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; return false;
} }
FileOutputStream fileOutputStream = null; int keylen = type.getPubkeyLen() * 8;
I2PAppContext context = I2PAppContext.getGlobalContext(); if (type.getBaseAlgorithm() == SigAlgo.EC) {
try { keylen /= 2;
// inefficiently go from Java to I2P to Java formats if (keylen == 528)
SimpleDataStructure signingKeypair[] = context.keyGenerator().generateSigningKeys(type); keylen = 521;
SigningPublicKey signingPublicKey = (SigningPublicKey) signingKeypair[0]; }
SigningPrivateKey signingPrivateKey = (SigningPrivateKey) signingKeypair[1]; boolean success = KeyStoreUtil.createKeys(ksFile, KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD, alias,
PublicKey pubkey = SigUtil.toJavaKey(signingPublicKey); "cn", "ou", 3652, type.getBaseAlgorithm().getName(),
PrivateKey privkey = SigUtil.toJavaKey(signingPrivateKey); keylen, keypw);
if (!success) {
fileOutputStream = new SecureFileOutputStream(pubFile); System.err.println("Error writing keys:");
fileOutputStream.write(pubkey.getEncoded()); return false;
fileOutputStream.close(); }
fileOutputStream = null; File outfile = new File(publicKeyFile);
success = KeyStoreUtil.exportCert(ksFile, KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD, alias, outfile);
fileOutputStream = new SecureFileOutputStream(privFile); if (!success) {
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) {
System.err.println("Error writing keys:"); System.err.println("Error writing keys:");
e.printStackTrace();
return false; return false;
} finally {
if (fileOutputStream != null)
try {
fileOutputStream.close();
} catch (IOException ioe) {}
} }
return true; return true;
} }