1 |
/* X509CRLEntry.java -- entry in a X.509 CRL. |
/* X509CRLEntry.java -- an entry in a X.509 CRL. |
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 |
45 |
|
|
46 |
import java.security.cert.CRLException; |
import java.security.cert.CRLException; |
47 |
|
|
48 |
|
import java.util.Collection; |
49 |
import java.util.Collections; |
import java.util.Collections; |
50 |
import java.util.Date; |
import java.util.Date; |
51 |
import java.util.HashMap; |
import java.util.HashMap; |
52 |
import java.util.HashSet; |
import java.util.HashSet; |
53 |
|
import java.util.Iterator; |
54 |
import java.util.Set; |
import java.util.Set; |
55 |
|
|
|
import gnu.java.io.ASN1ParsingException; |
|
56 |
import gnu.java.security.OID; |
import gnu.java.security.OID; |
57 |
import gnu.java.security.der.DERReader; |
import gnu.java.security.der.*; |
58 |
import gnu.java.security.der.DERValue; |
import gnu.java.security.x509.ext.*; |
|
import gnu.java.security.der.DERWriter; |
|
59 |
|
|
60 |
/** |
/** |
61 |
* A single entry in a X.509 certificate revocation list. |
* A single entry in a X.509 certificate revocation list. |
64 |
* @author Casey Marshall |
* @author Casey Marshall |
65 |
*/ |
*/ |
66 |
class X509CRLEntry extends java.security.cert.X509CRLEntry |
class X509CRLEntry extends java.security.cert.X509CRLEntry |
67 |
|
implements GnuPKIExtension |
68 |
{ |
{ |
69 |
|
|
70 |
// Constants and fields. |
// Constants and fields. |
71 |
// ------------------------------------------------------------------------ |
// ------------------------------------------------------------------------ |
72 |
|
|
73 |
|
private static final boolean DEBUG = false; |
74 |
|
private static void debug(String msg) |
75 |
|
{ |
76 |
|
if (DEBUG) |
77 |
|
{ |
78 |
|
System.err.print(">> X509CRLEntry: "); |
79 |
|
System.err.println(msg); |
80 |
|
} |
81 |
|
} |
82 |
|
|
83 |
/** The DER encoded form of this CRL entry. */ |
/** The DER encoded form of this CRL entry. */ |
84 |
private byte[] encoded; |
private byte[] encoded; |
85 |
|
|
89 |
/** The date the certificate was revoked. */ |
/** The date the certificate was revoked. */ |
90 |
private Date revocationDate; |
private Date revocationDate; |
91 |
|
|
92 |
/** The encoded extensions. */ |
/** The CRL entry extensions. */ |
93 |
private HashMap extensions; |
private HashMap extensions; |
94 |
|
|
|
/** The set of critical extension OIDs. */ |
|
|
private HashSet critOids; |
|
|
|
|
|
/** the set of non-critical extension OIDs. */ |
|
|
private HashSet nonCritOids; |
|
|
|
|
95 |
// Constructor. |
// Constructor. |
96 |
// ------------------------------------------------------------------------ |
// ------------------------------------------------------------------------ |
97 |
|
|
104 |
* @throws CRLException If the ASN.1 structure is invalid. |
* @throws CRLException If the ASN.1 structure is invalid. |
105 |
* @throws IOException If the bytes cannot be read. |
* @throws IOException If the bytes cannot be read. |
106 |
*/ |
*/ |
107 |
X509CRLEntry(int version, InputStream encoded) |
X509CRLEntry(int version, DERReader encoded) |
108 |
throws CRLException, IOException |
throws CRLException, IOException |
109 |
{ |
{ |
110 |
super(); |
super(); |
111 |
extensions = new HashMap(); |
extensions = new HashMap(); |
|
critOids = new HashSet(); |
|
|
nonCritOids = new HashSet(); |
|
112 |
try |
try |
113 |
{ |
{ |
114 |
parse(version, encoded); |
parse(version, encoded); |
128 |
|
|
129 |
public boolean equals(Object o) |
public boolean equals(Object o) |
130 |
{ |
{ |
131 |
return ((X509CRLEntry) o).serialNo.equals(serialNo) && |
if (!(o instanceof X509CRLEntry)) |
132 |
((X509CRLEntry) o).revocationDate.equals(revocationDate); |
return false; |
133 |
|
return ((X509CRLEntry) o).getSerialNumber().equals(serialNo) && |
134 |
|
((X509CRLEntry) o).getRevocationDate().equals(revocationDate); |
135 |
} |
} |
136 |
|
|
137 |
public int hashCode() |
public int hashCode() |
162 |
public String toString() |
public String toString() |
163 |
{ |
{ |
164 |
return "X509CRLEntry serial=" + serialNo + " revocation date=" |
return "X509CRLEntry serial=" + serialNo + " revocation date=" |
165 |
+ revocationDate + " critExt=" + critOids + " ext=" + nonCritOids; |
+ revocationDate + " ext=" + extensions; |
166 |
} |
} |
167 |
|
|
168 |
// X509Extension methods. |
// X509Extension methods. |
169 |
// ------------------------------------------------------------------------ |
// ------------------------------------------------------------------------- |
170 |
|
|
171 |
public boolean hasUnsupportedCriticalExtension() |
public boolean hasUnsupportedCriticalExtension() |
172 |
{ |
{ |
173 |
return false; // XXX |
for (Iterator it = extensions.values().iterator(); it.hasNext(); ) |
174 |
|
{ |
175 |
|
Extension e = (Extension) it.next(); |
176 |
|
if (e.isCritical() && !e.isSupported()) |
177 |
|
return true; |
178 |
|
} |
179 |
|
return false; |
180 |
} |
} |
181 |
|
|
182 |
public Set getCriticalExtensionOIDs() |
public Set getCriticalExtensionOIDs() |
183 |
{ |
{ |
184 |
return Collections.unmodifiableSet(critOids); |
HashSet s = new HashSet(); |
185 |
|
for (Iterator it = extensions.values().iterator(); it.hasNext(); ) |
186 |
|
{ |
187 |
|
Extension e = (Extension) it.next(); |
188 |
|
if (e.isCritical()) |
189 |
|
s.add(e.getOid().toString()); |
190 |
|
} |
191 |
|
return Collections.unmodifiableSet(s); |
192 |
} |
} |
193 |
|
|
194 |
public Set getNonCriticalExtensionOIDs() |
public Set getNonCriticalExtensionOIDs() |
195 |
{ |
{ |
196 |
return Collections.unmodifiableSet(nonCritOids); |
HashSet s = new HashSet(); |
197 |
|
for (Iterator it = extensions.values().iterator(); it.hasNext(); ) |
198 |
|
{ |
199 |
|
Extension e = (Extension) it.next(); |
200 |
|
if (!e.isCritical()) |
201 |
|
s.add(e.getOid().toString()); |
202 |
|
} |
203 |
|
return Collections.unmodifiableSet(s); |
204 |
} |
} |
205 |
|
|
206 |
public byte[] getExtensionValue(String oid) |
public byte[] getExtensionValue(String oid) |
207 |
{ |
{ |
208 |
byte[] ext = (byte[]) extensions.get(oid); |
Extension e = getExtension(new OID(oid)); |
209 |
if (ext != null) |
if (e != null) |
210 |
return (byte[]) ext.clone(); |
{ |
211 |
|
return e.getValue().getEncoded(); |
212 |
|
} |
213 |
return null; |
return null; |
214 |
} |
} |
215 |
|
|
216 |
|
// GnuPKIExtension method. |
217 |
|
// ------------------------------------------------------------------------- |
218 |
|
|
219 |
|
public Extension getExtension(OID oid) |
220 |
|
{ |
221 |
|
return (Extension) extensions.get(oid); |
222 |
|
} |
223 |
|
|
224 |
|
public Collection getExtensions() |
225 |
|
{ |
226 |
|
return extensions.values(); |
227 |
|
} |
228 |
|
|
229 |
// Own methods. |
// Own methods. |
230 |
// ------------------------------------------------------------------------ |
// ------------------------------------------------------------------------- |
231 |
|
|
232 |
private void parse(int version, InputStream in) throws Exception |
private void parse(int version, DERReader der) throws Exception |
233 |
{ |
{ |
234 |
DERReader der = new DERReader(in); |
// RevokedCertificate ::= SEQUENCE { |
235 |
DERValue entry = der.read(); |
DERValue entry = der.read(); |
236 |
|
debug("start CRL entry len == " + entry.getLength()); |
237 |
if (!entry.isConstructed()) |
if (!entry.isConstructed()) |
238 |
throw new ASN1ParsingException("malformed revokedCertificate"); |
throw new IOException("malformed revokedCertificate"); |
239 |
encoded = entry.getEncoded(); |
encoded = entry.getEncoded(); |
240 |
int len = 0; |
int len = 0; |
241 |
|
|
242 |
|
debug("encoded entry:\n" + Util.hexDump(encoded, ">>>> ")); |
243 |
|
|
244 |
|
// userCertificate CertificateSerialNumber, |
245 |
DERValue val = der.read(); |
DERValue val = der.read(); |
246 |
serialNo = (BigInteger) val.getValue(); |
serialNo = (BigInteger) val.getValue(); |
247 |
len += DERWriter.definiteEncodingSize(val.getLength()) |
len += val.getEncodedLength(); |
248 |
+ val.getLength() + 1; |
debug("userCertificate == " + serialNo + " current count == " + len); |
249 |
|
|
250 |
|
// revocationDate Time, |
251 |
val = der.read(); |
val = der.read(); |
252 |
revocationDate = (Date) val.getValue(); |
revocationDate = (Date) val.getValue(); |
253 |
len += DERWriter.definiteEncodingSize(val.getLength()) |
len += val.getEncodedLength(); |
254 |
+ val.getLength() + 1; |
debug("revocationDate == " + revocationDate + " current count == " + len); |
255 |
|
|
256 |
|
// crlEntryExtensions Extensions OPTIONAL |
257 |
|
// -- if present MUST be v2 |
258 |
if (len < entry.getLength()) |
if (len < entry.getLength()) |
259 |
{ |
{ |
260 |
if (version < 2) |
if (version < 2) |
261 |
throw new ASN1ParsingException("extra data in CRL entry"); |
throw new IOException("extra data in CRL entry"); |
262 |
while (len < entry.getLength()) |
DERValue exts = der.read(); |
263 |
|
if (!exts.isConstructed()) |
264 |
|
throw new IOException("malformed Extensions"); |
265 |
|
debug("start Extensions len == " + exts.getLength()); |
266 |
|
len = 0; |
267 |
|
while (len < exts.getLength()) |
268 |
{ |
{ |
269 |
val = der.read(); |
val = der.read(); |
270 |
if (!val.isConstructed()) |
if (!val.isConstructed()) |
271 |
throw new ASN1ParsingException("malformed Extension"); |
throw new IOException("malformed Extension"); |
272 |
OID extOid = (OID) der.read().getValue(); |
debug("start Extension len == " + val.getLength()); |
273 |
Boolean critical = Boolean.valueOf(false); |
Extension e = new Extension(val.getEncoded()); |
274 |
DERValue val2 = der.read(); |
extensions.put(e.getOid(), e); |
275 |
if (val2.getValue() instanceof Boolean) |
der.skip(val.getLength()); |
|
{ |
|
|
critical = (Boolean) val2.getValue(); |
|
|
val2 = der.read(); |
|
|
} |
|
|
byte[] ext = (byte[]) val2.getValue(); |
|
|
extensions.put(extOid.toString(), ext); |
|
|
if (critical.booleanValue()) |
|
|
critOids.add(extOid.toString()); |
|
|
else |
|
|
nonCritOids.add(extOid.toString()); |
|
276 |
len += val.getEncodedLength(); |
len += val.getEncodedLength(); |
277 |
|
debug("current count == " + len); |
278 |
} |
} |
279 |
} |
} |
280 |
} |
} |