001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.geronimo.util.jce.provider;
019
020 import java.io.ByteArrayOutputStream;
021 import java.io.IOException;
022 import java.math.BigInteger;
023 import java.security.InvalidKeyException;
024 import java.security.NoSuchAlgorithmException;
025 import java.security.NoSuchProviderException;
026 import java.security.Principal;
027 import java.security.Provider;
028 import java.security.PublicKey;
029 import java.security.Security;
030 import java.security.Signature;
031 import java.security.SignatureException;
032 import java.security.cert.CRLException;
033 import java.security.cert.Certificate;
034 import java.security.cert.X509CRL;
035 import java.security.cert.X509CRLEntry;
036 import java.security.cert.X509Certificate;
037 import java.util.Date;
038 import java.util.Enumeration;
039 import java.util.HashSet;
040 import java.util.Set;
041
042 import javax.security.auth.x500.X500Principal;
043
044 import org.apache.geronimo.util.asn1.ASN1OutputStream;
045 import org.apache.geronimo.util.asn1.DERObjectIdentifier;
046 import org.apache.geronimo.util.asn1.DEROutputStream;
047 import org.apache.geronimo.util.asn1.x509.CertificateList;
048 import org.apache.geronimo.util.asn1.x509.TBSCertList;
049 import org.apache.geronimo.util.asn1.x509.X509Extension;
050 import org.apache.geronimo.util.asn1.x509.X509Extensions;
051 import org.apache.geronimo.util.jce.X509Principal;
052
053 /**
054 * The following extensions are listed in RFC 2459 as relevant to CRLs
055 *
056 * Authority Key Identifier
057 * Issuer Alternative Name
058 * CRL Number
059 * Delta CRL Indicator (critical)
060 * Issuing Distribution Point (critical)
061 */
062 public class X509CRLObject
063 extends X509CRL
064 {
065 private CertificateList c;
066
067 public X509CRLObject(
068 CertificateList c)
069 {
070 this.c = c;
071 }
072
073 /**
074 * Will return true if any extensions are present and marked
075 * as critical as we currently dont handle any extensions!
076 */
077 public boolean hasUnsupportedCriticalExtension()
078 {
079 Set extns = getCriticalExtensionOIDs();
080 if ( extns != null && !extns.isEmpty() )
081 {
082 return true;
083 }
084
085 return false;
086 }
087
088 private Set getExtensionOIDs(boolean critical)
089 {
090 if (this.getVersion() == 2)
091 {
092 HashSet set = new HashSet();
093 X509Extensions extensions = c.getTBSCertList().getExtensions();
094 Enumeration e = extensions.oids();
095
096 while (e.hasMoreElements())
097 {
098 DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
099 X509Extension ext = extensions.getExtension(oid);
100
101 if (critical == ext.isCritical())
102 {
103 set.add(oid.getId());
104 }
105 }
106
107 return set;
108 }
109
110 return null;
111 }
112
113 public Set getCriticalExtensionOIDs()
114 {
115 return getExtensionOIDs(true);
116 }
117
118 public Set getNonCriticalExtensionOIDs()
119 {
120 return getExtensionOIDs(false);
121 }
122
123 public byte[] getExtensionValue(String oid)
124 {
125 X509Extensions exts = c.getTBSCertList().getExtensions();
126
127 if (exts != null)
128 {
129 X509Extension ext = exts.getExtension(new DERObjectIdentifier(oid));
130
131 if (ext != null)
132 {
133 ByteArrayOutputStream bOut = new ByteArrayOutputStream();
134 DEROutputStream dOut = new DEROutputStream(bOut);
135
136 try
137 {
138 dOut.writeObject(ext.getValue());
139
140 return bOut.toByteArray();
141 }
142 catch (Exception e)
143 {
144 throw new RuntimeException("error encoding " + e.getMessage(), e);
145 }
146 }
147 }
148
149 return null;
150 }
151
152 public byte[] getEncoded()
153 throws CRLException
154 {
155 ByteArrayOutputStream bOut = new ByteArrayOutputStream();
156 DEROutputStream dOut = new DEROutputStream(bOut);
157
158 try
159 {
160 dOut.writeObject(c);
161
162 return bOut.toByteArray();
163 }
164 catch (IOException e)
165 {
166 throw (CRLException)new CRLException(e.getMessage()).initCause(e);
167 }
168 }
169
170 public void verify(PublicKey key)
171 throws CRLException, NoSuchAlgorithmException,
172 InvalidKeyException, NoSuchProviderException,
173 SignatureException
174 {
175 verify(key, "BC");
176 }
177
178 public void verify(PublicKey key, String sigProvider)
179 throws CRLException, NoSuchAlgorithmException,
180 InvalidKeyException, NoSuchProviderException,
181 SignatureException
182 {
183 if ( !c.getSignatureAlgorithm().equals(c.getTBSCertList().getSignature()) )
184 {
185 throw new CRLException("Signature algorithm on CertifcateList does not match TBSCertList.");
186 }
187
188 Signature sig = Signature.getInstance(getSigAlgName(), sigProvider);
189
190 sig.initVerify(key);
191 sig.update(this.getTBSCertList());
192 if ( !sig.verify(this.getSignature()) )
193 {
194 throw new SignatureException("CRL does not verify with supplied public key.");
195 }
196 }
197
198 public int getVersion()
199 {
200 return c.getVersion();
201 }
202
203 public Principal getIssuerDN()
204 {
205 return new X509Principal(c.getIssuer());
206 }
207
208 public X500Principal getIssuerX500Principal()
209 {
210 try
211 {
212 ByteArrayOutputStream bOut = new ByteArrayOutputStream();
213 ASN1OutputStream aOut = new ASN1OutputStream(bOut);
214
215 aOut.writeObject(c.getIssuer());
216
217 return new X500Principal(bOut.toByteArray());
218 }
219 catch (IOException e)
220 {
221 throw new IllegalStateException("can't encode issuer DN", e);
222 }
223 }
224
225 public Date getThisUpdate()
226 {
227 return c.getThisUpdate().getDate();
228 }
229
230 public Date getNextUpdate()
231 {
232 if (c.getNextUpdate() != null)
233 {
234 return c.getNextUpdate().getDate();
235 }
236
237 return null;
238 }
239
240 public X509CRLEntry getRevokedCertificate(BigInteger serialNumber)
241 {
242 TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
243
244 if ( certs != null )
245 {
246 for ( int i = 0; i < certs.length; i++ )
247 {
248 if ( certs[i].getUserCertificate().getValue().equals(serialNumber) ) {
249 return new X509CRLEntryObject(certs[i]);
250 }
251 }
252 }
253
254 return null;
255 }
256
257 public Set getRevokedCertificates()
258 {
259 TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
260
261 if ( certs != null )
262 {
263 HashSet set = new HashSet();
264 for ( int i = 0; i < certs.length; i++ )
265 {
266 set.add(new X509CRLEntryObject(certs[i]));
267
268 }
269
270 return set;
271 }
272
273 return null;
274 }
275
276 public byte[] getTBSCertList()
277 throws CRLException
278 {
279 ByteArrayOutputStream bOut = new ByteArrayOutputStream();
280 DEROutputStream dOut = new DEROutputStream(bOut);
281
282 try
283 {
284 dOut.writeObject(c.getTBSCertList());
285
286 return bOut.toByteArray();
287 }
288 catch (IOException e)
289 {
290 throw (CRLException)new CRLException(e.getMessage()).initCause(e);
291 }
292 }
293
294 public byte[] getSignature()
295 {
296 return c.getSignature().getBytes();
297 }
298
299 public String getSigAlgName()
300 {
301 Provider[] provs = Security.getProviders();
302
303 //
304 // search every provider looking for a real algorithm
305 //
306 for (int i = 0; i != provs.length; i++)
307 {
308 String algName = provs[i].getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
309 if ( algName != null )
310 {
311 return algName;
312 }
313 }
314
315 return this.getSigAlgOID();
316 }
317
318 public String getSigAlgOID()
319 {
320 return c.getSignatureAlgorithm().getObjectId().getId();
321 }
322
323 public byte[] getSigAlgParams()
324 {
325 ByteArrayOutputStream bOut = new ByteArrayOutputStream();
326
327 if ( c.getSignatureAlgorithm().getParameters() != null )
328 {
329 try
330 {
331 DEROutputStream dOut = new DEROutputStream(bOut);
332
333 dOut.writeObject(c.getSignatureAlgorithm().getParameters());
334 }
335 catch (Exception e)
336 {
337 throw new RuntimeException("exception getting sig parameters " + e.getMessage(), e);
338 }
339
340 return bOut.toByteArray();
341 }
342
343 return null;
344 }
345
346 /**
347 * Returns a string representation of this CRL.
348 *
349 * @return a string representation of this CRL.
350 */
351 public String toString()
352 {
353 return "X.509 CRL";
354 }
355
356 /**
357 * Checks whether the given certificate is on this CRL.
358 *
359 * @param cert the certificate to check for.
360 * @return true if the given certificate is on this CRL,
361 * false otherwise.
362 */
363 public boolean isRevoked(Certificate cert)
364 {
365 if ( !cert.getType().equals("X.509") )
366 {
367 throw new RuntimeException("X.509 CRL used with non X.509 Cert");
368 }
369
370 TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
371
372 if ( certs != null )
373 {
374 BigInteger serial = ((X509Certificate)cert).getSerialNumber();
375
376 for ( int i = 0; i < certs.length; i++ )
377 {
378 if ( certs[i].getUserCertificate().getValue().equals(serial) )
379 {
380 return true;
381 }
382 }
383 }
384
385 return false;
386 }
387 }
388