javaextensions/satsa/apdu/src.s60/cstspinmanager.cpp
branchRCL_3
changeset 14 04becd199f91
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javaextensions/satsa/apdu/src.s60/cstspinmanager.cpp	Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,666 @@
+/*
+* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+ *
+*/
+
+
+//  INCLUDE FILES
+#include <charconv.h>
+#include <secdlg.h>
+
+#include "cstsapduexchanger.h"
+#include "cstsaccesscontrol.h"
+#include "cstspinmanager.h"
+#include "cstsauthtype.h"
+#include "cstspinattributes.h"
+#include "stsapduconstants.h"
+#include "cstspinapdu.h"
+#include "cstspinapduresp.h"
+#include "cstsresphandler.h"
+#include "cstspinconverter.h"
+#include "logger.h"
+
+
+using namespace java::util;
+
+namespace java
+{
+namespace satsa
+{
+
+//  CONSTANTS
+const TInt KSTSMaxPinAttempts = 3;
+const TInt KSTSPinHeaderLength = 4;
+
+CSTSPinManager::CSTSPinManager(CSTSApduExchanger* aApduExchanger,
+                               CSTSAccessControl* aAccessControl, MSTSRespHandler* aRespHandler) :
+        CActive(EPriorityNormal)
+{
+
+    CActiveScheduler::Add(this);
+    iApduExchanger = aApduExchanger;
+    iAccessControl = aAccessControl;
+    iRespHandler = aRespHandler;
+
+}
+
+void CSTSPinManager::ConstructL()
+{
+    // create pinUI
+    iSecurityDialog = SecurityDialogFactory::CreateL();
+
+    iAuthTypeFirstPin = CSTSAuthType::NewL();
+    iAuthTypeSecondPin = CSTSAuthType::NewL();
+
+}
+
+CSTSPinManager* CSTSPinManager::NewL(JNIEnv* aJni, jobject aPeer,
+                                     CSTSApduExchanger* aApduExchanger, CSTSAccessControl* aAccessControl,
+                                     MSTSRespHandler* aRespHandler)
+{
+    CSTSPinManager
+    * self =
+        new(ELeave) CSTSPinManager(aApduExchanger, aAccessControl, aRespHandler);
+
+    self->mJni = aJni;
+    self->mPeer = aPeer;
+    CleanupStack::PushL(self);
+    self->ConstructL();
+
+    CleanupStack::Pop(self);
+    return self;
+}
+
+// Destructor
+CSTSPinManager::~CSTSPinManager()
+{
+    Cancel();
+    delete iAuthTypeSecondPin;
+    delete iAuthTypeFirstPin;
+    if (iSecurityDialog)
+    {
+        iSecurityDialog->Release(); // Release deletes the object
+    }
+    delete iPinApdu;
+    delete iPinApduResp;
+    delete iResponseBuf;
+    delete mJni;
+}
+
+// -----------------------------------------------------------------------------
+// CSTSPinManager::DisablePinL
+// Calls proper private methods.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CSTSPinManager::DisablePinL(TInt aPinID)
+{
+    PreparePinMethodL(CSTSPinApdu::ESTSDisablePin, aPinID);
+    ShowPinUI(CSTSPinApdu::ESTSDisablePin);
+}
+
+// -----------------------------------------------------------------------------
+// CSTSPinManager::ChangePinL
+// Calls proper private methods.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CSTSPinManager::ChangePinL(TInt aPinID)
+{
+
+    PreparePinMethodL(CSTSPinApdu::ESTSChangePin, aPinID);
+    ShowPinUI(CSTSPinApdu::ESTSChangePin);
+
+}
+
+// -----------------------------------------------------------------------------
+// CSTSPinManager::EnablePinL
+// Calls proper private methods.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CSTSPinManager::EnablePinL(TInt aPinID)
+{
+
+    PreparePinMethodL(CSTSPinApdu::ESTSEnablePin, aPinID);
+    ShowPinUI(CSTSPinApdu::ESTSEnablePin);
+
+}
+
+// -----------------------------------------------------------------------------
+// CSTSPinManager::EnterPinL
+// Calls proper private methods.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CSTSPinManager::EnterPinL(TInt aPinID)
+{
+    PreparePinMethodL(CSTSPinApdu::ESTSVerifyPin, aPinID);
+    ShowPinUI(CSTSPinApdu::ESTSVerifyPin);
+}
+
+// -----------------------------------------------------------------------------
+// CSTSPinManager::UnblockPinL
+// Calls proper private methods.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CSTSPinManager::UnblockPinL(TInt aBlockedPinID, TInt aUnblockedPinID)
+{
+    PreparePinMethodL(CSTSPinApdu::ESTSUnblockPin, aBlockedPinID,
+                      aUnblockedPinID);
+    ShowPinUI(CSTSPinApdu::ESTSUnblockPin);
+}
+
+// -----------------------------------------------------------------------------
+// CSTSPinManager::CancelOperation
+// Cancels any pending operation
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CSTSPinManager::CancelOperation()
+{
+    LOG(ESATSA, EInfo, "CSTSPinManager::CancelOperation called!");
+    Cancel();
+}
+
+// -----------------------------------------------------------------------------
+// CSTSPinManager::RunL
+// If PIN value is got from UI, converts user gived PIN values in proper form
+// and sends PIN apdu to card. If user has selected cancel option, informs it
+// to java side. When apdu sending has returned, checks was user gived value
+// correct one and if was not, shows proper PIN ui again. If no retries is left
+// shows blocked PIN UI. Supplies response apdus to java side and in error
+// conditions supplies proper error code.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CSTSPinManager::RunL()
+{
+    LOG1(ESATSA, EInfo, "CSTSPinManager::RunL called!:%d", iStatus.Int());
+
+    if (iStatus == KErrCancel)
+    {
+        LOG(ESATSA, EInfo, "CSTSPinManager::RunL, Cancel selected");
+        // if the user selected cancel option. we return null
+        iRespHandler->OperationComplete(mJni, mPeer, NULL, KSTSErrCancel);
+
+    }
+    else if (iStatus != KErrNone)
+    {
+        LOG(ESATSA, EInfo, "CSTSPinManager::RunL, Error Occurred!!");
+        // in other error conditions supply error code
+        iRespHandler->OperationComplete(mJni, mPeer, NULL, iStatus.Int());
+    }
+    else // no problems
+    {
+        switch (iState)
+        {
+        case ESendingPINApdu:
+        {
+            LOG(ESATSA, EInfo, "CSTSPinManager::RunL, case ESendingPINApdu");
+            DoAfterSendApduL();
+            break;
+        }
+        case EShowingPinBlockedUI:
+        {
+            LOG(ESATSA, EInfo, "CSTSPinManager::RunL, case EShowingPinBlockedUI");
+            //return PIN method blocked value to java side
+            //that value is already got from card
+            DeliverResponseL();
+            break;
+        }
+        case EShowing1ValuePinUI:
+        {
+            LOG(ESATSA, EInfo, "CSTSPinManager::RunL, case EShowing1ValuePinUI");
+            DoAfter1ValuePinUIL();
+            break;
+        }
+        case EShowing2ValuePinUI:
+        {
+            LOG(ESATSA, EInfo, "CSTSPinManager::RunL, case EShowing2ValuePinUI");
+            DoAfter2ValuePinUIL();
+            break;
+        }
+        default:
+        {
+            break;
+        }
+        }
+    }
+}
+// -----------------------------------------------------------------------------
+// CSTSPinManager::DoCancel
+// Cancels all possible active actions like PIN UIs or apdu exchange
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CSTSPinManager::DoCancel()
+{
+    LOG(ESATSA, EInfo, "CSTSPinManager::DoCancel, called");
+    iSecurityDialog->Cancel();
+    iApduExchanger->CancelExchange();
+}
+
+// -----------------------------------------------------------------------------
+// CSTSPinManager::RunError
+// If leave occures in RunL,this method is called. Notifies java side with
+// leave code.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TInt CSTSPinManager::RunError(TInt aError)
+{
+    LOG1(ESATSA, EInfo, "CSTSPinManager::RunError, called: %d", aError);
+    iRespHandler->OperationComplete(mJni, mPeer, NULL, aError);
+    // must return KErrNone
+    return KErrNone;
+}
+
+// -----------------------------------------------------------------------------
+// CSTSPinManager::ConvertPINL Converts PIN to correct form for presenting it
+// to card. Implementation done according to document "PKCS #15 v1.1:
+// Cryptographic Token Information Syntax Standard" chapter "6.8.2.1
+// Transforming a supplied PIN".
+//
+// EXAMPLE (ascii-) Numeric PIN ‘1234’(10), stored length 8 bytes, and padding
+//  character ‘FF’(16) gives that the value presented to the card will be
+//  ‘31323334FFFFFFFF’(16)
+//
+// Returns: aConvertedPIN: PIN converted to needed format.
+// -----------------------------------------------------------------------------
+//
+void CSTSPinManager::ConvertPINL(const CSTSPinAttributes& aPinAttributes,
+                                 const TDes& aPinValue, HBufC8*& aConvertedPIN)
+{
+    LOG(ESATSA, EInfo, "CSTSPinManager::ConvertPINL called ");
+
+    TPtr8 convertedPtr(aConvertedPIN->Des());
+
+    CSTSPinAttributes::TPinType pinType = aPinAttributes.PinType();
+    LOG1(ESATSA, EInfo, "CSTSPinManager::ConvertPINL, pintype: %d", pinType);
+
+    if (pinType == CSTSPinAttributes::EUTF8)
+    {
+        // if case-sensitive bit is off, convert to uppercase
+        TBool upperCase = !aPinAttributes.IsPinFlagSet(
+                              CSTSPinAttributes::ECaseSensitive);
+        CSTSPinConverter::ConvertToUTF8L(aPinValue, convertedPtr, upperCase);
+    }
+    else if (pinType == CSTSPinAttributes::EBCD)
+    {
+        CSTSPinConverter::ConvertToBCDL(aPinValue, convertedPtr, EFalse); // not half BCD
+    }
+    else if (pinType == CSTSPinAttributes::EAsciiNumeric || pinType
+             == CSTSPinAttributes::EISO9564_1)
+    {
+        CSTSPinConverter::ConvertToASCIIL(aPinValue, convertedPtr);
+
+    }
+    else if (pinType == CSTSPinAttributes::EHalfNibbleBCD)
+    {
+        CSTSPinConverter::ConvertToBCDL(aPinValue, convertedPtr, ETrue); // Half BCD
+    }
+    else
+    {
+        User::Leave(KErrCorrupt);
+    }
+
+    // If indicated in the pinFlags field, pad to the right with the
+    // padding character, to stored length
+
+
+    // must be popped from cleanupstack before padding
+    CleanupStack::Pop(aConvertedPIN);
+    TInt err = CSTSPinConverter::DoBadding(aPinValue, aConvertedPIN,
+                                           aPinAttributes.StoredLength(), aPinAttributes.PadChar()[0]);
+    CleanupStack::PushL(aConvertedPIN);
+    User::LeaveIfError(err);
+
+}
+
+// -----------------------------------------------------------------------------
+// CSTSPinManager::PreparePinMethodL Makes preparation common for all PIN
+// methods. Checks, is PIN method allowed to use. Gets PIN headers from the
+// card and if there was not any, generates it. Sets needed PIN UI parameters.
+// Returns:
+//      iPinApdu: Saves APDU into this member variable
+//      iPinApduResp: Saves response APDU into this member variable
+//      iAuthTypeFirstPin: Saves PIN attributes into this member variable
+//      iAuthTypeSecondPin: Saves PIN attributes into this member variable
+//      iPINParamsFirstPin: Saves PIN UI parameters into this member variable
+//      iPINParamsSecondPin: Saves PIN UI parameters into this member variable
+// -----------------------------------------------------------------------------
+//
+void CSTSPinManager::PreparePinMethodL(
+    CSTSPinApdu::TSTSPinApduType aPinApduType, TInt aFirstPinID,
+    TInt aUnblockedPinID)
+{
+    LOG(ESATSA, EInfo, "CSTSPinManager::PreparePinMethodL called");
+
+    iPinApduType = aPinApduType;
+
+    // is pinmethods supported to use with card application
+    if (!iAccessControl->IsAllowedPinMethod())
+    {
+        ELOG(ESATSA, "CSTSPinManager::PreparePinMethodL, Not supported");
+        User::Leave(KSTSErrSecurity + KSTSErrSECNoRightsPin);
+    }
+
+    // gets the pin apdu header part from the card, if there is any
+    TPtrC8 headerPtr(iAccessControl->GetPinHeaderL(aFirstPinID,
+                     (TPinApduType) aPinApduType));
+
+    iAuthTypeFirstPin->CopyL(iAccessControl->GetPinAttributesL(aFirstPinID));
+
+    // leaves if PIN flags does not allow this PIN apdu
+    iAccessControl->CheckPinFlagsL((TPinApduType) aPinApduType);
+
+    // if pin headers are not found,
+    if (headerPtr == KNullDesC8())
+    {
+        // Pin reference is used if the APDU headers are not specified in the ACL
+        CSTSPinApdu* pinApdu = CSTSPinApdu::NewL(aPinApduType,
+                               iAuthTypeFirstPin->PinAttributes().PinReference(),
+                               CSTSApdu::ESTSUICC);
+        delete iPinApdu;
+        iPinApdu = pinApdu;
+    }
+    else
+    {
+        LOG(ESATSA, EInfo, "CSTSPinManager::PreparePinMethodL, specified header used");
+        CSTSCmdApdu* tmp = CSTSCmdApdu::NewL(headerPtr, CSTSApdu::ESTSUICC);
+        delete iPinApdu;
+        iPinApdu = tmp;
+    }
+
+    // check is the J2ME application allowed to use this apdu
+    if (!iAccessControl->IsAllowedApduL(iPinApdu->Header()))
+    {
+        ELOG(ESATSA, "CSTSPinManager::PreparePinMethodL, Not allowed");
+        // if not allowed
+        User::Leave(KSTSErrSecurity + KSTSErrSECIllegalApdu);
+    }
+
+    SetPINUIParametersL(iAuthTypeFirstPin, iPINParamsFirstPin);
+
+    // In unblockPIN case we need to initialize parameters of unblocked PIN
+    if (aPinApduType == EUnblockPinAPDU)
+    {
+        LOG(ESATSA, EInfo, "unblock parameters");
+        iAuthTypeSecondPin->CopyL(iAccessControl->GetPinAttributesL(
+                                      aUnblockedPinID));
+        SetPINUIParametersL(iAuthTypeSecondPin, iPINParamsSecondPin);
+    }
+
+    iRetries = EFirstTime;
+    LOG(ESATSA, EInfo, "-- CSTSPinManager::PreparePinMethodL");
+}
+
+// -----------------------------------------------------------------------------
+// CSTSPinManager::ShowPinUI Shows PIN UI for getting PIN value or values.
+// Shows correct UI depending on which PIN method is used.
+//
+// -----------------------------------------------------------------------------
+//
+void CSTSPinManager::ShowPinUI(CSTSPinApdu::TSTSPinApduType aPinApduType)
+{
+    LOG(ESATSA, EInfo, "CSTSPinManager::ShowPinUI+");
+    TBool retrying = iRetries == ERetrying;
+    TPinManagerState state = EShowing1ValuePinUI;
+    // get PIN from the user with UI
+    if (aPinApduType == EVerifyPinAPDU)
+    {
+        iSecurityDialog->EnterPIN(iPINParamsFirstPin, retrying,
+                                  iPinValueForFirstPin, iStatus);
+    }
+    else if (aPinApduType == EEnablePinAPDU)
+    {
+        iSecurityDialog->EnablePIN(iPINParamsFirstPin, retrying,
+                                   iPinValueForFirstPin, iStatus);
+
+    }
+    else if (aPinApduType == EDisablePinAPDU)
+    {
+        iSecurityDialog->DisablePIN(iPINParamsFirstPin, retrying,
+                                    iPinValueForFirstPin, iStatus);
+    }
+    else if (aPinApduType == EChangePinAPDU)
+    {
+        state = EShowing2ValuePinUI;
+        iSecurityDialog->ChangePIN(iPINParamsFirstPin, retrying,
+                                   iPinValueForFirstPin, iPinValueForSecondPin, iStatus);
+    }
+    else if (aPinApduType == EUnblockPinAPDU)
+    {
+        state = EShowing2ValuePinUI;
+        iSecurityDialog->UnblockPIN(iPINParamsFirstPin, iPINParamsSecondPin,
+                                    retrying, iPinValueForFirstPin, iPinValueForSecondPin, iStatus);
+    }
+    else
+    {
+
+    }
+
+    SetActive();
+    iState = state;
+
+}
+
+// -----------------------------------------------------------------------------
+// CSTSPinManager::DeliverResponseL
+// Saves responsebytes to member variable and delivers them to java side with
+// help of response handler.
+// -----------------------------------------------------------------------------
+//
+void CSTSPinManager::DeliverResponseL()
+{
+    LOG(ESATSA, EInfo, "CSTSPinManager::DeliverResponseL, called");
+    HBufC8* tmp = iPinApduResp->ResponseBytes().AllocL();
+    delete iResponseBuf;
+    iResponseBuf = tmp;
+
+    iRespHandler->OperationComplete(mJni, mPeer, iResponseBuf, KErrNone);
+
+}
+
+// -----------------------------------------------------------------------------
+// CSTSPinManager::SetPINUIParametersL
+// Uses authtype parameter to get needed values and sets them to gived PINParams
+// variable.
+// -----------------------------------------------------------------------------
+//
+void CSTSPinManager::SetPINUIParametersL(const CSTSAuthType* aAuthType,
+        TPINParams& aPINParams)
+{
+    // maximum length is optional in card, so we need to set something for
+    // PIN UI needs
+    TInt maxLength = PINMaxLength(aAuthType);
+    TInt minLength = aAuthType->PinAttributes().MinLength();
+
+    // create TPINParams
+
+    // label that identifies the PIN
+    aPINParams.iPINLabel = aAuthType->Label();
+    aPINParams.iTokenLabel = iAccessControl->TokenLabelL();
+    aPINParams.iMinLength = minLength;
+    aPINParams.iMaxLength = maxLength;
+
+}
+
+// -----------------------------------------------------------------------------
+// CSTSPinManager::DoAfterSendApduL
+// Checks response adpu and depending on response delivers response bytes
+// to response handler, shows PIN Blocked UI or shows previous PIN UI again.
+// -----------------------------------------------------------------------------
+//
+void CSTSPinManager::DoAfterSendApduL()
+{
+    //check response apdu, and show UI again if wrong pin value
+    CSTSPinApduResp* resp = CSTSPinApduResp::NewL();
+    delete iPinApduResp;
+    iPinApduResp = resp;
+    iApduExchanger->GetResponseBytes(*iPinApduResp);
+
+    TInt retriesLeft = iPinApduResp->RetriesLeft();
+
+    //if response not indicate retresleft value
+    if (retriesLeft == KErrNotFound)
+    {
+        // return response bytes to java side
+        DeliverResponseL();
+    }
+
+    //if pin is blocked, call iSecurityDialog::PINBlocked method
+    else if (iPinApduResp->IsBlocked())
+    {
+        // save state to member variable that we can return asynchronous
+        // after SetActive call
+        iRetries = EPINBlocked;
+
+        iSecurityDialog->PINBlocked(iPINParamsFirstPin, iStatus);
+        iState = EShowingPinBlockedUI;
+        SetActive();
+    }
+    // if user gived pin value was incorrect
+    else if (retriesLeft < KSTSMaxPinAttempts && retriesLeft > 0)
+    {
+        iRetries = ERetrying;
+        // "initialize" header
+        iPinApdu->ApduBytes().SetLength(KSTSPinHeaderLength);
+        // show UI again, because PIN value was wrong
+        ShowPinUI(iPinApduType);
+    }
+    // if max pin attemps is left, user gived pin value was correct
+    // one and we can supply response bytes to java side
+    else if (retriesLeft == KSTSMaxPinAttempts)
+    {
+        // return response bytes to java side
+        DeliverResponseL();
+    }
+    else
+    {
+        User::Leave(KSTSErrIO + KSTSErrIOCommProblems);
+    }
+}
+
+// -----------------------------------------------------------------------------
+// CSTSPinManager::DoAfter1ValuePinUIL
+// Convers PIN value gor from UI to proper form and sends proper PIN apdu to
+// smart card.
+// -----------------------------------------------------------------------------
+//
+void CSTSPinManager::DoAfter1ValuePinUIL()
+{
+    HBufC8* convertedBuf =
+        HBufC8::NewLC(PINMaxLength(iAuthTypeFirstPin, ETrue));
+
+    ConvertPINL(iAuthTypeFirstPin->PinAttributes(), iPinValueForFirstPin,
+                convertedBuf);
+    TPtr8 convertedPin(convertedBuf->Des());
+
+    iPinApdu->AppendDatabytesL(convertedPin);
+
+    CleanupStack::PopAndDestroy(convertedBuf);
+
+    iApduExchanger->ExchangeApduAsync(iStatus, *iPinApdu);
+    iState = ESendingPINApdu;
+    SetActive();
+
+}
+
+// -----------------------------------------------------------------------------
+// CSTSPinManager::DoAfter2ValuePinUIL
+// Convers PIN values gor from UI to proper form and sends proper PIN apdu to
+// smart card.
+// -----------------------------------------------------------------------------
+//
+void CSTSPinManager::DoAfter2ValuePinUIL()
+{
+
+    // in changePIN case we use same pin parameters for both pins
+    if (iPinApduType == EChangePinAPDU)
+    {
+        iAuthTypeSecondPin->CopyL(*iAuthTypeFirstPin);
+    }
+
+    // finds maximum length to create large enough buffer
+    TInt pinValue2MaxLength = PINMaxLength(iAuthTypeSecondPin, ETrue);
+
+    HBufC8* convertedBuf1 = HBufC8::NewLC((PINMaxLength(iAuthTypeFirstPin,
+                                           ETrue)) +pinValue2MaxLength);
+
+    ConvertPINL(iAuthTypeFirstPin->PinAttributes(), iPinValueForFirstPin,
+                convertedBuf1);
+
+    HBufC8* convertedBuf2 = HBufC8::NewLC(pinValue2MaxLength);
+    ConvertPINL(iAuthTypeSecondPin->PinAttributes(), iPinValueForSecondPin,
+                convertedBuf2);
+
+    TPtr8 convertedPins(convertedBuf1->Des());
+    convertedPins.Append(convertedBuf2->Des());
+
+    iPinApdu->AppendDatabytesL(convertedPins);
+
+    CleanupStack::PopAndDestroy(convertedBuf2);
+    CleanupStack::PopAndDestroy(convertedBuf1);
+
+    iApduExchanger->ExchangeApduAsync(iStatus, *iPinApdu);
+    iState = ESendingPINApdu;
+    SetActive();
+
+}
+
+// -----------------------------------------------------------------------------
+// CSTSPinManager::PINMaxLength
+// Is used to find PIN value max length for UI and for buffer creation. For UI
+// needs aReturnBiggest parameter is not used and method will return proper
+// maxLength of PIN. If is used for creating buffer for converted PIN
+// aReturnBiggest parameter must be set to ETrue. Then method will return either
+// maxlength or stored length value depending on which one is bigger.
+// -----------------------------------------------------------------------------
+//
+TInt CSTSPinManager::PINMaxLength(const CSTSAuthType* aAuthType,
+                                  TBool aReturnBiggest) const
+{
+    TInt returnValue;
+    TInt maxLength = aAuthType->PinAttributes().MaxLength();
+    TInt storedLength = aAuthType->PinAttributes().StoredLength();
+
+    // maximum length is optional in card, so we need to set something for
+    // PIN UI needs
+    if (maxLength == KErrNotFound)
+    {
+        // if optional maxLength is not found, we use mandatory stored length
+        maxLength = storedLength;
+    }
+    returnValue = maxLength;
+
+    // compares maxlength and stored length
+    if (aReturnBiggest)
+    {
+        if (storedLength > maxLength)
+        {
+            returnValue = storedLength;
+        }
+    }
+
+    return returnValue;
+}
+
+} // namespace satsa
+} // namespace java
+//  End of File
+