FileDocCategorySizeDatePackage
BrokerApplet.javaAPI DocJava Card32623Wed Mar 22 21:07:22 GMT 2006com.sun.javacard.samples.utilitydemo

BrokerApplet.java

/*
 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */


package com.sun.javacard.samples.utilitydemo;

import javacard.framework.*;
import javacardx.framework.math.*;
import javacardx.framework.tlv.*;
import javacardx.framework.util.intx.JCint;

/**
 * This class demonstrates usage of new Utility APIs including APIs for TLV
 * integer manipulation and big number math API
 */
public class BrokerApplet extends Applet{
    /**
     * Initial account balance
     */
    final static byte[] INITIAL_ACCOUNT_BALANCE = 
                {(byte)0x01, (byte)0x00, (byte)0x00, 
                 (byte)0x00, (byte)0x00, (byte)0x00 };
    /**
     * INS value for ISO 7816-4 VERIFY command
     */
    final static byte VERIFY = (byte) 0x20;
    
    /**
     * INS value to get complete portfolio
     */
    final static byte GET_COMPLETE_PORTFOLIO = (byte)0x01;
    
    /**
     * INS value to get information on a stock
     */
    final static byte GET_STOCK_INFO = (byte)0x02;

    /**
     * INS value to generate a stock purchase request for the broker
     */
    final static byte BUY_STOCK = (byte)0x03;
    
    /**
     * INS value to generate a sell stocks request for the broker
     */
    final static byte SELL_STOCK = (byte)0x04;
    
    /**
     * INS value to update the portfolio
     */
    final static byte UPDATE_PORTFOLIO = (byte)0x05;
    
    /**
     * INS value to get balance
     */
    final static byte GET_BALANCE = (byte)0x06;

    /**
     * Length of a stock symbol
     */
    final static byte STOCK_SYMBOL_LENGTH = (byte)5;
    
    /**
     * Maximum number of incorrect tries before the PIN is blocked
     */
    final static byte MAX_PIN_TRIES = (byte) 0x03;

    /**
     * Maximum PIN size
     */
    final static byte MAX_PIN_SIZE = (byte) 0x08;

    /**
     * SW bytes for PIN verification failure
     */
    final static short SW_VERIFICATION_FAILED = 0x6300;
    
    /**
     * SW bytes for No stock info found
     */
    final static short SW_STOCK_NOT_FOUND = 0x6301;

    /**
     * SW bytes for Not enough account balance
     */
    final static short SW_NOT_ENOUGH_ACCOUNT_BALANCE = 0x6302;

    /**
     * SW bytes for not enough stocks to sell
     */
    final static short SW_NOT_ENOUGH_STOCKS_TO_SELL = 0x6303;

    /**
     * SW bytes for malformed broker confirmation
     */
    final static short INVALID_BROKER_CONFIRMATION = 0x6304;
    
    /**
     * SW bytes for invalid broker signature
     */
    final static short INVALID_BROKER_SIGNATURE = 0x6305;
    
    /**
     * SW bytes for TLV Exception
     */
    final static short TLV_EXCEPTION = 0x6306;

    /**
     * SW bytes for Arithmetic exception
     */
    final static short ARITHMETIC_EXCEPTION = 0x6307;

    /**
     * SW bytes for Arithmetic exception
     */
    final static short INVALID_NUMBER_FORMAT = 0x6308;

    /**
     * The user PIN
     */
    private OwnerPIN pin;
    
    /**
     * Amount of money in user's account 
     */
    private BigNumber accountBalance;
    
    /**
     * This constructed BER TLV holds the portfolio
     */
    private ConstructedBERTLV portfolio;
    
    /**
     * dummy broker signature 
     */
    private static final byte[] dummySignature = {(byte)0x88, (byte)0x88,
                                                  (byte)0x88, (byte)0x88,
                                                  (byte)0x88, (byte)0x88,
                                                  (byte)0x88, (byte)0x88};
    
    /**
     * constructed BER TLV Tag for portfolio
     */
    ConstructedBERTag portfolioTag;

