org.cesecore.certificates.certificate.certextensions.BasicCertificateExtensionTest.java Source code

Java tutorial

Introduction

Here is the source code for org.cesecore.certificates.certificate.certextensions.BasicCertificateExtensionTest.java

Source

/*************************************************************************
 *                                                                       *
 *  CESeCore: CE Security Core                                           *
 *                                                                       *
 *  This software is free software; you can redistribute it and/or       *
 *  modify it under the terms of the GNU Lesser General Public           *
 *  License as published by the Free Software Foundation; either         *
 *  version 2.1 of the License, or any later version.                    *
 *                                                                       *
 *  See terms of license at gnu.org.                                     *
 *                                                                       *
 *************************************************************************/
package org.cesecore.certificates.certificate.certextensions;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Enumeration;
import java.util.Properties;

import org.apache.log4j.Logger;
import org.bouncycastle.asn1.ASN1Boolean;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERPrintableString;
import org.bouncycastle.asn1.DERSet;
import org.bouncycastle.asn1.DERUTF8String;
import org.bouncycastle.asn1.DLSequence;
import org.bouncycastle.asn1.DLSet;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.Extensions;
import org.bouncycastle.asn1.x509.ExtensionsGenerator;
import org.bouncycastle.util.encoders.Hex;
import org.cesecore.certificates.endentity.EndEntityInformation;
import org.cesecore.certificates.endentity.ExtendedInformation;
import org.cesecore.internal.InternalResources;
import org.junit.Test;

/**
 * @version $Id: BasicCertificateExtensionTest.java 20728 2015-02-20 14:55:55Z mikekushner $
 */
public class BasicCertificateExtensionTest {
    private static Logger log = Logger.getLogger(BasicCertificateExtensionTest.class);

    private static final InternalResources intres = InternalResources.getInstance();

    @Test
    public void test01NullBasicExtension() throws Exception {
        Properties props = new Properties();
        props.put("id1.property.encoding", "DERNULL");

        BasicCertificateExtension baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);

