Source for gnu.java.security.x509.X509CRL

   1: /* X509CRL.java -- X.509 certificate revocation list.
   2:    Copyright (C) 2003, 2004, 2010  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., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 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 gnu.java.security.Configuration;
  42: import gnu.java.security.OID;
  43: import gnu.java.security.der.BitString;
  44: import gnu.java.security.der.DER;
  45: import gnu.java.security.der.DERReader;
  46: import gnu.java.security.der.DERValue;
  47: import gnu.java.security.x509.ext.Extension;
  48: 
  49: import java.io.IOException;
  50: import java.io.InputStream;
  51: import java.math.BigInteger;
  52: import java.security.InvalidKeyException;
  53: import java.security.NoSuchAlgorithmException;
  54: import java.security.NoSuchProviderException;
  55: import java.security.Principal;
  56: import java.security.PublicKey;
  57: import java.security.Signature;
  58: import java.security.SignatureException;
  59: import java.security.cert.CRLException;
  60: import java.security.cert.Certificate;
  61: import java.util.Collection;
  62: import java.util.Collections;
  63: import java.util.Date;
  64: import java.util.HashMap;
  65: import java.util.HashSet;
  66: import java.util.Iterator;
  67: import java.util.Set;
  68: import java.util.logging.Logger;
  69: 
  70: import javax.security.auth.x500.X500Principal;
  71: 
  72: /**
  73:  * X.509 certificate revocation lists.
  74:  *
  75:  * @author Casey Marshall (rsdio@metastatic.org)
  76:  */
  77: public class X509CRL extends java.security.cert.X509CRL
  78:   implements GnuPKIExtension
  79: {
  80:   private static final Logger log = Configuration.DEBUG ?
  81:                         Logger.getLogger(X509CRL.class.getName()) : null;
  82: 
  83:   private static final OID ID_DSA = new OID("1.2.840.10040.4.1");
  84:   private static final OID ID_DSA_WITH_SHA1 = new OID("1.2.840.10040.4.3");
  85:   private static final OID ID_RSA = new OID("1.2.840.113549.1.1.1");
  86:   private static final OID ID_RSA_WITH_MD2 = new OID("1.2.840.113549.1.1.2");
  87:   private static final OID ID_RSA_WITH_MD5 = new OID("1.2.840.113549.1.1.4");
  88:   private static final OID ID_RSA_WITH_SHA1 = new OID("1.2.840.113549.1.1.5");
  89: 
  90:   private byte[] encoded;
  91: 
  92:   private byte[] tbsCRLBytes;
  93:   private int version;
  94:   private OID algId;
  95:   private byte[] algParams;
  96:   private Date thisUpdate;
  97:   private Date nextUpdate;
  98:   private X500DistinguishedName issuerDN;
  99:   private HashMap revokedCerts;
 100:   private HashMap extensions;
 101: 
 102:   private OID sigAlg;
 103:   private byte[] sigAlgParams;
 104:   private byte[] rawSig;
 105:   private byte[] signature;
 106: 
 107:   // Constructors.
 108:   // ------------------------------------------------------------------------
 109: 
 110:   /**
 111:    * Create a new X.509 CRL.
 112:    *
 113:    * @param encoded The DER encoded CRL.
 114:    * @throws CRLException If the input bytes are incorrect.
 115:    * @throws IOException  If the input bytes cannot be read.
 116:    */
 117:   public X509CRL(InputStream encoded) throws CRLException, IOException
 118:   {
 119:     super();
 120:     revokedCerts = new HashMap();
 121:     extensions = new HashMap();
 122:     try
 123:       {
 124:         parse(encoded);
 125:       }
 126:     catch (IOException ioe)
 127:       {
 128:         ioe.printStackTrace();
 129:         throw ioe;
 130:       }
 131:     catch (Exception x)
 132:       {
 133:         x.printStackTrace();
 134:         throw new CRLException(x.toString());
 135:       }
 136:   }
 137: 
 138:   // X509CRL methods.
 139:   // ------------------------------------------------------------------------
 140: 
 141:   public boolean equals(Object o)
 142:   {
 143:     if (!(o instanceof X509CRL))
 144:       return false;
 145:     return ((X509CRL) o).getRevokedCertificates().equals(revokedCerts.values());
 146:   }
 147: 
 148:   public int hashCode()
 149:   {
 150:     return revokedCerts.hashCode();
 151:   }
 152: 
 153:   public byte[] getEncoded() throws CRLException
 154:   {
 155:     return (byte[]) encoded.clone();
 156:   }
 157: 
 158:   public void verify(PublicKey key)
 159:     throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
 160:            NoSuchProviderException, SignatureException
 161:   {
 162:     Signature sig = Signature.getInstance(sigAlg.toString());
 163:     doVerify(sig, key);
 164:   }
 165: 
 166:   public void verify(PublicKey key, String provider)
 167:     throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
 168:            NoSuchProviderException, SignatureException
 169:   {
 170:     Signature sig = Signature.getInstance(sigAlg.toString(), provider);
 171:     doVerify(sig, key);
 172:   }
 173: 
 174:   public int getVersion()
 175:   {
 176:     return version;
 177:   }
 178: 
 179:   public Principal getIssuerDN()
 180:   {
 181:     return issuerDN;
 182:   }
 183: 
 184:   public X500Principal getIssuerX500Principal()
 185:   {
 186:     return new X500Principal(issuerDN.getDer());
 187:   }
 188: 
 189:   public Date getThisUpdate()
 190:   {
 191:     return (Date) thisUpdate.clone();
 192:   }
 193: 
 194:   public Date getNextUpdate()
 195:   {
 196:     if (nextUpdate != null)
 197:       return (Date) nextUpdate.clone();
 198:     return null;
 199:   }
 200: 
 201:   public java.security.cert.X509CRLEntry getRevokedCertificate(BigInteger serialNo)
 202:   {
 203:     return (java.security.cert.X509CRLEntry) revokedCerts.get(serialNo);
 204:   }
 205: 
 206:   public Set getRevokedCertificates()
 207:   {
 208:     return Collections.unmodifiableSet(new HashSet(revokedCerts.values()));
 209:   }
 210: 
 211:   public byte[] getTBSCertList() throws CRLException
 212:   {
 213:     return (byte[]) tbsCRLBytes.clone();
 214:   }
 215: 
 216:   public byte[] getSignature()
 217:   {
 218:     return (byte[]) rawSig.clone();
 219:   }
 220: 
 221:   public String getSigAlgName()
 222:   {
 223:     if (sigAlg.equals(ID_DSA_WITH_SHA1))
 224:       return "SHA1withDSA";
 225:     if (sigAlg.equals(ID_RSA_WITH_MD2))
 226:       return "MD2withRSA";
 227:     if (sigAlg.equals(ID_RSA_WITH_MD5))
 228:       return "MD5withRSA";
 229:     if (sigAlg.equals(ID_RSA_WITH_SHA1))
 230:       return "SHA1withRSA";
 231:     return "unknown";
 232:   }
 233: 
 234:   public String getSigAlgOID()
 235:   {
 236:     return sigAlg.toString();
 237:   }
 238: 
 239:   public byte[] getSigAlgParams()
 240:   {
 241:     if (sigAlgParams != null)
 242:       return (byte[]) sigAlgParams.clone();
 243:     return null;
 244:   }
 245: 
 246:   // X509Extension methods.
 247:   // ------------------------------------------------------------------------
 248: 
 249:   public boolean hasUnsupportedCriticalExtension()
 250:   {
 251:     for (Iterator it = extensions.values().iterator(); it.hasNext(); )
 252:       {
 253:         Extension e = (Extension) it.next();
 254:         if (e.isCritical() && !e.isSupported())
 255:           return true;
 256:       }
 257:     return false;
 258:   }
 259: 
 260:   public Set getCriticalExtensionOIDs()
 261:   {
 262:     HashSet s = new HashSet();
 263:     for (Iterator it = extensions.values().iterator(); it.hasNext(); )
 264:       {
 265:         Extension e = (Extension) it.next();
 266:         if (e.isCritical())
 267:           s.add(e.getOid().toString());
 268:       }
 269:     return Collections.unmodifiableSet(s);
 270:   }
 271: 
 272:   public Set getNonCriticalExtensionOIDs()
 273:   {
 274:     HashSet s = new HashSet();
 275:     for (Iterator it = extensions.values().iterator(); it.hasNext(); )
 276:       {
 277:         Extension e = (Extension) it.next();
 278:         if (!e.isCritical())
 279:           s.add(e.getOid().toString());
 280:       }
 281:     return Collections.unmodifiableSet(s);
 282:   }
 283: 
 284:   public byte[] getExtensionValue(String oid)
 285:   {
 286:     Extension e = getExtension(new OID(oid));
 287:     if (e != null)
 288:       {
 289:         return e.getValue().getEncoded();
 290:       }
 291:     return null;
 292:   }
 293: 
 294:   // GnuPKIExtension method.
 295:   // -------------------------------------------------------------------------
 296: 
 297:   public Extension getExtension(OID oid)
 298:   {
 299:     return (Extension) extensions.get(oid);
 300:   }
 301: 
 302:   public Collection getExtensions()
 303:   {
 304:     return extensions.values();
 305:   }
 306: 
 307:   // CRL methods.
 308:   // -------------------------------------------------------------------------
 309: 
 310:   public String toString()
 311:   {
 312:     return X509CRL.class.getName();
 313:   }
 314: 
 315:   public boolean isRevoked(Certificate cert)
 316:   {
 317:     if (!(cert instanceof java.security.cert.X509Certificate))
 318:       throw new IllegalArgumentException("not a X.509 certificate");
 319:     BigInteger certSerial =
 320:       ((java.security.cert.X509Certificate) cert).getSerialNumber();
 321:     X509CRLEntry ent = (X509CRLEntry) revokedCerts.get(certSerial);
 322:     if (ent == null)
 323:       return false;
 324:     return ent.getRevocationDate().compareTo(new Date()) < 0;
 325:   }
 326: 
 327:   // Own methods.
 328:   // ------------------------------------------------------------------------
 329: 
 330:   private void doVerify(Signature sig, PublicKey key)
 331:     throws CRLException, InvalidKeyException, SignatureException
 332:   {
 333:     sig.initVerify(key);
 334:     sig.update(tbsCRLBytes);
 335:     if (!sig.verify(signature))
 336:       throw new CRLException("signature not verified");
 337:   }
 338: 
 339:   private void parse(InputStream in) throws Exception
 340:   {
 341:     // CertificateList ::= SEQUENCE {
 342:     DERReader der = new DERReader(in);
 343:     DERValue val = der.read();
 344:     if (Configuration.DEBUG)
 345:       log.fine("start CertificateList len == " + val.getLength());
 346:     if (!val.isConstructed())
 347:       throw new IOException("malformed CertificateList");
 348:     encoded = val.getEncoded();
 349: 
 350:     //   tbsCertList ::= SEQUENCE {  -- TBSCertList
 351:     val = der.read();
 352:     if (!val.isConstructed())
 353:       throw new IOException("malformed TBSCertList");
 354:     if (Configuration.DEBUG)
 355:       log.fine("start tbsCertList  len == " + val.getLength());
 356:     tbsCRLBytes = val.getEncoded();
 357: 
 358:     //     version    Version OPTIONAL,
 359:     //                  -- If present must be v2
 360:     val = der.read();
 361:     if (val.getValue() instanceof BigInteger)
 362:       {
 363:         version = ((BigInteger) val.getValue()).intValue() + 1;
 364:         val = der.read();
 365:       }
 366:     else
 367:       version = 1;
 368:     if (Configuration.DEBUG)
 369:       log.fine("read version == " + version);
 370: 
 371:     //     signature   AlgorithmIdentifier,
 372:     if (Configuration.DEBUG)
 373:       log.fine("start AlgorithmIdentifier len == " + val.getLength());
 374:     if (!val.isConstructed())
 375:       throw new IOException("malformed AlgorithmIdentifier");
 376:     DERValue algIdVal = der.read();
 377:     algId = (OID) algIdVal.getValue();
 378:     if (Configuration.DEBUG)
 379:       log.fine("read object identifier == " + algId);
 380:     if (val.getLength() > algIdVal.getEncodedLength())
 381:       {
 382:         val = der.read();
 383:         if (Configuration.DEBUG)
 384:           log.fine("read parameters  len == " + val.getEncodedLength());
 385:         algParams = val.getEncoded();
 386:         if (val.isConstructed())
 387:           in.skip(val.getLength());
 388:       }
 389: 
 390:     //     issuer   Name,
 391:     val = der.read();
 392:     issuerDN = new X500DistinguishedName(val.getEncoded());
 393:     der.skip(val.getLength());
 394:     if (Configuration.DEBUG)
 395:       log.fine("read issuer == " + issuerDN);
 396: 
 397:     //     thisUpdate   Time,
 398:     thisUpdate = (Date) der.read().getValue();
 399:     if (Configuration.DEBUG)
 400:       log.fine("read thisUpdate == " + thisUpdate);
 401: 
 402:     //     nextUpdate   Time OPTIONAL,
 403:     val = der.read();
 404:     if (val.getValue() instanceof Date)
 405:       {
 406:         nextUpdate = (Date) val.getValue();
 407:         if (Configuration.DEBUG)
 408:           log.fine("read nextUpdate == " + nextUpdate);
 409:         val = der.read();
 410:       }
 411: 
 412:     //     revokedCertificates SEQUENCE OF SEQUENCE {
 413:     //       -- X509CRLEntry objects...
 414:     //     } OPTIONAL,
 415:     if (val.getTag() != 0)
 416:       {
 417:         int len = 0;
 418:         while (len < val.getLength())
 419:           {
 420:             X509CRLEntry entry = new X509CRLEntry(version, der);
 421:             revokedCerts.put(entry.getSerialNumber(), entry);
 422:             len += entry.getEncoded().length;
 423:           }
 424:         val = der.read();
 425:       }
 426: 
 427:     //    crlExtensions   [0] EXPLICIT Extensions OPTIONAL
 428:     //                        -- if present MUST be v2
 429:     if (val.getTagClass() != DER.UNIVERSAL && val.getTag() == 0)
 430:       {
 431:         if (version < 2)
 432:           throw new IOException("extra data in CRL");
 433:         DERValue exts = der.read();
 434:         if (!exts.isConstructed())
 435:           throw new IOException("malformed Extensions");
 436:         if (Configuration.DEBUG)
 437:           log.fine("start Extensions  len == " + exts.getLength());
 438:         int len = 0;
 439:         while (len < exts.getLength())
 440:           {
 441:             DERValue ext = der.read();
 442:             if (!ext.isConstructed())
 443:               throw new IOException("malformed Extension");
 444:             Extension e = new Extension(ext.getEncoded());
 445:             extensions.put(e.getOid(), e);
 446:             der.skip(ext.getLength());
 447:             len += ext.getEncodedLength();
 448:             if (Configuration.DEBUG)
 449:               log.fine("current count == " + len);
 450:           }
 451:         val = der.read();
 452:       }
 453: 
 454:     if (Configuration.DEBUG)
 455:       log.fine("read tag == " + val.getTag());
 456:     if (!val.isConstructed())
 457:       throw new IOException("malformed AlgorithmIdentifier");
 458:     if (Configuration.DEBUG)
 459:       log.fine("start AlgorithmIdentifier  len == " + val.getLength());
 460:     DERValue sigAlgVal = der.read();
 461:     if (Configuration.DEBUG)
 462:       log.fine("read tag == " + sigAlgVal.getTag());
 463:     if (sigAlgVal.getTag() != DER.OBJECT_IDENTIFIER)
 464:       throw new IOException("malformed AlgorithmIdentifier");
 465:     sigAlg = (OID) sigAlgVal.getValue();
 466:     if (Configuration.DEBUG)
 467:       {
 468:         log.fine("signature id == " + sigAlg);
 469:         log.fine("sigAlgVal length == " + sigAlgVal.getEncodedLength());
 470:       }
 471:     if (val.getLength() > sigAlgVal.getEncodedLength())
 472:       {
 473:         val = der.read();
 474:         if (Configuration.DEBUG)
 475:           log.fine("sig params tag = " + val.getTag() + " len == "
 476:                    + val.getEncodedLength());
 477:         sigAlgParams = (byte[]) val.getEncoded();
 478:         if (val.isConstructed())
 479:           in.skip(val.getLength());
 480:       }
 481:     val = der.read();
 482:     if (Configuration.DEBUG)
 483:       log.fine("read tag = " + val.getTag());
 484:     rawSig = val.getEncoded();
 485:     signature = ((BitString) val.getValue()).toByteArray();
 486:   }
 487: }