Changeset 81808d4


Ignore:
Timestamp:
Mar 11, 2018 10:17:06 PM (2 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
ffc0bcc
Parents:
63a8b46
Message:

Crypto: Add utils for renewing a cert in a keystore

Location:
core/java/src/net/i2p
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • core/java/src/net/i2p/crypto/CertUtil.java

    r63a8b46 r81808d4  
    158158
    159159    /**
     160     *  Get the set of Subject Alternative Names, including
     161     *  DNSNames, RFC822Names, IPv4 and v6 addresses as strings.
     162     *
     163     *  see X509Certificate.getSubjectAlternativeNames()
     164     *
     165     *  @return non-null, empty on error or none found
     166     *  @since 0.9.34
     167     */
     168    public static Set<String> getSubjectAlternativeNames(X509Certificate cert) {
     169        Set<String> rv = new HashSet<String>(8);
     170        try {
     171            Collection<List<?>> c = cert.getSubjectAlternativeNames();
     172            if (c != null) {
     173                for (List<?> list : c) {
     174                    try {
     175                        rv.add((String) list.get(1));
     176                    } catch (ClassCastException cce) {}
     177                }
     178            }
     179        } catch(GeneralSecurityException gse) {}
     180        return rv;
     181    }
     182
     183    /**
    160184     *  Get a value out of the subject distinguished name.
    161185     *
  • core/java/src/net/i2p/crypto/KeyStoreUtil.java

    r63a8b46 r81808d4  
    10061006    /**
    10071007     *  Export the private key and certificate chain (if any) out of a keystore.
    1008      *  Does NOT close the stream. Throws on all errors.
     1008     *  Does NOT close the output stream. Throws on all errors.
    10091009     *
    10101010     *  @param ks path to the keystore
     
    10311031        } finally {
    10321032            if (fis != null) try { fis.close(); } catch (IOException ioe) {}
     1033        }
     1034    }
     1035
     1036    /**
     1037     *  Renew the the private key certificate in a keystore.
     1038     *  Closes the input and output streams. Throws on all errors.
     1039     *
     1040     *  @param ks path to the keystore
     1041     *  @param ksPW the keystore password, may be null
     1042     *  @param alias the name of the key, or null to get the first one in keystore
     1043     *  @param keyPW the key password, must be at least 6 characters
     1044     *  @param validDays new cert to expire this many days from now
     1045     *  @return the new certificate
     1046     *  @since 0.9.34
     1047     */
     1048    public static X509Certificate renewPrivateKeyCertificate(File ks, String ksPW, String alias,
     1049                                                             String keyPW, int validDays)
     1050                                                             throws GeneralSecurityException, IOException {
     1051        InputStream fis = null;
     1052        OutputStream fos = null;
     1053        try {
     1054            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
     1055            fis = new FileInputStream(ks);
     1056            char[] pwchars = ksPW != null ? ksPW.toCharArray() : null;
     1057            keyStore.load(fis, pwchars);
     1058            try { fis.close(); } catch (IOException ioe) {}
     1059            fis = null;
     1060            char[] keypwchars = keyPW.toCharArray();
     1061            if (alias == null) {
     1062                for (Enumeration<String> e = keyStore.aliases(); e.hasMoreElements();) {
     1063                    alias = e.nextElement();
     1064                    break;
     1065                }
     1066                if (alias == null)
     1067                    throw new GeneralSecurityException("no private keys found");
     1068            }
     1069            PrivateKey pk = (PrivateKey) keyStore.getKey(alias, keypwchars);
     1070            if (pk == null)
     1071                throw new GeneralSecurityException("private key not found: " + alias);
     1072            Certificate[] certs = keyStore.getCertificateChain(alias);
     1073            if (certs.length != 1)
     1074                throw new GeneralSecurityException("Bad cert chain length");
     1075            X509Certificate cert = (X509Certificate) certs[0];
     1076            Object[] rv = SelfSignedGenerator.renew(cert, pk, validDays);
     1077            cert = (X509Certificate) rv[2];
     1078            certs[0] = cert;
     1079            keyStore.setKeyEntry(alias, pk, keypwchars, certs);
     1080            fos = new SecureFileOutputStream(ks);
     1081            keyStore.store(fos, pwchars);
     1082            return cert;
     1083        } finally {
     1084            if (fis != null) try { fis.close(); } catch (IOException ioe) {}
     1085            if (fos != null) try { fos.close(); } catch (IOException ioe) {}
    10331086        }
    10341087    }
  • core/java/src/net/i2p/crypto/SelfSignedGenerator.java

    r63a8b46 r81808d4  
    142142        PublicKey jpub = SigUtil.toJavaKey(pub);
    143143        PrivateKey jpriv = SigUtil.toJavaKey(priv);
    144 
     144        return generate(jpub, jpriv, priv, type, cname, altNames, ou, o, l, st, c, validDays);
     145    }
     146
     147    /**
     148     *  @param cname the common name, non-null. Must be a hostname or email address. IP addresses will not be correctly encoded.
     149     *  @param altNames the Subject Alternative Names. May be null. May contain hostnames and/or IP addresses.
     150     *                  cname, localhost, 127.0.0.1, and ::1 will be automatically added.
     151     *  @param ou The OU (organizational unit) in the distinguished name, non-null before 0.9.28, may be null as of 0.9.28
     152     *  @param o The O (organization)in the distinguished name, non-null before 0.9.28, may be null as of 0.9.28
     153     *  @param l The L (city or locality) in the distinguished name, non-null before 0.9.28, may be null as of 0.9.28
     154     *  @param st The ST (state or province) in the distinguished name, non-null before 0.9.28, may be null as of 0.9.28
     155     *  @param c The C (country) in the distinguished name, non-null before 0.9.28, may be null as of 0.9.28
     156     *
     157     *  @return length 4 array:
     158     *  rv[0] is a Java PublicKey
     159     *  rv[1] is a Java PrivateKey
     160     *  rv[2] is a Java X509Certificate
     161     *  rv[3] is a Java X509CRL
     162     *
     163     *  @since 0.9.34 added altNames param
     164     */
     165    private static Object[] generate(PublicKey jpub, PrivateKey jpriv, SigningPrivateKey priv, SigType type,
     166                                     String cname, Set<String> altNames, String ou, String o, String l, String st, String c,
     167                                     int validDays) throws GeneralSecurityException {
    145168        String oid;
    146169        switch (type) {
     
    221244        Object[] rv = { jpub, jpriv, cert, crl };
    222245        return rv;
     246    }
     247
     248    /**
     249     *  @param cert the old cert to be replaced
     250     *  @param jpriv the private key
     251     *
     252     *  @return length 4 array:
     253     *  rv[0] is a Java PublicKey, from cert as passed in
     254     *  rv[1] is a Java PrivateKey, jpriv as passed in
     255     *  rv[2] is a Java X509Certificate, new one
     256     *  rv[3] is a Java X509CRL, new one
     257     *
     258     *  @since 0.9.34 added altNames param
     259     */
     260    public static Object[] renew(X509Certificate cert, PrivateKey jpriv, int validDays) throws GeneralSecurityException {
     261        String cname = CertUtil.getSubjectValue(cert, "CN");
     262        if (cname == null)
     263            cname = "localhost";
     264        String ou = CertUtil.getSubjectValue(cert, "OU");
     265        String o = CertUtil.getSubjectValue(cert, "O");
     266        String l = CertUtil.getSubjectValue(cert, "L");
     267        String st = CertUtil.getSubjectValue(cert, "ST");
     268        String c = CertUtil.getSubjectValue(cert, "C");
     269        Set<String> altNames = CertUtil.getSubjectAlternativeNames(cert);
     270        SigningPrivateKey priv = SigUtil.fromJavaKey(jpriv);
     271        SigType type = priv.getType();
     272        SigningPublicKey pub = KeyGenerator.getSigningPublicKey(priv);
     273        PublicKey jpub = SigUtil.toJavaKey(pub);
     274        if (type == null)
     275                throw new GeneralSecurityException("Unsupported: " + jpriv);
     276        return generate(jpub, jpriv, priv, type, cname, altNames, ou, o, l, st, c, validDays);
    223277    }
    224278
     
    834888     *  Note: For CLI testing, use java -jar i2p.jar su3file keygen pubkey.crt keystore.ks commonName
    835889     */
     890    public static void main(String[] args) throws Exception {
     891        if (args.length == 0) {
     892            usage();
     893        } else if (args[0].equals("keygen")) {
     894            if (args.length >= 4)
     895                SU3File.main(args);
     896            else
     897                usage();
     898        } else if (args[0].equals("renew")) {
     899            if (args.length >= 3) {
     900                String ksPW, cert, ks;
     901                if (args[1].equals("-p")) {
     902                    ksPW = args[2];
     903                    cert = args[3];
     904                    ks = args[4];
     905                } else {
     906                    ksPW = KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD;
     907                    cert = args[1];
     908                    ks = args[2];
     909                }
     910                String keypw = "";
     911                try {
     912                    while (keypw.length() < 6) {
     913                        System.out.print("Enter password for key: ");
     914                        keypw = DataHelper.readLine(System.in);
     915                        if (keypw == null) {
     916                            System.out.println("\nEOF reading password");
     917                            System.exit(1);
     918                        }
     919                        keypw = keypw.trim();
     920                        if (keypw.length() > 0 && keypw.length() < 6)
     921                            System.out.println("Key password must be at least 6 characters");
     922                    }
     923                } catch (IOException ioe) {
     924                    System.out.println("Error asking for password");
     925                    throw ioe;
     926                }
     927                File ksf = new File(ks);
     928                X509Certificate newCert = KeyStoreUtil.renewPrivateKeyCertificate(ksf, ksPW, null, keypw, 3652);
     929                CertUtil.saveCert(newCert, new File(cert));
     930                System.out.println("Certificate renewed for 10 years, and stored in " + cert + " and " + ks);
     931            } else {
     932                usage();
     933            }
     934        } else {
     935            usage();
     936        }
    836937/****
    837     public static void main(String[] args) {
    838938        try {
    839939            int i = 0;
     
    846946            e.printStackTrace();
    847947        }
    848     }
    849 
     948****/
     949    }
     950
     951    private static void usage() {
     952        System.err.println("Usage: selfsignedgenerator keygen [-t type|code] [-p keystorepw] [-r crlFile.crl] publicKeyFile.crt keystore.ks localhost\n" +
     953                           "       selfsignedgenerator renew  [-p keystorepw] publicKeyFile.crt keystore.ks");
     954    }
     955/****
    850956    private static final void test(String name, SigType type) throws Exception {
    851957            Object[] rv = generate("cname@example.com", "ou", "o", null, "st", "c", 3652, type);
  • core/java/src/net/i2p/util/CommandLine.java

    r63a8b46 r81808d4  
    2424        "net.i2p.crypto.CertUtil",
    2525        "net.i2p.crypto.CryptoCheck",
     26        "net.i2p.crypto.SelfSignedGenerator",
    2627        "net.i2p.crypto.SU3File",
    2728        "net.i2p.crypto.TrustedUpdate",
Note: See TracChangeset for help on using the changeset viewer.