Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Online documentation (Javadoc)

...

Table of Contents
minLevel1
maxLevel7
typeflat

Basic transaction

A basic OLA transaction includes the following steps:

OLA classes instantiation (once at startup)

Code Block
private val finalola: Ola
ola;private val contact: OlaContact
private val contactless: OlaContactless
private val emv: OlaEmv
private val dev: Dev
private val publicKey: OlaPublicKey
...

init {
    ola = Ola.getInstance()
    contact = OlaContact.getInstance()
    contactless = OlaContactless.getInstance()
    emv = OlaEmv.getInstance()
    publicKey = OlaPublicKey()
    ...
}

OLA component initialisation (once at startup)

Code Block
/**
 * Configures OLA layer (key files paths, trace, etc...)
 */
private fun olaConfig() {
    val path = byteArrayOf(0xdf.toByte(), 0x01, 28)
    val pathValue = 
private final OlaEmv emv;      "/data/data/ca.amadis.tester/"
    val cakeys = byteArrayOf(0xdf.toByte(), 0x02, 34)
    val cakeysValue = "/data/data/ca.amadis.tester/CAKeys"
    val crl      = byteArrayOf(0xdf.toByte(), 0x03, 31)
    val crlValue = "/data/data/ca.amadis.tester/CRL"
    val efl = byteArrayOf(0xdf.toByte(), 0x04, 31)
    val eflValue = "/data/data/ca.amadis.tester/EFL"
    val pcsc = byteArrayOf(0xdf.toByte(), 0x05, 0x00) // pcsc not used
    val lang = byteArrayOf(0xdf.toByte(), 0x06, 0x00) // lang not used
    val runtimeParams = byteArrayOf(0xdf.toByte(), 0x07, 0x07, 0x00, 0x0F, 0x04, 0x0F, 
private final OlaContactless contactless;

this.ola = Ola.getInstance();
this.contactless = OlaContactless.getInstance();
this.emv = OlaEmv.getInstance();

OLA component initialisation (once at startup)

Code Block
/**
 * Configures OLA layer (key files paths, trace, etc...)
 */
private void olaConfig()0x0A, 0x00, 0x01)
    val traceLevel = byteArrayOf(0xdf.toByte(), 0x08, 0x01, 0x05)
    val pollingTechno = byteArrayOf(0xdf.toByte(), 0x10, 0x01, 0x04) // Contactless only
    var sredMode: ByteArray
    if (BuildConfig.FLAVOR.lowercase().contains("nosred")) {
     final  byte[] pathsredMode = {byteArrayOf(0xdf.toByte(byte)0xdf, 0x17, 0x01, 28}; 0x00) // SRED mode not active
    final} Stringelse pathValue{
= "/data/data/ca.amadis.tester/";     final byte[] cakeyssredMode = {byteArrayOf(0xdf.toByte(byte)0xdf, 0x17, 0x020x01, 34};
    final String cakeysValue = "/data/data/ca.amadis.tester/CAKeys";0x01) // SRED mode active
    }
  
 final byte[] crl =try {(byte)0xdf,
0x03, 31};     final String val crlValueout = "/data/data/ca.amadis.tester/CRL";ByteArrayOutputStream()
    final byte[] efl = {out.write(bytepath)0xdf,
  0x04, 31};     final String eflValue = "/data/data/ca.amadis.tester/EFL";out.write(pathValue.toByteArray())
        out.write(cakeys)
    final byte[] pcsc = {(byte)0xdf, 0x05, 0x00}; // pcsc not used
    final byte[] lang = {(byte)0xdf, 0x06, 0x00}; // lang not used out.write(cakeysValue.toByteArray())
        out.write(crl)
        out.write(crlValue.toByteArray())
        out.write(efl)
    final byte[] runtimeParams = {(byte)0xdf, 0x07, 0x07, 0x00, 0x0F, 0x04, 0x0F, 0x0A, 0x00, 0x01}; out.write(eflValue.toByteArray())
        out.write(pcsc)
     final byte[] traceLevel = {(byte)0xdf, 0x08, 0x01, 0x05}; out.write(lang)
       final byte[] pollingTechno = {(byte)0xdf, 0x10, 0x01, 0x04}; // Contactless only out.write(runtimeParams)
        out.write(traceLevel)
    final byte[] sredMode = {out.write(bytepollingTechno)0xdf,
0x17, 0x01, 0x01}; // SRED mode active  out.write(sredMode)
   try     
{         ByteArrayOutputStream out = new ByteArrayOutputStream();ola.initializeAtStartUp(out.toByteArray())
  
    } catch     out.write(path);
(e: IOException) {
    }
}

