#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/power.h>
#include <util/delay.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include "emv.h"
#include "scd_hal.h"
#include "scd_io.h"
#include "emv_values.h"
#include "scd_values.h"
#include "counter.h"
#include <stdint.h>
Go to the source code of this file.
Defines | |
#define | DEBUG 1 |
Functions | |
uint8_t | ResetICC (uint8_t warm, uint8_t *inverse_convention, uint8_t *proto, uint8_t *TC1, uint8_t *TA3, uint8_t *TB3, log_struct_t *logger) |
Starts a cold or warm reset for ICC. | |
void | SendT0ATRTerminal (uint8_t inverse_convention, uint8_t TC1, log_struct_t *logger) |
Sends default ATR for T=0 to terminal. | |
uint8_t | GetATRICC (uint8_t *inverse_convention, uint8_t *proto, uint8_t *TS, uint8_t *T0, uint16_t *selection, uint8_t bytes[32], uint8_t *tck, log_struct_t *logger) |
Receives the ATR from ICC after a successful activation. | |
EMVCommandHeader * | MakeCommandHeader (uint8_t cla, uint8_t ins, uint8_t p1, uint8_t p2, uint8_t p3) |
This function will return a command header structure. | |
EMVCommandHeader * | MakeCommandHeaderC (EMV_CMD command) |
This function will return a command header structure. | |
CAPDU * | MakeCommand (uint8_t cla, uint8_t ins, uint8_t p1, uint8_t p2, uint8_t p3, const uint8_t cmdData[], uint8_t lenData) |
This function will return a command APDU (CAPDU) structure. | |
CAPDU * | MakeCommandP (const EMVCommandHeader *cmdHdr, const uint8_t cmdData[], uint8_t lenData) |
This function will return a command APDU (CAPDU) structure. | |
CAPDU * | MakeCommandC (EMV_CMD command, const uint8_t cmdData[], uint8_t lenData) |
This function will return a command APDU (CAPDU) structure. | |
uint8_t | InitSCDTransaction (uint8_t t_inverse, uint8_t t_TC1, uint8_t *inverse_convention, uint8_t *proto, uint8_t *TC1, uint8_t *TA3, uint8_t *TB3, log_struct_t *logger) |
Initiates the communication with both the ICC and terminal for T=0. | |
uint8_t | GetCommandCase (uint8_t cla, uint8_t ins) |
Returns the command case from the command header. | |
EMVCommandHeader * | ReceiveT0CmdHeader (uint8_t inverse_convention, uint8_t TC1, log_struct_t *logger) |
Receive a command header from the terminal using protocol T=0. | |
uint8_t * | ReceiveT0CmdData (uint8_t inverse_convention, uint8_t TC1, uint8_t len, log_struct_t *logger) |
Receive a command data from the terminal using protocol T=0. | |
CAPDU * | ReceiveT0Command (uint8_t inverse_convention, uint8_t TC1, log_struct_t *logger) |
Receive a command (including data) from the terminal using protocol T=0. | |
uint8_t | SendT0CmdHeader (uint8_t inverse_convention, uint8_t TC1, EMVCommandHeader *cmdHeader, log_struct_t *logger) |
Send a command header to the ICC using protocol T=0. | |
uint8_t | SendT0CmdData (uint8_t inverse_convention, uint8_t TC1, uint8_t *cmdData, uint8_t len, log_struct_t *logger) |
Send a command data to the ICC using protocol T=0. | |
uint8_t | SendT0Command (uint8_t inverse_convention, uint8_t TC1, CAPDU *cmd, log_struct_t *logger) |
Send a command (including data) to the ICC using protocol T=0. | |
CAPDU * | ForwardCommand (uint8_t tInverse, uint8_t cInverse, uint8_t tTC1, uint8_t cTC1, log_struct_t *logger) |
Forwards a command from the terminal to the ICC for T=0. | |
uint8_t * | SerializeCommand (CAPDU *cmd, uint8_t *len) |
Serialize a CAPDU structure. | |
RAPDU * | ReceiveT0Response (uint8_t inverse_convention, EMVCommandHeader *cmdHeader, log_struct_t *logger) |
Receive response from ICC for T=0. | |
uint8_t | SendT0Response (uint8_t inverse_convention, EMVCommandHeader *cmdHeader, RAPDU *response, log_struct_t *logger) |
Send a response to the terminal. | |
RAPDU * | ForwardResponse (uint8_t tInverse, uint8_t cInverse, EMVCommandHeader *cmdHeader, log_struct_t *logger) |
Forwards a response from the ICC to the terminal. | |
uint8_t * | SerializeResponse (RAPDU *response, uint8_t *len) |
Serialize a RAPDU structure. | |
CRP * | ExchangeData (uint8_t tInverse, uint8_t cInverse, uint8_t tTC1, uint8_t cTC1, log_struct_t *logger) |
Makes a command-response exchange between terminal and ICC. | |
CRP * | ExchangeCompleteData (uint8_t tInverse, uint8_t cInverse, uint8_t tTC1, uint8_t cTC1, log_struct_t *logger) |
Makes a complete command-response exchange between terminal and ICC. | |
ByteArray * | MakeByteArray (uint8_t *data, uint8_t len) |
Encapsulates data in a ByteArray structure. | |
ByteArray * | MakeByteArrayV (uint8_t nargs,...) |
Creates a ByteArray structure from values. | |
ByteArray * | CopyByteArray (const uint8_t *data, uint8_t len) |
Copies data into a ByteArray structure. | |
void | FreeByteArray (ByteArray *data) |
Eliberates the memory used by a ByteArray. | |
void | FreeCAPDU (CAPDU *cmd) |
Eliberates the memory used by a CAPDU. | |
CAPDU * | CopyCAPDU (CAPDU *cmd) |
Makes a copy of a CAPDU. | |
void | FreeRAPDU (RAPDU *response) |
Eliberates the memory used by a RAPDU. | |
RAPDU * | CopyRAPDU (RAPDU *resp) |
Makes a copy of a RAPDU. | |
void | FreeCRP (CRP *data) |
Eliberates the memory used by a CRP. |
emv.c source file
Contains the implementation of functions used to implement the EMV standard
Copyright (C) 2012 Omar Choudary (omar.choudary@cl.cam.ac.uk)
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Definition in file emv.c.
ByteArray* CopyByteArray | ( | const uint8_t * | data, | |
uint8_t | len | |||
) |
Copies data into a ByteArray structure.
Create a ByteArray structure. This method copies the data to the ByteArray structure which means that the caller is responsible to eliberate the memory
data | the bytes to be copied to the structure | |
len | the length of the byte array |
CRP* ExchangeCompleteData | ( | uint8_t | tInverse, | |
uint8_t | cInverse, | |||
uint8_t | tTC1, | |||
uint8_t | cTC1, | |||
log_struct_t * | logger | |||
) |
Makes a complete command-response exchange between terminal and ICC.
This method exchange command-response pairs between terminal and ICC, similar to ExchangeData. However this method forwards data repeatedly until the response contains a success or error. The method returns the initial command and the final response. Intermediate stages are removed. If you need those stages use ExchangeData instead.
tInverse | different than 0 if inverse convention is to be used with the terminal | |
cInverse | different than 0 if inverse convention is to be used with the ICC | |
tTC1 | byte TC1 of ATR used with terminal | |
cTC1 | byte TC1 of ATR received from ICC | |
logger | a pointer to a log structure or NULL if no log is desired |
CRP* ExchangeData | ( | uint8_t | tInverse, | |
uint8_t | cInverse, | |||
uint8_t | tTC1, | |||
uint8_t | cTC1, | |||
log_struct_t * | logger | |||
) |
Makes a command-response exchange between terminal and ICC.
This method sends a command from the terminal to the ICC and also returns to the terminal the answer from the ICC. Both the command and the response are returned to the caller.
tInverse | different than 0 if inverse convention is to be used with the terminal | |
cInverse | different than 0 if inverse convention is to be used with the ICC | |
tTC1 | byte TC1 of ATR used with terminal | |
cTC1 | byte TC1 of ATR received from ICC | |
logger | a pointer to a log structure or NULL if no log is desired. |
CAPDU* ForwardCommand | ( | uint8_t | tInverse, | |
uint8_t | cInverse, | |||
uint8_t | tTC1, | |||
uint8_t | cTC1, | |||
log_struct_t * | logger | |||
) |
Forwards a command from the terminal to the ICC for T=0.
Receive a command from the terminal and then send it to the ICC
tInverse | different than 0 if inverse convention is to be used with the terminal | |
cInverse | different than 0 if inverse convention is to be used with the ICC | |
tTC1 | the N parameter from byte TC1 of ATR used with terminal | |
cTC1 | the N parameter from byte TC1 of ATR received from ICC | |
logger | a pointer to a log structure or NULL if no log is desired |
RAPDU* ForwardResponse | ( | uint8_t | tInverse, | |
uint8_t | cInverse, | |||
EMVCommandHeader * | cmdHeader, | |||
log_struct_t * | logger | |||
) |
Forwards a response from the ICC to the terminal.
Receive a response from the terminal and then send it to the terminal
tInverse | different than 0 if inverse convention is to be used with the terminal | |
cInverse | different than 0 if inverse convention is to be used with the ICC | |
cmdHeader | the header of the command for which response is expected | |
logger | a pointer to a log structure or NULL if no log is desired. |
void FreeByteArray | ( | ByteArray * | data | ) |
void FreeCAPDU | ( | CAPDU * | cmd | ) |
void FreeCRP | ( | CRP * | data | ) |
void FreeRAPDU | ( | RAPDU * | response | ) |
uint8_t GetATRICC | ( | uint8_t * | inverse_convention, | |
uint8_t * | proto, | |||
uint8_t * | TS, | |||
uint8_t * | T0, | |||
uint16_t * | selection, | |||
uint8_t | bytes[32], | |||
uint8_t * | tck, | |||
log_struct_t * | logger | |||
) |
Receives the ATR from ICC after a successful activation.
Receives the ATR from ICC after a successful activation
inverse_convention | non-zero if inverse convention is to be used | |
proto | 0 for T=0 and non-zero for T=1 | |
TS | is the TS byte of the ATR | |
T0 | is the T0 byte of the ATR | |
selection | is a 16-bit value, which will contain a 1-hot encoded list of which ATR bytes have been received as follows: -> (selection & (1 << b)) == 1 if byte 'b' has been received, 0 otherwise. -> The order of bytes is: TA1, TB1, TC1, TD1, TA2, TB2, ..., TA4, TB4, TC4, TD4 (total of 16 bits) TA1 corresponds to the most significant bit of 'selection'. See ISO 7816-3 or EMV Book 1 section ATR | |
bytes | a user supplied vector which will contain the values of: -> TA1, TB1, ..., TA4, TB4, TC4 and TD4 in bytes [0 ... 15] (16 values) -> historic bytes in bytes [16 ... 31] (16 values). See last nibble of T0 for the number of historic bytes (i.e. T0 & 0x0F). | |
tck | the TCK byte of the ATR if T=1 is used. A storage for this value must be supplied by the caller even if the value is not used. | |
logger | a pointer to a log structure or NULL if no log is desired. |
This implementation is compliant with EMV 4.2 Book 1
uint8_t GetCommandCase | ( | uint8_t | cla, | |
uint8_t | ins | |||
) |
Returns the command case from the command header.
Returns the case of an EMV command based on the header
The significance of the case is given by this table:
case | command data | response data 1 | absent | absent 2 | absent | present 3 | present | absent 4 | present | present
cla | byte CLA | |
ins | byte INS |
uint8_t InitSCDTransaction | ( | uint8_t | t_inverse, | |
uint8_t | t_TC1, | |||
uint8_t * | inverse_convention, | |||
uint8_t * | proto, | |||
uint8_t * | TC1, | |||
uint8_t * | TA3, | |||
uint8_t * | TB3, | |||
log_struct_t * | logger | |||
) |
Initiates the communication with both the ICC and terminal for T=0.
This function is used to establish the communication between the terminal and the SCD and between the SCD and the ICC at the same time.
The ATR from the card is replicated to the terminal, with the exception of the first byte (TS) which is dependent on the given parameter (t_inverse), since this will be sent before retrieving the corresponding ICC value.
If the function returs 0 (success) then both the terminal and the ICC should be in a good state, where the terminal is about to send the first command and the ICC is waiting for a command
This function assumes that the ICC was placed in the ICC holder before being called and it will loop until the terminal provides clock
t_inverse | specifies if direct(0) or inverse(non-zero) convention should be used in the communication with the terminal. Only direct convention should be used as specified in the standard. | |
t_TC1 | specifies the TC1 byte of the ATR sent to the terminal. This should be as small as possible in order to limit the latency of communication or large if a specific timeout between bytes is desired. | |
inverse_convention | direct (0) or inverse convention (1) is used by the ICC, as returned in the ATR | |
proto | protocol (T=0 or T=1) as returned by the ICC in the ATR | |
TC1 | as returned by the ICC in the ATR | |
TA3 | as returned by the ICC in the ATR | |
TB3 | as returned by the ICC in the ATR | |
logger | the log structure or NULL if no log is desired |
ByteArray* MakeByteArray | ( | uint8_t * | data, | |
uint8_t | len | |||
) |
Encapsulates data in a ByteArray structure.
Create a ByteArray structure. This method just links the data to the ByteArray structure which means that eliberating the data (calling free) of the ByteArray will have an effect on the data passed to this method.
data | the bytes to be linked to the structure | |
len | the length of the byte array |
ByteArray* MakeByteArrayV | ( | uint8_t | nargs, | |
... | ||||
) |
Creates a ByteArray structure from values.
Create a ByteArray structure. This method creates the structure based on the values directly passed to this method.
nargs | the number of values passed to this method | |
... | the variable number of values given |
CAPDU* MakeCommand | ( | uint8_t | cla, | |
uint8_t | ins, | |||
uint8_t | p1, | |||
uint8_t | p2, | |||
uint8_t | p3, | |||
const uint8_t | cmdData[], | |||
uint8_t | lenData | |||
) |
This function will return a command APDU (CAPDU) structure.
Makes a command APDU (CAPDU) for T=0 protocol
cla | byte CLA | |
ins | byte INS | |
p1 | byte P1 | |
p2 | byte P2 | |
p3 | byte P3. This value is not modified automatically to the value of lenData even if cmdData is not NULL. The caller needs to take care of this or use MakeCommandC instead | |
cmdData | command data. The data pointed by cmdData will be copied into the new CAPDU so the caller is responsible for handling the original cmdData | |
lenData | length in bytes of cmdData |
This function will return a command APDU (CAPDU) structure.
Makes a command APDU (CAPDU) for T=0 protocol. This method creates sets the default values based on the command type (see EMV_CMD). Also, the parameter p3 of the command header is given the value of lenData if cmdData is not NULL.
command | The speified command using the enum EMV_CMD. This function will create the default command header based on this. | |
cmdData | command data. The data pointed by cmdData will be copied into the new CAPDU so the caller is responsible for handling the original cmdData | |
lenData | length in bytes of cmdData |
EMVCommandHeader* MakeCommandHeader | ( | uint8_t | cla, | |
uint8_t | ins, | |||
uint8_t | p1, | |||
uint8_t | p2, | |||
uint8_t | p3 | |||
) |
This function will return a command header structure.
Makes a command header for T=0 protocol
cla | byte CLA | |
ins | byte INS | |
p1 | byte P1 | |
p2 | byte P2 | |
p3 | byte P3 |
EMVCommandHeader* MakeCommandHeaderC | ( | EMV_CMD | command | ) |
This function will return a command header structure.
Makes a command header for a given command. This function populates the command bytes with default values, where P3 is always 0. Calling functions should make sure to modify these bytes to the correct values.
command | type of command requested (see EMV_CMD) |
CAPDU* MakeCommandP | ( | const EMVCommandHeader * | cmdHdr, | |
const uint8_t | cmdData[], | |||
uint8_t | lenData | |||
) |
This function will return a command APDU (CAPDU) structure.
Makes a command APDU (CAPDU) for T=0 protocol. The difference to MakeCommand is that it takes a pointer to an EMVCommandHeader structure instead of values
cmdHdr | command header. The data pointed by cmdHdr will be copied into the new CAPDU so the caller is responsible for handling the original cmdHdr | |
cmdData | command data. The data pointed by cmdData will be copied into the new CAPDU so the caller is responsible for handling the original cmdData | |
lenData | length in bytes of cmdData |
uint8_t* ReceiveT0CmdData | ( | uint8_t | inverse_convention, | |
uint8_t | TC1, | |||
uint8_t | len, | |||
log_struct_t * | logger | |||
) |
Receive a command data from the terminal using protocol T=0.
Receive a command data from terminal for protocol T = 0
inverse_convention | different than 0 if inverse convention is to be used | |
TC1 | the N parameter received in byte TC1 of ATR |
len | lenght in bytes of command data expected | |
logger | a pointer to a log structure or NULL if no log is desired |
EMVCommandHeader* ReceiveT0CmdHeader | ( | uint8_t | inverse_convention, | |
uint8_t | TC1, | |||
log_struct_t * | logger | |||
) |
Receive a command header from the terminal using protocol T=0.
Receive a response from ICC for protocol T = 0
inverse_convention | different than 0 if inverse convention is to be used | |
TC1 | the N parameter received in byte TC1 of ATR | |
logger | a pointer to a log structure or NULL if no log is desired |
CAPDU* ReceiveT0Command | ( | uint8_t | inverse_convention, | |
uint8_t | TC1, | |||
log_struct_t * | logger | |||
) |
Receive a command (including data) from the terminal using protocol T=0.
Receive a command (including data) from terminal for protocol T = 0. For command cases 3 and 4 a procedure byte is sent back to the terminal to obtain the command data
inverse_convention | different than 0 if inverse convention is to be used | |
TC1 | the N parameter received in byte TC1 of ATR | |
logger | a pointer to a log structure or NULL if no log is desired |
RAPDU* ReceiveT0Response | ( | uint8_t | inverse_convention, | |
EMVCommandHeader * | cmdHeader, | |||
log_struct_t * | logger | |||
) |
Receive response from ICC for T=0.
This method receives a response from ICC for protocol T = 0. If [SW1,SW2] != [0x90,0] then the response is not complete. Either another command (e.g. get response) is expected, or the previous command with different lc, or an error has occurred. If [SW1,SW2] returned are '9000' then the command is successful and it will also contain data if this was expected. Different codes for the return codes can be found in EMV Book 1 and Book 3.
inverse_convention | different than 0 if inverse convention is to be used | |
cmdHeader | the header of the command for which response is expected | |
logger | a pointer to a log structure or NULL if no log is desired |
uint8_t ResetICC | ( | uint8_t | warm, | |
uint8_t * | inverse_convention, | |||
uint8_t * | proto, | |||
uint8_t * | TC1, | |||
uint8_t * | TA3, | |||
uint8_t * | TB3, | |||
log_struct_t * | logger | |||
) |
Starts a cold or warm reset for ICC.
Starts activation sequence for ICC
warm | 0 if a cold reset is to be issued, 1 otherwise | |
inverse_convention | non-zero if inverse convention is to be used | |
proto | 0 for T=0 and non-zero for T=1 | |
TC1 | see ISO 7816-3 or EMV Book 1 section ATR | |
TA3 | see ISO 7816-3 or EMV Book 1 section ATR | |
TB3 | see ISO 7816-3 or EMV Book 1 section ATR | |
logger | a pointer to a log structure or NULL if no log is desired. |
void SendT0ATRTerminal | ( | uint8_t | inverse_convention, | |
uint8_t | TC1, | |||
log_struct_t * | logger | |||
) |
Sends default ATR for T=0 to terminal.
Sends default ATR for T=0 to terminal
inverse_convention | specifies if direct (0) or inverse convention (non-zero) is to be used. Only direct convention should be used for future applications. | |
TC1 | specifies the TC1 byte of the ATR. This should be as small as possible in order to limit the latency of communication, or large if a large timeout between bytes is desired. | |
logger | a pointer to a log structure or NULL if no log is desired. |
uint8_t SendT0CmdData | ( | uint8_t | inverse_convention, | |
uint8_t | TC1, | |||
uint8_t * | cmdData, | |||
uint8_t | len, | |||
log_struct_t * | logger | |||
) |
Send a command data to the ICC using protocol T=0.
Send a command data to the ICC for protocol T = 0
inverse_convention | different than 0 if inverse convention is to be used | |
TC1 | the N parameter received in byte TC1 of ATR | |
cmdData | command data to be sent | |
len | lenght in bytes of command data to be sent | |
logger | a pointer to a log structure or NULL if no log is desired |
uint8_t SendT0CmdHeader | ( | uint8_t | inverse_convention, | |
uint8_t | TC1, | |||
EMVCommandHeader * | cmdHeader, | |||
log_struct_t * | logger | |||
) |
Send a command header to the ICC using protocol T=0.
Send a command header to the ICC for protocol T = 0
inverse_convention | different than 0 if inverse convention is to be used | |
TC1 | the N parameter received in byte TC1 of ATR | |
cmdHeader | command header to be sent | |
logger | a pointer to a log structure or NULL if no log is desired |
uint8_t SendT0Command | ( | uint8_t | inverse_convention, | |
uint8_t | TC1, | |||
CAPDU * | cmd, | |||
log_struct_t * | logger | |||
) |
Send a command (including data) to the ICC using protocol T=0.
Send a command (including data) to the ICC for protocol T = 0. For command cases 3 and 4 a procedure byte(s) is expected back before sending the data
inverse_convention | different than 0 if inverse convention is to be used | |
TC1 | the N parameter received in byte TC1 of ATR | |
cmd | command to be sent | |
logger | a pointer to a log structure or NULL if no log is desired |
uint8_t SendT0Response | ( | uint8_t | inverse_convention, | |
EMVCommandHeader * | cmdHeader, | |||
RAPDU * | response, | |||
log_struct_t * | logger | |||
) |
Send a response to the terminal.
Send a response (including data) to the terminal for protocol T = 0. Data (if available) is sent with a procedure byte prepended
inverse_convention | different than 0 if inverse convention is to be used | |
cmdHeader | header of command for which response is being sent | |
response | RAPDU containing the response to be sent | |
logger | a pointer to a log structure or NULL if no log is desired |
uint8_t* SerializeCommand | ( | CAPDU * | cmd, | |
uint8_t * | len | |||
) |
Serialize a CAPDU structure.
This function serializes (converts to a sequence of bytes) a CAPDU structure.
cmd | command to be serialized | |
len | length of the resulted byte stream |
uint8_t* SerializeResponse | ( | RAPDU * | response, | |
uint8_t * | len | |||
) |
Serialize a RAPDU structure.
This function serializes (converts to a sequence of bytes) a RAPDU structure.
response | response to be serialized | |
len | length of the resulted byte stream |