Merge from mainline (gomp-merge-2005-02-26).
[official-gcc.git] / libjava / gnu / java / security / x509 / X509Certificate.java
blob721439ef23839fe74aed861d692a319ea9fcece6
1 /* X509Certificate.java -- X.509 certificate.
2 Copyright (C) 2003, 2004 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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.
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.
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.
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.
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. */
39 package gnu.java.security.x509;
41 import java.io.InputStream;
42 import java.io.IOException;
43 import java.io.PrintWriter;
44 import java.io.Serializable;
45 import java.io.StringWriter;
47 import java.math.BigInteger;
49 import java.security.AlgorithmParameters;
50 import java.security.InvalidKeyException;
51 import java.security.KeyFactory;
52 import java.security.NoSuchAlgorithmException;
53 import java.security.NoSuchProviderException;
54 import java.security.Principal;
55 import java.security.PublicKey;
56 import java.security.Signature;
57 import java.security.SignatureException;
59 import java.security.cert.CertificateEncodingException;
60 import java.security.cert.CertificateException;
61 import java.security.cert.CertificateExpiredException;
62 import java.security.cert.CertificateNotYetValidException;
63 import java.security.cert.CertificateParsingException;
65 import java.security.interfaces.DSAParams;
66 import java.security.interfaces.DSAPublicKey;
67 import java.security.spec.DSAParameterSpec;
68 import java.security.spec.X509EncodedKeySpec;
70 import java.util.Arrays;
71 import java.util.ArrayList;
72 import java.util.Collection;
73 import java.util.Collections;
74 import java.util.Date;
75 import java.util.HashMap;
76 import java.util.HashSet;
77 import java.util.Iterator;
78 import java.util.List;
79 import java.util.Map;
80 import java.util.Set;
82 import javax.security.auth.x500.X500Principal;
84 import gnu.java.security.OID;
85 import gnu.java.security.der.*;
86 import gnu.java.security.x509.ext.*;
88 /**
89 * An implementation of X.509 certificates.
91 * @author Casey Marshall (rsdio@metastatic.org)
93 public class X509Certificate extends java.security.cert.X509Certificate
94 implements Serializable, GnuPKIExtension
97 // Constants and fields.
98 // ------------------------------------------------------------------------
100 private static final boolean DEBUG = false;
101 private static void debug(String msg)
103 if (DEBUG)
105 System.err.print(">> X509Certificate: ");
106 System.err.println(msg);
109 private static void debug(Throwable t)
111 if (DEBUG)
113 System.err.print(">> X509Certificate: ");
114 t.printStackTrace();
118 protected static final OID ID_DSA = new OID ("1.2.840.10040.4.1");
119 protected static final OID ID_DSA_WITH_SHA1 = new OID ("1.2.840.10040.4.3");
120 protected static final OID ID_RSA = new OID ("1.2.840.113549.1.1.1");
121 protected static final OID ID_RSA_WITH_MD2 = new OID ("1.2.840.113549.1.1.2");
122 protected static final OID ID_RSA_WITH_MD5 = new OID ("1.2.840.113549.1.1.4");
123 protected static final OID ID_RSA_WITH_SHA1 = new OID ("1.2.840.113549.1.1.5");
124 protected static final OID ID_ECDSA_WITH_SHA1 = new OID ("1.2.840.10045.4.1");
126 // This object SHOULD be serialized with an instance of
127 // java.security.cert.Certificate.CertificateRep, thus all fields are
128 // transient.
130 // The encoded certificate.
131 protected transient byte[] encoded;
133 // TBSCertificate part.
134 protected transient byte[] tbsCertBytes;
135 protected transient int version;
136 protected transient BigInteger serialNo;
137 protected transient OID algId;
138 protected transient byte[] algVal;
139 protected transient X500DistinguishedName issuer;
140 protected transient Date notBefore;
141 protected transient Date notAfter;
142 protected transient X500DistinguishedName subject;
143 protected transient PublicKey subjectKey;
144 protected transient BitString issuerUniqueId;
145 protected transient BitString subjectUniqueId;
146 protected transient Map extensions;
148 // Signature.
149 protected transient OID sigAlgId;
150 protected transient byte[] sigAlgVal;
151 protected transient byte[] signature;
153 // Constructors.
154 // ------------------------------------------------------------------------
157 * Create a new X.509 certificate from the encoded data. The input
158 * data are expected to be the ASN.1 DER encoding of the certificate.
160 * @param encoded The encoded certificate data.
161 * @throws IOException If the certificate cannot be read, possibly
162 * from a formatting error.
163 * @throws CertificateException If the data read is not an X.509
164 * certificate.
166 public X509Certificate(InputStream encoded)
167 throws CertificateException, IOException
169 super();
170 extensions = new HashMap();
173 parse(encoded);
175 catch (IOException ioe)
177 debug(ioe);
178 throw ioe;
180 catch (Exception e)
182 debug(e);
183 CertificateException ce = new CertificateException(e.getMessage());
184 ce.initCause (e);
185 throw ce;
189 protected X509Certificate()
191 extensions = new HashMap();
194 // X509Certificate methods.
195 // ------------------------------------------------------------------------
197 public void checkValidity()
198 throws CertificateExpiredException, CertificateNotYetValidException
200 checkValidity(new Date());
203 public void checkValidity(Date date)
204 throws CertificateExpiredException, CertificateNotYetValidException
206 if (date.compareTo(notBefore) < 0)
208 throw new CertificateNotYetValidException();
210 if (date.compareTo(notAfter) > 0)
212 throw new CertificateExpiredException();
216 public int getVersion()
218 return version;
221 public BigInteger getSerialNumber()
223 return serialNo;
226 public Principal getIssuerDN()
228 return issuer;
231 public X500Principal getIssuerX500Principal()
233 return new X500Principal(issuer.getDer());
236 public Principal getSubjectDN()
238 return subject;
241 public X500Principal getSubjectX500Principal()
243 return new X500Principal(subject.getDer());
246 public Date getNotBefore()
248 return (Date) notBefore.clone();
251 public Date getNotAfter()
253 return (Date) notAfter.clone();
256 public byte[] getTBSCertificate() throws CertificateEncodingException
258 return (byte[]) tbsCertBytes.clone();
261 public byte[] getSignature()
263 return (byte[]) signature.clone();
266 public String getSigAlgName()
268 if (sigAlgId.equals(ID_DSA_WITH_SHA1))
270 return "SHA1withDSA";
272 if (sigAlgId.equals(ID_RSA_WITH_MD2))
274 return "MD2withRSA";
276 if (sigAlgId.equals(ID_RSA_WITH_MD5))
278 return "MD5withRSA";
280 if (sigAlgId.equals(ID_RSA_WITH_SHA1))
282 return "SHA1withRSA";
284 return "unknown";
287 public String getSigAlgOID()
289 return sigAlgId.toString();
292 public byte[] getSigAlgParams()
294 return (byte[]) sigAlgVal.clone();
297 public boolean[] getIssuerUniqueID()
299 if (issuerUniqueId != null)
301 return issuerUniqueId.toBooleanArray();
303 return null;
306 public boolean[] getSubjectUniqueID()
308 if (subjectUniqueId != null)
310 return subjectUniqueId.toBooleanArray();
312 return null;
315 public boolean[] getKeyUsage()
317 Extension e = getExtension(KeyUsage.ID);
318 if (e != null)
320 KeyUsage ku = (KeyUsage) e.getValue();
321 boolean[] result = new boolean[9];
322 boolean[] b = ku.getKeyUsage().toBooleanArray();
323 System.arraycopy(b, 0, result, 0, b.length);
324 return result;
326 return null;
329 public List getExtendedKeyUsage() throws CertificateParsingException
331 Extension e = getExtension(ExtendedKeyUsage.ID);
332 if (e != null)
334 List a = ((ExtendedKeyUsage) e.getValue()).getPurposeIds();
335 List b = new ArrayList(a.size());
336 for (Iterator it = a.iterator(); it.hasNext(); )
338 b.add(it.next().toString());
340 return Collections.unmodifiableList(b);
342 return null;
345 public int getBasicConstraints()
347 Extension e = getExtension(BasicConstraints.ID);
348 if (e != null)
350 return ((BasicConstraints) e.getValue()).getPathLengthConstraint();
352 return -1;
355 public Collection getSubjectAlternativeNames()
356 throws CertificateParsingException
358 Extension e = getExtension(SubjectAlternativeNames.ID);
359 if (e != null)
361 return ((SubjectAlternativeNames) e.getValue()).getNames();
363 return null;
366 public Collection getIssuerAlternativeNames()
367 throws CertificateParsingException
369 Extension e = getExtension(IssuerAlternativeNames.ID);
370 if (e != null)
372 return ((IssuerAlternativeNames) e.getValue()).getNames();
374 return null;
377 \f// X509Extension methods.
378 // ------------------------------------------------------------------------
380 public boolean hasUnsupportedCriticalExtension()
382 for (Iterator it = extensions.values().iterator(); it.hasNext(); )
384 Extension e = (Extension) it.next();
385 if (e.isCritical() && !e.isSupported())
386 return true;
388 return false;
391 public Set getCriticalExtensionOIDs()
393 HashSet s = new HashSet();
394 for (Iterator it = extensions.values().iterator(); it.hasNext(); )
396 Extension e = (Extension) it.next();
397 if (e.isCritical())
398 s.add(e.getOid().toString());
400 return Collections.unmodifiableSet(s);
403 public Set getNonCriticalExtensionOIDs()
405 HashSet s = new HashSet();
406 for (Iterator it = extensions.values().iterator(); it.hasNext(); )
408 Extension e = (Extension) it.next();
409 if (!e.isCritical())
410 s.add(e.getOid().toString());
412 return Collections.unmodifiableSet(s);
415 public byte[] getExtensionValue(String oid)
417 Extension e = getExtension(new OID(oid));
418 if (e != null)
420 return e.getValue().getEncoded();
422 return null;
425 // GnuPKIExtension method.
426 // -------------------------------------------------------------------------
428 public Extension getExtension(OID oid)
430 return (Extension) extensions.get(oid);
433 public Collection getExtensions()
435 return extensions.values();
438 // Certificate methods.
439 // -------------------------------------------------------------------------
441 public byte[] getEncoded() throws CertificateEncodingException
443 return (byte[]) encoded.clone();
446 public void verify(PublicKey key)
447 throws CertificateException, NoSuchAlgorithmException,
448 InvalidKeyException, NoSuchProviderException, SignatureException
450 Signature sig = Signature.getInstance(sigAlgId.toString());
451 doVerify(sig, key);
454 public void verify(PublicKey key, String provider)
455 throws CertificateException, NoSuchAlgorithmException,
456 InvalidKeyException, NoSuchProviderException, SignatureException
458 Signature sig = Signature.getInstance(sigAlgId.toString(), provider);
459 doVerify(sig, key);
462 public String toString()
464 StringWriter str = new StringWriter();
465 PrintWriter out = new PrintWriter(str);
466 out.println(X509Certificate.class.getName() + " {");
467 out.println(" TBSCertificate {");
468 out.println(" version = " + version + ";");
469 out.println(" serialNo = " + serialNo + ";");
470 out.println(" signature = {");
471 out.println(" algorithm = " + getSigAlgName() + ";");
472 out.print(" parameters =");
473 if (sigAlgVal != null)
475 out.println();
476 out.print(Util.hexDump(sigAlgVal, " "));
478 else
480 out.println(" null;");
482 out.println(" }");
483 out.println(" issuer = " + issuer.getName() + ";");
484 out.println(" validity = {");
485 out.println(" notBefore = " + notBefore + ";");
486 out.println(" notAfter = " + notAfter + ";");
487 out.println(" }");
488 out.println(" subject = " + subject.getName() + ";");
489 out.println(" subjectPublicKeyInfo = {");
490 out.println(" algorithm = " + subjectKey.getAlgorithm());
491 out.println(" key =");
492 out.print(Util.hexDump(subjectKey.getEncoded(), " "));
493 out.println(" };");
494 out.println(" issuerUniqueId = " + issuerUniqueId + ";");
495 out.println(" subjectUniqueId = " + subjectUniqueId + ";");
496 out.println(" extensions = {");
497 for (Iterator it = extensions.values().iterator(); it.hasNext(); )
499 out.println(" " + it.next());
501 out.println(" }");
502 out.println(" }");
503 out.println(" signatureAlgorithm = " + getSigAlgName() + ";");
504 out.println(" signatureValue =");
505 out.print(Util.hexDump(signature, " "));
506 out.println("}");
507 return str.toString();
510 public PublicKey getPublicKey()
512 return subjectKey;
515 public boolean equals(Object other)
517 if (!(other instanceof X509Certificate))
518 return false;
521 if (other instanceof X509Certificate)
522 return Arrays.equals(encoded, ((X509Certificate) other).encoded);
523 byte[] enc = ((X509Certificate) other).getEncoded();
524 if (enc == null)
525 return false;
526 return Arrays.equals(encoded, enc);
528 catch (CertificateEncodingException cee)
530 return false;
534 // Own methods.
535 // ------------------------------------------------------------------------
538 * Verify this certificate's signature.
540 private void doVerify(Signature sig, PublicKey key)
541 throws CertificateException, InvalidKeyException, SignatureException
543 debug("verifying sig=" + sig + " key=" + key);
544 sig.initVerify(key);
545 sig.update(tbsCertBytes);
546 if (!sig.verify(signature))
548 throw new CertificateException("signature not validated");
553 * Parse a DER stream into an X.509 certificate.
555 * @param encoded The encoded bytes.
557 private void parse(InputStream encoded) throws Exception
559 DERReader der = new DERReader(encoded);
561 // Certificate ::= SEQUENCE {
562 DERValue cert = der.read();
563 debug("start Certificate len == " + cert.getLength());
565 this.encoded = cert.getEncoded();
566 if (!cert.isConstructed())
568 throw new IOException("malformed Certificate");
571 // TBSCertificate ::= SEQUENCE {
572 DERValue tbsCert = der.read();
573 if (tbsCert.getValue() != DER.CONSTRUCTED_VALUE)
575 throw new IOException("malformed TBSCertificate");
577 tbsCertBytes = tbsCert.getEncoded();
578 debug("start TBSCertificate len == " + tbsCert.getLength());
580 // Version ::= INTEGER [0] { v1(0), v2(1), v3(2) }
581 DERValue val = der.read();
582 if (val.getTagClass() == DER.CONTEXT && val.getTag() == 0)
584 version = ((BigInteger) der.read().getValue()).intValue() + 1;
585 val = der.read();
587 else
589 version = 1;
591 debug("read version == " + version);
593 // SerialNumber ::= INTEGER
594 serialNo = (BigInteger) val.getValue();
595 debug("read serial number == " + serialNo);
597 // AlgorithmIdentifier ::= SEQUENCE {
598 val = der.read();
599 if (!val.isConstructed())
601 throw new IOException("malformed AlgorithmIdentifier");
603 int certAlgLen = val.getLength();
604 debug("start AlgorithmIdentifier len == " + certAlgLen);
605 val = der.read();
607 // algorithm OBJECT IDENTIFIER,
608 algId = (OID) val.getValue();
609 debug("read algorithm ID == " + algId);
611 // parameters ANY DEFINED BY algorithm OPTIONAL }
612 if (certAlgLen > val.getEncodedLength())
614 val = der.read();
615 if (val == null)
617 algVal = null;
619 else
621 algVal = val.getEncoded();
623 if (val.isConstructed())
625 encoded.skip(val.getLength());
627 debug("read algorithm parameters == " + algVal);
630 // issuer Name,
631 val = der.read();
632 issuer = new X500DistinguishedName(val.getEncoded());
633 der.skip(val.getLength());
634 debug("read issuer == " + issuer);
636 // Validity ::= SEQUENCE {
637 // notBefore Time,
638 // notAfter Time }
639 if (!der.read().isConstructed())
641 throw new IOException("malformed Validity");
643 notBefore = (Date) der.read().getValue();
644 notAfter = (Date) der.read().getValue();
645 debug("read notBefore == " + notBefore);
646 debug("read notAfter == " + notAfter);
648 // subject Name,
649 val = der.read();
650 subject = new X500DistinguishedName(val.getEncoded());
651 der.skip(val.getLength());
652 debug("read subject == " + subject);
654 // SubjectPublicKeyInfo ::= SEQUENCE {
655 // algorithm AlgorithmIdentifier,
656 // subjectPublicKey BIT STRING }
657 DERValue spki = der.read();
658 if (!spki.isConstructed())
660 throw new IOException("malformed SubjectPublicKeyInfo");
662 KeyFactory spkFac = KeyFactory.getInstance("X.509");
663 subjectKey = spkFac.generatePublic(new X509EncodedKeySpec(spki.getEncoded()));
664 der.skip(spki.getLength());
665 debug("read subjectPublicKey == " + subjectKey);
667 if (version > 1)
669 val = der.read();
671 if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 1)
673 byte[] b = (byte[]) val.getValue();
674 issuerUniqueId = new BitString(b, 1, b.length-1, b[0] & 0xFF);
675 debug("read issuerUniqueId == " + issuerUniqueId);
676 val = der.read();
678 if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 2)
680 byte[] b = (byte[]) val.getValue();
681 subjectUniqueId = new BitString(b, 1, b.length-1, b[0] & 0xFF);
682 debug("read subjectUniqueId == " + subjectUniqueId);
683 val = der.read();
685 if (version >= 3 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 3)
687 val = der.read();
688 debug("start Extensions len == " + val.getLength());
689 int len = 0;
690 while (len < val.getLength())
692 DERValue ext = der.read();
693 debug("start extension len == " + ext.getLength());
694 Extension e = new Extension(ext.getEncoded());
695 extensions.put(e.getOid(), e);
696 der.skip(ext.getLength());
697 len += ext.getEncodedLength();
698 debug("count == " + len);
702 val = der.read();
703 if (!val.isConstructed())
705 throw new IOException("malformed AlgorithmIdentifier");
707 int sigAlgLen = val.getLength();
708 debug("start AlgorithmIdentifier len == " + sigAlgLen);
709 val = der.read();
710 sigAlgId = (OID) val.getValue();
711 debug("read algorithm id == " + sigAlgId);
712 if (sigAlgLen > val.getEncodedLength())
714 val = der.read();
715 if (val.getValue() == null)
717 if (subjectKey instanceof DSAPublicKey)
719 AlgorithmParameters params =
720 AlgorithmParameters.getInstance("DSA");
721 DSAParams dsap = ((DSAPublicKey) subjectKey).getParams();
722 DSAParameterSpec spec =
723 new DSAParameterSpec(dsap.getP(), dsap.getQ(), dsap.getG());
724 params.init(spec);
725 sigAlgVal = params.getEncoded();
728 else
730 sigAlgVal = (byte[]) val.getEncoded();
732 if (val.isConstructed())
734 encoded.skip(val.getLength());
736 debug("read parameters == " + sigAlgVal);
738 signature = ((BitString) der.read().getValue()).toByteArray();
739 debug("read signature ==\n" + Util.hexDump(signature, ">>>> "));