Towards Certifiably Correct
This presentation is the property of its rightful owner.
Sponsored Links
1 / 114

Towards Certifiably Correct Java Card Applets PowerPoint PPT Presentation


  • 55 Views
  • Uploaded on
  • Presentation posted in: General

Towards Certifiably Correct Java Card Applets. Alessandro Coglio. joint work with:. Matthias Anlauff Li-Mei Gilham. David Cyrluk Lambert Meertens. Kestrel Institute. IFIP WG 2.1 Meeting #60 (May 2005). Java. Java. S I Z E. Enterprise Edition. Standard Edition. Micro Edition. Card.

Download Presentation

Towards Certifiably Correct Java Card Applets

An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

Presentation Transcript


Towards certifiably correct java card applets

Towards Certifiably CorrectJava Card Applets

Alessandro Coglio

joint work with:

Matthias Anlauff

Li-Mei Gilham

David Cyrluk

Lambert Meertens

Kestrel Institute

IFIP WG 2.1 Meeting #60 (May 2005)


Towards certifiably correct java card applets

Java

Java


Towards certifiably correct java card applets

S

I

Z

E

Enterprise Edition

Standard Edition

Micro Edition

Card

Java

smartcards

chip

authentication,

banking,

telephony,

health care,

plasticsubstrate


Towards certifiably correct java card applets

Standard Edition

Java

  • language 

 ?

  • API

Card


Towards certifiably correct java card applets

JAVA CARD RUNTIMEENVIRONMENT (JCRE)

BYTECODEINTERPRETER

API

LIBRARY

Java

bytecode

program

Java Card

program

JAVACOMPILER

Java Card

applet

JAVA CARD

CONVERTER

(checks subset & API)

APPLET

. . .

. . .

Java Card applet

Java web applet

SMART CARD HW/OS


Towards certifiably correct java card applets

typicallywrittenby hand

Java Card

program

somewhatlow-level

 error-prone


Towards certifiably correct java card applets

Java Card

program

applet

spec


Towards certifiably correct java card applets

AutoSmart(automatic generator of smart card applets)

AUTOSMART

Java Card

program

applet

spec

  • for

  • high assurance

  • productivity


Towards certifiably correct java card applets

AUTOSMART

Java Card

program

applet

spec

AutoSmart(automatic generator of smart card applets)

AUTOSMART

Java Card

program

applet

spec


Towards certifiably correct java card applets

AutoSmart(automatic generator of smart card applets)

AUTOSMART

Java Card

program

applet

spec

proof

CHECKER

smaller & simplerthan AutoSmart

yes/no

 easier to trust


Towards certifiably correct java card applets

AUTOSMART

Java Card

program

applet

spec

written in

SmartSlang


Towards certifiably correct java card applets

SmartSlang(smart card specification language)

SmartSlang


Towards certifiably correct java card applets

domain-specific language

domain = smart cards

i.e. constructs specialized to smart card applications

under design

basic version done,

many additional constructs planned

precise semantics

in terms of state machines

applet : CommandStateResponseState

but no formal background necessary

SmartSlang(smart card specification language)


Towards certifiably correct java card applets

SmartSlang

SmartSlang example: e-wallet


Towards certifiably correct java card applets

SmartSlang example: e-wallet

expressive type system

e.g. integer ranges

(vs. byte/short/int in JC)

type Balance = Int(0,MAX_BALANCE);

type Amount = Int(1,MAX_AMOUNT);

const MAX_BALANCE = 10000;

const MAX_AMOUNT = 100;

state { Balance balance }

command credit(Amount amount) {

if (balance + amount <= MAX_BALANCE) {

balance = balance + amount;

} else {

respond EXCEEDED_BALANCE;

}

} apdu {0x80,0x30,0,0,ubytes[AMOUNT_BYTES](amount),0};

const EXCEEDED_BALANCE = 0x6A84;

...

1000000

  • capture semantics

  • automatic mappingto JC typese.g. Balance  short Amount  byte

(short,short)

int

pervasive change

in Java Card code


Towards certifiably correct java card applets

SmartSlang example: e-wallet

type Balance = Int(0,MAX_BALANCE);

type Amount = Int(1,MAX_AMOUNT);

const MAX_BALANCE = 10000;

const MAX_AMOUNT = 100;

state { Balance balance }

command credit(Amount amount) {

if (balance + amount <= MAX_BALANCE) {

balance = balance + amount;

} else {

respond EXCEEDED_BALANCE;

}

} apdu {0x80,0x30,0,0,ubytes[AMOUNT_BYTES](amount),0};

const EXCEEDED_BALANCE = 0x6A84;

...

explicit state components


Towards certifiably correct java card applets

SmartSlang example: e-wallet

type Balance = Int(0,MAX_BALANCE);

type Amount = Int(1,MAX_AMOUNT);

const MAX_BALANCE = 10000;

const MAX_AMOUNT = 100;

state { Balance balance }

command credit(Amount amount) {

if (balance + amount <= MAX_BALANCE) {

balance = balance + amount;

} else {

respond EXCEEDED_BALANCE;

}

} apdu {0x80,0x30,0,0,ubytes[AMOUNT_BYTES](amount),0};

const EXCEEDED_BALANCE = 0x6A84;

...

explicit symbolic commands

with high-level parameters

(vs. APDU bytes in JC)


Towards certifiably correct java card applets

SmartSlang example: e-wallet

type Balance = Int(0,MAX_BALANCE);

type Amount = Int(1,MAX_AMOUNT);

const MAX_BALANCE = 10000;

const MAX_AMOUNT = 100;

state { Balance balance }

command credit(Amount amount) {

if (balance + amount <= MAX_BALANCE) {

balance = balance + amount;

} else {

respond EXCEEDED_BALANCE;

}

} apdu {0x80,0x30,0,0,ubytes[AMOUNT_BYTES](amount),0};

const EXCEEDED_BALANCE = 0x6A84;

...

  • familiar todevelopers

  • “superset ofsubset of Java”

simple Java-likeexpressions &

statements


Towards certifiably correct java card applets

SmartSlang example: e-wallet

type Balance = Int(0,MAX_BALANCE);

type Amount = Int(1,MAX_AMOUNT);

const MAX_BALANCE = 10000;

const MAX_AMOUNT = 100;

state { Balance balance }

command credit(Amount amount) {

if (balance + amount <= MAX_BALANCE) {

balance = balance + amount;

} else {

respond EXCEEDED_BALANCE;

}

} apdu {0x80,0x30,0,0,ubytes[AMOUNT_BYTES](amount),0};

const EXCEEDED_BALANCE = 0x6A84;

...

explicit responses


Towards certifiably correct java card applets

SmartSlang example: e-wallet

type Balance = Int(0,MAX_BALANCE);

type Amount = Int(1,MAX_AMOUNT);

const MAX_BALANCE = 10000;

const MAX_AMOUNT = 100;

state { Balance balance }

command credit(Amount amount) {

if (balance + amount <= MAX_BALANCE) {

balance = balance + amount;

} else {

respond EXCEEDED_BALANCE;

}

} apdu {0x80,0x30,0,0,ubytes[AMOUNT_BYTES](amount),0};

const EXCEEDED_BALANCE = 0x6A84;

...

  • all type safetychecked statically(conservatively)

  • catches user errors

type-safe assignment


Towards certifiably correct java card applets

SmartSlang example: e-wallet

type Balance = Int(0,MAX_BALANCE);

type Amount = Int(1,MAX_AMOUNT);

const MAX_BALANCE = 10000;

const MAX_AMOUNT = 100;

state { Balance balance }

command credit(Amount amount) {

balance = balance + amount;

} apdu {0x80,0x30,0,0,ubytes[AMOUNT_BYTES](amount),0};

const EXCEEDED_BALANCE = 0x6A84;

...

  • all type safetychecked statically(conservatively)

  • catches user errors

type-safe assignment

user gets warning


Towards certifiably correct java card applets

SmartSlang example: e-wallet

type Balance = Int(0,MAX_BALANCE);

type Amount = Int(1,MAX_AMOUNT);

const MAX_BALANCE = 10000;

const MAX_AMOUNT = 100;

state { Balance balance }

command credit(Amount amount) {

if (balance + amount <= MAX_BALANCE) {

balance = balance + amount;

} else {

respond EXCEEDED_BALANCE;

}

} apdu {0x80,0x30,0,0,ubytes[AMOUNT_BYTES](amount),0};

const EXCEEDED_BALANCE = 0x6A84;

...

  • all type safetychecked statically(conservatively)

  • catches user errors

  • no runtime errors(e.g. array access)

  • type checker usesautomated reasoning

type-safe assignment

no such thing in JC!


Towards certifiably correct java card applets

SmartSlang example: e-wallet

type Balance = Int(0,MAX_BALANCE);

type Amount = Int(1,MAX_AMOUNT);

const MAX_BALANCE = 10000;

const MAX_AMOUNT = 100;

state { Balance balance }

command credit(Amount amount) {

if (balance + amount <= MAX_BALANCE) {

balance = balance + amount;

} else {

respond EXCEEDED_BALANCE;

}

} apdu {0x80,0x30,0,0,ubytes[AMOUNT_BYTES](amount),0};

const EXCEEDED_BALANCE = 0x6A84;

...

declarative APDU encoding (vs.

explicit decoding/dispatch in JC)

lengthy, error-prone JC

decoding/dispatching code

automatically generated


Towards certifiably correct java card applets

SmartSlang example: e-wallet

type Balance = Int(0,MAX_BALANCE);

type Amount = Int(1,MAX_AMOUNT);

const MAX_BALANCE = 10000;

const MAX_AMOUNT = 100;

state { Balance balance }

command credit(Amount amount) {

if (balance + amount <= MAX_BALANCE) {

balance = balance + amount;

} else {

respond EXCEEDED_BALANCE;

}

} apdu {0x80,0x30,0,0,ubytes[AMOUNT_BYTES](amount),0};

const EXCEEDED_BALANCE = 0x6A84;

...

amount encoded as byte

JC code to handle user

input data errors

(e.g. if amount > 100)

automatically generated


Towards certifiably correct java card applets

e-wallet example

example

e-wallet

type Balance = Int(0,MAX_BALANCE);

type Amount = Int(1,MAX_AMOUNT);

const MAX_BALANCE = 10000;

const MAX_AMOUNT = 100;

state { Balance balance }

command credit(Amount amount) {

if (balance + amount <= MAX_BALANCE) {

balance = balance + amount;

} else {

respond EXCEEDED_BALANCE;

}

} apdu {0x80,0x30,0,0,ubytes[AMOUNT_BYTES](amount),0};

const EXCEEDED_BALANCE = 0x6A84;

...

const MAX_BALANCE = 10000;

const MAX_AMOUNT = 100;

type Balance = Int(0,MAX_BALANCE);

type Amount = Int(1,MAX_AMOUNT);

const BALANCE_BYTES = ubytes(MAX_BALANCE).length;

const AMOUNT_BYTES = ubytes(MAX_AMOUNT).length;

state {

Balance balance

}

init() {

balance = 0;

} bytes {};

command credit(Amount amount) {

if (balance + amount <= MAX_BALANCE) {

balance = balance + amount;

} else {

respond EXCEEDED_BALANCE;

}

} apdu {CLA,0x30,0,0,ubytes[AMOUNT_BYTES](amount),0};