AID configuration

Code Block
private  out.write(pathValue.getBytesfun terminalContactlessConfig()); {

      outLog.write(cakeys);v("Transaction", "terminalContactlessConfig")
    
    out.write(cakeysValue.getBytes());val contactlessCfg = arrayOf(
        out.write(crl);
        out.write(crlValue.getBytes());ContactlessCfg(AID.FromBytes(byteArrayOf(0xA0.toByte(), 0x00, 0x00, 0x00, 0x04, 0x10, 0x10)), 
          out.write(efl);         out.write(eflValue.getBytes());    true, 
   out.write(pcsc);         out.write(lang);         out.write(runtimeParams);  2, 
     out.write(traceLevel);         out.write(pollingTechno);         out.write(sredMode);mcCfg),
         byte[] tlv = out.toByteArray();ContactlessCfg(AID.FromBytes(byteArrayOf(0xA0.toByte(), 0x00, 0x00, 0x00, 0x04, 0x20, 0x10)),
            ola.initializeAtStartUp(tlv);     }      catchtrue, (IOException
e)     {      }
}

AID configuration (once at startup)

Code Block
private void terminalContactlessConfig() {            2, 
       contactless.flushAIDSupported();      for (OLAConfig.ContactlessCfg config : OLAConfig.contactlessCfg)      {mcCfg),
        contactless.addAIDSupported(...)
    
    contactless.flushAIDSupported()
   config.aid,
      
    for (config in contactlessCfg) {
        contactless.addAIDSupported(
            config.aid,
            config.partial,
            config.kernelId.toByte(),
            config.additionalData
        )
    }
    
    contactless.commitSupportedAIDs()
}

Keys configuration

Code Block
private fun terminalPublicKeyConfig() {

    Log.v("Transaction", "terminalPublicKeyConfig")
    val publicKeyCfg = arrayOf(
        /* MasterCard */
        PublicKeyCfg(byteArrayOf(0xa0.toByte(), 0x00, 0x00, 0x00, 0x03),
                     0x92.toByte(),
                     byteArrayOf(0x99.toByte(), 0x6a, 0xf5.toByte(), 0x6f, 0x56, 0x91.toByte(), 0x87.toByte(), 0xd0.toByte(), 0x92.toByte(), 0x93.toByte(), 0xc1.toByte(), 0x48, 0x10, 0x45, 0x0e, 0xd8.toByte(), 0xee.toByte(), 0x33, 0x57, 0x39, 0x7b, 0x18, 0xa2.toByte(), 0x45, 0x8e.toByte(), 0xfa.toByte(), 0xa9.toByte(), 0x2d, 0xa3.toByte(), 0xb6.toByte(), 0xdf.toByte(), 0x65, 0x14, 0xec.toByte(), 0x06, 0x01, 0x95.toByte(), 0x31, 0x8f.toByte(), 0xd4.toByte(), 0x3b, 0xe9.toByte(), 0xb8.toByte(), 0xf0.toByte(), 0xcc.toByte(), 0x66, 0x9e.toByte(), 0x3f, 0x84.toByte(), 0x40, 0x57, 0xcb.toByte(), 0xdd.toByte(), 0xf8.toByte(), 0xbd.toByte(), 0xa1.toByte(), 0x91.toByte(), 0xbb.toByte(), 0x64, 0x47, 0x3b, 0xc8.toByte(), 0xdc.toByte(), 0x9a.toByte(), 0x73, 0x0d, 0xb8.toByte(), 0xf6.toByte(), 0xb4.toByte(), 0xed.toByte(), 0xe3.toByte(), 0x92.toByte(), 0x41, 0x86.toByte(), 0xff.toByte(), 0xd9.toByte(), 0xb8.toByte(), 0xc7.toByte(), 0x73, 0x57, 0x89.toByte(), 0xc2.toByte(), 0x3a, 0x36, 0xba.toByte(), 0x0b, 0x8a.toByte(), 0xf6.toByte(), 0x53, 0x72, 0xeb.toByte(), 0x57, 0xea.toByte(), 0x5d, 0x89.toByte(), 0xe7.toByte(), 0xd1.toByte(), 0x4e, 0x9c.toByte(), 0x7b, 0x6b, 0x55, 0x74, 0x60, 0xf1.toByte(), 0x08, 0x85.toByte(), 0xda.toByte(), 0x16, 0xac.toByte(), 0x92.toByte(), 0x3f, 0x15, 0xaf.toByte(), 0x37, 0x58, 0xf0.toByte(), 0xf0.toByte(), 0x3e, 0xbd.toByte(), 0x3c, 0x5c, 0x2c, 0x94.toByte(), 0x9c.toByte(), 0xba.toByte(), 0x30, 0x6d, 0xb4.toByte(), 0x4e, 0x6a, 0x2c, 0x07, 0x6c, 0x5f, 0x67, 0xe2.toByte(), 0x81.toByte(), 0xd7.toByte(), 0xef.toByte(), 0x56, 0x78, 0x5d, 0xc4.toByte(), 0xd7.toByte(), 0x59, 0x45, 0xe4.toByte(), 0x91.toByte(), 0xf0.toByte(), 0x19, 0x18, 0x80.toByte(), 0x0a, 0x9e.toByte(), 0x2d, 0xc6.toByte(), 0x6f, 0x60, 0x08, 0x05, 0x66, 0xce.toByte(), 0x0d, 0xaf.toByte(), 0x8d.toByte(), 0x17, 0xea.toByte(), 0xd4.toByte(), 0x6a, 0xd8.toByte(), 0xe3.toByte(), 0x0a, 0x24, 0x7c, 0x9f.toByte()),
        config.partial,             byteArrayOf(byte0x03)config.kernelId,
            config.additionalData         );
    }byteArrayOf(0x24, 0x12, 0x31)),
      contactless.commitSupportedAIDs();
}

