1291 lines · 44.3 KB · Java
RawDownload
/* * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.security.x509; import java.io.InputStream;import java.io.OutputStream;import java.io.IOException;import java.math.BigInteger;import java.security.Principal;import java.security.PublicKey;import java.security.PrivateKey;import java.security.Security;import java.security.Signature;import java.security.NoSuchAlgorithmException;import java.security.InvalidKeyException;import java.security.NoSuchProviderException;import java.security.SignatureException;import java.security.cert.Certificate;import java.security.cert.X509CRL;import java.security.cert.X509Certificate;import java.security.cert.X509CRLEntry;import java.security.cert.CRLException;import java.util.*; import javax.security.auth.x500.X500Principal; import sun.security.provider.X509Factory;import sun.security.util.*;import sun.misc.HexDumpEncoder; /** * <p> * An implmentation for X509 CRL (Certificate Revocation List). * <p> * The X.509 v2 CRL format is described below in ASN.1: * <pre> * CertificateList  ::=  SEQUENCE  { *     tbsCertList          TBSCertList, *     signatureAlgorithm   AlgorithmIdentifier, *     signature            BIT STRING  } * </pre> * More information can be found in * <a href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280: Internet X.509 * Public Key Infrastructure Certificate and CRL Profile</a>. * <p> * The ASN.1 definition of <code>tbsCertList</code> is: * <pre> * TBSCertList  ::=  SEQUENCE  { *     version                 Version OPTIONAL, *                             -- if present, must be v2 *     signature               AlgorithmIdentifier, *     issuer                  Name, *     thisUpdate              ChoiceOfTime, *     nextUpdate              ChoiceOfTime OPTIONAL, *     revokedCertificates     SEQUENCE OF SEQUENCE  { *         userCertificate         CertificateSerialNumber, *         revocationDate          ChoiceOfTime, *         crlEntryExtensions      Extensions OPTIONAL *                                 -- if present, must be v2 *         }  OPTIONAL, *     crlExtensions           [0]  EXPLICIT Extensions OPTIONAL *                                  -- if present, must be v2 *     } * </pre> * * @author Hemma Prafullchandra * @see X509CRL */public class X509CRLImpl extends X509CRL implements DerEncoder {     // CRL data, and its envelope    private byte[]      signedCRL = null; // DER encoded crl    private byte[]      signature = null; // raw signature bits    private byte[]      tbsCertList = null; // DER encoded "to-be-signed" CRL    private AlgorithmId sigAlgId = null; // sig alg in CRL     // crl information    private int              version;    private AlgorithmId      infoSigAlgId; // sig alg in "to-be-signed" crl    private X500Name         issuer = null;    private X500Principal    issuerPrincipal = null;    private Date             thisUpdate = null;    private Date             nextUpdate = null;    private Map<X509IssuerSerial,X509CRLEntry> revokedCerts = new LinkedHashMap<X509IssuerSerial,X509CRLEntry>();    private CRLExtensions    extensions = null;    private final static boolean isExplicit = true;    private static final long YR_2050 = 2524636800000L;     private boolean readOnly = false;     /**     * PublicKey that has previously been used to successfully verify     * the signature of this CRL. Null if the CRL has not     * yet been verified (successfully).     */    private PublicKey verifiedPublicKey;    /**     * If verifiedPublicKey is not null, name of the provider used to     * successfully verify the signature of this CRL, or the     * empty String if no provider was explicitly specified.     */    private String verifiedProvider;     /**     * Not to be used. As it would lead to cases of uninitialized     * CRL objects.     */    private X509CRLImpl() { }     /**     * Unmarshals an X.509 CRL from its encoded form, parsing the encoded     * bytes.  This form of constructor is used by agents which     * need to examine and use CRL contents. Note that the buffer     * must include only one CRL, and no "garbage" may be left at     * the end.     *     * @param crlData the encoded bytes, with no trailing padding.     * @exception CRLException on parsing errors.     */    public X509CRLImpl(byte[] crlData) throws CRLException {        try {            parse(new DerValue(crlData));        } catch (IOException e) {            signedCRL = null;            throw new CRLException("Parsing error: " + e.getMessage());        }    }     /**     * Unmarshals an X.509 CRL from an DER value.     *     * @param val a DER value holding at least one CRL     * @exception CRLException on parsing errors.     */    public X509CRLImpl(DerValue val) throws CRLException {        try {            parse(val);        } catch (IOException e) {            signedCRL = null;            throw new CRLException("Parsing error: " + e.getMessage());        }    }     /**     * Unmarshals an X.509 CRL from an input stream. Only one CRL     * is expected at the end of the input stream.     *     * @param inStrm an input stream holding at least one CRL     * @exception CRLException on parsing errors.     */    public X509CRLImpl(InputStream inStrm) throws CRLException {        try {            parse(new DerValue(inStrm));        } catch (IOException e) {            signedCRL = null;            throw new CRLException("Parsing error: " + e.getMessage());        }    }     /**     * Initial CRL constructor, no revoked certs, and no extensions.     *     * @param issuer the name of the CA issuing this CRL.     * @param thisUpdate the Date of this issue.     * @param nextUpdate the Date of the next CRL.     */    public X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate) {        this.issuer = issuer;        this.thisUpdate = thisDate;        this.nextUpdate = nextDate;    }     /**     * CRL constructor, revoked certs, no extensions.     *     * @param issuer the name of the CA issuing this CRL.     * @param thisUpdate the Date of this issue.     * @param nextUpdate the Date of the next CRL.     * @param badCerts the array of CRL entries.     *     * @exception CRLException on parsing/construction errors.     */    public X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate,                       X509CRLEntry[] badCerts)        throws CRLException    {        this.issuer = issuer;        this.thisUpdate = thisDate;        this.nextUpdate = nextDate;        if (badCerts != null) {            X500Principal crlIssuer = getIssuerX500Principal();            X500Principal badCertIssuer = crlIssuer;            for (int i = 0; i < badCerts.length; i++) {                X509CRLEntryImpl badCert = (X509CRLEntryImpl)badCerts[i];                try {                    badCertIssuer = getCertIssuer(badCert, badCertIssuer);                } catch (IOException ioe) {                    throw new CRLException(ioe);                }                badCert.setCertificateIssuer(crlIssuer, badCertIssuer);                X509IssuerSerial issuerSerial = new X509IssuerSerial                    (badCertIssuer, badCert.getSerialNumber());                this.revokedCerts.put(issuerSerial, badCert);                if (badCert.hasExtensions()) {                    this.version = 1;                }            }        }    }     /**     * CRL constructor, revoked certs and extensions.     *     * @param issuer the name of the CA issuing this CRL.     * @param thisUpdate the Date of this issue.     * @param nextUpdate the Date of the next CRL.     * @param badCerts the array of CRL entries.     * @param crlExts the CRL extensions.     *     * @exception CRLException on parsing/construction errors.     */    public X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate,               X509CRLEntry[] badCerts, CRLExtensions crlExts)        throws CRLException    {        this(issuer, thisDate, nextDate, badCerts);        if (crlExts != null) {            this.extensions = crlExts;            this.version = 1;        }    }     /**     * Returned the encoding as an uncloned byte array. Callers must     * guarantee that they neither modify it nor expose it to untrusted     * code.     */    public byte[] getEncodedInternal() throws CRLException {        if (signedCRL == null) {            throw new CRLException("Null CRL to encode");        }        return signedCRL;    }     /**     * Returns the ASN.1 DER encoded form of this CRL.     *     * @exception CRLException if an encoding error occurs.     */    public byte[] getEncoded() throws CRLException {        return getEncodedInternal().clone();    }     /**     * Encodes the "to-be-signed" CRL to the OutputStream.     *     * @param out the OutputStream to write to.     * @exception CRLException on encoding errors.     */    public void encodeInfo(OutputStream out) throws CRLException {        try {            DerOutputStream tmp = new DerOutputStream();            DerOutputStream rCerts = new DerOutputStream();            DerOutputStream seq = new DerOutputStream();             if (version != 0) // v2 crl encode version                tmp.putInteger(version);            infoSigAlgId.encode(tmp);            if ((version == 0) && (issuer.toString() == null))                throw new CRLException("Null Issuer DN not allowed in v1 CRL");            issuer.encode(tmp);             if (thisUpdate.getTime() < YR_2050)                tmp.putUTCTime(thisUpdate);            else                tmp.putGeneralizedTime(thisUpdate);             if (nextUpdate != null) {                if (nextUpdate.getTime() < YR_2050)                    tmp.putUTCTime(nextUpdate);                else                    tmp.putGeneralizedTime(nextUpdate);            }             if (!revokedCerts.isEmpty()) {                for (X509CRLEntry entry : revokedCerts.values()) {                    ((X509CRLEntryImpl)entry).encode(rCerts);                }                tmp.write(DerValue.tag_Sequence, rCerts);            }             if (extensions != null)                extensions.encode(tmp, isExplicit);             seq.write(DerValue.tag_Sequence, tmp);             tbsCertList = seq.toByteArray();            out.write(tbsCertList);        } catch (IOException e) {             throw new CRLException("Encoding error: " + e.getMessage());        }    }     /**     * Verifies that this CRL was signed using the     * private key that corresponds to the given public key.     *     * @param key the PublicKey used to carry out the verification.     *     * @exception NoSuchAlgorithmException on unsupported signature     * algorithms.     * @exception InvalidKeyException on incorrect key.     * @exception NoSuchProviderException if there's no default provider.     * @exception SignatureException on signature errors.     * @exception CRLException on encoding errors.     */    public void verify(PublicKey key)    throws CRLException, NoSuchAlgorithmException, InvalidKeyException,           NoSuchProviderException, SignatureException {        verify(key, "");    }     /**     * Verifies that this CRL was signed using the     * private key that corresponds to the given public key,     * and that the signature verification was computed by     * the given provider.     *     * @param key the PublicKey used to carry out the verification.     * @param sigProvider the name of the signature provider.     *     * @exception NoSuchAlgorithmException on unsupported signature     * algorithms.     * @exception InvalidKeyException on incorrect key.     * @exception NoSuchProviderException on incorrect provider.     * @exception SignatureException on signature errors.     * @exception CRLException on encoding errors.     */    public synchronized void verify(PublicKey key, String sigProvider)            throws CRLException, NoSuchAlgorithmException, InvalidKeyException,            NoSuchProviderException, SignatureException {         if (sigProvider == null) {            sigProvider = "";        }        if ((verifiedPublicKey != null) && verifiedPublicKey.equals(key)) {            // this CRL has already been successfully verified using            // this public key. Make sure providers match, too.            if (sigProvider.equals(verifiedProvider)) {                return;            }        }        if (signedCRL == null) {            throw new CRLException("Uninitialized CRL");        }        Signature   sigVerf = null;        if (sigProvider.length() == 0) {            sigVerf = Signature.getInstance(sigAlgId.getName());        } else {            sigVerf = Signature.getInstance(sigAlgId.getName(), sigProvider);        }        sigVerf.initVerify(key);         if (tbsCertList == null) {            throw new CRLException("Uninitialized CRL");        }         sigVerf.update(tbsCertList, 0, tbsCertList.length);         if (!sigVerf.verify(signature)) {            throw new SignatureException("Signature does not match.");        }        verifiedPublicKey = key;        verifiedProvider = sigProvider;    }     /**     * Encodes an X.509 CRL, and signs it using the given key.     *     * @param key the private key used for signing.     * @param algorithm the name of the signature algorithm used.     *     * @exception NoSuchAlgorithmException on unsupported signature     * algorithms.     * @exception InvalidKeyException on incorrect key.     * @exception NoSuchProviderException on incorrect provider.     * @exception SignatureException on signature errors.     * @exception CRLException if any mandatory data was omitted.     */    public void sign(PrivateKey key, String algorithm)    throws CRLException, NoSuchAlgorithmException, InvalidKeyException,        NoSuchProviderException, SignatureException {        sign(key, algorithm, null);    }     /**     * Encodes an X.509 CRL, and signs it using the given key.     *     * @param key the private key used for signing.     * @param algorithm the name of the signature algorithm used.     * @param provider the name of the provider.     *     * @exception NoSuchAlgorithmException on unsupported signature     * algorithms.     * @exception InvalidKeyException on incorrect key.     * @exception NoSuchProviderException on incorrect provider.     * @exception SignatureException on signature errors.     * @exception CRLException if any mandatory data was omitted.     */    public void sign(PrivateKey key, String algorithm, String provider)    throws CRLException, NoSuchAlgorithmException, InvalidKeyException,        NoSuchProviderException, SignatureException {        try {            if (readOnly)                throw new CRLException("cannot over-write existing CRL");            Signature sigEngine = null;            if ((provider == null) || (provider.length() == 0))                sigEngine = Signature.getInstance(algorithm);            else                sigEngine = Signature.getInstance(algorithm, provider);             sigEngine.initSign(key);                                 // in case the name is reset            sigAlgId = AlgorithmId.get(sigEngine.getAlgorithm());            infoSigAlgId = sigAlgId;             DerOutputStream out = new DerOutputStream();            DerOutputStream tmp = new DerOutputStream();             // encode crl info            encodeInfo(tmp);             // encode algorithm identifier            sigAlgId.encode(tmp);             // Create and encode the signature itself.            sigEngine.update(tbsCertList, 0, tbsCertList.length);            signature = sigEngine.sign();            tmp.putBitString(signature);             // Wrap the signed data in a SEQUENCE { data, algorithm, sig }            out.write(DerValue.tag_Sequence, tmp);            signedCRL = out.toByteArray();            readOnly = true;         } catch (IOException e) {            throw new CRLException("Error while encoding data: " +                                   e.getMessage());        }    }     /**     * Returns a printable string of this CRL.     *     * @return value of this CRL in a printable form.     */    public String toString() {        StringBuffer sb = new StringBuffer();        sb.append("X.509 CRL v" + (version+1) + "\n");        if (sigAlgId != null)            sb.append("Signature Algorithm: " + sigAlgId.toString() +                  ", OID=" + (sigAlgId.getOID()).toString() + "\n");        if (issuer != null)            sb.append("Issuer: " + issuer.toString() + "\n");        if (thisUpdate != null)            sb.append("\nThis Update: " + thisUpdate.toString() + "\n");        if (nextUpdate != null)            sb.append("Next Update: " + nextUpdate.toString() + "\n");        if (revokedCerts.isEmpty())            sb.append("\nNO certificates have been revoked\n");        else {            sb.append("\nRevoked Certificates: " + revokedCerts.size());            int i = 1;            for (Iterator<X509CRLEntry> iter = revokedCerts.values().iterator();                                             iter.hasNext(); i++)                sb.append("\n[" + i + "] " + iter.next().toString());

Lines 1–500 of 1291.