0N/A/*
2362N/A * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.security.x509;
0N/A
0N/Aimport java.io.InputStream;
0N/Aimport java.io.OutputStream;
0N/Aimport java.io.IOException;
0N/Aimport java.math.BigInteger;
0N/Aimport java.security.Principal;
0N/Aimport java.security.PublicKey;
0N/Aimport java.security.PrivateKey;
0N/Aimport java.security.Security;
0N/Aimport java.security.Signature;
0N/Aimport java.security.NoSuchAlgorithmException;
0N/Aimport java.security.InvalidKeyException;
0N/Aimport java.security.NoSuchProviderException;
0N/Aimport java.security.SignatureException;
0N/Aimport java.security.cert.Certificate;
0N/Aimport java.security.cert.X509CRL;
0N/Aimport java.security.cert.X509Certificate;
0N/Aimport java.security.cert.X509CRLEntry;
0N/Aimport java.security.cert.CRLException;
0N/Aimport java.util.*;
0N/A
0N/Aimport javax.security.auth.x500.X500Principal;
0N/A
0N/Aimport sun.security.provider.X509Factory;
0N/Aimport sun.security.util.*;
0N/Aimport sun.misc.HexDumpEncoder;
0N/A
0N/A/**
0N/A * <p>
5090N/A * An implementation for X509 CRL (Certificate Revocation List).
0N/A * <p>
0N/A * The X.509 v2 CRL format is described below in ASN.1:
0N/A * <pre>
0N/A * CertificateList ::= SEQUENCE {
0N/A * tbsCertList TBSCertList,
0N/A * signatureAlgorithm AlgorithmIdentifier,
0N/A * signature BIT STRING }
0N/A * </pre>
0N/A * More information can be found in
0N/A * <a href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280: Internet X.509
0N/A * Public Key Infrastructure Certificate and CRL Profile</a>.
0N/A * <p>
0N/A * The ASN.1 definition of <code>tbsCertList</code> is:
0N/A * <pre>
0N/A * TBSCertList ::= SEQUENCE {
0N/A * version Version OPTIONAL,
0N/A * -- if present, must be v2
0N/A * signature AlgorithmIdentifier,
0N/A * issuer Name,
0N/A * thisUpdate ChoiceOfTime,
0N/A * nextUpdate ChoiceOfTime OPTIONAL,
0N/A * revokedCertificates SEQUENCE OF SEQUENCE {
0N/A * userCertificate CertificateSerialNumber,
0N/A * revocationDate ChoiceOfTime,
0N/A * crlEntryExtensions Extensions OPTIONAL
0N/A * -- if present, must be v2
0N/A * } OPTIONAL,
0N/A * crlExtensions [0] EXPLICIT Extensions OPTIONAL
0N/A * -- if present, must be v2
0N/A * }
0N/A * </pre>
0N/A *
0N/A * @author Hemma Prafullchandra
0N/A * @see X509CRL
0N/A */
2346N/Apublic class X509CRLImpl extends X509CRL implements DerEncoder {
0N/A
0N/A // CRL data, and its envelope
0N/A private byte[] signedCRL = null; // DER encoded crl
0N/A private byte[] signature = null; // raw signature bits
0N/A private byte[] tbsCertList = null; // DER encoded "to-be-signed" CRL
0N/A private AlgorithmId sigAlgId = null; // sig alg in CRL
0N/A
0N/A // crl information
0N/A private int version;
0N/A private AlgorithmId infoSigAlgId; // sig alg in "to-be-signed" crl
0N/A private X500Name issuer = null;
0N/A private X500Principal issuerPrincipal = null;
0N/A private Date thisUpdate = null;
0N/A private Date nextUpdate = null;
5090N/A private Map<X509IssuerSerial,X509CRLEntry> revokedMap = new TreeMap<>();
5090N/A private List<X509CRLEntry> revokedList = new LinkedList<>();
0N/A private CRLExtensions extensions = null;
0N/A private final static boolean isExplicit = true;
0N/A private static final long YR_2050 = 2524636800000L;
0N/A
0N/A private boolean readOnly = false;
0N/A
0N/A /**
0N/A * PublicKey that has previously been used to successfully verify
0N/A * the signature of this CRL. Null if the CRL has not
0N/A * yet been verified (successfully).
0N/A */
0N/A private PublicKey verifiedPublicKey;
0N/A /**
0N/A * If verifiedPublicKey is not null, name of the provider used to
0N/A * successfully verify the signature of this CRL, or the
0N/A * empty String if no provider was explicitly specified.
0N/A */
0N/A private String verifiedProvider;
0N/A
0N/A /**
0N/A * Not to be used. As it would lead to cases of uninitialized
0N/A * CRL objects.
0N/A */
0N/A private X509CRLImpl() { }
0N/A
0N/A /**
0N/A * Unmarshals an X.509 CRL from its encoded form, parsing the encoded
0N/A * bytes. This form of constructor is used by agents which
0N/A * need to examine and use CRL contents. Note that the buffer
0N/A * must include only one CRL, and no "garbage" may be left at
0N/A * the end.
0N/A *
0N/A * @param crlData the encoded bytes, with no trailing padding.
0N/A * @exception CRLException on parsing errors.
0N/A */
0N/A public X509CRLImpl(byte[] crlData) throws CRLException {
0N/A try {
0N/A parse(new DerValue(crlData));
0N/A } catch (IOException e) {
0N/A signedCRL = null;
0N/A throw new CRLException("Parsing error: " + e.getMessage());
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Unmarshals an X.509 CRL from an DER value.
0N/A *
0N/A * @param val a DER value holding at least one CRL
0N/A * @exception CRLException on parsing errors.
0N/A */
0N/A public X509CRLImpl(DerValue val) throws CRLException {
0N/A try {
0N/A parse(val);
0N/A } catch (IOException e) {
0N/A signedCRL = null;
0N/A throw new CRLException("Parsing error: " + e.getMessage());
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Unmarshals an X.509 CRL from an input stream. Only one CRL
0N/A * is expected at the end of the input stream.
0N/A *
0N/A * @param inStrm an input stream holding at least one CRL
0N/A * @exception CRLException on parsing errors.
0N/A */
0N/A public X509CRLImpl(InputStream inStrm) throws CRLException {
0N/A try {
0N/A parse(new DerValue(inStrm));
0N/A } catch (IOException e) {
0N/A signedCRL = null;
0N/A throw new CRLException("Parsing error: " + e.getMessage());
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Initial CRL constructor, no revoked certs, and no extensions.
0N/A *
0N/A * @param issuer the name of the CA issuing this CRL.
0N/A * @param thisUpdate the Date of this issue.
0N/A * @param nextUpdate the Date of the next CRL.
0N/A */
0N/A public X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate) {
0N/A this.issuer = issuer;
0N/A this.thisUpdate = thisDate;
0N/A this.nextUpdate = nextDate;
0N/A }
0N/A
0N/A /**
0N/A * CRL constructor, revoked certs, no extensions.
0N/A *
0N/A * @param issuer the name of the CA issuing this CRL.
0N/A * @param thisUpdate the Date of this issue.
0N/A * @param nextUpdate the Date of the next CRL.
0N/A * @param badCerts the array of CRL entries.
0N/A *
0N/A * @exception CRLException on parsing/construction errors.
0N/A */
0N/A public X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate,
0N/A X509CRLEntry[] badCerts)
0N/A throws CRLException
0N/A {
0N/A this.issuer = issuer;
0N/A this.thisUpdate = thisDate;
0N/A this.nextUpdate = nextDate;
0N/A if (badCerts != null) {
0N/A X500Principal crlIssuer = getIssuerX500Principal();
0N/A X500Principal badCertIssuer = crlIssuer;
0N/A for (int i = 0; i < badCerts.length; i++) {
0N/A X509CRLEntryImpl badCert = (X509CRLEntryImpl)badCerts[i];
0N/A try {
0N/A badCertIssuer = getCertIssuer(badCert, badCertIssuer);
0N/A } catch (IOException ioe) {
0N/A throw new CRLException(ioe);
0N/A }
0N/A badCert.setCertificateIssuer(crlIssuer, badCertIssuer);
0N/A X509IssuerSerial issuerSerial = new X509IssuerSerial
0N/A (badCertIssuer, badCert.getSerialNumber());
5090N/A this.revokedMap.put(issuerSerial, badCert);
5090N/A this.revokedList.add(badCert);
0N/A if (badCert.hasExtensions()) {
0N/A this.version = 1;
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * CRL constructor, revoked certs and extensions.
0N/A *
0N/A * @param issuer the name of the CA issuing this CRL.
0N/A * @param thisUpdate the Date of this issue.
0N/A * @param nextUpdate the Date of the next CRL.
0N/A * @param badCerts the array of CRL entries.
0N/A * @param crlExts the CRL extensions.
0N/A *
0N/A * @exception CRLException on parsing/construction errors.
0N/A */
0N/A public X509CRLImpl(X500Name issuer, Date thisDate, Date nextDate,
0N/A X509CRLEntry[] badCerts, CRLExtensions crlExts)
0N/A throws CRLException
0N/A {
0N/A this(issuer, thisDate, nextDate, badCerts);
0N/A if (crlExts != null) {
0N/A this.extensions = crlExts;
0N/A this.version = 1;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returned the encoding as an uncloned byte array. Callers must
0N/A * guarantee that they neither modify it nor expose it to untrusted
0N/A * code.
0N/A */
0N/A public byte[] getEncodedInternal() throws CRLException {
0N/A if (signedCRL == null) {
0N/A throw new CRLException("Null CRL to encode");
0N/A }
0N/A return signedCRL;
0N/A }
0N/A
0N/A /**
0N/A * Returns the ASN.1 DER encoded form of this CRL.
0N/A *
0N/A * @exception CRLException if an encoding error occurs.
0N/A */
0N/A public byte[] getEncoded() throws CRLException {
0N/A return getEncodedInternal().clone();
0N/A }
0N/A
0N/A /**
0N/A * Encodes the "to-be-signed" CRL to the OutputStream.
0N/A *
0N/A * @param out the OutputStream to write to.
0N/A * @exception CRLException on encoding errors.
0N/A */
0N/A public void encodeInfo(OutputStream out) throws CRLException {
0N/A try {
0N/A DerOutputStream tmp = new DerOutputStream();
0N/A DerOutputStream rCerts = new DerOutputStream();
0N/A DerOutputStream seq = new DerOutputStream();
0N/A
0N/A if (version != 0) // v2 crl encode version
0N/A tmp.putInteger(version);
0N/A infoSigAlgId.encode(tmp);
0N/A if ((version == 0) && (issuer.toString() == null))
0N/A throw new CRLException("Null Issuer DN not allowed in v1 CRL");
0N/A issuer.encode(tmp);
0N/A
0N/A if (thisUpdate.getTime() < YR_2050)
0N/A tmp.putUTCTime(thisUpdate);
0N/A else
0N/A tmp.putGeneralizedTime(thisUpdate);
0N/A
0N/A if (nextUpdate != null) {
0N/A if (nextUpdate.getTime() < YR_2050)
0N/A tmp.putUTCTime(nextUpdate);
0N/A else
0N/A tmp.putGeneralizedTime(nextUpdate);
0N/A }
0N/A
5090N/A if (!revokedList.isEmpty()) {
5090N/A for (X509CRLEntry entry : revokedList) {
0N/A ((X509CRLEntryImpl)entry).encode(rCerts);
0N/A }
0N/A tmp.write(DerValue.tag_Sequence, rCerts);
0N/A }
0N/A
0N/A if (extensions != null)
0N/A extensions.encode(tmp, isExplicit);
0N/A
0N/A seq.write(DerValue.tag_Sequence, tmp);
0N/A
0N/A tbsCertList = seq.toByteArray();
0N/A out.write(tbsCertList);
0N/A } catch (IOException e) {
0N/A throw new CRLException("Encoding error: " + e.getMessage());
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Verifies that this CRL was signed using the
0N/A * private key that corresponds to the given public key.
0N/A *
0N/A * @param key the PublicKey used to carry out the verification.
0N/A *
0N/A * @exception NoSuchAlgorithmException on unsupported signature
0N/A * algorithms.
0N/A * @exception InvalidKeyException on incorrect key.
0N/A * @exception NoSuchProviderException if there's no default provider.
0N/A * @exception SignatureException on signature errors.
0N/A * @exception CRLException on encoding errors.
0N/A */
0N/A public void verify(PublicKey key)
0N/A throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
0N/A NoSuchProviderException, SignatureException {
0N/A verify(key, "");
0N/A }
0N/A
0N/A /**
0N/A * Verifies that this CRL was signed using the
0N/A * private key that corresponds to the given public key,
0N/A * and that the signature verification was computed by
0N/A * the given provider.
0N/A *
0N/A * @param key the PublicKey used to carry out the verification.
0N/A * @param sigProvider the name of the signature provider.
0N/A *
0N/A * @exception NoSuchAlgorithmException on unsupported signature
0N/A * algorithms.
0N/A * @exception InvalidKeyException on incorrect key.
0N/A * @exception NoSuchProviderException on incorrect provider.
0N/A * @exception SignatureException on signature errors.
0N/A * @exception CRLException on encoding errors.
0N/A */
0N/A public synchronized void verify(PublicKey key, String sigProvider)
0N/A throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
0N/A NoSuchProviderException, SignatureException {
0N/A
0N/A if (sigProvider == null) {
0N/A sigProvider = "";
0N/A }
0N/A if ((verifiedPublicKey != null) && verifiedPublicKey.equals(key)) {
0N/A // this CRL has already been successfully verified using
0N/A // this public key. Make sure providers match, too.
0N/A if (sigProvider.equals(verifiedProvider)) {
0N/A return;
0N/A }
0N/A }
0N/A if (signedCRL == null) {
0N/A throw new CRLException("Uninitialized CRL");
0N/A }
0N/A Signature sigVerf = null;
0N/A if (sigProvider.length() == 0) {
0N/A sigVerf = Signature.getInstance(sigAlgId.getName());
0N/A } else {
0N/A sigVerf = Signature.getInstance(sigAlgId.getName(), sigProvider);
0N/A }
0N/A sigVerf.initVerify(key);
0N/A
0N/A if (tbsCertList == null) {
0N/A throw new CRLException("Uninitialized CRL");
0N/A }
0N/A
0N/A sigVerf.update(tbsCertList, 0, tbsCertList.length);
0N/A
0N/A if (!sigVerf.verify(signature)) {
0N/A throw new SignatureException("Signature does not match.");
0N/A }
0N/A verifiedPublicKey = key;
0N/A verifiedProvider = sigProvider;
0N/A }
0N/A
0N/A /**
0N/A * Encodes an X.509 CRL, and signs it using the given key.
0N/A *
0N/A * @param key the private key used for signing.
0N/A * @param algorithm the name of the signature algorithm used.
0N/A *
0N/A * @exception NoSuchAlgorithmException on unsupported signature
0N/A * algorithms.
0N/A * @exception InvalidKeyException on incorrect key.
0N/A * @exception NoSuchProviderException on incorrect provider.
0N/A * @exception SignatureException on signature errors.
0N/A * @exception CRLException if any mandatory data was omitted.
0N/A */
0N/A public void sign(PrivateKey key, String algorithm)
0N/A throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
0N/A NoSuchProviderException, SignatureException {
0N/A sign(key, algorithm, null);
0N/A }
0N/A
0N/A /**
0N/A * Encodes an X.509 CRL, and signs it using the given key.
0N/A *
0N/A * @param key the private key used for signing.
0N/A * @param algorithm the name of the signature algorithm used.
0N/A * @param provider the name of the provider.
0N/A *
0N/A * @exception NoSuchAlgorithmException on unsupported signature
0N/A * algorithms.
0N/A * @exception InvalidKeyException on incorrect key.
0N/A * @exception NoSuchProviderException on incorrect provider.
0N/A * @exception SignatureException on signature errors.
0N/A * @exception CRLException if any mandatory data was omitted.
0N/A */
0N/A public void sign(PrivateKey key, String algorithm, String provider)
0N/A throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
0N/A NoSuchProviderException, SignatureException {
0N/A try {
0N/A if (readOnly)
0N/A throw new CRLException("cannot over-write existing CRL");
0N/A Signature sigEngine = null;
0N/A if ((provider == null) || (provider.length() == 0))
0N/A sigEngine = Signature.getInstance(algorithm);
0N/A else
0N/A sigEngine = Signature.getInstance(algorithm, provider);
0N/A
0N/A sigEngine.initSign(key);
0N/A
0N/A // in case the name is reset
0N/A sigAlgId = AlgorithmId.get(sigEngine.getAlgorithm());
0N/A infoSigAlgId = sigAlgId;
0N/A
0N/A DerOutputStream out = new DerOutputStream();
0N/A DerOutputStream tmp = new DerOutputStream();
0N/A
0N/A // encode crl info
0N/A encodeInfo(tmp);
0N/A
0N/A // encode algorithm identifier
0N/A sigAlgId.encode(tmp);
0N/A
0N/A // Create and encode the signature itself.
0N/A sigEngine.update(tbsCertList, 0, tbsCertList.length);
0N/A signature = sigEngine.sign();
0N/A tmp.putBitString(signature);
0N/A
0N/A // Wrap the signed data in a SEQUENCE { data, algorithm, sig }
0N/A out.write(DerValue.tag_Sequence, tmp);
0N/A signedCRL = out.toByteArray();
0N/A readOnly = true;
0N/A
0N/A } catch (IOException e) {
0N/A throw new CRLException("Error while encoding data: " +
0N/A e.getMessage());
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returns a printable string of this CRL.
0N/A *
0N/A * @return value of this CRL in a printable form.
0N/A */
0N/A public String toString() {
0N/A StringBuffer sb = new StringBuffer();
0N/A sb.append("X.509 CRL v" + (version+1) + "\n");
0N/A if (sigAlgId != null)
0N/A sb.append("Signature Algorithm: " + sigAlgId.toString() +
0N/A ", OID=" + (sigAlgId.getOID()).toString() + "\n");
0N/A if (issuer != null)
0N/A sb.append("Issuer: " + issuer.toString() + "\n");
0N/A if (thisUpdate != null)
0N/A sb.append("\nThis Update: " + thisUpdate.toString() + "\n");
0N/A if (nextUpdate != null)
0N/A sb.append("Next Update: " + nextUpdate.toString() + "\n");
5090N/A if (revokedList.isEmpty())
0N/A sb.append("\nNO certificates have been revoked\n");
0N/A else {
5090N/A sb.append("\nRevoked Certificates: " + revokedList.size());
0N/A int i = 1;
5090N/A for (X509CRLEntry entry: revokedList) {
5090N/A sb.append("\n[" + i++ + "] " + entry.toString());
5090N/A }
0N/A }
0N/A if (extensions != null) {
0N/A Collection<Extension> allExts = extensions.getAllExtensions();
0N/A Object[] objs = allExts.toArray();
0N/A sb.append("\nCRL Extensions: " + objs.length);
0N/A for (int i = 0; i < objs.length; i++) {
0N/A sb.append("\n[" + (i+1) + "]: ");
0N/A Extension ext = (Extension)objs[i];
0N/A try {
0N/A if (OIDMap.getClass(ext.getExtensionId()) == null) {
0N/A sb.append(ext.toString());
0N/A byte[] extValue = ext.getExtensionValue();
0N/A if (extValue != null) {
0N/A DerOutputStream out = new DerOutputStream();
0N/A out.putOctetString(extValue);
0N/A extValue = out.toByteArray();
0N/A HexDumpEncoder enc = new HexDumpEncoder();
0N/A sb.append("Extension unknown: "
0N/A + "DER encoded OCTET string =\n"
0N/A + enc.encodeBuffer(extValue) + "\n");
0N/A }
0N/A } else
0N/A sb.append(ext.toString()); // sub-class exists
0N/A } catch (Exception e) {
0N/A sb.append(", Error parsing this extension");
0N/A }
0N/A }
0N/A }
0N/A if (signature != null) {
0N/A HexDumpEncoder encoder = new HexDumpEncoder();
0N/A sb.append("\nSignature:\n" + encoder.encodeBuffer(signature)
0N/A + "\n");
0N/A } else
0N/A sb.append("NOT signed yet\n");
0N/A return sb.toString();
0N/A }
0N/A
0N/A /**
0N/A * Checks whether the given certificate is on this CRL.
0N/A *
0N/A * @param cert the certificate to check for.
0N/A * @return true if the given certificate is on this CRL,
0N/A * false otherwise.
0N/A */
0N/A public boolean isRevoked(Certificate cert) {
5090N/A if (revokedMap.isEmpty() || (!(cert instanceof X509Certificate))) {
0N/A return false;
0N/A }
0N/A X509Certificate xcert = (X509Certificate) cert;
0N/A X509IssuerSerial issuerSerial = new X509IssuerSerial(xcert);
5090N/A return revokedMap.containsKey(issuerSerial);
0N/A }
0N/A
0N/A /**
0N/A * Gets the version number from this CRL.
0N/A * The ASN.1 definition for this is:
0N/A * <pre>
0N/A * Version ::= INTEGER { v1(0), v2(1), v3(2) }
0N/A * -- v3 does not apply to CRLs but appears for consistency
0N/A * -- with definition of Version for certs
0N/A * </pre>
0N/A * @return the version number, i.e. 1 or 2.
0N/A */
0N/A public int getVersion() {
0N/A return version+1;
0N/A }
0N/A
0N/A /**
0N/A * Gets the issuer distinguished name from this CRL.
0N/A * The issuer name identifies the entity who has signed (and
0N/A * issued the CRL). The issuer name field contains an
0N/A * X.500 distinguished name (DN).
0N/A * The ASN.1 definition for this is:
0N/A * <pre>
0N/A * issuer Name
0N/A *
0N/A * Name ::= CHOICE { RDNSequence }
0N/A * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
0N/A * RelativeDistinguishedName ::=
0N/A * SET OF AttributeValueAssertion
0N/A *
0N/A * AttributeValueAssertion ::= SEQUENCE {
0N/A * AttributeType,
0N/A * AttributeValue }
0N/A * AttributeType ::= OBJECT IDENTIFIER
0N/A * AttributeValue ::= ANY
0N/A * </pre>
0N/A * The Name describes a hierarchical name composed of attributes,
0N/A * such as country name, and corresponding values, such as US.
0N/A * The type of the component AttributeValue is determined by the
0N/A * AttributeType; in general it will be a directoryString.
0N/A * A directoryString is usually one of PrintableString,
0N/A * TeletexString or UniversalString.
0N/A * @return the issuer name.
0N/A */
0N/A public Principal getIssuerDN() {
0N/A return (Principal)issuer;
0N/A }
0N/A
0N/A /**
0N/A * Return the issuer as X500Principal. Overrides method in X509CRL
0N/A * to provide a slightly more efficient version.
0N/A */
0N/A public X500Principal getIssuerX500Principal() {
0N/A if (issuerPrincipal == null) {
0N/A issuerPrincipal = issuer.asX500Principal();
0N/A }
0N/A return issuerPrincipal;
0N/A }
0N/A
0N/A /**
0N/A * Gets the thisUpdate date from the CRL.
0N/A * The ASN.1 definition for this is:
0N/A *
0N/A * @return the thisUpdate date from the CRL.
0N/A */
0N/A public Date getThisUpdate() {
0N/A return (new Date(thisUpdate.getTime()));
0N/A }
0N/A
0N/A /**
0N/A * Gets the nextUpdate date from the CRL.
0N/A *
0N/A * @return the nextUpdate date from the CRL, or null if
0N/A * not present.
0N/A */
0N/A public Date getNextUpdate() {
0N/A if (nextUpdate == null)
0N/A return null;
0N/A return (new Date(nextUpdate.getTime()));
0N/A }
0N/A
0N/A /**
0N/A * Gets the CRL entry with the given serial number from this CRL.
0N/A *
0N/A * @return the entry with the given serial number, or <code>null</code> if
0N/A * no such entry exists in the CRL.
0N/A * @see X509CRLEntry
0N/A */
0N/A public X509CRLEntry getRevokedCertificate(BigInteger serialNumber) {
5090N/A if (revokedMap.isEmpty()) {
0N/A return null;
0N/A }
0N/A // assume this is a direct CRL entry (cert and CRL issuer are the same)
0N/A X509IssuerSerial issuerSerial = new X509IssuerSerial
0N/A (getIssuerX500Principal(), serialNumber);
5090N/A return revokedMap.get(issuerSerial);
0N/A }
0N/A
0N/A /**
0N/A * Gets the CRL entry for the given certificate.
0N/A */
0N/A public X509CRLEntry getRevokedCertificate(X509Certificate cert) {
5090N/A if (revokedMap.isEmpty()) {
0N/A return null;
0N/A }
0N/A X509IssuerSerial issuerSerial = new X509IssuerSerial(cert);
5090N/A return revokedMap.get(issuerSerial);
0N/A }
0N/A
0N/A /**
0N/A * Gets all the revoked certificates from the CRL.
0N/A * A Set of X509CRLEntry.
0N/A *
0N/A * @return all the revoked certificates or <code>null</code> if there are
0N/A * none.
0N/A * @see X509CRLEntry
0N/A */
0N/A public Set<X509CRLEntry> getRevokedCertificates() {
5090N/A if (revokedList.isEmpty()) {
0N/A return null;
0N/A } else {
5090N/A return new TreeSet<X509CRLEntry>(revokedList);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Gets the DER encoded CRL information, the
0N/A * <code>tbsCertList</code> from this CRL.
0N/A * This can be used to verify the signature independently.
0N/A *
0N/A * @return the DER encoded CRL information.
0N/A * @exception CRLException on encoding errors.
0N/A */
0N/A public byte[] getTBSCertList() throws CRLException {
0N/A if (tbsCertList == null)
0N/A throw new CRLException("Uninitialized CRL");
0N/A byte[] dup = new byte[tbsCertList.length];
0N/A System.arraycopy(tbsCertList, 0, dup, 0, dup.length);
0N/A return dup;
0N/A }
0N/A
0N/A /**
0N/A * Gets the raw Signature bits from the CRL.
0N/A *
0N/A * @return the signature.
0N/A */
0N/A public byte[] getSignature() {
0N/A if (signature == null)
0N/A return null;
0N/A byte[] dup = new byte[signature.length];
0N/A System.arraycopy(signature, 0, dup, 0, dup.length);
0N/A return dup;
0N/A }
0N/A
0N/A /**
0N/A * Gets the signature algorithm name for the CRL
0N/A * signature algorithm. For example, the string "SHA1withDSA".
0N/A * The ASN.1 definition for this is:
0N/A * <pre>
0N/A * AlgorithmIdentifier ::= SEQUENCE {
0N/A * algorithm OBJECT IDENTIFIER,
0N/A * parameters ANY DEFINED BY algorithm OPTIONAL }
0N/A * -- contains a value of the type
0N/A * -- registered for use with the
0N/A * -- algorithm object identifier value
0N/A * </pre>
0N/A *
0N/A * @return the signature algorithm name.
0N/A */
0N/A public String getSigAlgName() {
0N/A if (sigAlgId == null)
0N/A return null;
0N/A return sigAlgId.getName();
0N/A }
0N/A
0N/A /**
0N/A * Gets the signature algorithm OID string from the CRL.
0N/A * An OID is represented by a set of positive whole number separated
0N/A * by ".", that means,<br>
0N/A * &lt;positive whole number&gt;.&lt;positive whole number&gt;.&lt;...&gt;
0N/A * For example, the string "1.2.840.10040.4.3" identifies the SHA-1
0N/A * with DSA signature algorithm defined in
0N/A * <a href="http://www.ietf.org/rfc/rfc3279.txt">RFC 3279: Algorithms and
0N/A * Identifiers for the Internet X.509 Public Key Infrastructure Certificate
0N/A * and CRL Profile</a>.
0N/A *
0N/A * @return the signature algorithm oid string.
0N/A */
0N/A public String getSigAlgOID() {
0N/A if (sigAlgId == null)
0N/A return null;
0N/A ObjectIdentifier oid = sigAlgId.getOID();
0N/A return oid.toString();
0N/A }
0N/A
0N/A /**
0N/A * Gets the DER encoded signature algorithm parameters from this
0N/A * CRL's signature algorithm. In most cases, the signature
0N/A * algorithm parameters are null, the parameters are usually
0N/A * supplied with the Public Key.
0N/A *
0N/A * @return the DER encoded signature algorithm parameters, or
0N/A * null if no parameters are present.
0N/A */
0N/A public byte[] getSigAlgParams() {
0N/A if (sigAlgId == null)
0N/A return null;
0N/A try {
0N/A return sigAlgId.getEncodedParams();
0N/A } catch (IOException e) {
0N/A return null;
0N/A }
0N/A }
0N/A
0N/A /**
2999N/A * Gets the signature AlgorithmId from the CRL.
2999N/A *
2999N/A * @return the signature AlgorithmId
2999N/A */
2999N/A public AlgorithmId getSigAlgId() {
2999N/A return sigAlgId;
2999N/A }
2999N/A
2999N/A /**
0N/A * return the AuthorityKeyIdentifier, if any.
0N/A *
0N/A * @returns AuthorityKeyIdentifier or null
0N/A * (if no AuthorityKeyIdentifierExtension)
0N/A * @throws IOException on error
0N/A */
0N/A public KeyIdentifier getAuthKeyId() throws IOException {
0N/A AuthorityKeyIdentifierExtension aki = getAuthKeyIdExtension();
0N/A if (aki != null) {
0N/A KeyIdentifier keyId = (KeyIdentifier)aki.get(aki.KEY_ID);
0N/A return keyId;
0N/A } else {
0N/A return null;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * return the AuthorityKeyIdentifierExtension, if any.
0N/A *
0N/A * @returns AuthorityKeyIdentifierExtension or null (if no such extension)
0N/A * @throws IOException on error
0N/A */
0N/A public AuthorityKeyIdentifierExtension getAuthKeyIdExtension()
0N/A throws IOException {
0N/A Object obj = getExtension(PKIXExtensions.AuthorityKey_Id);
0N/A return (AuthorityKeyIdentifierExtension)obj;
0N/A }
0N/A
0N/A /**
0N/A * return the CRLNumberExtension, if any.
0N/A *
0N/A * @returns CRLNumberExtension or null (if no such extension)
0N/A * @throws IOException on error
0N/A */
0N/A public CRLNumberExtension getCRLNumberExtension() throws IOException {
0N/A Object obj = getExtension(PKIXExtensions.CRLNumber_Id);
0N/A return (CRLNumberExtension)obj;
0N/A }
0N/A
0N/A /**
0N/A * return the CRL number from the CRLNumberExtension, if any.
0N/A *
0N/A * @returns number or null (if no such extension)
0N/A * @throws IOException on error
0N/A */
0N/A public BigInteger getCRLNumber() throws IOException {
0N/A CRLNumberExtension numExt = getCRLNumberExtension();
0N/A if (numExt != null) {
0N/A BigInteger num = (BigInteger)numExt.get(numExt.NUMBER);
0N/A return num;
0N/A } else {
0N/A return null;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * return the DeltaCRLIndicatorExtension, if any.
0N/A *
0N/A * @returns DeltaCRLIndicatorExtension or null (if no such extension)
0N/A * @throws IOException on error
0N/A */
0N/A public DeltaCRLIndicatorExtension getDeltaCRLIndicatorExtension()
0N/A throws IOException {
0N/A
0N/A Object obj = getExtension(PKIXExtensions.DeltaCRLIndicator_Id);
0N/A return (DeltaCRLIndicatorExtension)obj;
0N/A }
0N/A
0N/A /**
0N/A * return the base CRL number from the DeltaCRLIndicatorExtension, if any.
0N/A *
0N/A * @returns number or null (if no such extension)
0N/A * @throws IOException on error
0N/A */
0N/A public BigInteger getBaseCRLNumber() throws IOException {
0N/A DeltaCRLIndicatorExtension dciExt = getDeltaCRLIndicatorExtension();
0N/A if (dciExt != null) {
0N/A BigInteger num = (BigInteger)dciExt.get(dciExt.NUMBER);
0N/A return num;
0N/A } else {
0N/A return null;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * return the IssuerAlternativeNameExtension, if any.
0N/A *
0N/A * @returns IssuerAlternativeNameExtension or null (if no such extension)
0N/A * @throws IOException on error
0N/A */
0N/A public IssuerAlternativeNameExtension getIssuerAltNameExtension()
0N/A throws IOException {
0N/A Object obj = getExtension(PKIXExtensions.IssuerAlternativeName_Id);
0N/A return (IssuerAlternativeNameExtension)obj;
0N/A }
0N/A
0N/A /**
0N/A * return the IssuingDistributionPointExtension, if any.
0N/A *
0N/A * @returns IssuingDistributionPointExtension or null
0N/A * (if no such extension)
0N/A * @throws IOException on error
0N/A */
0N/A public IssuingDistributionPointExtension
0N/A getIssuingDistributionPointExtension() throws IOException {
0N/A
0N/A Object obj = getExtension(PKIXExtensions.IssuingDistributionPoint_Id);
0N/A return (IssuingDistributionPointExtension) obj;
0N/A }
0N/A
0N/A /**
0N/A * Return true if a critical extension is found that is
0N/A * not supported, otherwise return false.
0N/A */
0N/A public boolean hasUnsupportedCriticalExtension() {
0N/A if (extensions == null)
0N/A return false;
0N/A return extensions.hasUnsupportedCriticalExtension();
0N/A }
0N/A
0N/A /**
0N/A * Gets a Set of the extension(s) marked CRITICAL in the
0N/A * CRL. In the returned set, each extension is represented by
0N/A * its OID string.
0N/A *
0N/A * @return a set of the extension oid strings in the
0N/A * CRL that are marked critical.
0N/A */
0N/A public Set<String> getCriticalExtensionOIDs() {
0N/A if (extensions == null) {
0N/A return null;
0N/A }
5090N/A Set<String> extSet = new TreeSet<>();
0N/A for (Extension ex : extensions.getAllExtensions()) {
0N/A if (ex.isCritical()) {
0N/A extSet.add(ex.getExtensionId().toString());
0N/A }
0N/A }
0N/A return extSet;
0N/A }
0N/A
0N/A /**
0N/A * Gets a Set of the extension(s) marked NON-CRITICAL in the
0N/A * CRL. In the returned set, each extension is represented by
0N/A * its OID string.
0N/A *
0N/A * @return a set of the extension oid strings in the
0N/A * CRL that are NOT marked critical.
0N/A */
0N/A public Set<String> getNonCriticalExtensionOIDs() {
0N/A if (extensions == null) {
0N/A return null;
0N/A }
5090N/A Set<String> extSet = new TreeSet<>();
0N/A for (Extension ex : extensions.getAllExtensions()) {
0N/A if (!ex.isCritical()) {
0N/A extSet.add(ex.getExtensionId().toString());
0N/A }
0N/A }
0N/A return extSet;
0N/A }
0N/A
0N/A /**
0N/A * Gets the DER encoded OCTET string for the extension value
0N/A * (<code>extnValue</code>) identified by the passed in oid String.
0N/A * The <code>oid</code> string is
0N/A * represented by a set of positive whole number separated
0N/A * by ".", that means,<br>
0N/A * &lt;positive whole number&gt;.&lt;positive whole number&gt;.&lt;...&gt;
0N/A *
0N/A * @param oid the Object Identifier value for the extension.
0N/A * @return the der encoded octet string of the extension value.
0N/A */
0N/A public byte[] getExtensionValue(String oid) {
0N/A if (extensions == null)
0N/A return null;
0N/A try {
0N/A String extAlias = OIDMap.getName(new ObjectIdentifier(oid));
0N/A Extension crlExt = null;
0N/A
0N/A if (extAlias == null) { // may be unknown
0N/A ObjectIdentifier findOID = new ObjectIdentifier(oid);
0N/A Extension ex = null;
0N/A ObjectIdentifier inCertOID;
0N/A for (Enumeration<Extension> e = extensions.getElements();
0N/A e.hasMoreElements();) {
0N/A ex = e.nextElement();
0N/A inCertOID = ex.getExtensionId();
0N/A if (inCertOID.equals(findOID)) {
0N/A crlExt = ex;
0N/A break;
0N/A }
0N/A }
0N/A } else
0N/A crlExt = extensions.get(extAlias);
0N/A if (crlExt == null)
0N/A return null;
0N/A byte[] extData = crlExt.getExtensionValue();
0N/A if (extData == null)
0N/A return null;
0N/A DerOutputStream out = new DerOutputStream();
0N/A out.putOctetString(extData);
0N/A return out.toByteArray();
0N/A } catch (Exception e) {
0N/A return null;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * get an extension
0N/A *
0N/A * @param oid ObjectIdentifier of extension desired
0N/A * @returns Object of type <extension> or null, if not found
0N/A * @throws IOException on error
0N/A */
0N/A public Object getExtension(ObjectIdentifier oid) {
0N/A if (extensions == null)
0N/A return null;
0N/A
0N/A // XXX Consider cloning this
0N/A return extensions.get(OIDMap.getName(oid));
0N/A }
0N/A
0N/A /*
0N/A * Parses an X.509 CRL, should be used only by constructors.
0N/A */
0N/A private void parse(DerValue val) throws CRLException, IOException {
0N/A // check if can over write the certificate
0N/A if (readOnly)
0N/A throw new CRLException("cannot over-write existing CRL");
0N/A
0N/A if ( val.getData() == null || val.tag != DerValue.tag_Sequence)
0N/A throw new CRLException("Invalid DER-encoded CRL data");
0N/A
0N/A signedCRL = val.toByteArray();
0N/A DerValue seq[] = new DerValue[3];
0N/A
0N/A seq[0] = val.data.getDerValue();
0N/A seq[1] = val.data.getDerValue();
0N/A seq[2] = val.data.getDerValue();
0N/A
0N/A if (val.data.available() != 0)
0N/A throw new CRLException("signed overrun, bytes = "
0N/A + val.data.available());
0N/A
0N/A if (seq[0].tag != DerValue.tag_Sequence)
0N/A throw new CRLException("signed CRL fields invalid");
0N/A
0N/A sigAlgId = AlgorithmId.parse(seq[1]);
0N/A signature = seq[2].getBitString();
0N/A
0N/A if (seq[1].data.available() != 0)
0N/A throw new CRLException("AlgorithmId field overrun");
0N/A
0N/A if (seq[2].data.available() != 0)
0N/A throw new CRLException("Signature field overrun");
0N/A
0N/A // the tbsCertsList
0N/A tbsCertList = seq[0].toByteArray();
0N/A
0N/A // parse the information
0N/A DerInputStream derStrm = seq[0].data;
0N/A DerValue tmp;
0N/A byte nextByte;
0N/A
0N/A // version (optional if v1)
0N/A version = 0; // by default, version = v1 == 0
0N/A nextByte = (byte)derStrm.peekByte();
0N/A if (nextByte == DerValue.tag_Integer) {
0N/A version = derStrm.getInteger();
0N/A if (version != 1) // i.e. v2
0N/A throw new CRLException("Invalid version");
0N/A }
0N/A tmp = derStrm.getDerValue();
0N/A
0N/A // signature
0N/A AlgorithmId tmpId = AlgorithmId.parse(tmp);
0N/A
0N/A // the "inner" and "outer" signature algorithms must match
0N/A if (! tmpId.equals(sigAlgId))
0N/A throw new CRLException("Signature algorithm mismatch");
0N/A infoSigAlgId = tmpId;
0N/A
0N/A // issuer
0N/A issuer = new X500Name(derStrm);
0N/A if (issuer.isEmpty()) {
0N/A throw new CRLException("Empty issuer DN not allowed in X509CRLs");
0N/A }
0N/A
0N/A // thisUpdate
0N/A // check if UTCTime encoded or GeneralizedTime
0N/A
0N/A nextByte = (byte)derStrm.peekByte();
0N/A if (nextByte == DerValue.tag_UtcTime) {
0N/A thisUpdate = derStrm.getUTCTime();
0N/A } else if (nextByte == DerValue.tag_GeneralizedTime) {
0N/A thisUpdate = derStrm.getGeneralizedTime();
0N/A } else {
0N/A throw new CRLException("Invalid encoding for thisUpdate"
0N/A + " (tag=" + nextByte + ")");
0N/A }
0N/A
0N/A if (derStrm.available() == 0)
0N/A return; // done parsing no more optional fields present
0N/A
0N/A // nextUpdate (optional)
0N/A nextByte = (byte)derStrm.peekByte();
0N/A if (nextByte == DerValue.tag_UtcTime) {
0N/A nextUpdate = derStrm.getUTCTime();
0N/A } else if (nextByte == DerValue.tag_GeneralizedTime) {
0N/A nextUpdate = derStrm.getGeneralizedTime();
0N/A } // else it is not present
0N/A
0N/A if (derStrm.available() == 0)
0N/A return; // done parsing no more optional fields present
0N/A
0N/A // revokedCertificates (optional)
0N/A nextByte = (byte)derStrm.peekByte();
0N/A if ((nextByte == DerValue.tag_SequenceOf)
0N/A && (! ((nextByte & 0x0c0) == 0x080))) {
0N/A DerValue[] badCerts = derStrm.getSequence(4);
0N/A
0N/A X500Principal crlIssuer = getIssuerX500Principal();
0N/A X500Principal badCertIssuer = crlIssuer;
0N/A for (int i = 0; i < badCerts.length; i++) {
0N/A X509CRLEntryImpl entry = new X509CRLEntryImpl(badCerts[i]);
0N/A badCertIssuer = getCertIssuer(entry, badCertIssuer);
0N/A entry.setCertificateIssuer(crlIssuer, badCertIssuer);
0N/A X509IssuerSerial issuerSerial = new X509IssuerSerial
0N/A (badCertIssuer, entry.getSerialNumber());
5090N/A revokedMap.put(issuerSerial, entry);
5090N/A revokedList.add(entry);
0N/A }
0N/A }
0N/A
0N/A if (derStrm.available() == 0)
0N/A return; // done parsing no extensions
0N/A
0N/A // crlExtensions (optional)
0N/A tmp = derStrm.getDerValue();
0N/A if (tmp.isConstructed() && tmp.isContextSpecific((byte)0)) {
0N/A extensions = new CRLExtensions(tmp.data);
0N/A }
0N/A readOnly = true;
0N/A }
0N/A
0N/A /**
0N/A * Extract the issuer X500Principal from an X509CRL. Parses the encoded
0N/A * form of the CRL to preserve the principal's ASN.1 encoding.
0N/A *
0N/A * Called by java.security.cert.X509CRL.getIssuerX500Principal().
0N/A */
0N/A public static X500Principal getIssuerX500Principal(X509CRL crl) {
0N/A try {
0N/A byte[] encoded = crl.getEncoded();
0N/A DerInputStream derIn = new DerInputStream(encoded);
0N/A DerValue tbsCert = derIn.getSequence(3)[0];
0N/A DerInputStream tbsIn = tbsCert.data;
0N/A
0N/A DerValue tmp;
0N/A // skip version number if present
0N/A byte nextByte = (byte)tbsIn.peekByte();
0N/A if (nextByte == DerValue.tag_Integer) {
0N/A tmp = tbsIn.getDerValue();
0N/A }
0N/A
0N/A tmp = tbsIn.getDerValue(); // skip signature
0N/A tmp = tbsIn.getDerValue(); // issuer
0N/A byte[] principalBytes = tmp.toByteArray();
0N/A return new X500Principal(principalBytes);
0N/A } catch (Exception e) {
0N/A throw new RuntimeException("Could not parse issuer", e);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returned the encoding of the given certificate for internal use.
0N/A * Callers must guarantee that they neither modify it nor expose it
0N/A * to untrusted code. Uses getEncodedInternal() if the certificate
0N/A * is instance of X509CertImpl, getEncoded() otherwise.
0N/A */
0N/A public static byte[] getEncodedInternal(X509CRL crl) throws CRLException {
0N/A if (crl instanceof X509CRLImpl) {
0N/A return ((X509CRLImpl)crl).getEncodedInternal();
0N/A } else {
0N/A return crl.getEncoded();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Utility method to convert an arbitrary instance of X509CRL
0N/A * to a X509CRLImpl. Does a cast if possible, otherwise reparses
0N/A * the encoding.
0N/A */
0N/A public static X509CRLImpl toImpl(X509CRL crl)
0N/A throws CRLException {
0N/A if (crl instanceof X509CRLImpl) {
0N/A return (X509CRLImpl)crl;
0N/A } else {
0N/A return X509Factory.intern(crl);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returns the X500 certificate issuer DN of a CRL entry.
0N/A *
0N/A * @param entry the entry to check
0N/A * @param prevCertIssuer the previous entry's certificate issuer
0N/A * @return the X500Principal in a CertificateIssuerExtension, or
0N/A * prevCertIssuer if it does not exist
0N/A */
0N/A private X500Principal getCertIssuer(X509CRLEntryImpl entry,
0N/A X500Principal prevCertIssuer) throws IOException {
0N/A
0N/A CertificateIssuerExtension ciExt =
0N/A entry.getCertificateIssuerExtension();
0N/A if (ciExt != null) {
0N/A GeneralNames names = (GeneralNames)
0N/A ciExt.get(CertificateIssuerExtension.ISSUER);
0N/A X500Name issuerDN = (X500Name) names.get(0).getName();
0N/A return issuerDN.asX500Principal();
0N/A } else {
0N/A return prevCertIssuer;
0N/A }
0N/A }
0N/A
2346N/A @Override
2346N/A public void derEncode(OutputStream out) throws IOException {
2346N/A if (signedCRL == null)
2346N/A throw new IOException("Null CRL to encode");
2346N/A out.write(signedCRL.clone());
2346N/A }
2346N/A
0N/A /**
0N/A * Immutable X.509 Certificate Issuer DN and serial number pair
0N/A */
5090N/A private final static class X509IssuerSerial
5090N/A implements Comparable<X509IssuerSerial> {
0N/A final X500Principal issuer;
0N/A final BigInteger serial;
0N/A volatile int hashcode = 0;
0N/A
0N/A /**
0N/A * Create an X509IssuerSerial.
0N/A *
0N/A * @param issuer the issuer DN
0N/A * @param serial the serial number
0N/A */
0N/A X509IssuerSerial(X500Principal issuer, BigInteger serial) {
0N/A this.issuer = issuer;
0N/A this.serial = serial;
0N/A }
0N/A
0N/A /**
0N/A * Construct an X509IssuerSerial from an X509Certificate.
0N/A */
0N/A X509IssuerSerial(X509Certificate cert) {
0N/A this(cert.getIssuerX500Principal(), cert.getSerialNumber());
0N/A }
0N/A
0N/A /**
0N/A * Returns the issuer.
0N/A *
0N/A * @return the issuer
0N/A */
0N/A X500Principal getIssuer() {
0N/A return issuer;
0N/A }
0N/A
0N/A /**
0N/A * Returns the serial number.
0N/A *
0N/A * @return the serial number
0N/A */
0N/A BigInteger getSerial() {
0N/A return serial;
0N/A }
0N/A
0N/A /**
0N/A * Compares this X509Serial with another and returns true if they
0N/A * are equivalent.
0N/A *
0N/A * @param o the other object to compare with
0N/A * @return true if equal, false otherwise
0N/A */
0N/A public boolean equals(Object o) {
0N/A if (o == this) {
0N/A return true;
0N/A }
0N/A
0N/A if (!(o instanceof X509IssuerSerial)) {
0N/A return false;
0N/A }
0N/A
0N/A X509IssuerSerial other = (X509IssuerSerial) o;
0N/A if (serial.equals(other.getSerial()) &&
0N/A issuer.equals(other.getIssuer())) {
0N/A return true;
0N/A }
0N/A return false;
0N/A }
0N/A
0N/A /**
0N/A * Returns a hash code value for this X509IssuerSerial.
0N/A *
0N/A * @return the hash code value
0N/A */
0N/A public int hashCode() {
0N/A if (hashcode == 0) {
0N/A int result = 17;
0N/A result = 37*result + issuer.hashCode();
0N/A result = 37*result + serial.hashCode();
0N/A hashcode = result;
0N/A }
0N/A return hashcode;
0N/A }
5090N/A
5090N/A @Override
5090N/A public int compareTo(X509IssuerSerial another) {
5090N/A int cissuer = issuer.toString()
5090N/A .compareTo(another.issuer.toString());
5090N/A if (cissuer != 0) return cissuer;
5090N/A return this.serial.compareTo(another.serial);
5090N/A }
0N/A }
0N/A}