command debit(Amount amount) {

if (balance - amount >= 0) {

balance = balance - amount;

} else {

respond NEGATIVE_BALANCE;

}

} apdu {CLA,0x40,0,0,ubytes[AMOUNT_BYTES](amount),0};

command getBalance() {

respondok ubytes[BALANCE_BYTES](balance);

} apdu {CLA,0x50,0,0,{},BALANCE_BYTES};

const CLA = 0x80;

const EXCEEDED_BALANCE = 0x6A84;

const NEGATIVE_BALANCE = 0x6A85;

SmartSlang spec


Towards certifiably correct java card applets

package pkg;

import javacard.framework.*;

import javacard.security.*;

import javacardx.crypto.*;

class Wallet extends Applet {

static final short MAX_BALANCE = 10000;

static final short MAX_AMOUNT = 100;

static final short BALANCE_BYTES = 2;

static final short AMOUNT_BYTES = 1;

static final short EXCEEDED_BALANCE = 0x6A84;

static final byte CLA = (byte)0x80;

static final short NEGATIVE_BALANCE = 0x6A85;

short balance;

static byte[] _aux1;

byte[] inData;

short inDataLength; // always <= 255

private A (byte[] initpar, short off, byte len) {

_aux1 = new byte[2];

inData = new byte[255]; // command data is 255 bytes max

balance = 0;

register(initpar,(short)(off + 1),initpar[off]);

}

public boolean select () {

return true;

}

public void process (APDU apdu) {

if (selectingApplet()) return;

byte[] buffer = apdu.getBuffer();

if (buffer[ISO7816.OFFSET_CLA] != (byte)0x80)

ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);

switch (buffer[ISO7816.OFFSET_INS]) {

case 0x30:

credit(apdu);

return;

case 0x40:

debit(apdu);

return;

case 0x50:

getBalance(apdu);

return;

default:

ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);

}

}

void credit (APDU apdu) {

byte[] buffer = apdu.getBuffer();

if ((buffer[ISO7816.OFFSET_P1] != 0) || (buffer[ISO7816.OFFSET_P2] != 0))

ISOException.throwIt(ISO7816.SW_WRONG_P1P2);

inDataLength = nonNegativeByte(buffer[ISO7816.OFFSET_LC]);

if (inDataLength != 1)

ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

receiveIncomingData(apdu);

short amount = nonNegativeByte(inData[0]);

if ((amount < 1) || (amount > 100))

ISOException.throwIt(ISO7816.SW_WRONG_DATA);

if ((short)(balance + amount) <= MAX_BALANCE)

balance = (short)(balance + amount);

else

ISOException.throwIt((short)EXCEEDED_BALANCE);

}

void debit (APDU apdu) {

byte[] buffer = apdu.getBuffer();

if ((buffer[ISO7816.OFFSET_P1] != 0) || (buffer[ISO7816.OFFSET_P2] != 0))

ISOException.throwIt(ISO7816.SW_WRONG_P1P2);

inDataLength = nonNegativeByte(buffer[ISO7816.OFFSET_LC]);

if (inDataLength != 1)

ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

receiveIncomingData(apdu);

short amount = nonNegativeByte(inData[0]);

if ((amount < 1) || (amount > 100))

ISOException.throwIt(ISO7816.SW_WRONG_DATA);

if ((short)(balance - amount) >= 0)

balance = (short)(balance - amount);

else

ISOException.throwIt((short)NEGATIVE_BALANCE);

}

void getBalance (APDU apdu) {

byte[] buffer = apdu.getBuffer();

if ((buffer[ISO7816.OFFSET_P1] != 0) || (buffer[ISO7816.OFFSET_P2] != 0))

ISOException.throwIt(ISO7816.SW_WRONG_P1P2);

short requiredLe = BALANCE_BYTES;

short receivedLe = nonNegativeByte(buffer[ISO7816.OFFSET_LC]);

if (receivedLe == 0)

receivedLe = 256;

if (receivedLe != requiredLe) {

short swLow = (short)(requiredLe & 0xff);

ISOException.throwIt((short)(ISO7816.SW_CORRECT_LENGTH_00 + swLow));

}

byte[] _aux1 = Wallet._aux1;

ubytes((short)2,balance,_aux1);

sendOutgoingData(apdu,_aux1);

return;

}

static void ubytes(short n, short i, byte[] result) {

for (short k = (short)(n - 1); k >= 0; k--) {

result[k] = (byte) (i & 0xff);

i = (short) (i >>> 8);

}

}

static short nonNegativeByte(byte b) {

return (b < 0 ? (short)(b + 256) : b);

}

void receiveIncomingData(APDU apdu) {

byte[] buffer = apdu.getBuffer();

short totalRead = 0;

short chunkRead = apdu.setIncomingAndReceive();

do {

// error if too little or too much data:

if (chunkRead == 0 ||

(short) (totalRead + chunkRead) > inDataLength)

ISOException.throwIt(ISO7816.SW_WRONG_DATA);

// transfer from APDU buffer to inData array:

Util.arrayCopy(buffer,ISO7816.OFFSET_CDATA,

inData,totalRead,chunkRead);

// increment counter:

totalRead += chunkRead;

// get more data if necessary:

if (totalRead != inDataLength)

chunkRead = apdu.receiveBytes(ISO7816.OFFSET_CDATA);

} while (totalRead < inDataLength);

}

void sendOutgoingData(APDU apdu, byte[] data) {

apdu.setOutgoing();

apdu.setOutgoingLength((short)data.length);

apdu.sendBytesLong(data,(short)0,(short)data.length);

}

public static void install(byte[] initpar, short off, byte len) {

new Wallet(initpar,off,len);

}

}

size(code)

= ~ 3–4

size(spec)

JavaCardcode

e-wallet example

~ 150lines

~ 40 lines

const MAX_BALANCE = 10000;

const MAX_AMOUNT = 100;

type Balance = Int(0,MAX_BALANCE);

type Amount = Int(1,MAX_AMOUNT);

const BALANCE_BYTES = ubytes(MAX_BALANCE).length;

const AMOUNT_BYTES = ubytes(MAX_AMOUNT).length;

state {

Balance balance

}

init() {

balance = 0;

} bytes {};

command credit(Amount amount) {

if (balance + amount <= MAX_BALANCE) {

balance = balance + amount;

} else {

respond EXCEEDED_BALANCE;

}

} apdu {CLA,0x30,0,0,ubytes[AMOUNT_BYTES](amount),0};

command debit(Amount amount) {

if (balance - amount >= 0) {

balance = balance - amount;

} else {

respond NEGATIVE_BALANCE;

}

} apdu {CLA,0x40,0,0,ubytes[AMOUNT_BYTES](amount),0};

command getBalance() {

respondok ubytes[BALANCE_BYTES](balance);

} apdu {CLA,0x50,0,0,{},BALANCE_BYTES};

const CLA = 0x80;

const EXCEEDED_BALANCE = 0x6A84;

const NEGATIVE_BALANCE = 0x6A85;

AUTOSMART

SmartSlang spec

(actual files; font size 2)


Towards certifiably correct java card applets

e-wallet Java Card code

e-wallet

...

void credit (APDU apdu) {

byte[] buffer = apdu.getBuffer();

if ((buffer[ISO7816.OFFSET_P1] != 0) ||

(buffer[ISO7816.OFFSET_P2] != 0))

ISOException.throwIt(ISO7816.SW_WRONG_P1P2);

inDataLength =

nonNegativeByte(buffer[ISO7816.OFFSET_LC]);

if (inDataLength != 1)

ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

receiveIncomingData(apdu);

short amount = nonNegativeByte(inData[0]);

if ((amount < 1) || (amount > 100))

ISOException.throwIt(ISO7816.SW_WRONG_DATA);

if ((short)(balance + amount) <= MAX_BALANCE)

balance = (short)(balance + amount);

else

ISOException.throwIt((short)EXCEEDED_BALANCE);

}

...

...

void credit (APDU apdu) {

byte[] buffer = apdu.getBuffer();

if ((buffer[ISO7816.OFFSET_P1] != 0) ||

(buffer[ISO7816.OFFSET_P2] != 0))

ISOException.throwIt(ISO7816.SW_WRONG_P1P2);

inDataLength =

nonNegativeByte(buffer[ISO7816.OFFSET_LC]);

if (inDataLength != 1)

ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

receiveIncomingData(apdu);

short amount = nonNegativeByte(inData[0]);

if ((amount < 1) || (amount > 100))

ISOException.throwIt(ISO7816.SW_WRONG_DATA);

if ((short)(balance + amount) <= MAX_BALANCE)

balance = (short)(balance + amount);

else

ISOException.throwIt((short)EXCEEDED_BALANCE);

}

...

Java

Card

code


Towards certifiably correct java card applets

e-wallet Java Card code

...

void credit (APDU apdu) {

byte[] buffer = apdu.getBuffer();

if ((buffer[ISO7816.OFFSET_P1] != 0) ||

(buffer[ISO7816.OFFSET_P2] != 0))

ISOException.throwIt(ISO7816.SW_WRONG_P1P2);

inDataLength =

nonNegativeByte(buffer[ISO7816.OFFSET_LC]);

if (inDataLength != 1)

ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

receiveIncomingData(apdu);

short amount = nonNegativeByte(inData[0]);

if ((amount < 1) || (amount > 100))

ISOException.throwIt(ISO7816.SW_WRONG_DATA);

if ((short)(balance + amount) <= MAX_BALANCE)

balance = (short)(balance + amount);

else

ISOException.throwIt((short)EXCEEDED_BALANCE);

}

...

interestingcomputation


Towards certifiably correct java card applets

e-wallet Java Card code

...

void credit (APDU apdu) {

byte[] buffer = apdu.getBuffer();

if ((buffer[ISO7816.OFFSET_P1] != 0) ||

(buffer[ISO7816.OFFSET_P2] != 0))

ISOException.throwIt(ISO7816.SW_WRONG_P1P2);

inDataLength =

nonNegativeByte(buffer[ISO7816.OFFSET_LC]);

if (inDataLength != 1)

ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

receiveIncomingData(apdu);

short amount = nonNegativeByte(inData[0]);

if ((amount < 1) || (amount > 100))

ISOException.throwIt(ISO7816.SW_WRONG_DATA);

if ((short)(balance + amount) <= MAX_BALANCE)

balance = (short)(balance + amount);

else

ISOException.throwIt((short)EXCEEDED_BALANCE);

}

...

APDUchecking& decoding


Towards certifiably correct java card applets

SmartSlang counterpart

...

command credit(Amount amount) {

if (balance + amount <= MAX_BALANCE) {

balance = balance + amount;

} else {

respond EXCEEDED_BALANCE;

}

} apdu {0x80,0x30,0,0,ubytes[AMOUNT_BYTES](amount),0};

...


Towards certifiably correct java card applets

SmartSlang example: PKI

SmartSlang


Towards certifiably correct java card applets

SmartSlang example: PKI

built-in key types

type Key = RSAPrivateKey(1024);

type Message = Byte[1024/8];

type Pin = Byte[8];

type PinState = enum {blocked, notVerified(Int(1,3)), ...};

state { Key key, Pin pin, PinState pinState, ... }