    /**
     * constructed BER TLV Tag stock informaiton
     */
    ConstructedBERTag stockInfoTag;
    
    /**
     * constructed BER TLV Tag for sell stock request for broker
     */
    ConstructedBERTag sellStockReqTag;

    /**
     * constructed BER TLV Tag for stock purchase request for broker
     */
    ConstructedBERTag buyStockReqTag;
    
    /**
     * constructed BER TLV Tag for stock purchase confirmation from broker
     */
    ConstructedBERTag purchaseConfirmTag;
    
    /**
     * constructed BER TLV Tag for sell stock confirmation from broker
     */
    ConstructedBERTag sellConfirmTag;
    
    /**
     * constructed BER TLV Tag for last trade information
     */
    ConstructedBERTag lastTradeTag;
    
    /**
     * Primitive BER TLV Tag for number of stocks 
     */
    PrimitiveBERTag numStocksTag;
    /**
     * Primitive BER TLV Tag for price information
     */
    PrimitiveBERTag priceTag;
    /**
     * Primitive BER TLV Tag for stock symbol information
     */
    PrimitiveBERTag symbolTag;
    /**
     * Primitive BER TLV Tag for broker signature
     */
    PrimitiveBERTag signatureTag;
            
    /**
     * Big number for temporary calculations
     */
    BigNumber tempBigNum;
    
    /**
     * temporary buffer used as scratch space
     */
    byte[] scratchSpace;
        
    /**
     * The constructor
     * @param bArray input array
     * @param bOffset is the offset in input array
     * @param bLength input array length
     */
    BrokerApplet(byte[] bArray, short bOffset, byte bLength) {
        byte aidLen = bArray[bOffset]; // aid length
        if (aidLen == (byte) 0) {
            register();
        } else {
            register(bArray, (short) (bOffset + 1), aidLen);
        }

        // Ignore control info
        bOffset = (short) (bOffset + aidLen + 1);
        byte infoLen = bArray[bOffset]; // control info length
        bOffset = (short) (bOffset + infoLen + 1);

        byte paramLen = bArray[bOffset++]; // applet parameters length

        // Retrieve PIN initialization value from installation parameters

        if (paramLen > MAX_PIN_SIZE) {
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
        }

        // Retrieve the PIN
        pin = new OwnerPIN(MAX_PIN_TRIES, MAX_PIN_SIZE);
        pin.update(bArray, bOffset, (byte)(paramLen));
        
        // initialize account balance to 100,000.00
        accountBalance = new BigNumber((byte)8);
        accountBalance.init(INITIAL_ACCOUNT_BALANCE, (byte)0, 
                (byte)INITIAL_ACCOUNT_BALANCE.length, BigNumber.FORMAT_BCD);
        
        // initialize the temporary big number
        tempBigNum = new BigNumber(BigNumber.getMaxBytesSupported());
        
        // initialize primitive tags
        initPrimitiveTags();
        
        // initialize constructed tags
        initConstructedTags();
        
        // initialize the scratchSpace 
        scratchSpace = JCSystem.makeTransientByteArray((short)10, 
                                            JCSystem.CLEAR_ON_DESELECT);
        
        // create an empty portfolio 
        portfolioTag.toBytes(scratchSpace, (short)0);
        portfolio = (ConstructedBERTLV)BERTLV.getInstance(scratchSpace, 
                                                            (short)0, (short)2);
    }

    /**
     * Initialize the constructed tags
     */
    private void initConstructedTags(){
        portfolioTag = new ConstructedBERTag();
        stockInfoTag = new ConstructedBERTag();
        sellStockReqTag = new ConstructedBERTag();
        buyStockReqTag = new ConstructedBERTag();
        purchaseConfirmTag = new ConstructedBERTag();
        sellConfirmTag = new ConstructedBERTag();
        lastTradeTag = new ConstructedBERTag();
                
        portfolioTag.init((byte)3, (short)1);
        stockInfoTag.init((byte)3, (short)2);
        sellStockReqTag.init((byte)3, (short)3);
        buyStockReqTag.init((byte)3, (short)4);
        sellConfirmTag.init((byte)3, (short)5);
        purchaseConfirmTag.init((byte)3, (short)6);
        lastTradeTag.init((byte)3, (short)7);
    }    

