test.be.fedict.eid.applet.Pkcs15Test.java Source code

Java tutorial

Introduction

Here is the source code for test.be.fedict.eid.applet.Pkcs15Test.java

Source

/*
 * eID Applet Project.
 * Copyright (C) 2008-2009 FedICT.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version
 * 3.0 as published by the Free Software Foundation.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, see 
 * http://www.gnu.org/licenses/.
 */

package test.be.fedict.eid.applet;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Locale;

import javax.smartcardio.CardChannel;
import javax.smartcardio.CommandAPDU;
import javax.smartcardio.ResponseAPDU;

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import be.fedict.eid.applet.Messages;
import be.fedict.eid.applet.sc.PcscEid;

public class Pkcs15Test {

    private static final Log LOG = LogFactory.getLog(Pkcs15Test.class);

    private PcscEid pcscEid;

    @Before
    public void setUp() throws Exception {
        this.messages = new Messages(Locale.getDefault());
        this.pcscEid = new PcscEid(new TestView(), this.messages);
        if (false == this.pcscEid.isEidPresent()) {
            LOG.debug("insert eID card");
            this.pcscEid.waitForEidPresent();
        }
    }

    private Messages messages;

    @After
    public void tearDown() throws Exception {
        this.pcscEid.close();
    }

    @Documented
    @Target({ ElementType.TYPE, ElementType.FIELD })
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Tag {
        byte value();
    }

    @Tag(0x61)
    public static class Pkcs15ApplicationTemplate {
        @Tag(0x50)
        String label;

        @Tag(0x4f)
        byte[] id;

        @Tag(0x51)
        byte[] path;

        @Tag(0x73)
        byte[] discretionaryDataObjects;
    }

    public static class Pkcs15_EF_DIR {
        Pkcs15ApplicationTemplate[] applicationTemplates;
    }

    public static <T> T parsePkcs15File(byte[] data, Class<T> type)
            throws InstantiationException, IllegalAccessException {
        T result = type.newInstance();
        int dataIdx = 0;
        Tag tagAnnotation = type.getAnnotation(Tag.class);
        if (null != tagAnnotation) {
            byte tag = tagAnnotation.value();
            if (tag != data[0]) {
                throw new RuntimeException("incorrect tag: " + Integer.toHexString(tag));
            }
            dataIdx++;
            int size = data[1];
            dataIdx++;
            LOG.debug("size: " + size);
            if (data.length - dataIdx != size) {
                throw new RuntimeException("data size incorrect: " + size + " for tag " + Integer.toHexString(tag));
            }
        }
        Field[] fields = type.getDeclaredFields();
        if (1 == fields.length) {
            Field field = fields[0];
            if (field.getType().isArray()) {
                Class<?> componentType = field.getType().getComponentType();
                Object component = parsePkcs15File(data, componentType);
                Object array = Array.newInstance(componentType, 1);
                Array.set(array, 0, component);
                field.set(result, array);
                return result;
            }
        }
        while (dataIdx < data.length) {
            byte tag = data[dataIdx];
            dataIdx++;
            int size = data[dataIdx];
            dataIdx++;
            LOG.debug("tag: " + Integer.toHexString(tag) + "; size: " + size);
            for (Field field : fields) {
                Tag fieldTagAnnotation = field.getAnnotation(Tag.class);
                if (null != fieldTagAnnotation) {
                    byte fieldTag = fieldTagAnnotation.value();
                    if (fieldTag == tag) {
                        LOG.debug("field found for tag " + Integer.toHexString(tag) + ": " + field.getName());
                        Object value;
                        if (String.class.equals(field.getType())) {
                            value = new String(Arrays.copyOfRange(data, dataIdx, dataIdx + size));
                        } else if (byte[].class.equals(field.getType())) {
                            value = Arrays.copyOfRange(data, dataIdx, dataIdx + size);
                        } else {
                            throw new RuntimeException("unsupported field type: " + field.getType().getName()
                                    + " for field " + field.getName());
                        }
                        field.set(result, value);
                    }
                }
            }
            dataIdx += size;
        }
        return result;
    }