command privSignDecrypt(Message msg) {

if (pinState != verified) {

respond SW_SECURITY_NOK;

} else {

respondok decrypt(key,msg);

}

} apdu {0x80,0x42,0,0,msg,1024/8};

secure command putPIN(Pin newPin) {

pin = newPin;

pinState = notVerified(3);

} apdu {0x80,0x22,0,0,newPin,0};

...

automatic mapping to JC API classes


Towards certifiably correct java card applets

SmartSlang example: PKI

type Key = RSAPrivateKey(1024);

type Message = Byte[1024/8];

type Pin = Byte[8];

type PinState = enum {blocked, notVerified(Int(1,3)), ...};

state { Key key, Pin pin, PinState pinState, ... }

command privSignDecrypt(Message msg) {

if (pinState != verified) {

respond SW_SECURITY_NOK;

} else {

respondok decrypt(key,msg);

}

} apdu {0x80,0x42,0,0,msg,1024/8};

secure command putPIN(Pin newPin) {

pin = newPin;

pinState = notVerified(3);

} apdu {0x80,0x22,0,0,newPin,0};

...

built-in cryptographic functions

(vs. multiple API method calls in JC)

  • simple

  • automatic mappingto JC API method calls


Towards certifiably correct java card applets

SmartSlang example: PKI

type Key = RSAPrivateKey(1024);

type Message = Byte[1024/8];

type Pin = Byte[8];

type PinState = enum {blocked, notVerified(Int(1,3)), ...};

state { Key key, Pin pin, PinState pinState, ... }

command privSignDecrypt(Message msg) {

if (pinState != verified) {

respond SW_SECURITY_NOK;

} else {

respondok decrypt(key,msg);

}

} apdu {0x80,0x42,0,0,msg,1024/8};

secure command putPIN(Pin newPin) {

pin = newPin;

pinState = notVerified(3);

} apdu {0x80,0x22,0,0,newPin,0};

...

(# tries left)

enumerationtypes

  • with arguments

  • automatic mappingto byte constants +auxiliary variablesfor arguments in JC


Towards certifiably correct java card applets

SmartSlang example: PKI

type Key = RSAPrivateKey(1024);

type Message = Byte[1024/8];

type Pin = Byte[8];

type PinState = enum {blocked, notVerified(Int(1,3)), ...};

state { Key key, Pin pin, PinState pinState, ... }

command privSignDecrypt(Message msg) {

if (pinState != verified) {

respond SW_SECURITY_NOK;

} else {

respondok decrypt(key,msg);

}

} apdu {0x80,0x42,0,0,msg,1024/8};

secure command putPIN(Pin newPin) {

pin = newPin;

pinState = notVerified(3);

} apdu {0x80,0x22,0,0,newPin,0};

...

spread change in

Java Card code

construct for Global Platformsecure channels (vs. multipleAPI method calls in JC)

  • simple, localized

  • automatic mapping toJC API method calls


Towards certifiably correct java card applets

SmartSlang example: PKI

type Key = RSAPrivateKey(1024);

type Message = Byte[1024/8];

type Pin = Byte[8];

type PinState = enum {blocked, notVerified(Int(1,3)), ...};

state { Key key, Pin pin, PinState pinState, ... }

command privSignDecrypt(Message msg) {

if (pinState != verified) {

respond SW_SECURITY_NOK;

} else {

respondok decrypt(key,msg);

}

} apdu {0x80,0x42,0,0,msg,1024/8};

secure command putPIN(Pin newPin) {

pin = newPin;

pinState = notVerified(3);

} apdu {0x80,0x22,0,0,newPin,0};

...

decryption result computed on the

fly and returned (vs. pre-allocated

intermediate storage in JC)

  • simple functional model

  • automatic mapping topre-allocated intermediatestorage in JC

automatic static storage

management is significant

advantage for smart cards!


Towards certifiably correct java card applets

PKI example

PKI

example

type Key = RSAPrivateKey(1024);

type Message = Byte[1024/8];

type Pin = Byte[8];

type PinState = enum {blocked, notVerified(Int(1,3)), ...};

state { Key key, Pin pin, PinState pinState, ... }

command privSignDecrypt(Message msg) {

if (pinState != verified) {

respond SW_SECURITY_NOK;

} else {

respondok decrypt(key,msg);

}

} apdu {0x80,0x42,0,0,msg,1024/8};

secure command putPIN(Pin newPin) {

pin = newPin;

pinState = notVerified(3);

} apdu {0x80,0x22,0,0,newPin,0};

...

const KEY_SIZE = 1024; // in bits

type KeyState = rec {Bool isExponentSet, Bool isModulusSet};

const MSG_SIZE = KEY_SIZE / 8; // in bytes

type Message = Byte[MSG_SIZE];

const PIN_SIZE = 8;

type Pin = Byte[PIN_SIZE];

const MAX_TRIES = 3;

type PinState = enum {unset, notVerified(Int(1,MAX_TRIES)), verified, blocked};

const MAX_CERT_SIZE = 1000; // in bytes

type Certificate = Byte[0..MAX_CERT_SIZE];

const MAX_CERT_CHUNK_SIZE = 100; // in bytes

type CertificateChunk = Byte[1..MAX_CERT_CHUNK_SIZE];

const MAX_PROP_SIZE = 200; // in bytes

type Properties = Byte[0..MAX_PROP_SIZE];

type AppletState = enum {personalization, deployment, updating};

state {

RSAPrivateKey(KEY_SIZE) key,

KeyState keyState,

Pin pin,

PinState pinState,

Int(0,MAX_CERT_SIZE) certSize,

Certificate certificate,

Properties properties,

Int(0,MAX_CERT_SIZE) certBytesSent,

AppletState appletState

}

invariant appletState != deployment || (certBytesSent <= (certificate).length-1);

init() {

/* The current definition of SmartSlang requires every state component to be

initialized in the initialization block. This is a bit artificial for

certain state components that are really initialized by commands, e.g. keys,

forcing us to use meaningless values like all 0s. We may change the

definition of SmartSlang to no longer require all state components to be

initialized in the initialization block, while leaving the requirement that

every state component must be initialized before it is used for the first

time. Besides avoiding artificial initializations, this change would support

better semantic checking of the SmartSlang spec, because presumably a key

shouldn't be used before it is assigned a non-all-0s value. */

key = RSAPrivateKey(KEY_SIZE)

(repeat(0,KEY_SIZE/8), repeat(0,KEY_SIZE/8));

keyState = KeyState(false,false);

pin = repeat(0,8);

pinState = unset;

certSize = 0;

certificate = {};

properties = {};

certBytesSent = 0;

appletState = personalization;

} bytes {};

command putExponent(Byte[KEY_SIZE/8] exp) {

if (appletState == deployment) { respond SW_WRONG_STATE; }

key = RSAPrivateKey(KEY_SIZE) (exp, key.modulus);

keyState = KeyState (true, keyState.isModulusSet);

// we may extend SmartSlang with direct assignments to record components:

// key.exponent = exp;

// keyState.isExponentSet =true;

} apdu {CLA, INS_PUT_EXP, P1, P2, exp, 0};

command putModulus(Byte[KEY_SIZE/8] mod) {

if (appletState == deployment) { respond SW_WRONG_STATE; }

key = RSAPrivateKey(KEY_SIZE) (key.exponent, mod);

keyState = KeyState (keyState.isExponentSet, true);

} apdu {CLA, INS_PUT_MOD, P1, P2, mod, 0};

command putPIN(Pin p) {

if (appletState == deployment) { respond SW_WRONG_STATE; }

pin = p;

pinState = notVerified(MAX_TRIES);

} apdu {CLA, INS_PUT_PIN, P1, P2, p, 0};

command putCertificateSize(Int(1,MAX_CERT_SIZE) size) {

if (appletState == deployment) { respond SW_WRONG_STATE; }

certSize = size;

certificate = {};

} apdu {CLA, INS_CERT_SIZE, P1, P2, ubytes[2](size), 0};

command putCertificateChunk(CertificateChunk certChunk) {

if (appletState == deployment) { respond SW_WRONG_STATE; }

if (certSize == 0) { respond SW_CERT_SIZE_UNSET; }

if (certificate.length + certChunk.length > certSize)

{ respond SW_CERTIFICATE_TOO_LARGE; }

certificate = certificate ++ certChunk;

} apdu {CLA, INS_PUT_CERT, P1, P2, certChunk, 0};

command putProperties(Properties prop) {

if (appletState == deployment) { respond SW_WRONG_STATE; }

properties = prop;

} apdu {CLA, INS_PUT_PROP, P1, P2, prop, 0};

command unblockPIN() {

if (appletState != updating) { respond SW_WRONG_STATE; }

pinState = notVerified(MAX_TRIES);

} apdu {CLA, INS_UNBLOCK, P1, P2, {}, 0};

command deploy() {

if (appletState == deployment) { respond SW_WRONG_STATE; }

if (keyState == KeyState(true,true)

&& pinState != unset

&& certSize != 0

&& certificate.length == certSize

&& properties != {}) {

appletState = deployment;

} else {

respond SW_UNFINISHED_PERSONALIZATION;

}

} apdu {CLA, INS_DEPLOY, P1, P2, {}, 0};

command update() {

if (appletState != deployment) { respond SW_WRONG_STATE; }

appletState = updating;

} apdu {CLA, INS_UPDATE, P1, P2, {}, 0};

command getCertificateChunk() {

if (appletState != deployment) { respond SW_WRONG_STATE; }

CertificateChunk chunk;

if (certificate.length - certBytesSent >= MAX_CERT_CHUNK_SIZE) {

chunk = certificate[certBytesSent,MAX_CERT_CHUNK_SIZE];

certBytesSent = certBytesSent + MAX_CERT_CHUNK_SIZE;

} else {

chunk = certificate[certBytesSent..certificate.length-1];

certBytesSent = certificate.length;

}

if (certificate.length - certBytesSent >= MAX_CERT_CHUNK_SIZE) {

respond {chunk, SW1_MORE_DATA, MAX_CERT_CHUNK_SIZE};

} else if (certificate.length - certBytesSent > 0) {

respond {chunk, SW1_MORE_DATA, certificate.length - certBytesSent};

} else /* certificate.length == certBytesSent */ {

certBytesSent = 0; // reset

respondok chunk;

}

} apdu {CLA, INS_GET_CERT, P1, P2, {},

(certificate.length - certBytesSent >= MAX_CERT_CHUNK_SIZE) ?

MAX_CERT_CHUNK_SIZE : certificate.length - certBytesSent};

command getProperties() {

if (appletState != deployment) { respond SW_WRONG_STATE; }

respondok properties;

} apdu {CLA, INS_GET_PROP, P1, P2, {}, properties.length};

command pinVerify(Pin p) {

if (appletState != deployment) { respond SW_WRONG_STATE; }

switch (pinState) {

case verified: {

respondok;

}

case notVerified(triesLeft): {

if (p == pin) {

pinState = verified;

respondok;

} else if (triesLeft > 1) {

pinState = notVerified(triesLeft - 1);

respond {{}, SW1_WRONG_PIN, triesLeft};

} else {

pinState = blocked;

respond SW_PIN_BLOCKED;

}

}

case blocked: {

respond SW_PIN_BLOCKED;

}

case unset: {

// cannot happen -- could be proved using state invariants

}

}

} apdu {CLA, INS_VERIFY, P1, P2, p, 0};

command pinVerified() {

if (appletState != deployment) { respond SW_WRONG_STATE; }

switch (pinState) {

case verified: {

respondok;

}

case notVerified(triesLeft): {

respond {{}, SW1_TRIES_LEFT, triesLeft};

}

case blocked: {

respond SW_PIN_BLOCKED;

}

case unset: {

// cannot happen -- could be proved using state invariants

}

}

} apdu {CLA, INS_VERIFIED, P1, P2, {}, 0};

command privSignDecrypt(Message msg) {

if (appletState != deployment) { respond SW_WRONG_STATE; }

if (pinState != verified) {

respond SW_SECURITY_NOK;

} else {

respondok rsa(key,msg);

}

} apdu {CLA, INS_SIGN_DEC, P1, P2, msg, MSG_SIZE};

const CLA = 0x80;

const P1 = 0;

const P2 = 0;

const INS_PUT_EXP = 0x44;

const INS_PUT_MOD = 0x46;

const INS_PUT_PIN = 0x22;

const INS_CERT_SIZE = 0x3A;

const INS_PUT_CERT = 0x38;

const INS_PUT_PROP = 0x58;

const INS_UNBLOCK = 0x24;

const INS_DEPLOY = 0x70;

const INS_UPDATE = 0x72;

const INS_GET_CERT = 0x36;

const INS_GET_PROP = 0x56;

const INS_VERIFY = 0x20;

const INS_VERIFIED = 0x26;

const INS_SIGN_DEC = 0x42;

const SW_WRONG_STATE = 0x6985;

const SW_CERTIFICATE_TOO_LARGE = 0x6A80;

const SW_UNFINISHED_PERSONALIZATION = 0x6985;

const SW_PIN_BLOCKED = 0x6983;

const SW_SECURITY_NOK = 0x6982;

const SW_CERT_SIZE_UNSET = 0x6985;

const SW1_WRONG_PIN = 0x63;

const SW1_TRIES_LEFT = 0x63;

const SW1_MORE_DATA = 0x63;

select {

certBytesSent = 0; // reset

}

deselect {

if (pinState == verified) {

pinState = notVerified(MAX_TRIES);

}

}

SmartSlang spec


Towards certifiably correct java card applets

package pkg;

import javacard.framework.*;

import javacard.security.*;

import javacardx.crypto.*;

class A extends Applet {

static final short KEY_SIZE = 1024;

static final short MSG_SIZE = 128;

static final byte PIN_SIZE = 8;

static final byte MAX_TRIES = 3;

static final short MAX_CERT_SIZE = 1000;

static final byte MAX_CERT_CHUNK_SIZE = 100;

static final short MAX_PROP_SIZE = 200;

static final short SW_WRONG_STATE = 0x6985;

static final byte CLA = (byte)0x80;

static final byte INS_PUT_EXP = 0x44;

static final byte P1 = 0;

static final byte P2 = 0;

static final byte INS_PUT_MOD = 0x46;

static final byte INS_PUT_PIN = 0x22;

static final byte INS_CERT_SIZE = 0x3a;

static final short SW_CERT_SIZE_UNSET = 0x6985;

static final short SW_CERTIFICATE_TOO_LARGE = 0x6a80;

static final byte INS_PUT_CERT = 0x38;

static final byte INS_PUT_PROP = 0x58;

static final byte INS_UNBLOCK = 0x24;

static final short SW_UNFINISHED_PERSONALIZATION = 0x6985;

static final byte INS_DEPLOY = 0x70;

static final byte INS_UPDATE = 0x72;

static final byte SW1_MORE_DATA = 0x63;

static final byte INS_GET_CERT = 0x36;

static final byte INS_GET_PROP = 0x56;

static final byte SW1_WRONG_PIN = 0x63;

static final short SW_PIN_BLOCKED = 0x6983;

static final byte INS_VERIFY = 0x20;

static final byte SW1_TRIES_LEFT = 0x63;

static final byte INS_VERIFIED = 0x26;

static final short SW_SECURITY_NOK = 0x6982;

static final byte INS_SIGN_DEC = 0x42;

RSAPrivateKey key;

KeyState keyState;

byte[] pin;

PinState pinState;

short certSize;

ByteVector certificate;

ByteVector properties;

short certBytesSent;

byte appletState;

static byte[] exp;

static byte[] mod;

static byte[] p;

static ByteVector certChunk;

static ByteVector prop;

static byte[] msg;

static byte[] _aux1;

static byte[] _aux2;

static ByteVector chunk;

byte[] inData;

short inDataLength; // always <= 255

static Cipher rsaCipher;

private A (byte[] initpar, short off, byte len) {

key = (RSAPrivateKey)KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PRIVATE,

(short)1024,

false);

keyState = new KeyState();

pin = A.byteArrayNew((short)8);

pinState = new PinState();

certificate = new ByteVector((short)0,(short)1000);

properties = new ByteVector((short)0,(short)200);

chunk = new ByteVector((short)1,(short)100);

_aux2 = A.byteArrayNew((short)128);

_aux1 = A.byteArrayNew((short)128);

msg = A.byteArrayNew((short)128);

prop = new ByteVector((short)0,(short)200);

certChunk = new ByteVector((short)1,(short)100);

p = A.byteArrayNew((short)8);

mod = A.byteArrayNew((short)128);

exp = A.byteArrayNew((short)128);

inData = new byte[255]; // command data is 255 bytes max

rsaCipher = Cipher.getInstance(Cipher.ALG_RSA_NOPAD,false);

A.repeat((byte)0, (short)128, _aux1, (short)0);

A.repeat((byte)0, (short)128, _aux2, (short)0);

A.makeRSAPrivateKey((short)1024, _aux1, _aux2, key);

keyState.isExponentSet = false;

keyState.isModulusSet = false;

A.repeat((byte)0, (short)8, pin, (short)0);

pinState.elem = PinState.unset;

certSize = 0;

certificate.setSize((short)0);

properties.setSize((short)0);

certBytesSent = 0;

appletState = AppletState.personalization;

register(initpar, (short)(off + 1), initpar[off]);

}

public boolean select ()

{

certBytesSent = 0;

return true;

}

public void deselect ()

{

if (pinState.elem == PinState.verified)

{

pinState.elem = PinState.notVerified;

pinState.notVerified_arg = MAX_TRIES;

}

}

public void process (APDU apdu)

{

if (selectingApplet())

return;

byte[] buffer = apdu.getBuffer();

if (buffer[ISO7816.OFFSET_CLA] != CLA)

ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);

switch (buffer[ISO7816.OFFSET_INS])

{

case INS_PUT_EXP:

putExponent(apdu);

return;

case INS_PUT_MOD:

putModulus(apdu);

return;

case INS_PUT_PIN:

putPIN(apdu);

return;

case INS_CERT_SIZE:

putCertificateSize(apdu);

return;

case INS_PUT_CERT:

putCertificateChunk(apdu);

return;

case INS_PUT_PROP:

putProperties(apdu);

return;

case INS_UNBLOCK:

unblockPIN(apdu);

return;

case INS_DEPLOY:

deploy(apdu);

return;

case INS_UPDATE:

update(apdu);

return;

case INS_GET_CERT:

getCertificateChunk(apdu);

return;

case INS_GET_PROP:

getProperties(apdu);

return;

case INS_VERIFY:

pinVerify(apdu);

return;

case INS_VERIFIED:

pinVerified(apdu);

return;

case INS_SIGN_DEC:

privSignDecrypt(apdu);

return;

default:

ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);

}

}

