001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
013: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
014: * License for the specific language governing permissions and limitations under
015: * the License.
016: */
017:
018: package org.apache.harmony.tools.keytool;
019:
020: import java.io.FileNotFoundException;
021: import java.io.IOException;
022: import java.security.InvalidAlgorithmParameterException;
023: import java.security.KeyStore;
024: import java.security.KeyStoreException;
025: import java.security.NoSuchAlgorithmException;
026: import java.security.NoSuchProviderException;
027: import java.security.PublicKey;
028: import java.security.SignatureException;
029: import java.security.cert.CertPathBuilder;
030: import java.security.cert.CertPathBuilderException;
031: import java.security.cert.CertPathBuilderResult;
032: import java.security.cert.CertStore;
033: import java.security.cert.CertStoreException;
034: import java.security.cert.CertificateEncodingException;
035: import java.security.cert.CertificateException;
036: import java.security.cert.CollectionCertStoreParameters;
037: import java.security.cert.PKIXBuilderParameters;
038: import java.security.cert.TrustAnchor;
039: import java.security.cert.X509CertSelector;
040: import java.security.cert.X509Certificate;
041: import java.util.ArrayList;
042: import java.util.Arrays;
043: import java.util.Collection;
044: import java.util.Enumeration;
045: import java.util.HashSet;
046: import java.util.Iterator;
047: import java.util.List;
048: import java.util.NoSuchElementException;
049: import java.util.Set;
050:
051: import javax.security.auth.x500.X500Principal;
052:
053: /**
054: * A class for checking X.509 certificates and building and verifying X.509
055: * certificate chains.
056: */
057: public class CertChainVerifier {
058: private final static String strFailed = "Failed to build a certificate chain from reply.\n";
059:
060: /**
061: * A cerificate chain is built by looking up the certificate of the issuer
062: * of the current certificate. If a sertificate is self-signed it is assumed
063: * to be the root CA. After that the certificates are searched in the lists
064: * of revoked certificates. Certificate signatures are checked and
065: * certificate path is built in the same way as in import operation. If an
066: * error occurs the flow is not stopped but an attempt to continue is made.
067: * The results of the verification are printed to stdout.
068: *
069: * @param param
070: * @throws NoSuchAlgorithmException
071: * @throws NoSuchProviderException
072: * @throws FileNotFoundException
073: * @throws CertificateException
074: * @throws IOException
075: * @throws KeytoolException
076: * @throws KeyStoreException
077: */
078: static void verifyChain(KeytoolParameters param)
079: throws NoSuchAlgorithmException, NoSuchProviderException,
080: FileNotFoundException, CertificateException, IOException,
081: KeytoolException, KeyStoreException {
082:
083: try {
084: if (param.getCrlFile() != null) {
085: CRLManager.checkRevoked(param);
086: } else {
087: System.out
088: .println("Certificates revocation status is not checked, "
089: + "CRL file name is not supplied.");
090: }
091: } catch (Exception e) {
092: System.out.println(e);
093: System.out.println("Failed to check revocation status.");
094: }
095:
096: String provider = param.getProvider();
097: String certProvider = (param.getCertProvider() != null) ? param
098: .getCertProvider() : provider;
099: String sigProvider = (param.getSigProvider() != null) ? param
100: .getSigProvider() : provider;
101: String mdProvider = (param.getMdProvider() != null) ? param
102: .getMdProvider() : provider;
103:
104: // Don't catch exceptions here, because if exception is
105: // thrown here, there is no need to proceed.
106: Collection<X509Certificate> certs = CertReader.readCerts(param
107: .getFileName(), false, certProvider);
108: X509Certificate[] ordered = orderChain(certs);
109:
110: try {
111: for (int i = 0; i < ordered.length - 1; i++) {
112: checkSignature(ordered[i], ordered[i + 1]
113: .getPublicKey(), sigProvider, mdProvider);
114: }
115: // check the signature of the last element of the ordered chain
116: boolean lastSignChecked = findIssuerAndCheckSignature(param
117: .getKeyStore(), ordered[ordered.length - 1],
118: sigProvider, mdProvider);
119: // if haven't found issuer's certificate in main keystore
120: if (!lastSignChecked) {
121: if (param.isTrustCACerts()) {
122: // make the search and check again
123: lastSignChecked = findIssuerAndCheckSignature(param
124: .getCacerts(), ordered[ordered.length - 1],
125: sigProvider, mdProvider);
126: }
127:
128: if (!lastSignChecked) {
129: System.out
130: .println("Failed to find the issuer's certificate.");
131: System.out
132: .println("Failed to check the signature of certificate:");
133: KeyStoreCertPrinter.printX509CertDetailed(
134: ordered[ordered.length - 1], mdProvider);
135: }
136: }
137: } catch (Exception e) {
138: System.out.println(e);
139: System.out.println("Signature check failed.");
140: }
141:
142: try {
143: buildCertPath(param, ordered[0]);
144:
145: // won't come here if exception is thrown
146: System.out
147: .println("Certificate path is built successfully.");
148: } catch (Exception e) {
149: // Exception's own message contains strFailed string,
150: // but its cause can be more informative here.
151: System.out.println(e.getCause());
152: System.out.println("Failed to build a certificate path.");
153: }
154: System.out.println("Verification complete.");
155: }
156:
157: // Checks the signature, prints the result. Returns true if
158: // signature verification process succeeds (no exceptions or
159: // SignatureException thrown)
160: private static boolean checkSignature(X509Certificate cert,
161: PublicKey pubKey, String sigProvider, String mdProvider)
162: throws CertificateEncodingException,
163: NoSuchAlgorithmException, NoSuchProviderException {
164: try {
165: if (sigProvider == null) {
166: cert.verify(pubKey);
167: } else {
168: cert.verify(pubKey, sigProvider);
169: }
170: } catch (SignatureException e) {
171: System.out
172: .println("The signature is incorrect for certificate: ");
173: KeyStoreCertPrinter.printX509CertDetailed(cert, mdProvider);
174: } catch (Exception e) {
175: System.out.println(e);
176: System.out
177: .println("Signature verification failed for certificate: ");
178: KeyStoreCertPrinter.printX509CertDetailed(cert, mdProvider);
179: return false;
180: }
181: return true;
182: }
183:
184: // Searches for cert issuer's certificate in keyStore and checks if
185: // cert was signed using the private key corresponding to public key
186: // wrapped into the found certificate.
187: private static boolean findIssuerAndCheckSignature(
188: KeyStore keyStore, X509Certificate cert,
189: String sigProvider, String mdProvider)
190: throws KeyStoreException, CertificateEncodingException,
191: NoSuchAlgorithmException, NoSuchProviderException {
192:
193: Enumeration keyStoreAliases = keyStore.aliases();
194: while (keyStoreAliases.hasMoreElements()) {
195: // get a certificate from keyStore
196: X509Certificate nextKScert = (X509Certificate) keyStore
197: .getCertificate((String) keyStoreAliases
198: .nextElement());
199: if (nextKScert == null) {
200: continue;
201: }
202: if (Arrays.equals(cert.getIssuerX500Principal()
203: .getEncoded(), nextKScert.getSubjectX500Principal()
204: .getEncoded())) {
205: checkSignature(cert, keyStore.getCertificate(
206: (String) keyStoreAliases.nextElement())
207: .getPublicKey(), sigProvider, mdProvider);
208: return true;
209: }
210: }
211: return false;
212: }
213:
214: /**
215: * Builds a certificate chain from the given X509Certificate newCert to a
216: * self-signed root CA whose certificate is contained in the keystore or
217: * cacerts file (if "-trustcacerts" option is specified).
218: *
219: * @param param -
220: * specifies the keystore, provider name and other options (such
221: * as "-trustcacerts").
222: * @param newCert -
223: * certificate to start the chain
224: * @return the chain as an array of X509Certificate-s. If the chain cannot
225: * be built for some reason an exception is thrown.
226: * @throws KeyStoreException
227: * @throws FileNotFoundException
228: * @throws NoSuchAlgorithmException
229: * @throws CertificateException
230: * @throws IOException
231: * @throws KeytoolException
232: * @throws NoSuchProviderException
233: * @throws CertPathBuilderException
234: */
235: static X509Certificate[] buildFullCertPath(KeytoolParameters param,
236: X509Certificate newCert) throws KeyStoreException,
237: FileNotFoundException, NoSuchAlgorithmException,
238: CertificateException, IOException, KeytoolException,
239: CertPathBuilderException, NoSuchProviderException {
240:
241: X509CertSelector selector = new X509CertSelector();
242: selector.setCertificate(newCert);
243:
244: Collection[] trustedSeparated = separateTrusted(param);
245: Set selfSignedTAs = (Set) trustedSeparated[0];
246: Collection trustedCerts = trustedSeparated[1];
247: Collection selfSignedTAsCerts = trustedSeparated[2];
248:
249: String certProvider = (param.getCertProvider() != null) ? param
250: .getCertProvider() : param.getProvider();
251:
252: CertPathBuilderResult bldResult = buildCertPath(certProvider,
253: newCert, selfSignedTAs, trustedCerts);
254:
255: // The validation of the certificate path.
256: // According to black-box testing, RI keytool doesn't perform
257: // the certificate path validation procedure. Therefore this
258: // implementation also doesn't validate the certificate chain
259: // The path validation procedure can be done in future as an
260: // extension of the current functionality.
261:
262: // The imported certificate should be included in the chain;
263: // The root CA is not included in it.
264: X509Certificate[] newChainNoCA = (X509Certificate[]) bldResult
265: .getCertPath().getCertificates().toArray(
266: new X509Certificate[0]);
267:
268: // get the subject of the root CA which will be the last element of the
269: // chain
270: X500Principal caSubject = newChainNoCA[newChainNoCA.length - 1]
271: .getIssuerX500Principal();
272:
273: // set the search parameter for the root CA
274: selector.setCertificate(null);
275: selector.setSubject(caSubject);
276:
277: // add all root CAs to the CertStore to search through them
278: CollectionCertStoreParameters rootCAs = new CollectionCertStoreParameters(
279: selfSignedTAsCerts);
280: CertStore rootCAsCertStore;
281: try {
282: rootCAsCertStore = CertStore.getInstance("Collection",
283: rootCAs);
284: } catch (Exception e) {
285: throw new KeytoolException(strFailed, e);
286: }
287:
288: // find certificate to add to the end of the certificate chain
289: X509Certificate rootCA;
290: try {
291: rootCA = (X509Certificate) rootCAsCertStore
292: .getCertificates(selector).iterator().next();
293: } catch (CertStoreException e) {
294: throw new KeytoolException(strFailed, e);
295: }
296: // create a new array of certificates with the root CA in it.
297: X509Certificate[] newChain = new X509Certificate[newChainNoCA.length + 1];
298: System.arraycopy(newChainNoCA, 0, newChain, 0,
299: newChainNoCA.length);
300: newChain[newChain.length - 1] = rootCA;
301:
302: return newChain;
303: }
304:
305: /**
306: * Build a certificate chain up to the trust anchor, based on trusted
307: * certificates contained in the keystore and possibly cacerts file (if
308: * param.isTrustCACerts() returns true).
309: *
310: * @param param
311: * @param newCert
312: * @return
313: * @throws NoSuchAlgorithmException
314: * @throws CertificateException
315: * @throws KeyStoreException
316: * @throws CertPathBuilderException
317: * @throws IOException
318: * @throws KeytoolException
319: * @throws NoSuchProviderException
320: */
321: static CertPathBuilderResult buildCertPath(KeytoolParameters param,
322: X509Certificate newCert) throws NoSuchAlgorithmException,
323: CertificateException, KeyStoreException,
324: CertPathBuilderException, IOException, KeytoolException,
325: NoSuchProviderException {
326: Collection[] trustedSeparated = separateTrusted(param);
327: Set selfSignedTAs = (Set) trustedSeparated[0];
328: Collection trustedCerts = trustedSeparated[1];
329:
330: String certProvider = (param.getCertProvider() != null) ? param
331: .getCertProvider() : param.getProvider();
332:
333: return buildCertPath(certProvider, newCert, selfSignedTAs,
334: trustedCerts);
335: }
336:
337: // Build a certificate chain up to the self-signed trust anchor, based on
338: // trusted certificates given.
339: //
340: // @param certProvider
341: // @param newCert
342: // is a certificate to build chain for.
343: // @param selfSignedTAs
344: // are used as trust anchors.
345: // @param trustedCerts
346: // elements of trustedCerts are used as chain links It can be
347: // null if no intermediate certificates allowed.
348: private static CertPathBuilderResult buildCertPath(
349: String certProvider, X509Certificate newCert,
350: Set selfSignedTAs, Collection trustedCerts)
351: throws NoSuchAlgorithmException, CertificateException,
352: IOException, KeyStoreException, CertPathBuilderException,
353: KeytoolException, NoSuchProviderException {
354:
355: X509CertSelector selector = new X509CertSelector();
356: selector.setCertificate(newCert);
357:
358: String strPKIX = "PKIX";
359: String strNoSelfSigned = "Possibly, keystore doesn't "
360: + "contain any self-signed (root CA) trusted certificates. ";
361:
362: // this parameter will be used to generate the certificate chain
363: PKIXBuilderParameters builderParam = null;
364: try {
365: // set the search parameters with selector
366: // and TrustAnchors with selfSignedTAs
367: builderParam = new PKIXBuilderParameters(selfSignedTAs,
368: selector);
369: } catch (InvalidAlgorithmParameterException e) {
370: throw new KeytoolException(strFailed + strNoSelfSigned, e);
371: }
372:
373: if (trustedCerts != null) {
374: CollectionCertStoreParameters trustedCertsCCSParams = new CollectionCertStoreParameters(
375: trustedCerts);
376: CertStore trustedCertStore;
377: try {
378: trustedCertStore = CertStore.getInstance("Collection",
379: trustedCertsCCSParams);
380: } catch (Exception e) {
381: throw new KeytoolException(strFailed, e);
382: }
383:
384: // add certificates to use as chain links
385: builderParam.addCertStore(trustedCertStore);
386: }
387:
388: // disable the revocation checking
389: builderParam.setRevocationEnabled(false);
390:
391: CertPathBuilder cpBuilder;
392: try {
393: if (certProvider == null) {
394: cpBuilder = CertPathBuilder.getInstance(strPKIX);
395: } else {
396: cpBuilder = CertPathBuilder.getInstance(strPKIX,
397: certProvider);
398: }
399: } catch (NoSuchAlgorithmException e) {
400: throw new NoSuchAlgorithmException("The algorithm "
401: + strPKIX + " is not available.", e);
402: } catch (NoSuchProviderException e) {
403: throw (NoSuchProviderException) new NoSuchProviderException(
404: "The certProvider " + certProvider
405: + " is not found in the environment.")
406: .initCause(e);
407: }
408:
409: CertPathBuilderResult bldResult = null;
410: try {
411: // the actual building of the certificate chain is done here
412: bldResult = cpBuilder.build(builderParam);
413: } catch (CertPathBuilderException e) {
414: throw new CertPathBuilderException(strFailed, e);
415: } catch (InvalidAlgorithmParameterException e) {
416: throw new KeytoolException(strFailed + strNoSelfSigned, e);
417: }
418:
419: return bldResult;
420: }
421:
422: // Separates the trusted certificates from keystore (and cacerts file if
423: // "-trustcacerts" option is specified) into self-signed certificate
424: // authority certificates and non-self-signed certificates.
425: // @return - Returns an array of Collection-s.
426: // The first element of the array is Set<TrustAnchors> - self-signed CAs.
427: // The second - ArrayList of non-self-signed trusted certificates.
428: // The third - ArrayList of self-signed certificates which correspond to
429: // TrustAnchors contained in the first element of the array.
430: private static Collection[] separateTrusted(KeytoolParameters param)
431: throws KeyStoreException, FileNotFoundException,
432: IOException, NoSuchAlgorithmException,
433: CertificateException, KeytoolException,
434: NoSuchProviderException {
435: // Are there any trusted certificates in the keyStore?
436: boolean trustedExistInKS = false;
437: // Is "-trustcacerts" option specified?
438: boolean trustCaCerts = param.isTrustCACerts();
439: String strNoTrusted = "Possibly, keystore doesn't "
440: + "contain any trusted certificates. ";
441:
442: // This one is temporary. Used just to get trusted certificates
443: // from keyStore.
444: PKIXBuilderParameters keyStoreBuilderParam = null;
445: X509CertSelector selector = new X509CertSelector();
446:
447: // After getting the trusted certificates, they will be sorted into
448: // self-signed (they are considered to be CAs) and interim trusted
449: // certs.
450:
451: // self-signed trust anchors. The CertPath is ok if it finishes
452: // on such trust anchor.
453: Set selfSignedTAs = null;
454: // certificates of selfSignedTAs
455: Collection selfSignedTAsCerts = null;
456: // trusted certificates which can be the chain links of the CertPath
457: Collection trustedCerts = null;
458: try {
459: keyStoreBuilderParam = new PKIXBuilderParameters(param
460: .getKeyStore(), selector);
461:
462: // won't come here if exception is thrown
463: trustedExistInKS = true;
464: } catch (InvalidAlgorithmParameterException e) {
465: // if "-trustcacerts" option is NOT specified
466: if (!trustCaCerts) {
467: throw new KeytoolException(strFailed + strNoTrusted);
468: }
469: }
470:
471: // if there are trusted certificates in the keyStore
472: if (keyStoreBuilderParam != null) {
473: // trustAnchorsSet is a set of trusted certificates
474: // contained in keyStore
475: Set trustAnchorsSet = keyStoreBuilderParam
476: .getTrustAnchors();
477: int halfSize = trustAnchorsSet.size() / 2;
478: selfSignedTAs = new HashSet(halfSize);
479: selfSignedTAsCerts = new ArrayList(halfSize);
480: trustedCerts = new ArrayList(halfSize);
481:
482: Iterator trustAnchorsIter = trustAnchorsSet.iterator();
483: while (trustAnchorsIter.hasNext()) {
484: TrustAnchor ta = (TrustAnchor) trustAnchorsIter.next();
485: X509Certificate trCert = ta.getTrustedCert();
486: // if the trusted certificate is self-signed,
487: // add it to the selfSignedTAs.
488: if (Arrays.equals(trCert.getSubjectX500Principal()
489: .getEncoded(), trCert.getIssuerX500Principal()
490: .getEncoded())) {
491: selfSignedTAs.add(ta);
492: selfSignedTAsCerts.add(trCert);
493: } else {// otherwise just add it to the list of
494: // trusted certs
495: trustedCerts.add(trCert);
496: }
497: }
498: }
499:
500: // if "-trustcacerts" is specified, add CAs from cacerts
501: if (trustCaCerts) {
502: KeyStore cacertsFile = null;
503: try {
504: cacertsFile = param.getCacerts();
505: } catch (Exception e) {
506: if (trustedExistInKS) {
507: // if there are trusted certificates in keyStore,
508: // just print the notification
509: System.err.println(e.getMessage());
510: } else {// otherwise quit
511: throw new KeytoolException(strFailed, e);
512: }
513: }
514:
515: // if cacerts loaded
516: if (cacertsFile != null) {
517: PKIXBuilderParameters cacertsBuilderParam = null;
518: try {
519: cacertsBuilderParam = new PKIXBuilderParameters(
520: cacertsFile, selector);
521: } catch (InvalidAlgorithmParameterException e) {
522: if (!trustedExistInKS) {
523: throw new KeytoolException(strFailed
524: + strNoTrusted);
525: } else {
526: // if there are trusted certificates in keyStore,
527: // just return what have now
528: return new Collection[] { selfSignedTAs,
529: trustedCerts, selfSignedTAsCerts };
530: }
531: }
532:
533: Set<TrustAnchor> cacertsCAs = cacertsBuilderParam
534: .getTrustAnchors();
535:
536: // if there are no trusted certificates in the
537: // keyStore
538: if (!trustedExistInKS) {
539: Set trustAnchorsSet = cacertsBuilderParam
540: .getTrustAnchors();
541: int size = trustAnchorsSet.size();
542: // usually only self-signed CAs are in the
543: // cacerts file, so selfSignedTAs is of the
544: // same size as trustAnchorsSet.
545: selfSignedTAs = new HashSet(size);
546: selfSignedTAsCerts = new HashSet(size);
547: trustedCerts = new ArrayList();
548: }
549:
550: Iterator cacertsCAsIter = cacertsCAs.iterator();
551: while (cacertsCAsIter.hasNext()) {
552: TrustAnchor ta = (TrustAnchor) cacertsCAsIter
553: .next();
554: X509Certificate trCert = ta.getTrustedCert();
555: // if the trusted certificate is self-signed,
556: // add it to the selfSignedTAs.
557: if (Arrays.equals(trCert.getSubjectX500Principal()
558: .getEncoded(), trCert
559: .getIssuerX500Principal().getEncoded())) {
560: selfSignedTAs.add(ta);
561: selfSignedTAsCerts.add(trCert);
562: } else {// otherwise just add it to the list of
563: // trusted certs
564: trustedCerts.add(trCert);
565: }
566: }
567: }// if (cacertsFile != null)...
568: }// if (trustCacerts)...
569: return new Collection[] { selfSignedTAs, trustedCerts,
570: selfSignedTAsCerts };
571: }
572:
573: /**
574: * Orders a collection of certificates into a certificate chain beginning
575: * with the certificate which has public key equal to aliasPubKey.
576: *
577: * @throws KeytoolException
578: */
579: static X509Certificate[] orderChain(
580: Collection<X509Certificate> certs, PublicKey aliasPubKey)
581: throws KeytoolException {
582:
583: String strOrderFailed = "Failed to order the certificate chain.";
584:
585: // add certificates to the certstore to ease the search
586: CollectionCertStoreParameters chainCCSParams = new CollectionCertStoreParameters(
587: certs);
588: CertStore certStore;
589: try {
590: certStore = CertStore.getInstance("Collection",
591: chainCCSParams);
592: } catch (Exception e) {
593: throw new KeytoolException(strOrderFailed, e);
594: }
595:
596: // set up selector to search the certificates
597: X509CertSelector selector = new X509CertSelector();
598: // try to find the first certificate in the chain
599: selector.setSubjectPublicKey(aliasPubKey);
600:
601: // current certificate
602: X509Certificate current = null;
603: try {
604: current = (X509Certificate) certStore.getCertificates(
605: selector).iterator().next();
606: } catch (CertStoreException e) {
607: // do nothing
608: } catch (NoSuchElementException e) {
609: // do nothing
610: }
611:
612: if (current == null) {
613: throw new KeytoolException(
614: "Failed to find the requested public key "
615: + "in certificate reply.");
616: }
617: // number of certificates in collection
618: int colSize = certs.size();
619: // new chain to return
620: X509Certificate[] ordered = new X509Certificate[colSize];
621: ordered[0] = current;
622: selector.setSubjectPublicKey((PublicKey) null);
623:
624: // counter of ordered certificates
625: // it will be incremented later
626: int orderedCnt = 0;
627:
628: if (!Arrays.equals(current.getSubjectX500Principal()
629: .getEncoded(), current.getIssuerX500Principal()
630: .getEncoded())) {
631: // orderedCnt = 1, because the first certificate is already in
632: // the resulting array
633: for (orderedCnt = 1; orderedCnt < colSize; orderedCnt++) {
634: // set new filter
635: selector.setSubject(current.getIssuerX500Principal());
636: try {
637: // get issuer's certificate
638: current = (X509Certificate) certStore
639: .getCertificates(selector).iterator()
640: .next();
641: } catch (CertStoreException e) {
642: throw new KeytoolException(strOrderFailed, e);
643: } catch (NoSuchElementException e) {
644: break;
645: }
646:
647: if (Arrays.equals(current.getSubjectX500Principal()
648: .getEncoded(), current.getIssuerX500Principal()
649: .getEncoded())) {
650: // if self-signed, save it and quit. It is the last.
651: ordered[orderedCnt] = current;
652: break;
653: } else {
654: // add current certificate to the chain and continue
655: ordered[orderedCnt] = current;
656: }
657: }
658: }
659:
660: // If the certificate collection contains certificates which
661: // are not a part of the chain.
662: // ++orderedCnt is used because 'break's don't let the
663: // variable be incremented when it should be.
664: if (++orderedCnt < colSize) {
665: X509Certificate[] orderedShort = new X509Certificate[orderedCnt];
666: System.arraycopy(ordered, 0, orderedShort, 0, orderedCnt);
667: return orderedShort;
668: }
669:
670: return ordered;
671: }
672:
673: // orders a chain without a starting element given
674: static X509Certificate[] orderChain(
675: Collection<X509Certificate> certs) throws KeytoolException {
676:
677: int certsLen = certs.size();
678: int startPos = -1;
679:
680: List<X509Certificate> certsList = new ArrayList<X509Certificate>(
681: certs);
682:
683: // searching for the first element of the chain
684: for (int i = 0; i < certsLen; i++) {
685: X509Certificate curCert = certsList.get(i);
686: for (int j = 0; j < certsLen; j++) {
687: if (j != i) {
688: // if the subject is the issuer of another cert, it is not
689: // the first in the chain.
690: if (Arrays.equals(curCert.getSubjectX500Principal()
691: .getEncoded(), certsList.get(j)
692: .getIssuerX500Principal().getEncoded())) {
693: break;
694: }
695: }
696: // If the certificate's subject is not found to be an issuer to
697: // any other cert in this chain, then it is the first element.
698: if (j == certsLen - 1) {
699: startPos = i;
700: break;
701: }
702: }
703: // don't search any more, if the first element is found.
704: if (startPos > -1) {
705: break;
706: }
707: }
708:
709: return orderChain(certsList, certsList.get(startPos)
710: .getPublicKey());
711: }
712:
713: /**
714: * Checks if the X509Certificate cert is contained as a trusted certificate
715: * entry in keystore and possibly cacerts file (if "-trustcacerts" option is
716: * specified).
717: *
718: * @param param
719: * @param cert
720: * @return true if the certificate is trusted, false - otherwise.
721: * @throws FileNotFoundException
722: * @throws NoSuchAlgorithmException
723: * @throws CertificateException
724: * @throws IOException
725: * @throws KeyStoreException
726: * @throws NoSuchProviderException
727: */
728: static boolean isTrusted(KeytoolParameters param,
729: X509Certificate cert) throws FileNotFoundException,
730: NoSuchAlgorithmException, CertificateException,
731: IOException, KeyStoreException, NoSuchProviderException {
732: // check the main keyStore
733: KeyStore keyStore = param.getKeyStore();
734: String alias = keyStore.getCertificateAlias(cert);
735: if (alias != null) {
736: if (keyStore.isCertificateEntry(alias)) {
737: return true;
738: }
739: }
740:
741: if (!param.isTrustCACerts()) {
742: return false;
743: } else {// check cacerts file
744: KeyStore cacerts = param.getCacerts();
745: alias = cacerts.getCertificateAlias(cert);
746: if (alias != null) {
747: if (cacerts.isCertificateEntry(alias)) {
748: return true;
749: }
750: }
751: return false;
752: }
753: }
754: }
|