diff --git a/core/java/src/net/i2p/crypto/CertUtil.java b/core/java/src/net/i2p/crypto/CertUtil.java index fe588fce3..0b5dfe669 100644 --- a/core/java/src/net/i2p/crypto/CertUtil.java +++ b/core/java/src/net/i2p/crypto/CertUtil.java @@ -8,6 +8,8 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; +import java.security.PrivateKey; import java.security.PublicKey; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; @@ -36,31 +38,16 @@ public class CertUtil { private static final int LINE_LENGTH = 64; /** - * Modified from: - * http://www.exampledepot.com/egs/java.security.cert/ExportCert.html - * - * This method writes a certificate to a file in base64 format. + * Write a certificate to a file in base64 format. * * @return success * @since 0.8.2, moved from SSLEepGet in 0.9.9 */ public static boolean saveCert(Certificate cert, File file) { OutputStream os = null; - PrintWriter wr = null; try { - // Get the encoded form which is suitable for exporting - byte[] buf = cert.getEncoded(); os = new SecureFileOutputStream(file); - wr = new PrintWriter(new OutputStreamWriter(os, "UTF-8")); - wr.println("-----BEGIN CERTIFICATE-----"); - String b64 = Base64.encode(buf, true); // true = use standard alphabet - for (int i = 0; i < b64.length(); i += LINE_LENGTH) { - wr.println(b64.substring(i, Math.min(i + LINE_LENGTH, b64.length()))); - } - wr.println("-----END CERTIFICATE-----"); - wr.flush(); - if (wr.checkError()) - throw new IOException("Failed write to " + file); + exportCert(cert, os); return true; } catch (CertificateEncodingException cee) { error("Error writing X509 Certificate " + file.getAbsolutePath(), cee); @@ -73,6 +60,79 @@ public class CertUtil { } } + /** + * Writes the private key and all certs in base64 format. + * Does NOT close the stream. Throws on all errors. + * + * @param pk non-null + * @param certs certificate chain, null or empty to export pk only + * @throws InvalidKeyException if the key does not support encoding + * @throws CertificateEncodingException if a cert does not support encoding + * @since 0.9.24 + */ + public static void exportPrivateKey(PrivateKey pk, Certificate[] certs, OutputStream out) + throws IOException, GeneralSecurityException { + exportPrivateKey(pk, out); + if (certs == null) + return; + for (int i = 0; i < certs.length; i++) { + exportCert(certs[i], out); + } + } + + /** + * Modified from: + * http://www.exampledepot.com/egs/java.security.cert/ExportCert.html + * + * Writes a certificate in base64 format. + * Does NOT close the stream. Throws on all errors. + * + * @since 0.9.24, pulled out of saveCert() + */ + private static void exportCert(Certificate cert, OutputStream out) + throws IOException, CertificateEncodingException { + // Get the encoded form which is suitable for exporting + byte[] buf = cert.getEncoded(); + PrintWriter wr = new PrintWriter(new OutputStreamWriter(out, "UTF-8")); + wr.println("-----BEGIN CERTIFICATE-----"); + String b64 = Base64.encode(buf, true); // true = use standard alphabet + for (int i = 0; i < b64.length(); i += LINE_LENGTH) { + wr.println(b64.substring(i, Math.min(i + LINE_LENGTH, b64.length()))); + } + wr.println("-----END CERTIFICATE-----"); + wr.flush(); + if (wr.checkError()) + throw new IOException("Failed write to " + out); + } + + /** + * Modified from: + * http://www.exampledepot.com/egs/java.security.cert/ExportCert.html + * + * Writes a private key in base64 format. + * Does NOT close the stream. Throws on all errors. + * + * @throws InvalidKeyException if the key does not support encoding + * @since 0.9.24 + */ + private static void exportPrivateKey(PrivateKey pk, OutputStream out) + throws IOException, InvalidKeyException { + // Get the encoded form which is suitable for exporting + byte[] buf = pk.getEncoded(); + if (buf == null) + throw new InvalidKeyException("encoding unsupported for this key"); + PrintWriter wr = new PrintWriter(new OutputStreamWriter(out, "UTF-8")); + wr.println("-----BEGIN PRIVATE KEY-----"); + String b64 = Base64.encode(buf, true); // true = use standard alphabet + for (int i = 0; i < b64.length(); i += LINE_LENGTH) { + wr.println(b64.substring(i, Math.min(i + LINE_LENGTH, b64.length()))); + } + wr.println("-----END PRIVATE KEY-----"); + wr.flush(); + if (wr.checkError()) + throw new IOException("Failed write to " + out); + } + /** * Get a value out of the subject distinguished name. *