4217 lines · 166.7 KB · Java
RawDownload
     * stream.     */    private void dumpCert(Certificate cert, PrintStream out)        throws IOException, CertificateException    {        if (rfc) {            BASE64Encoder encoder = new BASE64Encoder();            out.println(X509Factory.BEGIN_CERT);            encoder.encodeBuffer(cert.getEncoded(), out);            out.println(X509Factory.END_CERT);        } else {            out.write(cert.getEncoded()); // binary        }    }     /**     * Converts a byte to hex digit and writes to the supplied buffer     */    private void byte2hex(byte b, StringBuffer buf) {        char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8',                            '9', 'A', 'B', 'C', 'D', 'E', 'F' };        int high = ((b & 0xf0) >> 4);        int low = (b & 0x0f);        buf.append(hexChars[high]);        buf.append(hexChars[low]);    }     /**     * Converts a byte array to hex string     */    private String toHexString(byte[] block) {        StringBuffer buf = new StringBuffer();        int len = block.length;        for (int i = 0; i < len; i++) {             byte2hex(block[i], buf);             if (i < len-1) {                 buf.append(":");             }        }        return buf.toString();    }     /**     * Recovers (private) key associated with given alias.     *     * @return an array of objects, where the 1st element in the array is the     * recovered private key, and the 2nd element is the password used to     * recover it.     */    private Pair<Key,char[]> recoverKey(String alias, char[] storePass,                                       char[] keyPass)        throws Exception    {        Key key = null;         if (keyStore.containsAlias(alias) == false) {            MessageFormat form = new MessageFormat                (rb.getString("Alias.alias.does.not.exist"));            Object[] source = {alias};            throw new Exception(form.format(source));        }        if (!keyStore.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class) &&                !keyStore.entryInstanceOf(alias, KeyStore.SecretKeyEntry.class)) {            MessageFormat form = new MessageFormat                (rb.getString("Alias.alias.has.no.key"));            Object[] source = {alias};            throw new Exception(form.format(source));        }         if (keyPass == null) {            // Try to recover the key using the keystore password            try {                key = keyStore.getKey(alias, storePass);                 keyPass = storePass;                passwords.add(keyPass);            } catch (UnrecoverableKeyException e) {                // Did not work out, so prompt user for key password                if (!token) {                    keyPass = getKeyPasswd(alias, null, null);                    key = keyStore.getKey(alias, keyPass);                } else {                    throw e;                }            }        } else {            key = keyStore.getKey(alias, keyPass);        }         return Pair.of(key, keyPass);    }     /**     * Recovers entry associated with given alias.     *     * @return an array of objects, where the 1st element in the array is the     * recovered entry, and the 2nd element is the password used to     * recover it (null if no password).     */    private Pair<Entry,char[]> recoverEntry(KeyStore ks,                            String alias,                            char[] pstore,                            char[] pkey) throws Exception {         if (ks.containsAlias(alias) == false) {            MessageFormat form = new MessageFormat                (rb.getString("Alias.alias.does.not.exist"));            Object[] source = {alias};            throw new Exception(form.format(source));        }         PasswordProtection pp = null;        Entry entry;         try {            // First attempt to access entry without key password            // (PKCS11 entry or trusted certificate entry, for example)             entry = ks.getEntry(alias, pp);            pkey = null;        } catch (UnrecoverableEntryException une) {             if(P11KEYSTORE.equalsIgnoreCase(ks.getType()) ||                KeyStoreUtil.isWindowsKeyStore(ks.getType())) {                // should not happen, but a possibility                throw une;            }             // entry is protected             if (pkey != null) {                 // try provided key password                 pp = new PasswordProtection(pkey);                entry = ks.getEntry(alias, pp);             } else {                 // try store pass                 try {                    pp = new PasswordProtection(pstore);                    entry = ks.getEntry(alias, pp);                    pkey = pstore;                } catch (UnrecoverableEntryException une2) {                    if (P12KEYSTORE.equalsIgnoreCase(ks.getType())) {                         // P12 keystore currently does not support separate                        // store and entry passwords                         throw une2;                    } else {                         // prompt for entry password                         pkey = getKeyPasswd(alias, null, null);                        pp = new PasswordProtection(pkey);                        entry = ks.getEntry(alias, pp);                    }                }            }        }         return Pair.of(entry, pkey);    }    /**     * Gets the requested finger print of the certificate.     */    private String getCertFingerPrint(String mdAlg, Certificate cert)        throws Exception    {        byte[] encCertInfo = cert.getEncoded();        MessageDigest md = MessageDigest.getInstance(mdAlg);        byte[] digest = md.digest(encCertInfo);        return toHexString(digest);    }     /**     * Prints warning about missing integrity check.     */    private void printWarning() {        System.err.println();        System.err.println(rb.getString            (".WARNING.WARNING.WARNING."));        System.err.println(rb.getString            (".The.integrity.of.the.information.stored.in.your.keystore."));        System.err.println(rb.getString            (".WARNING.WARNING.WARNING."));        System.err.println();    }     /**     * Validates chain in certification reply, and returns the ordered     * elements of the chain (with user certificate first, and root     * certificate last in the array).     *     * @param alias the alias name     * @param userCert the user certificate of the alias     * @param replyCerts the chain provided in the reply     */    private Certificate[] validateReply(String alias,                                        Certificate userCert,                                        Certificate[] replyCerts)        throws Exception    {        // order the certs in the reply (bottom-up).        // we know that all certs in the reply are of type X.509, because        // we parsed them using an X.509 certificate factory        int i;        PublicKey userPubKey = userCert.getPublicKey();        for (i=0; i<replyCerts.length; i++) {            if (userPubKey.equals(replyCerts[i].getPublicKey())) {                break;            }        }        if (i == replyCerts.length) {            MessageFormat form = new MessageFormat(rb.getString                ("Certificate.reply.does.not.contain.public.key.for.alias."));            Object[] source = {alias};            throw new Exception(form.format(source));        }         Certificate tmpCert = replyCerts[0];        replyCerts[0] = replyCerts[i];        replyCerts[i] = tmpCert;         X509Certificate thisCert = (X509Certificate)replyCerts[0];         for (i=1; i < replyCerts.length-1; i++) {            // find a cert in the reply who signs thisCert            int j;            for (j=i; j<replyCerts.length; j++) {                if (signedBy(thisCert, (X509Certificate)replyCerts[j])) {                    tmpCert = replyCerts[i];                    replyCerts[i] = replyCerts[j];                    replyCerts[j] = tmpCert;                    thisCert = (X509Certificate)replyCerts[i];                    break;                }            }            if (j == replyCerts.length) {                throw new Exception                    (rb.getString("Incomplete.certificate.chain.in.reply"));            }        }         if (noprompt) {            return replyCerts;        }         // do we trust the cert at the top?        Certificate topCert = replyCerts[replyCerts.length-1];        Certificate root = getTrustedSigner(topCert, keyStore);        if (root == null && trustcacerts && caks != null) {            root = getTrustedSigner(topCert, caks);        }        if (root == null) {            System.err.println();            System.err.println                    (rb.getString("Top.level.certificate.in.reply."));            printX509Cert((X509Certificate)topCert, System.out);            System.err.println();            System.err.print(rb.getString(".is.not.trusted."));            String reply = getYesNoReply                    (rb.getString("Install.reply.anyway.no."));            if ("NO".equals(reply)) {                return null;            }        } else {            if (root != topCert) {                // append the root CA cert to the chain                Certificate[] tmpCerts =                    new Certificate[replyCerts.length+1];                System.arraycopy(replyCerts, 0, tmpCerts, 0,                                 replyCerts.length);                tmpCerts[tmpCerts.length-1] = root;                replyCerts = tmpCerts;            }        }         return replyCerts;    }     /**     * Establishes a certificate chain (using trusted certificates in the     * keystore), starting with the user certificate     * and ending at a self-signed certificate found in the keystore.     *     * @param userCert the user certificate of the alias     * @param certToVerify the single certificate provided in the reply     */    private Certificate[] establishCertChain(Certificate userCert,                                             Certificate certToVerify)        throws Exception    {        if (userCert != null) {            // Make sure that the public key of the certificate reply matches            // the original public key in the keystore            PublicKey origPubKey = userCert.getPublicKey();            PublicKey replyPubKey = certToVerify.getPublicKey();            if (!origPubKey.equals(replyPubKey)) {                throw new Exception(rb.getString                        ("Public.keys.in.reply.and.keystore.don.t.match"));            }             // If the two certs are identical, we're done: no need to import            // anything            if (certToVerify.equals(userCert)) {                throw new Exception(rb.getString                        ("Certificate.reply.and.certificate.in.keystore.are.identical"));            }        }         // Build a hash table of all certificates in the keystore.        // Use the subject distinguished name as the key into the hash table.        // All certificates associated with the same subject distinguished        // name are stored in the same hash table entry as a vector.        Hashtable<Principal, Vector<Certificate>> certs = null;        if (keyStore.size() > 0) {            certs = new Hashtable<Principal, Vector<Certificate>>(11);            keystorecerts2Hashtable(keyStore, certs);        }        if (trustcacerts) {            if (caks!=null && caks.size()>0) {                if (certs == null) {                    certs = new Hashtable<Principal, Vector<Certificate>>(11);                }                keystorecerts2Hashtable(caks, certs);            }        }         // start building chain        Vector<Certificate> chain = new Vector<>(2);        if (buildChain((X509Certificate)certToVerify, chain, certs)) {            Certificate[] newChain = new Certificate[chain.size()];            // buildChain() returns chain with self-signed root-cert first and            // user-cert last, so we need to invert the chain before we store            // it            int j=0;            for (int i=chain.size()-1; i>=0; i--) {                newChain[j] = chain.elementAt(i);                j++;            }            return newChain;        } else {            throw new Exception                (rb.getString("Failed.to.establish.chain.from.reply"));        }    }     /**     * Recursively tries to establish chain from pool of trusted certs.     *     * @param certToVerify the cert that needs to be verified.     * @param chain the chain that's being built.     * @param certs the pool of trusted certs     *     * @return true if successful, false otherwise.     */    private boolean buildChain(X509Certificate certToVerify,                        Vector<Certificate> chain,                        Hashtable<Principal, Vector<Certificate>> certs) {        Principal issuer = certToVerify.getIssuerDN();        if (isSelfSigned(certToVerify)) {            // reached self-signed root cert;            // no verification needed because it's trusted.            chain.addElement(certToVerify);            return true;        }         // Get the issuer's certificate(s)        Vector<Certificate> vec = certs.get(issuer);        if (vec == null) {            return false;        }         // Try out each certificate in the vector, until we find one        // whose public key verifies the signature of the certificate        // in question.        for (Enumeration<Certificate> issuerCerts = vec.elements();             issuerCerts.hasMoreElements(); ) {            X509Certificate issuerCert                = (X509Certificate)issuerCerts.nextElement();            PublicKey issuerPubKey = issuerCert.getPublicKey();            try {                certToVerify.verify(issuerPubKey);            } catch (Exception e) {                continue;            }            if (buildChain(issuerCert, chain, certs)) {                chain.addElement(certToVerify);                return true;            }        }        return false;    }     /**     * Prompts user for yes/no decision.     *     * @return the user's decision, can only be "YES" or "NO"     */    private String getYesNoReply(String prompt)        throws IOException    {        String reply = null;        int maxRetry = 20;        do {            if (maxRetry-- < 0) {                throw new RuntimeException(rb.getString(                        "Too.many.retries.program.terminated"));            }            System.err.print(prompt);            System.err.flush();            reply = (new BufferedReader(new InputStreamReader                                        (System.in))).readLine();            if (collator.compare(reply, "") == 0 ||                collator.compare(reply, rb.getString("n")) == 0 ||                collator.compare(reply, rb.getString("no")) == 0) {                reply = "NO";            } else if (collator.compare(reply, rb.getString("y")) == 0 ||                       collator.compare(reply, rb.getString("yes")) == 0) {                reply = "YES";            } else {                System.err.println(rb.getString("Wrong.answer.try.again"));                reply = null;            }        } while (reply == null);        return reply;    }     /**     * Returns the keystore with the configured CA certificates.     */    public static KeyStore getCacertsKeyStore()        throws Exception    {        String sep = File.separator;        File file = new File(System.getProperty("java.home") + sep                             + "lib" + sep + "security" + sep                             + "cacerts");        if (!file.exists()) {            return null;        }        FileInputStream fis = null;        KeyStore caks = null;        try {            fis = new FileInputStream(file);            caks = KeyStore.getInstance(JKS);            caks.load(fis, null);        } finally {            if (fis != null) {                fis.close();            }        }        return caks;    }     /**     * Stores the (leaf) certificates of a keystore in a hashtable.     * All certs belonging to the same CA are stored in a vector that     * in turn is stored in the hashtable, keyed by the CA's subject DN     */    private void keystorecerts2Hashtable(KeyStore ks,                Hashtable<Principal, Vector<Certificate>> hash)        throws Exception {         for (Enumeration<String> aliases = ks.aliases();                                        aliases.hasMoreElements(); ) {            String alias = aliases.nextElement();            Certificate cert = ks.getCertificate(alias);            if (cert != null) {                Principal subjectDN = ((X509Certificate)cert).getSubjectDN();                Vector<Certificate> vec = hash.get(subjectDN);                if (vec == null) {                    vec = new Vector<Certificate>();                    vec.addElement(cert);                } else {                    if (!vec.contains(cert)) {                        vec.addElement(cert);                    }                }                hash.put(subjectDN, vec);            }        }    }     /**     * Returns the issue time that's specified the -startdate option     * @param s the value of -startdate option     */    private static Date getStartDate(String s) throws IOException {        Calendar c = new GregorianCalendar();        if (s != null) {            IOException ioe = new IOException(                    rb.getString("Illegal.startdate.value"));            int len = s.length();            if (len == 0) {                throw ioe;

Lines 3001–3500 of 4217. Previous lines