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 |
44 |
import gnu.java.security.der.DER; |
import gnu.java.security.der.DER; |
45 |
import gnu.java.security.der.DERReader; |
import gnu.java.security.der.DERReader; |
46 |
import gnu.java.security.der.DERValue; |
import gnu.java.security.der.DERValue; |
47 |
|
import gnu.java.security.x509.ext.Extension; |
48 |
|
|
49 |
import java.io.InputStream; |
import java.io.InputStream; |
50 |
import java.io.IOException; |
import java.io.IOException; |
58 |
import java.security.SignatureException; |
import java.security.SignatureException; |
59 |
import java.security.cert.Certificate; |
import java.security.cert.Certificate; |
60 |
import java.security.cert.CRLException; |
import java.security.cert.CRLException; |
61 |
import java.security.cert.X509CRLEntry; |
import java.util.Collection; |
62 |
import java.util.Collections; |
import java.util.Collections; |
63 |
import java.util.Date; |
import java.util.Date; |
64 |
import java.util.HashSet; |
import java.util.HashSet; |
65 |
import java.util.HashMap; |
import java.util.HashMap; |
66 |
|
import java.util.Iterator; |
67 |
import java.util.Set; |
import java.util.Set; |
68 |
|
|
69 |
import javax.security.auth.x500.X500Principal; |
import javax.security.auth.x500.X500Principal; |
74 |
* @author Casey Marshall (rsdio@metastatic.org) |
* @author Casey Marshall (rsdio@metastatic.org) |
75 |
*/ |
*/ |
76 |
public class X509CRL extends java.security.cert.X509CRL |
public class X509CRL extends java.security.cert.X509CRL |
77 |
|
implements GnuPKIExtension |
78 |
{ |
{ |
79 |
|
|
80 |
// Constants and fields. |
// Constants and fields. |
81 |
// ------------------------------------------------------------------------ |
// ------------------------------------------------------------------------ |
82 |
|
|
83 |
|
private static final boolean DEBUG = false; |
84 |
|
private static void debug(String msg) |
85 |
|
{ |
86 |
|
if (DEBUG) |
87 |
|
{ |
88 |
|
System.err.print(">> X509CRL: "); |
89 |
|
System.err.println(msg); |
90 |
|
} |
91 |
|
} |
92 |
|
|
93 |
private static final OID ID_DSA = new OID("1.2.840.10040.4.1"); |
private static final OID ID_DSA = new OID("1.2.840.10040.4.1"); |
94 |
private static final OID ID_DSA_WITH_SHA1 = new OID("1.2.840.10040.4.3"); |
private static final OID ID_DSA_WITH_SHA1 = new OID("1.2.840.10040.4.3"); |
95 |
private static final OID ID_RSA = new OID("1.2.840.113549.1.1.1"); |
private static final OID ID_RSA = new OID("1.2.840.113549.1.1.1"); |
105 |
private byte[] algParams; |
private byte[] algParams; |
106 |
private Date thisUpdate; |
private Date thisUpdate; |
107 |
private Date nextUpdate; |
private Date nextUpdate; |
108 |
private X500Principal issuerDN; |
private X500DistinguishedName issuerDN; |
109 |
private HashMap revokedCerts; |
private HashMap revokedCerts; |
110 |
private HashMap extensions; |
private HashMap extensions; |
111 |
private HashSet critOids; |
|
|
private HashSet nonCritOids; |
|
|
|
|
112 |
private OID sigAlg; |
private OID sigAlg; |
113 |
private byte[] sigAlgParams; |
private byte[] sigAlgParams; |
114 |
private byte[] rawSig; |
private byte[] rawSig; |
129 |
super(); |
super(); |
130 |
revokedCerts = new HashMap(); |
revokedCerts = new HashMap(); |
131 |
extensions = new HashMap(); |
extensions = new HashMap(); |
|
critOids = new HashSet(); |
|
|
nonCritOids = new HashSet(); |
|
132 |
try |
try |
133 |
{ |
{ |
134 |
parse(encoded); |
parse(encoded); |
150 |
|
|
151 |
public boolean equals(Object o) |
public boolean equals(Object o) |
152 |
{ |
{ |
153 |
return ((X509CRL) o).revokedCerts.equals(revokedCerts); |
if (!(o instanceof X509CRL)) |
154 |
|
return false; |
155 |
|
return ((X509CRL) o).getRevokedCertificates().equals(revokedCerts.values()); |
156 |
} |
} |
157 |
|
|
158 |
public int hashCode() |
public int hashCode() |
193 |
|
|
194 |
public X500Principal getIssuerX500Principal() |
public X500Principal getIssuerX500Principal() |
195 |
{ |
{ |
196 |
return issuerDN; |
return new X500Principal(issuerDN.getDer()); |
197 |
} |
} |
198 |
|
|
199 |
public Date getThisUpdate() |
public Date getThisUpdate() |
208 |
return null; |
return null; |
209 |
} |
} |
210 |
|
|
211 |
public X509CRLEntry getRevokedCertificate(BigInteger serialNo) |
public java.security.cert.X509CRLEntry getRevokedCertificate(BigInteger serialNo) |
212 |
{ |
{ |
213 |
return (X509CRLEntry) revokedCerts.get(serialNo); |
return (java.security.cert.X509CRLEntry) revokedCerts.get(serialNo); |
214 |
} |
} |
215 |
|
|
216 |
public Set getRevokedCertificates() |
public Set getRevokedCertificates() |
258 |
|
|
259 |
public boolean hasUnsupportedCriticalExtension() |
public boolean hasUnsupportedCriticalExtension() |
260 |
{ |
{ |
261 |
return false; // XXX |
for (Iterator it = extensions.values().iterator(); it.hasNext(); ) |
262 |
|
{ |
263 |
|
Extension e = (Extension) it.next(); |
264 |
|
if (e.isCritical() && !e.isSupported()) |
265 |
|
return true; |
266 |
|
} |
267 |
|
return false; |
268 |
} |
} |
269 |
|
|
270 |
public Set getCriticalExtensionOIDs() |
public Set getCriticalExtensionOIDs() |
271 |
{ |
{ |
272 |
return Collections.unmodifiableSet(critOids); |
HashSet s = new HashSet(); |
273 |
|
for (Iterator it = extensions.values().iterator(); it.hasNext(); ) |
274 |
|
{ |
275 |
|
Extension e = (Extension) it.next(); |
276 |
|
if (e.isCritical()) |
277 |
|
s.add(e.getOid().toString()); |
278 |
|
} |
279 |
|
return Collections.unmodifiableSet(s); |
280 |
} |
} |
281 |
|
|
282 |
public Set getNonCriticalExtensionOIDs() |
public Set getNonCriticalExtensionOIDs() |
283 |
{ |
{ |
284 |
return Collections.unmodifiableSet(nonCritOids); |
HashSet s = new HashSet(); |
285 |
|
for (Iterator it = extensions.values().iterator(); it.hasNext(); ) |
286 |
|
{ |
287 |
|
Extension e = (Extension) it.next(); |
288 |
|
if (!e.isCritical()) |
289 |
|
s.add(e.getOid().toString()); |
290 |
|
} |
291 |
|
return Collections.unmodifiableSet(s); |
292 |
} |
} |
293 |
|
|
294 |
public byte[] getExtensionValue(String oid) |
public byte[] getExtensionValue(String oid) |
295 |
{ |
{ |
296 |
byte[] ext = (byte[]) extensions.get(oid); |
Extension e = getExtension(new OID(oid)); |
297 |
if (ext != null) |
if (e != null) |
298 |
return (byte[]) ext.clone(); |
{ |
299 |
|
return e.getValue().getEncoded(); |
300 |
|
} |
301 |
return null; |
return null; |
302 |
} |
} |
303 |
|
|
304 |
|
// GnuPKIExtension method. |
305 |
|
// ------------------------------------------------------------------------- |
306 |
|
|
307 |
|
public Extension getExtension(OID oid) |
308 |
|
{ |
309 |
|
return (Extension) extensions.get(oid); |
310 |
|
} |
311 |
|
|
312 |
|
public Collection getExtensions() |
313 |
|
{ |
314 |
|
return extensions.values(); |
315 |
|
} |
316 |
|
|
317 |
// CRL methods. |
// CRL methods. |
318 |
// ------------------------------------------------------------------------ |
// ------------------------------------------------------------------------- |
319 |
|
|
320 |
public String toString() |
public String toString() |
321 |
{ |
{ |
322 |
return gnu.java.security.x509.X509CRL.class.getName(); |
return X509CRL.class.getName(); |
323 |
} |
} |
324 |
|
|
325 |
public boolean isRevoked(Certificate cert) |
public boolean isRevoked(Certificate cert) |
348 |
|
|
349 |
private void parse(InputStream in) throws Exception |
private void parse(InputStream in) throws Exception |
350 |
{ |
{ |
351 |
|
// CertificateList ::= SEQUENCE { |
352 |
DERReader der = new DERReader(in); |
DERReader der = new DERReader(in); |
353 |
DERValue val = der.read(); |
DERValue val = der.read(); |
354 |
|
debug("start CertificateList len == " + val.getLength()); |
355 |
if (!val.isConstructed()) |
if (!val.isConstructed()) |
356 |
throw new ASN1ParsingException("malformed CertificateList"); |
throw new IOException("malformed CertificateList"); |
357 |
encoded = val.getEncoded(); |
encoded = val.getEncoded(); |
358 |
|
|
359 |
|
// tbsCertList ::= SEQUENCE { -- TBSCertList |
360 |
val = der.read(); |
val = der.read(); |
361 |
if (!val.isConstructed()) |
if (!val.isConstructed()) |
362 |
throw new ASN1ParsingException("malformed TBSCertList"); |
throw new IOException("malformed TBSCertList"); |
363 |
|
debug("start tbsCertList len == " + val.getLength()); |
364 |
tbsCRLBytes = val.getEncoded(); |
tbsCRLBytes = val.getEncoded(); |
365 |
|
|
366 |
|
// version Version OPTIONAL, |
367 |
|
// -- If present must be v2 |
368 |
val = der.read(); |
val = der.read(); |
369 |
if (val.getValue() instanceof BigInteger) |
if (val.getValue() instanceof BigInteger) |
370 |
{ |
{ |
373 |
} |
} |
374 |
else |
else |
375 |
version = 1; |
version = 1; |
376 |
|
debug("read version == " + version); |
377 |
|
|
378 |
|
// signature AlgorithmIdentifier, |
379 |
|
debug("start AlgorithmIdentifier len == " + val.getLength()); |
380 |
if (!val.isConstructed()) |
if (!val.isConstructed()) |
381 |
throw new ASN1ParsingException("malformed AlgorithmIdentifier"); |
throw new IOException("malformed AlgorithmIdentifier"); |
382 |
DERValue algIdVal = der.read(); |
DERValue algIdVal = der.read(); |
383 |
algId = (OID) algIdVal.getValue(); |
algId = (OID) algIdVal.getValue(); |
384 |
|
debug("read object identifier == " + algId); |
385 |
if (val.getLength() > algIdVal.getEncodedLength()) |
if (val.getLength() > algIdVal.getEncodedLength()) |
386 |
{ |
{ |
387 |
val = der.read(); |
val = der.read(); |
388 |
|
debug("read parameters len == " + val.getEncodedLength()); |
389 |
algParams = val.getEncoded(); |
algParams = val.getEncoded(); |
390 |
if (val.isConstructed()) |
if (val.isConstructed()) |
391 |
in.skip(val.getLength()); |
in.skip(val.getLength()); |
392 |
} |
} |
393 |
|
|
394 |
issuerDN = new X500Principal(in); |
// issuer Name, |
395 |
|
val = der.read(); |
396 |
|
issuerDN = new X500DistinguishedName(val.getEncoded()); |
397 |
|
der.skip(val.getLength()); |
398 |
|
debug("read issuer == " + issuerDN); |
399 |
|
|
400 |
|
// thisUpdate Time, |
401 |
thisUpdate = (Date) der.read().getValue(); |
thisUpdate = (Date) der.read().getValue(); |
402 |
|
debug("read thisUpdate == " + thisUpdate); |
403 |
|
|
404 |
|
// nextUpdate Time OPTIONAL, |
405 |
val = der.read(); |
val = der.read(); |
406 |
if (val.getValue() instanceof Date) |
if (val.getValue() instanceof Date) |
407 |
{ |
{ |
408 |
nextUpdate = (Date) val.getValue(); |
nextUpdate = (Date) val.getValue(); |
409 |
|
debug("read nextUpdate == " + nextUpdate); |
410 |
val = der.read(); |
val = der.read(); |
411 |
} |
} |
412 |
|
|
413 |
|
// revokedCertificates SEQUENCE OF SEQUENCE { |
414 |
|
// -- X509CRLEntry objects... |
415 |
|
// } OPTIONAL, |
416 |
if (val.getTag() != 0) |
if (val.getTag() != 0) |
417 |
{ |
{ |
418 |
int len = 0; |
int len = 0; |
419 |
while (len < val.getLength()) |
while (len < val.getLength()) |
420 |
{ |
{ |
421 |
X509CRLEntry entry = |
X509CRLEntry entry = new X509CRLEntry(version, der); |
|
new gnu.java.security.x509.X509CRLEntry(version, in); |
|
422 |
revokedCerts.put(entry.getSerialNumber(), entry); |
revokedCerts.put(entry.getSerialNumber(), entry); |
423 |
len += entry.getEncoded().length; |
len += entry.getEncoded().length; |
424 |
} |
} |
425 |
|
val = der.read(); |
426 |
} |
} |
427 |
if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 0) |
|
428 |
|
// crlExtensions [0] EXPLICIT Extensions OPTIONAL |
429 |
|
// -- if present MUST be v2 |
430 |
|
if (val.getTagClass() != DER.UNIVERSAL && val.getTag() == 0) |
431 |
{ |
{ |
432 |
val = der.read(); |
if (version < 2) |
433 |
|
throw new IOException("extra data in CRL"); |
434 |
|
DERValue exts = der.read(); |
435 |
|
if (!exts.isConstructed()) |
436 |
|
throw new IOException("malformed Extensions"); |
437 |
|
debug("start Extensions len == " + exts.getLength()); |
438 |
int len = 0; |
int len = 0; |
439 |
while (len < val.getLength()) |
while (len < exts.getLength()) |
440 |
{ |
{ |
441 |
DERValue ext = der.read(); |
DERValue ext = der.read(); |
442 |
OID extId = (OID) der.read().getValue(); |
if (!ext.isConstructed()) |
443 |
DERValue val2 = der.read(); |
throw new IOException("malformed Extension"); |
444 |
Boolean crit = Boolean.valueOf(false); |
Extension e = new Extension(ext.getEncoded()); |
445 |
if (val2.getValue() instanceof Boolean) |
extensions.put(e.getOid(), e); |
446 |
{ |
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()); |
|
447 |
len += ext.getEncodedLength(); |
len += ext.getEncodedLength(); |
448 |
|
debug("current count == " + len); |
449 |
} |
} |
450 |
|
val = der.read(); |
451 |
} |
} |
452 |
|
|
453 |
val = der.read(); |
debug("read tag == " + val.getTag()); |
454 |
if (!val.isConstructed()) |
if (!val.isConstructed()) |
455 |
throw new ASN1ParsingException("malformed AlgorithmIdentifier"); |
throw new IOException("malformed AlgorithmIdentifier"); |
456 |
|
debug("start AlgorithmIdentifier len == " + val.getLength()); |
457 |
DERValue sigAlgVal = der.read(); |
DERValue sigAlgVal = der.read(); |
458 |
|
debug("read tag == " + sigAlgVal.getTag()); |
459 |
|
if (sigAlgVal.getTag() != DER.OBJECT_IDENTIFIER) |
460 |
|
throw new IOException("malformed AlgorithmIdentifier"); |
461 |
sigAlg = (OID) sigAlgVal.getValue(); |
sigAlg = (OID) sigAlgVal.getValue(); |
462 |
|
debug("signature id == " + sigAlg); |
463 |
|
debug("sigAlgVal length == " + sigAlgVal.getEncodedLength()); |
464 |
if (val.getLength() > sigAlgVal.getEncodedLength()) |
if (val.getLength() > sigAlgVal.getEncodedLength()) |
465 |
{ |
{ |
466 |
val = der.read(); |
val = der.read(); |
467 |
|
debug("sig params tag = " + val.getTag() + " len == " + val.getEncodedLength()); |
468 |
sigAlgParams = (byte[]) val.getEncoded(); |
sigAlgParams = (byte[]) val.getEncoded(); |
469 |
if (val.isConstructed()) |
if (val.isConstructed()) |
470 |
in.skip(val.getLength()); |
in.skip(val.getLength()); |
471 |
} |
} |
472 |
val = der.read(); |
val = der.read(); |
473 |
|
debug("read tag = " + val.getTag()); |
474 |
rawSig = val.getEncoded(); |
rawSig = val.getEncoded(); |
475 |
signature = ((BitString) val.getValue()).toByteArray(); |
signature = ((BitString) val.getValue()).toByteArray(); |
476 |
} |
} |