/*
* 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.
*/
/**
* @author Alexander Y. Kleymenov
* @version $Revision$
*/
package org.apache.harmony.security.tests.provider.cert;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.CRLException;
import java.security.cert.CertificateFactory;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Set;
import javax.security.auth.x500.X500Principal;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.apache.harmony.security.provider.cert.X509CRLImpl;
import org.apache.harmony.security.provider.cert.X509CertImpl;
import org.apache.harmony.security.x501.Name;
import org.apache.harmony.security.x509.AlgorithmIdentifier;
import org.apache.harmony.security.x509.AuthorityKeyIdentifier;
import org.apache.harmony.security.x509.CRLNumber;
import org.apache.harmony.security.x509.Certificate;
import org.apache.harmony.security.x509.CertificateIssuer;
import org.apache.harmony.security.x509.CertificateList;
import org.apache.harmony.security.x509.DistributionPointName;
import org.apache.harmony.security.x509.Extension;
import org.apache.harmony.security.x509.Extensions;
import org.apache.harmony.security.x509.GeneralName;
import org.apache.harmony.security.x509.GeneralNames;
import org.apache.harmony.security.x509.InvalidityDate;
import org.apache.harmony.security.x509.IssuingDistributionPoint;
import org.apache.harmony.security.x509.ReasonCode;
import org.apache.harmony.security.x509.ReasonFlags;
import org.apache.harmony.security.x509.SubjectPublicKeyInfo;
import org.apache.harmony.security.x509.TBSCertList;
import org.apache.harmony.security.x509.TBSCertificate;
import org.apache.harmony.security.x509.Validity;
/**
* X509CRLImplTest
*/
public class X509CRLImplTest extends TestCase {
// Algorithm name and its OID (http://oid.elibel.tm.fr)
private static String algOID = "1.2.840.10040.4.3";
private static String algName = "SHA1withDSA";
// DER boolean false encoding (http://asn1.elibel.tm.fr)
// Makes no sense. For testing purposes we need just provide
// some ASN.1 structure:
private static byte[] algParams = {1, 1, 0};
private static AlgorithmIdentifier signature;
private static byte[] signatureValue;
static {
signature = new AlgorithmIdentifier(algOID, algParams);
}
private static String issuerName = "O=CRL Issuer";
private static String certIssuerName = "O=Certificate Issuer";
private static BigInteger certSerialNumber1 = BigInteger.valueOf(555);
private static BigInteger certSerialNumber2 = BigInteger.valueOf(567);
private static BigInteger certSerialNumber3 = BigInteger.valueOf(777);
private static Date thisUpdate = new Date();
private static Date nextUpdate;
static {
nextUpdate = new Date(thisUpdate.getTime()+100000);
}
private static Extensions crlEntryExtensions = new Extensions();
static {
// Reason Code
crlEntryExtensions.addExtension(
new Extension("2.5.29.21", Extension.NON_CRITICAL,
new ReasonCode(ReasonCode.KEY_COMPROMISE)));
// Invalidity Date Extension
crlEntryExtensions.addExtension(
new Extension("2.5.29.24", Extension.NON_CRITICAL,
new InvalidityDate(new Date())));
// add the Certificate Issuer Extension to check if implementation
// support indirect CRLs. As says rfc 3280 (p.62):
// "If used by conforming CRL issuers, this extension MUST always be
// critical. If an implementation ignored this extension it could not
// correctly attribute CRL entries to certificates. This specification
// RECOMMENDS that implementations recognize this extension."
try {
crlEntryExtensions.addExtension(
new Extension("2.5.29.29", true,
new CertificateIssuer(
new GeneralName(new Name(certIssuerName))
))
);
} catch (Exception e) {
e.printStackTrace();
}
}
private static Date revocationDate = new Date();
private static List revokedCertificates = Arrays.asList(
new TBSCertList.RevokedCertificate[] {
new TBSCertList.RevokedCertificate(certSerialNumber1,
revocationDate, null),
// the item for certificate issued by other authority
new TBSCertList.RevokedCertificate(certSerialNumber2,
revocationDate, crlEntryExtensions),
new TBSCertList.RevokedCertificate(certSerialNumber3,
revocationDate, null),
});
private static Extensions crlExtensions;
static {
try {
crlExtensions = new Extensions(
Arrays.asList(new Extension[] {
// CRL Number Extension
new Extension("2.5.29.20", Extension.NON_CRITICAL,
new CRLNumber(BigInteger.valueOf(4444))),
// Authority Key Identifier
new Extension("2.5.29.35", false,
new AuthorityKeyIdentifier(
// keyIdentifier (random value)
new byte[] {1, 2, 3, 4, 5},
// authorityCertIssuer
new GeneralNames(
Arrays.asList(new GeneralName[] {
new GeneralName(new Name(certIssuerName))
})),
// authorityCertSerialNumber
certSerialNumber2)),
// Issuing Distribution Point
new Extension("2.5.29.28", Extension.CRITICAL,
new IssuingDistributionPoint(
new DistributionPointName(new GeneralNames(
Arrays.asList(new GeneralName[] {
new GeneralName(1, "rfc@822.Name"),
new GeneralName(2, "dNSName"),
new GeneralName(4, "O=Organization"),
new GeneralName(6, "http://uniform.Resource.Id"),
new GeneralName(7, "255.255.255.0"),
new GeneralName(8, "1.2.3.4444.55555")
}))),
new ReasonFlags(new boolean[] {true, true, false, false, true, true})
)),
}));
} catch (Exception e) {
e.printStackTrace();
}
}
// keys are using to make signature and to verify it
private static PublicKey publicKey;
private static PrivateKey privateKey;
private static byte[] signatureValueBytes;
static {
try {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
keyGen.initialize(1024);
KeyPair keyPair = keyGen.genKeyPair();
publicKey = keyPair.getPublic();
privateKey = keyPair.getPrivate();
} catch (Exception e) {
e.printStackTrace();
}
}
private static X509CRLImpl crl;
private static CertificateList certificateList;
private static TBSCertList tbscertlist;
private static byte[] encoding;
private static byte[] tbsEncoding;
static CertificateFactory factory;
static {
try {
Name issuer = new Name(issuerName);
tbscertlist =
new TBSCertList(2, signature, issuer, thisUpdate,
nextUpdate, revokedCertificates, crlExtensions);
tbsEncoding = tbscertlist.getEncoded();
try {
Signature sig= Signature.getInstance("DSA");
sig.initSign(privateKey);
sig.update(tbsEncoding, 0, tbsEncoding.length);
signatureValueBytes = sig.sign();
} catch (Exception e) {
e.printStackTrace();
fail("Unexpected exception was thrown: "+e.getMessage());
}
factory = CertificateFactory.getInstance("X.509");
} catch (Exception e) {
e.printStackTrace();
fail("Unexpected Exception was thrown: "+e.getMessage());
}
}
ByteArrayInputStream stream;
protected void setUp() throws java.lang.Exception {
if ("testVerify3".equals(getName())) {
signatureValue = new byte[signatureValueBytes.length];
// make incorrect signature value:
System.arraycopy(signatureValueBytes, 0,
signatureValue, 0, signatureValueBytes.length);
signatureValue[20]++;
} else {
signatureValue = signatureValueBytes;
}
certificateList =
new CertificateList(tbscertlist, signature, signatureValue);
encoding = CertificateList.ASN1.encode(certificateList);
stream = new ByteArrayInputStream(encoding);
crl = new X509CRLImpl(certificateList);
}
private static int XXX = 0, counter = 0;
public void testCreationCRL() throws Exception {
byte[] stamp = new byte[10];
if ((++counter)%10 != 0) {
XXX++;
}
byte tmp[] = BigInteger.valueOf(XXX).toByteArray();
System.arraycopy(tmp, 0, stamp, 0, tmp.length);
System.arraycopy(stamp, 0, encoding,
encoding.length-stamp.length, stamp.length);
stream.reset();
java.security.cert.X509CRL c = (java.security.cert.X509CRL)
factory.generateCRL(stream);
if (counter == 1) {
System.out.println("\nUSING: "+ c.getClass());
}
byte[] enc = c.getEncoded();
byte[] stamp_chek = new byte[stamp.length];
System.arraycopy(enc, enc.length - stamp.length,
stamp_chek, 0, stamp.length);
if (!Arrays.equals(stamp, stamp_chek)) {
fail("Wrong encoding received.");
}
}
/**
* X509CRLImpl(CertificateList crl) method testing.
* Tested during setup.
*/
public void testX509CRLImpl() {
try {
new X509CRLImpl((CertificateList)
CertificateList.ASN1.decode(encoding));
} catch (IOException e) {
fail("Unexpected exception was thrown");
}
}
/**
* getEncoded() method testing.
*/
public void testGetEncoded() {
try {
if (!Arrays.equals(encoding, crl.getEncoded())) {
fail("Incorrect encoding of CRL.");
}
} catch (CRLException e) {
fail("Unexpected CRLException was thrown.");
}
}
/**
* getVersion() method testing.
*/
public void testGetVersion() {
assertEquals("Incorrect version value", 2, crl.getVersion());
}
/**
* getIssuerDN() method testing.
*/
public void testGetIssuerDN() {
assertEquals("Incorrect issuer value",
new X500Principal(issuerName), crl.getIssuerDN());
}
/**
* getIssuerX500Principal() method testing.
*/
public void testGetIssuerX500Principal() {
assertEquals("Incorrect issuer value",
new X500Principal(issuerName), crl.getIssuerDN());
}
/**
* getThisUpdate() method testing.
*/
public void testGetThisUpdate() {
assertTrue("Incorrect thisUpdate value",
thisUpdate.getTime()/1000 == crl.getThisUpdate().getTime()/1000);
}
/**
* getNextUpdate() method testing.
*/
public void testGetNextUpdate() {
assertTrue("Incorrect nextUpdate value",
nextUpdate.getTime()/1000 == crl.getNextUpdate().getTime()/1000);
}
/**
* getRevokedCertificate(X509Certificate certificate) method testing.
*/
public void testGetRevokedCertificate1() {
try {
X509CertImpl cert1 = new X509CertImpl(
new Certificate(
new TBSCertificate(2, certSerialNumber1, signature,
new Name(certIssuerName),
new Validity(new Date(), new Date()),
new Name(certIssuerName),
new SubjectPublicKeyInfo(signature, new byte[10]),
null, null, null),
signature, new byte[10]));
X509CertImpl cert2 = new X509CertImpl(
new Certificate(
new TBSCertificate(2, certSerialNumber2, signature,
new Name(certIssuerName),
new Validity(new Date(), new Date()),
new Name(certIssuerName),
new SubjectPublicKeyInfo(signature, new byte[10]),
null, null, null),
signature, new byte[10]));
X509CertImpl cert3 = new X509CertImpl(
new Certificate(
new TBSCertificate(2, certSerialNumber3, signature,
new Name("O=Another Cert Issuer"),
new Validity(new Date(), new Date()),
new Name(certIssuerName),
new SubjectPublicKeyInfo(signature, new byte[10]),
null, null, null),
signature, new byte[10]));
assertNull("Certificate should not be presented in CRL "
+ "because issuer is not the same as CRL issuer",
crl.getRevokedCertificate(cert1));
assertNotNull("Certificate should be presented in CRL",
crl.getRevokedCertificate(cert2));
assertNull("Certificate should not be presented in CRL "
+ "because issuer is not the same as CRL issuer",
crl.getRevokedCertificate(cert3));
} catch (IOException e) {
// should never happen;
e.printStackTrace();
fail("Unexpected IOException was thrown:"+e.getMessage());
}
}
/**
* getRevokedCertificate(BigInteger serialNumber) method testing.
*/
public void testGetRevokedCertificate2() {
assertNotNull("The revoked certificate with the serial number '"
+ certSerialNumber1 + "' should be presented in CRL.",
crl.getRevokedCertificate(certSerialNumber1));
assertNull("The revoked certificate with the serial number '"
+ certSerialNumber2 + "' should not be presented in CRL.",
crl.getRevokedCertificate(certSerialNumber2));
assertNull("The revoked certificate with the serial number '"
+ certSerialNumber3 + "' should not be presented in CRL.",
crl.getRevokedCertificate(certSerialNumber3));
}
/**
* getRevokedCertificates() method testing.
*/
public void testGetRevokedCertificates() {
Set rcerts = crl.getRevokedCertificates();
assertNotNull("The set should not be null", rcerts);
assertTrue("The size of returned set is incorrect",
rcerts.size() == revokedCertificates.size());
}
/**
* getTBSCertList() method testing.
*/
public void testGetTBSCertList() {
try {
assertTrue(
"Retrieved tbsCertList encoding does not equal to expected",
Arrays.equals(tbscertlist.getEncoded(),
crl.getTBSCertList()));
} catch(CRLException e) {
e.printStackTrace();
fail("Unexpected CRLException was thrown: "+e.getMessage());
}
}
/**
* getSignature() method testing.
*/
public void testGetSignature() {
if (!Arrays.equals(signatureValueBytes, crl.getSignature())) {
fail("Incorrect Signature value.");
}
}
/**
* getSigAlgName() method testing.
*/
public void testGetSigAlgName() {
assertEquals("Incorrect value of signature algorithm name",
algName, crl.getSigAlgName());
}
/**
* getSigAlgOID() method testing.
*/
public void testGetSigAlgOID() {
assertEquals("Incorrect value of signature algorithm OID",
algOID, crl.getSigAlgOID());
}
/**
* getSigAlgParams() method testing.
*/
public void testGetSigAlgParams() {
if (!Arrays.equals(algParams, crl.getSigAlgParams())) {
fail("Incorrect SigAlgParams value.");
}
}
/**
* verify(PublicKey key) method testing.
*/
public void testVerify1() throws Exception {
crl.verify(publicKey);
}
/**
* verify(PublicKey key, String sigProvider) method testing.
*/
public void testVerify2() throws Exception {
crl.verify(publicKey, Signature.getInstance("SHA1withDSA")
.getProvider().getName());
}
/**
* verify(PublicKey key) method testing.
*/
public void testVerify3() throws Exception {
try {
crl.verify(publicKey);
fail("Incorrect signature successfully verified.");
} catch (Exception e) {
}
}
/**
* isRevoked(Certificate cert) method testing.
*/
public void testIsRevoked() {
try {
X509CertImpl cert1 = new X509CertImpl(
new Certificate(
new TBSCertificate(2, certSerialNumber1, signature,
new Name(certIssuerName),
new Validity(new Date(), new Date()),
new Name(certIssuerName),
new SubjectPublicKeyInfo(signature, new byte[10]),
null, null, null),
signature, new byte[10]));
X509CertImpl cert2 = new X509CertImpl(
new Certificate(
new TBSCertificate(2, certSerialNumber2, signature,
new Name(certIssuerName),
new Validity(new Date(), new Date()),
new Name(certIssuerName),
new SubjectPublicKeyInfo(signature, new byte[10]),
null, null, null),
signature, new byte[10]));
X509CertImpl cert3 = new X509CertImpl(
new Certificate(
new TBSCertificate(2, certSerialNumber3, signature,
new Name("O=Another Cert Issuer"),
new Validity(new Date(), new Date()),
new Name(certIssuerName),
new SubjectPublicKeyInfo(signature, new byte[10]),
null, null, null),
signature, new byte[10]));
assertFalse("Certificate should not be presented in CRL "
+ "because issuer is not the same as CRL issuer",
crl.isRevoked(cert1));
assertTrue("Certificate should be presented in CRL",
crl.isRevoked(cert2));
assertFalse("Certificate should not be presented in CRL "
+ "because issuer is not the same as CRL issuer",
crl.isRevoked(cert3));
} catch (IOException e) {
// should never happen;
e.printStackTrace();
fail("Unexpected IOException was thrown:"+e.getMessage());
}
}
/**
* toString() method testing.
*/
public void testToString() {
assertNotNull("The string representation should not be null",
crl.toString());
}
// the following implementations are tested in X509CertImplTest:
/**
* getNonCriticalExtensionOIDs() method testing.
*/
public void testGetNonCriticalExtensionOIDs() {
System.out.println("getNonCriticalExtensionOIDs: "
+ crl.getNonCriticalExtensionOIDs());
}
/**
* getCriticalExtensionOIDs() method testing.
*/
public void testGetCriticalExtensionOIDs() {
System.out.println("getCriticalExtensionOIDs: "
+ crl.getCriticalExtensionOIDs());
}
/**
* getExtensionValue(String oid) method testing.
*/
public void testGetExtensionValue() throws Exception {
assertNotNull(crl.getExtensionValue("2.5.29.20"));
assertNull("Null value should be returned in the case of "
+ "nonexisting extension", crl.getExtensionValue("1.1.1.1"));
}
/**
* hasUnsupportedCriticalExtension() method testing.
*/
public void testHasUnsupportedCriticalExtension() {
System.out.println("hasUnsupportedCriticalExtension: "
+ crl.hasUnsupportedCriticalExtension());
}
public static Test suite() {
return new TestSuite(X509CRLImplTest.class);
}
public static void main(String[] args) throws Exception {
/*
X509CRLImplTest test = new X509CRLImplTest();
test.setUp();
long startTime = System.currentTimeMillis();
for (int i=0; i<100000; i++) {
test.testCreationCRL();
}
System.out.println("time: "+(System.currentTimeMillis() - startTime));
/*/
junit.textui.TestRunner.run(suite());
}
}