/* * 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 */ 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.CertificateEncodingException; import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateNotYetValidException; import java.security.cert.CertificateParsingException; import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.Iterator; 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.asn1.ObjectIdentifier; import org.apache.harmony.security.provider.cert.X509CertImpl; import org.apache.harmony.security.tests.support.cert.TestUtils; import org.apache.harmony.security.x501.Name; import org.apache.harmony.security.x509.AlgorithmIdentifier; import org.apache.harmony.security.x509.AlternativeName; import org.apache.harmony.security.x509.AuthorityKeyIdentifier; import org.apache.harmony.security.x509.BasicConstraints; import org.apache.harmony.security.x509.CRLDistributionPoints; import org.apache.harmony.security.x509.Certificate; import org.apache.harmony.security.x509.CertificatePolicies; import org.apache.harmony.security.x509.DistributionPoint; import org.apache.harmony.security.x509.DistributionPointName; import org.apache.harmony.security.x509.ExtendedKeyUsage; 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.GeneralSubtree; import org.apache.harmony.security.x509.GeneralSubtrees; import org.apache.harmony.security.x509.InhibitAnyPolicy; import org.apache.harmony.security.x509.KeyUsage; import org.apache.harmony.security.x509.NameConstraints; import org.apache.harmony.security.x509.PolicyConstraints; import org.apache.harmony.security.x509.PolicyInformation; import org.apache.harmony.security.x509.ReasonFlags; import org.apache.harmony.security.x509.SubjectKeyIdentifier; import org.apache.harmony.security.x509.SubjectPublicKeyInfo; import org.apache.harmony.security.x509.TBSCertificate; import org.apache.harmony.security.x509.Validity; /** * X509CertImplTest */ public class X509CertImplTest extends TestCase { // // The values of certificate's fields: // int version = 2; //v3 BigInteger serialNumber = BigInteger.valueOf(555L); // Algorithm name and its OID (http://oid.elibel.tm.fr) String algOID = "1.2.840.10040.4.3"; 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: byte[] algParams = {1, 1, 0}; String issuerName = "O=Certificate Issuer"; long notBefore = 1000000000L; long notAfter = 2000000000L; String subjectName = "O=Subject Organization"; // keys are using to make signature and to verify it static PublicKey publicKey; static PrivateKey privateKey; byte[] key = new byte[] {1, 2, 3, 4, 5, 6, 7, 8}; // random value byte[] keyEncoding = null; boolean[] issuerUniqueID = new boolean[] {true, false, true, false, true, false, true, false}; // random value boolean[] subjectUniqueID = new boolean[] {false, true, false, true, false, true, false, true}; // random value // Extensions' values byte[] extValEncoding = new byte[] {1, 1, 1}; // random value boolean[] extnKeyUsage = new boolean[] {true, false, true, false, true, false, true, false, true}; // random value List extnExtendedKeyUsage = Arrays.asList(new int[][] { // Extended key usage values as specified in rfc 3280 // (http://www.ietf.org/rfc/rfc3280.txt): ObjectIdentifier.toIntArray("2.5.29.37.0"), // Any extended key usage ObjectIdentifier.toIntArray("1.3.6.1.5.5.7.3.1"), // TLS Web server authentication ObjectIdentifier.toIntArray("1.3.6.1.5.5.7.3.1"), // TLS Web server authentication ObjectIdentifier.toIntArray("1.3.6.1.5.5.7.3.2"), // TLS Web client authentication ObjectIdentifier.toIntArray("1.3.6.1.5.5.7.3.3"), // Code Signing ObjectIdentifier.toIntArray("1.3.6.1.5.5.7.3.4"), // E-mail protection ObjectIdentifier.toIntArray("1.3.6.1.5.5.7.3.5"), // IP security end system ObjectIdentifier.toIntArray("1.3.6.1.5.5.7.3.6"), // IP security tunnel termination ObjectIdentifier.toIntArray("1.3.6.1.5.5.7.3.7"), // IP security user ObjectIdentifier.toIntArray("1.3.6.1.5.5.7.3.8"), // Timestamping ObjectIdentifier.toIntArray("1.3.6.1.5.5.7.3.9"), // OCSP signing ObjectIdentifier.toIntArray("1.3.6.1.5.5.8.2.2"), // iKEIntermediate ObjectIdentifier.toIntArray("1.3.6.1.4.1.311.10.3.3"), // MS Server Gated Cryptography ObjectIdentifier.toIntArray("2.16.840.1.113730.4.1"), // Netscape Server Gated Cryptography }); static NameConstraints nameConstraints; int extnBCLen = 5; static GeneralNames extnSANames; static GeneralNames extnIANames; static { try { extnSANames = 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") })); GeneralSubtrees permittedNames = new GeneralSubtrees() .addSubtree(new GeneralSubtree( new GeneralName(1, "rfc@822.Name"), 1, 2)) .addSubtree(new GeneralSubtree( new GeneralName(2, "dNSName"))) .addSubtree(new GeneralSubtree( new GeneralName(8, "1.2.3.4444.55555"), 2)); GeneralSubtrees excludedNames = new GeneralSubtrees() .addSubtree(new GeneralSubtree( new GeneralName(1, "rfc@822.BadName"), 1, 2)) .addSubtree(new GeneralSubtree( new GeneralName(2, "BadDNSName"))) .addSubtree(new GeneralSubtree( new GeneralName(8, "2.3.4.4444.222"), 2)); nameConstraints = new NameConstraints(permittedNames, excludedNames); } catch (IOException e) { // should not be thrown e.printStackTrace(); extnSANames = new GeneralNames(); nameConstraints = new NameConstraints(); } extnIANames = extnSANames; try { KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA"); keyGen.initialize(1024); KeyPair keyPair = keyGen.genKeyPair(); publicKey = keyPair.getPublic(); privateKey = keyPair.getPrivate(); } catch (Exception e) { e.printStackTrace(); } } // Extensions Extension[] extensions = new Extension[] { // Supported critical extensions (as specified in rfc 3280 // http://www.ietf.org/rfc/rfc3280.txt): // Key Usage new Extension("2.5.29.15", true, new KeyUsage(extnKeyUsage)), // Basic Constraints new Extension("2.5.29.19", true, new BasicConstraints(true, extnBCLen)), // Certificate Policies with ANY policy new Extension("2.5.29.32", true, new CertificatePolicies() .addPolicyInformation(new PolicyInformation("2.5.29.32.0"))), // Subject Alternative Name new Extension("2.5.29.17", true, new AlternativeName(AlternativeName.SUBJECT, extnSANames)), // Name Constraints new Extension("2.5.29.30", true, nameConstraints), // Policy Constraints new Extension("2.5.29.36", true, new PolicyConstraints(1, 2)), // Extended Key Usage new Extension("2.5.29.37", true, new ExtendedKeyUsage(extnExtendedKeyUsage)), // Inhibit Any-Policy new Extension("2.5.29.54", true, new InhibitAnyPolicy(1)), // Unsupported critical extensions: new Extension("1.2.77.777", true, extValEncoding), // Non-critical extensions (as specified in rfc 3280 // http://www.ietf.org/rfc/rfc3280.txt): // Issuer Alternative Name new Extension("2.5.29.18", false, new AlternativeName(AlternativeName.ISSUER, extnSANames)), // CRL Distribution Points new Extension("2.5.29.31", false, new CRLDistributionPoints(Arrays.asList(new DistributionPoint[] { new DistributionPoint( new DistributionPointName(extnSANames), new ReasonFlags(extnKeyUsage), extnSANames ), }))), // Authority Key Identifier new Extension("2.5.29.35", false, new AuthorityKeyIdentifier( // random value for key identifier new byte[] {1, 2, 3, 4, 5}, extnSANames, serialNumber)), // Subject Key Identifier new Extension("2.5.29.14", false, // random value for key identifier new SubjectKeyIdentifier(new byte[] {1, 2, 3, 4, 5})), // Policy Mappings new Extension("2.5.29.33", false, extValEncoding), }; List allCritical = Arrays.asList(new String[] {"2.5.29.15", "2.5.29.19", "2.5.29.32", "2.5.29.17", "2.5.29.30", "2.5.29.36", "2.5.29.37", "2.5.29.54", "1.2.77.777"}); List allNonCritical = Arrays.asList(new String[] {"2.5.29.18", "2.5.29.35", "2.5.29.14", "2.5.29.33", "2.5.29.31"}); public X509Certificate certificate; byte[] tbsCertEncoding; byte[] signatureValue; // to minimize efforts on signature generation the signature will be // stored in this field static byte[] signatureValueBytes; byte[] certEncoding; /** * Creates the master certificate on the base of which * all functionality will be tested. * @return * @throws java.lang.Exception */ protected void setUp() throws java.lang.Exception { AlgorithmIdentifier signature = new AlgorithmIdentifier(algOID, algParams); Name issuer = new Name(issuerName); Name subject = new Name(subjectName); Validity validity = new Validity(new Date(notBefore), new Date(notAfter)); SubjectPublicKeyInfo subjectPublicKeyInfo = (SubjectPublicKeyInfo) SubjectPublicKeyInfo.ASN1.decode(publicKey.getEncoded()); keyEncoding = subjectPublicKeyInfo.getEncoded(); Extensions exts = new Extensions(Arrays.asList(extensions)); TBSCertificate tbsCertificate = new TBSCertificate(version, serialNumber, signature, issuer, validity, subject, subjectPublicKeyInfo, issuerUniqueID, subjectUniqueID, exts); tbsCertEncoding = tbsCertificate.getEncoded(); if (signatureValueBytes == null) { try { Signature sig= Signature.getInstance("DSA");//new byte[32]; sig.initSign(privateKey); sig.update(tbsCertEncoding, 0, tbsCertEncoding.length); signatureValueBytes = sig.sign(); } catch (Exception e) { e.printStackTrace(); signatureValueBytes = new byte[10]; } } 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; } Certificate cert = new Certificate(tbsCertificate, signature, signatureValue); certEncoding = cert.getEncoded(); cert = (Certificate) Certificate.ASN1.decode(certEncoding); certificate = new X509CertImpl(cert); } public void testCreation() throws Exception { ByteArrayInputStream bis = new ByteArrayInputStream(certEncoding); certificate = new X509CertImpl(bis); } /** * checkValidity() method testing. */ public void testCheckValidity1() { try { certificate.checkValidity(); fail("CertificateExpiredException should be thrown."); } catch (CertificateNotYetValidException e) { fail("Unexpected CertificateNotYetValidException was thrown."); } catch (CertificateExpiredException e) { } } /** * checkValidity(Date date) method testing. */ public void testCheckValidity2() { try { certificate.checkValidity(new Date(3000000000L)); fail("CertificateExpiredException should be thrown."); } catch (CertificateNotYetValidException e) { fail("Unexpected CertificateNotYetValidException was thrown."); } catch (CertificateExpiredException e) { } try { certificate.checkValidity(new Date(100000000L)); fail("CertificateNotYetValidException be thrown."); } catch (CertificateExpiredException e) { fail("Unexpected CertificateExpiredException was thrown."); } catch (CertificateNotYetValidException e) { } try { certificate.checkValidity(new Date(1000000000L)); certificate.checkValidity(new Date(1500000000L)); certificate.checkValidity(new Date(2000000000L)); } catch (CertificateExpiredException e) { fail("Unexpected CertificateExpiredException was thrown."); } catch (CertificateNotYetValidException e) { fail("Unexpected CertificateNotYetValidException was thrown."); } } /** * @tests java.security.cert.X509Certificate#getVersion() */ public void testGetVersion() throws IOException { byte[] x509CertEnc = TestUtils.getX509Certificate_v1(); // test initial version that is 1 assertEquals("Version 1:", 1, new X509CertImpl(x509CertEnc) .getVersion()); // as fas as we know offset of version byte in the cert. encoding // it is possible to change it to test other versions // offset of version byte in certificate encoding int offset = 8; // set version to 2 x509CertEnc[offset] = 1; assertEquals("Version 2:", 2, new X509CertImpl(x509CertEnc) .getVersion()); // set version to 3 x509CertEnc[offset] = 2; assertEquals("Version 3:", 3, new X509CertImpl(x509CertEnc) .getVersion()); } /** * getSerialNumber() method testing. */ public void testGetSerialNumber() { assertEquals("Incorrect value of version", serialNumber, certificate.getSerialNumber()); } /** * getIssuerDN() method testing. */ public void testGetIssuerDN() { assertEquals("Incorrect issuer", new X500Principal(issuerName).getName(), certificate.getIssuerDN().getName()); } /** * getIssuerX500Principal() method testing. */ public void testGetIssuerX500Principal() { assertEquals("Incorrect issuer", new X500Principal(issuerName), certificate.getIssuerX500Principal()); } /** * getSubjectDN() method testing. */ public void testGetSubjectDN() { assertEquals("Incorrect subject", new X500Principal(subjectName).getName(), certificate.getSubjectDN().getName()); } /** * getSubjectX500Principal() method testing. */ public void testGetSubjectX500Principal() { assertEquals("Incorrect subject", new X500Principal(subjectName), certificate.getSubjectX500Principal()); } /** * getNotBefore() method testing. */ public void testGetNotBefore() { assertEquals("Incorrect notBefore date", new Date(notBefore), certificate.getNotBefore()); } /** * getNotAfter() method testing. */ public void testGetNotAfter() { assertEquals("Incorrect notAfter date", new Date(notAfter), certificate.getNotAfter()); } public static void printAsHex(int perLine, String prefix, String delimiter, byte[] data) { for (int i=0; i