    /**
     * Initialize the primitive tags
     */
    private void initPrimitiveTags(){
        symbolTag = new PrimitiveBERTag();
        numStocksTag = new PrimitiveBERTag();
        priceTag = new PrimitiveBERTag();
        signatureTag = new PrimitiveBERTag();
                
        symbolTag.init((byte)3, (short)8);
        numStocksTag.init((byte)3, (short)9);
        priceTag.init((byte)3, (short)10);
        signatureTag.init((byte)3, (short)11);
    }
    
    /**
     * Installs this applet.
     * @see APDU
     * @param apdu the incoming APDU containing the INSTALL command.
     * @exception ISOException with the response bytes per ISO 7816-4
     */
    public static void install( byte[] bArray, short bOffset, byte bLength ){
        new BrokerApplet(bArray, bOffset, bLength);
    }
    
    /**
     * Select method
     */
    public boolean select() {
        // The applet declines to be selected
        // if the PIN is blocked.
        if (pin.getTriesRemaining() == 0) {
            return false;
        }
        return true;
    }

    /**
     * deselect method
     */
    public void deselect() {
        // Reset the PIN value
        pin.reset();
    }
    
    /**
     * Process method
     */
    public void process(APDU apdu) throws ISOException {
        // get the APDU buffer
        byte buffer[] = apdu.getBuffer();
        
        // return if this APDU is for applet selection
        if(selectingApplet())return;
        
        // mask the channel information
        buffer[ISO7816.OFFSET_CLA] = 
                (byte) (buffer[ISO7816.OFFSET_CLA] & (byte) 0xFC);
        
        // get the data part of the APDU if this is not getPortfolio command or
        // get balance command 
        if(buffer[ISO7816.OFFSET_INS] != GET_COMPLETE_PORTFOLIO &&
                buffer[ISO7816.OFFSET_INS] != GET_BALANCE)
            apdu.setIncomingAndReceive();
        
        // pin verification command
        if (buffer[ISO7816.OFFSET_CLA] == ISO7816.CLA_ISO7816) {
            if (buffer[ISO7816.OFFSET_INS] == VERIFY) {
                verify(buffer);
                return;
            } else {
                ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
            }
        }
        
        // if PIN is not already verified throw exception
        if(!pin.isValidated()){
            ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
        }
        
        short responseSize = 0;
        try{
            switch(buffer[ISO7816.OFFSET_INS]){
                case GET_COMPLETE_PORTFOLIO:
                    responseSize = getPortfolio(buffer);
                    break;
                case GET_STOCK_INFO:
                    responseSize = getStockInfo(buffer);
                    break;
                case BUY_STOCK:
                    responseSize = genStockPurchaseRequest(buffer);
                    break;
                case SELL_STOCK:
                    responseSize = genSellStockRequest(buffer);
                    break;
                case UPDATE_PORTFOLIO:
                    updatePortfolio(buffer);
                    return;
                case GET_BALANCE:
                    responseSize = getBalance(buffer);
                    break;
                default: ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
            }
        }catch(TLVException e){
            ISOException.throwIt(TLV_EXCEPTION);
        }catch(ArithmeticException e){
            ISOException.throwIt(ARITHMETIC_EXCEPTION);
        }
        
        // send the response data back
        apdu.setOutgoingAndSend((short)0, (byte)responseSize);
        
    }
    
    /**
     * Verifies the PIN.
     * 
     * @param buffer The APDU buffer
     */
    private void verify(byte[] buffer) {
        byte numBytes = buffer[ISO7816.OFFSET_LC];

        // Verify PIN
        if (pin.check(buffer, ISO7816.OFFSET_CDATA, numBytes) == false) {
            ISOException.throwIt(SW_VERIFICATION_FAILED);
        }
    }
    
