• Dieses Forum dient dem Erfahrungsaustausch und nicht dem (kommerziellen) Anbieten von Incentives zum Abschluss einer neuen Kreditkarte.

    Wer sich werben lassen möchte, kann gerne ein entsprechendes Thema im Bereich "Marketplace" starten.
    Wer neue Karteninhaber werben möchte, ist hier fehl am Platz. Das Forum braucht keinen Spam zur Anwerbung neuer Kreditkarteninhaber.

    Beiträge, bei denen neue Kreditkarteninhaber geworben werden sollen, werden ohne gesonderte Nachricht in beiden Foren entfernt.

    User, die sich zum Werben neuer Kreditkarteninhaber neu anmelden, werden wegen Spam direkt dauerhaft gesperrt. User, die an anderer Stelle im Forum mitdiskutieren, sich aber nicht an diese Regeln halten, müssen mit mindestens 7 Tagen Forenurlaub rechnen.

CVM-Listen

ANZEIGE

Escorpio

Erfahrenes Mitglied
30.01.2015
7.653
706
ANZEIGE
In dem Fall scheint es keine Auswahl zwischen zwei "APP's" wie Visa/VPay bzw. Mastercard/Maestro zu sein.

Alles läuft über Mastercard und man hat folgende Optionen

1. Debit (Sofortabbuchung vom Girokonto) bzw. monatliche Abbuchung
2. Ratenzahlung verteilt auf 3 Monate, Zinsfrei, innerhalb des Kreditlimits
3. Zahlung nach 3 Monaten, Zinsfrei, innerhalb des Kreditlimits (danach möglich auf Kredit mit Zinsen zu wechseln.. kA ob die Zinsen die ersten 3 Monate nachbelastet werden)
4. Kredit (sofort mit Zinsen verbunden)
5. Sparkonto (Optional kann man eine Art Tagesgeldkonto einrichten und von da abbuchen lassen)
So.. ich habe die Karte jetzt und den Chip mal ausgelesen. Es sind zwei APP's drauf, beide mit gleicher Kartennummer (wie auf der Karte geprägt) und diese heißen beide "Comptant". Was übersetzt so viel wie Bargeld heißt, gemeint ist damit aber je nach Einstellung der Bank, eine Debit bzw. verschobenes Debit (Abbuchung einmal im Monat) Zahlung gemeint. Am Terminal werden zumindest in Frankreich, die oben genannten 5 Möglichkeiten angezeigt (Foto vom Terminal reiche ich nach).

Online jedoch nur "Comptant" (Laut Liste Nr. 1) und Credit (Laut Liste Nr. 4)
Bildschirmfoto 2023-05-15 um 16.23.35.png
Also scheinen nur zwei Zahlungsoptionen ohne EMV Chip möglich zu sein, mit EMV allerdings min. 5. Das ganze aber scheinbar nicht via APP's geregelt.

Apple Pay Zahlungen werden automatisch als Comptant (Laut Liste Nr. 1) abgerechnet.

Zahlungen mit monatlicher Abbuchung (Laut Liste Nr. 1) haben ein eigenen und unabhängigen monatlichen Verfügungsrahmen. Dieses ist auch kommuniziert.
Die Kredit Optionen (Laut Liste Nr. 4) einen eigenen Kreditrahmen. Dieses ist auch kommuniziert.
Min. die Ratenzahlung (Laut Liste Nr. 2) scheint nicht nicht in eines der beiden Kreditlimite zu fallen, zumindest wird der Verfügbare Betrag nicht reduziert. Laut Webseite allerdings, bewegen sich diese Zahlungen innerhalb des Kreditlimits (kA. welches von beiden).
Zahlung nach 3 Monaten (Laut Liste Nr. 3) noch nicht ausprobiert.

Bildschirm­foto 2023-05-15 um 16.40.01.png

Wenn ich schlauer bin, kommt noch ein Nachtrag.
 
Zuletzt bearbeitet:

tcu99

Erfahrenes Mitglied
26.08.2016
6.525
1.141
Aus: https://www.vielfliegertreff.de/forum/threads/commerzbank-comdirect-sammelthread.138456/post-3859043 . Es passt hier vermutlich besser.

Ich habe nochmal die comdirect VISA Credit auslesen können.

CVM Liste, nach wie vor ohne Offline PIN.

Limits:
LCOL: 3
UCOL: 5
CTTAL: 50€
CTTAUL: 150€
Service Code: 201
  1. Fail cardholder verification if this CVM is unsuccessful: Enciphered PIN verified online - If terminal supports the CVM
  2. Fail cardholder verification if this CVM is unsuccessful: Signature (paper) - If terminal supports the CVM
  3. Fail cardholder verification if this CVM is unsuccessful: No CVM Required - Always
Die VISA Debit ist ähnlich konfiguriert. Service Code 221. Offline geht die Karte nicht (LCOL und UCOL auf 0). Also keine Änderung.
 
  • Like
Reaktionen: JFI und eddi78

eddi78

Aktives Mitglied
12.05.2018
157
98
CVM-Listen der Sparkassen-Card Mastercard Debit. Die Karte hat 4 CVM-Listen, vermutlich haben beide Applikationen Offline-PIN. Der Servicecode für Girocard ist 201, der für Mastercard Debit leider 221. Da die Karten aber meist eh mit einem saftigen FWG kommen, sind Einsätze in Fremdwährung ja sowieso eher selten.

Kannst Du das nochmal anschauen, da scheint die CVM Liste der Mastercard Debit zu fehlen. Die aufgeführten gehören zur Girocard. Bei meiner Sparkassen-Card MC-Debit mit Rohling (01/22) gibt es für den Mastercard-Teil (Application A0000000041010) zwei CVM Listen:
file5->record2
Screenshot_2023-06-03_16-58-53.png
und file5->record5
Screenshot_2023-06-03_17-09-16.png
 

BR 612

Erfahrenes Mitglied
08.01.2020
5.211
2.607
Oberpfalz
Ich habe mir die Karte nochmal angesehen (in Cardpeek). Diesmal bei "Get Process Options" (oder so ähnlich) No angeklickt (vorher Yes). Der Karte lies sich keine weitere CVM-Liste entlocken.
Auch wenn sich einige (zu Recht) wieder über mich lustig machen: Ja. Ich war einfach scharf auf die neue Karte. Und da es allem Anschein nach bei der Raiba HT keine GC/MC Debit wird (ich weiß, ungelegte Eier und so), naja. Zahle ich halt knapp 4,95 €. Mir egal.
Mir ging es darum, eine universelle Karte zu haben. Mein Metzger mag es lieber, mit Girocard bezahlt zu werden und andere Akzeptanzstellen mit SumUp nehmen nur Mastercard. Und ich habe keine Lust, ständig die andere App zu öffnen. Auch sonst sind die VR Banken trotz neuem Banking noch hinter der SPK zurück. Keine Push Nachrichten, Secure Go nur per Brief usw.
 

eddi78

Aktives Mitglied
12.05.2018
157
98
Ich habe mir die Karte nochmal angesehen (in Cardpeek). Diesmal bei "Get Process Options" (oder so ähnlich) No angeklickt (vorher Yes). Der Karte lies sich keine weitere CVM-Liste entlocken.
Hmm, das ist seltsam. Meine Daten habe ich auch mit Cardpeek ausgelesen. Diese Application A0000000041010 scheint immer Mastercard zu sein. So isses bei meinen anderen Mastercard Karten auch und zwar egal ob Debit oder Credit. Und unter eben dieser Application bekomme ich die oben abgebildeten CVM Listen bei der Sparkassen-Card. Ausserdem sind noch drei Applications der Girocard drauf, mit CVM Listen, wie sie in dem emv forum gepostet sind und noch eine Geldkarten-Application. Die Mastercard ist die vorletzte und die Geldkarte die letzte Application.
 

BR 612

