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)
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
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 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
;
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
;
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
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;
154 private transient OID sigAlgId
;
155 private transient byte[] sigAlgVal
;
156 private transient byte[] signature
;
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
171 public X509Certificate(InputStream encoded
)
172 throws CertificateException
, IOException
175 extensions
= new HashMap();
176 critOids
= new HashSet();
177 nonCritOids
= new HashSet();
182 catch (IOException ioe
)
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()
215 public BigInteger
getSerialNumber()
220 public Principal
getIssuerDN()
222 return getIssuerX500Principal();
225 public X500Principal
getIssuerX500Principal()
230 public Principal
getSubjectDN()
232 return getSubjectX500Principal();
235 public X500Principal
getSubjectX500Principal()
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
))
266 if (sigAlgId
.equals(ID_RSA_WITH_MD5
))
268 if (sigAlgId
.equals(ID_RSA_WITH_SHA1
))
269 return "SHA1withRSA";
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();
291 public boolean[] getSubjectUniqueID()
293 if (subjectUniqueId
!= null)
294 return subjectUniqueId
.toBooleanArray();
298 public boolean[] getKeyUsage()
300 if (keyUsage
!= null)
301 return keyUsage
.toBooleanArray();
305 public List
getExtendedKeyUsage() throws CertificateParsingException
307 byte[] ext
= (byte[]) extensions
.get("2.5.29.37");
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();
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();
335 public int getBasicConstraints()
337 return basicConstraints
;
340 public Collection
getSubjectAlternativeNames()
341 throws CertificateParsingException
343 byte[] ext
= getExtensionValue("2.5.29.17");
346 return getAltNames(ext
);
349 public Collection
getIssuerAlternativeNames()
350 throws CertificateParsingException
352 byte[] ext
= getExtensionValue("2.5.29.18");
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"))
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
);
388 return (byte[]) ext
.clone();
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());
408 public void verify(PublicKey key
, String provider
)
409 throws CertificateException
, NoSuchAlgorithmException
,
410 InvalidKeyException
, NoSuchProviderException
, SignatureException
412 Signature sig
= Signature
.getInstance(sigAlgId
.toString(), provider
);
416 public String
toString()
418 // XXX say more than this.
419 return gnu
.java
.security
.x509
.X509Certificate
.class.getName();
422 public PublicKey
getPublicKey()
427 protected Object
writeReplace() throws ObjectStreamException
429 return super.writeReplace();
433 // ------------------------------------------------------------------------
436 * Verify this certificate's signature.
438 private void doVerify(Signature sig
, PublicKey key
)
439 throws CertificateException
, InvalidKeyException
, SignatureException
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();
462 while (len
< seq
.getLength())
464 DERValue name
= der
.read();
465 ArrayList pair
= new ArrayList(2);
466 Object nameVal
= null;
467 switch (name
.getTag())
472 nameVal
= new String((byte[]) name
.getValue());
475 nameVal
= InetAddress
.getByAddress(
476 (byte[]) name
.getValue()).getHostAddress();
479 nameVal
= new OID((byte[]) name
.getValue());
485 nameVal
= name
.getEncoded();
488 throw new CertificateParsingException();
490 pair
.add(new Integer(name
.getTag()));
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;
537 // SerialNumber ::= INTEGER
538 serialNo
= (BigInteger
) val
.getValue();
540 // AlgorithmIdentifier ::= SEQUENCE {
542 if (!val
.isConstructed())
543 throw new ASN1ParsingException("malformed AlgorithmIdentifier");
544 int certAlgLen
= val
.getLength();
546 algId
= (OID
) val
.getValue();
547 if (certAlgLen
> val
.getEncodedLength())
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");
571 if (!val
.isConstructed())
572 throw new ASN1ParsingException("malformed AlgorithmIdentifier");
573 int keyAlgLen
= val
.getLength();
575 OID keyID
= (OID
) val
.getValue();
576 byte[] keyParams
= null;
577 if (keyAlgLen
> val
.getEncodedLength())
580 keyParams
= val
.getEncoded();
583 if (val
.isConstructed())
584 encoded
.skip(val
.getLength());
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()));
611 throw new ASN1ParsingException("unknown key algorithm " + keyID
);
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);
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);
627 if (version
>= 3 && val
.getTagClass() != DER
.UNIVERSAL
&& val
.getTag() == 3)
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();
642 byte[] extVal
= (byte[]) val2
.getValue();
643 extensions
.put(extId
.toString(), extVal
);
644 if (crit
.booleanValue())
645 critOids
.add(extId
.toString());
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)
663 if (val2
.getValue() instanceof Boolean
)
665 ca
= ((Boolean
) val2
.getValue()).booleanValue();
666 if (constraints
.getLength() > val2
.getEncodedLength())
669 if (val2
.getValue() instanceof BigInteger
)
670 constr
= ((BigInteger
) val2
.getValue()).intValue();
671 basicConstraints
= constr
;
674 len
+= ext
.getEncodedLength();
679 if (!val
.isConstructed())
680 throw new ASN1ParsingException("malformed AlgorithmIdentifier");
681 int sigAlgLen
= val
.getLength();
683 sigAlgId
= (OID
) val
.getValue();
684 if (sigAlgLen
> val
.getEncodedLength())
687 if (val
.getValue() == null)
688 sigAlgVal
= keyParams
;
690 sigAlgVal
= (byte[]) val
.getEncoded();
691 if (val
.isConstructed())
692 encoded
.skip(val
.getLength());
694 signature
= ((BitString
) der
.read().getValue()).toByteArray();