/* * 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.tests.javax.security.cert; import java.io.ByteArrayInputStream; 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.cert.CertificateFactory; import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; 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; /** */ 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 */ // TODO(tball): enable when sun.security port is complete. // 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 { } } // TODO(tball): implement when key signing is implemented. // 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()} */ // TODO(tball): enable when sun.security port is complete. // 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)); // // } // TODO(tball): implement when key signing is implemented. // /** // * @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()); // } // TODO(tball): implement when key signing is implemented. // /** // * @throws SignatureException // * @throws NoSuchProviderException // * @throws NoSuchAlgorithmException // * @throws java.security.cert.CertificateException // * @throws InvalidKeyException // * @throws IOException // * @throws CertificateException // * {@link Certificate#verify(PublicKey, String)} // */ // public void testVerifyPublicKeyString() throws Exception { // // try { // javaxCert.verify(javaxCert.getPublicKey(), myProvider.getName()); // } catch (NoSuchAlgorithmException e) { // // ok // } // // // myProvider.getService(type, algorithm) // // Keep track of the original position so the provider can be // // reinserted in the same spot later. // Provider[] providers = Security.getProviders(); // int i = 0; // for (; i < providers.length; i++) { // if (providers[i] == myProvider) { // break; // } // } // // Security.removeProvider(myProvider.getName()); // try { // javaxCert.verify(javaxCert.getPublicKey(), myProvider.getName()); // } catch (NoSuchProviderException e) { // // ok // } // // // Note: The position is 1-based, that is, 1 is most preferred, // // followed by 2, and so on // Security.insertProviderAt(myProvider, i + 1); // // // Find the Provider which offers MD5withRSA for the certificate's // // public key. // Signature signature = Signature.getInstance("MD5withRSA"); // signature.initVerify(javaxSSCert.getPublicKey()); // Provider provider = signature.getProvider(); // // // self signed cert: should verify with provider // try { // javaxSSCert.verify(javaxSSCert.getPublicKey(), // provider.getName()); // } catch (SignatureException e) { // fail("blu"); // } // // } public static Test suite() { return new TestSuite(X509CertificateTest.class); } }