void putExponent (APDU apdu)

{

byte[] buffer = apdu.getBuffer();

if ((buffer[ISO7816.OFFSET_P1] != P1) || (buffer[ISO7816.OFFSET_P2] != P2))

ISOException.throwIt(ISO7816.SW_WRONG_P1P2);

inDataLength = A.nonNegativeByte(buffer[ISO7816.OFFSET_LC]);

if (inDataLength != 128)

ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

receiveIncomingData(apdu);

Util.arrayCopy(inData, (short)0, exp, (short)0, inDataLength);

if (appletState == AppletState.deployment)

ISOException.throwIt(SW_WRONG_STATE);

A.getRSAModulus(key, _aux1);

A.makeRSAPrivateKey((short)1024, exp, _aux1, key);

keyState.isExponentSet = true;

keyState.isModulusSet = keyState.isModulusSet;

}

void putModulus (APDU apdu)

{

byte[] buffer = apdu.getBuffer();

if ((buffer[ISO7816.OFFSET_P1] != P1) || (buffer[ISO7816.OFFSET_P2] != P2))

ISOException.throwIt(ISO7816.SW_WRONG_P1P2);

inDataLength = A.nonNegativeByte(buffer[ISO7816.OFFSET_LC]);

if (inDataLength != 128)

ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

receiveIncomingData(apdu);

Util.arrayCopy(inData, (short)0, mod, (short)0, inDataLength);

if (appletState == AppletState.deployment)

ISOException.throwIt(SW_WRONG_STATE);

A.getRSAExponent(key, _aux1);

A.makeRSAPrivateKey((short)1024, _aux1, mod, key);

keyState.isExponentSet = keyState.isExponentSet;

keyState.isModulusSet = true;

}

void putPIN (APDU apdu)

{

byte[] buffer = apdu.getBuffer();

if ((buffer[ISO7816.OFFSET_P1] != P1) || (buffer[ISO7816.OFFSET_P2] != P2))

ISOException.throwIt(ISO7816.SW_WRONG_P1P2);

inDataLength = A.nonNegativeByte(buffer[ISO7816.OFFSET_LC]);

if (inDataLength != 8)

ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

receiveIncomingData(apdu);

Util.arrayCopy(inData, (short)0, p, (short)0, inDataLength);

if (appletState == AppletState.deployment)

ISOException.throwIt(SW_WRONG_STATE);

A.assign(p, pin, (short)0);

pinState.elem = PinState.notVerified;

pinState.notVerified_arg = MAX_TRIES;

}

void putCertificateSize (APDU apdu)

{

byte[] buffer = apdu.getBuffer();

if ((buffer[ISO7816.OFFSET_P1] != P1) || (buffer[ISO7816.OFFSET_P2] != P2))

ISOException.throwIt(ISO7816.SW_WRONG_P1P2);

inDataLength = A.nonNegativeByte(buffer[ISO7816.OFFSET_LC]);

if (inDataLength != 2)

ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

receiveIncomingData(apdu);

short size = Util.makeShort(inData[0], inData[1]);

if ((size < 1) || (size > 1000))

ISOException.throwIt(ISO7816.SW_WRONG_DATA);

if (appletState == AppletState.deployment)

ISOException.throwIt(SW_WRONG_STATE);

certSize = size;

certificate.setSize((short)0);

}

void putCertificateChunk (APDU apdu)

{

byte[] buffer = apdu.getBuffer();

if ((buffer[ISO7816.OFFSET_P1] != P1) || (buffer[ISO7816.OFFSET_P2] != P2))

ISOException.throwIt(ISO7816.SW_WRONG_P1P2);

inDataLength = A.nonNegativeByte(buffer[ISO7816.OFFSET_LC]);

if ((inDataLength < 1) || (inDataLength > 100))

ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

receiveIncomingData(apdu);

Util.arrayCopy(inData, (short)0, certChunk.data, (short)0, inDataLength);

if (appletState == AppletState.deployment)

ISOException.throwIt(SW_WRONG_STATE);

if (certSize == 0)

ISOException.throwIt(SW_CERT_SIZE_UNSET);

if ((short)(certificate.size() + certChunk.size()) > certSize)

ISOException.throwIt(SW_CERTIFICATE_TOO_LARGE);

A.concat(certificate, certChunk, certificate, (short)0, false);

}

