Tools: Export private key from private key file in X.509 form

Add missing loadprivatekey command to CertUtil
This commit is contained in:
zzz
2020-05-13 20:19:12 +00:00
parent f233416bf6
commit 50e44ece54
3 changed files with 73 additions and 2 deletions

View File

@ -40,6 +40,7 @@ import javax.security.auth.x500.X500Principal;
import net.i2p.I2PAppContext; import net.i2p.I2PAppContext;
import net.i2p.data.Base64; import net.i2p.data.Base64;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
import net.i2p.data.SigningPrivateKey;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.util.FileSuffixFilter; import net.i2p.util.FileSuffixFilter;
import net.i2p.util.SecureFileOutputStream; import net.i2p.util.SecureFileOutputStream;
@ -583,6 +584,10 @@ public final class CertUtil {
Certificate cert = loadCert(f); Certificate cert = loadCert(f);
boolean rv = isRevoked(I2PAppContext.getGlobalContext(), cert); boolean rv = isRevoked(I2PAppContext.getGlobalContext(), cert);
System.out.println("Revoked? " + rv); System.out.println("Revoked? " + rv);
} else if (args[0].equals("loadprivatekey")) {
PrivateKey priv = loadPrivateKey(new FileInputStream(f));
SigningPrivateKey spk = SigUtil.fromJavaKey(priv);
System.out.println("Found private key: " + spk);
} else if (args[0].equals("checkall")) { } else if (args[0].equals("checkall")) {
int rv = checkAll(f); int rv = checkAll(f);
//System.exit(rv); //System.exit(rv);

View File

@ -157,6 +157,23 @@ public final class SelfSignedGenerator {
} }
} }
/**
* Create a self-signed certificate for the existing private key.
*
* @param cname the common name, non-null. Must be a hostname or email address. IP addresses will not be correctly encoded.
* @return self-signed certificate
* @since 0.9.46
*/
public static X509Certificate generate(SigningPrivateKey priv, String cname,
int validDays) throws GeneralSecurityException {
SigningPublicKey pub = priv.toPublic();
PublicKey jpub = SigUtil.toJavaKey(pub);
PrivateKey jpriv = SigUtil.toJavaKey(priv);
SigType type = priv.getType();
Object[] o = generate(jpub, jpriv, priv, type, cname, null, null, null, null, null, null, validDays);
return (X509Certificate) o[2];
}
/** /**
* @param cname the common name, non-null. Must be a hostname or email address. IP addresses will not be correctly encoded. * @param cname the common name, non-null. Must be a hostname or email address. IP addresses will not be correctly encoded.
* @param altNames the Subject Alternative Names. May be null. May contain hostnames and/or IP addresses. * @param altNames the Subject Alternative Names. May be null. May contain hostnames and/or IP addresses.

View File

@ -5,12 +5,14 @@ import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream; import java.io.InputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.Date; import java.util.Date;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Locale; import java.util.Locale;
@ -29,12 +31,15 @@ import net.i2p.client.I2PSession;
import net.i2p.client.I2PSessionException; import net.i2p.client.I2PSessionException;
import net.i2p.client.naming.HostTxtEntry; import net.i2p.client.naming.HostTxtEntry;
import net.i2p.crypto.Blinding; import net.i2p.crypto.Blinding;
import net.i2p.crypto.CertUtil;
import net.i2p.crypto.DSAEngine; import net.i2p.crypto.DSAEngine;
import net.i2p.crypto.EncType; import net.i2p.crypto.EncType;
import net.i2p.crypto.KeyGenerator; import net.i2p.crypto.KeyGenerator;
import net.i2p.crypto.KeyPair; import net.i2p.crypto.KeyPair;
import net.i2p.crypto.SelfSignedGenerator;
import net.i2p.crypto.SigAlgo; import net.i2p.crypto.SigAlgo;
import net.i2p.crypto.SigType; import net.i2p.crypto.SigType;
import net.i2p.crypto.SigUtil;
import net.i2p.util.OrderedProperties; import net.i2p.util.OrderedProperties;
import net.i2p.util.RandomSource; import net.i2p.util.RandomSource;
import net.i2p.util.SecureFileOutputStream; import net.i2p.util.SecureFileOutputStream;
@ -101,10 +106,11 @@ public class PrivateKeyFile {
String signer = null; String signer = null;
String signername = null; String signername = null;
String signaction = null; String signaction = null;
String certfile = null;
int days = 365; int days = 365;
int mode = 0; int mode = 0;
boolean error = false; boolean error = false;
Getopt g = new Getopt("pkf", args, "t:nuxhse:c:a:o:d:r:p:b:y:z:"); Getopt g = new Getopt("pkf", args, "t:nuxhse:c:a:o:d:r:p:b:y:z:w:");
int c; int c;
while ((c = g.getopt()) != -1) { while ((c = g.getopt()) != -1) {
switch (c) { switch (c) {
@ -143,6 +149,14 @@ public class PrivateKeyFile {
signername = g.getOptarg(); signername = g.getOptarg();
break; break;
case 'w':
certfile = g.getOptarg();
if (mode == 0)
mode = c;
else
error = true;
break;
case 'y': case 'y':
signer = g.getOptarg(); signer = g.getOptarg();
break; break;
@ -348,6 +362,36 @@ public class PrivateKeyFile {
return; return;
} }
case 'w':
{
if (pkf.isOffline()) {
System.out.println("Private key is offline, not present in file, export failed");
return;
}
OutputStream out = null;
try {
SigningPrivateKey priv = pkf.getSigningPrivKey();
java.security.PrivateKey jpriv = SigUtil.toJavaKey(priv);
if (signername == null)
signername = "example.i2p";
X509Certificate cert = SelfSignedGenerator.generate(priv, signername, days);
java.security.cert.Certificate[] certs = { cert };
out = new FileOutputStream(certfile);
CertUtil.exportPrivateKey(jpriv, certs, out);
System.out.println("Private key and self-signed certificate exported to " + certfile);
} catch (IOException ioe) {
System.out.println("Private key export failed");
ioe.printStackTrace();
} catch (GeneralSecurityException gse) {
System.out.println("Private key export failed");
gse.printStackTrace();
} finally {
if (out != null) try { out.close(); } catch (IOException ioe) {}
}
return;
}
default: default:
// shouldn't happen // shouldn't happen
usage(); usage();
@ -359,9 +403,13 @@ public class PrivateKeyFile {
verifySignature(pkf.getDestination()); verifySignature(pkf.getDestination());
} }
} catch (I2PException e) { } catch (I2PException e) {
String orig = offline != null ? offline : filearg;
System.out.println("Error processing file: " + orig);
e.printStackTrace(); e.printStackTrace();
System.exit(1); System.exit(1);
} catch (IOException e) { } catch (IOException e) {
String orig = offline != null ? offline : filearg;
System.out.println("Error processing file: " + orig);
e.printStackTrace(); e.printStackTrace();
System.exit(1); System.exit(1);
} }
@ -385,6 +433,7 @@ public class PrivateKeyFile {
" -p enctype (specify enc type of destination)\n" + " -p enctype (specify enc type of destination)\n" +
" -r sigtype (specify sig type of transient key, default Ed25519)\n" + " -r sigtype (specify sig type of transient key, default Ed25519)\n" +
" -t sigtype (changes to KeyCertificate of the given sig type)\n" + " -t sigtype (changes to KeyCertificate of the given sig type)\n" +
" -w file.key (export the private signing key to the file specified, also uses -d and -b options)\n" +
" -y 2lddestfile (sign the authentication string with the 2LD key file specified)\n" + " -y 2lddestfile (sign the authentication string with the 2LD key file specified)\n" +
" -z signaction (authentication string command, must be \"addsubdomain\"\n" + " -z signaction (authentication string command, must be \"addsubdomain\"\n" +
""); "");
@ -941,8 +990,8 @@ public class PrivateKeyFile {
s.append(_transientSigningPrivKey); s.append(_transientSigningPrivKey);
} else { } else {
s.append(this.signingPrivKey); s.append(this.signingPrivKey);
s.append("\n");
} }
s.append("\n");
return s.toString(); return s.toString();
} }