1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55:
56: import ;
57: import ;
58: import ;
59: import ;
60: import ;
61: import ;
62: import ;
63: import ;
64: import ;
65: import ;
66: import ;
67: import ;
68: import ;
69: import ;
70: import ;
71: import ;
72: import ;
73: import ;
74: import ;
75: import ;
76: import ;
77: import ;
78: import ;
79: import ;
80: import ;
81: import ;
82: import ;
83: import ;
84: import ;
85: import ;
86: import ;
87: import ;
88: import ;
89: import ;
90: import ;
91: import ;
92:
93: import ;
94:
95:
100: public class X509Certificate extends java.security.cert.X509Certificate
101: implements Serializable, GnuPKIExtension
102: {
103:
104:
105:
106:
107: private static final long serialVersionUID = -2491127588187038216L;
108: private static final Logger logger = SystemLogger.SYSTEM;
109:
110: protected static final OID ID_DSA = new OID ("1.2.840.10040.4.1");
111: protected static final OID ID_DSA_WITH_SHA1 = new OID ("1.2.840.10040.4.3");
112: protected static final OID ID_RSA = new OID ("1.2.840.113549.1.1.1");
113: protected static final OID ID_RSA_WITH_MD2 = new OID ("1.2.840.113549.1.1.2");
114: protected static final OID ID_RSA_WITH_MD5 = new OID ("1.2.840.113549.1.1.4");
115: protected static final OID ID_RSA_WITH_SHA1 = new OID ("1.2.840.113549.1.1.5");
116: protected static final OID ID_ECDSA_WITH_SHA1 = new OID ("1.2.840.10045.4.1");
117:
118:
119:
120:
121:
122:
123: protected transient byte[] encoded;
124:
125:
126: protected transient byte[] tbsCertBytes;
127: protected transient int version;
128: protected transient BigInteger serialNo;
129: protected transient OID algId;
130: protected transient byte[] algVal;
131: protected transient X500DistinguishedName issuer;
132: protected transient Date notBefore;
133: protected transient Date notAfter;
134: protected transient X500DistinguishedName subject;
135: protected transient PublicKey subjectKey;
136: protected transient BitString issuerUniqueId;
137: protected transient BitString subjectUniqueId;
138: protected transient Map<OID, Extension> extensions;
139:
140:
141: protected transient OID sigAlgId;
142: protected transient byte[] sigAlgVal;
143: protected transient byte[] signature;
144:
145:
146:
147:
148:
158: public X509Certificate(InputStream encoded)
159: throws CertificateException, IOException
160: {
161: super();
162: extensions = new HashMap<OID, Extension>();
163: try
164: {
165: parse(encoded);
166: }
167: catch (IOException ioe)
168: {
169: logger.log (Component.X509, "", ioe);
170: throw ioe;
171: }
172: catch (Exception e)
173: {
174: logger.log (Component.X509, "", e);
175: CertificateException ce = new CertificateException(e.getMessage());
176: ce.initCause (e);
177: throw ce;
178: }
179: }
180:
181: protected X509Certificate()
182: {
183: extensions = new HashMap<OID, Extension>();
184: }
185:
186:
187:
188:
189: public void checkValidity()
190: throws CertificateExpiredException, CertificateNotYetValidException
191: {
192: checkValidity(new Date());
193: }
194:
195: public void checkValidity(Date date)
196: throws CertificateExpiredException, CertificateNotYetValidException
197: {
198: if (date.compareTo(notBefore) < 0)
199: {
200: throw new CertificateNotYetValidException();
201: }
202: if (date.compareTo(notAfter) > 0)
203: {
204: throw new CertificateExpiredException();
205: }
206: }
207:
208: public int getVersion()
209: {
210: return version;
211: }
212:
213: public BigInteger getSerialNumber()
214: {
215: return serialNo;
216: }
217:
218: public Principal getIssuerDN()
219: {
220: return issuer;
221: }
222:
223: public X500Principal getIssuerX500Principal()
224: {
225: return new X500Principal(issuer.getDer());
226: }
227:
228: public Principal getSubjectDN()
229: {
230: return subject;
231: }
232:
233: public X500Principal getSubjectX500Principal()
234: {
235: return new X500Principal(subject.getDer());
236: }
237:
238: public Date getNotBefore()
239: {
240: return (Date) notBefore.clone();
241: }
242:
243: public Date getNotAfter()
244: {
245: return (Date) notAfter.clone();
246: }
247:
248: public byte[] getTBSCertificate() throws CertificateEncodingException
249: {
250: return (byte[]) tbsCertBytes.clone();
251: }
252:
253: public byte[] getSignature()
254: {
255: return (byte[]) signature.clone();
256: }
257:
258: public String getSigAlgName()
259: {
260: if (sigAlgId.equals(ID_DSA_WITH_SHA1))
261: {
262: return "SHA1withDSA";
263: }
264: if (sigAlgId.equals(ID_RSA_WITH_MD2))
265: {
266: return "MD2withRSA";
267: }
268: if (sigAlgId.equals(ID_RSA_WITH_MD5))
269: {
270: return "MD5withRSA";
271: }
272: if (sigAlgId.equals(ID_RSA_WITH_SHA1))
273: {
274: return "SHA1withRSA";
275: }
276: return "unknown";
277: }
278:
279: public String getSigAlgOID()
280: {
281: return sigAlgId.toString();
282: }
283:
284: public byte[] getSigAlgParams()
285: {
286: return (byte[]) sigAlgVal.clone();
287: }
288:
289: public boolean[] getIssuerUniqueID()
290: {
291: if (issuerUniqueId != null)
292: {
293: return issuerUniqueId.toBooleanArray();
294: }
295: return null;
296: }
297:
298: public boolean[] getSubjectUniqueID()
299: {
300: if (subjectUniqueId != null)
301: {
302: return subjectUniqueId.toBooleanArray();
303: }
304: return null;
305: }
306:
307: public boolean[] getKeyUsage()
308: {
309: Extension e = getExtension(KeyUsage.ID);
310: if (e != null)
311: {
312: KeyUsage ku = (KeyUsage) e.getValue();
313: boolean[] result = new boolean[9];
314: boolean[] b = ku.getKeyUsage().toBooleanArray();
315: System.arraycopy(b, 0, result, 0, b.length);
316: return result;
317: }
318: return null;
319: }
320:
321: public List<String> getExtendedKeyUsage() throws CertificateParsingException
322: {
323: Extension e = getExtension(ExtendedKeyUsage.ID);
324: if (e != null)
325: {
326: List<OID> a = ((ExtendedKeyUsage) e.getValue()).getPurposeIds();
327: List<String> b = new ArrayList<String>(a.size());
328: for (OID oid : a)
329: b.add(oid.toString());
330: return Collections.unmodifiableList(b);
331: }
332: return null;
333: }
334:
335: public int getBasicConstraints()
336: {
337: Extension e = getExtension(BasicConstraints.ID);
338: if (e != null)
339: {
340: return ((BasicConstraints) e.getValue()).getPathLengthConstraint();
341: }
342: return -1;
343: }
344:
345: public Collection<List<?>> getSubjectAlternativeNames()
346: throws CertificateParsingException
347: {
348: Extension e = getExtension(SubjectAlternativeNames.ID);
349: if (e != null)
350: {
351: List<GeneralName> names
352: = ((SubjectAlternativeNames) e.getValue()).getNames();
353: List<List<?>> list = new ArrayList<List<?>>(names.size());
354: for (GeneralName name : names)
355: {
356: List<Object> n = new ArrayList<Object>(2);
357: n.add(name.kind().tag());
358: n.add(name.name());
359: list.add(n);
360: }
361: return list;
362: }
363: return null;
364: }
365:
366: public Collection<List<?>> getIssuerAlternativeNames()
367: throws CertificateParsingException
368: {
369: Extension e = getExtension(IssuerAlternativeNames.ID);
370: if (e != null)
371: {
372: List<GeneralName> names
373: = ((IssuerAlternativeNames) e.getValue()).getNames();
374: List<List<?>> list = new ArrayList<List<?>>(names.size());
375: for (GeneralName name : names)
376: {
377: List<Object> n = new ArrayList<Object>(2);
378: n.add(name.kind().tag());
379: n.add(name.name());
380: list.add(n);
381: }
382: return list;
383: }
384: return null;
385: }
386:
387:
388:
389:
390: public boolean hasUnsupportedCriticalExtension()
391: {
392: for (Iterator it = extensions.values().iterator(); it.hasNext(); )
393: {
394: Extension e = (Extension) it.next();
395: if (e.isCritical() && !e.isSupported())
396: return true;
397: }
398: return false;
399: }
400:
401: public Set<String> getCriticalExtensionOIDs()
402: {
403: HashSet<String> s = new HashSet<String>();
404: for (Extension e : extensions.values())
405: {
406: if (e.isCritical())
407: s.add(e.getOid().toString());
408: }
409: return Collections.unmodifiableSet(s);
410: }
411:
412: public Set<String> getNonCriticalExtensionOIDs()
413: {
414: HashSet<String> s = new HashSet<String>();
415: for (Extension e : extensions.values())
416: {
417: if (!e.isCritical())
418: s.add(e.getOid().toString());
419: }
420: return Collections.unmodifiableSet(s);
421: }
422:
423: public byte[] getExtensionValue(String oid)
424: {
425: Extension e = getExtension(new OID(oid));
426: if (e != null)
427: {
428: return e.getValue().getEncoded();
429: }
430: return null;
431: }
432:
433:
434:
435:
436: public Extension getExtension(OID oid)
437: {
438: return (Extension) extensions.get(oid);
439: }
440:
441: public Collection getExtensions()
442: {
443: return extensions.values();
444: }
445:
446:
447:
448:
449: public byte[] getEncoded() throws CertificateEncodingException
450: {
451: return (byte[]) encoded.clone();
452: }
453:
454: public void verify(PublicKey key)
455: throws CertificateException, NoSuchAlgorithmException,
456: InvalidKeyException, NoSuchProviderException, SignatureException
457: {
458: Signature sig = Signature.getInstance(sigAlgId.toString());
459: doVerify(sig, key);
460: }
461:
462: public void verify(PublicKey key, String provider)
463: throws CertificateException, NoSuchAlgorithmException,
464: InvalidKeyException, NoSuchProviderException, SignatureException
465: {
466: Signature sig = Signature.getInstance(sigAlgId.toString(), provider);
467: doVerify(sig, key);
468: }
469:
470: public String toString()
471: {
472: StringWriter str = new StringWriter();
473: PrintWriter out = new PrintWriter(str);
474: out.println(X509Certificate.class.getName() + " {");
475: out.println(" TBSCertificate {");
476: out.println(" version = " + version + ";");
477: out.println(" serialNo = " + serialNo + ";");
478: out.println(" signature = {");
479: out.println(" algorithm = " + getSigAlgName() + ";");
480: out.print(" parameters =");
481: if (sigAlgVal != null)
482: {
483: out.println();
484: out.print(Util.hexDump(sigAlgVal, " "));
485: }
486: else
487: {
488: out.println(" null;");
489: }
490: out.println(" }");
491: out.println(" issuer = " + issuer.getName() + ";");
492: out.println(" validity = {");
493: out.println(" notBefore = " + notBefore + ";");
494: out.println(" notAfter = " + notAfter + ";");
495: out.println(" }");
496: out.println(" subject = " + subject.getName() + ";");
497: out.println(" subjectPublicKeyInfo = {");
498: out.println(" algorithm = " + subjectKey.getAlgorithm());
499: out.println(" key =");
500: out.print(Util.hexDump(subjectKey.getEncoded(), " "));
501: out.println(" };");
502: out.println(" issuerUniqueId = " + issuerUniqueId + ";");
503: out.println(" subjectUniqueId = " + subjectUniqueId + ";");
504: out.println(" extensions = {");
505: for (Iterator it = extensions.values().iterator(); it.hasNext(); )
506: {
507: out.println(" " + it.next());
508: }
509: out.println(" }");
510: out.println(" }");
511: out.println(" signatureAlgorithm = " + getSigAlgName() + ";");
512: out.println(" signatureValue =");
513: out.print(Util.hexDump(signature, " "));
514: out.println("}");
515: return str.toString();
516: }
517:
518: public PublicKey getPublicKey()
519: {
520: return subjectKey;
521: }
522:
523: public boolean equals(Object other)
524: {
525: if (!(other instanceof X509Certificate))
526: return false;
527: try
528: {
529: if (other instanceof X509Certificate)
530: return Arrays.equals(encoded, ((X509Certificate) other).encoded);
531: byte[] enc = ((X509Certificate) other).getEncoded();
532: if (enc == null)
533: return false;
534: return Arrays.equals(encoded, enc);
535: }
536: catch (CertificateEncodingException cee)
537: {
538: return false;
539: }
540: }
541:
542:
543:
544:
545:
548: private void doVerify(Signature sig, PublicKey key)
549: throws CertificateException, InvalidKeyException, SignatureException
550: {
551: logger.log (Component.X509, "verifying sig={0} key={1}",
552: new Object[] { sig, key });
553: sig.initVerify(key);
554: sig.update(tbsCertBytes);
555: if (!sig.verify(signature))
556: {
557: throw new CertificateException("signature not validated");
558: }
559: }
560:
561:
566: private void parse(InputStream encoded) throws Exception
567: {
568: DERReader der = new DERReader(encoded);
569:
570:
571: DERValue cert = der.read();
572: logger.log (Component.X509, "start Certificate len == {0}",
573: Integer.valueOf(cert.getLength()));
574:
575: this.encoded = cert.getEncoded();
576: if (!cert.isConstructed())
577: {
578: throw new IOException("malformed Certificate");
579: }
580:
581:
582: DERValue tbsCert = der.read();
583: if (tbsCert.getValue() != DER.CONSTRUCTED_VALUE)
584: {
585: throw new IOException("malformed TBSCertificate");
586: }
587: tbsCertBytes = tbsCert.getEncoded();
588: logger.log (Component.X509, "start TBSCertificate len == {0}",
589: Integer.valueOf(tbsCert.getLength()));
590:
591:
592: DERValue val = der.read();
593: if (val.getTagClass() == DER.CONTEXT && val.getTag() == 0)
594: {
595: version = ((BigInteger) der.read().getValue()).intValue() + 1;
596: val = der.read();
597: }
598: else
599: {
600: version = 1;
601: }
602: logger.log (Component.X509, "read version == {0}",
603: Integer.valueOf(version));
604:
605:
606: serialNo = (BigInteger) val.getValue();
607: logger.log (Component.X509, "read serial number == {0}", serialNo);
608:
609:
610: val = der.read();
611: if (!val.isConstructed())
612: {
613: throw new IOException("malformed AlgorithmIdentifier");
614: }
615: int certAlgLen = val.getLength();
616: logger.log (Component.X509, "start AlgorithmIdentifier len == {0}",
617: Integer.valueOf(certAlgLen));
618: val = der.read();
619:
620:
621: algId = (OID) val.getValue();
622: logger.log (Component.X509, "read algorithm ID == {0}", algId);
623:
624:
625: if (certAlgLen > val.getEncodedLength())
626: {
627: val = der.read();
628: if (val == null)
629: {
630: algVal = null;
631: }
632: else
633: {
634: algVal = val.getEncoded();
635:
636: if (val.isConstructed())
637: encoded.skip(val.getLength());
638: }
639: logger.log (Component.X509, "read algorithm parameters == {0}", algVal);
640: }
641:
642:
643: val = der.read();
644: issuer = new X500DistinguishedName(val.getEncoded());
645: der.skip(val.getLength());
646: logger.log (Component.X509, "read issuer == {0}", issuer);
647:
648:
649:
650:
651: if (!der.read().isConstructed())
652: {
653: throw new IOException("malformed Validity");
654: }
655: notBefore = (Date) der.read().getValue();
656: logger.log (Component.X509, "read notBefore == {0}", notBefore);
657: notAfter = (Date) der.read().getValue();
658: logger.log (Component.X509, "read notAfter == {0}", notAfter);
659:
660:
661: val = der.read();
662: subject = new X500DistinguishedName(val.getEncoded());
663: der.skip(val.getLength());
664: logger.log (Component.X509, "read subject == {0}", subject);
665:
666:
667:
668:
669: DERValue spki = der.read();
670: if (!spki.isConstructed())
671: {
672: throw new IOException("malformed SubjectPublicKeyInfo");
673: }
674: KeyFactory spkFac = KeyFactory.getInstance("X.509");
675: subjectKey = spkFac.generatePublic(new X509EncodedKeySpec(spki.getEncoded()));
676: der.skip(spki.getLength());
677: logger.log (Component.X509, "read subjectPublicKey == {0}", subjectKey);
678:
679: val = der.read();
680: if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 1)
681: {
682: byte[] b = (byte[]) val.getValue();
683: issuerUniqueId = new BitString(b, 1, b.length-1, b[0] & 0xFF);
684: logger.log (Component.X509, "read issuerUniqueId == {0}", issuerUniqueId);
685: val = der.read();
686: }
687: if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 2)
688: {
689: byte[] b = (byte[]) val.getValue();
690: subjectUniqueId = new BitString(b, 1, b.length-1, b[0] & 0xFF);
691: logger.log (Component.X509, "read subjectUniqueId == {0}", subjectUniqueId);
692: val = der.read();
693: }
694: if (version >= 3 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 3)
695: {
696: val = der.read();
697: logger.log (Component.X509, "start Extensions len == {0}",
698: Integer.valueOf(val.getLength()));
699: int len = 0;
700: while (len < val.getLength())
701: {
702: DERValue ext = der.read();
703: logger.log (Component.X509, "start extension len == {0}",
704: Integer.valueOf(ext.getLength()));
705: Extension e = new Extension(ext.getEncoded());
706: extensions.put(e.getOid(), e);
707: der.skip(ext.getLength());
708: len += ext.getEncodedLength();
709: logger.log (Component.X509, "read extension {0} == {1}",
710: new Object[] { e.getOid (), e });
711: logger.log (Component.X509, "count == {0}", Integer.valueOf(len));
712: }
713:
714: val = der.read ();
715: }
716:
717: logger.log (Component.X509, "read value {0}", val);
718: if (!val.isConstructed())
719: {
720: throw new CertificateException ("malformed AlgorithmIdentifier");
721: }
722: int sigAlgLen = val.getLength();
723: logger.log (Component.X509, "start AlgorithmIdentifier len == {0}",
724: Integer.valueOf(sigAlgLen));
725: val = der.read();
726: sigAlgId = (OID) val.getValue();
727: logger.log (Component.X509, "read algorithm id == {0}", sigAlgId);
728: if (sigAlgLen > val.getEncodedLength())
729: {
730: val = der.read();
731: if (val.getValue() == null)
732: {
733: if (subjectKey instanceof DSAPublicKey)
734: {
735: AlgorithmParameters params =
736: AlgorithmParameters.getInstance("DSA");
737: DSAParams dsap = ((DSAPublicKey) subjectKey).getParams();
738: DSAParameterSpec spec =
739: new DSAParameterSpec(dsap.getP(), dsap.getQ(), dsap.getG());
740: params.init(spec);
741: sigAlgVal = params.getEncoded();
742: }
743: }
744: else
745: {
746: sigAlgVal = (byte[]) val.getEncoded();
747: }
748: if (val.isConstructed())
749: {
750: encoded.skip(val.getLength());
751: }
752: logger.log (Component.X509, "read parameters == {0}", sigAlgVal);
753: }
754: signature = ((BitString) der.read().getValue()).toByteArray();
755: logger.log (Component.X509, "read signature ==\n{0}", Util.hexDump(signature, ">>>> "));
756: }
757: }