OpenSSLX509CRL.java revision 75dc9601af8ab3c65114e3c8c57d29ce5ac64125
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package org.apache.harmony.xnet.provider.jsse; 18 19import org.apache.harmony.security.utils.AlgNameMapper; 20import org.apache.harmony.xnet.provider.jsse.OpenSSLX509CertificateFactory.ParsingException; 21 22import java.io.ByteArrayInputStream; 23import java.io.ByteArrayOutputStream; 24import java.io.InputStream; 25import java.math.BigInteger; 26import java.security.InvalidKeyException; 27import java.security.NoSuchAlgorithmException; 28import java.security.NoSuchProviderException; 29import java.security.Principal; 30import java.security.PublicKey; 31import java.security.Signature; 32import java.security.SignatureException; 33import java.security.cert.CRLException; 34import java.security.cert.Certificate; 35import java.security.cert.X509CRL; 36import java.security.cert.X509CRLEntry; 37import java.security.cert.X509Certificate; 38import java.util.ArrayList; 39import java.util.Arrays; 40import java.util.Calendar; 41import java.util.Date; 42import java.util.HashSet; 43import java.util.List; 44import java.util.Set; 45import java.util.TimeZone; 46 47import javax.security.auth.x500.X500Principal; 48 49public class OpenSSLX509CRL extends X509CRL { 50 private final long mContext; 51 52 private OpenSSLX509CRL(long ctx) { 53 mContext = ctx; 54 } 55 56 public static OpenSSLX509CRL fromX509DerInputStream(InputStream is) throws ParsingException { 57 final OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is); 58 59 try { 60 final long crlCtx = NativeCrypto.d2i_X509_CRL_bio(bis.getBioContext()); 61 if (crlCtx == 0) { 62 return null; 63 } 64 return new OpenSSLX509CRL(crlCtx); 65 } catch (Exception e) { 66 throw new ParsingException(e); 67 } finally { 68 NativeCrypto.BIO_free(bis.getBioContext()); 69 } 70 } 71 72 public static List<OpenSSLX509CRL> fromPkcs7DerInputStream(InputStream is) 73 throws ParsingException { 74 OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is); 75 76 final long[] certRefs; 77 try { 78 certRefs = NativeCrypto.d2i_PKCS7_bio(bis.getBioContext(), NativeCrypto.PKCS7_CRLS); 79 } catch (Exception e) { 80 throw new ParsingException(e); 81 } finally { 82 NativeCrypto.BIO_free(bis.getBioContext()); 83 } 84 85 final List<OpenSSLX509CRL> certs = new ArrayList<OpenSSLX509CRL>(certRefs.length); 86 for (int i = 0; i < certRefs.length; i++) { 87 if (certRefs[i] == 0) { 88 continue; 89 } 90 certs.add(new OpenSSLX509CRL(certRefs[i])); 91 } 92 return certs; 93 } 94 95 public static OpenSSLX509CRL fromX509PemInputStream(InputStream is) throws ParsingException { 96 final OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is); 97 98 try { 99 final long crlCtx = NativeCrypto.PEM_read_bio_X509_CRL(bis.getBioContext()); 100 if (crlCtx == 0) { 101 return null; 102 } 103 return new OpenSSLX509CRL(crlCtx); 104 } catch (Exception e) { 105 throw new ParsingException(e); 106 } finally { 107 NativeCrypto.BIO_free(bis.getBioContext()); 108 } 109 } 110 111 public static List<OpenSSLX509CRL> fromPkcs7PemInputStream(InputStream is) 112 throws ParsingException { 113 OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is); 114 115 final long[] certRefs; 116 try { 117 certRefs = NativeCrypto.PEM_read_bio_PKCS7(bis.getBioContext(), 118 NativeCrypto.PKCS7_CRLS); 119 } catch (Exception e) { 120 throw new ParsingException(e); 121 } finally { 122 NativeCrypto.BIO_free(bis.getBioContext()); 123 } 124 125 final List<OpenSSLX509CRL> certs = new ArrayList<OpenSSLX509CRL>(certRefs.length); 126 for (int i = 0; i < certRefs.length; i++) { 127 if (certRefs[i] == 0) { 128 continue; 129 } 130 certs.add(new OpenSSLX509CRL(certRefs[i])); 131 } 132 return certs; 133 } 134 135 @Override 136 public Set<String> getCriticalExtensionOIDs() { 137 String[] critOids = 138 NativeCrypto.get_X509_CRL_ext_oids(mContext, NativeCrypto.EXTENSION_TYPE_CRITICAL); 139 140 /* 141 * This API has a special case that if there are no extensions, we 142 * should return null. So if we have no critical extensions, we'll check 143 * non-critical extensions. 144 */ 145 if ((critOids.length == 0) 146 && (NativeCrypto.get_X509_CRL_ext_oids(mContext, 147 NativeCrypto.EXTENSION_TYPE_NON_CRITICAL).length == 0)) { 148 return null; 149 } 150 151 return new HashSet<String>(Arrays.asList(critOids)); 152 } 153 154 @Override 155 public byte[] getExtensionValue(String oid) { 156 return NativeCrypto.X509_CRL_get_ext_oid(mContext, oid); 157 } 158 159 @Override 160 public Set<String> getNonCriticalExtensionOIDs() { 161 String[] nonCritOids = 162 NativeCrypto.get_X509_CRL_ext_oids(mContext, 163 NativeCrypto.EXTENSION_TYPE_NON_CRITICAL); 164 165 /* 166 * This API has a special case that if there are no extensions, we 167 * should return null. So if we have no non-critical extensions, we'll 168 * check critical extensions. 169 */ 170 if ((nonCritOids.length == 0) 171 && (NativeCrypto.get_X509_CRL_ext_oids(mContext, 172 NativeCrypto.EXTENSION_TYPE_CRITICAL).length == 0)) { 173 return null; 174 } 175 176 return new HashSet<String>(Arrays.asList(nonCritOids)); 177 } 178 179 @Override 180 public boolean hasUnsupportedCriticalExtension() { 181 final String[] criticalOids = 182 NativeCrypto.get_X509_CRL_ext_oids(mContext, NativeCrypto.EXTENSION_TYPE_CRITICAL); 183 for (String oid : criticalOids) { 184 final long extensionRef = NativeCrypto.X509_CRL_get_ext(mContext, oid); 185 if (NativeCrypto.X509_supported_extension(extensionRef) != 1) { 186 return true; 187 } 188 } 189 190 return false; 191 } 192 193 @Override 194 public byte[] getEncoded() throws CRLException { 195 return NativeCrypto.i2d_X509_CRL(mContext); 196 } 197 198 private void verifyOpenSSL(OpenSSLKey pkey) throws CRLException, NoSuchAlgorithmException, 199 InvalidKeyException, NoSuchProviderException, SignatureException { 200 NativeCrypto.X509_CRL_verify(mContext, pkey.getPkeyContext()); 201 } 202 203 private void verifyInternal(PublicKey key, String sigProvider) throws CRLException, 204 NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, 205 SignatureException { 206 String sigAlg = getSigAlgName(); 207 if (sigAlg == null) { 208 sigAlg = getSigAlgOID(); 209 } 210 211 final Signature sig; 212 if (sigProvider == null) { 213 sig = Signature.getInstance(sigAlg); 214 } else { 215 sig = Signature.getInstance(sigAlg, sigProvider); 216 } 217 218 sig.initVerify(key); 219 sig.update(getTBSCertList()); 220 if (!sig.verify(getSignature())) { 221 throw new SignatureException("signature did not verify"); 222 } 223 } 224 225 @Override 226 public void verify(PublicKey key) throws CRLException, NoSuchAlgorithmException, 227 InvalidKeyException, NoSuchProviderException, SignatureException { 228 if (key instanceof OpenSSLKeyHolder) { 229 OpenSSLKey pkey = ((OpenSSLKeyHolder) key).getOpenSSLKey(); 230 verifyOpenSSL(pkey); 231 return; 232 } 233 234 verifyInternal(key, null); 235 } 236 237 @Override 238 public void verify(PublicKey key, String sigProvider) throws CRLException, 239 NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, 240 SignatureException { 241 verifyInternal(key, sigProvider); 242 } 243 244 @Override 245 public int getVersion() { 246 return (int) NativeCrypto.X509_CRL_get_version(mContext) + 1; 247 } 248 249 @Override 250 public Principal getIssuerDN() { 251 return getIssuerX500Principal(); 252 } 253 254 @Override 255 public X500Principal getIssuerX500Principal() { 256 final byte[] issuer = NativeCrypto.X509_CRL_get_issuer_name(mContext); 257 return new X500Principal(issuer); 258 } 259 260 @Override 261 public Date getThisUpdate() { 262 Calendar calendar = Calendar.getInstance(); 263 calendar.setTimeZone(TimeZone.getTimeZone("UTC")); 264 NativeCrypto.ASN1_TIME_to_Calendar(NativeCrypto.X509_CRL_get_lastUpdate(mContext), 265 calendar); 266 return calendar.getTime(); 267 } 268 269 @Override 270 public Date getNextUpdate() { 271 Calendar calendar = Calendar.getInstance(); 272 calendar.setTimeZone(TimeZone.getTimeZone("UTC")); 273 NativeCrypto.ASN1_TIME_to_Calendar(NativeCrypto.X509_CRL_get_nextUpdate(mContext), 274 calendar); 275 return calendar.getTime(); 276 } 277 278 @Override 279 public X509CRLEntry getRevokedCertificate(BigInteger serialNumber) { 280 final long revokedRef = NativeCrypto.X509_CRL_get0_by_serial(mContext, 281 serialNumber.toByteArray()); 282 if (revokedRef == 0) { 283 return null; 284 } 285 286 return new OpenSSLX509CRLEntry(NativeCrypto.X509_REVOKED_dup(revokedRef)); 287 } 288 289 @Override 290 public X509CRLEntry getRevokedCertificate(X509Certificate certificate) { 291 if (certificate instanceof OpenSSLX509Certificate) { 292 OpenSSLX509Certificate osslCert = (OpenSSLX509Certificate) certificate; 293 final long x509RevokedRef = NativeCrypto.X509_CRL_get0_by_cert(mContext, 294 osslCert.getContext()); 295 296 if (x509RevokedRef == 0) { 297 return null; 298 } 299 300 return new OpenSSLX509CRLEntry(NativeCrypto.X509_REVOKED_dup(x509RevokedRef)); 301 } 302 303 return getRevokedCertificate(certificate.getSerialNumber()); 304 } 305 306 @Override 307 public Set<? extends X509CRLEntry> getRevokedCertificates() { 308 final long[] entryRefs = NativeCrypto.X509_CRL_get_REVOKED(mContext); 309 if (entryRefs == null || entryRefs.length == 0) { 310 return null; 311 } 312 313 final Set<OpenSSLX509CRLEntry> crlSet = new HashSet<OpenSSLX509CRLEntry>(); 314 for (long entryRef : entryRefs) { 315 crlSet.add(new OpenSSLX509CRLEntry(entryRef)); 316 } 317 318 return crlSet; 319 } 320 321 @Override 322 public byte[] getTBSCertList() throws CRLException { 323 return NativeCrypto.get_X509_CRL_crl_enc(mContext); 324 } 325 326 @Override 327 public byte[] getSignature() { 328 return NativeCrypto.get_X509_CRL_signature(mContext); 329 } 330 331 @Override 332 public String getSigAlgName() { 333 return AlgNameMapper.map2AlgName(getSigAlgOID()); 334 } 335 336 @Override 337 public String getSigAlgOID() { 338 return NativeCrypto.get_X509_CRL_sig_alg_oid(mContext); 339 } 340 341 @Override 342 public byte[] getSigAlgParams() { 343 return NativeCrypto.get_X509_CRL_sig_alg_parameter(mContext); 344 } 345 346 @Override 347 public boolean isRevoked(Certificate cert) { 348 if (!(cert instanceof X509Certificate)) { 349 return false; 350 } 351 352 final OpenSSLX509Certificate osslCert; 353 if (cert instanceof OpenSSLX509Certificate) { 354 osslCert = (OpenSSLX509Certificate) cert; 355 } else { 356 try { 357 osslCert = OpenSSLX509Certificate.fromX509DerInputStream(new ByteArrayInputStream( 358 cert.getEncoded())); 359 } catch (Exception e) { 360 throw new RuntimeException("cannot convert certificate", e); 361 } 362 } 363 364 final long x509RevokedRef = NativeCrypto.X509_CRL_get0_by_cert(mContext, 365 osslCert.getContext()); 366 367 return x509RevokedRef != 0; 368 } 369 370 @Override 371 public String toString() { 372 ByteArrayOutputStream os = new ByteArrayOutputStream(); 373 final long bioCtx = NativeCrypto.create_BIO_OutputStream(os); 374 try { 375 NativeCrypto.X509_CRL_print(bioCtx, mContext); 376 return os.toString(); 377 } finally { 378 NativeCrypto.BIO_free(bioCtx); 379 } 380 } 381 382 @Override 383 protected void finalize() throws Throwable { 384 try { 385 if (mContext != 0) { 386 NativeCrypto.X509_CRL_free(mContext); 387 } 388 } finally { 389 super.finalize(); 390 } 391 } 392 393} 394