    @Test
    public void EF_DIR() throws Exception {
        byte[] dir = this.pcscEid.readFile(new byte[] { 0x2f, 0x00 });
        LOG.debug("size of EF(DIR): " + dir.length);
        LOG.debug("EF(DIR): " + new String(Hex.encodeHex(dir)));

        Pkcs15_EF_DIR result = parsePkcs15File(dir, Pkcs15_EF_DIR.class);
        assertNotNull(result);
        assertNotNull(result.applicationTemplates);
        assertEquals(1, result.applicationTemplates.length);
        Pkcs15ApplicationTemplate applicationTemplate = result.applicationTemplates[0];
        assertNotNull(applicationTemplate);
        assertNotNull(applicationTemplate.label);
        LOG.debug("application label: " + applicationTemplate.label);
        LOG.debug("application id: " + new String(Hex.encodeHex(applicationTemplate.id)));
        LOG.debug("application path: " + new String(Hex.encodeHex(applicationTemplate.path)));
        LOG.debug("application discretionary data objects: "
                + new String(Hex.encodeHex(applicationTemplate.discretionaryDataObjects)));
    }

    private Pkcs15ApplicationTemplate getApplication(Pkcs15_EF_DIR dir, byte[] applicationId) {
        for (Pkcs15ApplicationTemplate applicationTemplate : dir.applicationTemplates) {
            if (Arrays.equals(applicationId, applicationTemplate.id)) {
                return applicationTemplate;
            }
        }
        throw new RuntimeException(
                "no application template found for application id: " + new String(Hex.encodeHex(applicationId)));
    }

    @Test
    public void EF_ODF() throws Exception {
        byte[] dirData = this.pcscEid.readFile(new byte[] { 0x2f, 0x00 });
        Pkcs15_EF_DIR dir = parsePkcs15File(dirData, Pkcs15_EF_DIR.class);

        Pkcs15ApplicationTemplate applicationTemplate = getApplication(dir,
                new byte[] { (byte) 0xa0, 0x00, 0x00, 0x01, 0x77, 0x50, 0x4b, 0x43, 0x53, 0x2d, 0x31, 0x35 });

        byte[] odfFileId = new byte[applicationTemplate.path.length + 2];
        System.arraycopy(applicationTemplate.path, 0, odfFileId, 0, applicationTemplate.path.length);
        System.arraycopy(new byte[] { 0x50, 0x31 }, 0, odfFileId, 4, 2);

        byte[] odf = this.pcscEid.readFile(odfFileId);
        LOG.debug("size of EF(ODF): " + odf.length);
        LOG.debug("EF(ODF): " + new String(Hex.encodeHex(odf)));
    }

    @Test
    public void testSelectPkcs15Application() throws Exception {
        CardChannel cardChannel = this.pcscEid.getCardChannel();
        byte[] aId = new byte[] { (byte) 0xa0, 0x00, 0x00, 0x01, 0x77, 0x50, 0x4b, 0x43, 0x53, 0x2d, 0x31, 0x35 };
        CommandAPDU selectApplicationApdu = new CommandAPDU(0x00, 0xA4, 0x04, 0x0C, aId);
        ResponseAPDU responseApdu = cardChannel.transmit(selectApplicationApdu);
        assertEquals(0x9000, responseApdu.getSW());
    }

    @Test
    public void testSelectBelpicApplication() throws Exception {
        CardChannel cardChannel = this.pcscEid.getCardChannel();
        byte[] belpicAID = new byte[] { (byte) 0xA0, 0x00, 0x00, 0x00, 0x30, 0x29, 0x05, 0x70, 0x00, (byte) 0xAD,
                0x13, 0x10, 0x01, 0x01, (byte) 0xFF };
        CommandAPDU selectApplicationApdu = new CommandAPDU(0x00, 0xA4, 0x04, 0x0C, belpicAID);
        ResponseAPDU responseApdu = cardChannel.transmit(selectApplicationApdu);
        assertEquals(0x9000, responseApdu.getSW());
    }
}