001 /** 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one or more 004 * contributor license agreements. See the NOTICE file distributed with 005 * this work for additional information regarding copyright ownership. 006 * The ASF licenses this file to You under the Apache License, Version 2.0 007 * (the "License"); you may not use this file except in compliance with 008 * the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 package org.apache.geronimo.util.jce.provider; 020 021 import java.io.ByteArrayOutputStream; 022 import java.io.IOException; 023 import java.math.BigInteger; 024 import java.security.InvalidKeyException; 025 import java.security.NoSuchAlgorithmException; 026 import java.security.NoSuchProviderException; 027 import java.security.Principal; 028 import java.security.Provider; 029 import java.security.PublicKey; 030 import java.security.Security; 031 import java.security.Signature; 032 import java.security.SignatureException; 033 import java.security.cert.CRLException; 034 import java.security.cert.Certificate; 035 import java.security.cert.X509CRL; 036 import java.security.cert.X509CRLEntry; 037 import java.security.cert.X509Certificate; 038 import java.util.Date; 039 import java.util.Enumeration; 040 import java.util.HashSet; 041 import java.util.Set; 042 043 import javax.security.auth.x500.X500Principal; 044 045 import org.apache.geronimo.util.asn1.ASN1OutputStream; 046 import org.apache.geronimo.util.asn1.DERObjectIdentifier; 047 import org.apache.geronimo.util.asn1.DEROutputStream; 048 import org.apache.geronimo.util.asn1.x509.CertificateList; 049 import org.apache.geronimo.util.asn1.x509.TBSCertList; 050 import org.apache.geronimo.util.asn1.x509.X509Extension; 051 import org.apache.geronimo.util.asn1.x509.X509Extensions; 052 import org.apache.geronimo.util.jce.X509Principal; 053 054 /** 055 * The following extensions are listed in RFC 2459 as relevant to CRLs 056 * 057 * Authority Key Identifier 058 * Issuer Alternative Name 059 * CRL Number 060 * Delta CRL Indicator (critical) 061 * Issuing Distribution Point (critical) 062 */ 063 public class X509CRLObject 064 extends X509CRL 065 { 066 private CertificateList c; 067 068 public X509CRLObject( 069 CertificateList c) 070 { 071 this.c = c; 072 } 073 074 /** 075 * Will return true if any extensions are present and marked 076 * as critical as we currently dont handle any extensions! 077 */ 078 public boolean hasUnsupportedCriticalExtension() 079 { 080 Set extns = getCriticalExtensionOIDs(); 081 if ( extns != null && !extns.isEmpty() ) 082 { 083 return true; 084 } 085 086 return false; 087 } 088 089 private Set getExtensionOIDs(boolean critical) 090 { 091 if (this.getVersion() == 2) 092 { 093 HashSet set = new HashSet(); 094 X509Extensions extensions = c.getTBSCertList().getExtensions(); 095 Enumeration e = extensions.oids(); 096 097 while (e.hasMoreElements()) 098 { 099 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 // search every provider looking for a real algorithm 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