Source for gnu.java.security.x509.X509Certificate

   1: /* X509Certificate.java -- X.509 certificate.
   2:    Copyright (C) 2003, 2004, 2006  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.classpath.debug.Component;
  42: import gnu.classpath.debug.SystemLogger;
  43: 
  44: import gnu.java.security.OID;
  45: import gnu.java.security.der.BitString;
  46: import gnu.java.security.der.DER;
  47: import gnu.java.security.der.DERReader;
  48: import gnu.java.security.der.DERValue;
  49: import gnu.java.security.x509.ext.BasicConstraints;
  50: import gnu.java.security.x509.ext.ExtendedKeyUsage;
  51: import gnu.java.security.x509.ext.Extension;
  52: import gnu.java.security.x509.ext.IssuerAlternativeNames;
  53: import gnu.java.security.x509.ext.KeyUsage;
  54: import gnu.java.security.x509.ext.SubjectAlternativeNames;
  55: 
  56: import java.io.IOException;
  57: import java.io.InputStream;
  58: import java.io.PrintWriter;
  59: import java.io.Serializable;
  60: import java.io.StringWriter;
  61: import java.math.BigInteger;
  62: import java.security.AlgorithmParameters;
  63: import java.security.InvalidKeyException;
  64: import java.security.KeyFactory;
  65: import java.security.NoSuchAlgorithmException;
  66: import java.security.NoSuchProviderException;
  67: import java.security.Principal;
  68: import java.security.PublicKey;
  69: import java.security.Signature;
  70: import java.security.SignatureException;
  71: import java.security.cert.CertificateEncodingException;
  72: import java.security.cert.CertificateException;
  73: import java.security.cert.CertificateExpiredException;
  74: import java.security.cert.CertificateNotYetValidException;
  75: import java.security.cert.CertificateParsingException;
  76: import java.security.interfaces.DSAParams;
  77: import java.security.interfaces.DSAPublicKey;
  78: import java.security.spec.DSAParameterSpec;
  79: import java.security.spec.X509EncodedKeySpec;
  80: import java.util.ArrayList;
  81: import java.util.Arrays;
  82: import java.util.Collection;
  83: import java.util.Collections;
  84: import java.util.Date;
  85: import java.util.HashMap;
  86: import java.util.HashSet;
  87: import java.util.Iterator;
  88: import java.util.List;
  89: import java.util.Map;
  90: import java.util.Set;
  91: 
  92: import java.util.logging.Level;
  93: import java.util.logging.Logger;
  94: 
  95: import javax.security.auth.x500.X500Principal;
  96: 
  97: /**
  98:  * An implementation of X.509 certificates.
  99:  *
 100:  * @author Casey Marshall (rsdio@metastatic.org)
 101:  */
 102: public class X509Certificate extends java.security.cert.X509Certificate
 103:   implements Serializable, GnuPKIExtension
 104: {
 105: 
 106:   // Constants and fields.
 107:   // ------------------------------------------------------------------------
 108: 
 109:   private static final Logger logger = SystemLogger.SYSTEM;
 110: 
 111:   protected static final OID ID_DSA = new OID ("1.2.840.10040.4.1");
 112:   protected static final OID ID_DSA_WITH_SHA1 = new OID ("1.2.840.10040.4.3");
 113:   protected static final OID ID_RSA = new OID ("1.2.840.113549.1.1.1");
 114:   protected static final OID ID_RSA_WITH_MD2 = new OID ("1.2.840.113549.1.1.2");
 115:   protected static final OID ID_RSA_WITH_MD5 = new OID ("1.2.840.113549.1.1.4");
 116:   protected static final OID ID_RSA_WITH_SHA1 = new OID ("1.2.840.113549.1.1.5");
 117:   protected static final OID ID_ECDSA_WITH_SHA1 = new OID ("1.2.840.10045.4.1");
 118: 
 119:   // This object SHOULD be serialized with an instance of
 120:   // java.security.cert.Certificate.CertificateRep, thus all fields are
 121:   // transient.
 122: 
 123:   // The encoded certificate.
 124:   protected transient byte[] encoded;
 125: 
 126:   // TBSCertificate part.
 127:   protected transient byte[] tbsCertBytes;
 128:   protected transient int version;
 129:   protected transient BigInteger serialNo;
 130:   protected transient OID algId;
 131:   protected transient byte[] algVal;
 132:   protected transient X500DistinguishedName issuer;
 133:   protected transient Date notBefore;
 134:   protected transient Date notAfter;
 135:   protected transient X500DistinguishedName subject;
 136:   protected transient PublicKey subjectKey;
 137:   protected transient BitString issuerUniqueId;
 138:   protected transient BitString subjectUniqueId;
 139:   protected transient Map extensions;
 140: 
 141:   // Signature.
 142:   protected transient OID sigAlgId;
 143:   protected transient byte[] sigAlgVal;
 144:   protected transient byte[] signature;
 145: 
 146:   // Constructors.
 147:   // ------------------------------------------------------------------------
 148: 
 149:   /**
 150:    * Create a new X.509 certificate from the encoded data. The input
 151:    * data are expected to be the ASN.1 DER encoding of the certificate.
 152:    *
 153:    * @param encoded The encoded certificate data.
 154:    * @throws IOException If the certificate cannot be read, possibly
 155:    * from a formatting error.
 156:    * @throws CertificateException If the data read is not an X.509
 157:    * certificate.
 158:    */
 159:   public X509Certificate(InputStream encoded)
 160:     throws CertificateException, IOException
 161:   {
 162:     super();
 163:     extensions = new HashMap();
 164:     try
 165:       {
 166:         parse(encoded);
 167:       }
 168:     catch (IOException ioe)
 169:       {
 170:         logger.log (Component.X509, "", ioe);
 171:         throw ioe;
 172:       }
 173:     catch (Exception e)
 174:       {
 175:         logger.log (Component.X509, "", e);
 176:         CertificateException ce = new CertificateException(e.getMessage());
 177:         ce.initCause (e);
 178:         throw ce;
 179:       }
 180:   }
 181: 
 182:   protected X509Certificate()
 183:   {
 184:     extensions = new HashMap();
 185:   }
 186: 
 187:   // X509Certificate methods.
 188:   // ------------------------------------------------------------------------
 189: 
 190:   public void checkValidity()
 191:     throws CertificateExpiredException, CertificateNotYetValidException
 192:   {
 193:     checkValidity(new Date());
 194:   }
 195: 
 196:   public void checkValidity(Date date)
 197:     throws CertificateExpiredException, CertificateNotYetValidException
 198:   {
 199:     if (date.compareTo(notBefore) < 0)
 200:       {
 201:         throw new CertificateNotYetValidException();
 202:       }
 203:     if (date.compareTo(notAfter) > 0)
 204:       {
 205:         throw new CertificateExpiredException();
 206:       }
 207:   }
 208: 
 209:   public int getVersion()
 210:   {
 211:     return version;
 212:   }
 213: 
 214:   public BigInteger getSerialNumber()
 215:   {
 216:     return serialNo;
 217:   }
 218: 
 219:   public Principal getIssuerDN()
 220:   {
 221:     return issuer;
 222:   }
 223: 
 224:   public X500Principal getIssuerX500Principal()
 225:   {
 226:     return new X500Principal(issuer.getDer());
 227:   }
 228: 
 229:   public Principal getSubjectDN()
 230:   {
 231:     return subject;
 232:   }
 233: 
 234:   public X500Principal getSubjectX500Principal()
 235:   {
 236:     return new X500Principal(subject.getDer());
 237:   }
 238: 
 239:   public Date getNotBefore()
 240:   {
 241:     return (Date) notBefore.clone();
 242:   }
 243: 
 244:   public Date getNotAfter()
 245:   {
 246:     return (Date) notAfter.clone();
 247:   }
 248: 
 249:   public byte[] getTBSCertificate() throws CertificateEncodingException
 250:   {
 251:     return (byte[]) tbsCertBytes.clone();
 252:   }
 253: 
 254:   public byte[] getSignature()
 255:   {
 256:     return (byte[]) signature.clone();
 257:   }
 258: 
 259:   public String getSigAlgName()
 260:   {
 261:     if (sigAlgId.equals(ID_DSA_WITH_SHA1))
 262:       {
 263:         return "SHA1withDSA";
 264:       }
 265:     if (sigAlgId.equals(ID_RSA_WITH_MD2))
 266:       {
 267:         return "MD2withRSA";
 268:       }
 269:     if (sigAlgId.equals(ID_RSA_WITH_MD5))
 270:       {
 271:         return "MD5withRSA";
 272:       }
 273:     if (sigAlgId.equals(ID_RSA_WITH_SHA1))
 274:       {
 275:         return "SHA1withRSA";
 276:       }
 277:     return "unknown";
 278:   }
 279: 
 280:   public String getSigAlgOID()
 281:   {
 282:     return sigAlgId.toString();
 283:   }
 284: 
 285:   public byte[] getSigAlgParams()
 286:   {
 287:     return (byte[]) sigAlgVal.clone();
 288:   }
 289: 
 290:   public boolean[] getIssuerUniqueID()
 291:   {
 292:     if (issuerUniqueId != null)
 293:       {
 294:         return issuerUniqueId.toBooleanArray();
 295:       }
 296:     return null;
 297:   }
 298: 
 299:   public boolean[] getSubjectUniqueID()
 300:   {
 301:     if (subjectUniqueId != null)
 302:       {
 303:         return subjectUniqueId.toBooleanArray();
 304:       }
 305:     return null;
 306:   }
 307: 
 308:   public boolean[] getKeyUsage()
 309:   {
 310:     Extension e = getExtension(KeyUsage.ID);
 311:     if (e != null)
 312:       {
 313:         KeyUsage ku = (KeyUsage) e.getValue();
 314:         boolean[] result = new boolean[9];
 315:         boolean[] b = ku.getKeyUsage().toBooleanArray();
 316:         System.arraycopy(b, 0, result, 0, b.length);
 317:         return result;
 318:       }
 319:     return null;
 320:   }
 321: 
 322:   public List getExtendedKeyUsage() throws CertificateParsingException
 323:   {
 324:     Extension e = getExtension(ExtendedKeyUsage.ID);
 325:     if (e != null)
 326:       {
 327:         List a = ((ExtendedKeyUsage) e.getValue()).getPurposeIds();
 328:         List b = new ArrayList(a.size());
 329:         for (Iterator it = a.iterator(); it.hasNext(); )
 330:           {
 331:             b.add(it.next().toString());
 332:           }
 333:         return Collections.unmodifiableList(b);
 334:       }
 335:     return null;
 336:   }
 337: 
 338:   public int getBasicConstraints()
 339:   {
 340:     Extension e = getExtension(BasicConstraints.ID);
 341:     if (e != null)
 342:       {
 343:         return ((BasicConstraints) e.getValue()).getPathLengthConstraint();
 344:       }
 345:     return -1;
 346:   }
 347: 
 348:   public Collection getSubjectAlternativeNames()
 349:     throws CertificateParsingException
 350:   {
 351:     Extension e = getExtension(SubjectAlternativeNames.ID);
 352:     if (e != null)
 353:       {
 354:         return ((SubjectAlternativeNames) e.getValue()).getNames();
 355:       }
 356:     return null;
 357:   }
 358: 
 359:   public Collection getIssuerAlternativeNames()
 360:     throws CertificateParsingException
 361:   {
 362:     Extension e = getExtension(IssuerAlternativeNames.ID);
 363:     if (e != null)
 364:       {
 365:         return ((IssuerAlternativeNames) e.getValue()).getNames();
 366:       }
 367:     return null;
 368:   }
 369: 
 370: // X509Extension methods.
 371:   // ------------------------------------------------------------------------
 372: 
 373:   public boolean hasUnsupportedCriticalExtension()
 374:   {
 375:     for (Iterator it = extensions.values().iterator(); it.hasNext(); )
 376:       {
 377:         Extension e = (Extension) it.next();
 378:         if (e.isCritical() && !e.isSupported())
 379:           return true;
 380:       }
 381:     return false;
 382:   }
 383: 
 384:   public Set getCriticalExtensionOIDs()
 385:   {
 386:     HashSet s = new HashSet();
 387:     for (Iterator it = extensions.values().iterator(); it.hasNext(); )
 388:       {
 389:         Extension e = (Extension) it.next();
 390:         if (e.isCritical())
 391:           s.add(e.getOid().toString());
 392:       }
 393:     return Collections.unmodifiableSet(s);
 394:   }
 395: 
 396:   public Set getNonCriticalExtensionOIDs()
 397:   {
 398:     HashSet s = new HashSet();
 399:     for (Iterator it = extensions.values().iterator(); it.hasNext(); )
 400:       {
 401:         Extension e = (Extension) it.next();
 402:         if (!e.isCritical())
 403:           s.add(e.getOid().toString());
 404:       }
 405:     return Collections.unmodifiableSet(s);
 406:   }
 407: 
 408:   public byte[] getExtensionValue(String oid)
 409:   {
 410:     Extension e = getExtension(new OID(oid));
 411:     if (e != null)
 412:       {
 413:         return e.getValue().getEncoded();
 414:       }
 415:     return null;
 416:   }
 417: 
 418:   // GnuPKIExtension method.
 419:   // -------------------------------------------------------------------------
 420: 
 421:   public Extension getExtension(OID oid)
 422:   {
 423:     return (Extension) extensions.get(oid);
 424:   }
 425: 
 426:   public Collection getExtensions()
 427:   {
 428:     return extensions.values();
 429:   }
 430: 
 431:   // Certificate methods.
 432:   // -------------------------------------------------------------------------
 433: 
 434:   public byte[] getEncoded() throws CertificateEncodingException
 435:   {
 436:     return (byte[]) encoded.clone();
 437:   }
 438: 
 439:   public void verify(PublicKey key)
 440:     throws CertificateException, NoSuchAlgorithmException,
 441:            InvalidKeyException, NoSuchProviderException, SignatureException
 442:   {
 443:     Signature sig = Signature.getInstance(sigAlgId.toString());
 444:     doVerify(sig, key);
 445:   }
 446: 
 447:   public void verify(PublicKey key, String provider)
 448:     throws CertificateException, NoSuchAlgorithmException,
 449:            InvalidKeyException, NoSuchProviderException, SignatureException
 450:   {
 451:     Signature sig = Signature.getInstance(sigAlgId.toString(), provider);
 452:     doVerify(sig, key);
 453:   }
 454: 
 455:   public String toString()
 456:   {
 457:     StringWriter str = new StringWriter();
 458:     PrintWriter out = new PrintWriter(str);
 459:     out.println(X509Certificate.class.getName() + " {");
 460:     out.println("  TBSCertificate {");
 461:     out.println("    version = " + version + ";");
 462:     out.println("    serialNo = " + serialNo + ";");
 463:     out.println("    signature = {");
 464:     out.println("      algorithm = " + getSigAlgName() + ";");
 465:     out.print("      parameters =");
 466:     if (sigAlgVal != null)
 467:       {
 468:         out.println();
 469:         out.print(Util.hexDump(sigAlgVal, "        "));
 470:       }
 471:     else
 472:       {
 473:         out.println(" null;");
 474:       }
 475:     out.println("    }");
 476:     out.println("    issuer = " + issuer.getName() + ";");
 477:     out.println("    validity = {");
 478:     out.println("      notBefore = " + notBefore + ";");
 479:     out.println("      notAfter  = " + notAfter + ";");
 480:     out.println("    }");
 481:     out.println("    subject = " + subject.getName() + ";");
 482:     out.println("    subjectPublicKeyInfo = {");
 483:     out.println("      algorithm = " + subjectKey.getAlgorithm());
 484:     out.println("      key =");
 485:     out.print(Util.hexDump(subjectKey.getEncoded(), "        "));
 486:     out.println("    };");
 487:     out.println("    issuerUniqueId  = " + issuerUniqueId + ";");
 488:     out.println("    subjectUniqueId = " + subjectUniqueId + ";");
 489:     out.println("    extensions = {");
 490:     for (Iterator it = extensions.values().iterator(); it.hasNext(); )
 491:       {
 492:         out.println("      " + it.next());
 493:       }
 494:     out.println("    }");
 495:     out.println("  }");
 496:     out.println("  signatureAlgorithm = " + getSigAlgName() + ";");
 497:     out.println("  signatureValue =");
 498:     out.print(Util.hexDump(signature, "    "));
 499:     out.println("}");
 500:     return str.toString();
 501:   }
 502: 
 503:   public PublicKey getPublicKey()
 504:   {
 505:     return subjectKey;
 506:   }
 507: 
 508:   public boolean equals(Object other)
 509:   {
 510:     if (!(other instanceof X509Certificate))
 511:       return false;
 512:     try
 513:       {
 514:         if (other instanceof X509Certificate)
 515:           return Arrays.equals(encoded, ((X509Certificate) other).encoded);
 516:         byte[] enc = ((X509Certificate) other).getEncoded();
 517:         if (enc == null)
 518:           return false;
 519:         return Arrays.equals(encoded, enc);
 520:       }
 521:     catch (CertificateEncodingException cee)
 522:       {
 523:         return false;
 524:       }
 525:   }
 526: 
 527:   // Own methods.
 528:   // ------------------------------------------------------------------------
 529: 
 530:   /**
 531:    * Verify this certificate's signature.
 532:    */
 533:   private void doVerify(Signature sig, PublicKey key)
 534:     throws CertificateException, InvalidKeyException, SignatureException
 535:   {
 536:     logger.log (Component.X509, "verifying sig={0} key={1}",
 537:                 new Object[] { sig, key });
 538:     sig.initVerify(key);
 539:     sig.update(tbsCertBytes);
 540:     if (!sig.verify(signature))
 541:       {
 542:         throw new CertificateException("signature not validated");
 543:       }
 544:   }
 545: 
 546:   /**
 547:    * Parse a DER stream into an X.509 certificate.
 548:    *
 549:    * @param encoded The encoded bytes.
 550:    */
 551:   private void parse(InputStream encoded) throws Exception
 552:   {
 553:     DERReader der = new DERReader(encoded);
 554: 
 555:     // Certificate ::= SEQUENCE {
 556:     DERValue cert = der.read();
 557:     logger.log (Component.X509, "start Certificate  len == {0}",
 558:                 new Integer (cert.getLength()));
 559: 
 560:     this.encoded = cert.getEncoded();
 561:     if (!cert.isConstructed())
 562:       {
 563:         throw new IOException("malformed Certificate");
 564:       }
 565: 
 566:     // TBSCertificate ::= SEQUENCE {
 567:     DERValue tbsCert = der.read();
 568:     if (tbsCert.getValue() != DER.CONSTRUCTED_VALUE)
 569:       {
 570:         throw new IOException("malformed TBSCertificate");
 571:       }
 572:     tbsCertBytes = tbsCert.getEncoded();
 573:     logger.log (Component.X509, "start TBSCertificate  len == {0}",
 574:                 new Integer (tbsCert.getLength()));
 575: 
 576:     // Version ::= INTEGER [0] { v1(0), v2(1), v3(2) }
 577:     DERValue val = der.read();
 578:     if (val.getTagClass() == DER.CONTEXT && val.getTag() == 0)
 579:       {
 580:         version = ((BigInteger) der.read().getValue()).intValue() + 1;
 581:         val = der.read();
 582:       }
 583:     else
 584:       {
 585:         version = 1;
 586:       }
 587:     logger.log (Component.X509, "read version == {0}",
 588:                 new Integer (version));
 589: 
 590:     // SerialNumber ::= INTEGER
 591:     serialNo = (BigInteger) val.getValue();
 592:     logger.log (Component.X509, "read serial number == {0}", serialNo);
 593: 
 594:     // AlgorithmIdentifier ::= SEQUENCE {
 595:     val = der.read();
 596:     if (!val.isConstructed())
 597:       {
 598:         throw new IOException("malformed AlgorithmIdentifier");
 599:       }
 600:     int certAlgLen = val.getLength();
 601:     logger.log (Component.X509, "start AlgorithmIdentifier  len == {0}",
 602:                 new Integer (certAlgLen));
 603:     val = der.read();
 604: 
 605:     //   algorithm    OBJECT IDENTIFIER,
 606:     algId = (OID) val.getValue();
 607:     logger.log (Component.X509, "read algorithm ID == {0}", algId);
 608: 
 609:     //   parameters   ANY DEFINED BY algorithm OPTIONAL }
 610:     if (certAlgLen > val.getEncodedLength())
 611:       {
 612:         val = der.read();
 613:         if (val == null)
 614:           {
 615:             algVal = null;
 616:           }
 617:         else
 618:           {
 619:             algVal = val.getEncoded();
 620: 
 621:             if (val.isConstructed())
 622:               encoded.skip(val.getLength());
 623:           }
 624:         logger.log (Component.X509, "read algorithm parameters == {0}", algVal);
 625:       }
 626: 
 627:     // issuer   Name,
 628:     val = der.read();
 629:     issuer = new X500DistinguishedName(val.getEncoded());
 630:     der.skip(val.getLength());
 631:     logger.log (Component.X509, "read issuer == {0}", issuer);
 632: 
 633:     // Validity ::= SEQUENCE {
 634:     //   notBefore   Time,
 635:     //   notAfter    Time }
 636:     if (!der.read().isConstructed())
 637:       {
 638:         throw new IOException("malformed Validity");
 639:       }
 640:     notBefore = (Date) der.read().getValue();
 641:     logger.log (Component.X509, "read notBefore == {0}", notBefore);
 642:     notAfter  = (Date) der.read().getValue();
 643:     logger.log (Component.X509, "read notAfter == {0}", notAfter);
 644: 
 645:     // subject   Name,
 646:     val = der.read();
 647:     subject = new X500DistinguishedName(val.getEncoded());
 648:     der.skip(val.getLength());
 649:     logger.log (Component.X509, "read subject == {0}", subject);
 650: 
 651:     // SubjectPublicKeyInfo ::= SEQUENCE {
 652:     //   algorithm         AlgorithmIdentifier,
 653:     //   subjectPublicKey  BIT STRING }
 654:     DERValue spki = der.read();
 655:     if (!spki.isConstructed())
 656:       {
 657:         throw new IOException("malformed SubjectPublicKeyInfo");
 658:       }
 659:     KeyFactory spkFac = KeyFactory.getInstance("X.509");
 660:     subjectKey = spkFac.generatePublic(new X509EncodedKeySpec(spki.getEncoded()));
 661:     der.skip(spki.getLength());
 662:     logger.log (Component.X509, "read subjectPublicKey == {0}", subjectKey);
 663: 
 664:     val = der.read();
 665:     if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 1)
 666:       {
 667:         byte[] b = (byte[]) val.getValue();
 668:         issuerUniqueId = new BitString(b, 1, b.length-1, b[0] & 0xFF);
 669:         logger.log (Component.X509, "read issuerUniqueId == {0}", issuerUniqueId);
 670:         val = der.read();
 671:       }
 672:     if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 2)
 673:       {
 674:         byte[] b = (byte[]) val.getValue();
 675:         subjectUniqueId = new BitString(b, 1, b.length-1, b[0] & 0xFF);
 676:         logger.log (Component.X509, "read subjectUniqueId == {0}", subjectUniqueId);
 677:         val = der.read();
 678:       }
 679:     if (version >= 3 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 3)
 680:       {
 681:         val = der.read();
 682:         logger.log (Component.X509, "start Extensions  len == {0}",
 683:                     new Integer (val.getLength()));
 684:         int len = 0;
 685:         while (len < val.getLength())
 686:           {
 687:             DERValue ext = der.read();
 688:             logger.log (Component.X509, "start extension  len == {0}",
 689:                         new Integer (ext.getLength()));
 690:             Extension e = new Extension(ext.getEncoded());
 691:             extensions.put(e.getOid(), e);
 692:             der.skip(ext.getLength());
 693:             len += ext.getEncodedLength();
 694:             logger.log (Component.X509, "read extension {0} == {1}",
 695:                         new Object[] { e.getOid (), e });
 696:             logger.log (Component.X509, "count == {0}", new Integer (len));
 697:           }
 698: 
 699:         val = der.read ();
 700:       }
 701: 
 702:     logger.log (Component.X509, "read value {0}", val);
 703:     if (!val.isConstructed())
 704:       {
 705:         throw new CertificateException ("malformed AlgorithmIdentifier");
 706:       }
 707:     int sigAlgLen = val.getLength();
 708:     logger.log (Component.X509, "start AlgorithmIdentifier  len == {0}",
 709:                 new Integer (sigAlgLen));
 710:     val = der.read();
 711:     sigAlgId = (OID) val.getValue();
 712:     logger.log (Component.X509, "read algorithm id == {0}", sigAlgId);
 713:     if (sigAlgLen > val.getEncodedLength())
 714:       {
 715:         val = der.read();
 716:         if (val.getValue() == null)
 717:           {
 718:             if (subjectKey instanceof DSAPublicKey)
 719:               {
 720:                 AlgorithmParameters params =
 721:                   AlgorithmParameters.getInstance("DSA");
 722:                 DSAParams dsap = ((DSAPublicKey) subjectKey).getParams();
 723:                 DSAParameterSpec spec =
 724:                   new DSAParameterSpec(dsap.getP(), dsap.getQ(), dsap.getG());
 725:                 params.init(spec);
 726:                 sigAlgVal = params.getEncoded();
 727:               }
 728:           }
 729:         else
 730:           {
 731:             sigAlgVal = (byte[]) val.getEncoded();
 732:           }
 733:         if (val.isConstructed())
 734:           {
 735:             encoded.skip(val.getLength());
 736:           }
 737:         logger.log (Component.X509, "read parameters == {0}", sigAlgVal);
 738:       }
 739:     signature = ((BitString) der.read().getValue()).toByteArray();
 740:     logger.log (Component.X509, "read signature ==\n{0}", Util.hexDump(signature, ">>>> "));
 741:   }
 742: }