void putProperties (APDU apdu)

{

byte[] buffer = apdu.getBuffer();

if ((buffer[ISO7816.OFFSET_P1] != P1) || (buffer[ISO7816.OFFSET_P2] != P2))

ISOException.throwIt(ISO7816.SW_WRONG_P1P2);

inDataLength = A.nonNegativeByte(buffer[ISO7816.OFFSET_LC]);

if ((inDataLength < 0) || (inDataLength > 200))

ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

receiveIncomingData(apdu);

Util.arrayCopy(inData, (short)0, prop.data, (short)0, inDataLength);

if (appletState == AppletState.deployment)

ISOException.throwIt(SW_WRONG_STATE);

A.assign(prop, properties, (short)0, false);

}

void unblockPIN (APDU apdu)

{

byte[] buffer = apdu.getBuffer();

if ((buffer[ISO7816.OFFSET_P1] != P1) || (buffer[ISO7816.OFFSET_P2] != P2))

ISOException.throwIt(ISO7816.SW_WRONG_P1P2);

if (appletState != AppletState.updating)

ISOException.throwIt(SW_WRONG_STATE);

pinState.elem = PinState.notVerified;

pinState.notVerified_arg = MAX_TRIES;

}

void deploy (APDU apdu)

{

byte[] buffer = apdu.getBuffer();

if ((buffer[ISO7816.OFFSET_P1] != P1) || (buffer[ISO7816.OFFSET_P2] != P2))

ISOException.throwIt(ISO7816.SW_WRONG_P1P2);

if (appletState == AppletState.deployment)

ISOException.throwIt(SW_WRONG_STATE);

if ((((((keyState.isExponentSet == true)

&& (keyState.isModulusSet == true))

&& (pinState.elem != PinState.unset))

&& (certSize != 0))

&& (certificate.size() == certSize))

&& (properties.size() != 0))

appletState = AppletState.deployment;

else

ISOException.throwIt(SW_UNFINISHED_PERSONALIZATION);

}

void update (APDU apdu)

{

byte[] buffer = apdu.getBuffer();

if ((buffer[ISO7816.OFFSET_P1] != P1) || (buffer[ISO7816.OFFSET_P2] != P2))

ISOException.throwIt(ISO7816.SW_WRONG_P1P2);

if (appletState != AppletState.deployment)

ISOException.throwIt(SW_WRONG_STATE);

appletState = AppletState.updating;

}

void getCertificateChunk (APDU apdu)

{

byte[] buffer = apdu.getBuffer();

if ((buffer[ISO7816.OFFSET_P1] != P1) || (buffer[ISO7816.OFFSET_P2] != P2))

ISOException.throwIt(ISO7816.SW_WRONG_P1P2);

short requiredLe = MAX_CERT_CHUNK_SIZE;

short receivedLe = A.nonNegativeByte(buffer[ISO7816.OFFSET_LC]);

if (receivedLe == 0)

receivedLe = 256;

if (receivedLe != requiredLe)

{

short swLow = (short)(requiredLe & 0xff);

ISOException.throwIt((short)(ISO7816.SW_CORRECT_LENGTH_00 + swLow));

}

if (appletState != AppletState.deployment)

ISOException.throwIt(SW_WRONG_STATE);

if ((short)(certificate.size() - certBytesSent) >= MAX_CERT_CHUNK_SIZE)

{

A.subarrayFromLength(certificate,

certBytesSent,

MAX_CERT_CHUNK_SIZE,

chunk,

(short)0,

false);

certBytesSent = (short)(certBytesSent + MAX_CERT_CHUNK_SIZE);

}

else

{

A.subarrayFromLength(certificate,

certBytesSent,

(short)(((certificate.size() - 1)

- certBytesSent)

+ 1),

chunk,

(short)0,

false);

certBytesSent = certificate.size();

}

if ((short)(certificate.size() - certBytesSent) >= MAX_CERT_CHUNK_SIZE)

{

sendOutgoingData(apdu, chunk.data, chunk.len);

ISOException.throwIt(Util.makeShort(SW1_MORE_DATA,

MAX_CERT_CHUNK_SIZE));

}

else

if ((short)(certificate.size() - certBytesSent) > 0)

{

sendOutgoingData(apdu, chunk.data, chunk.len);

ISOException.throwIt(Util.makeShort(SW1_MORE_DATA,

(byte)(certificate.size()

- certBytesSent)));

}

else

{

certBytesSent = 0;

sendOutgoingData(apdu, chunk.data, chunk.len);

return;

}

}

void getProperties (APDU apdu)

{

byte[] buffer = apdu.getBuffer();

if ((buffer[ISO7816.OFFSET_P1] != P1) || (buffer[ISO7816.OFFSET_P2] != P2))

ISOException.throwIt(ISO7816.SW_WRONG_P1P2);

short requiredLe = properties.size();

short receivedLe = A.nonNegativeByte(buffer[ISO7816.OFFSET_LC]);

if (receivedLe == 0)

receivedLe = 256;

if (receivedLe != requiredLe)

{

short swLow = (short)(requiredLe & 0xff);

ISOException.throwIt((short)(ISO7816.SW_CORRECT_LENGTH_00 + swLow));

}

if (appletState != AppletState.deployment)

ISOException.throwIt(SW_WRONG_STATE);

sendOutgoingData(apdu, properties.data, properties.len);

return;

}

void pinVerify (APDU apdu)

{

byte[] buffer = apdu.getBuffer();

if ((buffer[ISO7816.OFFSET_P1] != P1) || (buffer[ISO7816.OFFSET_P2] != P2))

ISOException.throwIt(ISO7816.SW_WRONG_P1P2);

inDataLength = A.nonNegativeByte(buffer[ISO7816.OFFSET_LC]);

if (inDataLength != 8)

ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

receiveIncomingData(apdu);

Util.arrayCopy(inData, (short)0, p, (short)0, inDataLength);

if (appletState != AppletState.deployment)

ISOException.throwIt(SW_WRONG_STATE);

switch (pinState.elem)

{

case PinState.verified:

return;

case PinState.notVerified:

byte triesLeft = pinState.notVerified_arg;

if (A.equals(p, pin))

{

pinState.elem = PinState.verified;

return;

}

else

if (triesLeft > 1)

{

pinState.elem = PinState.notVerified;

pinState.notVerified_arg = (byte)(triesLeft - 1);

ISOException.throwIt(Util.makeShort(SW1_WRONG_PIN,

triesLeft));

}

else

{

pinState.elem = PinState.blocked;

ISOException.throwIt(SW_PIN_BLOCKED);

}

case PinState.blocked:

ISOException.throwIt(SW_PIN_BLOCKED);

case PinState.unset:

}

}

void pinVerified (APDU apdu)

{

byte[] buffer = apdu.getBuffer();

if ((buffer[ISO7816.OFFSET_P1] != P1) || (buffer[ISO7816.OFFSET_P2] != P2))

ISOException.throwIt(ISO7816.SW_WRONG_P1P2);

if (appletState != AppletState.deployment)

ISOException.throwIt(SW_WRONG_STATE);

switch (pinState.elem)

{

case PinState.verified:

return;

case PinState.notVerified:

byte triesLeft = pinState.notVerified_arg;

ISOException.throwIt(Util.makeShort(SW1_TRIES_LEFT, triesLeft));

case PinState.blocked:

ISOException.throwIt(SW_PIN_BLOCKED);

case PinState.unset:

}

}

void privSignDecrypt (APDU apdu)

{

byte[] buffer = apdu.getBuffer();

if ((buffer[ISO7816.OFFSET_P1] != P1) || (buffer[ISO7816.OFFSET_P2] != P2))

ISOException.throwIt(ISO7816.SW_WRONG_P1P2);

inDataLength = A.nonNegativeByte(buffer[ISO7816.OFFSET_LC]);

if (inDataLength != 128)

ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

receiveIncomingData(apdu);

Util.arrayCopy(inData, (short)0, msg, (short)0, inDataLength);

if (appletState != AppletState.deployment)

ISOException.throwIt(SW_WRONG_STATE);

if (pinState.elem != PinState.verified)

ISOException.throwIt(SW_SECURITY_NOK);

else

{

A.rsa(key, msg, _aux1);

sendOutgoingData(apdu, _aux1);

return;

}

}

static void assign(ByteVector source, ByteVector target, short offset, boolean setSize) {

short len = source.size();

if (setSize) target.setSize(len);

Util.arrayCopy(source.data,(short)0,target.data,offset,len);

}

static void concat(ByteVector vec1, ByteVector vec2, ByteVector result, short offset, boolean setSize) {

short len1 = vec1.size();

short len2 = vec2.size();

if (setSize) result.setSize((short)(len1+len2));

Util.arrayCopy(vec2.data,(short)0,result.data,(short)(len1+offset),len2);

if (vec1.data != result.data)

Util.arrayCopy(vec1.data,(short)0,result.data,offset,len1);

}

static void subarrayFromLength(ByteVector vec, short i, short n, ByteVector result, short offset, boolean setSize) {

if (setSize) result.setSize(n);

Util.arrayCopy(vec.data,i,result.data,offset,n);

}

static void getRSAExponent(RSAPrivateKey key, byte[] result) {

key.getExponent(result,(short)0);

}

static void getRSAModulus(RSAPrivateKey key, byte[] result) {

key.getModulus(result,(short)0);

}

static void assign(byte[] source, byte[] target, short offset) {

short len = (short) source.length;

Util.arrayCopy(source,(short)0,target,offset,len);

}

static boolean equals(byte[] arr1, byte[] arr2) {

short len = (short) arr1.length;

if (arr2.length != len) return false;

for (short i = 0; i < len; i++)

if (arr1[i] != arr2[i]) return false;

return true;

}

static byte[] byteArrayNew(short size) {

return new byte[size];

}

static void repeat(byte elem, short n, byte[] result, short offset) {

Util.arrayFillNonAtomic(result,offset,n,elem);

}

static void makeRSAPrivateKey

(short len, byte[] exponent, byte[] modulus, RSAPrivateKey result) {

result.setExponent(exponent,(short)0,(short)len);

result.setModulus(modulus,(short)0,(short)len);

}

static short nonNegativeByte(byte b) {

return (b < 0 ? (short)(b + 256) : b);

}

void receiveIncomingData(APDU apdu) {

byte[] buffer = apdu.getBuffer();

short totalRead = 0;

short chunkRead = apdu.setIncomingAndReceive();

do {

// error if too little or too much data:

if (chunkRead == 0 ||

(short) (totalRead + chunkRead) > inDataLength)

ISOException.throwIt(ISO7816.SW_WRONG_DATA);

// transfer from APDU buffer to inData array:

Util.arrayCopy(buffer,ISO7816.OFFSET_CDATA,

inData,totalRead,chunkRead);

// increment counter:

totalRead += chunkRead;

// get more data if necessary:

if (totalRead != inDataLength)

chunkRead = apdu.receiveBytes(ISO7816.OFFSET_CDATA);

} while (totalRead < inDataLength);

}

