1 /* X509CRL.java -- X.509 certificate revocation list. 2 Copyright (C) 2003 Free Software Foundation, Inc. 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 19 02111-1307 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 39 package gnu.java.security.x509; 40 41 import java.io.InputStream; 42 import java.io.IOException; 43 44 import java.math.BigInteger; 45 46 import java.util.Calendar; 47 import java.util.Collections; 48 import java.util.Date; 49 import java.util.HashSet; 50 import java.util.HashMap; 51 import java.util.Set; 52 53 import java.security.InvalidKeyException; 54 import java.security.NoSuchAlgorithmException; 55 import java.security.NoSuchProviderException; 56 import java.security.PublicKey; 57 import java.security.Principal; 58 import java.security.Signature; 59 import java.security.SignatureException; 60 import java.security.cert.Certificate; 61 import java.security.cert.CRLException; 62 import java.security.cert.X509CRLEntry; 63 64 import javax.security.auth.x500.X500Principal; 65 66 import gnu.java.io.ASN1ParsingException; 67 import gnu.java.security.OID; 68 import gnu.java.security.der.BitString; 69 import gnu.java.security.der.DER; 70 import gnu.java.security.der.DERReader; 71 import gnu.java.security.der.DERValue; 72 import gnu.java.security.der.DERWriter; 73 74 /** 75 * X.509 certificate revocation lists. 76 * 77 * @author Casey Marshall (rsdio@metastatic.org) 78 */ 79 public class X509CRL extends java.security.cert.X509CRL 80 { 81 82 // Constants and fields. 83 // ------------------------------------------------------------------------ 84 85 private static final OID ID_DSA = new OID("1.2.840.10040.4.1"); 86 private static final OID ID_DSA_WITH_SHA1 = new OID("1.2.840.10040.4.3"); 87 private static final OID ID_RSA = new OID("1.2.840.113549.1.1.1"); 88 private static final OID ID_RSA_WITH_MD2 = new OID("1.2.840.113549.1.1.2"); 89 private static final OID ID_RSA_WITH_MD5 = new OID("1.2.840.113549.1.1.4"); 90 private static final OID ID_RSA_WITH_SHA1 = new OID("1.2.840.113549.1.1.5"); 91 92 private byte[] encoded; 93 94 private byte[] tbsCRLBytes; 95 private int version; 96 private OID algId; 97 private byte[] algParams; 98 private Date thisUpdate; 99 private Date nextUpdate; 100 private X500Principal issuerDN; 101 private HashMap revokedCerts; 102 private HashMap extensions; 103 private HashSet critOids; 104 private HashSet nonCritOids; 105 106 private OID sigAlg; 107 private byte[] sigAlgParams; 108 private byte[] rawSig; 109 private byte[] signature; 110 111 // Constructors. 112 // ------------------------------------------------------------------------ 113 114 /** 115 * Create a new X.509 CRL. 116 * 117 * @param encoded The DER encoded CRL. 118 * @throws CRLException If the input bytes are incorrect. 119 * @throws IOException If the input bytes cannot be read. 120 */ X509CRL(InputStream encoded)121 public X509CRL(InputStream encoded) throws CRLException, IOException 122 { 123 super(); 124 revokedCerts = new HashMap(); 125 extensions = new HashMap(); 126 critOids = new HashSet(); 127 nonCritOids = new HashSet(); 128 try 129 { 130 parse(encoded); 131 } 132 catch (IOException ioe) 133 { 134 ioe.printStackTrace(); 135 throw ioe; 136 } 137 catch (Exception x) 138 { 139 x.printStackTrace(); 140 throw new CRLException(x.toString()); 141 } 142 } 143 144 // X509CRL methods. 145 // ------------------------------------------------------------------------ 146 equals(Object o)147 public boolean equals(Object o) 148 { 149 return ((X509CRL) o).revokedCerts.equals(revokedCerts); 150 } 151 hashCode()152 public int hashCode() 153 { 154 return revokedCerts.hashCode(); 155 } 156 getEncoded()157 public byte[] getEncoded() throws CRLException 158 { 159 return (byte[]) encoded.clone(); 160 } 161 verify(PublicKey key)162 public void verify(PublicKey key) 163 throws CRLException, NoSuchAlgorithmException, InvalidKeyException, 164 NoSuchProviderException, SignatureException 165 { 166 Signature sig = Signature.getInstance(sigAlg.toString()); 167 doVerify(sig, key); 168 } 169 verify(PublicKey key, String provider)170 public void verify(PublicKey key, String provider) 171 throws CRLException, NoSuchAlgorithmException, InvalidKeyException, 172 NoSuchProviderException, SignatureException 173 { 174 Signature sig = Signature.getInstance(sigAlg.toString(), provider); 175 doVerify(sig, key); 176 } 177 getVersion()178 public int getVersion() 179 { 180 return version; 181 } 182 getIssuerDN()183 public Principal getIssuerDN() 184 { 185 return issuerDN; 186 } 187 getIssuerX500Principal()188 public X500Principal getIssuerX500Principal() 189 { 190 return issuerDN; 191 } 192 getThisUpdate()193 public Date getThisUpdate() 194 { 195 return (Date) thisUpdate.clone(); 196 } 197 getNextUpdate()198 public Date getNextUpdate() 199 { 200 if (nextUpdate != null) 201 return (Date) nextUpdate.clone(); 202 return null; 203 } 204 getRevokedCertificate(BigInteger serialNo)205 public X509CRLEntry getRevokedCertificate(BigInteger serialNo) 206 { 207 return (X509CRLEntry) revokedCerts.get(serialNo); 208 } 209 getRevokedCertificates()210 public Set getRevokedCertificates() 211 { 212 return Collections.unmodifiableSet(new HashSet(revokedCerts.values())); 213 } 214 getTBSCertList()215 public byte[] getTBSCertList() throws CRLException 216 { 217 return (byte[]) tbsCRLBytes.clone(); 218 } 219 getSignature()220 public byte[] getSignature() 221 { 222 return (byte[]) rawSig.clone(); 223 } 224 getSigAlgName()225 public String getSigAlgName() 226 { 227 if (sigAlg.equals(ID_DSA_WITH_SHA1)) 228 return "SHA1withDSA"; 229 if (sigAlg.equals(ID_RSA_WITH_MD2)) 230 return "MD2withRSA"; 231 if (sigAlg.equals(ID_RSA_WITH_MD5)) 232 return "MD5withRSA"; 233 if (sigAlg.equals(ID_RSA_WITH_SHA1)) 234 return "SHA1withRSA"; 235 return "unknown"; 236 } 237 getSigAlgOID()238 public String getSigAlgOID() 239 { 240 return sigAlg.toString(); 241 } 242 getSigAlgParams()243 public byte[] getSigAlgParams() 244 { 245 if (sigAlgParams != null) 246 return (byte[]) sigAlgParams.clone(); 247 return null; 248 } 249 250 // X509Extension methods. 251 // ------------------------------------------------------------------------ 252 hasUnsupportedCriticalExtension()253 public boolean hasUnsupportedCriticalExtension() 254 { 255 return false; // XXX 256 } 257 getCriticalExtensionOIDs()258 public Set getCriticalExtensionOIDs() 259 { 260 return Collections.unmodifiableSet(critOids); 261 } 262 getNonCriticalExtensionOIDs()263 public Set getNonCriticalExtensionOIDs() 264 { 265 return Collections.unmodifiableSet(nonCritOids); 266 } 267 getExtensionValue(String oid)268 public byte[] getExtensionValue(String oid) 269 { 270 byte[] ext = (byte[]) extensions.get(oid); 271 if (ext != null) 272 return (byte[]) ext.clone(); 273 return null; 274 } 275 276 // CRL methods. 277 // ------------------------------------------------------------------------ 278 toString()279 public String toString() 280 { 281 return gnu.java.security.x509.X509CRL.class.getName(); 282 } 283 isRevoked(Certificate cert)284 public boolean isRevoked(Certificate cert) 285 { 286 if (!(cert instanceof java.security.cert.X509Certificate)) 287 throw new IllegalArgumentException("not a X.509 certificate"); 288 BigInteger certSerial = 289 ((java.security.cert.X509Certificate) cert).getSerialNumber(); 290 X509CRLEntry ent = (X509CRLEntry) revokedCerts.get(certSerial); 291 if (ent == null) 292 return false; 293 return ent.getRevocationDate().compareTo(new Date()) < 0; 294 } 295 296 // Own methods. 297 // ------------------------------------------------------------------------ 298 doVerify(Signature sig, PublicKey key)299 private void doVerify(Signature sig, PublicKey key) 300 throws CRLException, InvalidKeyException, SignatureException 301 { 302 sig.initVerify(key); 303 sig.update(tbsCRLBytes); 304 if (!sig.verify(signature)) 305 throw new CRLException("signature not verified"); 306 } 307 parse(InputStream in)308 private void parse(InputStream in) throws Exception 309 { 310 DERReader der = new DERReader(in); 311 DERValue val = der.read(); 312 if (!val.isConstructed()) 313 throw new ASN1ParsingException("malformed CertificateList"); 314 encoded = val.getEncoded(); 315 316 val = der.read(); 317 if (!val.isConstructed()) 318 throw new ASN1ParsingException("malformed TBSCertList"); 319 tbsCRLBytes = val.getEncoded(); 320 321 val = der.read(); 322 if (val.getValue() instanceof BigInteger) 323 { 324 version = ((BigInteger) val.getValue()).intValue() + 1; 325 val = der.read(); 326 } 327 else 328 version = 1; 329 330 if (!val.isConstructed()) 331 throw new ASN1ParsingException("malformed AlgorithmIdentifier"); 332 DERValue algIdVal = der.read(); 333 algId = (OID) algIdVal.getValue(); 334 if (val.getLength() > algIdVal.getEncodedLength()) 335 { 336 val = der.read(); 337 algParams = val.getEncoded(); 338 if (val.isConstructed()) 339 in.skip(val.getLength()); 340 } 341 342 issuerDN = new X500Principal(in); 343 344 thisUpdate = (Date) der.read().getValue(); 345 346 val = der.read(); 347 if (val.getValue() instanceof Date) 348 { 349 nextUpdate = (Date) val.getValue(); 350 val = der.read(); 351 } 352 if (val.getTag() != 0) 353 { 354 int len = 0; 355 while (len < val.getLength()) 356 { 357 X509CRLEntry entry = 358 new gnu.java.security.x509.X509CRLEntry(version, in); 359 revokedCerts.put(entry.getSerialNumber(), entry); 360 len += entry.getEncoded().length; 361 } 362 } 363 if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 0) 364 { 365 val = der.read(); 366 int len = 0; 367 while (len < val.getLength()) 368 { 369 DERValue ext = der.read(); 370 OID extId = (OID) der.read().getValue(); 371 DERValue val2 = der.read(); 372 Boolean crit = Boolean.valueOf(false); 373 if (val2.getValue() instanceof Boolean) 374 { 375 crit = (Boolean) val2.getValue(); 376 val2 = der.read(); 377 } 378 byte[] extVal = (byte[]) val2.getValue(); 379 extensions.put(extId.toString(), extVal); 380 if (crit.booleanValue()) 381 critOids.add(extId.toString()); 382 else 383 nonCritOids.add(extId.toString()); 384 len += ext.getEncodedLength(); 385 } 386 } 387 388 val = der.read(); 389 if (!val.isConstructed()) 390 throw new ASN1ParsingException("malformed AlgorithmIdentifier"); 391 DERValue sigAlgVal = der.read(); 392 sigAlg = (OID) sigAlgVal.getValue(); 393 if (val.getLength() > sigAlgVal.getEncodedLength()) 394 { 395 val = der.read(); 396 sigAlgParams = (byte[]) val.getEncoded(); 397 if (val.isConstructed()) 398 in.skip(val.getLength()); 399 } 400 val = der.read(); 401 rawSig = val.getEncoded(); 402 signature = ((BitString) val.getValue()).toByteArray(); 403 } 404 } 405