2003-12-26 Guilhem Lavaux <guilhem@kaffe.org>
[official-gcc.git] / libjava / gnu / java / security / x509 / X509Certificate.java
blob1ec2e87c2c6cfea2561960c6e78e7c659d688014
1 /* X509Certificate.java -- X.509 certificate.
2 Copyright (C) 2003 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.ByteArrayInputStream;
42 import java.io.InputStream;
43 import java.io.IOException;
44 import java.io.ObjectStreamException;
45 import java.io.Serializable;
47 import java.math.BigInteger;
49 import java.net.InetAddress;
51 import java.security.AlgorithmParameters;
52 import java.security.InvalidKeyException;
53 import java.security.KeyFactory;
54 import java.security.NoSuchAlgorithmException;
55 import java.security.NoSuchProviderException;
56 import java.security.Principal;
57 import java.security.PublicKey;
58 import java.security.Signature;
59 import java.security.SignatureException;
61 import java.security.cert.CertificateEncodingException;
62 import java.security.cert.CertificateException;
63 import java.security.cert.CertificateExpiredException;
64 import java.security.cert.CertificateNotYetValidException;
65 import java.security.cert.CertificateParsingException;
67 import java.security.spec.DSAParameterSpec;
68 import java.security.spec.DSAPublicKeySpec;
69 import java.security.spec.RSAPublicKeySpec;
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.LinkedList;
79 import java.util.List;
80 import java.util.Set;
82 import javax.security.auth.x500.X500Principal;
84 import gnu.java.io.ASN1ParsingException;
85 import gnu.java.security.OID;
86 import gnu.java.security.der.BitString;
87 import gnu.java.security.der.DER;
88 import gnu.java.security.der.DERReader;
89 import gnu.java.security.der.DERValue;
90 import gnu.java.security.der.DERWriter;
92 /**
93 * An implementation of X.509 certificates.
95 * @author Casey Marshall (rsdio@metastatic.org)
97 public class X509Certificate extends java.security.cert.X509Certificate
98 implements Serializable
101 // Constants and fields.
102 // ------------------------------------------------------------------------
104 private static final OID ID_DSA = new OID("1.2.840.10040.4.1");
105 private static final OID ID_DSA_WITH_SHA1 = new OID("1.2.840.10040.4.3");
106 private static final OID ID_RSA = new OID("1.2.840.113549.1.1.1");
107 private static final OID ID_RSA_WITH_MD2 = new OID("1.2.840.113549.1.1.2");
108 private static final OID ID_RSA_WITH_MD5 = new OID("1.2.840.113549.1.1.4");
109 private static final OID ID_RSA_WITH_SHA1 = new OID("1.2.840.113549.1.1.5");
111 private static final OID ID_EXTENSION = new OID("2.5.29");
112 private static final OID ID_KEY_USAGE = ID_EXTENSION.getChild(15);
113 private static final OID ID_BASIC_CONSTRAINTS = ID_EXTENSION.getChild(19);
114 private static final OID ID_EXT_KEY_USAGE = ID_EXTENSION.getChild(37);
116 private static final int OTHER_NAME = 0;
117 private static final int RFC882_NAME = 1;
118 private static final int DNS_NAME = 2;
119 private static final int X400_ADDRESS = 3;
120 private static final int DIRECTORY_NAME = 4;
121 private static final int EDI_PARTY_NAME = 5;
122 private static final int URI = 6;
123 private static final int IP_ADDRESS = 7;
124 private static final int REGISTERED_ID = 8;
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 private transient byte[] encoded;
133 // TBSCertificate part.
134 private transient byte[] tbsCertBytes;
135 private transient int version;
136 private transient BigInteger serialNo;
137 private transient OID algId;
138 private transient byte[] algVal;
139 private transient X500Principal issuer;
140 private transient Date notBefore;
141 private transient Date notAfter;
142 private transient X500Principal subject;
143 private transient PublicKey subjectKey;
144 private transient BitString issuerUniqueId;
145 private transient BitString subjectUniqueId;
146 private transient HashMap extensions;
147 private transient HashSet critOids;
148 private transient HashSet nonCritOids;
150 private transient BitString keyUsage;
151 private transient int basicConstraints = -1;
153 // Signature.
154 private transient OID sigAlgId;
155 private transient byte[] sigAlgVal;
156 private transient byte[] signature;
158 // Constructors.
159 // ------------------------------------------------------------------------
162 * Create a new X.509 certificate from the encoded data. The input
163 * data are expected to be the ASN.1 DER encoding of the certificate.
165 * @param encoded The encoded certificate data.
166 * @throws IOException If the certificate cannot be read, possibly
167 * from a formatting error.
168 * @throws CertificateException If the data read is not an X.509
169 * certificate.
171 public X509Certificate(InputStream encoded)
172 throws CertificateException, IOException
174 super();
175 extensions = new HashMap();
176 critOids = new HashSet();
177 nonCritOids = new HashSet();
180 parse(encoded);
182 catch (IOException ioe)
184 throw ioe;
186 catch (Exception e)
188 throw new CertificateException(e.toString());
192 // X509Certificate methods.
193 // ------------------------------------------------------------------------
195 public void checkValidity()
196 throws CertificateExpiredException, CertificateNotYetValidException
198 checkValidity(new Date());
201 public void checkValidity(Date date)
202 throws CertificateExpiredException, CertificateNotYetValidException
204 if (date.compareTo(notBefore) < 0)
205 throw new CertificateNotYetValidException();
206 if (date.compareTo(notAfter) > 0)
207 throw new CertificateExpiredException();
210 public int getVersion()
212 return version;
215 public BigInteger getSerialNumber()
217 return serialNo;
220 public Principal getIssuerDN()
222 return getIssuerX500Principal();
225 public X500Principal getIssuerX500Principal()
227 return issuer;
230 public Principal getSubjectDN()
232 return getSubjectX500Principal();
235 public X500Principal getSubjectX500Principal()
237 return subject;
240 public Date getNotBefore()
242 return (Date) notBefore.clone();
245 public Date getNotAfter()
247 return (Date) notAfter.clone();
250 public byte[] getTBSCertificate() throws CertificateEncodingException
252 return (byte[]) tbsCertBytes.clone();
255 public byte[] getSignature()
257 return (byte[]) signature.clone();
260 public String getSigAlgName()
262 if (sigAlgId.equals(ID_DSA_WITH_SHA1))
263 return "SHA1withDSA";
264 if (sigAlgId.equals(ID_RSA_WITH_MD2 ))
265 return "MD2withRSA";
266 if (sigAlgId.equals(ID_RSA_WITH_MD5 ))
267 return "MD5withRSA";
268 if (sigAlgId.equals(ID_RSA_WITH_SHA1 ))
269 return "SHA1withRSA";
270 return "unknown";
271 // return sigAlgId.getShortName();
274 public String getSigAlgOID()
276 return sigAlgId.toString();
279 public byte[] getSigAlgParams()
281 return (byte[]) sigAlgVal.clone();
284 public boolean[] getIssuerUniqueID()
286 if (issuerUniqueId != null)
287 return issuerUniqueId.toBooleanArray();
288 return null;
291 public boolean[] getSubjectUniqueID()
293 if (subjectUniqueId != null)
294 return subjectUniqueId.toBooleanArray();
295 return null;
298 public boolean[] getKeyUsage()
300 if (keyUsage != null)
301 return keyUsage.toBooleanArray();
302 return null;
305 public List getExtendedKeyUsage() throws CertificateParsingException
307 byte[] ext = (byte[]) extensions.get("2.5.29.37");
308 if (ext == null)
309 return null;
310 LinkedList usages = new LinkedList();
313 DERReader der = new DERReader(new ByteArrayInputStream(ext));
314 DERValue seq = der.read();
315 if (!seq.isConstructed())
316 throw new CertificateParsingException();
317 int len = 0;
318 while (len < seq.getLength())
320 DERValue oid = der.read();
321 if (!(oid.getValue() instanceof OID))
322 throw new CertificateParsingException();
323 usages.add(oid.getValue().toString());
324 len += DERWriter.definiteEncodingSize(oid.getLength())
325 + oid.getLength() + 1;
328 catch (IOException ioe)
330 throw new CertificateParsingException();
332 return usages;
335 public int getBasicConstraints()
337 return basicConstraints;
340 public Collection getSubjectAlternativeNames()
341 throws CertificateParsingException
343 byte[] ext = getExtensionValue("2.5.29.17");
344 if (ext == null)
345 return null;
346 return getAltNames(ext);
349 public Collection getIssuerAlternativeNames()
350 throws CertificateParsingException
352 byte[] ext = getExtensionValue("2.5.29.18");
353 if (ext == null)
354 return null;
355 return getAltNames(ext);
358 \f// X509Extension methods.
359 // ------------------------------------------------------------------------
361 public boolean hasUnsupportedCriticalExtension()
363 for (Iterator it = critOids.iterator(); it.hasNext(); )
365 String oid = (String) it.next();
366 if (!oid.equals("2.5.29.15") && !oid.equals("2.5.29.17") &&
367 !oid.equals("2.5.29.18") && !oid.equals("2.5.29.19") &&
368 !oid.equals("2.5.29.37"))
369 return true;
371 return false;
374 public Set getCriticalExtensionOIDs()
376 return Collections.unmodifiableSet(critOids);
379 public Set getNonCriticalExtensionOIDs()
381 return Collections.unmodifiableSet(nonCritOids);
384 public byte[] getExtensionValue(String oid)
386 byte[] ext = (byte[]) extensions.get(oid);
387 if (ext != null)
388 return (byte[]) ext.clone();
389 return null;
392 // Certificate methods.
393 // ------------------------------------------------------------------------
395 public byte[] getEncoded() throws CertificateEncodingException
397 return (byte[]) encoded.clone();
400 public void verify(PublicKey key)
401 throws CertificateException, NoSuchAlgorithmException,
402 InvalidKeyException, NoSuchProviderException, SignatureException
404 Signature sig = Signature.getInstance(sigAlgId.toString());
405 doVerify(sig, key);
408 public void verify(PublicKey key, String provider)
409 throws CertificateException, NoSuchAlgorithmException,
410 InvalidKeyException, NoSuchProviderException, SignatureException
412 Signature sig = Signature.getInstance(sigAlgId.toString(), provider);
413 doVerify(sig, key);
416 public String toString()
418 // XXX say more than this.
419 return gnu.java.security.x509.X509Certificate.class.getName();
422 public PublicKey getPublicKey()
424 return subjectKey;
427 protected Object writeReplace() throws ObjectStreamException
429 return super.writeReplace();
432 // Own methods.
433 // ------------------------------------------------------------------------
436 * Verify this certificate's signature.
438 private void doVerify(Signature sig, PublicKey key)
439 throws CertificateException, InvalidKeyException, SignatureException
441 sig.initVerify(key);
442 sig.update(tbsCertBytes);
443 if (!sig.verify(signature))
444 throw new CertificateException("signature not validated");
448 * Read a GeneralNames structure.
450 private List getAltNames(byte[] encoded)
451 throws CertificateParsingException
453 LinkedList names = new LinkedList();
456 ByteArrayInputStream in = new ByteArrayInputStream(encoded);
457 DERReader der = new DERReader(in);
458 DERValue seq = der.read();
459 if (!seq.isConstructed())
460 throw new CertificateParsingException();
461 int len = 0;
462 while (len < seq.getLength())
464 DERValue name = der.read();
465 ArrayList pair = new ArrayList(2);
466 Object nameVal = null;
467 switch (name.getTag())
469 case RFC882_NAME:
470 case DNS_NAME:
471 case URI:
472 nameVal = new String((byte[]) name.getValue());
473 break;
474 case IP_ADDRESS:
475 nameVal = InetAddress.getByAddress(
476 (byte[]) name.getValue()).getHostAddress();
477 break;
478 case REGISTERED_ID:
479 nameVal = new OID((byte[]) name.getValue());
480 break;
481 case OTHER_NAME:
482 case X400_ADDRESS:
483 case DIRECTORY_NAME:
484 case EDI_PARTY_NAME:
485 nameVal = name.getEncoded();
486 break;
487 default:
488 throw new CertificateParsingException();
490 pair.add(new Integer(name.getTag()));
491 pair.add(nameVal);
492 names.add(pair);
493 if (name.isConstructed())
494 in.skip(name.getLength());
495 len += name.getEncodedLength();
498 catch (IOException ioe)
500 throw new CertificateParsingException(ioe.toString());
502 return Collections.unmodifiableList(names);
506 * Parse a DER stream into an X.509 certificate.
508 * @param encoded The encoded bytes.
510 private void parse(InputStream encoded) throws Exception
512 DERReader der = new DERReader(encoded);
514 // Certificate ::= SEQUENCE {
515 DERValue cert = der.read();
516 this.encoded = cert.getEncoded();
517 if (!cert.isConstructed())
518 throw new ASN1ParsingException("malformed Certificate");
520 // TBSCertificate ::= SEQUENCE {
521 DERValue tbsCert = der.read();
522 if (tbsCert.getValue() != DER.CONSTRUCTED_VALUE)
523 throw new ASN1ParsingException("malformed TBSCertificate");
524 tbsCertBytes = tbsCert.getEncoded();
526 DERValue val = der.read();
527 if (val.getTagClass() == DER.CONTEXT && val.getTag() == 0)
529 // Version ::= INTEGER [0] { v1(0), v2(1), v3(2) }
530 version = ((BigInteger) der.read().getValue()).intValue() + 1;
531 val = der.read();
533 else
535 version = 1;
537 // SerialNumber ::= INTEGER
538 serialNo = (BigInteger) val.getValue();
540 // AlgorithmIdentifier ::= SEQUENCE {
541 val = der.read();
542 if (!val.isConstructed())
543 throw new ASN1ParsingException("malformed AlgorithmIdentifier");
544 int certAlgLen = val.getLength();
545 val = der.read();
546 algId = (OID) val.getValue();
547 if (certAlgLen > val.getEncodedLength())
549 val = der.read();
550 if (val == null)
551 algVal = null;
552 else
553 algVal = val.getEncoded();
554 if (val.isConstructed())
555 encoded.skip(val.getLength());
558 issuer = new X500Principal(encoded);
560 if (!der.read().isConstructed())
561 throw new ASN1ParsingException("malformed Validity");
562 notBefore = (Date) der.read().getValue();
563 notAfter = (Date) der.read().getValue();
565 subject = new X500Principal(encoded);
567 if (!der.read().isConstructed())
568 throw new ASN1ParsingException("malformed SubjectPublicKeyInfo");
570 val = der.read();
571 if (!val.isConstructed())
572 throw new ASN1ParsingException("malformed AlgorithmIdentifier");
573 int keyAlgLen = val.getLength();
574 val = der.read();
575 OID keyID = (OID) val.getValue();
576 byte[] keyParams = null;
577 if (keyAlgLen > val.getEncodedLength())
579 val = der.read();
580 keyParams = val.getEncoded();
581 if (algVal == null)
582 algVal = keyParams;
583 if (val.isConstructed())
584 encoded.skip(val.getLength());
586 val = der.read();
587 byte[] keyVal = ((BitString) val.getValue()).toByteArray();
589 if (keyID.equals(ID_DSA))
591 AlgorithmParameters params = AlgorithmParameters.getInstance("DSA");
592 params.init(keyParams, "ASN.1");
593 KeyFactory keyFac = KeyFactory.getInstance("DSA");
594 DSAParameterSpec spec = (DSAParameterSpec)
595 params.getParameterSpec(DSAParameterSpec.class);
596 subjectKey = keyFac.generatePublic(new DSAPublicKeySpec(
597 (BigInteger) new DERReader(keyVal).read().getValue(),
598 spec.getP(), spec.getQ(), spec.getG()));
600 else if (keyID.equals(ID_RSA))
602 KeyFactory keyFac = KeyFactory.getInstance("RSA");
603 DERReader rsaKey = new DERReader(keyVal);
604 if (!rsaKey.read().isConstructed())
605 throw new ASN1ParsingException("malformed RSAPublicKey");
606 subjectKey = keyFac.generatePublic(new RSAPublicKeySpec(
607 (BigInteger) rsaKey.read().getValue(),
608 (BigInteger) rsaKey.read().getValue()));
610 else
611 throw new ASN1ParsingException("unknown key algorithm " + keyID);
613 if (version > 1)
614 val = der.read();
615 if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 1)
617 byte[] b = (byte[]) val.getValue();
618 issuerUniqueId = new BitString(b, 1, b.length-1, b[0] & 0xFF);
619 val = der.read();
621 if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 2)
623 byte[] b = (byte[]) val.getValue();
624 subjectUniqueId = new BitString(b, 1, b.length-1, b[0] & 0xFF);
625 val = der.read();
627 if (version >= 3 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 3)
629 val = der.read();
630 int len = 0;
631 while (len < val.getLength())
633 DERValue ext = der.read();
634 OID extId = (OID) der.read().getValue();
635 DERValue val2 = der.read();
636 Boolean crit = Boolean.valueOf(false);
637 if (val2.getValue() instanceof Boolean)
639 crit = (Boolean) val2.getValue();
640 val2 = der.read();
642 byte[] extVal = (byte[]) val2.getValue();
643 extensions.put(extId.toString(), extVal);
644 if (crit.booleanValue())
645 critOids.add(extId.toString());
646 else
647 nonCritOids.add(extId.toString());
648 if (extId.equals(ID_KEY_USAGE))
650 keyUsage = (BitString) DERReader.read(extVal).getValue();
652 else if (extId.equals(ID_BASIC_CONSTRAINTS))
654 DERReader bc = new DERReader(extVal);
655 DERValue constraints = bc.read();
656 if (!constraints.isConstructed())
657 throw new ASN1ParsingException("malformed BasicConstraints");
658 if (constraints.getLength() > 0)
660 boolean ca = false;
661 int constr = -1;
662 val2 = bc.read();
663 if (val2.getValue() instanceof Boolean)
665 ca = ((Boolean) val2.getValue()).booleanValue();
666 if (constraints.getLength() > val2.getEncodedLength())
667 val2 = bc.read();
669 if (val2.getValue() instanceof BigInteger)
670 constr = ((BigInteger) val2.getValue()).intValue();
671 basicConstraints = constr;
674 len += ext.getEncodedLength();
678 val = der.read();
679 if (!val.isConstructed())
680 throw new ASN1ParsingException("malformed AlgorithmIdentifier");
681 int sigAlgLen = val.getLength();
682 val = der.read();
683 sigAlgId = (OID) val.getValue();
684 if (sigAlgLen > val.getEncodedLength())
686 val = der.read();
687 if (val.getValue() == null)
688 sigAlgVal = keyParams;
689 else
690 sigAlgVal = (byte[]) val.getEncoded();
691 if (val.isConstructed())
692 encoded.skip(val.getLength());
694 signature = ((BitString) der.read().getValue()).toByteArray();