static void rsa(Key key, byte[] data, byte[] result) {

short sizeInBytes = (short) (key.getSize() / 8);

rsaCipher.init(key,Cipher.MODE_ENCRYPT);

rsaCipher.doFinal(data,(short)0,sizeInBytes,result,(short)0);

}

void sendOutgoingData(APDU apdu, byte[] data) {

sendOutgoingData(apdu, data, (short)data.length);

}

void sendOutgoingData(APDU apdu, byte[] data, short len) {

apdu.setOutgoing();

apdu.setOutgoingLength(len);

apdu.sendBytesLong(data,(short)0,len);

}

public static void install(byte[] initpar, short off, byte len)

throws ISOException {

new A(initpar,off,len);

}

}

class KeyState {

boolean isExponentSet;

boolean isModulusSet;

KeyState () { }

}

class PinState {

static final byte unset = 0;

static final byte notVerified = 1;

static final byte verified = 2;

static final byte blocked = 3;

byte elem;

byte notVerified_arg = 1;

PinState () { }

}

class AppletState {

static final byte personalization = 0;

static final byte deployment = 1;

static final byte updating = 2;

}

class VectorBase {

short len;

void setSize(short newSize) {

len = newSize;

}

short size() {

return len;

}

}

class ByteVector extends VectorBase {

byte[] data;

ByteVector(short minLen, short maxLen) {

data = A.byteArrayNew(maxLen);

setSize(minLen);

}

}

PKI example

~ 240 lines

~ 700lines

size(code)

const KEY_SIZE = 1024; // in bits

type KeyState = rec {Bool isExponentSet, Bool isModulusSet};

const MSG_SIZE = KEY_SIZE / 8; // in bytes

type Message = Byte[MSG_SIZE];

const PIN_SIZE = 8;

type Pin = Byte[PIN_SIZE];

const MAX_TRIES = 3;

type PinState = enum {unset, notVerified(Int(1,MAX_TRIES)), verified, blocked};

const MAX_CERT_SIZE = 1000; // in bytes

type Certificate = Byte[0..MAX_CERT_SIZE];

const MAX_CERT_CHUNK_SIZE = 100; // in bytes

type CertificateChunk = Byte[1..MAX_CERT_CHUNK_SIZE];

const MAX_PROP_SIZE = 200; // in bytes

type Properties = Byte[0..MAX_PROP_SIZE];

type AppletState = enum {personalization, deployment, updating};

state {

RSAPrivateKey(KEY_SIZE) key,

KeyState keyState,

Pin pin,

PinState pinState,

Int(0,MAX_CERT_SIZE) certSize,

Certificate certificate,

Properties properties,

Int(0,MAX_CERT_SIZE) certBytesSent,

AppletState appletState

}

invariant appletState != deployment || (certBytesSent <= (certificate).length-1);

init() {

/* The current definition of SmartSlang requires every state component to be

initialized in the initialization block. This is a bit artificial for

certain state components that are really initialized by commands, e.g. keys,

forcing us to use meaningless values like all 0s. We may change the

definition of SmartSlang to no longer require all state components to be

initialized in the initialization block, while leaving the requirement that

every state component must be initialized before it is used for the first

time. Besides avoiding artificial initializations, this change would support

better semantic checking of the SmartSlang spec, because presumably a key

shouldn't be used before it is assigned a non-all-0s value. */

key = RSAPrivateKey(KEY_SIZE)

(repeat(0,KEY_SIZE/8), repeat(0,KEY_SIZE/8));

keyState = KeyState(false,false);

pin = repeat(0,8);

pinState = unset;

certSize = 0;

certificate = {};

properties = {};

certBytesSent = 0;

appletState = personalization;

} bytes {};

command putExponent(Byte[KEY_SIZE/8] exp) {

if (appletState == deployment) { respond SW_WRONG_STATE; }

key = RSAPrivateKey(KEY_SIZE) (exp, key.modulus);

keyState = KeyState (true, keyState.isModulusSet);

// we may extend SmartSlang with direct assignments to record components:

// key.exponent = exp;

// keyState.isExponentSet =true;

} apdu {CLA, INS_PUT_EXP, P1, P2, exp, 0};

command putModulus(Byte[KEY_SIZE/8] mod) {

if (appletState == deployment) { respond SW_WRONG_STATE; }

key = RSAPrivateKey(KEY_SIZE) (key.exponent, mod);

keyState = KeyState (keyState.isExponentSet, true);

} apdu {CLA, INS_PUT_MOD, P1, P2, mod, 0};

command putPIN(Pin p) {

if (appletState == deployment) { respond SW_WRONG_STATE; }

pin = p;

pinState = notVerified(MAX_TRIES);

} apdu {CLA, INS_PUT_PIN, P1, P2, p, 0};

command putCertificateSize(Int(1,MAX_CERT_SIZE) size) {

if (appletState == deployment) { respond SW_WRONG_STATE; }

certSize = size;

certificate = {};

} apdu {CLA, INS_CERT_SIZE, P1, P2, ubytes[2](size), 0};

command putCertificateChunk(CertificateChunk certChunk) {

if (appletState == deployment) { respond SW_WRONG_STATE; }

if (certSize == 0) { respond SW_CERT_SIZE_UNSET; }

if (certificate.length + certChunk.length > certSize)

{ respond SW_CERTIFICATE_TOO_LARGE; }

certificate = certificate ++ certChunk;

} apdu {CLA, INS_PUT_CERT, P1, P2, certChunk, 0};

command putProperties(Properties prop) {

if (appletState == deployment) { respond SW_WRONG_STATE; }

properties = prop;

} apdu {CLA, INS_PUT_PROP, P1, P2, prop, 0};

command unblockPIN() {

if (appletState != updating) { respond SW_WRONG_STATE; }

pinState = notVerified(MAX_TRIES);

} apdu {CLA, INS_UNBLOCK, P1, P2, {}, 0};

command deploy() {

if (appletState == deployment) { respond SW_WRONG_STATE; }

if (keyState == KeyState(true,true)

&& pinState != unset

&& certSize != 0

&& certificate.length == certSize

&& properties != {}) {

appletState = deployment;

} else {

respond SW_UNFINISHED_PERSONALIZATION;

}

} apdu {CLA, INS_DEPLOY, P1, P2, {}, 0};

command update() {

if (appletState != deployment) { respond SW_WRONG_STATE; }

appletState = updating;

} apdu {CLA, INS_UPDATE, P1, P2, {}, 0};

command getCertificateChunk() {

if (appletState != deployment) { respond SW_WRONG_STATE; }

CertificateChunk chunk;

if (certificate.length - certBytesSent >= MAX_CERT_CHUNK_SIZE) {

chunk = certificate[certBytesSent,MAX_CERT_CHUNK_SIZE];

certBytesSent = certBytesSent + MAX_CERT_CHUNK_SIZE;

} else {

chunk = certificate[certBytesSent..certificate.length-1];

certBytesSent = certificate.length;

}

if (certificate.length - certBytesSent >= MAX_CERT_CHUNK_SIZE) {

respond {chunk, SW1_MORE_DATA, MAX_CERT_CHUNK_SIZE};

} else if (certificate.length - certBytesSent > 0) {

respond {chunk, SW1_MORE_DATA, certificate.length - certBytesSent};

} else /* certificate.length == certBytesSent */ {

certBytesSent = 0; // reset

respondok chunk;

}

} apdu {CLA, INS_GET_CERT, P1, P2, {},

(certificate.length - certBytesSent >= MAX_CERT_CHUNK_SIZE) ?

MAX_CERT_CHUNK_SIZE : certificate.length - certBytesSent};

command getProperties() {

if (appletState != deployment) { respond SW_WRONG_STATE; }

respondok properties;

} apdu {CLA, INS_GET_PROP, P1, P2, {}, properties.length};

command pinVerify(Pin p) {

if (appletState != deployment) { respond SW_WRONG_STATE; }

switch (pinState) {

case verified: {

respondok;

}

case notVerified(triesLeft): {

if (p == pin) {

pinState = verified;

respondok;

} else if (triesLeft > 1) {

pinState = notVerified(triesLeft - 1);

respond {{}, SW1_WRONG_PIN, triesLeft};

} else {

pinState = blocked;

respond SW_PIN_BLOCKED;

}

}

case blocked: {

respond SW_PIN_BLOCKED;

}

case unset: {

// cannot happen -- could be proved using state invariants

}

}

} apdu {CLA, INS_VERIFY, P1, P2, p, 0};

command pinVerified() {

if (appletState != deployment) { respond SW_WRONG_STATE; }

switch (pinState) {

case verified: {

respondok;

}

case notVerified(triesLeft): {

respond {{}, SW1_TRIES_LEFT, triesLeft};

}

case blocked: {

respond SW_PIN_BLOCKED;

}

case unset: {

// cannot happen -- could be proved using state invariants

}

}

} apdu {CLA, INS_VERIFIED, P1, P2, {}, 0};

command privSignDecrypt(Message msg) {

if (appletState != deployment) { respond SW_WRONG_STATE; }

if (pinState != verified) {

respond SW_SECURITY_NOK;

} else {

respondok rsa(key,msg);

}

} apdu {CLA, INS_SIGN_DEC, P1, P2, msg, MSG_SIZE};

const CLA = 0x80;

const P1 = 0;

const P2 = 0;

const INS_PUT_EXP = 0x44;

const INS_PUT_MOD = 0x46;

const INS_PUT_PIN = 0x22;

const INS_CERT_SIZE = 0x3A;

const INS_PUT_CERT = 0x38;

const INS_PUT_PROP = 0x58;

const INS_UNBLOCK = 0x24;

const INS_DEPLOY = 0x70;

const INS_UPDATE = 0x72;

const INS_GET_CERT = 0x36;

const INS_GET_PROP = 0x56;

const INS_VERIFY = 0x20;

const INS_VERIFIED = 0x26;

const INS_SIGN_DEC = 0x42;

const SW_WRONG_STATE = 0x6985;

const SW_CERTIFICATE_TOO_LARGE = 0x6A80;

const SW_UNFINISHED_PERSONALIZATION = 0x6985;

const SW_PIN_BLOCKED = 0x6983;

const SW_SECURITY_NOK = 0x6982;

const SW_CERT_SIZE_UNSET = 0x6985;

const SW1_WRONG_PIN = 0x63;

const SW1_TRIES_LEFT = 0x63;

const SW1_MORE_DATA = 0x63;

select {

certBytesSent = 0; // reset

}

deselect {

if (pinState == verified) {

pinState = notVerified(MAX_TRIES);

}

}

= ~ 3

size(spec)

AUTOSMART

JavaCardcode

SmartSlang spec

(actual files; font size 1)


Towards certifiably correct java card applets

PKI

PKI Java Card code

...

static byte[] _aux1;

static Cipher rsaCipher;

...

rsaCipher = Cipher.getInstance(Cipher.ALG_RSA_NOPAD,false);

_aux1 = new byte[(short)128];

...

