0001: /*
0002: * @(#)X509CRLImpl.java 1.30 06/10/10
0003: *
0004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0006: *
0007: * This program is free software; you can redistribute it and/or
0008: * modify it under the terms of the GNU General Public License version
0009: * 2 only, as published by the Free Software Foundation.
0010: *
0011: * This program is distributed in the hope that it will be useful, but
0012: * WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * General Public License version 2 for more details (a copy is
0015: * included at /legal/license.txt).
0016: *
0017: * You should have received a copy of the GNU General Public License
0018: * version 2 along with this work; if not, write to the Free Software
0019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020: * 02110-1301 USA
0021: *
0022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0023: * Clara, CA 95054 or visit www.sun.com if you need additional
0024: * information or have any questions.
0025: *
0026: */
0027:
0028: package sun.security.x509;
0029:
0030: import java.io.InputStream;
0031: import java.io.OutputStream;
0032: import java.io.IOException;
0033: import java.math.BigInteger;
0034: import java.security.Principal;
0035: import java.security.PublicKey;
0036: import java.security.PrivateKey;
0037: import java.security.Security;
0038: import java.security.Signature;
0039: import java.security.NoSuchAlgorithmException;
0040: import java.security.InvalidKeyException;
0041: import java.security.NoSuchProviderException;
0042: import java.security.SignatureException;
0043: import java.security.cert.Certificate;
0044: import java.security.cert.X509CRL;
0045: import java.security.cert.X509Certificate;
0046: import java.security.cert.X509CRLEntry;
0047: import java.security.cert.CRLException;
0048: import java.util.Collection;
0049: import java.util.Date;
0050: import java.util.Enumeration;
0051: import java.util.Hashtable;
0052: import java.util.Set;
0053: import java.util.HashSet;
0054:
0055: import javax.security.auth.x500.X500Principal;
0056:
0057: import sun.security.util.*;
0058: import sun.misc.HexDumpEncoder;
0059:
0060: /**
0061: * <p>
0062: * An implmentation for X509 CRL (Certificate Revocation List).
0063: * <p>
0064: * The X.509 v2 CRL format is described below in ASN.1:
0065: * <pre>
0066: * CertificateList ::= SEQUENCE {
0067: * tbsCertList TBSCertList,
0068: * signatureAlgorithm AlgorithmIdentifier,
0069: * signature BIT STRING }
0070: * </pre>
0071: * More information can be found in RFC 2459,
0072: * "Internet X.509 Public Key Infrastructure Certificate and CRL
0073: * Profile" at <A HREF="http://www.ietf.org/rfc/rfc2459.txt">
0074: * http://www.ietf.org/rfc/rfc2459.txt </A>.
0075: * <p>
0076: * The ASN.1 definition of <code>tbsCertList</code> is:
0077: * <pre>
0078: * TBSCertList ::= SEQUENCE {
0079: * version Version OPTIONAL,
0080: * -- if present, must be v2
0081: * signature AlgorithmIdentifier,
0082: * issuer Name,
0083: * thisUpdate ChoiceOfTime,
0084: * nextUpdate ChoiceOfTime OPTIONAL,
0085: * revokedCertificates SEQUENCE OF SEQUENCE {
0086: * userCertificate CertificateSerialNumber,
0087: * revocationDate ChoiceOfTime,
0088: * crlEntryExtensions Extensions OPTIONAL
0089: * -- if present, must be v2
0090: * } OPTIONAL,
0091: * crlExtensions [0] EXPLICIT Extensions OPTIONAL
0092: * -- if present, must be v2
0093: * }
0094: * </pre>
0095: *
0096: * @author Hemma Prafullchandra
0097: * @version 1.30, 10/10/06
0098: * @see X509CRL
0099: */
0100: public class X509CRLImpl extends X509CRL {
0101:
0102: // CRL data, and its envelope
0103: private byte[] signedCRL = null; // DER encoded crl
0104: private byte[] signature = null; // raw signature bits
0105: private byte[] tbsCertList = null; // DER encoded "to-be-signed" CRL
0106: private AlgorithmId sigAlgId = null; // sig alg in CRL
0107:
0108: // crl information
0109: private int version;
0110: private AlgorithmId infoSigAlgId; // sig alg in "to-be-signed" crl
0111: private X500Name issuer = null;
0112: private X500Principal issuerPrincipal = null;
0113: private Date this Update = null;
0114: private Date nextUpdate = null;
0115: private Hashtable revokedCerts = new Hashtable(11);
0116: private CRLExtensions extensions = null;
0117: private final static boolean isExplicit = true;
0118: private static final long YR_2050 = 2524636800000L;
0119:
0120: private boolean readOnly = false;
0121:
0122: /**
0123: * PublicKey that has previously been used to successfully verify
0124: * the signature of this CRL. Null if the CRL has not
0125: * yet been verified (successfully).
0126: */
0127: private PublicKey verifiedPublicKey;
0128: /**
0129: * If verifiedPublicKey is not null, name of the provider used to
0130: * successfully verify the signature of this CRL, or the
0131: * empty String if no provider was explicitly specified.
0132: */
0133: private String verifiedProvider;
0134:
0135: /**
0136: * Not to be used. As it would lead to cases of uninitialized
0137: * CRL objects.
0138: */
0139: private X509CRLImpl() {
0140: }
0141:
0142: /**
0143: * Unmarshals an X.509 CRL from its encoded form, parsing the encoded
0144: * bytes. This form of constructor is used by agents which
0145: * need to examine and use CRL contents. Note that the buffer
0146: * must include only one CRL, and no "garbage" may be left at
0147: * the end.
0148: *
0149: * @param crlData the encoded bytes, with no trailing padding.
0150: * @exception CRLException on parsing errors.
0151: */
0152: public X509CRLImpl(byte[] crlData) throws CRLException {
0153: try {
0154: parse(new DerValue(crlData));
0155: } catch (IOException e) {
0156: signedCRL = null;
0157: throw new CRLException("Parsing error: " + e.getMessage());
0158: }
0159: }
0160:
0161: /**
0162: * Unmarshals an X.509 CRL from an DER value.
0163: *
0164: * @param val a DER value holding at least one CRL
0165: * @exception CRLException on parsing errors.
0166: */
0167: public X509CRLImpl(DerValue val) throws CRLException {
0168: try {
0169: parse(val);
0170: } catch (IOException e) {
0171: signedCRL = null;
0172: throw new CRLException("Parsing error: " + e.getMessage());
0173: }
0174: }
0175:
0176: /**
0177: * Unmarshals an X.509 CRL from an input stream. Only one CRL
0178: * is expected at the end of the input stream.
0179: *
0180: * @param inStrm an input stream holding at least one CRL
0181: * @exception CRLException on parsing errors.
0182: */
0183: public X509CRLImpl(InputStream inStrm) throws CRLException {
0184: try {
0185: parse(new DerValue(inStrm));
0186: } catch (IOException e) {
0187: signedCRL = null;
0188: throw new CRLException("Parsing error: " + e.getMessage());
0189: }
0190: }
0191:
0192: /**
0193: * Initial CRL constructor, no revoked certs, and no extensions.
0194: *
0195: * @param issuer the name of the CA issuing this CRL.
0196: * @param thisUpdate the Date of this issue.
0197: * @param nextUpdate the Date of the next CRL.
0198: */
0199: public X509CRLImpl(X500Name issuer, Date this Date, Date nextDate) {
0200: this .issuer = issuer;
0201: this .this Update = this Date;
0202: this .nextUpdate = nextDate;
0203: }
0204:
0205: /**
0206: * CRL constructor, revoked certs, no extensions.
0207: *
0208: * @param issuer the name of the CA issuing this CRL.
0209: * @param thisUpdate the Date of this issue.
0210: * @param nextUpdate the Date of the next CRL.
0211: * @param badCerts the array of CRL entries.
0212: *
0213: * @exception CRLException on parsing/construction errors.
0214: */
0215: public X509CRLImpl(X500Name issuer, Date this Date, Date nextDate,
0216: X509CRLEntry[] badCerts) throws CRLException {
0217: this .issuer = issuer;
0218: this .this Update = this Date;
0219: this .nextUpdate = nextDate;
0220: if (badCerts != null) {
0221: for (int i = 0; i < badCerts.length; i++) {
0222: if (badCerts[i] != null) {
0223: this .revokedCerts.put(
0224: badCerts[i].getSerialNumber(), badCerts[i]);
0225: if (badCerts[i].hasExtensions())
0226: this .version = 1;
0227: }
0228: }
0229: }
0230: }
0231:
0232: /**
0233: * CRL constructor, revoked certs and extensions.
0234: *
0235: * @param issuer the name of the CA issuing this CRL.
0236: * @param thisUpdate the Date of this issue.
0237: * @param nextUpdate the Date of the next CRL.
0238: * @param badCerts the array of CRL entries.
0239: * @param crlExts the CRL extensions.
0240: *
0241: * @exception CRLException on parsing/construction errors.
0242: */
0243: public X509CRLImpl(X500Name issuer, Date this Date, Date nextDate,
0244: X509CRLEntry[] badCerts, CRLExtensions crlExts)
0245: throws CRLException {
0246: this (issuer, this Date, nextDate, badCerts);
0247: if (crlExts != null) {
0248: this .extensions = crlExts;
0249: this .version = 1;
0250: }
0251: }
0252:
0253: /**
0254: * Returned the encoding as an uncloned byte array. Callers must
0255: * guarantee that they neither modify it nor expose it to untrusted
0256: * code.
0257: */
0258: public byte[] getEncodedInternal() throws CRLException {
0259: if (signedCRL == null) {
0260: throw new CRLException("Null CRL to encode");
0261: }
0262: return signedCRL;
0263: }
0264:
0265: /**
0266: * Returns the ASN.1 DER encoded form of this CRL.
0267: *
0268: * @exception CRLException if an encoding error occurs.
0269: */
0270: public byte[] getEncoded() throws CRLException {
0271: return (byte[]) getEncodedInternal().clone();
0272: }
0273:
0274: /**
0275: * Encodes the "to-be-signed" CRL to the OutputStream.
0276: *
0277: * @param out the OutputStream to write to.
0278: * @exception CRLException on encoding errors.
0279: */
0280: public void encodeInfo(OutputStream out) throws CRLException {
0281: try {
0282: DerOutputStream tmp = new DerOutputStream();
0283: DerOutputStream rCerts = new DerOutputStream();
0284: DerOutputStream seq = new DerOutputStream();
0285:
0286: if (version != 0) // v2 crl encode version
0287: tmp.putInteger(version);
0288: infoSigAlgId.encode(tmp);
0289: if ((version == 0) && (issuer.toString() == null))
0290: throw new CRLException(
0291: "Null Issuer DN not allowed in v1 CRL");
0292: issuer.encode(tmp);
0293:
0294: if (this Update.getTime() < YR_2050)
0295: tmp.putUTCTime(this Update);
0296: else
0297: tmp.putGeneralizedTime(this Update);
0298:
0299: if (nextUpdate != null) {
0300: if (nextUpdate.getTime() < YR_2050)
0301: tmp.putUTCTime(nextUpdate);
0302: else
0303: tmp.putGeneralizedTime(nextUpdate);
0304: }
0305:
0306: if (!revokedCerts.isEmpty()) {
0307: for (Enumeration e = revokedCerts.elements(); e
0308: .hasMoreElements();)
0309: ((X509CRLEntryImpl) e.nextElement()).encode(rCerts);
0310: tmp.write(DerValue.tag_Sequence, rCerts);
0311: }
0312:
0313: if (extensions != null)
0314: extensions.encode(tmp, isExplicit);
0315:
0316: seq.write(DerValue.tag_Sequence, tmp);
0317:
0318: tbsCertList = seq.toByteArray();
0319: out.write(tbsCertList);
0320: } catch (IOException e) {
0321: throw new CRLException("Encoding error: " + e.getMessage());
0322: }
0323: }
0324:
0325: /**
0326: * Verifies that this CRL was signed using the
0327: * private key that corresponds to the given public key.
0328: *
0329: * @param key the PublicKey used to carry out the verification.
0330: *
0331: * @exception NoSuchAlgorithmException on unsupported signature
0332: * algorithms.
0333: * @exception InvalidKeyException on incorrect key.
0334: * @exception NoSuchProviderException if there's no default provider.
0335: * @exception SignatureException on signature errors.
0336: * @exception CRLException on encoding errors.
0337: */
0338: public void verify(PublicKey key) throws CRLException,
0339: NoSuchAlgorithmException, InvalidKeyException,
0340: NoSuchProviderException, SignatureException {
0341: verify(key, "");
0342: }
0343:
0344: /**
0345: * Verifies that this CRL was signed using the
0346: * private key that corresponds to the given public key,
0347: * and that the signature verification was computed by
0348: * the given provider.
0349: *
0350: * @param key the PublicKey used to carry out the verification.
0351: * @param sigProvider the name of the signature provider.
0352: *
0353: * @exception NoSuchAlgorithmException on unsupported signature
0354: * algorithms.
0355: * @exception InvalidKeyException on incorrect key.
0356: * @exception NoSuchProviderException on incorrect provider.
0357: * @exception SignatureException on signature errors.
0358: * @exception CRLException on encoding errors.
0359: */
0360: public synchronized void verify(PublicKey key, String sigProvider)
0361: throws CRLException, NoSuchAlgorithmException,
0362: InvalidKeyException, NoSuchProviderException,
0363: SignatureException {
0364:
0365: if (sigProvider == null) {
0366: sigProvider = "";
0367: }
0368: if ((verifiedPublicKey != null)
0369: && verifiedPublicKey.equals(key)) {
0370: // this CRL has already been successfully verified using
0371: // this public key. Make sure providers match, too.
0372: if (sigProvider.equals(verifiedProvider)) {
0373: return;
0374: }
0375: }
0376: if (signedCRL == null) {
0377: throw new CRLException("Uninitialized CRL");
0378: }
0379: Signature sigVerf = null;
0380: if (sigProvider.length() == 0) {
0381: sigVerf = Signature.getInstance(sigAlgId.getName());
0382: } else {
0383: sigVerf = Signature.getInstance(sigAlgId.getName(),
0384: sigProvider);
0385: }
0386: sigVerf.initVerify(key);
0387:
0388: if (tbsCertList == null) {
0389: throw new CRLException("Uninitialized CRL");
0390: }
0391:
0392: sigVerf.update(tbsCertList, 0, tbsCertList.length);
0393:
0394: if (!sigVerf.verify(signature)) {
0395: throw new SignatureException("Signature does not match.");
0396: }
0397: verifiedPublicKey = key;
0398: verifiedProvider = sigProvider;
0399: }
0400:
0401: /**
0402: * Encodes an X.509 CRL, and signs it using the given key.
0403: *
0404: * @param key the private key used for signing.
0405: * @param algorithm the name of the signature algorithm used.
0406: *
0407: * @exception NoSuchAlgorithmException on unsupported signature
0408: * algorithms.
0409: * @exception InvalidKeyException on incorrect key.
0410: * @exception NoSuchProviderException on incorrect provider.
0411: * @exception SignatureException on signature errors.
0412: * @exception CRLException if any mandatory data was omitted.
0413: */
0414: public void sign(PrivateKey key, String algorithm)
0415: throws CRLException, NoSuchAlgorithmException,
0416: InvalidKeyException, NoSuchProviderException,
0417: SignatureException {
0418: sign(key, algorithm, null);
0419: }
0420:
0421: /**
0422: * Encodes an X.509 CRL, and signs it using the given key.
0423: *
0424: * @param key the private key used for signing.
0425: * @param algorithm the name of the signature algorithm used.
0426: * @param provider the name of the provider.
0427: *
0428: * @exception NoSuchAlgorithmException on unsupported signature
0429: * algorithms.
0430: * @exception InvalidKeyException on incorrect key.
0431: * @exception NoSuchProviderException on incorrect provider.
0432: * @exception SignatureException on signature errors.
0433: * @exception CRLException if any mandatory data was omitted.
0434: */
0435: public void sign(PrivateKey key, String algorithm, String provider)
0436: throws CRLException, NoSuchAlgorithmException,
0437: InvalidKeyException, NoSuchProviderException,
0438: SignatureException {
0439: try {
0440: if (readOnly)
0441: throw new CRLException("cannot over-write existing CRL");
0442: Signature sigEngine = null;
0443: if ((provider == null) || (provider.length() == 0))
0444: sigEngine = Signature.getInstance(algorithm);
0445: else
0446: sigEngine = Signature.getInstance(algorithm, provider);
0447:
0448: sigEngine.initSign(key);
0449:
0450: // in case the name is reset
0451: sigAlgId = AlgorithmId.get(sigEngine.getAlgorithm());
0452: infoSigAlgId = sigAlgId;
0453:
0454: DerOutputStream out = new DerOutputStream();
0455: DerOutputStream tmp = new DerOutputStream();
0456:
0457: // encode crl info
0458: encodeInfo(tmp);
0459:
0460: // encode algorithm identifier
0461: sigAlgId.encode(tmp);
0462:
0463: // Create and encode the signature itself.
0464: sigEngine.update(tbsCertList, 0, tbsCertList.length);
0465: signature = sigEngine.sign();
0466: tmp.putBitString(signature);
0467:
0468: // Wrap the signed data in a SEQUENCE { data, algorithm, sig }
0469: out.write(DerValue.tag_Sequence, tmp);
0470: signedCRL = out.toByteArray();
0471: readOnly = true;
0472:
0473: } catch (IOException e) {
0474: throw new CRLException("Error while encoding data: "
0475: + e.getMessage());
0476: }
0477: }
0478:
0479: /**
0480: * Returns a printable string of this CRL.
0481: *
0482: * @return value of this CRL in a printable form.
0483: */
0484: public String toString() {
0485: StringBuffer sb = new StringBuffer();
0486: sb.append("X.509 CRL v" + (version + 1) + "\n");
0487: if (sigAlgId != null)
0488: sb.append("Signature Algorithm: " + sigAlgId.toString()
0489: + ", OID=" + (sigAlgId.getOID()).toString() + "\n");
0490: if (issuer != null)
0491: sb.append("Issuer: " + issuer.toString() + "\n");
0492: if (this Update != null)
0493: sb.append("\nThis Update: " + this Update.toString() + "\n");
0494: if (nextUpdate != null)
0495: sb.append("Next Update: " + nextUpdate.toString() + "\n");
0496: if (revokedCerts.isEmpty())
0497: sb.append("\nNO certificates have been revoked\n");
0498: else {
0499: sb.append("\nRevoked Certificates: " + revokedCerts.size());
0500: int i = 1;
0501: for (Enumeration e = revokedCerts.elements(); e
0502: .hasMoreElements(); i++)
0503: sb.append("\n[" + i + "] "
0504: + ((X509CRLEntry) e.nextElement()).toString());
0505: }
0506: if (extensions != null) {
0507: Collection allExts = extensions.getAllExtensions();
0508: Object[] objs = allExts.toArray();
0509: sb.append("\nCRL Extensions: " + objs.length);
0510: for (int i = 0; i < objs.length; i++) {
0511: sb.append("\n[" + (i + 1) + "]: ");
0512: Extension ext = (Extension) objs[i];
0513: try {
0514: if (OIDMap.getClass(ext.getExtensionId()) == null) {
0515: sb.append(ext.toString());
0516: byte[] extValue = ext.getExtensionValue();
0517: if (extValue != null) {
0518: DerOutputStream out = new DerOutputStream();
0519: out.putOctetString(extValue);
0520: extValue = out.toByteArray();
0521: HexDumpEncoder enc = new HexDumpEncoder();
0522: sb
0523: .append("Extension unknown: "
0524: + "DER encoded OCTET string =\n"
0525: + enc
0526: .encodeBuffer(extValue)
0527: + "\n");
0528: }
0529: } else
0530: sb.append(ext.toString()); // sub-class exists
0531: } catch (Exception e) {
0532: sb.append(", Error parsing this extension");
0533: }
0534: }
0535: }
0536: if (signature != null) {
0537: HexDumpEncoder encoder = new HexDumpEncoder();
0538: sb.append("\nSignature:\n"
0539: + encoder.encodeBuffer(signature) + "\n");
0540: } else
0541: sb.append("NOT signed yet\n");
0542: return sb.toString();
0543: }
0544:
0545: /**
0546: * Checks whether the given certificate is on this CRL.
0547: *
0548: * @param cert the certificate to check for.
0549: * @return true if the given certificate is on this CRL,
0550: * false otherwise.
0551: */
0552: public boolean isRevoked(Certificate cert) {
0553: if (revokedCerts == null || revokedCerts.isEmpty())
0554: return false;
0555: if (!(cert instanceof X509Certificate))
0556: return false;
0557: BigInteger serialNumber = ((X509Certificate) cert)
0558: .getSerialNumber();
0559: return revokedCerts.containsKey(serialNumber);
0560: }
0561:
0562: /**
0563: * Gets the version number from this CRL.
0564: * The ASN.1 definition for this is:
0565: * <pre>
0566: * Version ::= INTEGER { v1(0), v2(1), v3(2) }
0567: * -- v3 does not apply to CRLs but appears for consistency
0568: * -- with definition of Version for certs
0569: * </pre>
0570: * @return the version number, i.e. 1 or 2.
0571: */
0572: public int getVersion() {
0573: return version + 1;
0574: }
0575:
0576: /**
0577: * Gets the issuer distinguished name from this CRL.
0578: * The issuer name identifies the entity who has signed (and
0579: * issued the CRL). The issuer name field contains an
0580: * X.500 distinguished name (DN).
0581: * The ASN.1 definition for this is:
0582: * <pre>
0583: * issuer Name
0584: *
0585: * Name ::= CHOICE { RDNSequence }
0586: * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
0587: * RelativeDistinguishedName ::=
0588: * SET OF AttributeValueAssertion
0589: *
0590: * AttributeValueAssertion ::= SEQUENCE {
0591: * AttributeType,
0592: * AttributeValue }
0593: * AttributeType ::= OBJECT IDENTIFIER
0594: * AttributeValue ::= ANY
0595: * </pre>
0596: * The Name describes a hierarchical name composed of attributes,
0597: * such as country name, and corresponding values, such as US.
0598: * The type of the component AttributeValue is determined by the
0599: * AttributeType; in general it will be a directoryString.
0600: * A directoryString is usually one of PrintableString,
0601: * TeletexString or UniversalString.
0602: * @return the issuer name.
0603: */
0604: public Principal getIssuerDN() {
0605: return (Principal) issuer;
0606: }
0607:
0608: /**
0609: * Return the issuer as X500Principal. Overrides method in X509CRL
0610: * to provide a slightly more efficient version.
0611: */
0612: public X500Principal getIssuerX500Principal() {
0613: if (issuerPrincipal == null) {
0614: issuerPrincipal = issuer.asX500Principal();
0615: }
0616: return issuerPrincipal;
0617: }
0618:
0619: /**
0620: * Gets the thisUpdate date from the CRL.
0621: * The ASN.1 definition for this is:
0622: *
0623: * @return the thisUpdate date from the CRL.
0624: */
0625: public Date getThisUpdate() {
0626: return (new Date(this Update.getTime()));
0627: }
0628:
0629: /**
0630: * Gets the nextUpdate date from the CRL.
0631: *
0632: * @return the nextUpdate date from the CRL, or null if
0633: * not present.
0634: */
0635: public Date getNextUpdate() {
0636: if (nextUpdate == null)
0637: return null;
0638: return (new Date(nextUpdate.getTime()));
0639: }
0640:
0641: /**
0642: * Gets the CRL entry with the given serial number from this CRL.
0643: *
0644: * @return the entry with the given serial number, or null if no such
0645: * entry exists in the CRL.
0646: * @see X509CRLEntry
0647: */
0648: public X509CRLEntry getRevokedCertificate(BigInteger serialNumber) {
0649: if (revokedCerts == null || revokedCerts.isEmpty())
0650: return null;
0651: return (X509CRLEntry) revokedCerts.get(serialNumber);
0652: }
0653:
0654: /**
0655: * Gets all the revoked certificates from the CRL.
0656: * A Set of X509CRLEntry.
0657: *
0658: * @return all the revoked certificates or null if there are
0659: * none.
0660: * @see X509CRLEntry
0661: */
0662: public Set getRevokedCertificates() {
0663: if (revokedCerts == null || revokedCerts.isEmpty())
0664: return null;
0665: else {
0666: HashSet certSet = new HashSet(11);
0667: Collection badCerts = revokedCerts.values();
0668: Object[] objs = badCerts.toArray();
0669: for (int i = 0; i < objs.length; i++)
0670: certSet.add(objs[i]);
0671: return certSet;
0672: }
0673: }
0674:
0675: /**
0676: * Gets the DER encoded CRL information, the
0677: * <code>tbsCertList</code> from this CRL.
0678: * This can be used to verify the signature independently.
0679: *
0680: * @return the DER encoded CRL information.
0681: * @exception CRLException on encoding errors.
0682: */
0683: public byte[] getTBSCertList() throws CRLException {
0684: if (tbsCertList == null)
0685: throw new CRLException("Uninitialized CRL");
0686: byte[] dup = new byte[tbsCertList.length];
0687: System.arraycopy(tbsCertList, 0, dup, 0, dup.length);
0688: return dup;
0689: }
0690:
0691: /**
0692: * Gets the raw Signature bits from the CRL.
0693: *
0694: * @return the signature.
0695: */
0696: public byte[] getSignature() {
0697: if (signature == null)
0698: return null;
0699: byte[] dup = new byte[signature.length];
0700: System.arraycopy(signature, 0, dup, 0, dup.length);
0701: return dup;
0702: }
0703:
0704: /**
0705: * Gets the signature algorithm name for the CRL
0706: * signature algorithm. For example, the string "SHA1withDSA".
0707: * The ASN.1 definition for this is:
0708: * <pre>
0709: * AlgorithmIdentifier ::= SEQUENCE {
0710: * algorithm OBJECT IDENTIFIER,
0711: * parameters ANY DEFINED BY algorithm OPTIONAL }
0712: * -- contains a value of the type
0713: * -- registered for use with the
0714: * -- algorithm object identifier value
0715: * </pre>
0716: *
0717: * @return the signature algorithm name.
0718: */
0719: public String getSigAlgName() {
0720: if (sigAlgId == null)
0721: return null;
0722: return sigAlgId.getName();
0723: }
0724:
0725: /**
0726: * Gets the signature algorithm OID string from the CRL.
0727: * An OID is represented by a set of positive whole number separated
0728: * by ".", that means,<br>
0729: * <positive whole number>.<positive whole number>.<...>
0730: * For example, the string "1.2.840.10040.4.3" identifies the SHA-1
0731: * with DSA signature algorithm, as per RFC 2459.
0732: *
0733: * @return the signature algorithm oid string.
0734: */
0735: public String getSigAlgOID() {
0736: if (sigAlgId == null)
0737: return null;
0738: ObjectIdentifier oid = sigAlgId.getOID();
0739: return oid.toString();
0740: }
0741:
0742: /**
0743: * Gets the DER encoded signature algorithm parameters from this
0744: * CRL's signature algorithm. In most cases, the signature
0745: * algorithm parameters are null, the parameters are usually
0746: * supplied with the Public Key.
0747: *
0748: * @return the DER encoded signature algorithm parameters, or
0749: * null if no parameters are present.
0750: */
0751: public byte[] getSigAlgParams() {
0752: if (sigAlgId == null)
0753: return null;
0754: try {
0755: return sigAlgId.getEncodedParams();
0756: } catch (IOException e) {
0757: return null;
0758: }
0759: }
0760:
0761: /**
0762: * return the AuthorityKeyIdentifier, if any.
0763: *
0764: * @returns AuthorityKeyIdentifier or null
0765: * (if no AuthorityKeyIdentifierExtension)
0766: * @throws IOException on error
0767: */
0768: public KeyIdentifier getAuthKeyId() throws IOException {
0769: AuthorityKeyIdentifierExtension aki = getAuthKeyIdExtension();
0770: if (aki != null) {
0771: KeyIdentifier keyId = (KeyIdentifier) aki.get(aki.KEY_ID);
0772: return keyId;
0773: } else {
0774: return null;
0775: }
0776: }
0777:
0778: /**
0779: * return the AuthorityKeyIdentifierExtension, if any.
0780: *
0781: * @returns AuthorityKeyIdentifierExtension or null (if no such extension)
0782: * @throws IOException on error
0783: */
0784: public AuthorityKeyIdentifierExtension getAuthKeyIdExtension()
0785: throws IOException {
0786: Object obj = getExtension(PKIXExtensions.AuthorityKey_Id);
0787: return (AuthorityKeyIdentifierExtension) obj;
0788: }
0789:
0790: /**
0791: * return the CRLNumberExtension, if any.
0792: *
0793: * @returns CRLNumberExtension or null (if no such extension)
0794: * @throws IOException on error
0795: */
0796: public CRLNumberExtension getCRLNumberExtension()
0797: throws IOException {
0798: Object obj = getExtension(PKIXExtensions.CRLNumber_Id);
0799: return (CRLNumberExtension) obj;
0800: }
0801:
0802: /**
0803: * return the CRL number from the CRLNumberExtension, if any.
0804: *
0805: * @returns number or null (if no such extension)
0806: * @throws IOException on error
0807: */
0808: public BigInteger getCRLNumber() throws IOException {
0809: CRLNumberExtension numExt = getCRLNumberExtension();
0810: if (numExt != null) {
0811: BigInteger num = (BigInteger) numExt.get(numExt.NUMBER);
0812: return num;
0813: } else {
0814: return null;
0815: }
0816: }
0817:
0818: /**
0819: * return the IssuerAlternativeNameExtension, if any.
0820: *
0821: * @returns IssuerAlternativeNameExtension or null (if no such extension)
0822: * @throws IOException on error
0823: */
0824: public IssuerAlternativeNameExtension getIssuerAltNameExtension()
0825: throws IOException {
0826: Object obj = getExtension(PKIXExtensions.IssuerAlternativeName_Id);
0827: return (IssuerAlternativeNameExtension) obj;
0828: }
0829:
0830: /**
0831: * Return true if a critical extension is found that is
0832: * not supported, otherwise return false.
0833: */
0834: public boolean hasUnsupportedCriticalExtension() {
0835: if (extensions == null)
0836: return false;
0837: return extensions.hasUnsupportedCriticalExtension();
0838: }
0839:
0840: /**
0841: * Gets a Set of the extension(s) marked CRITICAL in the
0842: * CRL. In the returned set, each extension is represented by
0843: * its OID string.
0844: *
0845: * @return a set of the extension oid strings in the
0846: * CRL that are marked critical.
0847: */
0848: public Set getCriticalExtensionOIDs() {
0849: if (extensions == null)
0850: return null;
0851: HashSet extSet = new HashSet(11);
0852: Extension ex;
0853: for (Enumeration e = extensions.getElements(); e
0854: .hasMoreElements();) {
0855: ex = (Extension) e.nextElement();
0856: if (ex.isCritical())
0857: extSet.add(((ObjectIdentifier) ex.getExtensionId())
0858: .toString());
0859: }
0860: return extSet;
0861: }
0862:
0863: /**
0864: * Gets a Set of the extension(s) marked NON-CRITICAL in the
0865: * CRL. In the returned set, each extension is represented by
0866: * its OID string.
0867: *
0868: * @return a set of the extension oid strings in the
0869: * CRL that are NOT marked critical.
0870: */
0871: public Set getNonCriticalExtensionOIDs() {
0872: if (extensions == null)
0873: return null;
0874: HashSet extSet = new HashSet(11);
0875: Extension ex;
0876: for (Enumeration e = extensions.getElements(); e
0877: .hasMoreElements();) {
0878: ex = (Extension) e.nextElement();
0879: if (!ex.isCritical())
0880: extSet.add(((ObjectIdentifier) ex.getExtensionId())
0881: .toString());
0882: }
0883: return extSet;
0884: }
0885:
0886: /**
0887: * Gets the DER encoded OCTET string for the extension value
0888: * (<code>extnValue</code>) identified by the passed in oid String.
0889: * The <code>oid</code> string is
0890: * represented by a set of positive whole number separated
0891: * by ".", that means,<br>
0892: * <positive whole number>.<positive whole number>.<...>
0893: *
0894: * @param oid the Object Identifier value for the extension.
0895: * @return the der encoded octet string of the extension value.
0896: */
0897: public byte[] getExtensionValue(String oid) {
0898: if (extensions == null)
0899: return null;
0900: try {
0901: String extAlias = OIDMap.getName(new ObjectIdentifier(oid));
0902: Extension crlExt = null;
0903:
0904: if (extAlias == null) { // may be unknown
0905: ObjectIdentifier findOID = new ObjectIdentifier(oid);
0906: Extension ex = null;
0907: ObjectIdentifier inCertOID;
0908: for (Enumeration e = extensions.getElements(); e
0909: .hasMoreElements();) {
0910: ex = (Extension) e.nextElement();
0911: inCertOID = ex.getExtensionId();
0912: if (inCertOID.equals(findOID)) {
0913: crlExt = ex;
0914: break;
0915: }
0916: }
0917: } else
0918: crlExt = extensions.get(extAlias);
0919: if (crlExt == null)
0920: return null;
0921: byte[] extData = crlExt.getExtensionValue();
0922: if (extData == null)
0923: return null;
0924: DerOutputStream out = new DerOutputStream();
0925: out.putOctetString(extData);
0926: return out.toByteArray();
0927: } catch (Exception e) {
0928: return null;
0929: }
0930: }
0931:
0932: /**
0933: * get an extension
0934: *
0935: * @param oid ObjectIdentifier of extension desired
0936: * @returns Object of type <extension> or null, if not found
0937: * @throws IOException on error
0938: */
0939: public Object getExtension(ObjectIdentifier oid) {
0940: if (extensions == null)
0941: return null;
0942:
0943: // NOTE: Consider cloning this
0944: return extensions.get(OIDMap.getName(oid));
0945: }
0946:
0947: /*
0948: * Parses an X.509 CRL, should be used only by constructors.
0949: */
0950: private void parse(DerValue val) throws CRLException, IOException {
0951: // check if can over write the certificate
0952: if (readOnly)
0953: throw new CRLException("cannot over-write existing CRL");
0954:
0955: signedCRL = val.toByteArray();
0956: DerValue seq[] = new DerValue[3];
0957:
0958: seq[0] = val.data.getDerValue();
0959: seq[1] = val.data.getDerValue();
0960: seq[2] = val.data.getDerValue();
0961:
0962: if (val.data.available() != 0)
0963: throw new CRLException("signed overrun, bytes = "
0964: + val.data.available());
0965:
0966: if (seq[0].tag != DerValue.tag_Sequence)
0967: throw new CRLException("signed CRL fields invalid");
0968:
0969: sigAlgId = AlgorithmId.parse(seq[1]);
0970: signature = seq[2].getBitString();
0971:
0972: if (seq[1].data.available() != 0)
0973: throw new CRLException("AlgorithmId field overrun");
0974:
0975: if (seq[2].data.available() != 0)
0976: throw new CRLException("Signature field overrun");
0977:
0978: // the tbsCertsList
0979: tbsCertList = seq[0].toByteArray();
0980:
0981: // parse the information
0982: DerInputStream derStrm = seq[0].data;
0983: DerValue tmp;
0984: byte nextByte;
0985:
0986: // version (optional if v1)
0987: version = 0; // by default, version = v1 == 0
0988: nextByte = (byte) derStrm.peekByte();
0989: if (nextByte == DerValue.tag_Integer) {
0990: version = derStrm.getInteger();
0991: if (version != 1) // i.e. v2
0992: throw new CRLException("Invalid version");
0993: }
0994: tmp = derStrm.getDerValue();
0995:
0996: // signature
0997: AlgorithmId tmpId = AlgorithmId.parse(tmp);
0998:
0999: // the "inner" and "outer" signature algorithms must match
1000: if (!tmpId.equals(sigAlgId))
1001: throw new CRLException("Signature algorithm mismatch");
1002: infoSigAlgId = tmpId;
1003:
1004: // issuer
1005: issuer = new X500Name(derStrm);
1006: String issuerString = issuer.toString();
1007: if ((issuerString == null || issuerString.length() == 0)
1008: && version == 0)
1009: throw new CRLException(
1010: "Null Issuer DN allowed only in v2 CRL");
1011:
1012: // thisUpdate
1013: // check if UTCTime encoded or GeneralizedTime
1014:
1015: nextByte = (byte) derStrm.peekByte();
1016: if (nextByte == DerValue.tag_UtcTime) {
1017: this Update = derStrm.getUTCTime();
1018: } else if (nextByte == DerValue.tag_GeneralizedTime) {
1019: this Update = derStrm.getGeneralizedTime();
1020: } else {
1021: throw new CRLException("Invalid encoding for thisUpdate"
1022: + " (tag=" + nextByte + ")");
1023: }
1024:
1025: if (derStrm.available() == 0)
1026: return; // done parsing no more optional fields present
1027:
1028: // nextUpdate (optional)
1029: nextByte = (byte) derStrm.peekByte();
1030: if (nextByte == DerValue.tag_UtcTime) {
1031: nextUpdate = derStrm.getUTCTime();
1032: } else if (nextByte == DerValue.tag_GeneralizedTime) {
1033: nextUpdate = derStrm.getGeneralizedTime();
1034: } // else it is not present
1035:
1036: if (derStrm.available() == 0)
1037: return; // done parsing no more optional fields present
1038:
1039: // revokedCertificates (optional)
1040: nextByte = (byte) derStrm.peekByte();
1041: if ((nextByte == DerValue.tag_SequenceOf)
1042: && (!((nextByte & 0x0c0) == 0x080))) {
1043: DerValue[] badCerts = derStrm.getSequence(4);
1044:
1045: for (int i = 0; i < badCerts.length; i++) {
1046: X509CRLEntryImpl entry = new X509CRLEntryImpl(
1047: badCerts[i]);
1048: revokedCerts.put(entry.getSerialNumber(),
1049: (X509CRLEntry) entry);
1050: }
1051: }
1052:
1053: if (derStrm.available() == 0)
1054: return; // done parsing no extensions
1055:
1056: // crlExtensions (optional)
1057: tmp = derStrm.getDerValue();
1058: if (tmp.isConstructed() && tmp.isContextSpecific((byte) 0)) {
1059: extensions = new CRLExtensions(tmp.data);
1060: }
1061: readOnly = true;
1062: }
1063:
1064: /**
1065: * Extract the issuer X500Principal from an X509CRL. Parses the encoded
1066: * form of the CRL to preserve the principal's ASN.1 encoding.
1067: *
1068: * Called by java.security.cert.X509CRL.getIssuerX500Principal().
1069: */
1070: public static X500Principal getIssuerX500Principal(X509CRL crl) {
1071: try {
1072: byte[] encoded = crl.getEncoded();
1073: DerInputStream derIn = new DerInputStream(encoded);
1074: DerValue tbsCert = derIn.getSequence(3)[0];
1075: DerInputStream tbsIn = tbsCert.data;
1076:
1077: DerValue tmp;
1078: // skip version number if present
1079: byte nextByte = (byte) tbsIn.peekByte();
1080: if (nextByte == DerValue.tag_Integer) {
1081: tmp = tbsIn.getDerValue();
1082: }
1083:
1084: tmp = tbsIn.getDerValue(); // skip signature
1085: tmp = tbsIn.getDerValue(); // issuer
1086: byte[] principalBytes = tmp.toByteArray();
1087: return new X500Principal(principalBytes);
1088: } catch (Exception e) {
1089: throw new RuntimeException("Could not parse issuer", e);
1090: }
1091: }
1092:
1093: /**
1094: * Returned the encoding of the given certificate for internal use.
1095: * Callers must guarantee that they neither modify it nor expose it
1096: * to untrusted code. Uses getEncodedInternal() if the certificate
1097: * is instance of X509CertImpl, getEncoded() otherwise.
1098: */
1099: public static byte[] getEncodedInternal(X509CRL crl)
1100: throws CRLException {
1101: if (crl instanceof X509CRLImpl) {
1102: return ((X509CRLImpl) crl).getEncodedInternal();
1103: } else {
1104: return crl.getEncoded();
1105: }
1106: }
1107:
1108: }
|