forked from I2P_Developers/i2p.i2p
Crypto: Use new internal key generation instead of calling
out to keytool; save CRL for new su3 amd family keys Allow su3 bulksign for xml files (news)
This commit is contained in:
@ -97,9 +97,9 @@ public final class CertUtil {
|
||||
* Writes a certificate in base64 format.
|
||||
* Does NOT close the stream. Throws on all errors.
|
||||
*
|
||||
* @since 0.9.24, pulled out of saveCert()
|
||||
* @since 0.9.24, pulled out of saveCert(), public since 0.9.25
|
||||
*/
|
||||
private static void exportCert(Certificate cert, OutputStream out)
|
||||
public static void exportCert(Certificate cert, OutputStream out)
|
||||
throws IOException, CertificateEncodingException {
|
||||
// Get the encoded form which is suitable for exporting
|
||||
byte[] buf = cert.getEncoded();
|
||||
@ -365,7 +365,7 @@ public final class CertUtil {
|
||||
* @throws CRLException if the crl does not support encoding
|
||||
* @since 0.9.25
|
||||
*/
|
||||
private static void exportCRL(X509CRL crl, OutputStream out)
|
||||
public static void exportCRL(X509CRL crl, OutputStream out)
|
||||
throws IOException, CRLException {
|
||||
byte[] buf = crl.getEncoded();
|
||||
writePEM(buf, "X509 CRL", out);
|
||||
|
@ -9,12 +9,16 @@ import java.math.BigInteger;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateExpiredException;
|
||||
import java.security.cert.CertificateNotYetValidException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.cert.X509CRL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
@ -430,6 +434,9 @@ public final class KeyStoreUtil {
|
||||
/**
|
||||
* Create a keypair and store it in the keystore at ks, creating it if necessary.
|
||||
*
|
||||
* For new code, the createKeys() with the SigType argument is recommended over this one,
|
||||
* as it throws exceptions, and returns the certificate and CRL.
|
||||
*
|
||||
* Warning, may take a long time.
|
||||
*
|
||||
* @param ks path to the keystore
|
||||
@ -447,6 +454,137 @@ public final class KeyStoreUtil {
|
||||
*/
|
||||
public static boolean createKeys(File ks, String ksPW, String alias, String cname, String ou,
|
||||
int validDays, String keyAlg, int keySize, String keyPW) {
|
||||
boolean useKeytool = I2PAppContext.getGlobalContext().getBooleanProperty("crypto.useExternalKeytool");
|
||||
if (useKeytool) {
|
||||
return createKeysCLI(ks, ksPW, alias, cname, ou, validDays, keyAlg, keySize, keyPW);
|
||||
} else {
|
||||
try {
|
||||
createKeysAndCRL(ks, ksPW, alias, cname, ou, validDays, keyAlg, keySize, keyPW);
|
||||
return true;
|
||||
} catch (GeneralSecurityException gse) {
|
||||
error("Create keys error", gse);
|
||||
return false;
|
||||
} catch (IOException ioe) {
|
||||
error("Create keys error", ioe);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* New way - Native Java, does not call out to keytool.
|
||||
* Create a keypair and store it in the keystore at ks, creating it if necessary.
|
||||
*
|
||||
* This returns the public key, private key, certificate, and CRL in an array.
|
||||
* All of these are Java classes. Keys may be converted to I2P classes with SigUtil.
|
||||
* The private key and selfsigned cert are stored in the keystore.
|
||||
* The public key may be derived from the private key with KeyGenerator.getSigningPublicKey().
|
||||
* The public key certificate may be stored separately with
|
||||
* CertUtil.saveCert() if desired.
|
||||
* The CRL is not stored by this method, store it with
|
||||
* CertUtil.saveCRL() or CertUtil.exportCRL() if desired.
|
||||
*
|
||||
* Throws on all errors.
|
||||
* 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 all you need:
|
||||
* rv[0] is a Java PublicKey
|
||||
* rv[1] is a Java PrivateKey
|
||||
* rv[2] is a Java X509Certificate
|
||||
* rv[3] is a Java X509CRL
|
||||
* @since 0.9.25
|
||||
*/
|
||||
public static Object[] createKeysAndCRL(File ks, String ksPW, String alias, String cname, String ou,
|
||||
int validDays, String keyAlg, int keySize, String keyPW)
|
||||
throws GeneralSecurityException, IOException {
|
||||
String algoName = getSigAlg(keySize, keyAlg);
|
||||
SigType type = null;
|
||||
for (SigType t : EnumSet.allOf(SigType.class)) {
|
||||
if (t.getAlgorithmName().equals(algoName)) {
|
||||
type = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (type == null)
|
||||
throw new GeneralSecurityException("Unsupported algorithm/size: " + keyAlg + '/' + keySize);
|
||||
return createKeysAndCRL(ks, ksPW, alias, cname, ou, validDays, type, keyPW);
|
||||
}
|
||||
|
||||
/**
|
||||
* New way - Native Java, does not call out to keytool.
|
||||
* Create a keypair and store it in the keystore at ks, creating it if necessary.
|
||||
*
|
||||
* This returns the public key, private key, certificate, and CRL in an array.
|
||||
* All of these are Java classes. Keys may be converted to I2P classes with SigUtil.
|
||||
* The private key and selfsigned cert are stored in the keystore.
|
||||
* The public key may be derived from the private key with KeyGenerator.getSigningPublicKey().
|
||||
* The public key certificate may be stored separately with
|
||||
* CertUtil.saveCert() if desired.
|
||||
* The CRL is not stored by this method, store it with
|
||||
* CertUtil.saveCRL() or CertUtil.exportCRL() if desired.
|
||||
*
|
||||
* Throws on all errors.
|
||||
* 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 all you need:
|
||||
* rv[0] is a Java PublicKey
|
||||
* rv[1] is a Java PrivateKey
|
||||
* rv[2] is a Java X509Certificate
|
||||
* rv[3] is a Java X509CRL
|
||||
* @since 0.9.25
|
||||
*/
|
||||
public static Object[] createKeysAndCRL(File ks, String ksPW, String alias, String cname, String ou,
|
||||
int validDays, SigType type, String keyPW)
|
||||
throws GeneralSecurityException, IOException {
|
||||
Object[] rv = SelfSignedGenerator.generate(cname, ou, "XX", "I2P Anonymous Network", "XX", "XX", validDays, type);
|
||||
PublicKey jpub = (PublicKey) rv[0];
|
||||
PrivateKey jpriv = (PrivateKey) rv[1];
|
||||
X509Certificate cert = (X509Certificate) rv[2];
|
||||
X509CRL crl = (X509CRL) rv[3];
|
||||
List<X509Certificate> certs = Collections.singletonList(cert);
|
||||
storePrivateKey(ks, ksPW, alias, keyPW, jpriv, certs);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* OLD way - keytool
|
||||
* Create a keypair and store it in the keystore at ks, creating it if necessary.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
private static boolean createKeysCLI(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) {
|
||||
|
@ -15,6 +15,8 @@ import java.security.GeneralSecurityException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.cert.X509CRL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
@ -33,6 +35,7 @@ import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Signature;
|
||||
import net.i2p.data.SimpleDataStructure;
|
||||
import net.i2p.util.SecureFileOutputStream;
|
||||
|
||||
/**
|
||||
* Succesor to the ".sud" format used in TrustedUpdate.
|
||||
@ -538,10 +541,11 @@ public class SU3File {
|
||||
String ctype = null;
|
||||
String ftype = null;
|
||||
String kfile = null;
|
||||
String crlfile = null;
|
||||
String kspass = KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD;
|
||||
boolean error = false;
|
||||
boolean shouldVerify = true;
|
||||
Getopt g = new Getopt("SU3File", args, "t:c:f:k:xp:");
|
||||
Getopt g = new Getopt("SU3File", args, "t:c:f:k:xp:r:");
|
||||
int c;
|
||||
while ((c = g.getopt()) != -1) {
|
||||
switch (c) {
|
||||
@ -561,6 +565,10 @@ public class SU3File {
|
||||
kfile = g.getOptarg();
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
crlfile = g.getOptarg();
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
shouldVerify = false;
|
||||
break;
|
||||
@ -598,7 +606,10 @@ public class SU3File {
|
||||
} else if ("verifysig".equals(cmd)) {
|
||||
ok = verifySigCLI(a.get(0), kfile);
|
||||
} else if ("keygen".equals(cmd)) {
|
||||
ok = genKeysCLI(stype, a.get(0), a.get(1), a.get(2), kspass);
|
||||
Properties props = new Properties();
|
||||
props.setProperty("prng.bufferSize", "16384");
|
||||
new I2PAppContext(props);
|
||||
ok = genKeysCLI(stype, a.get(0), a.get(1), crlfile, a.get(2), kspass);
|
||||
} else if ("extract".equals(cmd)) {
|
||||
ok = extractCLI(a.get(0), a.get(1), shouldVerify, kfile);
|
||||
} else {
|
||||
@ -614,9 +625,10 @@ public class SU3File {
|
||||
}
|
||||
|
||||
private static final void showUsageCLI() {
|
||||
System.err.println("Usage: SU3File keygen [-t type|code] [-p keystorepw] publicKeyFile keystore.ks you@mail.i2p\n" +
|
||||
System.err.println("Usage: SU3File keygen [-t type|code] [-p keystorepw] [-r crlFile.crl] publicKeyFile.crt keystore.ks you@mail.i2p\n" +
|
||||
" SU3File sign [-t type|code] [-c type|code] [-f type|code] [-p keystorepw] inputFile.zip signedFile.su3 keystore.ks version you@mail.i2p\n" +
|
||||
" SU3File bulksign [-t type|code] [-c type|code] [-p keystorepw] directory keystore.ks version you@mail.i2p\n" +
|
||||
" (signs all .zip and .xml files in the directory)\n" +
|
||||
" SU3File showversion signedFile.su3\n" +
|
||||
" SU3File verifysig [-k file.crt] signedFile.su3 ## -k use this pubkey cert for verification\n" +
|
||||
" SU3File extract [-x] [-k file.crt] signedFile.su3 outFile ## -x don't check sig");
|
||||
@ -750,7 +762,7 @@ public class SU3File {
|
||||
int success = 0;
|
||||
for (File in : files) {
|
||||
String inputFile = in.getPath();
|
||||
if (!inputFile.endsWith(".zip"))
|
||||
if (!inputFile.endsWith(".zip") && !inputFile.endsWith(".xml"))
|
||||
continue;
|
||||
String signedFile = inputFile.substring(0, inputFile.length() - 4) + ".su3";
|
||||
boolean rv = signCLI(stype, ctype, null, inputFile, signedFile,
|
||||
@ -897,26 +909,29 @@ public class SU3File {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param crlFile may be null; non-null to save
|
||||
* @return success
|
||||
* @since 0.9.9
|
||||
*/
|
||||
private static final boolean genKeysCLI(String stype, String publicKeyFile, String privateKeyFile,
|
||||
String alias, String kspass) {
|
||||
String crlFile, String alias, String kspass) {
|
||||
SigType type = stype == null ? SigType.getByCode(Integer.valueOf(DEFAULT_SIG_CODE)) : SigType.parseSigType(stype);
|
||||
if (type == null) {
|
||||
System.out.println("Signature type " + stype + " is not supported");
|
||||
return false;
|
||||
}
|
||||
return genKeysCLI(type, publicKeyFile, privateKeyFile, alias, kspass);
|
||||
return genKeysCLI(type, publicKeyFile, privateKeyFile, crlFile, alias, kspass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes Java-encoded keys (X.509 for public and PKCS#8 for private)
|
||||
*
|
||||
* @param crlFile may be null; non-null to save
|
||||
* @return success
|
||||
* @since 0.9.9
|
||||
*/
|
||||
private static final boolean genKeysCLI(SigType type, String publicKeyFile, String privateKeyFile,
|
||||
String alias, String kspass) {
|
||||
String crlFile, String alias, String kspass) {
|
||||
File pubFile = new File(publicKeyFile);
|
||||
if (pubFile.exists()) {
|
||||
System.out.println("Error: Not overwriting file " + publicKeyFile);
|
||||
@ -948,24 +963,29 @@ public class SU3File {
|
||||
} catch (IOException ioe) {
|
||||
return false;
|
||||
}
|
||||
int keylen = type.getPubkeyLen() * 8;
|
||||
if (type.getBaseAlgorithm() == SigAlgo.EC) {
|
||||
keylen /= 2;
|
||||
if (keylen == 528)
|
||||
keylen = 521;
|
||||
}
|
||||
boolean success = KeyStoreUtil.createKeys(ksFile, kspass, alias,
|
||||
alias, "I2P", 3652, type.getBaseAlgorithm().getName(),
|
||||
keylen, keypw);
|
||||
if (!success) {
|
||||
OutputStream out = null;
|
||||
try {
|
||||
Object[] rv = KeyStoreUtil.createKeysAndCRL(ksFile, kspass, alias,
|
||||
alias, "I2P", 3652, type, keypw);
|
||||
X509Certificate cert = (X509Certificate) rv[2];
|
||||
out = new SecureFileOutputStream(publicKeyFile);
|
||||
CertUtil.exportCert(cert, out);
|
||||
if (crlFile != null) {
|
||||
out.close();
|
||||
X509CRL crl = (X509CRL) rv[3];
|
||||
out = new SecureFileOutputStream(crlFile);
|
||||
CertUtil.exportCRL(crl, out);
|
||||
}
|
||||
} catch (GeneralSecurityException gse) {
|
||||
System.err.println("Error creating keys for " + alias);
|
||||
gse.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
File outfile = new File(publicKeyFile);
|
||||
success = KeyStoreUtil.exportCert(ksFile, KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD, alias, outfile);
|
||||
if (!success) {
|
||||
System.err.println("Error writing public key for " + alias + " to " + outfile);
|
||||
} catch (IOException ioe) {
|
||||
System.err.println("Error creating keys for " + alias);
|
||||
ioe.printStackTrace();
|
||||
return false;
|
||||
} finally {
|
||||
if (out != null) try { out.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ import java.security.KeyStore;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.cert.X509CRL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@ -51,6 +53,7 @@ public class FamilyKeyCrypto {
|
||||
public static final String PROP_FAMILY_NAME = "netdb.family.name";
|
||||
public static final String PROP_KEY_PASSWORD = "netdb.family.keyPassword";
|
||||
public static final String CERT_SUFFIX = ".crt";
|
||||
public static final String CRL_SUFFIX = ".crl";
|
||||
public static final String KEYSTORE_PREFIX = "family-";
|
||||
public static final String KEYSTORE_SUFFIX = ".ks";
|
||||
public static final String CN_SUFFIX = ".family.i2p.net";
|
||||
@ -61,6 +64,7 @@ public class FamilyKeyCrypto {
|
||||
private static final int DEFAULT_KEY_SIZE = SigType.ECDSA_SHA256_P256.isAvailable() ? 256 : 1024;
|
||||
private static final String KS_DIR = "keystore";
|
||||
private static final String CERT_DIR = "certificates/family";
|
||||
private static final String CRL_DIR = "crls";
|
||||
public static final String OPT_NAME = "family";
|
||||
public static final String OPT_SIG = "family.sig";
|
||||
public static final String OPT_KEY = "family.key";
|
||||
@ -270,11 +274,12 @@ public class FamilyKeyCrypto {
|
||||
throw new GeneralSecurityException(s);
|
||||
}
|
||||
}
|
||||
createKeyStore(ks);
|
||||
|
||||
// Now read it back out of the new keystore and save it in ascii form
|
||||
// where the clients can get to it.
|
||||
exportCert(ks);
|
||||
try {
|
||||
createKeyStore(ks);
|
||||
} catch (IOException ioe) {
|
||||
throw new GeneralSecurityException("Failed to create NetDb family keystore", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -286,26 +291,22 @@ public class FamilyKeyCrypto {
|
||||
*
|
||||
* @throws GeneralSecurityException on all errors
|
||||
*/
|
||||
private void createKeyStore(File ks) throws GeneralSecurityException {
|
||||
private void createKeyStore(File ks) throws GeneralSecurityException, IOException {
|
||||
// make a random 48 character password (30 * 8 / 5)
|
||||
String keyPassword = KeyStoreUtil.randomString();
|
||||
// and one for the cname
|
||||
String cname = _fname + CN_SUFFIX;
|
||||
|
||||
boolean success = KeyStoreUtil.createKeys(ks, KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD, _fname, cname, "family",
|
||||
Object[] rv = KeyStoreUtil.createKeysAndCRL(ks, KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD, _fname, cname, "family",
|
||||
DEFAULT_KEY_VALID_DAYS, DEFAULT_KEY_ALGORITHM,
|
||||
DEFAULT_KEY_SIZE, keyPassword);
|
||||
if (success) {
|
||||
success = ks.exists();
|
||||
if (success) {
|
||||
|
||||
Map<String, String> changes = new HashMap<String, String>();
|
||||
changes.put(PROP_KEYSTORE_PASSWORD, KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD);
|
||||
changes.put(PROP_KEY_PASSWORD, keyPassword);
|
||||
changes.put(PROP_FAMILY_NAME, _fname);
|
||||
_context.router().saveConfig(changes, null);
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
|
||||
_log.logAlways(Log.INFO, "Created new private key for netdb family \"" + _fname +
|
||||
"\" in keystore: " + ks.getAbsolutePath() + "\n" +
|
||||
"Copy the keystore to the other routers in the family,\n" +
|
||||
@ -314,27 +315,22 @@ public class FamilyKeyCrypto {
|
||||
PROP_KEYSTORE_PASSWORD + '=' + KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD + '\n' +
|
||||
PROP_KEY_PASSWORD + '=' + keyPassword);
|
||||
|
||||
} else {
|
||||
String s = "Failed to create NetDb family keystore.\n" +
|
||||
"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();
|
||||
_log.error(s);
|
||||
throw new GeneralSecurityException(s);
|
||||
}
|
||||
X509Certificate cert = (X509Certificate) rv[2];
|
||||
exportCert(cert);
|
||||
X509CRL crl = (X509CRL) rv[3];
|
||||
exportCRL(ks.getParentFile(), crl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull the cert back OUT of the keystore and save it as ascii
|
||||
* Save the public key certificate
|
||||
* so the clients can get to it.
|
||||
*/
|
||||
private void exportCert(File ks) {
|
||||
private void exportCert(X509Certificate cert) {
|
||||
File sdir = new SecureDirectory(_context.getConfigDir(), CERT_DIR);
|
||||
if (sdir.exists() || sdir.mkdirs()) {
|
||||
String ksPass = _context.getProperty(PROP_KEYSTORE_PASSWORD, KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD);
|
||||
String name = _fname.replace("@", "_at_") + CERT_SUFFIX;
|
||||
File out = new File(sdir, name);
|
||||
boolean success = KeyStoreUtil.exportCert(ks, ksPass, _fname, out);
|
||||
boolean success = CertUtil.saveCert(cert, out);
|
||||
if (success) {
|
||||
_log.logAlways(Log.INFO, "Created new public key certificate for netdb family \"" + _fname +
|
||||
"\" in file: " + out.getAbsolutePath() + "\n" +
|
||||
@ -342,10 +338,34 @@ public class FamilyKeyCrypto {
|
||||
"Copy the certificate to the directory $I2P/" + CERT_DIR + " for each of the other routers in the family.\n" +
|
||||
"Give this certificate to an I2P developer for inclusion in the next I2P release.");
|
||||
} else {
|
||||
_log.error("Error getting SSL cert to save as ASCII");
|
||||
_log.error("Error saving family key certificate");
|
||||
}
|
||||
} else {
|
||||
_log.error("Error saving ASCII SSL keys");
|
||||
_log.error("Error saving family key certificate");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the CRL just in case.
|
||||
* @param ksdir parent of directory to save in
|
||||
* @since 0.9.25
|
||||
*/
|
||||
private void exportCRL(File ksdir, X509CRL crl) {
|
||||
File sdir = new SecureDirectory(ksdir, CRL_DIR);
|
||||
if (sdir.exists() || sdir.mkdirs()) {
|
||||
String name = KEYSTORE_PREFIX + _fname.replace("@", "_at_") + '-' + System.currentTimeMillis() + CRL_SUFFIX;
|
||||
File out = new File(sdir, name);
|
||||
boolean success = CertUtil.saveCRL(crl, out);
|
||||
if (success) {
|
||||
_log.logAlways(Log.INFO, "Created certificate revocation list (CRL) for netdb family \"" + _fname +
|
||||
"\" in file: " + out.getAbsolutePath() + "\n" +
|
||||
"Back up the keystore and CRL files and keep them secure.\n" +
|
||||
"If your private key is ever compromised, give the CRL to an I2P developer for publication.");
|
||||
} else {
|
||||
_log.error("Error saving family key CRL");
|
||||
}
|
||||
} else {
|
||||
_log.error("Error saving family key CRL");
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user