1 |
/* X509Certificate.java -- X.509 certificate. |
/* X509Certificate.java -- X.509 certificate. |
2 |
Copyright (C) 2003 Free Software Foundation, Inc. |
Copyright (C) 2003, 2004 Free Software Foundation, Inc. |
3 |
|
|
4 |
This file is part of GNU Classpath. |
This file is part of GNU Classpath. |
5 |
|
|
7 |
it under the terms of the GNU General Public License as published by |
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) |
the Free Software Foundation; either version 2, or (at your option) |
9 |
any later version. |
any later version. |
10 |
|
|
11 |
GNU Classpath is distributed in the hope that it will be useful, but |
GNU Classpath is distributed in the hope that it will be useful, but |
12 |
WITHOUT ANY WARRANTY; without even the implied warranty of |
WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
42 |
import java.io.InputStream; |
import java.io.InputStream; |
43 |
import java.io.IOException; |
import java.io.IOException; |
44 |
import java.io.ObjectStreamException; |
import java.io.ObjectStreamException; |
45 |
|
import java.io.PrintWriter; |
46 |
import java.io.Serializable; |
import java.io.Serializable; |
47 |
|
import java.io.StringWriter; |
48 |
|
|
49 |
import java.math.BigInteger; |
import java.math.BigInteger; |
50 |
|
|
66 |
import java.security.cert.CertificateNotYetValidException; |
import java.security.cert.CertificateNotYetValidException; |
67 |
import java.security.cert.CertificateParsingException; |
import java.security.cert.CertificateParsingException; |
68 |
|
|
69 |
|
import java.security.interfaces.DSAParams; |
70 |
|
import java.security.interfaces.DSAPublicKey; |
71 |
import java.security.spec.DSAParameterSpec; |
import java.security.spec.DSAParameterSpec; |
72 |
import java.security.spec.DSAPublicKeySpec; |
import java.security.spec.X509EncodedKeySpec; |
|
import java.security.spec.RSAPublicKeySpec; |
|
73 |
|
|
74 |
|
import java.util.Arrays; |
75 |
import java.util.ArrayList; |
import java.util.ArrayList; |
76 |
import java.util.Collection; |
import java.util.Collection; |
77 |
import java.util.Collections; |
import java.util.Collections; |
81 |
import java.util.Iterator; |
import java.util.Iterator; |
82 |
import java.util.LinkedList; |
import java.util.LinkedList; |
83 |
import java.util.List; |
import java.util.List; |
84 |
|
import java.util.Map; |
85 |
import java.util.Set; |
import java.util.Set; |
86 |
|
|
87 |
import javax.security.auth.x500.X500Principal; |
import javax.security.auth.x500.X500Principal; |
88 |
|
|
|
import gnu.java.io.ASN1ParsingException; |
|
89 |
import gnu.java.security.OID; |
import gnu.java.security.OID; |
90 |
import gnu.java.security.der.BitString; |
import gnu.java.security.der.*; |
91 |
import gnu.java.security.der.DER; |
import gnu.java.security.x509.ext.*; |
|
import gnu.java.security.der.DERReader; |
|
|
import gnu.java.security.der.DERValue; |
|
|
import gnu.java.security.der.DERWriter; |
|
92 |
|
|
93 |
/** |
/** |
94 |
* An implementation of X.509 certificates. |
* An implementation of X.509 certificates. |
96 |
* @author Casey Marshall (rsdio@metastatic.org) |
* @author Casey Marshall (rsdio@metastatic.org) |
97 |
*/ |
*/ |
98 |
public class X509Certificate extends java.security.cert.X509Certificate |
public class X509Certificate extends java.security.cert.X509Certificate |
99 |
implements Serializable |
implements Serializable, GnuPKIExtension |
100 |
{ |
{ |
101 |
|
|
102 |
// Constants and fields. |
// Constants and fields. |
103 |
// ------------------------------------------------------------------------ |
// ------------------------------------------------------------------------ |
104 |
|
|
105 |
private static final OID ID_DSA = new OID("1.2.840.10040.4.1"); |
private static final boolean DEBUG = false; |
106 |
private static final OID ID_DSA_WITH_SHA1 = new OID("1.2.840.10040.4.3"); |
private static void debug(String msg) |
107 |
private static final OID ID_RSA = new OID("1.2.840.113549.1.1.1"); |
{ |
108 |
private static final OID ID_RSA_WITH_MD2 = new OID("1.2.840.113549.1.1.2"); |
if (DEBUG) |
109 |
private static final OID ID_RSA_WITH_MD5 = new OID("1.2.840.113549.1.1.4"); |
{ |
110 |
private static final OID ID_RSA_WITH_SHA1 = new OID("1.2.840.113549.1.1.5"); |
System.err.print(">> X509Certificate: "); |
111 |
|
System.err.println(msg); |
112 |
private static final OID ID_EXTENSION = new OID("2.5.29"); |
} |
113 |
private static final OID ID_KEY_USAGE = ID_EXTENSION.getChild(15); |
} |
114 |
private static final OID ID_BASIC_CONSTRAINTS = ID_EXTENSION.getChild(19); |
private static void debug(Throwable t) |
115 |
private static final OID ID_EXT_KEY_USAGE = ID_EXTENSION.getChild(37); |
{ |
116 |
|
if (DEBUG) |
117 |
private static final int OTHER_NAME = 0; |
{ |
118 |
private static final int RFC882_NAME = 1; |
System.err.print(">> X509Certificate: "); |
119 |
private static final int DNS_NAME = 2; |
t.printStackTrace(); |
120 |
private static final int X400_ADDRESS = 3; |
} |
121 |
private static final int DIRECTORY_NAME = 4; |
} |
122 |
private static final int EDI_PARTY_NAME = 5; |
|
123 |
private static final int URI = 6; |
protected static final OID ID_DSA = new OID ("1.2.840.10040.4.1"); |
124 |
private static final int IP_ADDRESS = 7; |
protected static final OID ID_DSA_WITH_SHA1 = new OID ("1.2.840.10040.4.3"); |
125 |
private static final int REGISTERED_ID = 8; |
protected static final OID ID_RSA = new OID ("1.2.840.113549.1.1.1"); |
126 |
|
protected static final OID ID_RSA_WITH_MD2 = new OID ("1.2.840.113549.1.1.2"); |
127 |
|
protected static final OID ID_RSA_WITH_MD5 = new OID ("1.2.840.113549.1.1.4"); |
128 |
|
protected static final OID ID_RSA_WITH_SHA1 = new OID ("1.2.840.113549.1.1.5"); |
129 |
|
protected static final OID ID_ECDSA_WITH_SHA1 = new OID ("1.2.840.10045.4.1"); |
130 |
|
|
131 |
// This object SHOULD be serialized with an instance of |
// This object SHOULD be serialized with an instance of |
132 |
// java.security.cert.Certificate.CertificateRep, thus all fields are |
// java.security.cert.Certificate.CertificateRep, thus all fields are |
133 |
// transient. |
// transient. |
134 |
|
|
135 |
// The encoded certificate. |
// The encoded certificate. |
136 |
private transient byte[] encoded; |
protected transient byte[] encoded; |
137 |
|
|
138 |
// TBSCertificate part. |
// TBSCertificate part. |
139 |
private transient byte[] tbsCertBytes; |
protected transient byte[] tbsCertBytes; |
140 |
private transient int version; |
protected transient int version; |
141 |
private transient BigInteger serialNo; |
protected transient BigInteger serialNo; |
142 |
private transient OID algId; |
protected transient OID algId; |
143 |
private transient byte[] algVal; |
protected transient byte[] algVal; |
144 |
private transient X500Principal issuer; |
protected transient X500DistinguishedName issuer; |
145 |
private transient Date notBefore; |
protected transient Date notBefore; |
146 |
private transient Date notAfter; |
protected transient Date notAfter; |
147 |
private transient X500Principal subject; |
protected transient X500DistinguishedName subject; |
148 |
private transient PublicKey subjectKey; |
protected transient PublicKey subjectKey; |
149 |
private transient BitString issuerUniqueId; |
protected transient BitString issuerUniqueId; |
150 |
private transient BitString subjectUniqueId; |
protected transient BitString subjectUniqueId; |
151 |
private transient HashMap extensions; |
protected transient Map extensions; |
|
private transient HashSet critOids; |
|
|
private transient HashSet nonCritOids; |
|
|
|
|
|
private transient BitString keyUsage; |
|
|
private transient int basicConstraints = -1; |
|
152 |
|
|
153 |
// Signature. |
// Signature. |
154 |
private transient OID sigAlgId; |
protected transient OID sigAlgId; |
155 |
private transient byte[] sigAlgVal; |
protected transient byte[] sigAlgVal; |
156 |
private transient byte[] signature; |
protected transient byte[] signature; |
157 |
|
|
158 |
// Constructors. |
// Constructors. |
159 |
// ------------------------------------------------------------------------ |
// ------------------------------------------------------------------------ |
173 |
{ |
{ |
174 |
super(); |
super(); |
175 |
extensions = new HashMap(); |
extensions = new HashMap(); |
|
critOids = new HashSet(); |
|
|
nonCritOids = new HashSet(); |
|
176 |
try |
try |
177 |
{ |
{ |
178 |
parse(encoded); |
parse(encoded); |
179 |
} |
} |
180 |
catch (IOException ioe) |
catch (IOException ioe) |
181 |
{ |
{ |
182 |
|
debug(ioe); |
183 |
throw ioe; |
throw ioe; |
184 |
} |
} |
185 |
catch (Exception e) |
catch (Exception e) |
186 |
{ |
{ |
187 |
throw new CertificateException(e.toString()); |
debug(e); |
188 |
|
CertificateException ce = new CertificateException(e.getMessage()); |
189 |
|
ce.initCause (e); |
190 |
|
throw ce; |
191 |
} |
} |
192 |
} |
} |
193 |
|
|
194 |
|
protected X509Certificate() |
195 |
|
{ |
196 |
|
extensions = new HashMap(); |
197 |
|
} |
198 |
|
|
199 |
// X509Certificate methods. |
// X509Certificate methods. |
200 |
// ------------------------------------------------------------------------ |
// ------------------------------------------------------------------------ |
201 |
|
|
209 |
throws CertificateExpiredException, CertificateNotYetValidException |
throws CertificateExpiredException, CertificateNotYetValidException |
210 |
{ |
{ |
211 |
if (date.compareTo(notBefore) < 0) |
if (date.compareTo(notBefore) < 0) |
212 |
throw new CertificateNotYetValidException(); |
{ |
213 |
|
throw new CertificateNotYetValidException(); |
214 |
|
} |
215 |
if (date.compareTo(notAfter) > 0) |
if (date.compareTo(notAfter) > 0) |
216 |
throw new CertificateExpiredException(); |
{ |
217 |
|
throw new CertificateExpiredException(); |
218 |
|
} |
219 |
} |
} |
220 |
|
|
221 |
public int getVersion() |
public int getVersion() |
230 |
|
|
231 |
public Principal getIssuerDN() |
public Principal getIssuerDN() |
232 |
{ |
{ |
233 |
return getIssuerX500Principal(); |
return issuer; |
234 |
} |
} |
235 |
|
|
236 |
public X500Principal getIssuerX500Principal() |
public X500Principal getIssuerX500Principal() |
237 |
{ |
{ |
238 |
return issuer; |
return new X500Principal(issuer.getDer()); |
239 |
} |
} |
240 |
|
|
241 |
public Principal getSubjectDN() |
public Principal getSubjectDN() |
242 |
{ |
{ |
243 |
return getSubjectX500Principal(); |
return subject; |
244 |
} |
} |
245 |
|
|
246 |
public X500Principal getSubjectX500Principal() |
public X500Principal getSubjectX500Principal() |
247 |
{ |
{ |
248 |
return subject; |
return new X500Principal(subject.getDer()); |
249 |
} |
} |
250 |
|
|
251 |
public Date getNotBefore() |
public Date getNotBefore() |
271 |
public String getSigAlgName() |
public String getSigAlgName() |
272 |
{ |
{ |
273 |
if (sigAlgId.equals(ID_DSA_WITH_SHA1)) |
if (sigAlgId.equals(ID_DSA_WITH_SHA1)) |
274 |
return "SHA1withDSA"; |
{ |
275 |
if (sigAlgId.equals(ID_RSA_WITH_MD2 )) |
return "SHA1withDSA"; |
276 |
return "MD2withRSA"; |
} |
277 |
if (sigAlgId.equals(ID_RSA_WITH_MD5 )) |
if (sigAlgId.equals(ID_RSA_WITH_MD2)) |
278 |
return "MD5withRSA"; |
{ |
279 |
if (sigAlgId.equals(ID_RSA_WITH_SHA1 )) |
return "MD2withRSA"; |
280 |
return "SHA1withRSA"; |
} |
281 |
|
if (sigAlgId.equals(ID_RSA_WITH_MD5)) |
282 |
|
{ |
283 |
|
return "MD5withRSA"; |
284 |
|
} |
285 |
|
if (sigAlgId.equals(ID_RSA_WITH_SHA1)) |
286 |
|
{ |
287 |
|
return "SHA1withRSA"; |
288 |
|
} |
289 |
return "unknown"; |
return "unknown"; |
|
// return sigAlgId.getShortName(); |
|
290 |
} |
} |
291 |
|
|
292 |
public String getSigAlgOID() |
public String getSigAlgOID() |
302 |
public boolean[] getIssuerUniqueID() |
public boolean[] getIssuerUniqueID() |
303 |
{ |
{ |
304 |
if (issuerUniqueId != null) |
if (issuerUniqueId != null) |
305 |
return issuerUniqueId.toBooleanArray(); |
{ |
306 |
|
return issuerUniqueId.toBooleanArray(); |
307 |
|
} |
308 |
return null; |
return null; |
309 |
} |
} |
310 |
|
|
311 |
public boolean[] getSubjectUniqueID() |
public boolean[] getSubjectUniqueID() |
312 |
{ |
{ |
313 |
if (subjectUniqueId != null) |
if (subjectUniqueId != null) |
314 |
return subjectUniqueId.toBooleanArray(); |
{ |
315 |
|
return subjectUniqueId.toBooleanArray(); |
316 |
|
} |
317 |
return null; |
return null; |
318 |
} |
} |
319 |
|
|
320 |
public boolean[] getKeyUsage() |
public boolean[] getKeyUsage() |
321 |
{ |
{ |
322 |
if (keyUsage != null) |
Extension e = getExtension(KeyUsage.ID); |
323 |
return keyUsage.toBooleanArray(); |
if (e != null) |
324 |
|
{ |
325 |
|
KeyUsage ku = (KeyUsage) e.getValue(); |
326 |
|
boolean[] result = new boolean[9]; |
327 |
|
boolean[] b = ku.getKeyUsage().toBooleanArray(); |
328 |
|
System.arraycopy(b, 0, result, 0, b.length); |
329 |
|
return result; |
330 |
|
} |
331 |
return null; |
return null; |
332 |
} |
} |
333 |
|
|
334 |
public List getExtendedKeyUsage() throws CertificateParsingException |
public List getExtendedKeyUsage() throws CertificateParsingException |
335 |
{ |
{ |
336 |
byte[] ext = (byte[]) extensions.get("2.5.29.37"); |
Extension e = getExtension(ExtendedKeyUsage.ID); |
337 |
if (ext == null) |
if (e != null) |
|
return null; |
|
|
LinkedList usages = new LinkedList(); |
|
|
try |
|
338 |
{ |
{ |
339 |
DERReader der = new DERReader(new ByteArrayInputStream(ext)); |
List a = ((ExtendedKeyUsage) e.getValue()).getPurposeIds(); |
340 |
DERValue seq = der.read(); |
List b = new ArrayList(a.size()); |
341 |
if (!seq.isConstructed()) |
for (Iterator it = a.iterator(); it.hasNext(); ) |
|
throw new CertificateParsingException(); |
|
|
int len = 0; |
|
|
while (len < seq.getLength()) |
|
342 |
{ |
{ |
343 |
DERValue oid = der.read(); |
b.add(it.next().toString()); |
|
if (!(oid.getValue() instanceof OID)) |
|
|
throw new CertificateParsingException(); |
|
|
usages.add(oid.getValue().toString()); |
|
|
len += DERWriter.definiteEncodingSize(oid.getLength()) |
|
|
+ oid.getLength() + 1; |
|
344 |
} |
} |
345 |
|
return Collections.unmodifiableList(b); |
346 |
} |
} |
347 |
catch (IOException ioe) |
return null; |
|
{ |
|
|
throw new CertificateParsingException(); |
|
|
} |
|
|
return usages; |
|
348 |
} |
} |
349 |
|
|
350 |
public int getBasicConstraints() |
public int getBasicConstraints() |
351 |
{ |
{ |
352 |
return basicConstraints; |
Extension e = getExtension(BasicConstraints.ID); |
353 |
|
if (e != null) |
354 |
|
{ |
355 |
|
return ((BasicConstraints) e.getValue()).getPathLengthConstraint(); |
356 |
|
} |
357 |
|
return -1; |
358 |
} |
} |
359 |
|
|
360 |
public Collection getSubjectAlternativeNames() |
public Collection getSubjectAlternativeNames() |
361 |
throws CertificateParsingException |
throws CertificateParsingException |
362 |
{ |
{ |
363 |
byte[] ext = getExtensionValue("2.5.29.17"); |
Extension e = getExtension(SubjectAlternativeNames.ID); |
364 |
if (ext == null) |
if (e != null) |
365 |
return null; |
{ |
366 |
return getAltNames(ext); |
return ((SubjectAlternativeNames) e.getValue()).getNames(); |
367 |
|
} |
368 |
|
return null; |
369 |
} |
} |
370 |
|
|
371 |
public Collection getIssuerAlternativeNames() |
public Collection getIssuerAlternativeNames() |
372 |
throws CertificateParsingException |
throws CertificateParsingException |
373 |
{ |
{ |
374 |
byte[] ext = getExtensionValue("2.5.29.18"); |
Extension e = getExtension(IssuerAlternativeNames.ID); |
375 |
if (ext == null) |
if (e != null) |
376 |
return null; |
{ |
377 |
return getAltNames(ext); |
return ((IssuerAlternativeNames) e.getValue()).getNames(); |
378 |
|
} |
379 |
|
return null; |
380 |
} |
} |
381 |
|
|
382 |
// X509Extension methods. |
// X509Extension methods. |
384 |
|
|
385 |
public boolean hasUnsupportedCriticalExtension() |
public boolean hasUnsupportedCriticalExtension() |
386 |
{ |
{ |
387 |
for (Iterator it = critOids.iterator(); it.hasNext(); ) |
for (Iterator it = extensions.values().iterator(); it.hasNext(); ) |
388 |
{ |
{ |
389 |
String oid = (String) it.next(); |
Extension e = (Extension) it.next(); |
390 |
if (!oid.equals("2.5.29.15") && !oid.equals("2.5.29.17") && |
if (e.isCritical() && !e.isSupported()) |
|
!oid.equals("2.5.29.18") && !oid.equals("2.5.29.19") && |
|
|
!oid.equals("2.5.29.37")) |
|
391 |
return true; |
return true; |
392 |
} |
} |
393 |
return false; |
return false; |
395 |
|
|
396 |
public Set getCriticalExtensionOIDs() |
public Set getCriticalExtensionOIDs() |
397 |
{ |
{ |
398 |
return Collections.unmodifiableSet(critOids); |
HashSet s = new HashSet(); |
399 |
|
for (Iterator it = extensions.values().iterator(); it.hasNext(); ) |
400 |
|
{ |
401 |
|
Extension e = (Extension) it.next(); |
402 |
|
if (e.isCritical()) |
403 |
|
s.add(e.getOid().toString()); |
404 |
|
} |
405 |
|
return Collections.unmodifiableSet(s); |
406 |
} |
} |
407 |
|
|
408 |
public Set getNonCriticalExtensionOIDs() |
public Set getNonCriticalExtensionOIDs() |
409 |
{ |
{ |
410 |
return Collections.unmodifiableSet(nonCritOids); |
HashSet s = new HashSet(); |
411 |
|
for (Iterator it = extensions.values().iterator(); it.hasNext(); ) |
412 |
|
{ |
413 |
|
Extension e = (Extension) it.next(); |
414 |
|
if (!e.isCritical()) |
415 |
|
s.add(e.getOid().toString()); |
416 |
|
} |
417 |
|
return Collections.unmodifiableSet(s); |
418 |
} |
} |
419 |
|
|
420 |
public byte[] getExtensionValue(String oid) |
public byte[] getExtensionValue(String oid) |
421 |
{ |
{ |
422 |
byte[] ext = (byte[]) extensions.get(oid); |
Extension e = getExtension(new OID(oid)); |
423 |
if (ext != null) |
if (e != null) |
424 |
return (byte[]) ext.clone(); |
{ |
425 |
|
return e.getValue().getEncoded(); |
426 |
|
} |
427 |
return null; |
return null; |
428 |
} |
} |
429 |
|
|
430 |
|
// GnuPKIExtension method. |
431 |
|
// ------------------------------------------------------------------------- |
432 |
|
|
433 |
|
public Extension getExtension(OID oid) |
434 |
|
{ |
435 |
|
return (Extension) extensions.get(oid); |
436 |
|
} |
437 |
|
|
438 |
|
public Collection getExtensions() |
439 |
|
{ |
440 |
|
return extensions.values(); |
441 |
|
} |
442 |
|
|
443 |
// Certificate methods. |
// Certificate methods. |
444 |
// ------------------------------------------------------------------------ |
// ------------------------------------------------------------------------- |
445 |
|
|
446 |
public byte[] getEncoded() throws CertificateEncodingException |
public byte[] getEncoded() throws CertificateEncodingException |
447 |
{ |
{ |
449 |
} |
} |
450 |
|
|
451 |
public void verify(PublicKey key) |
public void verify(PublicKey key) |
452 |
throws CertificateException, NoSuchAlgorithmException, |
throws CertificateException, NoSuchAlgorithmException, |
453 |
InvalidKeyException, NoSuchProviderException, SignatureException |
InvalidKeyException, NoSuchProviderException, SignatureException |
454 |
{ |
{ |
455 |
Signature sig = Signature.getInstance(sigAlgId.toString()); |
Signature sig = Signature.getInstance(sigAlgId.toString()); |
466 |
|
|
467 |
public String toString() |
public String toString() |
468 |
{ |
{ |
469 |
// XXX say more than this. |
StringWriter str = new StringWriter(); |
470 |
return gnu.java.security.x509.X509Certificate.class.getName(); |
PrintWriter out = new PrintWriter(str); |
471 |
|
out.println(X509Certificate.class.getName() + " {"); |
472 |
|
out.println(" TBSCertificate {"); |
473 |
|
out.println(" version = " + version + ";"); |
474 |
|
out.println(" serialNo = " + serialNo + ";"); |
475 |
|
out.println(" signature = {"); |
476 |
|
out.println(" algorithm = " + getSigAlgName() + ";"); |
477 |
|
out.print(" parameters ="); |
478 |
|
if (sigAlgVal != null) |
479 |
|
{ |
480 |
|
out.println(); |
481 |
|
out.print(Util.hexDump(sigAlgVal, " ")); |
482 |
|
} |
483 |
|
else |
484 |
|
{ |
485 |
|
out.println(" null;"); |
486 |
|
} |
487 |
|
out.println(" }"); |
488 |
|
out.println(" issuer = " + issuer.getName() + ";"); |
489 |
|
out.println(" validity = {"); |
490 |
|
out.println(" notBefore = " + notBefore + ";"); |
491 |
|
out.println(" notAfter = " + notAfter + ";"); |
492 |
|
out.println(" }"); |
493 |
|
out.println(" subject = " + subject.getName() + ";"); |
494 |
|
out.println(" subjectPublicKeyInfo = {"); |
495 |
|
out.println(" algorithm = " + subjectKey.getAlgorithm()); |
496 |
|
out.println(" key ="); |
497 |
|
out.print(Util.hexDump(subjectKey.getEncoded(), " ")); |
498 |
|
out.println(" };"); |
499 |
|
out.println(" issuerUniqueId = " + issuerUniqueId + ";"); |
500 |
|
out.println(" subjectUniqueId = " + subjectUniqueId + ";"); |
501 |
|
out.println(" extensions = {"); |
502 |
|
for (Iterator it = extensions.values().iterator(); it.hasNext(); ) |
503 |
|
{ |
504 |
|
out.println(" " + it.next()); |
505 |
|
} |
506 |
|
out.println(" }"); |
507 |
|
out.println(" }"); |
508 |
|
out.println(" signatureAlgorithm = " + getSigAlgName() + ";"); |
509 |
|
out.println(" signatureValue ="); |
510 |
|
out.print(Util.hexDump(signature, " ")); |
511 |
|
out.println("}"); |
512 |
|
return str.toString(); |
513 |
} |
} |
514 |
|
|
515 |
public PublicKey getPublicKey() |
public PublicKey getPublicKey() |
517 |
return subjectKey; |
return subjectKey; |
518 |
} |
} |
519 |
|
|
520 |
protected Object writeReplace() throws ObjectStreamException |
public boolean equals(Object other) |
521 |
{ |
{ |
522 |
return super.writeReplace(); |
if (!(other instanceof X509Certificate)) |
523 |
|
return false; |
524 |
|
try |
525 |
|
{ |
526 |
|
if (other instanceof X509Certificate) |
527 |
|
return Arrays.equals(encoded, ((X509Certificate) other).encoded); |
528 |
|
byte[] enc = ((X509Certificate) other).getEncoded(); |
529 |
|
if (enc == null) |
530 |
|
return false; |
531 |
|
return Arrays.equals(encoded, enc); |
532 |
|
} |
533 |
|
catch (CertificateEncodingException cee) |
534 |
|
{ |
535 |
|
return false; |
536 |
|
} |
537 |
} |
} |
538 |
|
|
539 |
// Own methods. |
// Own methods. |
540 |
// ------------------------------------------------------------------------ |
// ------------------------------------------------------------------------ |
541 |
|
|
545 |
private void doVerify(Signature sig, PublicKey key) |
private void doVerify(Signature sig, PublicKey key) |
546 |
throws CertificateException, InvalidKeyException, SignatureException |
throws CertificateException, InvalidKeyException, SignatureException |
547 |
{ |
{ |
548 |
|
debug("verifying sig=" + sig + " key=" + key); |
549 |
sig.initVerify(key); |
sig.initVerify(key); |
550 |
sig.update(tbsCertBytes); |
sig.update(tbsCertBytes); |
551 |
if (!sig.verify(signature)) |
if (!sig.verify(signature)) |
|
throw new CertificateException("signature not validated"); |
|
|
} |
|
|
|
|
|
/** |
|
|
* Read a GeneralNames structure. |
|
|
*/ |
|
|
private List getAltNames(byte[] encoded) |
|
|
throws CertificateParsingException |
|
|
{ |
|
|
LinkedList names = new LinkedList(); |
|
|
try |
|
552 |
{ |
{ |
553 |
ByteArrayInputStream in = new ByteArrayInputStream(encoded); |
throw new CertificateException("signature not validated"); |
|
DERReader der = new DERReader(in); |
|
|
DERValue seq = der.read(); |
|
|
if (!seq.isConstructed()) |
|
|
throw new CertificateParsingException(); |
|
|
int len = 0; |
|
|
while (len < seq.getLength()) |
|
|
{ |
|
|
DERValue name = der.read(); |
|
|
ArrayList pair = new ArrayList(2); |
|
|
Object nameVal = null; |
|
|
switch (name.getTag()) |
|
|
{ |
|
|
case RFC882_NAME: |
|
|
case DNS_NAME: |
|
|
case URI: |
|
|
nameVal = new String((byte[]) name.getValue()); |
|
|
break; |
|
|
case IP_ADDRESS: |
|
|
nameVal = InetAddress.getByAddress( |
|
|
(byte[]) name.getValue()).getHostAddress(); |
|
|
break; |
|
|
case REGISTERED_ID: |
|
|
nameVal = new OID((byte[]) name.getValue()); |
|
|
break; |
|
|
case OTHER_NAME: |
|
|
case X400_ADDRESS: |
|
|
case DIRECTORY_NAME: |
|
|
case EDI_PARTY_NAME: |
|
|
nameVal = name.getEncoded(); |
|
|
break; |
|
|
default: |
|
|
throw new CertificateParsingException(); |
|
|
} |
|
|
pair.add(new Integer(name.getTag())); |
|
|
pair.add(nameVal); |
|
|
names.add(pair); |
|
|
if (name.isConstructed()) |
|
|
in.skip(name.getLength()); |
|
|
len += name.getEncodedLength(); |
|
|
} |
|
554 |
} |
} |
|
catch (IOException ioe) |
|
|
{ |
|
|
throw new CertificateParsingException(ioe.toString()); |
|
|
} |
|
|
return Collections.unmodifiableList(names); |
|
555 |
} |
} |
556 |
|
|
557 |
/** |
/** |
565 |
|
|
566 |
// Certificate ::= SEQUENCE { |
// Certificate ::= SEQUENCE { |
567 |
DERValue cert = der.read(); |
DERValue cert = der.read(); |
568 |
|
debug("start Certificate len == " + cert.getLength()); |
569 |
|
|
570 |
this.encoded = cert.getEncoded(); |
this.encoded = cert.getEncoded(); |
571 |
if (!cert.isConstructed()) |
if (!cert.isConstructed()) |
572 |
throw new ASN1ParsingException("malformed Certificate"); |
{ |
573 |
|
throw new IOException("malformed Certificate"); |
574 |
|
} |
575 |
|
|
576 |
// TBSCertificate ::= SEQUENCE { |
// TBSCertificate ::= SEQUENCE { |
577 |
DERValue tbsCert = der.read(); |
DERValue tbsCert = der.read(); |
578 |
if (tbsCert.getValue() != DER.CONSTRUCTED_VALUE) |
if (tbsCert.getValue() != DER.CONSTRUCTED_VALUE) |
579 |
throw new ASN1ParsingException("malformed TBSCertificate"); |
{ |
580 |
|
throw new IOException("malformed TBSCertificate"); |
581 |
|
} |
582 |
tbsCertBytes = tbsCert.getEncoded(); |
tbsCertBytes = tbsCert.getEncoded(); |
583 |
|
debug("start TBSCertificate len == " + tbsCert.getLength()); |
584 |
|
|
585 |
|
// Version ::= INTEGER [0] { v1(0), v2(1), v3(2) } |
586 |
DERValue val = der.read(); |
DERValue val = der.read(); |
587 |
if (val.getTagClass() == DER.CONTEXT && val.getTag() == 0) |
if (val.getTagClass() == DER.CONTEXT && val.getTag() == 0) |
588 |
{ |
{ |
|
// Version ::= INTEGER [0] { v1(0), v2(1), v3(2) } |
|
589 |
version = ((BigInteger) der.read().getValue()).intValue() + 1; |
version = ((BigInteger) der.read().getValue()).intValue() + 1; |
590 |
val = der.read(); |
val = der.read(); |
591 |
} |
} |
593 |
{ |
{ |
594 |
version = 1; |
version = 1; |
595 |
} |
} |
596 |
|
debug("read version == " + version); |
597 |
|
|
598 |
// SerialNumber ::= INTEGER |
// SerialNumber ::= INTEGER |
599 |
serialNo = (BigInteger) val.getValue(); |
serialNo = (BigInteger) val.getValue(); |
600 |
|
debug("read serial number == " + serialNo); |
601 |
|
|
602 |
// AlgorithmIdentifier ::= SEQUENCE { |
// AlgorithmIdentifier ::= SEQUENCE { |
603 |
val = der.read(); |
val = der.read(); |
604 |
if (!val.isConstructed()) |
if (!val.isConstructed()) |
605 |
throw new ASN1ParsingException("malformed AlgorithmIdentifier"); |
{ |
606 |
|
throw new IOException("malformed AlgorithmIdentifier"); |
607 |
|
} |
608 |
int certAlgLen = val.getLength(); |
int certAlgLen = val.getLength(); |
609 |
|
debug("start AlgorithmIdentifier len == " + certAlgLen); |
610 |
val = der.read(); |
val = der.read(); |
611 |
|
|
612 |
|
// algorithm OBJECT IDENTIFIER, |
613 |
algId = (OID) val.getValue(); |
algId = (OID) val.getValue(); |
614 |
|
debug("read algorithm ID == " + algId); |
615 |
|
|
616 |
|
// parameters ANY DEFINED BY algorithm OPTIONAL } |
617 |
if (certAlgLen > val.getEncodedLength()) |
if (certAlgLen > val.getEncodedLength()) |
618 |
{ |
{ |
619 |
val = der.read(); |
val = der.read(); |
620 |
if (val == null) |
if (val == null) |
621 |
algVal = null; |
{ |
622 |
|
algVal = null; |
623 |
|
} |
624 |
else |
else |
625 |
algVal = val.getEncoded(); |
{ |
626 |
|
algVal = val.getEncoded(); |
627 |
|
} |
628 |
if (val.isConstructed()) |
if (val.isConstructed()) |
629 |
encoded.skip(val.getLength()); |
{ |
630 |
|
encoded.skip(val.getLength()); |
631 |
|
} |
632 |
|
debug("read algorithm parameters == " + algVal); |
633 |
} |
} |
634 |
|
|
635 |
issuer = new X500Principal(encoded); |
// issuer Name, |
636 |
|
val = der.read(); |
637 |
|
issuer = new X500DistinguishedName(val.getEncoded()); |
638 |
|
der.skip(val.getLength()); |
639 |
|
debug("read issuer == " + issuer); |
640 |
|
|
641 |
|
// Validity ::= SEQUENCE { |
642 |
|
// notBefore Time, |
643 |
|
// notAfter Time } |
644 |
if (!der.read().isConstructed()) |
if (!der.read().isConstructed()) |
645 |
throw new ASN1ParsingException("malformed Validity"); |
{ |
646 |
|
throw new IOException("malformed Validity"); |
647 |
|
} |
648 |
notBefore = (Date) der.read().getValue(); |
notBefore = (Date) der.read().getValue(); |
649 |
notAfter = (Date) der.read().getValue(); |
notAfter = (Date) der.read().getValue(); |
650 |
|
debug("read notBefore == " + notBefore); |
651 |
|
debug("read notAfter == " + notAfter); |
652 |
|
|
653 |
subject = new X500Principal(encoded); |
// subject Name, |
|
|
|
|
if (!der.read().isConstructed()) |
|
|
throw new ASN1ParsingException("malformed SubjectPublicKeyInfo"); |
|
|
|
|
|
val = der.read(); |
|
|
if (!val.isConstructed()) |
|
|
throw new ASN1ParsingException("malformed AlgorithmIdentifier"); |
|
|
int keyAlgLen = val.getLength(); |
|
654 |
val = der.read(); |
val = der.read(); |
655 |
OID keyID = (OID) val.getValue(); |
subject = new X500DistinguishedName(val.getEncoded()); |
656 |
byte[] keyParams = null; |
der.skip(val.getLength()); |
657 |
if (keyAlgLen > val.getEncodedLength()) |
debug("read subject == " + subject); |
658 |
{ |
|
659 |
val = der.read(); |
// SubjectPublicKeyInfo ::= SEQUENCE { |
660 |
keyParams = val.getEncoded(); |
// algorithm AlgorithmIdentifier, |
661 |
if (algVal == null) |
// subjectPublicKey BIT STRING } |
662 |
algVal = keyParams; |
DERValue spki = der.read(); |
663 |
if (val.isConstructed()) |
if (!spki.isConstructed()) |
664 |
encoded.skip(val.getLength()); |
{ |
665 |
} |
throw new IOException("malformed SubjectPublicKeyInfo"); |
666 |
val = der.read(); |
} |
667 |
byte[] keyVal = ((BitString) val.getValue()).toByteArray(); |
KeyFactory spkFac = KeyFactory.getInstance("X.509"); |
668 |
|
subjectKey = spkFac.generatePublic(new X509EncodedKeySpec(spki.getEncoded())); |
669 |
|
der.skip(spki.getLength()); |
670 |
|
debug("read subjectPublicKey == " + subjectKey); |
671 |
|
|
672 |
if (keyID.equals(ID_DSA)) |
if (version > 1) |
673 |
{ |
{ |
674 |
AlgorithmParameters params = AlgorithmParameters.getInstance("DSA"); |
val = der.read(); |
|
params.init(keyParams, "ASN.1"); |
|
|
KeyFactory keyFac = KeyFactory.getInstance("DSA"); |
|
|
DSAParameterSpec spec = (DSAParameterSpec) |
|
|
params.getParameterSpec(DSAParameterSpec.class); |
|
|
subjectKey = keyFac.generatePublic(new DSAPublicKeySpec( |
|
|
(BigInteger) new DERReader(keyVal).read().getValue(), |
|
|
spec.getP(), spec.getQ(), spec.getG())); |
|
|
} |
|
|
else if (keyID.equals(ID_RSA)) |
|
|
{ |
|
|
KeyFactory keyFac = KeyFactory.getInstance("RSA"); |
|
|
DERReader rsaKey = new DERReader(keyVal); |
|
|
if (!rsaKey.read().isConstructed()) |
|
|
throw new ASN1ParsingException("malformed RSAPublicKey"); |
|
|
subjectKey = keyFac.generatePublic(new RSAPublicKeySpec( |
|
|
(BigInteger) rsaKey.read().getValue(), |
|
|
(BigInteger) rsaKey.read().getValue())); |
|
675 |
} |
} |
|
else |
|
|
throw new ASN1ParsingException("unknown key algorithm " + keyID); |
|
|
|
|
|
if (version > 1) |
|
|
val = der.read(); |
|
676 |
if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 1) |
if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 1) |
677 |
{ |
{ |
678 |
byte[] b = (byte[]) val.getValue(); |
byte[] b = (byte[]) val.getValue(); |
679 |
issuerUniqueId = new BitString(b, 1, b.length-1, b[0] & 0xFF); |
issuerUniqueId = new BitString(b, 1, b.length-1, b[0] & 0xFF); |
680 |
|
debug("read issuerUniqueId == " + issuerUniqueId); |
681 |
val = der.read(); |
val = der.read(); |
682 |
} |
} |
683 |
if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 2) |
if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 2) |
684 |
{ |
{ |
685 |
byte[] b = (byte[]) val.getValue(); |
byte[] b = (byte[]) val.getValue(); |
686 |
subjectUniqueId = new BitString(b, 1, b.length-1, b[0] & 0xFF); |
subjectUniqueId = new BitString(b, 1, b.length-1, b[0] & 0xFF); |
687 |
|
debug("read subjectUniqueId == " + subjectUniqueId); |
688 |
val = der.read(); |
val = der.read(); |
689 |
} |
} |
690 |
if (version >= 3 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 3) |
if (version >= 3 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 3) |
691 |
{ |
{ |
692 |
val = der.read(); |
val = der.read(); |
693 |
|
debug("start Extensions len == " + val.getLength()); |
694 |
int len = 0; |
int len = 0; |
695 |
while (len < val.getLength()) |
while (len < val.getLength()) |
696 |
{ |
{ |
697 |
DERValue ext = der.read(); |
DERValue ext = der.read(); |
698 |
OID extId = (OID) der.read().getValue(); |
debug("start extension len == " + ext.getLength()); |
699 |
DERValue val2 = der.read(); |
Extension e = new Extension(ext.getEncoded()); |
700 |
Boolean crit = Boolean.valueOf(false); |
extensions.put(e.getOid(), e); |
701 |
if (val2.getValue() instanceof Boolean) |
der.skip(ext.getLength()); |
|
{ |
|
|
crit = (Boolean) val2.getValue(); |
|
|
val2 = der.read(); |
|
|
} |
|
|
byte[] extVal = (byte[]) val2.getValue(); |
|
|
extensions.put(extId.toString(), extVal); |
|
|
if (crit.booleanValue()) |
|
|
critOids.add(extId.toString()); |
|
|
else |
|
|
nonCritOids.add(extId.toString()); |
|
|
if (extId.equals(ID_KEY_USAGE)) |
|
|
{ |
|
|
keyUsage = (BitString) DERReader.read(extVal).getValue(); |
|
|
} |
|
|
else if (extId.equals(ID_BASIC_CONSTRAINTS)) |
|
|
{ |
|
|
DERReader bc = new DERReader(extVal); |
|
|
DERValue constraints = bc.read(); |
|
|
if (!constraints.isConstructed()) |
|
|
throw new ASN1ParsingException("malformed BasicConstraints"); |
|
|
if (constraints.getLength() > 0) |
|
|
{ |
|
|
boolean ca = false; |
|
|
int constr = -1; |
|
|
val2 = bc.read(); |
|
|
if (val2.getValue() instanceof Boolean) |
|
|
{ |
|
|
ca = ((Boolean) val2.getValue()).booleanValue(); |
|
|
if (constraints.getLength() > val2.getEncodedLength()) |
|
|
val2 = bc.read(); |
|
|
} |
|
|
if (val2.getValue() instanceof BigInteger) |
|
|
constr = ((BigInteger) val2.getValue()).intValue(); |
|
|
basicConstraints = constr; |
|
|
} |
|
|
} |
|
702 |
len += ext.getEncodedLength(); |
len += ext.getEncodedLength(); |
703 |
|
debug("count == " + len); |
704 |
} |
} |
705 |
} |
} |
706 |
|
|
707 |
val = der.read(); |
val = der.read(); |
708 |
if (!val.isConstructed()) |
if (!val.isConstructed()) |
709 |
throw new ASN1ParsingException("malformed AlgorithmIdentifier"); |
{ |
710 |
|
throw new IOException("malformed AlgorithmIdentifier"); |
711 |
|
} |
712 |
int sigAlgLen = val.getLength(); |
int sigAlgLen = val.getLength(); |
713 |
|
debug("start AlgorithmIdentifier len == " + sigAlgLen); |
714 |
val = der.read(); |
val = der.read(); |
715 |
sigAlgId = (OID) val.getValue(); |
sigAlgId = (OID) val.getValue(); |
716 |
|
debug("read algorithm id == " + sigAlgId); |
717 |
if (sigAlgLen > val.getEncodedLength()) |
if (sigAlgLen > val.getEncodedLength()) |
718 |
{ |
{ |
719 |
val = der.read(); |
val = der.read(); |
720 |
if (val.getValue() == null) |
if (val.getValue() == null) |
721 |
sigAlgVal = keyParams; |
{ |
722 |
|
if (subjectKey instanceof DSAPublicKey) |
723 |
|
{ |
724 |
|
AlgorithmParameters params = |
725 |
|
AlgorithmParameters.getInstance("DSA"); |
726 |
|
DSAParams dsap = ((DSAPublicKey) subjectKey).getParams(); |
727 |
|
DSAParameterSpec spec = |
728 |
|
new DSAParameterSpec(dsap.getP(), dsap.getQ(), dsap.getG()); |
729 |
|
params.init(spec); |
730 |
|
sigAlgVal = params.getEncoded(); |
731 |
|
} |
732 |
|
} |
733 |
else |
else |
734 |
sigAlgVal = (byte[]) val.getEncoded(); |
{ |
735 |
|
sigAlgVal = (byte[]) val.getEncoded(); |
736 |
|
} |
737 |
if (val.isConstructed()) |
if (val.isConstructed()) |
738 |
encoded.skip(val.getLength()); |
{ |
739 |
|
encoded.skip(val.getLength()); |
740 |
|
} |
741 |
|
debug("read parameters == " + sigAlgVal); |
742 |
} |
} |
743 |
signature = ((BitString) der.read().getValue()).toByteArray(); |
signature = ((BitString) der.read().getValue()).toByteArray(); |
744 |
|
debug("read signature ==\n" + Util.hexDump(signature, ">>>> ")); |
745 |
} |
} |
746 |
} |
} |