1 /**
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one or more
4 * contributor license agreements. See the NOTICE file distributed with
5 * this work for additional information regarding copyright ownership.
6 * The ASF licenses this file to You under the Apache License, Version 2.0
7 * (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 package org.apache.geronimo.util.jce.provider;
20
21 import java.io.ByteArrayOutputStream;
22 import java.io.IOException;
23 import java.math.BigInteger;
24 import java.security.InvalidKeyException;
25 import java.security.NoSuchAlgorithmException;
26 import java.security.NoSuchProviderException;
27 import java.security.Principal;
28 import java.security.Provider;
29 import java.security.PublicKey;
30 import java.security.Security;
31 import java.security.Signature;
32 import java.security.SignatureException;
33 import java.security.cert.CRLException;
34 import java.security.cert.Certificate;
35 import java.security.cert.X509CRL;
36 import java.security.cert.X509CRLEntry;
37 import java.security.cert.X509Certificate;
38 import java.util.Date;
39 import java.util.Enumeration;
40 import java.util.HashSet;
41 import java.util.Set;
42
43 import javax.security.auth.x500.X500Principal;
44
45 import org.apache.geronimo.util.asn1.ASN1OutputStream;
46 import org.apache.geronimo.util.asn1.DERObjectIdentifier;
47 import org.apache.geronimo.util.asn1.DEROutputStream;
48 import org.apache.geronimo.util.asn1.x509.CertificateList;
49 import org.apache.geronimo.util.asn1.x509.TBSCertList;
50 import org.apache.geronimo.util.asn1.x509.X509Extension;
51 import org.apache.geronimo.util.asn1.x509.X509Extensions;
52 import org.apache.geronimo.util.jce.X509Principal;
53
54 /**
55 * The following extensions are listed in RFC 2459 as relevant to CRLs
56 *
57 * Authority Key Identifier
58 * Issuer Alternative Name
59 * CRL Number
60 * Delta CRL Indicator (critical)
61 * Issuing Distribution Point (critical)
62 */
63 public class X509CRLObject
64 extends X509CRL
65 {
66 private CertificateList c;
67
68 public X509CRLObject(
69 CertificateList c)
70 {
71 this.c = c;
72 }
73
74 /**
75 * Will return true if any extensions are present and marked
76 * as critical as we currently dont handle any extensions!
77 */
78 public boolean hasUnsupportedCriticalExtension()
79 {
80 Set extns = getCriticalExtensionOIDs();
81 if ( extns != null && !extns.isEmpty() )
82 {
83 return true;
84 }
85
86 return false;
87 }
88
89 private Set getExtensionOIDs(boolean critical)
90 {
91 if (this.getVersion() == 2)
92 {
93 HashSet set = new HashSet();
94 X509Extensions extensions = c.getTBSCertList().getExtensions();
95 Enumeration e = extensions.oids();
96
97 while (e.hasMoreElements())
98 {
99 DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
100 X509Extension ext = extensions.getExtension(oid);
101
102 if (critical == ext.isCritical())
103 {
104 set.add(oid.getId());
105 }
106 }
107
108 return set;
109 }
110
111 return null;
112 }
113
114 public Set getCriticalExtensionOIDs()
115 {
116 return getExtensionOIDs(true);
117 }
118
119 public Set getNonCriticalExtensionOIDs()
120 {
121 return getExtensionOIDs(false);
122 }
123
124 public byte[] getExtensionValue(String oid)
125 {
126 X509Extensions exts = c.getTBSCertList().getExtensions();
127
128 if (exts != null)
129 {
130 X509Extension ext = exts.getExtension(new DERObjectIdentifier(oid));
131
132 if (ext != null)
133 {
134 ByteArrayOutputStream bOut = new ByteArrayOutputStream();
135 DEROutputStream dOut = new DEROutputStream(bOut);
136
137 try
138 {
139 dOut.writeObject(ext.getValue());
140
141 return bOut.toByteArray();
142 }
143 catch (Exception e)
144 {
145 throw new RuntimeException("error encoding " + e.toString());
146 }
147 }
148 }
149
150 return null;
151 }
152
153 public byte[] getEncoded()
154 throws CRLException
155 {
156 ByteArrayOutputStream bOut = new ByteArrayOutputStream();
157 DEROutputStream dOut = new DEROutputStream(bOut);
158
159 try
160 {
161 dOut.writeObject(c);
162
163 return bOut.toByteArray();
164 }
165 catch (IOException e)
166 {
167 throw new CRLException(e.toString());
168 }
169 }
170
171 public void verify(PublicKey key)
172 throws CRLException, NoSuchAlgorithmException,
173 InvalidKeyException, NoSuchProviderException,
174 SignatureException
175 {
176 verify(key, "BC");
177 }
178
179 public void verify(PublicKey key, String sigProvider)
180 throws CRLException, NoSuchAlgorithmException,
181 InvalidKeyException, NoSuchProviderException,
182 SignatureException
183 {
184 if ( !c.getSignatureAlgorithm().equals(c.getTBSCertList().getSignature()) )
185 {
186 throw new CRLException("Signature algorithm on CertifcateList does not match TBSCertList.");
187 }
188
189 Signature sig = Signature.getInstance(getSigAlgName(), sigProvider);
190
191 sig.initVerify(key);
192 sig.update(this.getTBSCertList());
193 if ( !sig.verify(this.getSignature()) )
194 {
195 throw new SignatureException("CRL does not verify with supplied public key.");
196 }
197 }
198
199 public int getVersion()
200 {
201 return c.getVersion();
202 }
203
204 public Principal getIssuerDN()
205 {
206 return new X509Principal(c.getIssuer());
207 }
208
209 public X500Principal getIssuerX500Principal()
210 {
211 try
212 {
213 ByteArrayOutputStream bOut = new ByteArrayOutputStream();
214 ASN1OutputStream aOut = new ASN1OutputStream(bOut);
215
216 aOut.writeObject(c.getIssuer());
217
218 return new X500Principal(bOut.toByteArray());
219 }
220 catch (IOException e)
221 {
222 throw new IllegalStateException("can't encode issuer DN");
223 }
224 }
225
226 public Date getThisUpdate()
227 {
228 return c.getThisUpdate().getDate();
229 }
230
231 public Date getNextUpdate()
232 {
233 if (c.getNextUpdate() != null)
234 {
235 return c.getNextUpdate().getDate();
236 }
237
238 return null;
239 }
240
241 public X509CRLEntry getRevokedCertificate(BigInteger serialNumber)
242 {
243 TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
244
245 if ( certs != null )
246 {
247 for ( int i = 0; i < certs.length; i++ )
248 {
249 if ( certs[i].getUserCertificate().getValue().equals(serialNumber) ) {
250 return new X509CRLEntryObject(certs[i]);
251 }
252 }
253 }
254
255 return null;
256 }
257
258 public Set getRevokedCertificates()
259 {
260 TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
261
262 if ( certs != null )
263 {
264 HashSet set = new HashSet();
265 for ( int i = 0; i < certs.length; i++ )
266 {
267 set.add(new X509CRLEntryObject(certs[i]));
268
269 }
270
271 return set;
272 }
273
274 return null;
275 }
276
277 public byte[] getTBSCertList()
278 throws CRLException
279 {
280 ByteArrayOutputStream bOut = new ByteArrayOutputStream();
281 DEROutputStream dOut = new DEROutputStream(bOut);
282
283 try
284 {
285 dOut.writeObject(c.getTBSCertList());
286
287 return bOut.toByteArray();
288 }
289 catch (IOException e)
290 {
291 throw new CRLException(e.toString());
292 }
293 }
294
295 public byte[] getSignature()
296 {
297 return c.getSignature().getBytes();
298 }
299
300 public String getSigAlgName()
301 {
302 Provider[] provs = Security.getProviders();
303
304
305
306
307 for (int i = 0; i != provs.length; i++)
308 {
309 String algName = provs[i].getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
310 if ( algName != null )
311 {
312 return algName;
313 }
314 }
315
316 return this.getSigAlgOID();
317 }
318
319 public String getSigAlgOID()
320 {
321 return c.getSignatureAlgorithm().getObjectId().getId();
322 }
323
324 public byte[] getSigAlgParams()
325 {
326 ByteArrayOutputStream bOut = new ByteArrayOutputStream();
327
328 if ( c.getSignatureAlgorithm().getParameters() != null )
329 {
330 try
331 {
332 DEROutputStream dOut = new DEROutputStream(bOut);
333
334 dOut.writeObject(c.getSignatureAlgorithm().getParameters());
335 }
336 catch (Exception e)
337 {
338 throw new RuntimeException("exception getting sig parameters " + e);
339 }
340
341 return bOut.toByteArray();
342 }
343
344 return null;
345 }
346
347 /**
348 * Returns a string representation of this CRL.
349 *
350 * @return a string representation of this CRL.
351 */
352 public String toString()
353 {
354 return "X.509 CRL";
355 }
356
357 /**
358 * Checks whether the given certificate is on this CRL.
359 *
360 * @param cert the certificate to check for.
361 * @return true if the given certificate is on this CRL,
362 * false otherwise.
363 */
364 public boolean isRevoked(Certificate cert)
365 {
366 if ( !cert.getType().equals("X.509") )
367 {
368 throw new RuntimeException("X.509 CRL used with non X.509 Cert");
369 }
370
371 TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
372
373 if ( certs != null )
374 {
375 BigInteger serial = ((X509Certificate)cert).getSerialNumber();
376
377 for ( int i = 0; i < certs.length; i++ )
378 {
379 if ( certs[i].getUserCertificate().getValue().equals(serial) )
380 {
381 return true;
382 }
383 }
384 }
385
386 return false;
387 }
388 }
389