Keys configuration (once at startup)

Code Block
private void terminalPublicKeyConfig() {  ...)
        
    publicKey.flush();

    for byte rid[] = {(byte)0xA0, 0x00, 0x00, 0x00, 0x03};(config in publicKeyCfg) {
        byteval idxmaxReached = SingleObjectHolder(byte)0x92;
    byte modulus[] = {0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11};
false)
        val key: PublicKeyData = publicKey.PublicKeyData(
   byte exponentValue[] = {0x03};     byte expirDate[] = {0x22, 0x12, 0x31}; config.rid,
        Holders.SingleObjectHolder<Boolean> wasMaxReached_holder = new Holders.SingleObjectHolder<Boolean>(false);config.idx,
      OlaPublicKey.PublicKeyData key = publicKey.new PublicKeyData(rid, idx, config.modulus,
exponentValue, expirDate);
    publicKey.add(key, null, wasMaxReached_holder);      publicKey.commit();
}

Transaction related data (before each transaction)

Code Block
private void txnSetTransactionRelatedData() {config.exponentValue,
            emv.setTag(OlaTag.TRANSACTION_DATE,config.expirDate
        )
       new byte[]{0x20 publicKey.add(key, 0x10null, 0x28}maxReached);
    }

    publicKey.commit()
}

Transaction related data ()

Code Block
private fun txnSetTransactionRelatedData() {

    Log.v("Transaction",  // 9A
"txnSetTransactionRelatedData")
    emv.setTag(OlaTag.TRANSACTION_TIMEDATE, byteArrayOf(0x20,             new byte[]{0x12, 0x00, 0x00});0x10, 0x28))                          // 9F219A
    emv.setTag(OlaTag.AMOUNTTRANSACTION_AUTHORISED,             new byte[]{0x00, 0x00, 0x00, 0x00, 0x01, 0x50});   // 9F02
    emv.setTag(OlaTag.AMOUNT_OTHER_NUM,TIME, byteArrayOf(0x12, 0x00, 0x00))                 new byte[]{0x00, 0x00, 0x00, 0x00, 0x00, 0x50});   // 9F039F21
    emv.setTag(OlaTag.TRANSACTIONAMOUNT_CURRENCY_CODEAUTHORISED, byteArrayOf(0x00, 0x00, 0x00,  new byte[]{0x08, 0x40});0x00, 0x01, 0x50))       // 9F02
    emv.setTag(OlaTag.AMOUNT_OTHER_NUM, byteArrayOf(0x00, 0x00, 0x00, 0x00, 0x00, 0x50))        // 5F2A9F03
    emv.setTag(OlaTag.TRANSACTION_CURRENCY_EXPONENT, new byte[]{0x02});          CODE, byteArrayOf(0x08, 0x40))                       // 5F365F2A
    emv.setTag(OlaTag.TRANSACTION_CURRENCY_TYPE,              new byte[]{0x00});EXPONENT, byteArrayOf(0x02))                         // 5F36
    emv.setTag(OlaTag.TRANSACTION_TYPE, byteArrayOf(0x00)) // 9C      /*      * Other possible tags to set here:      * Account Type (5F57)      * Transaction Category Code (9F53)// 9C

    /*
      * AllOther otherpossible tags mustto be set throughhere:
the combinations!      */
}