void privSignDecrypt (APDU apdu) {

byte[] buffer = apdu.getBuffer();

if ((buffer[ISO7816.OFFSET_P1] != 0) ||

(buffer[ISO7816.OFFSET_P2] != 0))

ISOException.throwIt(ISO7816.SW_WRONG_P1P2);

inDataLength = nonNegativeByte(buffer[ISO7816.OFFSET_LC]);

if (inDataLength != 128)

ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

receiveIncomingData(apdu);

Util.arrayCopy(inData,(short)0,msg,(short)0,inDataLength);

if (pinState.elem != PinState.verified)

ISOException.throwIt(SW_SECURITY_NOK);

else {

rsaCipher.init(key,Cipher.MODE_DECRYPT);

rsaCipher.doFinal(msg,(short)0,(short)128,_aux1,(short)0);

sendOutgoingData(apdu, _aux1);

return;

}

}

...

...

static byte[] _aux1;

static Cipher rsaCipher;

...

rsaCipher = Cipher.getInstance(Cipher.ALG_RSA_NOPAD,false);

_aux1 = new byte[(short)128];

...

void privSignDecrypt (APDU apdu) {

byte[] buffer = apdu.getBuffer();

if ((buffer[ISO7816.OFFSET_P1] != 0) ||

(buffer[ISO7816.OFFSET_P2] != 0))

ISOException.throwIt(ISO7816.SW_WRONG_P1P2);

inDataLength = nonNegativeByte(buffer[ISO7816.OFFSET_LC]);

if (inDataLength != 128)

ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

receiveIncomingData(apdu);

Util.arrayCopy(inData,(short)0,msg,(short)0,inDataLength);

if (pinState.elem != PinState.verified)

ISOException.throwIt(SW_SECURITY_NOK);

else {

rsaCipher.init(key,Cipher.MODE_DECRYPT);

rsaCipher.doFinal(msg,(short)0,(short)128,_aux1,(short)0);

sendOutgoingData(apdu, _aux1);

return;

}

}

...

Java

Card

code


Towards certifiably correct java card applets

PKI Java Card code

...

static byte[] _aux1;

static Cipher rsaCipher;

...

rsaCipher = Cipher.getInstance(Cipher.ALG_RSA_NOPAD,false);

_aux1 = new byte[(short)128];

...

void privSignDecrypt (APDU apdu) {

byte[] buffer = apdu.getBuffer();

if ((buffer[ISO7816.OFFSET_P1] != 0) ||

(buffer[ISO7816.OFFSET_P2] != 0))

ISOException.throwIt(ISO7816.SW_WRONG_P1P2);

inDataLength = nonNegativeByte(buffer[ISO7816.OFFSET_LC]);

if (inDataLength != 128)

ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

receiveIncomingData(apdu);

Util.arrayCopy(inData,(short)0,msg,(short)0,inDataLength);

if (pinState.elem != PinState.verified)

ISOException.throwIt(SW_SECURITY_NOK);

else {

rsaCipher.init(key,Cipher.MODE_DECRYPT);

rsaCipher.doFinal(msg,(short)0,(short)128,_aux1,(short)0);

sendOutgoingData(apdu, _aux1);

return;

}

}

...

intermediate

storage

pre-allocation

APDUchecking& decoding

arrays accessed withinbounds by construction

interestingcomputation

code for “respondok decrypt(key,msg)”


Towards certifiably correct java card applets

SmartSlang counterpart

command privSignDecrypt(Message msg) {

if (pinState != verified) {

respond SW_SECURITY_NOK;

} else {

respondok decrypt(key,msg);

}

} apdu {0x80,0x42,0,0,msg,1024/8};


Towards certifiably correct java card applets

SmartSlang example: PIN construct

SmartSlang


Towards certifiably correct java card applets

SmartSlang example: PIN construct

(under design)

identifier (there may be multiple PINs)

pin p {

length 8;

maxtries 3;

protect {privSignDecrypt,

getCertificate};

apdu verify {0x80,0x20,0,0};

apdu set {0x80,0x22,0,0} secure;

}

in bytes (determines strength)

before blocking

commands that requirePIN to be verified first

APDU header for

command to verify

PIN (data = PIN)

APDU header for

command to (re)set

PIN (data = PIN)

use secure channel

implicit state variables, commands,and checks in other commands

(tentative syntax)


Towards certifiably correct java card applets

SmartSlang example: PIN construct

(under design)

code

= ~7–8

spec

pin p {

length 8;

maxtries 3;

protect {privSignDecrypt,

getCertificate};

apdu verify {0x80,0x20,0,0};

apdu set {0x80,0x22,0,0} secure;

}

pin p {

length 8;

maxtries 3;

protect {privSignDecrypt,

getCertificate};

apdu verify {0x80,0x20,0,0};

apdu set {0x80,0x22,0,0} secure;

}

  • similar high-level constructs planned for

  • challenge-response authentication

  • piecewise data read/write

  • key establishment

estimated


Towards certifiably correct java card applets

SmartSlang

is SmartSlang just a macro language?

is AutoSmart just a macro expander?


Towards certifiably correct java card applets

is SmartSlang just a macro language?

is AutoSmart just a macro expander?

NO:

  • expressive types, statically checked

  • automated reasoning

  • automatic static storage management by type analysis

  • APDU decoding/checking

  • non-local mapping of spec constructs into code


Towards certifiably correct java card applets

inside AutoSmart

AutoSmart

applet

spec

applet

code

AUTOSMART


Towards certifiably correct java card applets

SPEC

CHECKER

CODE

GENERATOR

inside AutoSmart

applet

spec

applet

code

AUTOSMART


Towards certifiably correct java card applets

checked

applet

spec

parses spec

parser generated from grammarvia our own parser generator

checks type safety

includes Fourier-Motzkin decisionprocedure for linear arithmetic

checks other properties

e.g. restrictions to allow generationof code to check and decode APDUs

applet

spec

SPEC

CHECKER


Towards certifiably correct java card applets

checked

applet

spec

formal relationship

CODE GENERATOR

applet

code

provable correctness?

SmartSlang

semanticsin logic

Java Card

semanticsin logic

SMARTSLANG

LOGIC

JAVA CARD

LOGIC

SmartSlang

applet representedin logic

Java Card

applet representedin logic

provable correctness


Towards certifiably correct java card applets

applet represented

in logic

applet represented

in logic

applet represented

in logic


Towards certifiably correct java card applets

applet represented

in logic

Metaslang, thespecification languageof

which is a form ofhigher-order logic

other choices are possible


Towards certifiably correct java card applets

?

applet represented

in logic


Towards certifiably correct java card applets

applet

applet


Towards certifiably correct java card applets

selection

command (APDU)

initialization(w/ params.)

response (APDU)

deselection

applet

what is observable?


Towards certifiably correct java card applets

including erroneous ones

selection

applet

command (APDU)

initialization(w/ params.)

response (APDU)

deselection

type Event = | initialize InitParam

| process Command * Response

| select

| deselect

type Command = ...

type Response = ...

type InitParam = ...


Towards certifiably correct java card applets

selection

applet

command (APDU)

initialization(w/ params.)

response (APDU)

deselection

type Event = | initialize InitParam

| process Command * Response

| select

| deselect

type Trace = (Nat -> Event) | orderOK?

type Trace = Nat -> Event

op orderOK? : (Nat -> Event) -> Boolean

def orderOK? tr =

embed? initialize (tr 0) &&

...


Towards certifiably correct java card applets

selection

applet

command (APDU)

initialization(w/ params.)

response (APDU)

deselection

type Event = | initialize InitParam

| process Command * Response

| select

| deselect

type Trace = (Nat -> Event) | orderOK?

type Applet = Set Trace

type Set a = a -> Boolean


Towards certifiably correct java card applets

Applets = spec

type Event = | initialize InitParam

| process Command * Response

| select

| deselect

type Trace = (Nat -> Event) | orderOK?

type Applet = Set Trace

endspec


Towards certifiably correct java card applets

Applets = spec

type Event = | initialize InitParam

| process Command * Response

| select

| deselect

type Trace = (Nat -> Event) | orderOK?

type Applet = Set Trace

endspec

Applet = spec

import Applets

op applet : Applet

def applet = ...

endspec


Towards certifiably correct java card applets

Applet = spec

import Applets

type Aux

op aux : Aux

...

op applet : Applet

def applet = ...

endspec

Applet’ = spec

import Applets

type Aux’

op aux’ : Aux’

...

op applet’ : Applet

def applet’ = ...

endspec


Towards certifiably correct java card applets

Applet = spec

import Applets

type Aux

op aux : Aux

...

op applet : Applet

def applet = ...

endspec

Applet’ = spec

import Applets

type Aux’

op aux’ : Aux’

...

op applet’ : Applet

def applet’ = ...

endspec

Applet = spec

import Applets

type Aux

op aux : Aux

...

op applet : Applet

def applet = ...

endspec

Applet’ = spec

import Applets

type Aux’

op aux’ : Aux’

...

op applet’ : Applet

def applet’ = ...

endspec


Towards certifiably correct java card applets

Applet = spec

import Applets

type Aux

op aux : Aux

...

op applet : Applet

def applet = ...

endspec

Applet’ = spec

import Applets

type Aux’

op aux’ : Aux’

...

op applet’ : Applet

def applet’ = ...

endspec

FormalRelationship = spec

endspec


Towards certifiably correct java card applets

Applet = spec

import Applets

type Aux

op aux : Aux

...

op applet : Applet

def applet = ...

endspec

Applet’ = spec

import Applets

type Aux’

op aux’ : Aux’

...

op applet’ : Applet

def applet’ = ...

endspec

FormalRelationship = spec

import Applet

endspec


Towards certifiably correct java card applets

Applet’ = spec

import Applets

type Aux’

op aux’ : Aux’

...

op applet’ : Applet

def applet’ = ...

endspec

FormalRelationship = spec

import Applet, Applet’

endspec


Towards certifiably correct java card applets

applets have sameobservable behavior

FormalRelationship = spec

import Applet, Applet’

theorem applet = applet’

endspec


Towards certifiably correct java card applets

Applet = spec

import Applets

type Aux

op aux : Aux

...

op applet : Applet

def applet = ...

endspec

defined in termsof SmartSlang

FormalRelationship = spec

import Applet, Applet’

theorem applet = applet’

endspec


Towards certifiably correct java card applets

SmartSlang

SmartSlang


Towards certifiably correct java card applets

SmartSlang = spec

(abstract)

syntax

static

semantics

dynamic

semantics

endspec

SmartSlang

(simplified)

type Expression = ...

type Statement = ...

type Command = ...

...

type Spec = ...

op wellFormed? : Spec -> Boolean

def wellFormed? = ...

type WFSpec = Spec | wellFormed?

type Value = ...

type State = ...

op expSem : Expression -> (State -> Value)

op stmSem : Statement -> (State -> State)

...


Towards certifiably correct java card applets

SmartSlang = spec

type Expression = ...

type Statement = ...

type Command = ...

...

type Spec = ...

op wellFormed? : Spec -> Boolean

def wellFormed? = ...

type WFSpec = Spec | wellFormed?

type Value = ...

type State = ...

op expSem : Expression -> (State -> Value)

op stmSem : Statement -> (State -> State)

...

endspec

SSApplets = spec

import SmartSlang

endspec


Towards certifiably correct java card applets

Applets = spec

type Event = ...

type Trace = ...

type Applet = ...

endspec

SSApplets = spec