        ASN1Encodable value = getObject(baseExt.getValueEncoded(null, null, null, null, null, null));
        assertTrue(value.getClass().toString(), value instanceof DERNull);
        assertTrue(baseExt.getOID().equals("1.2.3"));
        assertTrue(baseExt.getId() == 1);
        assertFalse(baseExt.isCriticalFlag());
    }

    @Test
    public void test02IntegerBasicExtension() throws Exception {
        Properties props = new Properties();
        props.put("id1.property.encoding", "DERINTEGER");
        props.put("id1.property.value", "1234");

        BasicCertificateExtension baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);

        ASN1Encodable value = getObject(baseExt.getValueEncoded(null, null, null, null, null, null));
        assertTrue(value.getClass().toString(), value instanceof ASN1Integer);
        assertTrue(((ASN1Integer) value).toString(), ((ASN1Integer) value).toString().equals("1234"));
        assertTrue(baseExt.getOID().equals("1.2.3"));
        assertTrue(baseExt.getId() == 1);
        assertFalse(baseExt.isCriticalFlag());

        props = new Properties();
        props.put("id1.property.encoding", "DERINTEGER");
        props.put("id1.property.value", "123SA4");
        boolean exceptionThrown = false;
        try {
            baseExt = new BasicCertificateExtension();
            baseExt.init(1, "1.2.3", false, props);
            value = getObject(baseExt.getValueEncoded(null, null, null, null, null, null));
        } catch (CertificateExtensionException e) {
            exceptionThrown = true;
            assertEquals(intres.getLocalizedMessage("certext.basic.illegalvalue", "123SA4", 1, "1.2.3"),
                    e.getMessage());
        }
        assertTrue(exceptionThrown);

    }

    @Test
    public void test03BitStringBasicExtension() throws Exception {
        Properties props = new Properties();
        props.put("id1.property.encoding", "DERBITSTRING");
        props.put("id1.property.value", "1111"); // this is 15 decimal
        BasicCertificateExtension baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);
        byte[] result = { 15 };
        ASN1Encodable value = getObject(baseExt.getValueEncoded(null, null, null, null, null, null));
        assertTrue(value.getClass().toString(), value instanceof DERBitString);
        assertEquals(((DERBitString) value).getBytes()[0], result[0]);
        assertEquals(((DERBitString) value).getPadBits(), 0);
        assertTrue(baseExt.getOID().equals("1.2.3"));
        assertTrue(baseExt.getId() == 1);
        assertFalse(baseExt.isCriticalFlag());

        props = new Properties();
        props.put("id1.property.encoding", "DERBITSTRING");
        // SSL Client and S/MIME in NetscapeCertType
        // This will be -96 in decimal, don't ask me why, but it is!
        props.put("id1.property.value", "10100000");

        baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);
        value = getObject(baseExt.getValueEncoded(null, null, null, null, null, null));
        assertTrue(value.getClass().toString(), value instanceof DERBitString);
        new BigInteger(((DERBitString) value).getBytes()); // Will throw if value is wrong
        //log.debug(bi.toString(2));
        //log.debug(bi.toString());
        //log.debug(((DERBitString)value).getBytes()[0]);
        assertEquals(((DERBitString) value).getBytes()[0], -96);
        assertEquals(((DERBitString) value).getPadBits(), 5);
        assertTrue(baseExt.getOID().equals("1.2.3"));
        assertTrue(baseExt.getId() == 1);
        assertFalse(baseExt.isCriticalFlag());

        // Test error
        props = new Properties();
        props.put("id1.property.encoding", "DERBITSTRING");
        props.put("id1.property.value", "qqqq");
        baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);
        try {
            value = getObject(baseExt.getValueEncoded(null, null, null, null, null, null));
            assertTrue("Should throw", false);
        } catch (CertificateExtensionException e) {
            assertEquals(intres.getLocalizedMessage("certext.basic.illegalvalue", "qqqq", 1, "1.2.3"),
                    e.getMessage());
        }

    }

    @Test
    public void test04BooleanBasicExtension() throws Exception {
        Properties props = new Properties();
        props.put("id1.property.encoding", "DERBOOLEAN");
        props.put("id1.property.value", "true");

        BasicCertificateExtension baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);

        ASN1Encodable value = getObject(baseExt.getValueEncoded(null, null, null, null, null, null));
        assertTrue(value.getClass().toString(), value instanceof ASN1Boolean);
        assertTrue(((ASN1Boolean) value).toString(), ((ASN1Boolean) value).toString().equals("TRUE"));
        assertTrue(baseExt.getOID().equals("1.2.3"));
        assertTrue(baseExt.getId() == 1);
        assertFalse(baseExt.isCriticalFlag());

        props.put("id1.property.value", "false");

        baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);

        value = getObject(baseExt.getValueEncoded(null, null, null, null, null, null));
        assertTrue(((ASN1Boolean) value).toString(), ((ASN1Boolean) value).toString().equals("FALSE"));

        props = new Properties();
        props.put("id1.property.encoding", "DERBOOLEAN");
        props.put("id1.property.value", "1sdf");
        boolean exceptionThrown = false;
        try {
            baseExt = new BasicCertificateExtension();
            baseExt.init(1, "1.2.3", false, props);
            value = getObject(baseExt.getValueEncoded(null, null, null, null, null, null));
        } catch (CertificateExtensionException e) {
            exceptionThrown = true;
            assertEquals(intres.getLocalizedMessage("certext.basic.illegalvalue", "1sdf", 1, "1.2.3"),
                    e.getMessage());
        }
        assertTrue(exceptionThrown);
    }

    @Test
    public void test05OctetBasicExtension() throws Exception {
        Properties props = new Properties();
        props.put("id1.property.encoding", "DEROCTETSTRING");
        props.put("id1.property.value", "DBE81232");

        BasicCertificateExtension baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);

        ASN1Encodable value = getObject(baseExt.getValueEncoded(null, null, null, null, null, null));
        assertTrue(value.getClass().toString(), value instanceof DEROctetString);
        assertTrue(((DEROctetString) value).toString(),
                ((DEROctetString) value).toString().equalsIgnoreCase("#DBE81232"));

        props = new Properties();
        props.put("id1.property.encoding", "DEROCTETSTRING");
        props.put("id1.property.value", "123SA4");
        boolean exceptionThrown = false;
        try {
            baseExt = new BasicCertificateExtension();
            baseExt.init(1, "1.2.3", false, props);
            value = getObject(baseExt.getValueEncoded(null, null, null, null, null, null));
        } catch (CertificateExtensionException e) {
            exceptionThrown = true;
            assertEquals(intres.getLocalizedMessage("certext.basic.illegalvalue", "123SA4", 1, "1.2.3"),
                    e.getMessage());
        }
        assertTrue(exceptionThrown);

    }

    @Test
    public void test06PritableStringExtension() throws Exception {
        Properties props = new Properties();
        props.put("id1.property.encoding", "DERPRINTABLESTRING");
        props.put("id1.property.value", "This is a printable string");

        BasicCertificateExtension baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);

        ASN1Encodable value = getObject(baseExt.getValueEncoded(null, null, null, null, null, null));
        assertTrue(value.getClass().toString(), value instanceof DERPrintableString);
        assertTrue(((DERPrintableString) value).toString(),
                ((DERPrintableString) value).toString().equals("This is a printable string"));

        props = new Properties();
        props.put("id1.property.encoding", "DERPRINTABLESTRING");
        props.put("id1.property.value", "This is a non  printable string ");
        boolean exceptionThrown = false;
        try {
            baseExt = new BasicCertificateExtension();
            baseExt.init(1, "1.2.3", false, props);
            value = getObject(baseExt.getValueEncoded(null, null, null, null, null, null));
        } catch (CertificateExtensionException e) {
            exceptionThrown = true;
            assertEquals(intres.getLocalizedMessage("certext.basic.illegalvalue",
                    "This is a non  printable string ", 1, "1.2.3"), e.getMessage());
            // Verify with unicode encoded as well to ensure file encodings were not just messed up
            assertEquals(
                    intres.getLocalizedMessage("certext.basic.illegalvalue",
                            "This is a non  printable string \u00E5\u00E4\u00F6\u00FC\u00E8", 1, "1.2.3"),
                    e.getMessage());
        }
        assertTrue(exceptionThrown);
    }

    @Test
    public void test07UTF8StringExtension() throws Exception {
        Properties props = new Properties();
        props.put("id1.property.encoding", "DERUTF8STRING");
        props.put("id1.property.value", "This is a utf8  string");

        BasicCertificateExtension baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);

        ASN1Encodable value = getObject(baseExt.getValueEncoded(null, null, null, null, null, null));
        assertTrue(value.getClass().toString(), value instanceof DERUTF8String);
        assertTrue(((DERUTF8String) value).getString(),
                ((DERUTF8String) value).getString().equals("This is a utf8  string"));

    }

    @Test
    public void test08WrongEncoding() throws Exception {
        Properties props = new Properties();
        props.put("id1.property.encoding", "DERUTF8sdfTRING");
        props.put("id1.property.value", "This is a utf8  string");

        BasicCertificateExtension baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);
        try {
            baseExt.getValueEncoded(null, null, null, null, null, null);
            assertTrue("Should throw", false);
        } catch (CertificateExtensionException e) {
            assertEquals(intres.getLocalizedMessage("certext.basic.incorrectenc", "DERUTF8sdfTRING", 1),
                    e.getMessage());
        }

        Properties props1 = new Properties();
        props1.put("id1.property.encoding", "DERUTF8STRING");
        props1.put("id1.property.value", "");

        BasicCertificateExtension baseExt1 = new BasicCertificateExtension();
        baseExt1.init(1, "1.2.3", false, props1);
        try {
            baseExt1.getValueEncoded(null, null, null, null, null, null);
            assertTrue("Should throw", false);
        } catch (CertificateExtensionException e) {
            // NOPMD
        }
    }

    @Test
    public void test09OidExtension() throws Exception {
        Properties props = new Properties();
        props.put("id1.property.encoding", "DERBOJECTIDENTIFIER");
        props.put("id1.property.value", "1.1.1.255.1");

        BasicCertificateExtension baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);

        ASN1Encodable value = getObject(baseExt.getValueEncoded(null, null, null, null, null, null));
        assertTrue(value.getClass().toString(), value instanceof ASN1ObjectIdentifier);
        assertTrue(((ASN1ObjectIdentifier) value).getId(),
                ((ASN1ObjectIdentifier) value).getId().equals("1.1.1.255.1"));

        props = new Properties();
        props.put("id1.property.encoding", "DERBOJECTIDENTIFIER");
        props.put("id1.property.value", "3.1.1.255.1"); // Illegal oid, must be 0-2 in first char

        baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);
        try {
            baseExt.getValueEncoded(null, null, null, null, null, null);
            assertTrue("Should throw", false);
        } catch (CertificateExtensionException e) {
            // NOPMD
        }
    }

    @Test
    public void test10SequencedExtension() throws Exception {
        Properties props = new Properties();
        props.put("id1.property.encoding", "DERUTF8STRING "); // Also test that we ignore spaces in the end here
        props.put("id1.property.nvalues", "3");
        props.put("id1.property.value1", "foo1");
        props.put("id1.property.value2", "foo2");
        props.put("id1.property.value3", "foo3");

        BasicCertificateExtension baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);

        ASN1Encodable value = getObject(baseExt.getValueEncoded(null, null, null, null, null, null));
        assertTrue(value.getClass().toString(), value instanceof DLSequence);
        DLSequence seq = (DLSequence) value;
        assertEquals(3, seq.size());
        @SuppressWarnings("unchecked")
        Enumeration<ASN1Encodable> e = seq.getObjects();
        int i = 1;
        while (e.hasMoreElements()) {
            ASN1Encodable v = e.nextElement();
            assertTrue(v.getClass().toString(), v instanceof DERUTF8String);
            String str = ((DERUTF8String) v).getString();
            log.info(str);
            assertEquals(str, "foo" + i++);
        }
    }

    @Test
    public void test11IA5StringExtension() throws Exception {
        Properties props = new Properties();
        props.put("id1.property.encoding", "DERIA5STRING");
        props.put("id1.property.value", "This is a printable string");

        BasicCertificateExtension baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);

        ASN1Encodable value = getObject(baseExt.getValueEncoded(null, null, null, null, null, null));
        assertTrue(value.getClass().toString(), value instanceof DERIA5String);
        assertEquals("This is a printable string", ((DERIA5String) value).toString());

        props = new Properties();
        props.put("id1.property.encoding", "DERIA5STRING");
        props.put("id1.property.value", "This is a non printable string ");
        boolean exceptionThrown = false;
        try {
            baseExt = new BasicCertificateExtension();
            baseExt.init(1, "1.2.3", false, props);
            value = getObject(baseExt.getValueEncoded(null, null, null, null, null, null));
        } catch (CertificateExtensionException e) {
            exceptionThrown = true;
        }
        assertTrue(exceptionThrown);
    }

    @Test
    public void test12DERObjectExtension() throws Exception {
        Properties props = new Properties();
        props.put("id1.property.encoding", "DEROBJECT");
        ASN1EncodableVector vec = new ASN1EncodableVector();
        vec.add(new DERPrintableString("foo1"));
        vec.add(new DERPrintableString("foo2"));
        vec.add(new DERPrintableString("foo3"));
        DERSet set = new DERSet(vec);
        String str = new String(Hex.encode(set.getEncoded()));
        props.put("id1.property.value", str);

        BasicCertificateExtension baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);

        ASN1Encodable value = getObject(baseExt.getValueEncoded(null, null, null, null, null, null));
        assertTrue(value.getClass().toString(), value instanceof DLSet);
        DLSet set1 = (DLSet) value;
        assertEquals(3, set1.size());

        props = new Properties();
        props.put("id1.property.encoding", "DEROBJECT");
        props.put("id1.property.value", "This is not an asn1 hex encoded object");
        baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);
        try {
            value = getObject(baseExt.getValueEncoded(null, null, null, null, null, null));
            assertTrue("Should throw", false);
        } catch (CertificateExtensionException e) {
            // NOPMD
        }
    }

    /**
    * Test with dynamic=true and no static value specified.
    *
    * There should be an exception if no value was specified in ExtendedInformation.
    * But it should succeed if an value was specified in ExtendedInformation.
    */
    @Test
    public void test13DynamicTrueNoStatic() throws Exception {
        Properties props = new Properties();
        props.put("id1.property.encoding", "DERPRINTABLESTRING");
        props.put("id1.property.dynamic", "true");
        BasicCertificateExtension baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);
        EndEntityInformation userData = new EndEntityInformation();
        userData.setExtendedinformation(new ExtendedInformation());

        // Fail without value specified
        try {
            baseExt.getValueEncoded(userData, null, null, null, null, null);
            fail("Should have failed as no value was specified in EI.");
        } catch (CertificateExtensionException ex) {
            assertEquals(intres.getLocalizedMessage("certext.basic.incorrectvalue", 1, "1.2.3"), ex.getMessage());
        }

        // Success with value specified
        userData.getExtendedinformation().setExtensionData("1.2.3", "The value 123");
        ASN1InputStream in = new ASN1InputStream(
                new ByteArrayInputStream(baseExt.getValueEncoded(userData, null, null, null, null, null)));
        try {
            ASN1Encodable value1 = in.readObject();
            assertTrue(value1.getClass().toString(), value1 instanceof DERPrintableString);
            assertEquals("The value 123", ((DERPrintableString) value1).getString());
        } finally {
            in.close();
        }

    }

    /**
     * Test with dynamic=true and and a static value specified.
     *
     * The static value should be used if no value was specified in ExtendedInformation.
     * The value from ExtendedInformation should be used if present.
     */
    @Test
    public void test14DynamicTrueStatic() throws Exception {
        Properties props = new Properties();
        props.put("id1.property.encoding", "DERPRINTABLESTRING");
        props.put("id1.property.dynamic", "true");
        props.put("id1.property.value", "The static value 123");
        BasicCertificateExtension baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);
        EndEntityInformation userData = new EndEntityInformation();
        userData.setExtendedinformation(new ExtendedInformation());

        // Without value in userdata, the static value is used
        ASN1InputStream in = new ASN1InputStream(
                new ByteArrayInputStream(baseExt.getValueEncoded(userData, null, null, null, null, null)));
        ASN1Encodable value1 = in.readObject();
        assertTrue(value1.getClass().toString(), value1 instanceof DERPrintableString);
        assertEquals("The static value 123", ((DERPrintableString) value1).getString());

        // With value in userdata, that value is used
        userData.getExtendedinformation().setExtensionData("1.2.3", "A dynamic value 123");
        in = new ASN1InputStream(
                new ByteArrayInputStream(baseExt.getValueEncoded(userData, null, null, null, null, null)));
        value1 = in.readObject();
        assertTrue(value1.getClass().toString(), value1 instanceof DERPrintableString);
        assertEquals("A dynamic value 123", ((DERPrintableString) value1).getString());
    }

    /**
     * Test with dynamic=true and and a static value specified where nvalues are used.
     *
     * The static values should be used if no value was specified in ExtendedInformation.
     * The values from ExtendedInformation should be used if present.
     */
    @SuppressWarnings("unchecked")
    @Test
    public void test15DynamicTrueStaticNvalues() throws Exception {
        Properties props = new Properties();
        props.put("id1.property.encoding", "DERPRINTABLESTRING");
        props.put("id1.property.dynamic", "true");
        props.put("id1.property.nvalues", "3");
        props.put("id1.property.value1", "The static value 1");
        props.put("id1.property.value2", "The static value 2");
        props.put("id1.property.value3", "The static value 3");
        BasicCertificateExtension baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);
        EndEntityInformation userData = new EndEntityInformation();
        userData.setExtendedinformation(new ExtendedInformation());

        // Without value in userdata, the static values is used
        ASN1InputStream in = new ASN1InputStream(
                new ByteArrayInputStream(baseExt.getValueEncoded(userData, null, null, null, null, null)));
        ASN1Encodable value = in.readObject();
        assertTrue(value.getClass().toString(), value instanceof DLSequence);
        DLSequence seq = (DLSequence) value;
        assertEquals(3, seq.size());
        Enumeration<ASN1Encodable> e = seq.getObjects();
        int i = 1;
        while (e.hasMoreElements()) {
            ASN1Encodable v = e.nextElement();
            assertTrue(v.getClass().toString(), v instanceof DERPrintableString);
            String str = ((DERPrintableString) v).getString();
            assertEquals(str, "The static value " + i++);
        }

        // With values in userdata, that values is used
        userData.getExtendedinformation().setExtensionData("1.2.3.value1", "A dynamic value 1");
        userData.getExtendedinformation().setExtensionData("1.2.3.value2", "A dynamic value 2");
        userData.getExtendedinformation().setExtensionData("1.2.3.value3", "A dynamic value 3");
        in = new ASN1InputStream(
                new ByteArrayInputStream(baseExt.getValueEncoded(userData, null, null, null, null, null)));
        value = in.readObject();
        assertTrue(value.getClass().toString(), value instanceof DLSequence);
        seq = (DLSequence) value;
        assertEquals(3, seq.size());
        e = seq.getObjects();
        i = 1;
        while (e.hasMoreElements()) {
            ASN1Encodable v = (ASN1Encodable) e.nextElement();
            assertTrue(v.getClass().toString(), v instanceof DERPrintableString);
            String str = ((DERPrintableString) v).getString();
            assertEquals(str, "A dynamic value " + i++);
        }
    }

    /**
     * Test that without dynamic specified it defaults to dynamic=false.
     *
     * The static value should be used regardless of there was a value in 
     * ExtendedInformation or not.
     */
    @Test
    public void test16DynamicDefaultsToFalse() throws Exception {
        Properties props = new Properties();
        props.put("id1.property.encoding", "DERPRINTABLESTRING");
        props.put("id1.property.value", "The static value");
        BasicCertificateExtension baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);
        EndEntityInformation userData = new EndEntityInformation();
        userData.setExtendedinformation(new ExtendedInformation());

        // Ok without value specified
        ASN1InputStream in = new ASN1InputStream(
                new ByteArrayInputStream(baseExt.getValueEncoded(userData, null, null, null, null, null)));
        ASN1Encodable value1 = in.readObject();
        assertTrue(value1.getClass().toString(), value1 instanceof DERPrintableString);
        assertEquals("The static value", ((DERPrintableString) value1).getString());

        // Ignoring dynamic value specified
        userData.getExtendedinformation().setExtensionData("1.2.3", "The value 123");
        in = new ASN1InputStream(
                new ByteArrayInputStream(baseExt.getValueEncoded(userData, null, null, null, null, null)));
        value1 = in.readObject();
        assertTrue(value1.getClass().toString(), value1 instanceof DERPrintableString);
        assertEquals("The static value", ((DERPrintableString) value1).getString());
    }

    /**
     * Same as test16DynamicDefaultsToFalse but with dynamic explicitly set to
     *  false.
     */
    @Test
    public void test17DynamicFalse() throws Exception {
        Properties props = new Properties();
        props.put("id1.property.encoding", "DERPRINTABLESTRING");
        props.put("id1.property.value", "The static value");
        props.put("id1.property.dynamic", "false");
        BasicCertificateExtension baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);
        EndEntityInformation userData = new EndEntityInformation();
        userData.setExtendedinformation(new ExtendedInformation());

        // Ok without value specified
        ASN1InputStream in = new ASN1InputStream(
                new ByteArrayInputStream(baseExt.getValueEncoded(userData, null, null, null, null, null)));
        ASN1Encodable value = in.readObject();
        assertTrue(value.getClass().toString(), value instanceof DERPrintableString);
        assertEquals("The static value", ((DERPrintableString) value).getString());

        // Ignoring dynamic value specified
        userData.getExtendedinformation().setExtensionData("1.2.3", "The value 123");
        in = new ASN1InputStream(
                new ByteArrayInputStream(baseExt.getValueEncoded(userData, null, null, null, null, null)));
        value = in.readObject();
        assertTrue(value.getClass().toString(), value instanceof DERPrintableString);
        assertEquals("The static value", ((DERPrintableString) value).getString());
    }

    /**
     * Test with dynamic=true and value specified with key 1.2.3.value=.
     */
    @Test
    public void test18DynamicValueValue() throws Exception {
        Properties props = new Properties();
        props.put("id1.property.encoding", "DERPRINTABLESTRING");
        props.put("id1.property.dynamic", "true");
        BasicCertificateExtension baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);
        EndEntityInformation userData = new EndEntityInformation();
        userData.setExtendedinformation(new ExtendedInformation());

        // Success with value specified
        userData.getExtendedinformation().setExtensionData("1.2.3.value", "The value 456");
        ASN1InputStream in = new ASN1InputStream(
                new ByteArrayInputStream(baseExt.getValueEncoded(userData, null, null, null, null, null)));
        try {
            ASN1Encodable value1 = in.readObject();
            assertTrue(value1.getClass().toString(), value1 instanceof DERPrintableString);
            assertEquals("The value 456", ((DERPrintableString) value1).getString());
        } finally {
            in.close();
        }
    }

    /**
     * Test using encoding=RAW and both dynamic and static value.
     */
    @Test
    public void test19RawValue() throws Exception {
        Properties props = new Properties();
        props.put("id1.property.encoding", "RAW");
        props.put("id1.property.dynamic", "true");
        props.put("id1.property.value", "aabbccdd");
        BasicCertificateExtension baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);
        EndEntityInformation userData = new EndEntityInformation();
        userData.setExtendedinformation(new ExtendedInformation());

        // Without value in userdata, the static value is used
        byte[] value = baseExt.getValueEncoded(userData, null, null, null, null, null);
        assertEquals("value", "aabbccdd", new String(Hex.encode(value)));

        // With value in userdata, that value is used
        userData.getExtendedinformation().setExtensionData("1.2.3", "eeff0000");
        value = baseExt.getValueEncoded(userData, null, null, null, null, null);
        assertEquals("value", "eeff0000", new String(Hex.encode(value)));
    }

    @Test
    public void test20CertExtensionEncoding() throws Exception {
        Properties props = new Properties();
        props.put("id1.property.encoding", "DERIA5STRING");
        props.put("id1.property.value", "This is a printable string");

        BasicCertificateExtension baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);

        byte[] value = baseExt.getValueEncoded(null, null, null, null, null, null);

        ExtensionsGenerator extgen = new ExtensionsGenerator();
        extgen.addExtension(new ASN1ObjectIdentifier(baseExt.getOID()), baseExt.isCriticalFlag(), value);
        Extensions exts = extgen.generate();
        ASN1ObjectIdentifier oid = new ASN1ObjectIdentifier(baseExt.getOID());
        Extension ext = exts.getExtension(oid);
        assertNotNull(ext);
        // Read the extension value, it's a DERIA5String wrapped in an ASN1OctetString
        ASN1OctetString str = ext.getExtnValue();
        ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(str.getOctets()));
        DERIA5String ia5str = (DERIA5String) aIn.readObject();
        aIn.close();
        assertEquals("This is a printable string", ia5str.getString());
    }

    private ASN1Encodable getObject(byte[] valueEncoded) throws IOException {
        ASN1InputStream in = new ASN1InputStream(new ByteArrayInputStream(valueEncoded));
        try {
            return in.readObject();
        } finally {
            in.close();
        }
    }

    /**
     * Test using encoding=RAW and only dynamic value.
     */
    @Test
    public void test21RawValueNotSpecified() throws Exception {
        Properties props = new Properties();
        props.put("id1.property.encoding", "RAW");
        props.put("id1.property.dynamic", "true");
        BasicCertificateExtension baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);
        EndEntityInformation userData = new EndEntityInformation();
        userData.setExtendedinformation(new ExtendedInformation());

        // Without value in userdata it should fail
        try {
            baseExt.getValueEncoded(userData, null, null, null, null, null);
            fail("Should have fail as no dynamic value specified");
        } catch (CertificateExtensionException ex) {
            assertEquals(intres.getLocalizedMessage("certext.basic.incorrectvalue", 1, "1.2.3"), ex.getMessage());
        }

        // With value in userdata, that value is used
        userData.getExtendedinformation().setExtensionData("1.2.3", "eeff0000");
        byte[] value = baseExt.getValueEncoded(userData, null, null, null, null, null);
        assertEquals("value", "eeff0000", new String(Hex.encode(value)));
    }

    /**
     * Test without any value specified.
     */
    @Test
    public void test22ValueNotSpecified() throws Exception {
        Properties props = new Properties();
        props.put("id1.property.encoding", "DERINTEGER");

        BasicCertificateExtension baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);

        try {
            baseExt.getValueEncoded(null, null, null, null, null, null);
            fail("Should have fail as no value specified");
        } catch (CertificateExtensionException ex) {
            assertEquals(intres.getLocalizedMessage("certext.basic.incorrectvalue", 1, "1.2.3"), ex.getMessage());
        }
    }

    /**
     * Test using encoding=RAW but nvalues > 1 specified which is a
     * configuration error.
     */
    @Test
    public void test23RawValueButNValues() throws Exception {
        Properties props = new Properties();
        props.put("id1.property.encoding", "RAW");
        props.put("id1.property.dynamic", "true");
        props.put("id1.property.nvalues", "3");
        props.put("id1.property.value1", "foo1");
        props.put("id1.property.value2", "foo2");
        props.put("id1.property.value3", "foo3");

        BasicCertificateExtension baseExt = new BasicCertificateExtension();
        baseExt.init(1, "1.2.3", false, props);
        EndEntityInformation userData = new EndEntityInformation();
        userData.setExtendedinformation(new ExtendedInformation());

        try {
            baseExt.getValueEncoded(userData, null, null, null, null, null);
            fail("Should have fail as both raw and nvalues specified");
        } catch (CertificateExtensionException ex) {
            assertEquals(intres.getLocalizedMessage("certext.certextmissconfigured", 1), ex.getMessage());
        }
    }
}