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