Erfahrenes Mitglied
08.01.2020
5.211
2.607
Oberpfalz
Ich habe bislang mit der physischen Karte noch nicht über das Co-Badge gezahlt. Heute nur einmal über Girocard. Wenn ich beim nächsten Mal dran denke, werde ich per physischer Karte mit Mastercard zahlen (ggf. erzwungen per AppSelect) und die Karte dann ein weiteres Mal auslesen.
 

eddi78

Aktives Mitglied
12.05.2018
157
98
Ich habe bislang mit der physischen Karte noch nicht über das Co-Badge gezahlt. Heute nur einmal über Girocard. Wenn ich beim nächsten Mal dran denke, werde ich per physischer Karte mit Mastercard zahlen (ggf. erzwungen per AppSelect) und die Karte dann ein weiteres Mal auslesen.Ok
War bei mir auch nicht der Fall. Habe die Karte nur ein Mal überhaupt benutzt als ich sie bekommen hatte. Das war eine Girocard-Zahlung gesteckt mit PIN Eingabe. Vielleicht liegts ja am Rohling, meiner ist bissl älter (7 Monate).
 

tcu99

Erfahrenes Mitglied
26.08.2016
6.525
1.141
CVM-Listen der Sparkassen-Card Mastercard Debit. Die Karte hat 4 CVM-Listen, vermutlich haben beide Applikationen Offline-PIN. Der Servicecode für Girocard ist 201, der für Mastercard Debit leider 221. Da die Karten aber meist eh mit einem saftigen FWG kommen, sind Einsätze in Fremdwährung ja sowieso eher selten.

Unabhängig davon: 221 Service Code heißt übrigens nicht, dass eine Karte kein Offline Limit haben kann.
Das ist z.B. bei den Solarisbank Karten so.

Genauso ist 201 keine Garantie für Offline Fähigkeit. Bei Wise steht das Offline Limit z.B. auf 0, obwohl die Karte einen 201 Service Code hat.
 
Zuletzt bearbeitet:

AJ44

Erfahrenes Mitglied
24.03.2019
7.518
6.673
Unabhängig davon: 221 Service Code heißt übrigens nicht, dass eine Karte kein Offline Limit haben kann.
Das ist z.B. bei den Solarisbank Karten so.

Genauso ist 201 keine Garantie für Offline Fähigkeit. Bei Wise steht das Offline Limit z.B. auf 0, obwohl die Karte einen 201 Service Code hat.
Es ist und bleibt somit irgendwie undurchsichtig. Da steigt man dann ja auch kaum noch durch welche Karte jetzt wirklich gut konfiguriert ist.
 

BR 612

Erfahrenes Mitglied
08.01.2020
5.211
2.607
Oberpfalz
Unabhängig davon: 221 Service Code heißt übrigens nicht, dass eine Karte kein Offline Limit haben kann.
Das ist z.B. bei den Solarisbank Karten so.

Genauso ist 201 keine Garantie für Offline Fähigkeit. Bei Wise steht das Offline Limit z.B. auf 0, obwohl die Karte einen 201 Service Code hat.
221 mit Offline Limit ist aber dennoch nicht offline fähig. Das 201er Karten auch de facto nur onlinefähig sein können, wenn sie kein UCOL und UCOTA haben, ist mir auch bewusst.
Glücklicherweise ist die Karte bei mir ja nicht allein im Portfolio. Wise und Advanzia (wobei beide lt. der neuen CreditCard-Checker App auch keine Offline-Limits, aber beide 201 [wobei Advanzia definitiv mal welche hatte])
Ich war so frei und habe die ausgelesenen Daten im Wiki ergänzt.
 

Manaburner

Erfahrenes Mitglied
22.01.2020
865
597
Ich habe mir die Karte nochmal angesehen (in Cardpeek). Diesmal bei "Get Process Options" (oder so ähnlich) No angeklickt (vorher Yes). Der Karte lies sich keine weitere CVM-Liste entlocken.

Auch wenn sich einige (zu Recht) wieder über mich lustig machen: Ja. Ich war einfach scharf auf die neue Karte. Und da es allem Anschein nach bei der Raiba HT keine GC/MC Debit wird (ich weiß, ungelegte Eier und so), naja. Zahle ich halt knapp 4,95 €. Mir egal.
Mir ging es darum, eine universelle Karte zu haben. Mein Metzger mag es lieber, mit Girocard bezahlt zu werden und andere Akzeptanzstellen mit SumUp nehmen nur Mastercard. Und ich habe keine Lust, ständig die andere App zu öffnen. Auch sonst sind die VR Banken trotz neuem Banking noch hinter der SPK zurück. Keine Push Nachrichten, Secure Go nur per Brief usw.
Bei welcher Sparkasse?
 

mattes77

Erfahrenes Mitglied
14.06.2016
3.019
1.479
Ich als absoluter Laie (der keine technischen Kenntnisse hat, sich aber trotzdem unter anderem z.B. wegen des
Nutzens von Karten an Automaten Tankstellen sehr für die Konfiguration der Karten interessiert)
würde sagen, dass z. B. die Openbank R42 Karte hervorragend konfiguriert ist! (anhamd des von JFI und
anderen gepflegten wikis!).

Kurz offtopic zur Karte:

Bei uns am Ort kann ich die R42 Karte aber z.B. nicht mehr so einfach einfach nutzen. Ein Tankautomat der BayWa z.B.
will seit Anfang 2023 immer 180 € im Voraus blocken statt wie früher 80 €!!


Die Ikano Rote Mastercard war damals auch top konfiguriert, Sie hatte meiner Erinnerung nach auch ähnliche offline
Limits wie die Openbank. Als ich sie das einzige Mal ausgetauscht bekam. schickte mit der Kundenservice zudem auf
meine ausdrückliche Bitte eine Karte ohne NFC Funktion zu. Ich vermisse die Karte und habe eigentlich nie vollwertigen
Ersatz gefunden!
:idea:
 
Zuletzt bearbeitet:

BR 612

Erfahrenes Mitglied
08.01.2020
5.211
2.607
Oberpfalz
Bei welcher Sparkasse?
Taunus Sparkasse. Die lokalen Sparkassen sind alle ganz schön teuer. Es gibt keine, wo der Grundpreis unter 5 € ist und bei fast allen ist entweder Kontowecker oder push TAN zusätzlich bepreist. Darauf habe ich keine Lust. 5 € ist bei mir die Schmerzgrenze für ein Konto, bei einem sehr guten Konto von mir aus auch 6-7 €, aber mehr nicht. Weitere Details siehe mein neuster Post im Zahlkartenportfolio.
würde sagen, dass z. B. die Openbank R42 Karte hervorragend konfiguriert ist! (anhamd des von JFI und
anderen gepflegten wikis!).
Ob die Karte die Offline-Limits immer noch hat, ist unsicher. Die gepostete Karte ist mittlerweile auch 3 Jahre alt und mit 30 € sind die Offline-Limits sowieso nicht besonders hoch. Für ein paar Getränke im Flugzeug oder für die Autobahnmaut mag das reichen, für mehr aber auch nicht. Immerhin hat die Karte Offline-PIN.
Bei uns am Ort kann ich die R42 Karte aber z.B. nicht mehr so einfach einfach nutzen. Ein Tankautomat der BayWa z.B.
will seit Anfang 2023 immer 180 € im Voraus blocken statt wie früher 80 €!!
Angesichts der massiv gestiegenen Tankpreise (und der Steigerung der Gewinnmargen der Ölmultis, es gibt keinen Grund, dass Benzin 1,80 € kostet, wenn man bedenkt, dass der Ölpreis wieder auf dem Stand von 2018 ist [damals war Benzin bei 1,40 € und galt als teuer]) und die Steuern nicht um 0,40 € pro Liter gestiegen sind) kein Wunder. Da es ja immer mehr Debitkarten gibt (wo eben erstmal Kontoguthaben geblockt wird) und viele Tankstellen mit solchen Tankautomaten arbeiten, würde ich mir wünschen, man könnte am Terminal den Maximalbetrag auswählen. Wenn man nur für 20 € tanken möchte, sollte man z. B. 20 € auswählen (oder von mir aus auch 30 oder 40 €) können, damit nicht direkt 180 € geblockt werden obwohl man weiß, dass man nur 20 € reinfüllen wird.
Und bevor hier wieder die Spezialisten um die Ecke kommen: Ja, viele hier im Forum dürften die Liquidität haben, aber eben nicht alle. Teilweise scheint es auch noch Banken zu geben, wo der Differenzbetrag zw. Autorisierung und Tankung erst 2 Tage später mit der endgültigen Buchung freigegeben wird.
 
