0N/A/*
2362N/A * Copyright (c) 1997, 2006, 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.IOException;
0N/Aimport java.security.cert.CRLException;
0N/Aimport java.security.cert.CRLReason;
0N/Aimport java.security.cert.CertificateException;
0N/Aimport java.security.cert.X509CRLEntry;
0N/Aimport java.math.BigInteger;
5090N/Aimport java.util.*;
0N/A
0N/Aimport javax.security.auth.x500.X500Principal;
0N/A
0N/Aimport sun.security.util.*;
0N/Aimport sun.misc.HexDumpEncoder;
0N/A
0N/A/**
0N/A * <p>Abstract class for a revoked certificate in a CRL.
0N/A * This class is for each entry in the <code>revokedCertificates</code>,
0N/A * so it deals with the inner <em>SEQUENCE</em>.
0N/A * The ASN.1 definition for this is:
0N/A * <pre>
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 *
0N/A * CertificateSerialNumber ::= INTEGER
0N/A *
0N/A * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
0N/A *
0N/A * Extension ::= SEQUENCE {
0N/A * extnId OBJECT IDENTIFIER,
0N/A * critical BOOLEAN DEFAULT FALSE,
0N/A * extnValue OCTET STRING
0N/A * -- contains a DER encoding of a value
0N/A * -- of the type registered for use with
0N/A * -- the extnId object identifier value
0N/A * }
0N/A * </pre>
0N/A *
0N/A * @author Hemma Prafullchandra
0N/A */
0N/A
5090N/Apublic class X509CRLEntryImpl extends X509CRLEntry
5090N/A implements Comparable<X509CRLEntryImpl> {
0N/A
0N/A private SerialNumber serialNumber = null;
0N/A private Date revocationDate = null;
0N/A private CRLExtensions extensions = null;
0N/A private byte[] revokedCert = null;
0N/A private X500Principal certIssuer;
0N/A
0N/A private final static boolean isExplicit = false;
0N/A private static final long YR_2050 = 2524636800000L;
0N/A
0N/A /**
0N/A * Constructs a revoked certificate entry using the given
0N/A * serial number and revocation date.
0N/A *
0N/A * @param num the serial number of the revoked certificate.
0N/A * @param date the Date on which revocation took place.
0N/A */
0N/A public X509CRLEntryImpl(BigInteger num, Date date) {
0N/A this.serialNumber = new SerialNumber(num);
0N/A this.revocationDate = date;
0N/A }
0N/A
0N/A /**
0N/A * Constructs a revoked certificate entry using the given
0N/A * serial number, revocation date and the entry
0N/A * extensions.
0N/A *
0N/A * @param num the serial number of the revoked certificate.
0N/A * @param date the Date on which revocation took place.
0N/A * @param crlEntryExts the extensions for this entry.
0N/A */
0N/A public X509CRLEntryImpl(BigInteger num, Date date,
0N/A CRLExtensions crlEntryExts) {
0N/A this.serialNumber = new SerialNumber(num);
0N/A this.revocationDate = date;
0N/A this.extensions = crlEntryExts;
0N/A }
0N/A
0N/A /**
0N/A * Unmarshals a revoked certificate from its encoded form.
0N/A *
0N/A * @param revokedCert the encoded bytes.
0N/A * @exception CRLException on parsing errors.
0N/A */
0N/A public X509CRLEntryImpl(byte[] revokedCert) throws CRLException {
0N/A try {
0N/A parse(new DerValue(revokedCert));
0N/A } catch (IOException e) {
0N/A this.revokedCert = null;
0N/A throw new CRLException("Parsing error: " + e.toString());
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Unmarshals a revoked certificate from its encoded form.
0N/A *
0N/A * @param derVal the DER value containing the revoked certificate.
0N/A * @exception CRLException on parsing errors.
0N/A */
0N/A public X509CRLEntryImpl(DerValue derValue) throws CRLException {
0N/A try {
0N/A parse(derValue);
0N/A } catch (IOException e) {
0N/A revokedCert = null;
0N/A throw new CRLException("Parsing error: " + e.toString());
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returns true if this revoked certificate entry has
0N/A * extensions, otherwise false.
0N/A *
0N/A * @return true if this CRL entry has extensions, otherwise
0N/A * false.
0N/A */
0N/A public boolean hasExtensions() {
0N/A return (extensions != null);
0N/A }
0N/A
0N/A /**
0N/A * Encodes the revoked certificate to an output stream.
0N/A *
0N/A * @param outStrm an output stream to which the encoded revoked
0N/A * certificate is written.
0N/A * @exception CRLException on encoding errors.
0N/A */
0N/A public void encode(DerOutputStream outStrm) throws CRLException {
0N/A try {
0N/A if (revokedCert == null) {
0N/A DerOutputStream tmp = new DerOutputStream();
0N/A // sequence { serialNumber, revocationDate, extensions }
0N/A serialNumber.encode(tmp);
0N/A
0N/A if (revocationDate.getTime() < YR_2050) {
0N/A tmp.putUTCTime(revocationDate);
0N/A } else {
0N/A tmp.putGeneralizedTime(revocationDate);
0N/A }
0N/A
0N/A if (extensions != null)
0N/A extensions.encode(tmp, isExplicit);
0N/A
0N/A DerOutputStream seq = new DerOutputStream();
0N/A seq.write(DerValue.tag_Sequence, tmp);
0N/A
0N/A revokedCert = seq.toByteArray();
0N/A }
0N/A outStrm.write(revokedCert);
0N/A } catch (IOException e) {
0N/A throw new CRLException("Encoding error: " + e.toString());
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returns the ASN.1 DER-encoded form of this CRL Entry,
0N/A * which corresponds to the inner SEQUENCE.
0N/A *
0N/A * @exception CRLException if an encoding error occurs.
0N/A */
0N/A public byte[] getEncoded() throws CRLException {
5090N/A return getEncoded0().clone();
5090N/A }
5090N/A
5090N/A // Called internally to avoid clone
5090N/A private byte[] getEncoded0() throws CRLException {
0N/A if (revokedCert == null)
0N/A this.encode(new DerOutputStream());
5090N/A return revokedCert;
0N/A }
0N/A
0N/A @Override
0N/A public X500Principal getCertificateIssuer() {
0N/A return certIssuer;
0N/A }
0N/A
0N/A void setCertificateIssuer(X500Principal crlIssuer, X500Principal certIssuer) {
0N/A if (crlIssuer.equals(certIssuer)) {
0N/A this.certIssuer = null;
0N/A } else {
0N/A this.certIssuer = certIssuer;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Gets the serial number from this X509CRLEntry,
0N/A * i.e. the <em>userCertificate</em>.
0N/A *
0N/A * @return the serial number.
0N/A */
0N/A public BigInteger getSerialNumber() {
0N/A return serialNumber.getNumber();
0N/A }
0N/A
0N/A /**
0N/A * Gets the revocation date from this X509CRLEntry,
0N/A * the <em>revocationDate</em>.
0N/A *
0N/A * @return the revocation date.
0N/A */
0N/A public Date getRevocationDate() {
0N/A return new Date(revocationDate.getTime());
0N/A }
0N/A
0N/A /**
0N/A * This method is the overridden implementation of the getRevocationReason
0N/A * method in X509CRLEntry. It is better performance-wise since it returns
0N/A * cached values.
0N/A */
0N/A @Override
0N/A public CRLReason getRevocationReason() {
0N/A Extension ext = getExtension(PKIXExtensions.ReasonCode_Id);
0N/A if (ext == null) {
0N/A return null;
0N/A }
0N/A CRLReasonCodeExtension rcExt = (CRLReasonCodeExtension) ext;
0N/A return rcExt.getReasonCode();
0N/A }
0N/A
0N/A /**
0N/A * This static method is the default implementation of the
0N/A * getRevocationReason method in X509CRLEntry.
0N/A */
0N/A public static CRLReason getRevocationReason(X509CRLEntry crlEntry) {
0N/A try {
0N/A byte[] ext = crlEntry.getExtensionValue("2.5.29.21");
0N/A if (ext == null) {
0N/A return null;
0N/A }
0N/A DerValue val = new DerValue(ext);
0N/A byte[] data = val.getOctetString();
0N/A
0N/A CRLReasonCodeExtension rcExt =
0N/A new CRLReasonCodeExtension(Boolean.FALSE, data);
0N/A return rcExt.getReasonCode();
0N/A } catch (IOException ioe) {
0N/A return null;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * get Reason Code from CRL entry.
0N/A *
0N/A * @returns Integer or null, if no such extension
0N/A * @throws IOException on error
0N/A */
0N/A public Integer getReasonCode() throws IOException {
0N/A Object obj = getExtension(PKIXExtensions.ReasonCode_Id);
0N/A if (obj == null)
0N/A return null;
0N/A CRLReasonCodeExtension reasonCode = (CRLReasonCodeExtension)obj;
0N/A return (Integer)(reasonCode.get(reasonCode.REASON));
0N/A }
0N/A
0N/A /**
0N/A * Returns a printable string of this revoked certificate.
0N/A *
0N/A * @return value of this revoked certificate in a printable form.
0N/A */
0N/A @Override
0N/A public String toString() {
0N/A StringBuilder sb = new StringBuilder();
0N/A
0N/A sb.append(serialNumber.toString());
0N/A sb.append(" On: " + revocationDate.toString());
0N/A if (certIssuer != null) {
0N/A sb.append("\n Certificate issuer: " + certIssuer);
0N/A }
0N/A if (extensions != null) {
0N/A Collection allEntryExts = extensions.getAllExtensions();
0N/A Object[] objs = allEntryExts.toArray();
0N/A
0N/A sb.append("\n CRL Entry 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 sb.append("\n");
0N/A return sb.toString();
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 this
0N/A * X509CRLEntry. In the returned set, each extension is
0N/A * represented by its OID string.
0N/A *
0N/A * @return a set of the extension oid strings in the
0N/A * Object 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 this
0N/A * X509CRLEntry. In the returned set, each extension is
0N/A * represented by its OID string.
0N/A *
0N/A * @return a set of the extension oid strings in the
0N/A * Object that are 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 * (<em>extnValue</em>) 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;positive
0N/A * 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
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 Extension of type <extension> or null, if not found
0N/A */
0N/A public Extension getExtension(ObjectIdentifier oid) {
0N/A if (extensions == null)
0N/A return null;
0N/A
0N/A // following returns null if no such OID in map
0N/A //XXX consider cloning this
0N/A return extensions.get(OIDMap.getName(oid));
0N/A }
0N/A
0N/A private void parse(DerValue derVal)
0N/A throws CRLException, IOException {
0N/A
0N/A if (derVal.tag != DerValue.tag_Sequence) {
0N/A throw new CRLException("Invalid encoded RevokedCertificate, " +
0N/A "starting sequence tag missing.");
0N/A }
0N/A if (derVal.data.available() == 0)
0N/A throw new CRLException("No data encoded for RevokedCertificates");
0N/A
0N/A revokedCert = derVal.toByteArray();
0N/A // serial number
0N/A DerInputStream in = derVal.toDerInputStream();
0N/A DerValue val = in.getDerValue();
0N/A this.serialNumber = new SerialNumber(val);
0N/A
0N/A // revocationDate
0N/A int nextByte = derVal.data.peekByte();
0N/A if ((byte)nextByte == DerValue.tag_UtcTime) {
0N/A this.revocationDate = derVal.data.getUTCTime();
0N/A } else if ((byte)nextByte == DerValue.tag_GeneralizedTime) {
0N/A this.revocationDate = derVal.data.getGeneralizedTime();
0N/A } else
0N/A throw new CRLException("Invalid encoding for revocation date");
0N/A
0N/A if (derVal.data.available() == 0)
0N/A return; // no extensions
0N/A
0N/A // crlEntryExtensions
0N/A this.extensions = new CRLExtensions(derVal.toDerInputStream());
0N/A }
0N/A
0N/A /**
0N/A * Utility method to convert an arbitrary instance of X509CRLEntry
0N/A * to a X509CRLEntryImpl. Does a cast if possible, otherwise reparses
0N/A * the encoding.
0N/A */
0N/A public static X509CRLEntryImpl toImpl(X509CRLEntry entry)
0N/A throws CRLException {
0N/A if (entry instanceof X509CRLEntryImpl) {
0N/A return (X509CRLEntryImpl)entry;
0N/A } else {
0N/A return new X509CRLEntryImpl(entry.getEncoded());
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returns the CertificateIssuerExtension
0N/A *
0N/A * @return the CertificateIssuerExtension, or null if it does not exist
0N/A */
0N/A CertificateIssuerExtension getCertificateIssuerExtension() {
0N/A return (CertificateIssuerExtension)
0N/A getExtension(PKIXExtensions.CertificateIssuer_Id);
0N/A }
0N/A
5090N/A /**
5090N/A * Returns all extensions for this entry in a map
5090N/A * @return the extension map, can be empty, but not null
5090N/A */
0N/A public Map<String, java.security.cert.Extension> getExtensions() {
5090N/A if (extensions == null) {
5090N/A return Collections.emptyMap();
5090N/A }
0N/A Collection<Extension> exts = extensions.getAllExtensions();
5090N/A Map<String, java.security.cert.Extension> map = new TreeMap<>();
0N/A for (Extension ext : exts) {
0N/A map.put(ext.getId(), ext);
0N/A }
0N/A return map;
0N/A }
5090N/A
5090N/A @Override
5090N/A public int compareTo(X509CRLEntryImpl that) {
5090N/A int compSerial = getSerialNumber().compareTo(that.getSerialNumber());
5090N/A if (compSerial != 0) {
5090N/A return compSerial;
5090N/A }
5090N/A try {
5090N/A byte[] thisEncoded = this.getEncoded0();
5090N/A byte[] thatEncoded = that.getEncoded0();
5090N/A for (int i=0; i<thisEncoded.length && i<thatEncoded.length; i++) {
5090N/A int a = thisEncoded[i] & 0xff;
5090N/A int b = thatEncoded[i] & 0xff;
5090N/A if (a != b) return a-b;
5090N/A }
5090N/A return thisEncoded.length -thatEncoded.length;
5090N/A } catch (CRLException ce) {
5090N/A return -1;
5090N/A }
5090N/A }
0N/A}