1package org.bouncycastle.jce.provider; 2 3import java.io.ByteArrayOutputStream; 4import java.io.IOException; 5import java.math.BigInteger; 6import java.security.cert.CRLException; 7import java.security.cert.X509CRLEntry; 8import java.util.Date; 9import java.util.Enumeration; 10import java.util.HashSet; 11import java.util.Set; 12 13import javax.security.auth.x500.X500Principal; 14 15import org.bouncycastle.asn1.DERObjectIdentifier; 16import org.bouncycastle.asn1.DEROutputStream; 17import org.bouncycastle.asn1.x509.GeneralName; 18import org.bouncycastle.asn1.x509.GeneralNames; 19import org.bouncycastle.asn1.x509.TBSCertList; 20import org.bouncycastle.asn1.x509.X509Extension; 21import org.bouncycastle.asn1.x509.X509Extensions; 22import org.bouncycastle.x509.extension.X509ExtensionUtil; 23 24/** 25 * The following extensions are listed in RFC 2459 as relevant to CRL Entries 26 * 27 * ReasonCode Hode Instruction Code Invalidity Date Certificate Issuer 28 * (critical) 29 */ 30public class X509CRLEntryObject extends X509CRLEntry 31{ 32 private TBSCertList.CRLEntry c; 33 34 private boolean isIndirect = false; 35 36 private X500Principal previousCertificateIssuer = null; 37 38 public X509CRLEntryObject(TBSCertList.CRLEntry c) 39 { 40 this.c = c; 41 } 42 43 /** 44 * Constructor for CRLEntries of indirect CRLs. If <code>isIndirect</code> 45 * is <code>false</code> {@link #getCertificateIssuer()} will always 46 * return <code>null</code>, <code>previousCertificateIssuer</code> is 47 * ignored. If this <code>isIndirect</code> is specified and this CRLEntry 48 * has no certificate issuer CRL entry extension 49 * <code>previousCertificateIssuer</code> is returned by 50 * {@link #getCertificateIssuer()}. 51 * 52 * @param c 53 * TBSCertList.CRLEntry object. 54 * @param isIndirect 55 * <code>true</code> if the corresponding CRL is a indirect 56 * CRL. 57 * @param previousCertificateIssuer 58 * Certificate issuer of the previous CRLEntry. 59 */ 60 public X509CRLEntryObject( 61 TBSCertList.CRLEntry c, 62 boolean isIndirect, 63 X500Principal previousCertificateIssuer) 64 { 65 this.c = c; 66 this.isIndirect = isIndirect; 67 this.previousCertificateIssuer = previousCertificateIssuer; 68 } 69 70 /** 71 * Will return true if any extensions are present and marked as critical as 72 * we currently dont handle any extensions! 73 */ 74 public boolean hasUnsupportedCriticalExtension() 75 { 76 Set extns = getCriticalExtensionOIDs(); 77 if (extns != null && !extns.isEmpty()) 78 { 79 return true; 80 } 81 82 return false; 83 } 84 85 public X500Principal getCertificateIssuer() 86 { 87 if (!isIndirect) 88 { 89 return null; 90 } 91 92 byte[] ext = getExtensionValue(X509Extensions.CertificateIssuer.getId()); 93 if (ext == null) 94 { 95 return previousCertificateIssuer; 96 } 97 98 try 99 { 100 GeneralName[] names = GeneralNames.getInstance( 101 X509ExtensionUtil.fromExtensionValue(ext)).getNames(); 102 for (int i = 0; i < names.length; i++) 103 { 104 if (names[i].getTagNo() == GeneralName.directoryName) 105 { 106 return new X500Principal(names[i].getName().getDERObject().getDEREncoded()); 107 } 108 } 109 throw new RuntimeException( 110 "Cannot extract directory name from certificate issuer CRL entry extension"); 111 } 112 catch (IOException e) 113 { 114 throw new RuntimeException( 115 "Cannot extract certificate issuer CRL entry extension " 116 + e); 117 } 118 } 119 120 private Set getExtensionOIDs(boolean critical) 121 { 122 X509Extensions extensions = c.getExtensions(); 123 124 if (extensions != null) 125 { 126 Set set = new HashSet(); 127 Enumeration e = extensions.oids(); 128 129 while (e.hasMoreElements()) 130 { 131 DERObjectIdentifier oid = (DERObjectIdentifier) e.nextElement(); 132 X509Extension ext = extensions.getExtension(oid); 133 134 if (critical == ext.isCritical()) 135 { 136 set.add(oid.getId()); 137 } 138 } 139 140 return set; 141 } 142 143 return null; 144 } 145 146 public Set getCriticalExtensionOIDs() 147 { 148 return getExtensionOIDs(true); 149 } 150 151 public Set getNonCriticalExtensionOIDs() 152 { 153 return getExtensionOIDs(false); 154 } 155 156 public byte[] getExtensionValue(String oid) 157 { 158 X509Extensions exts = c.getExtensions(); 159 160 if (exts != null) 161 { 162 X509Extension ext = exts.getExtension(new DERObjectIdentifier(oid)); 163 164 if (ext != null) 165 { 166 try 167 { 168 return ext.getValue().getEncoded(); 169 } 170 catch (Exception e) 171 { 172 throw new RuntimeException("error encoding " + e.toString()); 173 } 174 } 175 } 176 177 return null; 178 } 179 180 public byte[] getEncoded() 181 throws CRLException 182 { 183 ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 184 DEROutputStream dOut = new DEROutputStream(bOut); 185 186 try 187 { 188 dOut.writeObject(c); 189 190 return bOut.toByteArray(); 191 } 192 catch (IOException e) 193 { 194 throw new CRLException(e.toString()); 195 } 196 } 197 198 public BigInteger getSerialNumber() 199 { 200 return c.getUserCertificate().getValue(); 201 } 202 203 public Date getRevocationDate() 204 { 205 return c.getRevocationDate().getDate(); 206 } 207 208 public boolean hasExtensions() 209 { 210 return c.getExtensions() != null; 211 } 212 213 public String toString() 214 { 215 StringBuffer buf = new StringBuffer(); 216 String nl = System.getProperty("line.separator"); 217 218 buf.append(" userCertificate: ").append(this.getSerialNumber()).append(nl); 219 buf.append(" revocationDate: ").append(this.getRevocationDate()).append(nl); 220 221 X509Extensions extensions = c.getExtensions(); 222 223 if (extensions != null) 224 { 225 Enumeration e = extensions.oids(); 226 if (e.hasMoreElements()) 227 { 228 buf.append(" crlEntryExtensions:").append(nl); 229 230 while (e.hasMoreElements()) 231 { 232 DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement(); 233 X509Extension ext = extensions.getExtension(oid); 234 buf.append(ext); 235 } 236 } 237 } 238 239 return buf.toString(); 240 } 241} 242