import SmartSlang, Applets

endspec


Towards certifiably correct java card applets

SSApplets = spec

import SmartSlang, Applets

op appletOf : WFSpec -> Applet

def appletOf = ...

endspec

SSApplet = spec

import SSApplets

op appletSpec : WFSpec

def appletSpec = ...

op applet : Applet

def applet = appletOf appletSpec

endspec


Towards certifiably correct java card applets

SSApplets = spec

import SmartSlang, Applets

op appletOf : WFSpec -> Applet

def appletOf = ...

endspec

SSApplet = spec

import SSApplets

op appletSpec : WFSpec

def appletSpec = ...

op applet : Applet

def applet = appletOf appletSpec

endspec


Towards certifiably correct java card applets

abstract

syntax

tree

PARSER

META

Metaslang

expression

e:Spec

+

1

x

SmartSlang

spec

(.ssl file)

x+1

plus(var “x”,

const 1)

SSApplet = spec

import SSApplets

op appletSpec : WFSpec

def appletSpec = ...

op applet : Applet

def applet = appletOf appletSpec

endspec


Towards certifiably correct java card applets

abstract

syntax

tree

SmartSlang

spec

PARSER

META

(.ssl file)

Metaslang

expression

e:Spec

SSApplet = spec

import SSApplets

op appletSpec : WFSpec

def appletSpec = ...

op applet : Applet

def applet = appletOf appletSpec

endspec

COPY &PASTE


Towards certifiably correct java card applets

abstract

syntax

tree

PARSER

META

Metaslang

expression

e:Spec

SmartSlang

spec

(.ssl file)

Spec

e

SSApplet = spec

import SSApplets

op appletSpec : WFSpec

def appletSpec =

op applet : Applet

def applet = appletOf appletSpec

endspec

COPY &PASTE

WFSpec

WFSpec < Spec

subtype proof obligation:

wellFormed? e


Towards certifiably correct java card applets

abstract

syntax

tree

SmartSlang

spec

PARSER

META

SSMS

Metaslang

expression

e:Spec

Metaslang

spec

proof

obligation

SSApplet = spec

import SSApplets

op appletSpec : WFSpec

def appletSpec = e

op applet : Applet

def applet = appletOf appletSpec

endspec

COPY &PASTE


Towards certifiably correct java card applets

(previously showed)

formal relationship

AUTOSMART

applet

spec

applet

code

SmartSlang

semanticsin logic

Java Card

semanticsin logic

SMARTSLANG

LOGIC

JAVA CARD

LOGIC

SmartSlang

applet representedin logic

Java Card

applet representedin logic

provable correctness


Towards certifiably correct java card applets

(previously showed)

formal relationship

AUTOSMART

applet

spec

applet

code

SmartSlang

semanticsin logic

Java Card

semanticsin logic

SMARTSLANG

LOGIC

JAVA CARD

LOGIC

fixed

SmartSlang

applet representedin logic

Java Card

applet representedin logic

provable correctness


Towards certifiably correct java card applets

formal relationship

AUTOSMART

applet

spec

applet

code

Java Card

semanticsin logic

SMARTSLANG

LOGIC

JAVA CARD

LOGIC

SmartSlang

applet representedin logic

Java Card

applet representedin logic

provable correctness


Towards certifiably correct java card applets

same for Java Card

Java Card


Towards certifiably correct java card applets

same for Java Card

JavaCard = spec

type Expression = ...

type Statement = ...

...

type Program = ...

op wellFormed? : Program -> Boolean

def wellFormed? = ...

op WFProgram = Program | wellFormed?

type Object = ...

type Heap = ...

type State = ...

type Exception = ...

op expSem : Expression -> ...

op stmSem : Statement -> ...

...

endspec

JCApplets = spec

import JavaCard, Applets

op appletOf : WFProgram -> Applet

def appletOf = ...

endspec

JCApplet = spec

import JCApplets

op appletPrg : WFProgram

def appletPrg = ...

op applet : Applet

def applet = appletOf appletPrg

endspec


Towards certifiably correct java card applets

abstract

syntax

tree

PARSER

META

Metaslang

expression

e:Program

same for Java Card

Java Card

program

(.java file)

JCApplet = spec

import JCApplets

op appletPrg : WFProgram

def appletPrg = ...

op applet : Applet

def applet = appletOf appletPrg

endspec

COPY &PASTE


Towards certifiably correct java card applets

abstract

syntax

tree

PARSER

META

Metaslang

expression

e:Program

same for Java Card

Java Card

program

(.java file)

Program

e

JCApplet = spec

import JCApplets

op appletPrg : WFProgram

def appletPrg =

op applet : Applet

def applet = appletOf appletPrg

endspec

COPY &PASTE

WFProgram

WFProgram < Program

subtype proof obligation:

wellFormed? e


Towards certifiably correct java card applets

same for Java Card

abstract

syntax

tree

Java Card

program

PARSER

META

JCMS

Metaslang

expression

e:Program

Metaslang

spec

proof

obligation

JCApplet = spec

import JCApplets

op appletPrg : WFProgram

def appletPrg = restrict e

op applet : Applet

def applet = appletOf appletPrg

endspec

COPY &PASTE


Towards certifiably correct java card applets

(previously showed)

AUTOSMART

SmartSlang

spec

Java Card

program

proof

CHECKER

how does itwork exactly?

yes/no


Towards certifiably correct java card applets

CHECKER

AUTOSMART

AUTOSMART

CHECKER

(not to scale)


Towards certifiably correct java card applets

CHECKER

SS

AUTOSMART

JC


Towards certifiably correct java card applets

CHECKER

SS

SS  MS

AUTOSMART

WELL-FORMED?

prf

MS

SPECCHECKER

y/n

prf

=BEHAVIOR?

AND

y/n

y/n

CODEGENERATOR

y/n

WELL-FORMED?

prf

MS

JC

JC  MS


Towards certifiably correct java card applets

CHECKER

SS

AUTOSMART

prf

prf

y/n

prf

JC


Towards certifiably correct java card applets

CHECKER

SS

prf

y/n

simple?

JC


Towards certifiably correct java card applets

CHECKER

SS

SS  MS

proof checkerfor Metaslang

WELL-FORMED?

MS

(unavoidable)

y/n

trivial

prf

=BEHAVIOR?

AND

y/n

y/n

y/n

WELL-FORMED?

MS

JC

JC  MS


Towards certifiably correct java card applets

SS  MS

SS/JCMS

SS/JC

MS

JC  MS


Towards certifiably correct java card applets

PARSER

META

COPY &PASTE

SS/JC

MS

relativelysimple

verysimple

trivial

can be made simpler…


Towards certifiably correct java card applets

(previously showed)

SmartSlang = spec

type Expression = ...

type Statement = ...

type Command = ...

...

type Spec = ...

op wellFormed? : Spec -> Boolean

def wellFormed? = ...

type WFSpec = Spec | wellFormed?

type Value = ...

type State = ...

op expSem : Expression -> (State -> Value)

op stmSem : Statement -> (State -> State)

...

endspec

SmartSlang’ = spec

import SmartSlang

endspec


Towards certifiably correct java card applets

SmartSlang’ = spec

import SmartSlang

op parse : String -> Option Spec

def parse = ...

endspec


Towards certifiably correct java card applets

SmartSlang’ = spec

import SmartSlang

op parse : String -> Option Spec

def parse = ...

op denotesWFSpec? : String -> Boolean

def denotesWFSpec? str =

case parse str of

| Some spc -> wellFormed? spc

| None -> false

endspec


Towards certifiably correct java card applets

SmartSlang’ = spec

import SmartSlang

op parse : String -> Option Spec

def parse = ...

op denotesWFSpec? : String -> Boolean

def denotesWFSpec? str =

case parse str of

| Some spc -> wellFormed? spc

| None -> false

type WFSpecString = String | denotesWFSpec?

endspec

SSApplets’ = spec

import SmartSlang’, Applets

endspec


Towards certifiably correct java card applets

SSApplets’ = spec

import SmartSlang’, Applets

op appletOf : WFSpecString -> Applet

def appletOf = ...

endspec

SSApplet’ = spec

import SSApplets’

op appletStr : WFSpecString

def appletStr = ...

op applet : Applet

def applet = appletOf appletStr

endspec

as before but

spec  string


Towards certifiably correct java card applets

SmartSlang

spec

SSApplet’ = spec

import SSApplets’

op appletStr : WFSpecString

def appletStr = ...

op applet : Applet

def applet = appletOf appletStr

endspec


Towards certifiably correct java card applets

subtype proof obligation:

denotesWFSpec? “ ”

SmartSlang

spec

SmartSlang

spec

SmartSlang

spec

SSMS

SSApplet’ = spec

import SSApplets’

op appletStr : WFSpecString

def appletStr = “ ”

op applet : Applet

def applet = appletOf appletStr

endspec


Towards certifiably correct java card applets

SmartSlang

spec

SmartSlang

spec

trivialcopy &paste

SSMS

Metaslang

spec

SSApplet’ = spec

import SSApplets’

op appletStr : WFSpecString

def appletStr = “ ”

op applet : Applet

def applet = appletOf appletStr

endspec

SmartSlang

spec


Towards certifiably correct java card applets

SmartSlang

spec

SmartSlang

spec

SmartSlang

spec

Java Card

program

trivialcopy &paste

SSMS

JCMS

Metaslang

spec

Metaslang

spec

proof obligations include parsing


Towards certifiably correct java card applets

(previously showed)

AUTOSMART

SPECCHECKER

CODEGENERATOR

SS

JC

SSMS

prf

WELL-FORMED?

MS

y/n


Towards certifiably correct java card applets

AUTOSMART

SPECCHECKER

CODEGENERATOR

SS

JC


Towards certifiably correct java card applets

(checked)

CODEGENERATOR

SS

JC

JCMS

prf

prf

WELL-FORMED?

y/n

MS


Towards certifiably correct java card applets

(checked)

CODEGENERATOR

SS

JC

SSMS

JCMS

prf

=BEHAVIOR?

MS

MS

y/n


Towards certifiably correct java card applets

CODEGENERATOR

SS

JC

CODEGENERATOR

proof


Towards certifiably correct java card applets

CODEGENERATOR

STEP 1

STEP 2

SS

JC

+

proof


Towards certifiably correct java card applets

more steps  easier proofs

CODEGENERATOR

STEP 1

STEP 2

STEP 3

STEP 4

SS

JC

+

proof


Towards certifiably correct java card applets

STEP 1

STEP 2

STEP n

STEP 3

. . . . . . . . . . .

SS

JC

withinSmartSlang

languagechange

withinJava Card

declarativetransformations?


Towards certifiably correct java card applets

example of transformation & proof

transformation


Towards certifiably correct java card applets

x+0x

e.g.

expSem e = expSem e’

applet = applet’

example of transformation & proof

ee’

(SS or JC expressions)

(proof depends on e and e’)

fa(a,x,y) expSem x = expSem y =>appletOf a = appletOf a[x/y]

(proved onceand for all)

instantiation + modus ponens


Towards certifiably correct java card applets

approach is more general

than smart card applets

L1L2

L1

L2

languages L1 & L2

translation L1L2

(possibly L1 = L2)

e.g.

  • compilers

  • code generators

  • theorem prover interfaces


  • Login