Zuletzt bearbeitet:
  • Like
Reaktionen: Manaburner

tcu99

Erfahrenes Mitglied
26.08.2016
6.525
1.141
221 mit Offline Limit ist aber dennoch nicht offline fähig. Das 201er Karten auch de facto nur onlinefähig sein können, wenn sie kein UCOL und UCOTA haben, ist mir auch bewusst.
Glücklicherweise ist die Karte bei mir ja nicht allein im Portfolio. Wise und Advanzia (wobei beide lt. der neuen CreditCard-Checker App auch keine Offline-Limits, aber beide 201 [wobei Advanzia definitiv mal welche hatte])
Ich war so frei und habe die ausgelesenen Daten im Wiki ergänzt.

Das ist nicht richtig, Stefan.
Die Offline Limits geben genau an, wann eine Karte offline abgelehnt werden muss und das ist die bindene Grenze bei EMV Transaktionen.
Der Service Code ist für den Magnetstreifen wichtig und stammt aus der ISO/IEC 7813, hat aber nicht wirklich was mit Chip Transaktionen zu tun. Das findet man raus, wenn man einfach den passenden Wikipedia Eintrag dazu liest.
Offline Magstripe ist auch nahezu verschwunden, weil es ein hohes Risiko darstellt und EMV sich als Standard auch etabliert hat.

Daher durchaus nachvollziehbar, dass man den Service Code heute auf 221 flippt und die Offlinemöglichkeit nur über EMV abbildet.
Das kann man auch ohne Probleme in den EMV Docs nachlesen. Die Bedeutung der Tags ist frei einsehbar im Internet ;)
 

BR 612

Erfahrenes Mitglied
08.01.2020
5.211
2.607
Oberpfalz
Das ist nicht richtig, Stefan.
Die Offline Limits geben genau an, wann eine Karte offline abgelehnt werden muss und das ist die bindene Grenze bei EMV Transaktionen.
Der Service Code ist für den Magnetstreifen wichtig und stammt aus der ISO/IEC 7813, hat aber nicht wirklich was mit Chip Transaktionen zu tun. Das findet man raus, wenn man einfach den passenden Wikipedia Eintrag dazu liest.
Offline Magstripe ist auch nahezu verschwunden, weil es ein hohes Risiko darstellt und EMV sich als Standard auch etabliert hat.

Daher durchaus nachvollziehbar, dass man den Service Code heute auf 221 flippt und die Offlinemöglichkeit nur über EMV abbildet.
Das kann man auch ohne Probleme in den EMV Docs nachlesen. Die Bedeutung der Tags ist frei einsehbar im Internet ;)
Ok, dann lag ich da falsch. Aber: Welcher Wikipedia Eintrag genau? Im EMV Artikel habe ich nichts dazu gefunden.
Dann wäre 221 ja gar nicht so schlimm, wenn die Offline-Limits ausschlaggebend sind. Bedeutet aber auch dass neuere Advanzia-Karten z. B. nicht offline fähig sind und die Karten der Solarisbank, C24 Bank oder Comdirect schon. Zum Glück befinden sich Offline-Transaktionen aber eh immer mehr auf dem Rückzug.
 

tcu99

Erfahrenes Mitglied
26.08.2016
6.525
1.141
Es geht auch mit Cardpeek.
Dazu dieses Skript verwenden und in Cardpeek laden (mit einem Editor als .lua speichern und in den script Ordner von Cardpeek ablegen). Klappt mit Mastercard und Visa (sollte zumindest mit 95% der Karten gehen). Ich hoffe, dass ich die Frage dann nicht nochmal 590x in diesem Forum lesen muss :D

Das (Ur-)Skript gibt es hier bei Github https://github.com/L1L1/cardpeek

Ich gebe keinen Support!
Das Skript wird dann als "EMV2" auswählbar. Viel Spaß damit

Code:
--
-- This file is part of Cardpeek, the smartcard reader utility.
--
-- Copyright 2009-2015 by 'L1L1'
--
-- Cardpeek is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- Cardpeek is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with Cardpeek.  If not, see <http://www.gnu.org/licenses/>.
--
-- @name EMV2
-- @description Bank cards 'PIN and chip'
-- @targets 0.8
--
-- History:
-- Aug 07 2010: Corrected bug in GPO command.
-- Aug 08 2010: Corrected bug in AFL data processing
-- Mar 27 2011: Added CVM patch from Adam Laurie.
-- Jan 23 2012: Added UK Post Office Card Account in AID list from Tyson Key.
-- Mar 25 2012: Added a few AIDs
-- Feb 21 2014: Better NFC compatibility by using current date in GPO.
-- Nov 16 2014: Many improvements from Andrew Kozlic (Many new AIDs, parses AIP, GPO Format 1, AFLs, and more.)
-- Jun 23 2023: Readout of offline limits added
-- @update March 05 2014: Avoid error when card don't have tag 82 or 94 in GPO (issue 62)

require('lib.tlv')
require('lib.strict')

--------------------------------------------------------------------------
-- GLOBAL EMV CARD COMMANDS extending general lib.apdu
--------------------------------------------------------------------------

function build_empty_pdol_data_block(pdol)
    local data = bytes.new(8);
    local o_tag
    local o_len

    while pdol do
        o_tag, pdol = asn1.split_tag(pdol)
        o_len, pdol = asn1.split_tag(pdol)

        if o_tag==0x9F66 and o_len==4 then
            --  Terminal Transaction Qualifiers (VISA)
            data = data .. "30 00 00 00"
        elseif o_tag==0x9F1A and o_len==2 then
            -- Terminal country code
            data = data .. "0250"
        elseif o_tag==0x5F2A and o_len==2 then
            -- Transaction currency code
            data = data .. "0978"
        elseif o_tag==0x9A and o_len==3 then
            -- Transaction date
            data = data .. os.date("%y %m %d")
        elseif o_tag==0x9F37 and o_len==4 then
            -- Unpredictable number
            data = data .. "DEADBEEF"
        else
            -- When in doubt Zeroize
            while o_len > 0 do
                data = data .. 0x00
                o_len = o_len-1
            end
        end
    end
    return data
end