Preprocessing

Code Block
private OlaError txnPreProcess() { Account Type (5F57)
      * OlaErrorTransaction retCategory =Code contactless.preprocess(9F53);
    if (ret != OlaError.OLA_OK)*
     { * All other tags must be set  Log.e("OLA-TESTER", "contactless pre-process failed");through the combinations!
      }*/
     return retemv.setTag(0x9F53, byteArrayOf(0x11));
}

...

Preprocessing

Code Block
private shortfun txnGetCardtxnPreProcess(): OlaError {

    Log.dv("OLA-TESTERTransaction", "PRESENT CARDtxnPreProcess");

 
    val ret = contactless.preprocess()
  int foundTechnos   if (ret != dev.technoPolling(60000);OlaError.OLA_OK) {
        l("Result of foundTechnos: "+ foundTechnos);Log.e("Transaction", "txnPreProcess - contactless pre-process failed")
    }
if (foundTechnos==4)   return  {
   ret
}

Card detection

Code Block
private fun txnGetCard(): Int {

   return clcEMV_CARD; //TODO remove hard-coding
    } Log.v("Transaction", "txnGetCard - **** PRESENT CARD ****")
    val elsefoundTechnos = dev.technoPolling(30)
  {  Log.v("Transaction", "txnGetCard - result of foundTechnos:  return 0;$foundTechnos")
    return }
}

Do transaction

Code Block
private OlaError doTransaction(if (foundTechnos == 4) {
     SingleObjectHolder<Integer> nbCandidatesHolder = new SingleObjectHolder<Integer>();
 clcEMV_CARD //TODO remove hard-coding
  OlaError ret = contactless.buildCandidateList(nbCandidatesHolder);
} else {
    if (ret != OlaError.OLA_OK) 0
   { }
}

Do transaction

Code Block
private fun doTransaction(): OlaError {

 showOutcome(ret);   Log.v("Transaction", "doTransaction }- buildCandidateList")
    /*val nbCandidatesHolder = SingleObjectHolder<Int>()
  * For now,var finalSelectCandidateret is useless. Everything from preprocessing to card
     * processing is done in "buildCandidateList". This will change as soon as exit conditions
= contactless.buildCandidateList(nbCandidatesHolder)
    if (ret != OlaError.OLA_OK) {
        Outcome.showOutcome(contactless, ret)
    }
    *
are availble in OLA 2.xLog.v("Transaction", hence"doTransaction we- keepnb allof the function calls herecandidates: ${nbCandidatesHolder.get()}")
    Log.v("Transaction", "doTransaction - */finalSelectCandidate")
    SingleObjectHolder<Byte>val kernel_id_holder = new SingleObjectHolder<Byte>();
    ret = contactless.finalSelectCandidate(1, kernel_id_holder);
    if (ret != OlaError.OLA_OK) {
        {Outcome.showOutcome(contactless, ret)
    }

  showOutcome(ret);  Log.v("Transaction", "doTransaction - }
doTransaction")
    ret = contactless.doTransaction();
    Outcome.showOutcome(contactless, ret);
     if (ret == OlaError.OLA_OK)     {
        SingleObjectHolder<byte[]>val bytesHolder = new SingleObjectHolder<byte[]>SingleObjectHolder<ByteArray>();
     
  for (int olaTag : batch)     for (olaTag in batch) {
            OlaErrorval result = emv.getTag(olaTag, bytesHolder);
            if (result == OlaError.OLA_OK) {
                Log.v("Transaction", "doTransaction - result for getTag(): $result => " +
                l("Result for ola_contactless_get_tag(): "+result+" => "+ ArraysUtils.toStringbytesToHex(bytesHolder.get()));
            } else {
                Log.v("Transaction", "doTransaction - result for getTag(): $result => tag missing")

      l("Result for ola_contactless_get_tag(): "+result+" => tag missing");}
        }
    }

    Log.d("OLA-TESTERTransaction", "doTransaction - **** REMOVE CARD **** ")

    contactless.clean();

    return ret;
}