| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package sun.security.x509;  | 
 | 
 | 
 | 
import java.io.IOException;  | 
 | 
import java.security.cert.CRLException;  | 
 | 
import java.security.cert.CRLReason;  | 
 | 
import java.security.cert.X509CRLEntry;  | 
 | 
import java.math.BigInteger;  | 
 | 
import java.util.*;  | 
 | 
 | 
 | 
import javax.security.auth.x500.X500Principal;  | 
 | 
 | 
 | 
import sun.security.util.*;  | 
 | 
import sun.misc.HexDumpEncoder;  | 
 | 
 | 
 | 
/**  | 
 | 
 * <p>Abstract class for a revoked certificate in a CRL.  | 
 | 
 * This class is for each entry in the <code>revokedCertificates</code>,  | 
 | 
 * so it deals with the inner <em>SEQUENCE</em>.  | 
 | 
 * The ASN.1 definition for this is:  | 
 | 
 * <pre>  | 
 | 
 * revokedCertificates    SEQUENCE OF SEQUENCE  { | 
 | 
 *     userCertificate    CertificateSerialNumber,  | 
 | 
 *     revocationDate     ChoiceOfTime,  | 
 | 
 *     crlEntryExtensions Extensions OPTIONAL  | 
 | 
 *                        -- if present, must be v2  | 
 | 
 * }  OPTIONAL  | 
 | 
 *  | 
 | 
 * CertificateSerialNumber  ::=  INTEGER  | 
 | 
 *  | 
 | 
 * Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension  | 
 | 
 *  | 
 | 
 * Extension  ::=  SEQUENCE  { | 
 | 
 *     extnId        OBJECT IDENTIFIER,  | 
 | 
 *     critical      BOOLEAN DEFAULT FALSE,  | 
 | 
 *     extnValue     OCTET STRING  | 
 | 
 *                   -- contains a DER encoding of a value  | 
 | 
 *                   -- of the type registered for use with  | 
 | 
 *                   -- the extnId object identifier value  | 
 | 
 * }  | 
 | 
 * </pre>  | 
 | 
 *  | 
 | 
 * @author Hemma Prafullchandra  | 
 | 
 */  | 
 | 
 | 
 | 