function card.get_processing_options(pdol)
    local command
    local pdol_data
    if pdol and #pdol>0 then
       pdol_data = build_empty_pdol_data_block(pdol)
       command = bytes.new(8,"80 A8 00 00",#pdol_data+2,0x83,#pdol_data,pdol_data,"00")
    else
       command = bytes.new(8,"80 A8 00 00 02 83 00 00")
    end
    return card.send(command)
end

-- override card.get_data() for EMV
function card.get_data(data)
        local command = bytes.new(8,"80 CA",bit.AND(bit.SHR(data,8),0xFF),bit.AND(data,0xFF),0)
        return card.send(command)
end


-- ------------------------------------------------------------------------
-- EMV
-- ------------------------------------------------------------------------

TRANSACTION_TYPE = {
  [0]="Purchase",
  [1]="Cash"
}

function ui_parse_transaction_type(node,cc)
    local tt = TRANSACTION_TYPE[cc[0]]
    if tt == nil then
       return tostring(cc)
    end
    nodes.set_attribute(node,"val",cc)
    nodes.set_attribute(node,"alt",tt)
    return true
end

function ui_parse_CVM(node,data)
    local i
    local left
    local right
    local leftstring
    local rightstring
    local subnode
    local out

    nodes.append(node,{    classname="item",
                      label="X",
                size=4,
                val=bytes.sub(data,0,3)})

    nodes.append(node,{    classname="item",
                label="Y",
                size=4,
                val=bytes.sub(data,4,7)})

    for i= 4,(#data/2)-1 do
        left = data:get(i*2)
        right = data:get(i*2+1)

        if left == 0 and right == 0 then
            -- Amex pads the list with zeroes at the end
            -- Once we reach the zeroes, we're done parsing
            break
        end
      
        subnode = nodes.append(node, { classname="item",
                           label="CVM",
                           id=i-3,
                           size=2,
                           val=bytes.sub(data,i*2,i*2+1)})

        if bit.AND(left,0x40) == 0x40 then
            out = "Apply succeeding CV rule if this rule is unsuccessful: "
        else
            out = "Fail cardholder verification if this CVM is unsuccessful: "
        end

        if CVM_REFERENCE_BYTE1[bit.AND(left,0xBF)] == nil then
            leftstring = string.format("Unknown (%02X)",left)
        else
            leftstring = CVM_REFERENCE_BYTE1[bit.AND(left,0xBF)]
        end
        if CVM_REFERENCE_BYTE2[right] == nil then
            rightstring = string.format("Unknown (%02X)",right)
        else
            rightstring = CVM_REFERENCE_BYTE2[right]
        end
        out = out .. leftstring .. " - " .. rightstring
        nodes.set_attribute(subnode,"alt",out)
    end
        nodes.set_attribute(node,"val",data)
    return true
end


function ui_parse_bits(node,data,reference,data_label)
    local i
    local j
    local meaning
  
    nodes.set_attribute(node,"val",data)
    for i = 1,#data do
        for j = 8,1,-1 do
            if bit32.extract(data[i-1], j-1) ~= 0 then
                if reference[i][j] == nil then
                    meaning = "Unknown"
                else
                    meaning = reference[i][j]
                end
                nodes.append(node,{ classname="item",
                                                  label=data_label,
                                                  id=string.format("%d.%d",i,j),
                                                  val=meaning })
            end
        end
    end
end

function ui_parse_AIP(node,data)
    ui_parse_bits(node,data,AIP_REFERENCE,"Application Function")
end

function ui_parse_AUC(node,data)
    ui_parse_bits(node,data,AUC_REFERENCE,"Application Usage")
end

function ui_parse_IAC(node,data)
    ui_parse_bits(node,data,IAC_REFERENCE,"Condition")
end

function ui_parse_DOL(node,data)
    local tag
    local len
    local tag_name
    local tag_func
    local list

    nodes.set_attribute(node, "val", data)

    list = ""
    while data
    do
        tag, data = asn1.split_tag(data)
        len, data = asn1.split_length(data)
        tag_name, tag_func = tlv_tag_info(tag, EMV_REFERENCE, 0);
        if tag_name == nil then
            tag_name = TLV_TYPES[bit.SHR(tlv_tag_msb(tag),6)+1];
        end
        list = list .. string.format("%s %X [%d]. ", tag_name, tag, len);
    end
    nodes.set_attribute(node, "alt", list);
end

function ui_parse_TL(node,data)
    local tag
    local tag_name
    local tag_func
    local list

    nodes.set_attribute(node, "val", data)

    list = ""
    while data
    do
        tag, data = asn1.split_tag(data)
        tag_name, tag_func = tlv_tag_info(tag, EMV_REFERENCE, 0);
        if tag_name == nil then
            tag_name = TLV_TYPES[bit.SHR(tlv_tag_msb(tag),6)+1];
        end
        list = list .. string.format("%s %X. ", tag_name, tag);
    end
    nodes.set_attribute(node, "alt", list);
end

function ui_parse_AFL(node,data)
    local ref
    local i

    nodes.set_attribute(node, "val", data)

    if #data % 4 ~= 0 then
    log.print(log.WARNING,"Size of AFL is not a multiple of 4")
        return
    end

    for i=0,#data-1,4 do
        ref = nodes.append(node,{ classname="item",
                                  label="Item",
                                  id=i/4 + 1,
                                  val=bytes.sub(data,i,i+3),
                                  size=4 })
        nodes.append(ref,{ classname="item",
                           label="Short File Identifier (SFI)",
                           id='88',
                           val=bit.SHR(data:get(i),3),
                           size=1 })
        nodes.append(ref,{ classname="item",
                           label="First record",
                           val=data:get(i+1),
                           size=1 })
        nodes.append(ref,{ classname="item",
                           label="Last record",
                           val=data:get(i+2),
                           size=1 })
        nodes.append(ref,{ classname="item",
                           label="Number of records involved in offline data authentication",
                           val=data:get(i+3),
                           size=1 })
      
    end
end

CVM_REFERENCE_BYTE1 = {
   [0x00] = "Fail CVM processing",
   [0x01] = "Plaintext PIN verification performed by ICC",
   [0x02] = "Enciphered PIN verified online",
   [0x03] = "Plaintext PIN verification performed by ICC and signature (paper)",
   [0x04] = "Enciphered PIN verification performed by ICC",
   [0x05] = "Enciphered PIN verification performed by ICC and signature (paper)",
   [0x1E] = "Signature (paper)",
   [0x1F] = "No CVM Required",
}

CVM_REFERENCE_BYTE2 = {
   [0x00] = "Always",
   [0x01] = "If unattended cash",
   [0x02] = "If not attended cash and not manual cash and not purchase with cashback",
   [0x03] = "If terminal supports the CVM",
   [0x04] = "If manual cash",
   [0x05] = "If purchase with cashback",
   [0x06] = "If transaction is in the application currency and is under X value",
   [0x07] = "If transaction is in the application currency and is over X value",
   [0x08] = "If transaction is in the application currency and is under Y value",
   [0x09] = "If transaction is in the application currency and is over Y value"
} 

AIP_REFERENCE = {
  [1] = { -- Byte 1
    [1] = "CDA supported",
    [3] = "Issuer authentication is supported",
    [4] = "Terminal risk management is to be performed",
    [5] = "Cardholder verification is supported",
    [6] = "DDA supported",
    [7] = "SDA supported"
  },
  [2] = { -- Byte 2
  }
}

AUC_REFERENCE = {
  [1] = { -- Byte 1
    [1] = "Valid at terminals other than ATMs",
    [2] = "Valid at ATMs",
    [3] = "Valid for international services",
    [4] = "Valid for domestic services",
    [5] = "Valid for international goods",
    [6] = "Valid for domestic goods",
    [7] = "Valid for international cash transactions",
    [8] = "Valid for domestic cash transactions"
  },
  [2] = { -- Byte 2
    [7] = "International cashback allowed",
    [8] = "Domestic cashback allowed"
  }
}

IAC_REFERENCE = {
  [1] = { -- Byte 1
    [3] = "CDA failed",
    [4] = "DDA failed",
    [5] = "Card appears on terminal exception file",
    [6] = "ICC data missing",
    [7] = "SDA failed",
    [8] = "Offline data authentication was not performed"
  },
  [2] = { -- Byte 2
    [4] = "New card",
    [5] = "Requested service not allowed for card product",
    [6] = "Application not yet effective",
    [7] = "Expired application",
    [8] = "ICC and terminal have different application versions"
  },
  [3] = { -- Byte 3
    [3] = "Online PIN entered",
    [4] = "PIN entry required, PIN pad present, but PIN was not entered",
    [5] = "PIN entry required and PIN pad not present or not working",
    [6] = "PIN Try Limit exceeded",
    [7] = "Unrecognised CVM",
    [8] = "Cardholder verification was not successful"
  },
  [4] = { -- Byte 4
    [4] = "Merchant forced transaction online",
    [5] = "Transaction selected randomly for online processing",
    [6] = "Upper consecutive offline limit exceeded",
    [7] = "Lower consecutive offline limit exceeded",
    [8] = "Transaction exceeds floor limit"
  },
  [5] = { -- Byte 5
    [5] = "Script processing failed after final GENERATE AC",
    [6] = "Script processing failed before final GENERATE AC",
    [7] = "Issuer authentication failed",
    [8] = "Default TDOL used"
  }
}

EMV_REFERENCE = {
   ['5D'] = {"Directory Definition File (DDF) Name" },
   ['61'] = {"Application Template" },
   ['70'] = {"Application Data File (ADF)" },
   ['71'] = {"Issuer Script Template 1" },
   ['77'] = {"Response Message Template Format 2" },
   ['80'] = {"Response Message Template Format 1" },
   ['82'] = {"Application Interchange Profile (AIP)", ui_parse_AIP },
   ['87'] = {"Application Priority Indicator" },
   ['88'] = {"Short File Identifier (SFI)" },
   ['89'] = {"Authorisation Code" },
   ['8A'] = {"Authorisation Response Code" },
   ['8C'] = {"Card Risk Management Data Object List 1 (CDOL1)", ui_parse_DOL },
   ['8D'] = {"Card Risk Management Data Object List 2 (CDOL2)", ui_parse_DOL },
   ['8E'] = {"Cardholder Verification Method (CVM) List", ui_parse_CVM },
   ['8F'] = {"Certificate Authority Public Key Index (PKI)" },
   ['90'] = {"Issuer PK Certificate" },
   ['91'] = {"Issuer Authentication Data" },
   ['92'] = {"Issuer PK Remainder" },
   ['93'] = {"Signed Static Application Data" },
   ['94'] = {"Application File Locator (AFL)", ui_parse_AFL },
   ['95'] = {"Terminal Verification Results (TVR)" },
   ['97'] = {"Transaction Certificate Data Object List (TDOL)", ui_parse_DOL },
   ['98'] = {"Transaction Certificate (TC) Hash Value" },
   ['99'] = {"Transaction Personal Identification Number (PIN) Data" },
   ['9A'] = {"Transaction Date", ui_parse_YYMMDD },
   ['9B'] = {"Transaction Status Information" },
   ['9C'] = {"Transaction Type", ui_parse_transaction_type },
   ['9D'] = {"Directory Definition File (DDF) Name" },
   ['A5'] = {"FCI Proprietary Template" },
   ['CA'] = {"Lower Cum. Offline Transaction Amt (LCOTA)" },
   ['CB'] = {"Upper Cum. Offline Transaction Amt (UCOTA)" },
   ['5F36'] = {"Transaction Currency Exponent" },
   ['5F53'] = {"International Bank Account Number (IBAN)" },
   ['5F54'] = {"Bank Identifier Code (BIC)" },
   ['5F55'] = {"Issuer Country Code (alpha2 format)" },
   ['5F56'] = {"Issuer Country Code (alpha3 format)" },
   ['9F01'] = {"Acquirer Identifier" },
   ['9F02'] = {"Amount, Authorized" },
   ['9F03'] = {"Amount, Other" },
   ['9F04'] = {"Amount, Other (Binary)" },
   ['9F05'] = {"Application Discretionary Data" },
   ['9F06'] = {"Application Identifier (AID) - terminal" },
   ['9F07'] = {"Application Usage Control", ui_parse_AUC },
   ['9F08'] = {"Application Version Number" },
   ['9F09'] = {"Application Version Number" },
   ['9F0B'] = {"Cardholder Name - Extended" },
   ['9F0D'] = {"Issuer Action Code - Default", ui_parse_IAC },
   ['9F0E'] = {"Issuer Action Code - Denial", ui_parse_IAC },
   ['9F0F'] = {"Issuer Action Code - Online", ui_parse_IAC },
   ['9F10'] = {"Issuer Application Data" },
   ['9F11'] = {"Issuer Code Table Index" },
   ['9F12'] = {"Application Preferred Name" },
   ['9F13'] = {"Last Online ATC Register", ui_parse_number },
   ['9F14'] = {"Lower Consecutive Offline Limit (Terminal Check)" },
   ['9F15'] = {"Merchant Category Code" },
   ['9F16'] = {"Merchant Identifier" },
   ['9F17'] = {"PIN Try Counter", ui_parse_number },
   ['9F18'] = {"Issuer Script Identifier" },
   ['9F19'] = {"Dynamic Data Authentication Data Object List (DDOL)", ui_parse_DOL },
   ['9F1A'] = {"Terminal Country Code", ui_parse_country_code },
   ['9F1B'] = {"Terminal Floor Limit" },
   ['9F1C'] = {"Terminal Identification" },
   ['9F1D'] = {"Terminal Risk Management Data" },
   ['9F1E'] = {"Interface Device (IFD) Serial Number" },
   ['9F1F'] = {"Track 1 Discretionary Data", ui_parse_printable },
   ['9F20'] = {"Track 2 Discretionary Data" },
   ['9F21'] = {"Transaction Time" },
   ['9F22'] = {"Certification Authority Public Key Index" },
   ['9F23'] = {"Upper Consecutive Offline Limit (Terminal Check)" },
   ['9F26'] = {"Application Cryptogram (AC)" },
   ['9F27'] = {"Cryptogram Information Data" },
   ['9F2D'] = {"ICC PIN Encipherment Public Key Certificate" },
   ['9F2E'] = {"ICC PIN Encipherment Public Key Exponent" },
   ['9F2F'] = {"ICC PIN Encipherment Public Key Remainder" },
   ['9F32'] = {"Issuer PK Exponent" },
   ['9F33'] = {"Terminal Capabilities" },
   ['9F34'] = {"Cardholder Verification Method (CVM) Results" },
   ['9F35'] = {"Terminal Type" },
   ['9F36'] = {"Application Transaction Counter (ATC)", ui_parse_number },
   ['9F37'] = {"Unpredictable number" },
   ['9F38'] = {"Processing Options Data Object List (PDOL)", ui_parse_DOL },
   ['9F39'] = {"Point-of-Service (POS) Entry Mode" },
   ['9F3A'] = {"Amount, Reference Currency" },
   ['9F3B'] = {"Application Reference Currency" },
   ['9F3C'] = {"Transaction Reference Currency Code" },
   ['9F3D'] = {"Transaction Reference Currency Exponent" },
   ['9F40'] = {"Additional Terminal Capabilities" },
   ['9F41'] = {"Transaction Sequence Counter" },
   ['9F42'] = {"Application Currency Code", ui_parse_currency_code },
   ['9F43'] = {"Application Reference Currency Exponent" },
   ['9F44'] = {"Application Currency Exponent" },
   ['9F45'] = {"Data Authentication Code" },
   ['9F46'] = {"ICC Public Key Certificate" },
   ['9F47'] = {"ICC Public Key Exponent" },
   ['9F48'] = {"ICC Public Key Remainder" },
   ['9F49'] = {"Dynamic Data Authentication Data Object List (DDOL)", ui_parse_DOL },
   ['9F4A'] = {"Static Data Authentication Tag List", ui_parse_TL },
   ['9F4B'] = {"Signed Dynamic Application Data" },
   ['9F4C'] = {"Integrated Circuit Card (ICC) Dynamic Number" },
   ['9F4D'] = {"Log Entry" },
   ['9F4E'] = {"Merchant Name and Location" },
   ['9F4F'] = {"Log Format", ui_parse_DOL },
   ['9F51'] = {"Application Currency Code", ui_parse_currency_code },
   ['9F52'] = {"Card Verification Results (CVR)" },
   ['9F53'] = {"Consecutive Transaction Limit (International)" },
   ['9F54'] = {"Cumulative Total Transaction Amount Limit" },
   ['9F55'] = {"Geographic Indicator" },
   ['9F56'] = {"Issuer Authentication Indicator" },
   ['9F57'] = {"Issuer Country Code" },
   ['9F58'] = {"Lower Consecutive Offline Limit (Card Check)" },
   ['9F59'] = {"Upper Consecutive Offline Limit (Card Check)" },
   ['9F5A'] = {"Issuer URL2" },
   ['9F5C'] = {"Cumulative Total Transaction Amount Upper Limit" },
   ['9F72'] = {"Consecutive Transaction Limit (International - Country)" },
   ['9F73'] = {"Currency Conversion Factor" },
   ['9F74'] = {"VLP Issuer Authorization Code" },
   ['9F75'] = {"Cumulative Total Transaction Amount Limit - Dual Currency" },
   ['9F76'] = {"Secondary Application Currency Code", ui_parse_currency_code },
   ['9F77'] = {"VLP Funds Limit" },
   ['9F78'] = {"VLP Single Transaction Limit" },
   ['9F79'] = {"VLP Available Funds" },
   ['9F7F'] = {"Card Production Life Cycle (CPLC) History File Identifiers" },
   ['BF0C'] = {"FCI Issuer Discretionary Data" }
}

function emv_parse(cardenv,tlv)
    return tlv_parse(cardenv,tlv,EMV_REFERENCE)
end

PPSE = "#325041592E5359532E4444463031"
PSE  = "#315041592E5359532E4444463031"

-- AID_LIST enhanced with information from Wikipedia
-- http://en.wikipedia.org/wiki/EMV

AID_LIST = {
  "#A0000000031010",        -- Visa credit or debit
  "#A000000003101001",      -- VISA Credit
  "#A000000003101002",      -- VISA Debit
  "#A0000000032010",        -- Visa electron
  "#A0000000032020",        -- V pay
  "#A0000000033010",        -- VISA Interlink 
  "#A0000000034010",        -- VISA Specific 
  "#A0000000035010",        -- VISA Specific 
  "#A0000000036010",        -- Domestic Visa Cash Stored Value
  "#A0000000036020",        -- International Visa Cash Stored Value
  "#A0000000038002",        -- Barclays/HBOS     
  "#A0000000038010",        -- Visa Plus
  "#A0000000039010",        -- VISA Loyalty
  "#A000000003999910",      -- VISA ATM 
  "#A000000004",            -- US Debit (MC)
  "#A0000000041010",        -- Mastercard credit or debit
  "#A00000000410101213",    -- MasterCard
  "#A00000000410101215",    -- MasterCard
  "#A000000004110101213",   -- Mastercard Credit
  "#A0000000042010",        -- MasterCard Specific
  "#A0000000043010",        -- MasterCard Specific
  "#A0000000043060",        -- Mastercard Maestro
  "#A0000000044010",        -- MasterCard Specific
  "#A0000000045010",        -- MasterCard Specific
  "#A0000000046000",        -- Mastercard Cirrus
  "#A0000000048002",        -- NatWest or SecureCode Auth
  "#A0000000049999",        -- Mastercard
  "#A0000000050001",        -- UK Domestic Maestro - Switch (debit card) Maestro
  "#A0000000050002",        -- UK Domestic Maestro - Switch (debit card) Solo
  "#A0000000250000",        -- American Express (Credit/Debit)
  "#A00000002501",          -- American Express
  "#A000000025010402",      -- American Express
  "#A000000025010701",      -- American Express ExpressPay
  "#A000000025010801",      -- American Express
  "#A0000000291010",        -- ATM card LINK (UK) ATM network
  "#A0000000421010",        -- French CB
  "#A0000000422010",        -- French CB
  "#A00000006510",          -- JCB
  "#A0000000651010",        -- JCB
  "#A00000006900",          -- FR Moneo
  "#A000000098",            -- US Debit (Visa)
  "#A0000000980848",        -- Schwab Bank Debit Card
  "#A0000001211010",        -- Dankort Danish domestic debit card
  "#A0000001410001",        -- Pagobancomat Italian domestic debit card 
  "#A000000152",            -- US Debit (Discover)
  "#A0000001523010",        -- Diners club/Discover
  "#A0000001544442",        -- Banricompras Debito (Brazil)
  "#A0000001850002",        -- UK Post Office Card Account card
  "#A0000002281010",        -- SAMA Saudi Arabia domestic credit/debit card
  "#A0000002282010",        -- SAMA Saudi Arabia domestic credit/debit card
  "#A0000002771010",        -- Interac
  "#A0000003156020",        -- Chipknip
  "#A0000003241010",        -- Discover
  "#A0000003591010028001",  -- ZKA Girocard (Germany)
  "#A0000003710001",        -- InterSwitch Verve Card (Nigeria)
  "#A0000004540010",        -- Etranzact Genesis Card (Nigeria)
  "#A0000004540011",        -- Etranzact Genesis Card 2 (Nigeria)
  "#A0000004766C",          -- Google
  "#A0000005241010",        -- RuPay (India)
  "#A000000620",            -- US Debit (DNA)
  "#D27600002545500100",    -- ZKA Girocard (Germany)
  "#D5780000021010",        -- BankAxept Norwegian domestic debit card
}

EXTRA_DATA = { 0x9F36, 0x9F13, 0x9F17, 0x9F4D, 0x9F4F, 0x9F14, 0x9F23, 0x9F58, 0x9F59, 0x9F54, 0x9F5C, 0xCA, 0xCB }


function emv_process_ppse(cardenv)
    local sw, resp
    local APP
    local dirent

    sw, resp = card.select(PPSE)

    if sw ~= 0x9000 then
            log.print(log.INFO,"No PPSE")
       return false
    end

    -- Construct tree
    APP = nodes.append(cardenv, {classname="application", label="application", id=PPSE})
    emv_parse(APP,resp)

    AID_LIST = {}

    for dirent in nodes.find(APP,{ id="4F" }) do
        aid = tostring(nodes.get_attribute(dirent,"val"))
        log.print(log.INFO,"PPSE contains application #" .. aid)
        table.insert(AID_LIST,"#"..aid)
    end
    return true

end

function emv_process_pse(cardenv)
    local sw, resp
    local APP
    local ref
    local sfi
    local FILE
    local rec
    local REC
    local RECORD
    local aid
    local warm_atr
    local tag4F

        sw, resp = card.select(PSE)
  
    -- Could it be a french card?
    if sw == 0x6E00 then
       card.warm_reset()
       warm_atr = card.last_atr()
       nodes.append(cardenv, {classname="atr", label="ATR", id="warm", size=#warm_atr, val=warm_atr})
           sw, resp = card.select(PSE)
    end

    -- could it be a contactless smartcard?
    if sw == 0x6A82 then
       return emv_process_ppse(cardenv)
    end

    if sw ~= 0x9000 then
        log.print(log.INFO,"No PSE")
        return false
    end

    -- Construct tree
    APP = nodes.append(cardenv, {classname="application", label="application", id=PSE})
    emv_parse(APP,resp)

    ref = nodes.find_first(APP,{id="88"})
    if (ref) then
        sfi = nodes.get_attribute(ref,"val")
        FILE = nodes.append(APP,{classname="file", label="file", id=sfi[0]})

        rec = 1
        AID_LIST = {}
        repeat
            sw,resp = card.read_record(sfi:get(0),rec)
            if sw == 0x9000 then
                RECORD = nodes.append(FILE, {classname="record", label="record", id=tostring(rec)})
                emv_parse(RECORD,resp)
                for tag4F in nodes.find(RECORD,{id="4F"}) do
                    aid = tostring(nodes.get_attribute(tag4F,"val"))
                    log.print(log.INFO,"PSE contains application #" .. aid)
                    table.insert(AID_LIST,"#"..aid)
                end
                rec = rec + 1
            end
       until sw ~= 0x9000
    else
       log.print(log.WARNING,"SFI indicator (tag 88) not found in PSE")
    end
    return true
end

function visa_process_application_logs(application, log_sfi, log_max)
    local sw, resp
    local LOG_FILE
    local LOG_DATA
    local LOG_FORMAT
    local log_recno

    LOG_FILE   = nodes.append(application,{ classname="file",
                            label="file",
                            id=tostring(log_sfi)})

    LOG_DATA   = nodes.append(LOG_FILE, { classname="item",
                          label = "log data"})
  
    log.print(log.INFO,string.format("Reading LOG SFI %i",log_sfi))
    for log_recno =1,log_max do
           sw,resp = card.read_record(log_sfi, log_recno)
       if sw ~= 0x9000 then
                  log.print(log.WARNING,"Read log record failed")
          break
       else
              nodes.append(LOG_DATA,{ classname = "record",
                          label="record",
                          id=log_recno,
                          size=#resp,
                          val=resp})
       end
    end

end


function emv_process_application_logs(application, log_sfi, log_max)
    local log_format
    local log_tag
    local log_items = { }
    local sw, resp
    local tag
    local tag_name
    local tag_func
    local len
    local i
    local item
    local item_pos
    local LOG_FILE
    local LOG_DATA
    local LOG_FORMAT
    local REC
    local ITEM
    local ITEM_AMOUNT
    local log_recno
    local data
    local currency_code, currency_name, currency_digits

    LOG_FILE   = nodes.append(application,     { classname="file", label="log file", id=log_sfi})
    LOG_FORMAT = nodes.append(LOG_FILE,       { classname="block", label="log format"})
  
    log_format = application:find_first({id = "9F4F"}):get_attribute("val")

    i = 1
    item = ""
    nodes.set_attribute(LOG_FORMAT,"val",log_format);
    while log_format
    do
        tag, log_format = asn1.split_tag(log_format)
        len, log_format = asn1.split_length(log_format)
        tag_name, tag_func = tlv_tag_info(tag,EMV_REFERENCE,0);
        log_items[i]= { tag, len, tag_name, tag_func }
        i = i+1
        item = item .. string.format("%X[%d] ", tag, len);
    end
    nodes.set_attribute(LOG_FORMAT,"alt",item);

    log.print(log.INFO,string.format("Reading LOG SFI %i",log_sfi))
    for log_recno =1,log_max do
           sw,resp = card.read_record(log_sfi,log_recno)
       if sw ~= 0x9000 then
                  log.print(log.WARNING,"Read log record failed")
          break
       else
              REC = nodes.append(LOG_FILE,{classname="record", label="record", id=log_recno, size=#resp})
          item_pos = 0
          ITEM_AMOUNT = nil
          currency_digits = 0
          for i=1,#log_items do
             if log_items[i][3] then
                ITEM = nodes.append(REC,{ classname="item",
                              label=log_items[i][3],
                              size=log_items[i][2] })
             else
                ITEM = nodes.append(REC,{ classname="item",
                              label=string.format("tag %X",log_items[i][1]),
                              size=log_items[i][2] })
             end

             data = bytes.sub(resp,item_pos,item_pos+log_items[i][2]-1)
                 nodes.set_attribute(ITEM,"val",data)

             if log_items[i][1]==0x9F02 then
                ITEM_AMOUNT=ITEM
             elseif log_items[i][1]==0x5F2A then
                    currency_code   = tonumber(tostring(data))
                currency_name   = iso_currency_code_name(currency_code)
                    currency_digits = iso_currency_code_digits(currency_code)
                    nodes.set_attribute(ITEM,"alt",currency_name)
             elseif log_items[i][4] then
                log_items[i][4](ITEM,data)
                     end
                 item_pos = item_pos + log_items[i][2]
              end

              if ITEM_AMOUNT then
             local amount = tostring(nodes.get_attribute(ITEM_AMOUNT,"val"))
             nodes.set_attribute(ITEM_AMOUNT,"alt",string.format("%.2f",amount/(10^currency_digits)))
          end
       end
    end

end

function emv_process_application(cardenv,aid)
    local sw, resp
    local ref
    local ref2
    local pdol
    local AFL = bytes.new(8);
    local extra
    local j -- counter
    local tag_name
    local tag_func
    local AIP

    log.print(log.INFO,"Processing application "..aid)

    -- Select AID
    sw,resp = card.select(aid)
    if sw ~=0x9000 then
       return false
    end

    -- Process 'File Control Infomation' and get PDOL
    local APP
    local FCI
  
    APP = nodes.append(cardenv, { classname = "application", label = "application", id=aid })
    FCI = nodes.append(APP, { classname = "header", label = "answer to select", size=#resp, val=resp })
    emv_parse(FCI,resp)
    ref = nodes.find_first(FCI,{id="9F38"})
    if (ref) then
       pdol = nodes.get_attribute(ref,"val")
    else
       pdol = nil;
    end

    -- INITIATE get processing options, now that we have pdol
    local GPO
    local query

    query = "Issue a GET PROCESSING OPTIONS command?";
    ref = nodes.find_first(FCI,{id="50"})
    if (ref) then
       query = "Issue a GET PROCESSING OPTIONS command to the "..nodes.get_attribute(ref,"alt"):match( "^%s*(.-)%s*$").." application?"
    end

        if ui.question(query,{"Yes","No"})==1 then
            -- Get processing options
            log.print(log.INFO,"Attempting GPO")
            sw,resp = card.get_processing_options(pdol)
            if sw ~=0x9000 then
                if pdol then
                    -- try empty GPO just in case the card is blocking some stuff
                    log.print(log.WARNING,
                              string.format("GPO with data failed with code %X, retrying GPO without data",sw))
                    sw,resp = card.get_processing_options(nil) 
                end
           end
           if sw ~=0x9000 then
                log.print(log.ERROR,"GPO Failed")
        ui.question("GET PROCESSING OPTIONS failed, the script will continue to read the card",{"OK"})
           else
            GPO = nodes.append(APP,{classname="block",label="processing_options", size=#resp, val=resp})
        emv_parse(GPO,resp)
                ref = nodes.find_first(GPO,{id="94"})
                ref2 = nodes.find_first(GPO,{id="80"})
        if ref then
            AFL = nodes.get_attribute(ref, "val")
        elseif ref2 then
            -- Parse a Format 1 GET PROCESSING OPTIONS response message.
            AFL = nodes.get_attribute(ref2, "val")
            AIP = bytes.sub(AFL,0,1)
            AFL = bytes.sub(AFL,2)
            if nodes.find_first(GPO,{id="82"}) then
                tag_value_parse(ref2, 0x82, AIP, EMV_REFERENCE)
            end
            if  nodes.find_first(GPO,{id="94"}) then           
                tag_value_parse(ref2, 0x94, AFL, EMV_REFERENCE)
            end
            else
                log.print(log.WARNING,
                      "GPO Response message contains neither a Format 1 nor a Format 2 Data Field")
        end
       end
    end

    -- Read extra data
    --extra = nodes.append(APP,{classname="block",label="extra emv data"})
    for j=1,#EXTRA_DATA do
        sw,resp = card.get_data(EXTRA_DATA[j])
        if sw == 0x9000 then
           emv_parse(APP,resp):set_attribute("classname","block")
        end
    end
  
    -- find LOG INFO
    local LOG
    local logformat
  
    logformat=nil
    ref = nodes.find_first(APP,{id="9F4D"})
    -- I've seen this on some cards :
    if ref==nil then
       -- proprietary style ?
       ref = nodes.find_first(APP,{id="DF60"})
       logformat = "VISA"
    else
       logformat = "EMV"
    end

    if ref then
           LOG = nodes.get_attribute(ref,"val")
    else
       sw, resp = card.get_data(0x9F4D)
             if sw==0x9000 then
              LOG = tostring(resp)
          logformat = "EMV"
       else
          sw, resp = card.get_data(0xDF60)
          if sw==0x9000 then
                 LOG = tostring(resp)
             logformat = "VISA"
          else
             logformat = nil
                 LOG = nil
          end
       end
    end

    if logformat then
       log.print(log.INFO,"Found "..logformat.." transaction log indicator")
    else
       log.print(log.INFO,"No transaction log indicator")
    end


    local sfi_index
    local rec_index
    local max_rec_index
    local SFI
    local REC
    local i

    -- Process Application File Locator
    local AFL_info = {}
    for i=0,#AFL-1,4 do
        sfi_index=bit.SHR(AFL:get(i),3)
        if AFL_info[sfi_index] == nil then
           AFL_info[sfi_index] = {['max'] = AFL:get(i+2)}
        else
           AFL_info[sfi_index]['max'] = math.max(AFL:get(i+2), AFL_info[sfi_index]['max'])
        end
        for j=AFL:get(i+1),AFL:get(i+2) do
            -- Include in offline data authentication.
            AFL_info[sfi_index][j] = AFL_info[sfi_index][j] or (j < AFL:get(i+1)+AFL:get(i+3))
        end
    end

      
        for sfi_index=1,31 do
        SFI = nil
        max_rec_index = 5
        -- Amex has files where records don't start at 1
        -- The highest starting number I've seen is 4,
        -- so don't treat a failure of a lower-than-five record number as "end of records in a file"
        if AFL_info[sfi_index] then
           max_rec_index = math.max(max_rec_index, AFL_info[sfi_index]['max'])
        end

        if (logformat==nil or LOG:get(0)~=sfi_index) then

                for rec_index=1,255 do
                log.print(log.INFO,string.format("Reading SFI %i, record %i",sfi_index, rec_index))
                    sw,resp = card.read_record(sfi_index,rec_index)
                        if sw ~= 0x9000 then
                                      log.print(log.WARNING,string.format("Read record failed for SFI %i, record %i",sfi_index,rec_index))

                                    if rec_index > max_rec_index then
                        break
                    end
                    else
                    if (SFI==nil) then
                               SFI = nodes.append(APP,{classname="file", label="file",    id=sfi_index})
                    end
                        REC = nodes.append(SFI,{classname="record", label="record", id=rec_index})
                    if (AFL_info[sfi_index] ~= nil) and (AFL_info[sfi_index][rec_index] == true) then
                        nodes.append(REC,{classname="item", label="AFL Information", val="This record is to be included in offline data authentication"})
                    end
                        if (emv_parse(REC,resp)==false) then
                        nodes.set_attribute(REC,"val",resp)
                        nodes.set_attribute(REC,"size",#resp)
                    end
                    end
  
                end -- for rec_index

        end -- if log exists

            end -- for sfi_index

    -- Read logs if they exist
    if logformat=="EMV" then
           emv_process_application_logs(APP,LOG:get(0),LOG:get(1))
    elseif logformat=="VISA" then
       visa_process_application_logs(APP,LOG:get(0),LOG:get(1))
    end


    return true
end

DAYCOUNT_DATA =
{
  [0] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
  [1] = {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
}

function yearday_to_day_and_month(yday, leap)
-- yday = 1, ..., 366 (day of year)
-- leap = 0 (non-leap year) or 1 (leap year)
    if (yday < 1) or (yday - leap > 365) then
        return nil, nil;
    end

    local month
    month = math.floor(yday/30)
    if yday > DAYCOUNT_DATA[leap][month + 1] then
        month = month + 1
    end
    return yday - DAYCOUNT_DATA[leap][month], month
end

function ui_parse_cplc_date(node,data)
    local date = tostring(data)
    local day
    local month
    local year
    local yday

    if string.len(date) ~= 4 then
        return
    end

    year = 0 + string.sub(date, 1, 1)
    yday = 0 + string.sub(date, 2, 4)

    if yday == 366 then
        date = "???" .. year .. "-12-31"
    nodes.set_attribute(node, "alt", date)
    return
    end

    day, month = yearday_to_day_and_month(yday, 0)
    if day == nil then
        return
    end

    date = string.format("???%d-%02d-%02d", year, month, day)

    if (year % 2 == 0) and (yday >= 60) then
        day, month = yearday_to_day_and_month(yday, 1)
        date = date .. string.format(" or ???%d-%02d-%02d", year, month, day)
    end

    nodes.set_attribute(node, "alt", date)
end

CPLC_DATA =
{
  { "IC Fabricator", 2 } ,
  { "IC Type", 2 },
  { "Operating System Provider Identifier", 2 },
  { "Operating System Release Date", 2, ui_parse_cplc_date },
  { "Operating System Release Level", 2 },
  { "IC Fabrication Date", 2, ui_parse_cplc_date },
  { "IC Serial Number", 4 },
  { "IC Batch Identifier", 2 },
  { "IC ModuleFabricator", 2 },
  { "IC ModulePackaging Date", 2, ui_parse_cplc_date },
  { "ICC Manufacturer", 2 },
  { "IC Embedding Date", 2, ui_parse_cplc_date },
  { "Prepersonalizer Identifier", 2 },
  { "Prepersonalization Date", 2, ui_parse_cplc_date },
  { "Prepersonalization Equipment", 4 },
  { "Personalizer Identifier", 2 },
  { "Personalization Date", 2, ui_parse_cplc_date },
  { "Personalization Equipment", 4 },
}

function emv_process_cplc(cardenv)
    local sw, resp
    local CPLC
    local cplc_data
    local cplc_tag
    local i
    local pos
    local ref2
    local tlv_value
    local tlv_ui_func

    log.print(log.INFO,"Processing CPLC data")
    sw,resp = card.get_data(0x9F7F)
    if sw == 0x9000 then
       cplc_tag, cplc_data = asn1.split(resp)
       CPLC      = nodes.append(cardenv,{classname="block", label="cpcl data", id="9F7F", size=#cplc_data})
       nodes.set_attribute(CPLC,"val",cplc_data)
       pos = 0
       for i=1,#CPLC_DATA do
           ref2 = nodes.append(CPLC,{classname="item", label=CPLC_DATA[i][1], id=pos});
           tlv_value = bytes.sub(cplc_data,pos,pos+CPLC_DATA[i][2]-1)
               nodes.set_attribute(ref2,"val",tlv_value)
           tlv_ui_func = CPLC_DATA[i][3]
           if tlv_ui_func then
               tlv_ui_func(ref2,tlv_value)
               end
           pos = pos + CPLC_DATA[i][2]
       end
    end
end


-- PROCESSING

if card.connect() then

   local mycard = card.tree_startup("EMV")

   emv_process_pse(mycard)
   card.warm_reset()

   for i=1,#AID_LIST
   do
        -- print(AID_LIST[i])
    emv_process_application(mycard,AID_LIST[i])
    card.warm_reset()
   end

   emv_process_cplc(mycard)

   card.disconnect()
else
   ui.question("No card detected in reader",{"OK"})
end
 
Zuletzt bearbeitet:

selaf

Erfahrenes Mitglied
24.08.2018
1.824
1.466
Es geht auch mit Cardpeek. Dazu dieses Skript verwenden und in Cardpeek laden (mit einem Editor als .lua speichern und in den script Ordner von Cardpeek ablegen)....

Vielen Dank erst mal. Magst du dein Script vielleicht als Pull-Request direkt an das Cardpeek Projekt schicken? Ich hatte an dem Script auch schon "rumgepfuscht" um die Abstürze mit diversen neuen Visa Debit zu vermeiden, aber das war eher gefährliches Halbwissen.

"Script im Forum" ist für die meisten vermutlich keine Lösung, zumal du (nachvollziehbar) nicht den Support an der Backen haben möchtest. Daher würde ich wohl erst mal weiterhin an die tolle App von @ehambuch verweisen.
 
  • Like
Reaktionen: geos

tcu99

Erfahrenes Mitglied
26.08.2016
6.525
1.141
Glaube kaum, dass da was passiert. Da ist seit 2019 nichts passiert.
Jonas (@JFI) kann es aber in sein Wiki packen. Ich schicke ihm das Skript zu.
 
  • Like
Reaktionen: eddi78

eddi78

Aktives Mitglied
12.05.2018
157
98
Genauso ist 201 keine Garantie für Offline Fähigkeit. Bei Wise steht das Offline Limit z.B. auf 0, obwohl die Karte einen 201 Service Code hat.
Ich hab jetzt mal meine Advanzias mit dem angepassten Skript ausgelesen.

Bei der alten (Rohling 02/18) (sign first) LCOL 2, UCOL 4, LCOTA 50, UCOTA 200. Service Code 201
Bei der neuen (Rohling 03/21) (PIN first) LCOL 0, UCOL 0, LCOTA 0, UCOTA 0. Service Code 201

Bedeutet das nun, dass die Advanzia nicht mehr offline fähig ist?
 
Zuletzt bearbeitet: