/* * 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 tests.api.javax.security.cert; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import tests.targets.security.cert.CertificateFactoryTestX509; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.Principal; import java.security.Provider; import java.security.PublicKey; import java.security.Security; import java.security.SignatureException; import java.security.Provider.Service; import java.security.cert.CertificateFactory; import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.Set; import java.util.logging.Logger; import javax.security.cert.Certificate; import javax.security.cert.CertificateEncodingException; import javax.security.cert.CertificateException; import javax.security.cert.CertificateExpiredException; import javax.security.cert.CertificateNotYetValidException; import javax.security.cert.X509Certificate; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import tests.targets.security.cert.CertificateFactoryTestX509; /** */ public class X509CertificateTest extends TestCase { // Testing data was generated by using of classes // from org.apache.harmony.security.asn1 package encoded // by org.apache.harmony.misc.Base64 class. private static String base64cert = "-----BEGIN CERTIFICATE-----\n" + "MIIC+jCCAragAwIBAgICAiswDAYHKoZIzjgEAwEBADAdMRswGQYDVQQKExJDZXJ0a" + "WZpY2F0ZSBJc3N1ZXIwIhgPMTk3MDAxMTIxMzQ2NDBaGA8xOTcwMDEyNDAzMzMyMF" + "owHzEdMBsGA1UEChMUU3ViamVjdCBPcmdhbml6YXRpb24wGTAMBgcqhkjOOAQDAQE" + "AAwkAAQIDBAUGBwiBAgCqggIAVaOCAhQwggIQMA8GA1UdDwEB/wQFAwMBqoAwEgYD" + "VR0TAQH/BAgwBgEB/wIBBTAUBgNVHSABAf8ECjAIMAYGBFUdIAAwZwYDVR0RAQH/B" + "F0wW4EMcmZjQDgyMi5OYW1lggdkTlNOYW1lpBcxFTATBgNVBAoTDE9yZ2FuaXphdG" + "lvboYaaHR0cDovL3VuaWZvcm0uUmVzb3VyY2UuSWSHBP///wCIByoDolyDsgMwDAY" + "DVR0eAQH/BAIwADAMBgNVHSQBAf8EAjAAMIGZBgNVHSUBAf8EgY4wgYsGBFUdJQAG" + "CCsGAQUFBwMBBggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMDBggrBgEFBQcDB" + "AYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcDBwYIKwYBBQUHAwgGCCsGAQUFBw" + "MJBggrBgEFBQgCAgYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GA1UdNgEB/wQDAgE" + "BMA4GBCpNhgkBAf8EAwEBATBkBgNVHRIEXTBbgQxyZmNAODIyLk5hbWWCB2ROU05h" + "bWWkFzEVMBMGA1UEChMMT3JnYW5pemF0aW9uhhpodHRwOi8vdW5pZm9ybS5SZXNvd" + "XJjZS5JZIcE////AIgHKgOiXIOyAzAJBgNVHR8EAjAAMAoGA1UdIwQDAQEBMAoGA1" + "UdDgQDAQEBMAoGA1UdIQQDAQEBMAwGByqGSM44BAMBAQADMAAwLQIUAL4QvoazNWP" + "7jrj84/GZlhm09DsCFQCBKGKCGbrP64VtUt4JPmLjW1VxQA==\n" + "-----END CERTIFICATE-----"; /* * a self-signed certificate */ private static final String selfSignedCert = "-----BEGIN CERTIFICATE-----\n" + "MIIDPzCCAqigAwIBAgIBADANBgkqhkiG9w0BAQUFADB5MQswCQYDVQQGEwJBTjEQ" + "MA4GA1UECBMHQW5kcm9pZDEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5k" + "cm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBh" + "bmRyb2lkLmNvbTAeFw0wOTAzMjAxNzAwMDZaFw0xMjAzMTkxNzAwMDZaMHkxCzAJ" + "BgNVBAYTAkFOMRAwDgYDVQQIEwdBbmRyb2lkMRAwDgYDVQQKEwdBbmRyb2lkMRAw" + "DgYDVQQLEwdBbmRyb2lkMRAwDgYDVQQDEwdBbmRyb2lkMSIwIAYJKoZIhvcNAQkB" + "FhNhbmRyb2lkQGFuZHJvaWQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB" + "gQCqQkDtkiEXmV8O5EK4y2Y9YyoWNDx70z4fqD+9muuzJGuM5NovMbxhBycuKHF3" + "WK60iXzrsAYkB1c8VHHbcUEFqz2fBdLKyxy/nYohlo8TYSVpEjt3vfc0sgmp4FKU" + "RDHO2z3rZPHWysV9L9ZvjeQpiwaYipU9epdBmvFmxQmCDQIDAQABo4HWMIHTMB0G" + "A1UdDgQWBBTnm32QKeqQC38IQXZOQSPoQyypAzCBowYDVR0jBIGbMIGYgBTnm32Q" + "KeqQC38IQXZOQSPoQyypA6F9pHsweTELMAkGA1UEBhMCQU4xEDAOBgNVBAgTB0Fu" + "ZHJvaWQxEDAOBgNVBAoTB0FuZHJvaWQxEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNV" + "BAMTB0FuZHJvaWQxIjAgBgkqhkiG9w0BCQEWE2FuZHJvaWRAYW5kcm9pZC5jb22C" + "AQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQAUmDApQu+r5rglS1WF" + "BKXE3R2LasFvbBwdw2E0MAc0TWqLVW91VW4VWMX4r+C+c7rZpYXXtRqFRCuI/czL" + "0e1GaUP/Wa6bXBcm2u7Iv2dVAaAOELmFSVTZeR57Lm9lT9kQLp24kmNndIsiDW3T" + "XZ4pY/k2kxungOKx8b8pGYE9Bw==\n" + "-----END CERTIFICATE-----"; private java.security.cert.X509Certificate cert; private javax.security.cert.X509Certificate tbt_cert; private java.security.cert.X509Certificate javaCert; private Provider myProvider; private javax.security.cert.X509Certificate javaxCert; private java.security.cert.Certificate javaSSCert; private Provider mySSProvider; private Certificate javaxSSCert; @Override protected void setUp() throws Exception { try { ByteArrayInputStream bais = new ByteArrayInputStream(base64cert .getBytes()); CertificateFactory cf = CertificateFactory.getInstance("X.509"); this.cert = (java.security.cert.X509Certificate) cf .generateCertificate(bais); this.tbt_cert = X509Certificate.getInstance(cert.getEncoded()); // non self signed cert this.javaCert = (java.security.cert.X509Certificate)cf .generateCertificate(new ByteArrayInputStream(selfSignedCert.getBytes())); this.javaxCert = X509Certificate.getInstance(javaCert.getEncoded()); myProvider = cf.getProvider(); Security.addProvider(myProvider); // self signed cert this.javaSSCert = cf.generateCertificate(new ByteArrayInputStream( selfSignedCert.getBytes())); this.javaxSSCert = X509Certificate.getInstance(javaCert .getEncoded()); mySSProvider = cf.getProvider(); Security.addProvider(mySSProvider); } catch (java.security.cert.CertificateException e) { // The requested certificate type is not available. // Test pass.. this.cert = null; Logger.global.warning("Error in test setup: Certificate type not supported"); } catch (javax.security.cert.CertificateException e) { // The requested certificate type is not available. // Test pass.. this.cert = null; Logger.global.warning("Error in test setup: Certificate type not supported"); } } /** * X509Certificate() constructor testing. * {@link X509Certificate#X509Certificate() } */ public void testConstructor() { //Direct constructor, check if it throws an exception X509Certificate cert = new MyCertificate(); } /** * getInstance(InputStream inStream) method testing. */ public void testGetInstance1() { if (this.cert == null) { // The requested certificate type is not available. // Test can not be applied. return; } try { ByteArrayInputStream bais = new ByteArrayInputStream(cert .getEncoded()); X509Certificate.getInstance(bais); } catch (java.security.cert.CertificateEncodingException e) { fail("Unexpected CertificateEncodingException was thrown."); } catch (CertificateEncodingException e) { fail("Unexpected CertificateEncodingException was thrown."); } catch (CertificateException e) { // The requested certificate type is not available. // Test pass.. } // Regression for HARMONY-756 try { X509Certificate.getInstance((InputStream) null); fail("No expected CertificateException"); } catch (CertificateException e) { // expected; } } /** * getInstance(byte[] certData) method testing. * @throws CertificateEncodingException * @throws java.security.cert.CertificateEncodingException */ public void testGetInstance2() throws java.security.cert.CertificateEncodingException, CertificateEncodingException { boolean certificateException = false; X509Certificate c = null; if (this.cert == null) { // The requested certificate type is not available. // Test can not be applied. return; } try { c = X509Certificate.getInstance(cert.getEncoded()); } catch (java.security.cert.CertificateEncodingException e) { fail("Unexpected CertificateEncodingException was thrown."); } catch (CertificateException e) { // The requested certificate type is not available. // Test pass.. certificateException = true; } if (! certificateException) { assertNotNull(c); assertTrue(Arrays.equals(c.getEncoded(),cert.getEncoded() )); } try { X509Certificate.getInstance(new byte[]{(byte) 1 }); } catch (CertificateException e) { //ok } // Regression for HARMONY-756 try { X509Certificate.getInstance((byte[]) null); fail("No expected CertificateException"); } catch (CertificateException e) { // expected; } } /** * checkValidity() method testing. * @throws CertificateNotYetValidException * @throws CertificateExpiredException * @throws java.security.cert.CertificateExpiredException * @throws java.security.cert.CertificateNotYetValidException */ public void testCheckValidity1() throws CertificateExpiredException, CertificateNotYetValidException, java.security.cert.CertificateExpiredException, java.security.cert.CertificateNotYetValidException { if (this.cert == null) { // The requested certificate type is not available. // Test can not be applied. return; } Date date = new Date(); Date nb_date = tbt_cert.getNotBefore(); Date na_date = tbt_cert.getNotAfter(); try { tbt_cert.checkValidity(); assertFalse("CertificateExpiredException expected", date .compareTo(na_date) > 0); assertFalse("CertificateNotYetValidException expected", date .compareTo(nb_date) < 0); } catch (CertificateExpiredException e) { assertTrue("Unexpected CertificateExpiredException was thrown", date.compareTo(na_date) > 0); } catch (CertificateNotYetValidException e) { assertTrue("Unexpected CertificateNotYetValidException was thrown", date.compareTo(nb_date) < 0); } try { tbt_cert.checkValidity(); } catch (CertificateExpiredException e) { // ok } try { cert.checkValidity(); } catch (java.security.cert.CertificateExpiredException e) { // ok } } /** * checkValidity(Date date) method testing. * @throws CertificateNotYetValidException * @throws CertificateExpiredException */ public void testCheckValidity2() throws CertificateNotYetValidException, CertificateExpiredException { if (this.cert == null) { // The requested certificate type is not available. // Test can not be applied. return; } Date[] date = new Date[8]; Calendar calendar = Calendar.getInstance(); for (int i = 0; i < date.length; i++) { calendar.set(i * 500, Calendar.JANUARY, 1); date[i] = calendar.getTime(); } Date nb_date = tbt_cert.getNotBefore(); Date na_date = tbt_cert.getNotAfter(); for (int i = 0; i < date.length; i++) { try { tbt_cert.checkValidity(date[i]); assertFalse("CertificateExpiredException expected", date[i] .compareTo(na_date) > 0); assertFalse("CertificateNotYetValidException expected", date[i] .compareTo(nb_date) < 0); } catch (CertificateExpiredException e) { assertTrue("Unexpected CertificateExpiredException was thrown", date[i].compareTo(na_date) > 0); } catch (CertificateNotYetValidException e) { assertTrue("Unexpected CertificateNotYetValidException " + "was thrown", date[i].compareTo(nb_date) < 0); } } Calendar calendarNow = Calendar.getInstance(); try { tbt_cert.checkValidity(calendarNow.getTime()); } catch (CertificateExpiredException e) { //ok } Calendar calendarPast = GregorianCalendar.getInstance(); calendarPast.clear(); try { tbt_cert.checkValidity(calendarPast.getTime()); } catch (CertificateNotYetValidException e) { //ok } } /** * getVersion() method testing. */ public void testGetVersion() { if (this.cert == null) { // The requested certificate type is not available. // Test can not be applied. return; } assertEquals("The version is not correct.", tbt_cert.getVersion(), 2); } /** * getSerialNumber() method testing. */ public void testGetSerialNumber() { if (this.cert == null) { // The requested certificate type is not available. // Test can not be applied. return; } assertEquals("The serial number is not correct.", tbt_cert .getSerialNumber(), cert.getSerialNumber()); } /** * getIssuerDN() method testing. */ public void testGetIssuerDN() { if (this.cert == null) { // The requested certificate type is not available. // Test can not be applied. Logger.global.warning("testGetIssuerDN: error in test setup."); } assertEquals("The issuer DN is not correct.", tbt_cert.getIssuerDN(), cert.getIssuerDN()); } /** * getSubjectDN() method testing. */ public void testGetSubjectDN() { if (this.cert == null) { // The requested certificate type is not available. // Test can not be applied. return; } assertEquals("The subject DN is not correct.", tbt_cert.getSubjectDN(), cert.getSubjectDN()); } /** * getNotBefore() method testing. */ public void testGetNotBefore() { if (this.cert == null) { // The requested certificate type is not available. // Test can not be applied. return; } assertEquals("The NotBefore date is not correct.", tbt_cert .getNotBefore(), cert.getNotBefore()); } /** * getNotAfter() method testing. */ public void testGetNotAfter() { if (this.cert == null) { // The requested certificate type is not available. // Test can not be applied. return; } assertEquals("The NotAfter date is not correct.", tbt_cert .getNotAfter(), cert.getNotAfter()); } /** * getSigAlgName() method testing. */ public void testGetSigAlgName() { if (this.cert == null) { // The requested certificate type is not available. // Test can not be applied. return; } assertEquals("The name of signature algorithm is not correct.", tbt_cert.getSigAlgName(), cert.getSigAlgName()); } /** * getSigAlgOID() method testing. */ public void testGetSigAlgOID() { if (this.cert == null) { // The requested certificate type is not available. // Test can not be applied. return; } assertEquals("The name of OID of signature algorithm is not correct.", tbt_cert.getSigAlgOID(), cert.getSigAlgOID()); } /** * getSigAlgParams() method testing. */ public void testGetSigAlgParams() { if (this.cert == null) { // The requested certificate type is not available. // Test can not be applied. return; } assertTrue("The byte array with encoded algorithm parameters " + "is not correct.", Arrays.equals(tbt_cert.getSigAlgParams(), cert.getSigAlgParams())); } /** * The stub class used for testing of non abstract methods. */ private class MyCertificate extends X509Certificate { public MyCertificate() { super(); } @Override public void checkValidity() throws CertificateExpiredException, CertificateNotYetValidException { } @Override public void checkValidity(Date arg0) throws CertificateExpiredException, CertificateNotYetValidException { } @Override public Principal getIssuerDN() { return null; } @Override public Date getNotAfter() { return null; } @Override public Date getNotBefore() { return null; } @Override public BigInteger getSerialNumber() { return null; } @Override public String getSigAlgName() { return null; } @Override public String getSigAlgOID() { return null; } @Override public byte[] getSigAlgParams() { return null; } @Override public Principal getSubjectDN() { return null; } @Override public int getVersion() { return 0; } @Override public byte[] getEncoded() throws CertificateEncodingException { return null; } @Override public PublicKey getPublicKey() { return null; } @Override public String toString() { return null; } @Override public void verify(PublicKey key) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException { } @Override public void verify(PublicKey key, String sigProvider) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException { } } public class MyModifiablePublicKey implements PublicKey { private PublicKey key; private boolean modifiedAlgo; private String algo; private String format; private boolean modifiedFormat; private boolean modifiedEncoding; private byte[] encoding; public MyModifiablePublicKey(PublicKey k) { super(); this.key = k; } public String getAlgorithm() { if (modifiedAlgo) { return algo; } else { return key.getAlgorithm(); } } public String getFormat() { if (modifiedFormat) { return this.format; } else { return key.getFormat(); } } public byte[] getEncoded() { if (modifiedEncoding) { return this.encoding; } else { return key.getEncoded(); } } public long getSerVerUID() { return key.serialVersionUID; } public void setAlgorithm(String myAlgo) { modifiedAlgo = true; this.algo = myAlgo; } public void setFormat(String myFormat) { modifiedFormat = true; format = myFormat; } public void setEncoding(byte[] myEncoded) { modifiedEncoding = true; encoding = myEncoded; } } /** * @throws CertificateEncodingException * {@link Certificate#getEncoded()} */ public void testGetEncoded() throws CertificateEncodingException, java.security.cert.CertificateException { // cert = DER encoding of the ASN1.0 structure assertTrue(Arrays.equals(cert.getEncoded(), tbt_cert.getEncoded())); assertFalse(Arrays.equals(javaxCert.getEncoded(), tbt_cert.getEncoded())); } /** * {@link Certificate#getPublicKey()} */ public void testGetPublicKey() { PublicKey key = javaxCert.getPublicKey(); assertNotNull(key); assertEquals(javaxCert.getPublicKey(), javaCert.getPublicKey()); assertEquals(key.getAlgorithm(),"RSA"); key = javaxSSCert.getPublicKey(); assertNotNull(key); assertEquals(key.getAlgorithm(),"RSA"); //assertTrue(mySSProvider.containsKey(key)); } /** * @throws SignatureException * @throws NoSuchProviderException * @throws NoSuchAlgorithmException * @throws InvalidKeyException * @throws CertificateException * {@link Certificate#verify(PublicKey)} */ // Side Effect: Destroys MD5 provider, hurts succeeding tests public void testVerifyPublicKey() throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, SignatureException, CertificateException { // Preconditions assertNotNull(javaxCert.getPublicKey()); assertNotNull(javaxSSCert.getPublicKey()); //precondition for self signed certificates /*assertEquals(((X509Certificate) javaxSSCert).getIssuerDN().getName(), ((X509Certificate) javaxSSCert).getSubjectDN());*/ // must always evaluate true for self signed // here not self signed: try { javaxCert.verify(javaxCert.getPublicKey()); } catch (SignatureException e) { // ok } PublicKey k = javaxCert.getPublicKey(); MyModifiablePublicKey changedEncoding = new MyModifiablePublicKey(k); changedEncoding .setEncoding(new byte[javaxCert.getEncoded().length - 1]); try { javaxCert.verify(tbt_cert.getPublicKey()); } catch (InvalidKeyException e) { // ok } try { javaxCert.verify(null); } catch (Exception e) { // ok } try { javaxCert.verify(changedEncoding); fail("Exception expected"); } catch (Exception e) { // ok } // following test doesn't work because the algorithm is derived from // somewhere else. // MyModifiablePublicKey changedAlgo = new MyModifiablePublicKey(k); // changedAlgo.setAlgorithm("MD5withBla"); // try { // javaxCert.verify(changedAlgo); // fail("Exception expected"); // } catch (SignatureException e) { // // ok // } // Security.removeProvider(mySSProvider.getName()); // try { // javaxSSCert.verify(javaxSSCert.getPublicKey()); // } catch (NoSuchProviderException e) { // // ok // } // Security.addProvider(mySSProvider); // must always evaluate true for self signed // javaxSSCert.verify(javaxSSCert.getPublicKey()); } /** * @throws SignatureException * @throws NoSuchProviderException * @throws NoSuchAlgorithmException * @throws java.security.cert.CertificateException * @throws InvalidKeyException * @throws IOException * @throws CertificateException * {@link Certificate#verify(PublicKey, String)} */ // SideEffect: Destroys MD5 provider, hurts succeeding tests public void testVerifyPublicKeyString() throws InvalidKeyException, java.security.cert.CertificateException, NoSuchAlgorithmException, NoSuchProviderException, SignatureException, IOException, CertificateException { try { javaxCert.verify(javaxCert.getPublicKey(), myProvider.getName()); } catch (NoSuchAlgorithmException e) { // ok } // myProvider.getService(type, algorithm) Security.removeProvider(myProvider.getName()); try { javaxCert.verify(javaxCert.getPublicKey(), myProvider.getName()); } catch (NoSuchProviderException e) { // ok } Security.addProvider(myProvider); Provider[] providers = Security.getProviders("Signature.MD5withRSA"); if (providers == null || providers.length == 0) { fail("no Provider for Signature.MD5withRSA"); return; } // self signed cert: should verify with provider try { javaxSSCert.verify(javaxSSCert.getPublicKey(), providers[0].getName()); } catch (SignatureException e) { fail("blu"); } } public static Test suite() { return new TestSuite(X509CertificateTest.class); } }