public class X509CRLEntryImpl extends X509CRLEntry  | 
 | 
        implements Comparable<X509CRLEntryImpl> { | 
 | 
 | 
 | 
    private SerialNumber serialNumber = null;  | 
 | 
    private Date revocationDate = null;  | 
 | 
    private CRLExtensions extensions = null;  | 
 | 
    private byte[] revokedCert = null;  | 
 | 
    private X500Principal certIssuer;  | 
 | 
 | 
 | 
    private final static boolean isExplicit = false;  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public X509CRLEntryImpl(BigInteger num, Date date) { | 
 | 
        this.serialNumber = new SerialNumber(num);  | 
 | 
        this.revocationDate = date;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public X509CRLEntryImpl(BigInteger num, Date date,  | 
 | 
                           CRLExtensions crlEntryExts) { | 
 | 
        this.serialNumber = new SerialNumber(num);  | 
 | 
        this.revocationDate = date;  | 
 | 
        this.extensions = crlEntryExts;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public X509CRLEntryImpl(byte[] revokedCert) throws CRLException { | 
 | 
        try { | 
 | 
            parse(new DerValue(revokedCert));  | 
 | 
        } catch (IOException e) { | 
 | 
            this.revokedCert = null;  | 
 | 
            throw new CRLException("Parsing error: " + e.toString()); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public X509CRLEntryImpl(DerValue derValue) throws CRLException { | 
 | 
        try { | 
 | 
            parse(derValue);  | 
 | 
        } catch (IOException e) { | 
 | 
            revokedCert = null;  | 
 | 
            throw new CRLException("Parsing error: " + e.toString()); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public boolean hasExtensions() { | 
 | 
        return (extensions != null);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public void encode(DerOutputStream outStrm) throws CRLException { | 
 | 
        try { | 
 | 
            if (revokedCert == null) { | 
 | 
                DerOutputStream tmp = new DerOutputStream();  | 
 | 
                  | 
 | 
                serialNumber.encode(tmp);  | 
 | 
 | 
 | 
                if (revocationDate.getTime() < CertificateValidity.YR_2050) { | 
 | 
                    tmp.putUTCTime(revocationDate);  | 
 | 
                } else { | 
 | 
                    tmp.putGeneralizedTime(revocationDate);  | 
 | 
                }  | 
 | 
 | 
 | 
                if (extensions != null)  | 
 | 
                    extensions.encode(tmp, isExplicit);  | 
 | 
 | 
 | 
                DerOutputStream seq = new DerOutputStream();  | 
 | 
                seq.write(DerValue.tag_Sequence, tmp);  | 
 | 
 | 
 | 
                revokedCert = seq.toByteArray();  | 
 | 
            }  | 
 | 
            outStrm.write(revokedCert);  | 
 | 
        } catch (IOException e) { | 
 | 
             throw new CRLException("Encoding error: " + e.toString()); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public byte[] getEncoded() throws CRLException { | 
 | 
        return getEncoded0().clone();  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    private byte[] getEncoded0() throws CRLException { | 
 | 
        if (revokedCert == null)  | 
 | 
            this.encode(new DerOutputStream());  | 
 | 
        return revokedCert;  | 
 | 
    }  | 
 | 
 | 
 | 
    @Override  | 
 | 
    public X500Principal getCertificateIssuer() { | 
 | 
        return certIssuer;  | 
 | 
    }  | 
 | 
 | 
 | 
    void setCertificateIssuer(X500Principal crlIssuer, X500Principal certIssuer) { | 
 | 
        if (crlIssuer.equals(certIssuer)) { | 
 | 
            this.certIssuer = null;  | 
 | 
        } else { | 
 | 
            this.certIssuer = certIssuer;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public BigInteger getSerialNumber() { | 
 | 
        return serialNumber.getNumber();  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public Date getRevocationDate() { | 
 | 
        return new Date(revocationDate.getTime());  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    @Override  | 
 | 
    public CRLReason getRevocationReason() { | 
 | 
        Extension ext = getExtension(PKIXExtensions.ReasonCode_Id);  | 
 | 
        if (ext == null) { | 
 | 
            return null;  | 
 | 
        }  | 
 | 
        CRLReasonCodeExtension rcExt = (CRLReasonCodeExtension) ext;  | 
 | 
        return rcExt.getReasonCode();  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public static CRLReason getRevocationReason(X509CRLEntry crlEntry) { | 
 | 
        try { | 
 | 
            byte[] ext = crlEntry.getExtensionValue("2.5.29.21"); | 
 | 
            if (ext == null) { | 
 | 
                return null;  | 
 | 
            }  | 
 | 
            DerValue val = new DerValue(ext);  | 
 | 
            byte[] data = val.getOctetString();  | 
 | 
 | 
 | 
            CRLReasonCodeExtension rcExt =  | 
 | 
                new CRLReasonCodeExtension(Boolean.FALSE, data);  | 
 | 
            return rcExt.getReasonCode();  | 
 | 
        } catch (IOException ioe) { | 
 | 
            return null;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public Integer getReasonCode() throws IOException { | 
 | 
        Object obj = getExtension(PKIXExtensions.ReasonCode_Id);  | 
 | 
        if (obj == null)  | 
 | 
            return null;  | 
 | 
        CRLReasonCodeExtension reasonCode = (CRLReasonCodeExtension)obj;  | 
 | 
        return reasonCode.get(CRLReasonCodeExtension.REASON);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    @Override  | 
 | 
    public String toString() { | 
 | 
        StringBuilder sb = new StringBuilder();  | 
 | 
 | 
 | 
        sb.append(serialNumber.toString());  | 
 | 
        sb.append("  On: " + revocationDate.toString()); | 
 | 
        if (certIssuer != null) { | 
 | 
            sb.append("\n    Certificate issuer: " + certIssuer); | 
 | 
        }  | 
 | 
        if (extensions != null) { | 
 | 
            Collection<Extension> allEntryExts = extensions.getAllExtensions();  | 
 | 
            Extension[] exts = allEntryExts.toArray(new Extension[0]);  | 
 | 
 | 
 | 
            sb.append("\n    CRL Entry Extensions: " + exts.length); | 
 | 
            for (int i = 0; i < exts.length; i++) { | 
 | 
                sb.append("\n    [" + (i+1) + "]: "); | 
 | 
                Extension ext = exts[i];  | 
 | 
                try { | 
 | 
                    if (OIDMap.getClass(ext.getExtensionId()) == null) { | 
 | 
                        sb.append(ext.toString());  | 
 | 
                        byte[] extValue = ext.getExtensionValue();  | 
 | 
                        if (extValue != null) { | 
 | 
                            DerOutputStream out = new DerOutputStream();  | 
 | 
                            out.putOctetString(extValue);  | 
 | 
                            extValue = out.toByteArray();  | 
 | 
                            HexDumpEncoder enc = new HexDumpEncoder();  | 
 | 
                            sb.append("Extension unknown: " | 
 | 
                                      + "DER encoded OCTET string =\n"  | 
 | 
                                      + enc.encodeBuffer(extValue) + "\n");  | 
 | 
                        }  | 
 | 
                    } else  | 
 | 
                        sb.append(ext.toString());   | 
 | 
                } catch (Exception e) { | 
 | 
                    sb.append(", Error parsing this extension"); | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
        sb.append("\n"); | 
 | 
        return sb.toString();  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public boolean hasUnsupportedCriticalExtension() { | 
 | 
        if (extensions == null)  | 
 | 
            return false;  | 
 | 
        return extensions.hasUnsupportedCriticalExtension();  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public Set<String> getCriticalExtensionOIDs() { | 
 | 
        if (extensions == null) { | 
 | 
            return null;  | 
 | 
        }  | 
 | 
        Set<String> extSet = new TreeSet<>();  | 
 | 
        for (Extension ex : extensions.getAllExtensions()) { | 
 | 
            if (ex.isCritical()) { | 
 | 
                extSet.add(ex.getExtensionId().toString());  | 
 | 
            }  | 
 | 
        }  | 
 | 
        return extSet;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public Set<String> getNonCriticalExtensionOIDs() { | 
 | 
        if (extensions == null) { | 
 | 
            return null;  | 
 | 
        }  | 
 | 
        Set<String> extSet = new TreeSet<>();  | 
 | 
        for (Extension ex : extensions.getAllExtensions()) { | 
 | 
            if (!ex.isCritical()) { | 
 | 
                extSet.add(ex.getExtensionId().toString());  | 
 | 
            }  | 
 | 
        }  | 
 | 
        return extSet;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public byte[] getExtensionValue(String oid) { | 
 | 
        if (extensions == null)  | 
 | 
            return null;  | 
 | 
        try { | 
 | 
            String extAlias = OIDMap.getName(new ObjectIdentifier(oid));  | 
 | 
            Extension crlExt = null;  | 
 | 
 | 
 | 
            if (extAlias == null) {  | 
 | 
                ObjectIdentifier findOID = new ObjectIdentifier(oid);  | 
 | 
                Extension ex = null;  | 
 | 
                ObjectIdentifier inCertOID;  | 
 | 
                for (Enumeration<Extension> e = extensions.getElements();  | 
 | 
                                                 e.hasMoreElements();) { | 
 | 
                    ex = e.nextElement();  | 
 | 
                    inCertOID = ex.getExtensionId();  | 
 | 
                    if (inCertOID.equals((Object)findOID)) { | 
 | 
                        crlExt = ex;  | 
 | 
                        break;  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            } else  | 
 | 
                crlExt = extensions.get(extAlias);  | 
 | 
            if (crlExt == null)  | 
 | 
                return null;  | 
 | 
            byte[] extData = crlExt.getExtensionValue();  | 
 | 
            if (extData == null)  | 
 | 
                return null;  | 
 | 
 | 
 | 
            DerOutputStream out = new DerOutputStream();  | 
 | 
            out.putOctetString(extData);  | 
 | 
            return out.toByteArray();  | 
 | 
        } catch (Exception e) { | 
 | 
            return null;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public Extension getExtension(ObjectIdentifier oid) { | 
 | 
        if (extensions == null)  | 
 | 
            return null;  | 
 | 
 | 
 | 
        // following returns null if no such OID in map  | 
 | 
          | 
 | 
        return extensions.get(OIDMap.getName(oid));  | 
 | 
    }  | 
 | 
 | 
 | 
    private void parse(DerValue derVal)  | 
 | 
    throws CRLException, IOException { | 
 | 
 | 
 | 
        if (derVal.tag != DerValue.tag_Sequence) { | 
 | 
            throw new CRLException("Invalid encoded RevokedCertificate, " + | 
 | 
                                  "starting sequence tag missing.");  | 
 | 
        }  | 
 | 
        if (derVal.data.available() == 0)  | 
 | 
            throw new CRLException("No data encoded for RevokedCertificates"); | 
 | 
 | 
 | 
        revokedCert = derVal.toByteArray();  | 
 | 
          | 
 | 
        DerInputStream in = derVal.toDerInputStream();  | 
 | 
        DerValue val = in.getDerValue();  | 
 | 
        this.serialNumber = new SerialNumber(val);  | 
 | 
 | 
 | 
          | 
 | 
        int nextByte = derVal.data.peekByte();  | 
 | 
        if ((byte)nextByte == DerValue.tag_UtcTime) { | 
 | 
            this.revocationDate = derVal.data.getUTCTime();  | 
 | 
        } else if ((byte)nextByte == DerValue.tag_GeneralizedTime) { | 
 | 
            this.revocationDate = derVal.data.getGeneralizedTime();  | 
 | 
        } else  | 
 | 
            throw new CRLException("Invalid encoding for revocation date"); | 
 | 
 | 
 | 
        if (derVal.data.available() == 0)  | 
 | 
            return;    | 
 | 
 | 
 | 
          | 
 | 
        this.extensions = new CRLExtensions(derVal.toDerInputStream());  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public static X509CRLEntryImpl toImpl(X509CRLEntry entry)  | 
 | 
            throws CRLException { | 
 | 
        if (entry instanceof X509CRLEntryImpl) { | 
 | 
            return (X509CRLEntryImpl)entry;  | 
 | 
        } else { | 
 | 
            return new X509CRLEntryImpl(entry.getEncoded());  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    CertificateIssuerExtension getCertificateIssuerExtension() { | 
 | 
        return (CertificateIssuerExtension)  | 
 | 
            getExtension(PKIXExtensions.CertificateIssuer_Id);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public Map<String, java.security.cert.Extension> getExtensions() { | 
 | 
        if (extensions == null) { | 
 | 
            return Collections.emptyMap();  | 
 | 
        }  | 
 | 
        Collection<Extension> exts = extensions.getAllExtensions();  | 
 | 
        Map<String, java.security.cert.Extension> map = new TreeMap<>();  | 
 | 
        for (Extension ext : exts) { | 
 | 
            map.put(ext.getId(), ext);  | 
 | 
        }  | 
 | 
        return map;  | 
 | 
    }  | 
 | 
 | 
 | 
    @Override  | 
 | 
    public int compareTo(X509CRLEntryImpl that) { | 
 | 
        int compSerial = getSerialNumber().compareTo(that.getSerialNumber());  | 
 | 
        if (compSerial != 0) { | 
 | 
            return compSerial;  | 
 | 
        }  | 
 | 
        try { | 
 | 
            byte[] thisEncoded = this.getEncoded0();  | 
 | 
            byte[] thatEncoded = that.getEncoded0();  | 
 | 
            for (int i=0; i<thisEncoded.length && i<thatEncoded.length; i++) { | 
 | 
                int a = thisEncoded[i] & 0xff;  | 
 | 
                int b = thatEncoded[i] & 0xff;  | 
 | 
                if (a != b) return a-b;  | 
 | 
            }  | 
 | 
            return thisEncoded.length -thatEncoded.length;  | 
 | 
        } catch (CRLException ce) { | 
 | 
            return -1;  | 
 | 
        }  | 
 | 
    }  | 
 | 
}  |