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)
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., 51 Franklin Street, Fifth Floor, Boston, MA
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
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 gnu
.classpath
.debug
.Component
;
42 import gnu
.classpath
.debug
.SystemLogger
;
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
;
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
;
92 import java
.util
.logging
.Level
;
93 import java
.util
.logging
.Logger
;
95 import javax
.security
.auth
.x500
.X500Principal
;
98 * An implementation of X.509 certificates.
100 * @author Casey Marshall (rsdio@metastatic.org)
102 public class X509Certificate
extends java
.security
.cert
.X509Certificate
103 implements Serializable
, GnuPKIExtension
106 // Constants and fields.
107 // ------------------------------------------------------------------------
109 private static final Logger logger
= SystemLogger
.SYSTEM
;
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");
119 // This object SHOULD be serialized with an instance of
120 // java.security.cert.Certificate.CertificateRep, thus all fields are
123 // The encoded certificate.
124 protected transient byte[] encoded
;
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
;
142 protected transient OID sigAlgId
;
143 protected transient byte[] sigAlgVal
;
144 protected transient byte[] signature
;
147 // ------------------------------------------------------------------------
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.
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
159 public X509Certificate(InputStream encoded
)
160 throws CertificateException
, IOException
163 extensions
= new HashMap();
168 catch (IOException ioe
)
170 logger
.log (Component
.X509
, "", ioe
);
175 logger
.log (Component
.X509
, "", e
);
176 CertificateException ce
= new CertificateException(e
.getMessage());
182 protected X509Certificate()
184 extensions
= new HashMap();
187 // X509Certificate methods.
188 // ------------------------------------------------------------------------
190 public void checkValidity()
191 throws CertificateExpiredException
, CertificateNotYetValidException
193 checkValidity(new Date());
196 public void checkValidity(Date date
)
197 throws CertificateExpiredException
, CertificateNotYetValidException
199 if (date
.compareTo(notBefore
) < 0)
201 throw new CertificateNotYetValidException();
203 if (date
.compareTo(notAfter
) > 0)
205 throw new CertificateExpiredException();
209 public int getVersion()
214 public BigInteger
getSerialNumber()
219 public Principal
getIssuerDN()
224 public X500Principal
getIssuerX500Principal()
226 return new X500Principal(issuer
.getDer());
229 public Principal
getSubjectDN()
234 public X500Principal
getSubjectX500Principal()
236 return new X500Principal(subject
.getDer());
239 public Date
getNotBefore()
241 return (Date
) notBefore
.clone();
244 public Date
getNotAfter()
246 return (Date
) notAfter
.clone();
249 public byte[] getTBSCertificate() throws CertificateEncodingException
251 return (byte[]) tbsCertBytes
.clone();
254 public byte[] getSignature()
256 return (byte[]) signature
.clone();
259 public String
getSigAlgName()
261 if (sigAlgId
.equals(ID_DSA_WITH_SHA1
))
263 return "SHA1withDSA";
265 if (sigAlgId
.equals(ID_RSA_WITH_MD2
))
269 if (sigAlgId
.equals(ID_RSA_WITH_MD5
))
273 if (sigAlgId
.equals(ID_RSA_WITH_SHA1
))
275 return "SHA1withRSA";
280 public String
getSigAlgOID()
282 return sigAlgId
.toString();
285 public byte[] getSigAlgParams()
287 return (byte[]) sigAlgVal
.clone();
290 public boolean[] getIssuerUniqueID()
292 if (issuerUniqueId
!= null)
294 return issuerUniqueId
.toBooleanArray();
299 public boolean[] getSubjectUniqueID()
301 if (subjectUniqueId
!= null)
303 return subjectUniqueId
.toBooleanArray();
308 public boolean[] getKeyUsage()
310 Extension e
= getExtension(KeyUsage
.ID
);
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
);
322 public List
getExtendedKeyUsage() throws CertificateParsingException
324 Extension e
= getExtension(ExtendedKeyUsage
.ID
);
327 List a
= ((ExtendedKeyUsage
) e
.getValue()).getPurposeIds();
328 List b
= new ArrayList(a
.size());
329 for (Iterator it
= a
.iterator(); it
.hasNext(); )
331 b
.add(it
.next().toString());
333 return Collections
.unmodifiableList(b
);
338 public int getBasicConstraints()
340 Extension e
= getExtension(BasicConstraints
.ID
);
343 return ((BasicConstraints
) e
.getValue()).getPathLengthConstraint();
348 public Collection
getSubjectAlternativeNames()
349 throws CertificateParsingException
351 Extension e
= getExtension(SubjectAlternativeNames
.ID
);
354 return ((SubjectAlternativeNames
) e
.getValue()).getNames();
359 public Collection
getIssuerAlternativeNames()
360 throws CertificateParsingException
362 Extension e
= getExtension(IssuerAlternativeNames
.ID
);
365 return ((IssuerAlternativeNames
) e
.getValue()).getNames();
370 \f// X509Extension methods.
371 // ------------------------------------------------------------------------
373 public boolean hasUnsupportedCriticalExtension()
375 for (Iterator it
= extensions
.values().iterator(); it
.hasNext(); )
377 Extension e
= (Extension
) it
.next();
378 if (e
.isCritical() && !e
.isSupported())
384 public Set
getCriticalExtensionOIDs()
386 HashSet s
= new HashSet();
387 for (Iterator it
= extensions
.values().iterator(); it
.hasNext(); )
389 Extension e
= (Extension
) it
.next();
391 s
.add(e
.getOid().toString());
393 return Collections
.unmodifiableSet(s
);
396 public Set
getNonCriticalExtensionOIDs()
398 HashSet s
= new HashSet();
399 for (Iterator it
= extensions
.values().iterator(); it
.hasNext(); )
401 Extension e
= (Extension
) it
.next();
403 s
.add(e
.getOid().toString());
405 return Collections
.unmodifiableSet(s
);
408 public byte[] getExtensionValue(String oid
)
410 Extension e
= getExtension(new OID(oid
));
413 return e
.getValue().getEncoded();
418 // GnuPKIExtension method.
419 // -------------------------------------------------------------------------
421 public Extension
getExtension(OID oid
)
423 return (Extension
) extensions
.get(oid
);
426 public Collection
getExtensions()
428 return extensions
.values();
431 // Certificate methods.
432 // -------------------------------------------------------------------------
434 public byte[] getEncoded() throws CertificateEncodingException
436 return (byte[]) encoded
.clone();
439 public void verify(PublicKey key
)
440 throws CertificateException
, NoSuchAlgorithmException
,
441 InvalidKeyException
, NoSuchProviderException
, SignatureException
443 Signature sig
= Signature
.getInstance(sigAlgId
.toString());
447 public void verify(PublicKey key
, String provider
)
448 throws CertificateException
, NoSuchAlgorithmException
,
449 InvalidKeyException
, NoSuchProviderException
, SignatureException
451 Signature sig
= Signature
.getInstance(sigAlgId
.toString(), provider
);
455 public String
toString()
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)
469 out
.print(Util
.hexDump(sigAlgVal
, " "));
473 out
.println(" null;");
476 out
.println(" issuer = " + issuer
.getName() + ";");
477 out
.println(" validity = {");
478 out
.println(" notBefore = " + notBefore
+ ";");
479 out
.println(" notAfter = " + notAfter
+ ";");
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(), " "));
487 out
.println(" issuerUniqueId = " + issuerUniqueId
+ ";");
488 out
.println(" subjectUniqueId = " + subjectUniqueId
+ ";");
489 out
.println(" extensions = {");
490 for (Iterator it
= extensions
.values().iterator(); it
.hasNext(); )
492 out
.println(" " + it
.next());
496 out
.println(" signatureAlgorithm = " + getSigAlgName() + ";");
497 out
.println(" signatureValue =");
498 out
.print(Util
.hexDump(signature
, " "));
500 return str
.toString();
503 public PublicKey
getPublicKey()
508 public boolean equals(Object other
)
510 if (!(other
instanceof X509Certificate
))
514 if (other
instanceof X509Certificate
)
515 return Arrays
.equals(encoded
, ((X509Certificate
) other
).encoded
);
516 byte[] enc
= ((X509Certificate
) other
).getEncoded();
519 return Arrays
.equals(encoded
, enc
);
521 catch (CertificateEncodingException cee
)
528 // ------------------------------------------------------------------------
531 * Verify this certificate's signature.
533 private void doVerify(Signature sig
, PublicKey key
)
534 throws CertificateException
, InvalidKeyException
, SignatureException
536 logger
.log (Component
.X509
, "verifying sig={0} key={1}",
537 new Object
[] { sig
, key
});
539 sig
.update(tbsCertBytes
);
540 if (!sig
.verify(signature
))
542 throw new CertificateException("signature not validated");
547 * Parse a DER stream into an X.509 certificate.
549 * @param encoded The encoded bytes.
551 private void parse(InputStream encoded
) throws Exception
553 DERReader der
= new DERReader(encoded
);
555 // Certificate ::= SEQUENCE {
556 DERValue cert
= der
.read();
557 logger
.log (Component
.X509
, "start Certificate len == {0}",
558 new Integer (cert
.getLength()));
560 this.encoded
= cert
.getEncoded();
561 if (!cert
.isConstructed())
563 throw new IOException("malformed Certificate");
566 // TBSCertificate ::= SEQUENCE {
567 DERValue tbsCert
= der
.read();
568 if (tbsCert
.getValue() != DER
.CONSTRUCTED_VALUE
)
570 throw new IOException("malformed TBSCertificate");
572 tbsCertBytes
= tbsCert
.getEncoded();
573 logger
.log (Component
.X509
, "start TBSCertificate len == {0}",
574 new Integer (tbsCert
.getLength()));
576 // Version ::= INTEGER [0] { v1(0), v2(1), v3(2) }
577 DERValue val
= der
.read();
578 if (val
.getTagClass() == DER
.CONTEXT
&& val
.getTag() == 0)
580 version
= ((BigInteger
) der
.read().getValue()).intValue() + 1;
587 logger
.log (Component
.X509
, "read version == {0}",
588 new Integer (version
));
590 // SerialNumber ::= INTEGER
591 serialNo
= (BigInteger
) val
.getValue();
592 logger
.log (Component
.X509
, "read serial number == {0}", serialNo
);
594 // AlgorithmIdentifier ::= SEQUENCE {
596 if (!val
.isConstructed())
598 throw new IOException("malformed AlgorithmIdentifier");
600 int certAlgLen
= val
.getLength();
601 logger
.log (Component
.X509
, "start AlgorithmIdentifier len == {0}",
602 new Integer (certAlgLen
));
605 // algorithm OBJECT IDENTIFIER,
606 algId
= (OID
) val
.getValue();
607 logger
.log (Component
.X509
, "read algorithm ID == {0}", algId
);
609 // parameters ANY DEFINED BY algorithm OPTIONAL }
610 if (certAlgLen
> val
.getEncodedLength())
619 algVal
= val
.getEncoded();
621 if (val
.isConstructed())
622 encoded
.skip(val
.getLength());
624 logger
.log (Component
.X509
, "read algorithm parameters == {0}", algVal
);
629 issuer
= new X500DistinguishedName(val
.getEncoded());
630 der
.skip(val
.getLength());
631 logger
.log (Component
.X509
, "read issuer == {0}", issuer
);
633 // Validity ::= SEQUENCE {
636 if (!der
.read().isConstructed())
638 throw new IOException("malformed Validity");
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
);
647 subject
= new X500DistinguishedName(val
.getEncoded());
648 der
.skip(val
.getLength());
649 logger
.log (Component
.X509
, "read subject == {0}", subject
);
651 // SubjectPublicKeyInfo ::= SEQUENCE {
652 // algorithm AlgorithmIdentifier,
653 // subjectPublicKey BIT STRING }
654 DERValue spki
= der
.read();
655 if (!spki
.isConstructed())
657 throw new IOException("malformed SubjectPublicKeyInfo");
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
);
668 if (version
>= 2 && val
.getTagClass() != DER
.UNIVERSAL
&& val
.getTag() == 1)
670 byte[] b
= (byte[]) val
.getValue();
671 issuerUniqueId
= new BitString(b
, 1, b
.length
-1, b
[0] & 0xFF);
672 logger
.log (Component
.X509
, "read issuerUniqueId == {0}", issuerUniqueId
);
675 if (version
>= 2 && val
.getTagClass() != DER
.UNIVERSAL
&& val
.getTag() == 2)
677 byte[] b
= (byte[]) val
.getValue();
678 subjectUniqueId
= new BitString(b
, 1, b
.length
-1, b
[0] & 0xFF);
679 logger
.log (Component
.X509
, "read subjectUniqueId == {0}", subjectUniqueId
);
682 if (version
>= 3 && val
.getTagClass() != DER
.UNIVERSAL
&& val
.getTag() == 3)
685 logger
.log (Component
.X509
, "start Extensions len == {0}",
686 new Integer (val
.getLength()));
688 while (len
< val
.getLength())
690 DERValue ext
= der
.read();
691 logger
.log (Component
.X509
, "start extension len == {0}",
692 new Integer (ext
.getLength()));
693 Extension e
= new Extension(ext
.getEncoded());
694 extensions
.put(e
.getOid(), e
);
695 der
.skip(ext
.getLength());
696 len
+= ext
.getEncodedLength();
697 logger
.log (Component
.X509
, "read extension {0} == {1}",
698 new Object
[] { e
.getOid (), e
});
699 logger
.log (Component
.X509
, "count == {0}", new Integer (len
));
705 logger
.log (Component
.X509
, "read value {0}", val
);
706 if (!val
.isConstructed())
708 throw new CertificateException ("malformed AlgorithmIdentifier");
710 int sigAlgLen
= val
.getLength();
711 logger
.log (Component
.X509
, "start AlgorithmIdentifier len == {0}",
712 new Integer (sigAlgLen
));
714 sigAlgId
= (OID
) val
.getValue();
715 logger
.log (Component
.X509
, "read algorithm id == {0}", sigAlgId
);
716 if (sigAlgLen
> val
.getEncodedLength())
719 if (val
.getValue() == null)
721 if (subjectKey
instanceof DSAPublicKey
)
723 AlgorithmParameters params
=
724 AlgorithmParameters
.getInstance("DSA");
725 DSAParams dsap
= ((DSAPublicKey
) subjectKey
).getParams();
726 DSAParameterSpec spec
=
727 new DSAParameterSpec(dsap
.getP(), dsap
.getQ(), dsap
.getG());
729 sigAlgVal
= params
.getEncoded();
734 sigAlgVal
= (byte[]) val
.getEncoded();
736 if (val
.isConstructed())
738 encoded
.skip(val
.getLength());
740 logger
.log (Component
.X509
, "read parameters == {0}", sigAlgVal
);
742 signature
= ((BitString
) der
.read().getValue()).toByteArray();
743 logger
.log (Component
.X509
, "read signature ==\n{0}", Util
.hexDump(signature
, ">>>> "));