Smart Card Guy

Smart Card, Java Card, PCI DSS, IoT Device Security

Java Card サンプルアプリ - Service

開発環境構築

こちらを参照 smartcardguy.hatenablog.jp

Java Card Service

Serviceアプリ

  • javacard.framework.service (Class BaseService)の使い方
  • BasicServiceにはhelper method (getCLA, get INS等)が多数用意されているので、Codeの書き方が簡単
  • 仕様
    • INS = 0x10の場合、data "0xAB"とstatus word 6617を返す。
    • INS = 0x20の場合、status word 6618を返す。
    • INS = 0x30の場合、status word 9000を返す。

File構成

  • Main.java
  • TestService.java
  • PreProcess.java
  • PostProcess.java

Source code

Main.java
package com.sun.jcclassic.samples.service;

import javacard.framework.APDU;
import javacard.framework.ISOException;
import javacard.framework.service.Dispatcher;
import javacard.framework.service.Service;

/**
 *
 */
public class Main extends javacard.framework.Applet {

    private Dispatcher disp;
    private Service serv;

    public Main() {
        disp = new Dispatcher((short) 1);
        serv = new TestService();
        disp.addService(serv, Dispatcher.PROCESS_COMMAND);

        register();
    }

    public static void install(byte[] aid, short s, byte b) {
        new Main();
    }

    @Override
    public void process(APDU apdu) throws ISOException {

        if(!selectingApplet()){
            disp.process(apdu);
        }

    }

}
TestService.java
/** 
 * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
 * 
 */

package com.sun.jcclassic.samples.service;

import javacard.framework.APDU;
import javacard.framework.service.BasicService;

/**
 *
 */
public class TestService extends BasicService {

    @Override
    public boolean processCommand(APDU command) {

        if (getINS(command) == (byte) 0x10) {
            setOutputLength(command, (short) 1);
            command.getBuffer()[5] = (byte) 0xAB;
            succeedWithStatusWord(command, (short) 0x6617);

            return true;
        }

        if (getINS(command) == (byte) 0x20) {

            setOutputLength(command, (short) 0);

            succeedWithStatusWord(command, (short) 0x6618);

            return true;
        }

        if (getINS(command) == (byte) 0x30) {

            setOutputLength(command, (short) 0);
            succeed(command);
            return true;
        }

        return false;
    }

}
PreProcess.java
/** 
 * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
 * 
 */

package com.sun.jcclassic.samples.service;

/**
 * 
 */
public class PreProcess {

    /** Creates new PreProcess */
    public PreProcess() {
    }

}
PostProcess.java
package com.sun.jcclassic.samples.service;

/**
 * 
 */
public class PostProcess {

    /** Creates new PostProcess */
    public PostProcess() {
    }

}

service.scr

//Test script for Applet 'Service'

output on;

//create Service
0x80 0xB8 0x00 0x00 0x0C 0x0A 0xa0 0x00 0x00 0x00 0x62 0x03 0x01 0x0c 0x09 0x01 0x00 0x7F;

// Select Service //aid/A000000062/03010C0901
0x00 0xA4 0x04 0x00 0x0a 0xa0 0x00 0x00 0x00 0x62 0x03 0x01 0x0c 0x09 0x01 0x7F;

//Send the APDU here
0x80 0x10 0x00 0x00 0x00 0x7F;
0x80 0x20 0x00 0x00 0x00 0x7F;
0x80 0x30 0x00 0x00 0x00 0x7F;

実行

  • 「Run Configuration」機能を利用した実行の仕方はここを参照。https://docs.oracle.com/en/java/javacard/3.1/guide/running-service-sample-eclipse.html
  • ここでは、HelloWorldサンプルと同じく手っ取り早く下記の3つのスクリプトを実行
    • cap-com.sun.jcclassic...service.script実行 : service.capをインストール
    • create-com.sun.jcclassic...Main.script : Main appletのInstance作成
    • service.scr : Service作成、Select, Send APDU

実行結果

CMD>//Test script for Applet 'Service'
output on;
APDU|OUTPUT ON;
//create Service
0x80 0xB8 0x00 0x00 0x0C 0x0A 0xa0 0x00 0x00 0x00 0x62 0x03 0x01 0x0c 0x09 0x01 0x00 0x7F;
APDU|CLA: 80, INS: b8, P1: 00, P2: 00, Lc: 0c, 0a, a0, 00, 00, 00, 62, 03, 01, 0c, 09, 01, 00, Le: 00, SW1: 64, SW2: 44
// Select Service //aid/A000000062/03010C0901
0x00 0xA4 0x04 0x00 0x0a 0xa0 0x00 0x00 0x00 0x62 0x03 0x01 0x0c 0x09 0x01 0x7F;
APDU|CLA: 00, INS: a4, P1: 04, P2: 00, Lc: 0a, a0, 00, 00, 00, 62, 03, 01, 0c, 09, 01, Le: 00, SW1: 90, SW2: 00
//Send the APDU here
0x80 0x10 0x00 0x00 0x00 0x7F;
APDU|CLA: 80, INS: 10, P1: 00, P2: 00, Lc: 00, Le: 01, ab, SW1: 66, SW2: 17
0x80 0x20 0x00 0x00 0x00 0x7F;
APDU|CLA: 80, INS: 20, P1: 00, P2: 00, Lc: 00, Le: 00, SW1: 66, SW2: 18
0x80 0x30 0x00 0x00 0x00 0x7F;
APDU|CLA: 80, INS: 30, P1: 00, P2: 00, Lc: 00, Le: 00, SW1: 90, SW2: 00
CMD>

OUTPUTの解析

//Send the APDU here
0x80 0x10 0x00 0x00 0x00 0x7F;    <= INS : 10
APDU|CLA: 80, INS: 10, P1: 00, P2: 00, Lc: 00, Le: 01, ab, SW1: 66, SW2: 17  <= Le (Response data length) : 0x01, data : 0xab

0x80 0x20 0x00 0x00 0x00 0x7F;    <= INS : 20
APDU|CLA: 80, INS: 20, P1: 00, P2: 00, Lc: 00, Le: 00, SW1: 66, SW2: 18

0x80 0x30 0x00 0x00 0x00 0x7F;    <= INS : 30
APDU|CLA: 80, INS: 30, P1: 00, P2: 00, Lc: 00, Le: 00, SW1: 90, SW2: 00