/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.synapse.transport.certificatevalidation; import junit.framework.TestCase; import org.apache.synapse.transport.certificatevalidation.crl.CRLCache; import org.apache.synapse.transport.certificatevalidation.crl.CRLVerifier;import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.x509.*; import org.bouncycastle.x509.X509V2CRLGenerator; import org.bouncycastle.x509.X509V3CertificateGenerator; import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure; import java.lang.reflect.Method; import java.math.BigInteger; import java.security.*; import java.security.cert.X509CRL; import java.security.cert.X509Certificate; import java.util.Date; import java.util.List; public class CRLVerifierTest extends TestCase { /** * To test CRLVerifier behaviour when a revoked certificate is given, a fake certificate will be created, signed * by a fake root certificate. To make our life easy, the CrlDistributionPoint extension will be extracted from * the real peer certificate in resources directory and copied to the fake certificate as a certificate extension. * So the criDistributionPointURL in the fake certificate will be the same as in the real certificate. * The created X509CRL object will be put to CRLCache against the criDistributionPointURL. Since the crl is in the * cache, there will NOT be a remote call to the CRL server at criDistributionPointURL. * @throws Exception */ public void testRevokedCertificate() throws Exception { //Add BouncyCastle as Security Provider. Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); Utils utils = new Utils(); //Create X509Certificate from the real certificate file in resource folder. X509Certificate realPeerCertificate = utils.getRealPeerCertificate(); //Extract crlDistributionPointUrl from the real peer certificate. String crlDistributionPointUrl = getCRLDistributionPointUrl(realPeerCertificate); //Create fake CA certificate. KeyPair caKeyPair = utils.generateRSAKeyPair(); X509Certificate fakeCACert = utils.generateFakeRootCert(caKeyPair); //Create fake peer certificate signed by the fake CA private key. This will be a revoked certificate. KeyPair peerKeyPair = utils.generateRSAKeyPair(); BigInteger revokedSerialNumber = BigInteger.valueOf(111); X509Certificate fakeRevokedCertificate = generateFakePeerCert(revokedSerialNumber, peerKeyPair.getPublic(), caKeyPair.getPrivate(), fakeCACert, realPeerCertificate); //Create a crl with fakeRevokedCertificate marked as revoked. X509CRL x509CRL = createCRL(fakeCACert, caKeyPair.getPrivate(), revokedSerialNumber); CRLCache cache = CRLCache.getCache(); cache.init(5, 5); cache.setCacheValue(crlDistributionPointUrl, x509CRL); CRLVerifier crlVerifier = new CRLVerifier(cache); RevocationStatus status = crlVerifier.checkRevocationStatus(fakeRevokedCertificate, null); //the fake crl we created will be checked if the fake certificate is revoked. So the status should be REVOKED. assertTrue(status == RevocationStatus.REVOKED); } /** * This will use Reflection to call getCrlDistributionPoints() private method in CRLVerifier. * @param certificate is a certificate with a proper CRLDistributionPoints extension. * @return the extracted cRLDistributionPointUrl. * @throws Exception */ private String getCRLDistributionPointUrl(X509Certificate certificate) throws Exception { CRLVerifier crlVerifier = new CRLVerifier(null); // use reflection since getCrlDistributionPoints() is private. Class<? extends CRLVerifier> crlVerifierClass = crlVerifier.getClass(); Method getCrlDistributionPoints = crlVerifierClass.getDeclaredMethod("getCrlDistributionPoints", X509Certificate.class); getCrlDistributionPoints.setAccessible(true); //getCrlDistributionPoints(..) returns a list of urls. Get the first one. List<String> distPoints = (List<String>) getCrlDistributionPoints.invoke(crlVerifier, certificate); return distPoints.get(0); } /** * Creates a fake CRL for the fake CA. The fake certificate with the given revokedSerialNumber will be marked * as Revoked in the returned CRL. * @param caCert the fake CA certificate. * @param caPrivateKey private key of the fake CA. * @param revokedSerialNumber the serial number of the fake peer certificate made to be marked as revoked. * @return the created fake CRL * @throws Exception */ public static X509CRL createCRL(X509Certificate caCert, PrivateKey caPrivateKey, BigInteger revokedSerialNumber) throws Exception { X509V2CRLGenerator crlGen = new X509V2CRLGenerator(); Date now = new Date(); crlGen.setIssuerDN(caCert.getSubjectX500Principal()); crlGen.setThisUpdate(now); crlGen.setNextUpdate(new Date(now.getTime() + TestConstants.NEXT_UPDATE_PERIOD)); crlGen.setSignatureAlgorithm("SHA256WithRSAEncryption"); crlGen.addCRLEntry(revokedSerialNumber, now, CRLReason.privilegeWithdrawn); crlGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(caCert)); crlGen.addExtension(X509Extensions.CRLNumber, false, new CRLNumber(BigInteger.valueOf(1))); return crlGen.generateX509CRL(caPrivateKey, "BC"); } public X509Certificate generateFakePeerCert(BigInteger serialNumber, PublicKey entityKey, PrivateKey caKey, X509Certificate caCert, X509Certificate firstCertificate) throws Exception { Utils utils = new Utils(); X509V3CertificateGenerator certGen = utils.getUsableCertificateGenerator(caCert, entityKey, serialNumber); certGen.copyAndAddExtension(new DERObjectIdentifier(X509Extensions.CRLDistributionPoints.getId()), false, firstCertificate); return certGen.generateX509Certificate(caKey, "BC"); } }