Formal specification of Gemplus’ electronic purse case study Néstor Cataño & Marieke Huisman INRIA Sophia-Antipolis {ncatano,
The electronic purse Developed by trainee at Gemplus Goal: develop more complex application, using object-oriented features Revision by members research lab and new trainee Result: not completely finished, not fully representative
Software documentation Management & history of the development Clear, concise and unambiguous Correspondance with implementation
Some Fragments from LoyaltiesTable // huge modifications on 31/07/2000 // now, we handle AID objects instead of byte arrays that represents them. // that way, we gain some space, and code is clearer. /* the purse stores in this object the loyalties that are allowed to communicate with it*/ class LoyaltiesTable { //////////////// ATTRIBUTES //////////////// // temporarily modified by RM on 26/07/2000 for memory reason //private final static byte NB_MAX = (byte)20; private final static byte NB_MAX = (byte)3; … /* suppress all the entries of the loyalty specified by aid */ void delLoyalty(AID aid) {…} … /* suppress the notification of the loyalty specified by aid*/ void removeNotification(AID aid) {…}
Software documentation Management & history of the development Clear, concise and unambiguous Correspondance with implementation Formal specification And verification Difficult and labour-intensive
This talk Different approaches to formal specification and verification Static checking (lightweight formal methods) The electronic purse case study Static checking of the electronic purse: class invariants
Specification language Close to programming language Expressions from programming language Eiffel, JML, ESC/Java, Jass with specification-specific constructs (forall, exists, implication etc.)
Checking techniques Run-time checking Full verification (syntactic or semantic) (Eiffel, JML, Jass) (Jive) (LOOP) Static checking (ESC/Java)
Static checking with ESC/Java Compaq Research (Leino et al.) Focus on finding common program errors (nullpointers, array index out of bounds) Proof obligations to dedicated theorem prover (assume - assert pairs) Issues warnings
Static checking with ESC/Java ESC/Java = Compromise between soundness, completeness, and efficiency
ESC/Java pragmas Preconditions (requires) Postconditions (ensures) Exceptional postconditions (exsures) Modifies clause Class invariants Implication, quantification Value expression in pre-state (\old(E)) Result value of method (\result)
The electronic purse Supports debit, credit and currency change operations Interaction with loyalty, card issuer and terminal Packages: utils, pacapinterfaces and purse
The purse package PurseApplet: installation, (de)selection, communication with terminal Purse: –implements basic functionalities –keeps track of balance, transactions, currency changes, loyalties
The purse package AccessControl: restricted set of users for certain operations Currencies Cryptographic concepts
Writing the specification For each method: requires, ensures, exsures, modifies First basic classes (utils), then more application-specific Appropriate class invariants, e.g. restricting domain of instance variables
Writing the specification Discrepancies between documentation and implementation
Writing the specification Discrepancies between documentation and implementation
Writing the specification Discrepancies between documentation and implementation Usage of existing API specification
Writing the specification Discrepancies between documentation and implementation Usage of existing API specification.spec files for e.g. visa and crypto classes
Writing the specification Discrepancies between documentation and implementation Usage of existing API specification.spec files for e.g. visa and crypto classes Avoid warnings as much as possible, but still full specification
Class invariants Restrict state space of a class –reference never null pointer invariant purse != null; –variable within a certain range invariant decPart >= 0 && decPart < PRECISION; invariant intPart >= 0 && intPart < MAX_DECIMAL_NUMBER; */ Easy to write, easy to check
Enumeration types /* the transaction status*/ public static final byte INDETERMINE= (byte)0;... /* the transaction status*/ public static final byte TYPE_CREDIT= (byte)50; /* the transaction status*/ public static final byte TYPE_DEBIT= (byte)51;... /* the transaction type: debit or credit*/ private byte type;... /* set all this transaction attributes to 0*/void reset() { isValid = false; number = (short)0; type = INDETERMINE; typeProduit = (short)0;... }
/* the transaction type: debit or credit*/ private byte type;... /* set all this transaction attributes to 0*/ void reset() { isValid = false; number = (short)0; type = INDETERMINE; typeProduit = (short)0;... }
public AccessCondition() { super(); // commented by Rodolphe Muller on 16/06/2000 // strange to set the condition here to 0 and to // FREE above setCondition((byte)0); } Enumeration types invariant condition == FREE || condition == LOCKED || condition == SECRET_CODE || condition == SECURE_MESSAGING || condition == (SECRET_CODE | SECURE_MESSAGING) */ public AccessCondition() { super(); // commented by Rodolphe Muller on 16/06/2000 // strange to set the condition here to 0 and to // FREE above setCondition((byte)0); } public AccessCondition() { super(); // commented by Rodolphe Muller on 16/06/2000 // strange to set the condition here to 0 and to // FREE above setCondition((byte)0); } NB. FREE == (byte)1;
switch(condition) { case FREE:... case SECRET_CODE:... case SECURE_MESSAGING:... case SECRET_CODE | SECURE_MESSAGING:... case LOCKED:... default: assert false; t = AccessConditionException.C_C_INVALIDE; AccessConditionException.throwIt(t); } Avoiding dead code switch(condition) { case FREE:... case SECRET_CODE:... case SECURE_MESSAGING:... case SECRET_CODE | SECURE_MESSAGING:... case LOCKED:... default: t = AccessConditionException.C_C_INVALIDE; AccessConditionException.throwIt(t); }
Other problems Incorrect coding Forgetting variable modifiers (final) Underspecified documentation Is MAX_DECIMAL_NUMBER.999 legal? And how do you round it? Superfluous methods (isNegatif()) Complex and undocumented datastructures (with incorrect corrections)
Complete specification Available from verificard/electronic_purse
Conclusions Using lightweight formal methods, applications can be improved Class invariants make implicit assumptions explicit and check them Case study convinced Gemplus to look at JML and ESC/Java ESC/Java useful, but possibilities for improvement
Complete specification Available from verificard/electronic_purse
Writing the specification modifies M; requires true; ensures Q; exsures (E) !P; */ void m () {... }
Writing the specification Offensive modifies M; requires P; ensures Q; exsures (E) false; */ void m () {... } Defensive modifies M; requires true; ensures Q; exsures (E) !P; */ void m () {... }
Experiences with ESC/Java Pleasant tool, easy to work with Specifications written by non- experienced user Two/three months work all together
Suggestions for ESC/Java specification language Richer specification language modifies \nothing, modifies \field_of(E) Extra quantifiers Run-time exceptions without explicit throws clause Use of pure methods in specifications
modifies sessionNumber, date.jour, date.mois, date.annee, heure.heure, heure.minute; modifies ancienneDevise, nouvelleDevise, isValid, status; modifies id[*], terminalTC[*], terminalSN[*] ; requires es != null ; requires es.id != terminalTC & es.id != terminalSN & es.terminalTC != terminalSN; ensures sessionNumber == es.sessionNumber ; ensures ancienneDevise == es.ancienneDevise ; ensures nouvelleDevise == es.nouvelleDevise ; ensures isValid == es.isValid ; ensures status == es.status ; ensures (\forall int i;0 es.id[i] == id[i]); ensures (\forall int i;0 es.terminalTC[i] == terminalTC[i]); ensures (\forall int i;0 es.terminalSN[i] == terminalSN[i]); exsures (TransactionException e) e._reason == TransactionException.BUFFER_FULL && JCSystem._transactionDepth == 1; exsures (NullPointerException) false; exsures (ArrayIndexOutOfBoundsException) false; modifies sessionNumber, date.jour, date.mois, date.annee, heure.heure, heure.minute; modifies ancienneDevise, nouvelleDevise, isValid, status; modifies id[*], terminalTC[*], terminalSN[*] ; requires es != null ; requires es.id != terminalTC & es.id != terminalSN & es.terminalTC != terminalSN; ensures sessionNumber == es.sessionNumber ; ensures ancienneDevise == es.ancienneDevise ; ensures nouvelleDevise == es.nouvelleDevise ; ensures isValid == es.isValid ; ensures status == es.status ; ensures (\forall int i;0 es.id[i] == id[i]); ensures (\forall int i;0 es.terminalTC[i] == terminalTC[i]); ensures (\forall int i;0 es.terminalSN[i] == terminalSN[i]); exsures (TransactionException e) e._reason == TransactionException.BUFFER_FULL && JCSystem._transactionDepth == 1; exsures (NullPointerException) false; exsures (ArrayIndexOutOfBoundsException) false; Example specification
And as we would like it to be... modifies sessionNumber, date.jour, date.mois, date.annee, heure.heure, heure.minute; modifies ancienneDevise, nouvelleDevise, isValid, status; modifies id[*], terminalTC[*], terminalSN[*] ; requires es != null ; requires es.id != terminalTC & es.id != terminalSN & es.terminalTC != terminalSN; ensures this.equal(es); exsures (TransactionException e) e._reason == TransactionException.BUFFER_FULL && JCSystem._transactionDepth == 1; exsures (NullPointerException) false; exsures (ArrayIndexOutOfBoundsException) false;
Verification of modifies clauses modifies x; ensures x == 3; */ void m() { x = 3; n (); } void n() { x = 4; } Missing modifies clause Specification accepted NO
Modifies clauses Implementation of modifiable checker Extension of JML Static checking technique, based on syntax Neither sound, nor complete Fully described in separate paper (ask Néstor or me)
Future work Develop application with annotations from scratch Extension to multi-threading Automated verification technique for termination of loops Cryptographic aspects of the specification