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