diff --git a/core/java/src/net/i2p/crypto/CertUtil.java b/core/java/src/net/i2p/crypto/CertUtil.java index 239b057edb3bdf9d680eca8e64ce4f1336032040..fe588fce375d44738e31379f4bf0f7c923dd8ee4 100644 --- a/core/java/src/net/i2p/crypto/CertUtil.java +++ b/core/java/src/net/i2p/crypto/CertUtil.java @@ -1,11 +1,16 @@ package net.i2p.crypto; import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; +import java.security.GeneralSecurityException; +import java.security.PublicKey; import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.util.Locale; @@ -134,4 +139,40 @@ public class CertUtil { Log l = ctx.logManager().getLog(CertUtil.class); l.log(level, msg, t); } + + /** + * Get the Java public key from a X.509 certificate file. + * Throws if the certificate is invalid (e.g. expired). + * + * @return non-null, throws on all errors including certificate invalid + * @since 0.9.24 moved from SU3File private method + */ + public static PublicKey loadKey(File kd) throws IOException, GeneralSecurityException { + return loadCert(kd).getPublicKey(); + } + + /** + * Get the certificate from a X.509 certificate file. + * Throws if the certificate is invalid (e.g. expired). + * + * @return non-null, throws on all errors including certificate invalid + * @since 0.9.24 adapted from SU3File private method + */ + public static X509Certificate loadCert(File kd) throws IOException, GeneralSecurityException { + InputStream fis = null; + try { + fis = new FileInputStream(kd); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate)cf.generateCertificate(fis); + cert.checkValidity(); + return cert; + } catch (IllegalArgumentException iae) { + // java 1.8.0_40-b10, openSUSE + // Exception in thread "main" java.lang.IllegalArgumentException: Input byte array has wrong 4-byte ending unit + // at java.util.Base64$Decoder.decode0(Base64.java:704) + throw new GeneralSecurityException("cert error", iae); + } finally { + try { if (fis != null) fis.close(); } catch (IOException foo) {} + } + } } diff --git a/core/java/src/net/i2p/crypto/DirKeyRing.java b/core/java/src/net/i2p/crypto/DirKeyRing.java index cc840b36e796d730de755622f0e3a10e198fbf34..899f41847dec24d1d05fa92df2891aa646a52a40 100644 --- a/core/java/src/net/i2p/crypto/DirKeyRing.java +++ b/core/java/src/net/i2p/crypto/DirKeyRing.java @@ -35,6 +35,8 @@ class DirKeyRing implements KeyRing { * and have a CN == keyName. * * CN check unsupported on Android. + * + * @return null if file doesn't exist, throws on all other errors */ public PublicKey getKey(String keyName, String scope, SigType type) throws GeneralSecurityException, IOException { @@ -47,26 +49,15 @@ class DirKeyRing implements KeyRing { File kd = new File(sd, fileName + ".crt"); if (!kd.exists()) return null; - InputStream fis = null; - try { - fis = new FileInputStream(kd); - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - X509Certificate cert = (X509Certificate)cf.generateCertificate(fis); - cert.checkValidity(); - if (!SystemVersion.isAndroid()) { - // getSubjectValue() unsupported on Android. - // Any cert problems will be caught in non-Android testing. - String cn = CertUtil.getSubjectValue(cert, "CN"); - if (!keyName.equals(cn)) - throw new GeneralSecurityException("CN mismatch: " + cn); - } - return cert.getPublicKey(); - } catch (IllegalArgumentException iae) { - // java 1.8.0_40-b10, openSUSE - throw new GeneralSecurityException("Bad cert", iae); - } finally { - try { if (fis != null) fis.close(); } catch (IOException foo) {} + X509Certificate cert = CertUtil.loadCert(kd); + if (!SystemVersion.isAndroid()) { + // getSubjectValue() unsupported on Android. + // Any cert problems will be caught in non-Android testing. + String cn = CertUtil.getSubjectValue(cert, "CN"); + if (!keyName.equals(cn)) + throw new GeneralSecurityException("CN mismatch: " + cn); } + return cert.getPublicKey(); } /** diff --git a/core/java/src/net/i2p/crypto/KeyStoreUtil.java b/core/java/src/net/i2p/crypto/KeyStoreUtil.java index 7c79fa274f35c55e3b3f68d9b95167438fe9f85a..fe65a7afb057fc8fe625ed0dbaeebbae6fb2d894 100644 --- a/core/java/src/net/i2p/crypto/KeyStoreUtil.java +++ b/core/java/src/net/i2p/crypto/KeyStoreUtil.java @@ -12,7 +12,6 @@ import java.security.PrivateKey; import java.security.cert.Certificate; import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateNotYetValidException; -import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.Enumeration; import java.util.Locale; @@ -317,46 +316,32 @@ public class KeyStoreUtil { * @since 0.8.2, moved from SSLEepGet in 0.9.9 */ public static boolean addCert(File file, String alias, KeyStore ks) { - InputStream fis = null; try { - fis = new FileInputStream(file); - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - X509Certificate cert = (X509Certificate)cf.generateCertificate(fis); + X509Certificate cert = CertUtil.loadCert(file); info("Read X509 Certificate from " + file.getAbsolutePath() + " Issuer: " + cert.getIssuerX500Principal() + " Serial: " + cert.getSerialNumber().toString(16) + "; Valid From: " + cert.getNotBefore() + " To: " + cert.getNotAfter()); - try { - cert.checkValidity(); - } catch (CertificateExpiredException cee) { - String s = "Rejecting expired X509 Certificate: " + file.getAbsolutePath(); - // Android often has old system certs - if (SystemVersion.isAndroid()) - warn(s, cee); - else - error(s, cee); - return false; - } catch (CertificateNotYetValidException cnyve) { - error("Rejecting X509 Certificate not yet valid: " + file.getAbsolutePath(), cnyve); - return false; - } ks.setCertificateEntry(alias, cert); info("Now trusting X509 Certificate, Issuer: " + cert.getIssuerX500Principal()); + } catch (CertificateExpiredException cee) { + String s = "Rejecting expired X509 Certificate: " + file.getAbsolutePath(); + // Android often has old system certs + if (SystemVersion.isAndroid()) + warn(s, cee); + else + error(s, cee); + return false; + } catch (CertificateNotYetValidException cnyve) { + error("Rejecting X509 Certificate not yet valid: " + file.getAbsolutePath(), cnyve); + return false; } catch (GeneralSecurityException gse) { error("Error reading X509 Certificate: " + file.getAbsolutePath(), gse); return false; } catch (IOException ioe) { error("Error reading X509 Certificate: " + file.getAbsolutePath(), ioe); return false; - } catch (IllegalArgumentException iae) { - // java 1.8.0_40-b10, openSUSE - // Exception in thread "main" java.lang.IllegalArgumentException: Input byte array has wrong 4-byte ending unit - // at java.util.Base64$Decoder.decode0(Base64.java:704) - error("Error reading X509 Certificate: " + file.getAbsolutePath(), iae); - return false; - } finally { - try { if (fis != null) fis.close(); } catch (IOException foo) {} } return true; } diff --git a/core/java/src/net/i2p/crypto/SU3File.java b/core/java/src/net/i2p/crypto/SU3File.java index f8753aee50d3a55454e49c10c35aa0bdaa837be7..3c8154c6eeab3e9f87aed62b0f813e46d9f2e196 100644 --- a/core/java/src/net/i2p/crypto/SU3File.java +++ b/core/java/src/net/i2p/crypto/SU3File.java @@ -15,8 +15,6 @@ import java.security.GeneralSecurityException; import java.security.MessageDigest; import java.security.PrivateKey; import java.security.PublicKey; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; @@ -978,24 +976,12 @@ public class SU3File { * @since 0.9.15 */ private static PublicKey loadKey(File kd) throws IOException { - InputStream fis = null; try { - fis = new FileInputStream(kd); - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - X509Certificate cert = (X509Certificate)cf.generateCertificate(fis); - cert.checkValidity(); - return cert.getPublicKey(); + return CertUtil.loadKey(kd); } catch (GeneralSecurityException gse) { IOException ioe = new IOException("cert error"); ioe.initCause(gse); throw ioe; - } catch (IllegalArgumentException iae) { - // java 1.8.0_40-b10, openSUSE - IOException ioe = new IOException("cert error"); - ioe.initCause(iae); - throw ioe; - } finally { - try { if (fis != null) fis.close(); } catch (IOException foo) {} } } }