    /**
     * Return following information on all the stocks
     *  - Primitive TLV for stock symbol
     *  - Primitive TLV for number of stocks we currently have
     *  - Constructed TLV for last trade containing following
     *      - Primitive TLV for number of stocks
     *      - Primitive TLV for price
     * @param buffer is the input APDU buffer
     * @return size of response data
     */
    private short getPortfolio(byte[] buffer){
        try{
            return portfolio.toBytes(buffer, (short)0);
        }catch(TLVException e){
            if(e.getReason() == TLVException.EMPTY_TLV)
                ISOException.throwIt(SW_STOCK_NOT_FOUND);
        }
        return 0;
    }
    
    /**
     * Returns stock information
     * Input: 5 bytes representing stock symbol
     * Output: Constructed BER TLV containing the following:
     *  - Primitive TLV for stock symbol
     *  - Primitive TLV for number of stocks we currently have
     *  - Constructed TLV for last trade containing following
     *      - Primitive TLV for number of stocks
     *      - Primitive TLV for price
     * @param buffer is the input APDU buffer
     * @return size of response data
     */
    private short getStockInfo(byte[] buffer){
        // Find the stock in the portfolio
        ConstructedBERTLV stockInfo = findStock(buffer, ISO7816.OFFSET_CDATA);
        if(stockInfo == null)ISOException.throwIt(SW_STOCK_NOT_FOUND);
        return stockInfo.toBytes(buffer, (short)0);
    }
    
    /**
     * Finds a stock that matches the stock symbol
     * @param buffer is the byte array containing the stock symbol
     * @param offset is the offset in the byte array for stock symbol
     * @return ConstructedBERTLV for the stock information if stock
     * is found. If the stock is not found ISOException is thrown
     */
    private ConstructedBERTLV findStock(byte[] buffer, short offset){
        // We go through all the stocks that we have to find the
        // one we're looking for 
        ConstructedBERTLV stockInfo = 
                (ConstructedBERTLV)portfolio.find(stockInfoTag);
        
        while(stockInfo != null){
            PrimitiveBERTLV symbol = (PrimitiveBERTLV)stockInfo.find(symbolTag);
            symbol.getValue(scratchSpace, (short)0);
            if(Util.arrayCompare(buffer, offset, scratchSpace, 
                    (short)0, STOCK_SYMBOL_LENGTH) == 0){
                return stockInfo;
            }
            stockInfo = 
                (ConstructedBERTLV)portfolio.findNext(stockInfoTag, stockInfo, (short)1);
        }
        return null;
    }
    
    /**
     * Return current balance
     * @param buffer is the input APDU buffer
     * @return size of response data
     */
    private short getBalance(byte[] buffer){
        if(buffer[ISO7816.OFFSET_P1] == BigNumber.FORMAT_BCD)
            accountBalance.toBytes(buffer, (short)0, 
                    (short)8, BigNumber.FORMAT_BCD);
        else if (buffer[ISO7816.OFFSET_P1] == BigNumber.FORMAT_HEX)
            accountBalance.toBytes(buffer, (short)0, 
                    (short)8, BigNumber.FORMAT_HEX);
        else
            ISOException.throwIt(INVALID_NUMBER_FORMAT);
        return (short)8;
    }
    

    /**
     * Performs the following steps to assist in buying a stock
     * - Check available funds
     * - Create a "signed" request for the broker
     * @param buffer is the input APDU buffer
     * @return size of response data
     */
    private byte genStockPurchaseRequest(byte[] buffer){
        short offset = ISO7816.OFFSET_CDATA;
        // first 5 bytes contain the stock symbol with each byte represnting
        // an ASCII value
        offset += (short)5;
        
        // Now get the number of stocks we want to buy.
        int numStocksToBuy = JCint.getInt(buffer, offset); 
        offset += (short)4;
        
        // get the desired buy price
        short priceToBuyAt = Util.getShort(buffer, offset);
        offset += (short)2;

        // verify that we have enough balance available
        verifyBalanceAvailability(buffer);

        // Generate the request. The request is a constructed BER TLV with 
        // following elements:
        //      - Stock symbol
        //      - desired price
        //      - number of stocks to buy

        // output the broker request tag and length
        offset = buyStockReqTag.toBytes(buffer, (short)0);
        buffer[offset++] = (byte)0;
        
        // output the stock symbol TLV
        offset = symbolTag.toBytes(scratchSpace, (short)0);
        scratchSpace[offset++] = STOCK_SYMBOL_LENGTH;
        offset = Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, 
                scratchSpace, offset, STOCK_SYMBOL_LENGTH);
        ConstructedBERTLV.append(scratchSpace, (short)0, buffer, (short)0);
        completeBrokerRequest(buffer, priceToBuyAt, numStocksToBuy);
        return (byte)(buffer[1] + 2); // total length of TLV 
    }
    
    /**
     * Verifies that we have enough balance available to buy a stock
     * @param buffer is the input buffer containing the number of stocks
     * we want to buy and the price of the stock
     */
    void verifyBalanceAvailability(byte[] buffer){
        try{
            short offset = ISO7816.OFFSET_CDATA + (short)5;
            // check if we have enough balance available to buy this stock
            // initialize the number with number of stocks to buy
            tempBigNum.init(buffer, offset, (short)4, BigNumber.FORMAT_HEX);
            offset += (short)4;
            //multiply this number by desired stock price
            tempBigNum.multiply(buffer, offset, (short)2, BigNumber.FORMAT_HEX);
            
            // now we compare this number against the current available balance
            // to determine if we have enough funds available.
            if(accountBalance.compareTo(tempBigNum) < (byte)0){
                ISOException.throwIt(SW_NOT_ENOUGH_ACCOUNT_BALANCE);
            }
        }catch(ArithmeticException e){
            ISOException.throwIt(SW_NOT_ENOUGH_ACCOUNT_BALANCE);
        }
    }
    
    /**
     * Returns stock a sell stock request to the client if we hold
     * enough stocks.
     * Input: Stock symbol, the number of stocks to sell and desired price
     * Output: Constructed BER TLV containing the following:
     *  - Primitive TLV for stock symbol
     *  - Primitive TLV for desired stock price
     *  - Primitive TLV for number of stocks to sell
     *  - Primitive TLV for signature
     * @param buffer is the input APDU buffer
     * @return size of response data
     */
    private byte genSellStockRequest(byte[] buffer){
        short offset = ISO7816.OFFSET_CDATA;

        // check to see if we actually have this stock
        ConstructedBERTLV stockInfo = findStock(buffer, offset);
        if(stockInfo == null) ISOException.throwIt(SW_STOCK_NOT_FOUND);
        
        offset += STOCK_SYMBOL_LENGTH;
        
        // Now get the number of stocks we want to sell.
        int numStocksToSell = JCint.getInt(buffer, offset); 
        offset += (short)4;
        
        // get the desired sell price
        short priceToSellAt = Util.getShort(buffer, offset);
        offset += (short)2;
        
        // now within this constructed BER TLV, we need to find the Primitive 
        // TLV that has the number of stocks we currently hold
        PrimitiveBERTLV numStocksTLV = 
                    (PrimitiveBERTLV)stockInfo.find(numStocksTag);
        // use the buffer as scratch space since we have already 
        // taken out the values that we wanted to take out.
        numStocksTLV.getValue(buffer, (short)0);
        // we already know that this is a 4 byte integer value
        // create an integer from bytes
        int numCurrStock = JCint.getInt(buffer, (byte)0);
        
        // check that we have enough stocks that meet the
        // sell request requirement
        if(numCurrStock < numStocksToSell)
            ISOException.throwIt(SW_NOT_ENOUGH_STOCKS_TO_SELL);
      
        Util.arrayFillNonAtomic(buffer, (short)0, (short)100, (byte)0);
        // output the broker request tag and length
        offset = sellStockReqTag.toBytes(buffer, (short)0);
        buffer[offset] = 0;
        
        // output the stock symbol TLV
        PrimitiveBERTLV stockSymbol = 
                (PrimitiveBERTLV)stockInfo.find(symbolTag);
        
        offset = stockSymbol.toBytes(scratchSpace, (short)0);
        // append to sell request
        ConstructedBERTLV.append(scratchSpace, (short)0, buffer, (short)0);
        completeBrokerRequest(buffer, priceToSellAt, numStocksToSell);
        return (byte)(buffer[1] + 1); // length of TLV 
    }

    /**
     * This method completes the stock sell or purchase request for broker.
     * In this method we add the following primitive TLVs to the broker 
     * request constructed TLV
     * Primitive TLV for desired stock price
     * Primitive TLV for number of stocks to sell
     * Primitive TLV for signature
     * @param buffer is the input APDU buffer
     * @return size of response data
     */
    private void completeBrokerRequest(byte[] buffer, 
                                    short priceToSellAt, int numStocksToSell){
        short offset = 0;
        // output the desired stock price TLV
        offset = priceTag.toBytes(scratchSpace, (short)0);
        scratchSpace[offset++] = (byte)2;
        Util.setShort(scratchSpace, offset, priceToSellAt);
        ConstructedBERTLV.append(scratchSpace, (short)0, buffer, (short)0);
        
        // output number of stocks: Tag then length then value
        offset = numStocksTag.toBytes(scratchSpace, (short)0);
        scratchSpace[offset++] = (byte)4;
        JCint.setInt(scratchSpace, offset, numStocksToSell);
        ConstructedBERTLV.append(scratchSpace, (short)0, buffer, (short)0);
        
        // output the signature tag length and value
        offset = signatureTag.toBytes(scratchSpace, (short)0);
        scratchSpace[offset++] = (byte)8; // signature length
        Util.arrayCopyNonAtomic(dummySignature, (short)0, scratchSpace, 
                                            offset, (byte)8);              
        ConstructedBERTLV.append(scratchSpace, (short)0, buffer, (short)0);
    }
    

    /**
     * Verifies the signature of broker and if the signature is verified
     * update the portfolio including stocks and available balance
     * @param buffer is the input APDU buffer
     */
    private void updatePortfolio(byte[] buffer){
        short offset = ISO7816.OFFSET_CDATA;
        boolean isSellConfirmation = false;
        /*
         * The buffer contains the constructed BER TLV received from the 
         * broker. The constructed BER TLV contains the following values
         * in form of primitive TLV objects
         * - Stock Symbol 
         * - Stock Price
         * - Number of stocks
         * - Broker Signature (dummy signature 9999 9999 is used)
         */
        // To find out if this a sell confirmation or purchase confirmation
        // we match the tag against sell and purchase confirmation tags
        if(!BERTag.isConstructed(buffer, offset) || 
                BERTag.tagClass(buffer, offset) != (byte)3)
            ISOException.throwIt(INVALID_BROKER_CONFIRMATION);
        // get the tag number
        short confirmTagNumber = BERTag.tagNumber(buffer, offset);
        if(confirmTagNumber == sellConfirmTag.tagNumber())
            isSellConfirmation = true;
        else if(confirmTagNumber == purchaseConfirmTag.tagNumber())
            isSellConfirmation = false;
        else 
            ISOException.throwIt(INVALID_BROKER_CONFIRMATION);
        
        // get the stock symbol TLV
        symbolTag.toBytes(scratchSpace, (short)0);
        short symbolTLVOffset = ConstructedBERTLV.find(buffer, offset, 
                                                    scratchSpace, (short)0);
        
        numStocksTag.toBytes(scratchSpace, (short)0);
        short numStocksTLVOffset = ConstructedBERTLV.find(buffer, offset, 
                                                    scratchSpace, (short)0);
        short numStocksValueOffset = PrimitiveBERTLV.getValueOffset(buffer, 
                                                           numStocksTLVOffset);
        // get the stock price
        priceTag.toBytes(scratchSpace, (short)0);
        short priceTLVOffset = ConstructedBERTLV.find(buffer, offset, 
                                                    scratchSpace, (short)0);
        short priceValueOffset = PrimitiveBERTLV.getValueOffset(buffer, 
                                                           priceTLVOffset);
        
        verifyBrokerSignature(buffer, ISO7816.OFFSET_CDATA);
        
        // next is the stock symbol in 5 bytes. If we find already have
        // the stock, we will update that TLV accordingly. If we do not
        // have the stock, we'll add the new stock to portfolio
        ConstructedBERTLV stockInfo = findStock(buffer, 
                PrimitiveBERTLV.getValueOffset(buffer, symbolTLVOffset));
        
        if(stockInfo == null){
            if(isSellConfirmation){
                // we didn't have the stock that we sold!!!
                ISOException.throwIt(INVALID_BROKER_CONFIRMATION);
            } 
            // create the new constructed TLV for this stock
            stockInfo = createNewStockTLV(buffer, symbolTLVOffset, 
                    numStocksTLVOffset, priceTLVOffset);
            portfolio.append(stockInfo);
            updateAccountBalance(buffer, numStocksValueOffset, 
                                    priceValueOffset, isSellConfirmation);
            return;
        }
        // update the existing stockInfoTLV
        // update num stocks
        PrimitiveBERTLV numStocksTLV = 
                (PrimitiveBERTLV)stockInfo.find(numStocksTag);
        numStocksTLV.getValue(scratchSpace, (short)0);
        tempBigNum.init(scratchSpace, (short)0, (byte)4, BigNumber.FORMAT_HEX);
        if(!isSellConfirmation){
            tempBigNum.add(buffer, numStocksValueOffset, (short)4, 
                                                        BigNumber.FORMAT_HEX);
        }else{
            tempBigNum.subtract(buffer, numStocksValueOffset, (short)4, 
                                                        BigNumber.FORMAT_HEX);
            // if stocks now number 0, we remove this TLV
            Util.arrayFillNonAtomic(scratchSpace, (short)0, (short)1, (byte)0);
            if(tempBigNum.compareTo(scratchSpace, (short)0, 
                    (short)1, BigNumber.FORMAT_HEX) == 0){
                portfolio.delete(stockInfo, (short)1);
                return;
            }
        }
        tempBigNum.toBytes(scratchSpace, (short)0, (short)4, 
                BigNumber.FORMAT_HEX);
        numStocksTLV.replaceValue(scratchSpace, (short)0, (short)4);
        
        // update last trade information
        ConstructedBERTLV lastTradeTLV = 
                (ConstructedBERTLV)stockInfo.find(lastTradeTag);        
        numStocksTLV = (PrimitiveBERTLV)lastTradeTLV.find(numStocksTag);
        numStocksTLV.replaceValue(buffer, numStocksValueOffset, (short)4);
        PrimitiveBERTLV priceTLV = (PrimitiveBERTLV)lastTradeTLV.find(priceTag);
        priceTLV.replaceValue(buffer, priceValueOffset, (short)2);

        // update the account balance
        updateAccountBalance(buffer, numStocksValueOffset, 
                priceValueOffset, isSellConfirmation);
    }
    
    /**
     * Update the account balance
     * @param buffer is the input buffer
     * @param numStocksOffset is the offset in the buffer where number of 
     * stocks information is at
     * @param priceOffset is the offset in the buffer where stock price
     * information is at
     * @param sold is the boolean indicating the if the stock was bought or
     * sold
     */
    void updateAccountBalance(byte[] buffer, short numStocksOffset, 
            short priceOffset, boolean sold){
        tempBigNum.init(buffer, numStocksOffset, (byte)4, BigNumber.FORMAT_HEX);
        
        // get the amount for this trade
        tempBigNum.multiply(buffer, priceOffset, (short)2, 
                BigNumber.FORMAT_HEX);
        
        tempBigNum.toBytes(scratchSpace, (short)0, 
                (short)8, BigNumber.FORMAT_HEX);
        
        if(sold){
            // if stock was sold, we add to the balance
            accountBalance.add(scratchSpace, (short)0, 
                    (short)8, BigNumber.FORMAT_HEX);
        }else{
            // if stock was bought we subtract the amount
            // from balance
            accountBalance.subtract(scratchSpace, (short)0, 
                    (short)8, BigNumber.FORMAT_HEX);
        }
    }
    
    /**
     * Verify the broker signature. This method throws an exception if the
     * broker signature is invalid
     * @param buffer is the input APDU buffer
     * @param TLVOffset is the offset within the buffer where the TLV for 
     * the broker signature starts
     */ 
    void verifyBrokerSignature(byte[] buffer, short TLVOffset){
        // get the stock price
        signatureTag.toBytes(scratchSpace, (short)0);
        short sigTLVOffset = ConstructedBERTLV.find(buffer, TLVOffset, 
                                                    scratchSpace, (short)0);
        short sigValueOffset = PrimitiveBERTLV.getValueOffset(buffer, 
                                                                sigTLVOffset);
        if(Util.arrayCompare(buffer, sigValueOffset, dummySignature, 
                (short)0, (byte)dummySignature.length) != 0){
            ISOException.throwIt(INVALID_BROKER_SIGNATURE);
        }
    }
    
    /**
     * As a rsult of a stock that is bought, we create a new
     * TLV to hold the information regarding the newly bought stock
     * @param buffer contains the new stock information
     * @param symbolOffset is the offset within buffer where the new
     * stock symbol is present
     * @param numOffset is the offset within the buffer where the 
     * information regarding number of stocks is at
     * @param priceOffset is the offset within the buffer where the 
     * information regarding price at which the stock was bought is at
     * @return newly created constructed BERTLV object that is eventually
     * added to the portfolio.
     */
    private ConstructedBERTLV createNewStockTLV(byte buffer[], 
        short symbolOffset, short numOffset, short priceOffset){
        // this TLV contains the following
        // - Primitive TLV for stock symbol
        // - Primitive TLV for number of stocks we currently have
        // - Constructed TLV for last trade containing following
        //     - Primitive TLV for number of stocks
        //     - Primitive TLV for price        
        Util.arrayFillNonAtomic(scratchSpace, (short)0, 
                                (short)scratchSpace.length, (byte)0);
        short offset = stockInfoTag.toBytes(scratchSpace, (short)0);
        // length is 0 which is already set in so don't need to modify
        ConstructedBERTLV stockInfo = (ConstructedBERTLV)BERTLV.getInstance(
                scratchSpace, (short)0, (short)2);
        // create the stock symbol TLV 
        offset = symbolTag.toBytes(scratchSpace, (short)0);
        PrimitiveBERTLV symbolTLV = (PrimitiveBERTLV)BERTLV.getInstance(
                                        buffer, symbolOffset, (short)7);
        // append to the stockInfo TLV
        stockInfo.append(symbolTLV);
        
        // clean up the scratch space for number TLV
        PrimitiveBERTLV numStocksTLV = (PrimitiveBERTLV)BERTLV.getInstance(
                                        buffer, numOffset, (short)6);
        // append to the stockInfo TLV
        stockInfo.append(numStocksTLV);
        
       // create the last trade TLV
        offset = lastTradeTag.toBytes(scratchSpace, (short)0);
        scratchSpace[offset] = 0;
        ConstructedBERTLV lastTradeInfo = (ConstructedBERTLV)BERTLV.getInstance(
                scratchSpace, (short)0, (short)2);
        
        PrimitiveBERTLV LTradeNumStocksTLV = (PrimitiveBERTLV)BERTLV.getInstance(
                                        buffer, numOffset, (short)6);
        lastTradeInfo.append(LTradeNumStocksTLV);
        
        PrimitiveBERTLV priceTLV = (PrimitiveBERTLV)BERTLV.getInstance(
                                        buffer, priceOffset, (short)4);
        lastTradeInfo.append(priceTLV);
        
        // now append the last trade TLV to stockInfo TLV
        stockInfo.append(lastTradeInfo);
        
        // this completes the stockInfo
        return stockInfo;
    }
}