Generic library for working with PN532-like chips

Fork of PN532 by Seeed

Committer:
r4z0r7o3
Date:
Wed Feb 04 19:04:54 2015 +0000
Revision:
10:f959b305a571
Parent:
7:26c1b3b6c192
Try multiple known auth. keys on classic.  Also fixed all debugging messages so they all end with newlines.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
yihui 3:4189a10038e6 1 /**************************************************************************/
yihui 3:4189a10038e6 2 /*!
yihui 3:4189a10038e6 3 @file emulatetag.cpp
yihui 3:4189a10038e6 4 @author Armin Wieser
yihui 3:4189a10038e6 5 @license BSD
yihui 3:4189a10038e6 6 */
yihui 3:4189a10038e6 7 /**************************************************************************/
yihui 3:4189a10038e6 8
yihui 3:4189a10038e6 9 #include "emulatetag.h"
yihui 3:4189a10038e6 10 #include "PN532_debug.h"
yihui 3:4189a10038e6 11
yihui 3:4189a10038e6 12 #include <string.h>
yihui 3:4189a10038e6 13
yihui 3:4189a10038e6 14 #define MAX_TGREAD
yihui 3:4189a10038e6 15
yihui 3:4189a10038e6 16
yihui 3:4189a10038e6 17 // Command APDU
yihui 3:4189a10038e6 18 #define C_APDU_CLA 0
yihui 3:4189a10038e6 19 #define C_APDU_INS 1 // instruction
yihui 3:4189a10038e6 20 #define C_APDU_P1 2 // parameter 1
yihui 3:4189a10038e6 21 #define C_APDU_P2 3 // parameter 2
yihui 3:4189a10038e6 22 #define C_APDU_LC 4 // length command
yihui 3:4189a10038e6 23 #define C_APDU_DATA 5 // data
yihui 3:4189a10038e6 24
yihui 3:4189a10038e6 25 #define C_APDU_P1_SELECT_BY_ID 0x00
yihui 3:4189a10038e6 26 #define C_APDU_P1_SELECT_BY_NAME 0x04
yihui 3:4189a10038e6 27
yihui 3:4189a10038e6 28 // Response APDU
yihui 3:4189a10038e6 29 #define R_APDU_SW1_COMMAND_COMPLETE 0x90
yihui 3:4189a10038e6 30 #define R_APDU_SW2_COMMAND_COMPLETE 0x00
yihui 3:4189a10038e6 31
yihui 3:4189a10038e6 32 #define R_APDU_SW1_NDEF_TAG_NOT_FOUND 0x6a
yihui 3:4189a10038e6 33 #define R_APDU_SW2_NDEF_TAG_NOT_FOUND 0x82
yihui 3:4189a10038e6 34
yihui 3:4189a10038e6 35 #define R_APDU_SW1_FUNCTION_NOT_SUPPORTED 0x6A
yihui 3:4189a10038e6 36 #define R_APDU_SW2_FUNCTION_NOT_SUPPORTED 0x81
yihui 3:4189a10038e6 37
yihui 3:4189a10038e6 38 #define R_APDU_SW1_MEMORY_FAILURE 0x65
yihui 3:4189a10038e6 39 #define R_APDU_SW2_MEMORY_FAILURE 0x81
yihui 3:4189a10038e6 40
yihui 3:4189a10038e6 41 #define R_APDU_SW1_END_OF_FILE_BEFORE_REACHED_LE_BYTES 0x62
yihui 3:4189a10038e6 42 #define R_APDU_SW2_END_OF_FILE_BEFORE_REACHED_LE_BYTES 0x82
yihui 3:4189a10038e6 43
yihui 3:4189a10038e6 44 // ISO7816-4 commands
yihui 3:4189a10038e6 45 #define ISO7816_SELECT_FILE 0xA4
yihui 3:4189a10038e6 46 #define ISO7816_READ_BINARY 0xB0
yihui 3:4189a10038e6 47 #define ISO7816_UPDATE_BINARY 0xD6
yihui 3:4189a10038e6 48
yihui 3:4189a10038e6 49 typedef enum { NONE, CC, NDEF } tag_file; // CC ... Compatibility Container
yihui 3:4189a10038e6 50
yihui 3:4189a10038e6 51 const uint8_t compatibility_container[] = {
yihui 3:4189a10038e6 52 0, 0x0F,
yihui 3:4189a10038e6 53 0x20,
yihui 3:4189a10038e6 54 0, 0x54,
yihui 3:4189a10038e6 55 0, 0xFF,
yihui 3:4189a10038e6 56 0x04,
yihui 3:4189a10038e6 57 0x06,
yihui 3:4189a10038e6 58 0xE1, 0x04,
yihui 3:4189a10038e6 59 0xFF, 0xFE,
yihui 3:4189a10038e6 60 0x00,
yihui 3:4189a10038e6 61 0x00
yihui 3:4189a10038e6 62 };
yihui 3:4189a10038e6 63
yihui 3:4189a10038e6 64 bool EmulateTag::init(){
yihui 3:4189a10038e6 65 pn532.begin();
yihui 3:4189a10038e6 66 return pn532.SAMConfig();
yihui 3:4189a10038e6 67 }
yihui 3:4189a10038e6 68
yihui 3:4189a10038e6 69 void EmulateTag::setNdefFile(const uint8_t* ndef, const int16_t ndefLength){
yihui 3:4189a10038e6 70 if(ndefLength > (NDEF_MAX_LENGTH -2)){
r4z0r7o3 10:f959b305a571 71 DMSG("ndef file too large (> NDEF_MAX_LENGHT -2) - aborting\n");
yihui 3:4189a10038e6 72 return;
yihui 3:4189a10038e6 73 }
yihui 3:4189a10038e6 74
yihui 3:4189a10038e6 75 ndef_file[0] = ndefLength >> 8;
yihui 3:4189a10038e6 76 ndef_file[1] = ndefLength & 0xFF;
yihui 3:4189a10038e6 77 memcpy(ndef_file+2, ndef, ndefLength);
yihui 3:4189a10038e6 78 }
yihui 3:4189a10038e6 79
yihui 3:4189a10038e6 80 void EmulateTag::setUid(uint8_t* uid){
yihui 3:4189a10038e6 81 uidPtr = uid;
yihui 3:4189a10038e6 82 }
yihui 3:4189a10038e6 83
yihui 3:4189a10038e6 84 bool EmulateTag::emulate(const uint16_t tgInitAsTargetTimeout){
yihui 3:4189a10038e6 85
yihui 3:4189a10038e6 86 uint8_t command[] = {
yihui 3:4189a10038e6 87 PN532_COMMAND_TGINITASTARGET,
yihui 3:4189a10038e6 88 5, // MODE: PICC only, Passive only
yihui 3:4189a10038e6 89
yihui 3:4189a10038e6 90 0x04, 0x00, // SENS_RES
yihui 3:4189a10038e6 91 0x00, 0x00, 0x00, // NFCID1
yihui 3:4189a10038e6 92 0x20, // SEL_RES
yihui 3:4189a10038e6 93
yihui 3:4189a10038e6 94 0,0,0,0,0,0,0,0,
yihui 3:4189a10038e6 95 0,0,0,0,0,0,0,0, // FeliCaParams
yihui 3:4189a10038e6 96 0,0,
yihui 3:4189a10038e6 97
yihui 3:4189a10038e6 98 0,0,0,0,0,0,0,0,0,0, // NFCID3t
yihui 3:4189a10038e6 99
yihui 3:4189a10038e6 100 0, // length of general bytes
yihui 3:4189a10038e6 101 0 // length of historical bytes
yihui 3:4189a10038e6 102 };
yihui 3:4189a10038e6 103
yihui 3:4189a10038e6 104 if(uidPtr != 0){ // if uid is set copy 3 bytes to nfcid1
yihui 3:4189a10038e6 105 memcpy(command + 4, uidPtr, 3);
yihui 3:4189a10038e6 106 }
yihui 3:4189a10038e6 107
yihui 3:4189a10038e6 108 if(1 != pn532.tgInitAsTarget(command,sizeof(command), tgInitAsTargetTimeout)){
r4z0r7o3 10:f959b305a571 109 DMSG("tgInitAsTarget failed or timed out!\n");
yihui 3:4189a10038e6 110 return false;
yihui 3:4189a10038e6 111 }
yihui 3:4189a10038e6 112
yihui 3:4189a10038e6 113 tagWrittenByInitiator = false;
yihui 3:4189a10038e6 114
yihui 3:4189a10038e6 115 uint8_t rwbuf[128];
yihui 3:4189a10038e6 116 uint8_t sendlen;
yihui 3:4189a10038e6 117 int16_t status;
yihui 3:4189a10038e6 118 tag_file currentFile = NONE;
screamer 7:26c1b3b6c192 119 //uint16_t cc_size = sizeof(compatibility_container);
yihui 3:4189a10038e6 120 bool runLoop = true;
yihui 3:4189a10038e6 121
yihui 3:4189a10038e6 122 while(runLoop){
yihui 3:4189a10038e6 123 status = pn532.tgGetData(rwbuf, sizeof(rwbuf));
yihui 3:4189a10038e6 124 if(status < 0){
yihui 3:4189a10038e6 125 DMSG("tgGetData failed!\n");
yihui 3:4189a10038e6 126 pn532.inRelease();
yihui 3:4189a10038e6 127 return true;
yihui 3:4189a10038e6 128 }
yihui 3:4189a10038e6 129
yihui 3:4189a10038e6 130 uint8_t p1 = rwbuf[C_APDU_P1];
yihui 3:4189a10038e6 131 uint8_t p2 = rwbuf[C_APDU_P2];
yihui 3:4189a10038e6 132 uint8_t lc = rwbuf[C_APDU_LC];
yihui 3:4189a10038e6 133 uint16_t p1p2_length = ((int16_t) p1 << 8) + p2;
yihui 3:4189a10038e6 134
yihui 3:4189a10038e6 135 switch(rwbuf[C_APDU_INS]){
yihui 3:4189a10038e6 136 case ISO7816_SELECT_FILE:
yihui 3:4189a10038e6 137 switch(p1){
yihui 3:4189a10038e6 138 case C_APDU_P1_SELECT_BY_ID:
yihui 3:4189a10038e6 139 if(p2 != 0x0c){
yihui 3:4189a10038e6 140 DMSG("C_APDU_P2 != 0x0c\n");
yihui 3:4189a10038e6 141 setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
yihui 3:4189a10038e6 142 } else if(lc == 2 && rwbuf[C_APDU_DATA] == 0xE1 && (rwbuf[C_APDU_DATA+1] == 0x03 || rwbuf[C_APDU_DATA+1] == 0x04)){
yihui 3:4189a10038e6 143 setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
yihui 3:4189a10038e6 144 if(rwbuf[C_APDU_DATA+1] == 0x03){
yihui 3:4189a10038e6 145 currentFile = CC;
yihui 3:4189a10038e6 146 } else if(rwbuf[C_APDU_DATA+1] == 0x04){
yihui 3:4189a10038e6 147 currentFile = NDEF;
yihui 3:4189a10038e6 148 }
yihui 3:4189a10038e6 149 } else {
yihui 3:4189a10038e6 150 setResponse(TAG_NOT_FOUND, rwbuf, &sendlen);
yihui 3:4189a10038e6 151 }
yihui 3:4189a10038e6 152 break;
yihui 3:4189a10038e6 153 case C_APDU_P1_SELECT_BY_NAME:
yihui 3:4189a10038e6 154 const uint8_t ndef_tag_application_name_v2[] = {0, 0x7, 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01 };
yihui 3:4189a10038e6 155 if(0 == memcmp(ndef_tag_application_name_v2, rwbuf + C_APDU_P2, sizeof(ndef_tag_application_name_v2))){
yihui 3:4189a10038e6 156 setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
yihui 3:4189a10038e6 157 } else{
yihui 3:4189a10038e6 158 DMSG("function not supported\n");
yihui 3:4189a10038e6 159 setResponse(FUNCTION_NOT_SUPPORTED, rwbuf, &sendlen);
yihui 3:4189a10038e6 160 }
yihui 3:4189a10038e6 161 break;
yihui 3:4189a10038e6 162 }
yihui 3:4189a10038e6 163 break;
yihui 3:4189a10038e6 164 case ISO7816_READ_BINARY:
yihui 3:4189a10038e6 165 switch(currentFile){
yihui 3:4189a10038e6 166 case NONE:
yihui 3:4189a10038e6 167 setResponse(TAG_NOT_FOUND, rwbuf, &sendlen);
yihui 3:4189a10038e6 168 break;
yihui 3:4189a10038e6 169 case CC:
yihui 3:4189a10038e6 170 if( p1p2_length > NDEF_MAX_LENGTH){
yihui 3:4189a10038e6 171 setResponse(END_OF_FILE_BEFORE_REACHED_LE_BYTES, rwbuf, &sendlen);
yihui 3:4189a10038e6 172 }else {
yihui 3:4189a10038e6 173 memcpy(rwbuf,compatibility_container + p1p2_length, lc);
yihui 3:4189a10038e6 174 setResponse(COMMAND_COMPLETE, rwbuf + lc, &sendlen, lc);
yihui 3:4189a10038e6 175 }
yihui 3:4189a10038e6 176 break;
yihui 3:4189a10038e6 177 case NDEF:
yihui 3:4189a10038e6 178 if( p1p2_length > NDEF_MAX_LENGTH){
yihui 3:4189a10038e6 179 setResponse(END_OF_FILE_BEFORE_REACHED_LE_BYTES, rwbuf, &sendlen);
yihui 3:4189a10038e6 180 }else {
yihui 3:4189a10038e6 181 memcpy(rwbuf, ndef_file + p1p2_length, lc);
yihui 3:4189a10038e6 182 setResponse(COMMAND_COMPLETE, rwbuf + lc, &sendlen, lc);
yihui 3:4189a10038e6 183 }
yihui 3:4189a10038e6 184 break;
yihui 3:4189a10038e6 185 }
yihui 3:4189a10038e6 186 break;
yihui 3:4189a10038e6 187 case ISO7816_UPDATE_BINARY:
yihui 3:4189a10038e6 188 if( p1p2_length > NDEF_MAX_LENGTH){
yihui 3:4189a10038e6 189 setResponse(MEMORY_FAILURE, rwbuf, &sendlen);
yihui 3:4189a10038e6 190 }
yihui 3:4189a10038e6 191 else{
yihui 3:4189a10038e6 192 memcpy(ndef_file + p1p2_length, rwbuf + C_APDU_DATA, lc);
yihui 3:4189a10038e6 193 setResponse(COMMAND_COMPLETE, rwbuf, &sendlen);
yihui 3:4189a10038e6 194 tagWrittenByInitiator = true;
yihui 3:4189a10038e6 195 }
yihui 3:4189a10038e6 196 break;
yihui 3:4189a10038e6 197 default:
r4z0r7o3 10:f959b305a571 198 DMSG("Command not supported ");
yihui 3:4189a10038e6 199 DMSG_HEX(rwbuf[C_APDU_INS]);
yihui 3:4189a10038e6 200 DMSG("\n");
yihui 3:4189a10038e6 201 setResponse(FUNCTION_NOT_SUPPORTED, rwbuf, &sendlen);
yihui 3:4189a10038e6 202 }
yihui 3:4189a10038e6 203 status = pn532.tgSetData(rwbuf, sendlen);
yihui 3:4189a10038e6 204 if(status < 0){
yihui 3:4189a10038e6 205 DMSG("tgSetData failed\n!");
yihui 3:4189a10038e6 206 pn532.inRelease();
yihui 3:4189a10038e6 207 return true;
yihui 3:4189a10038e6 208 }
yihui 3:4189a10038e6 209 }
yihui 3:4189a10038e6 210 pn532.inRelease();
yihui 3:4189a10038e6 211 return true;
yihui 3:4189a10038e6 212 }
yihui 3:4189a10038e6 213
yihui 3:4189a10038e6 214 void EmulateTag::setResponse(responseCommand cmd, uint8_t* buf, uint8_t* sendlen, uint8_t sendlenOffset){
yihui 3:4189a10038e6 215 switch(cmd){
yihui 3:4189a10038e6 216 case COMMAND_COMPLETE:
yihui 3:4189a10038e6 217 buf[0] = R_APDU_SW1_COMMAND_COMPLETE;
yihui 3:4189a10038e6 218 buf[1] = R_APDU_SW2_COMMAND_COMPLETE;
yihui 3:4189a10038e6 219 *sendlen = 2 + sendlenOffset;
yihui 3:4189a10038e6 220 break;
yihui 3:4189a10038e6 221 case TAG_NOT_FOUND:
yihui 3:4189a10038e6 222 buf[0] = R_APDU_SW1_NDEF_TAG_NOT_FOUND;
yihui 3:4189a10038e6 223 buf[1] = R_APDU_SW2_NDEF_TAG_NOT_FOUND;
yihui 3:4189a10038e6 224 *sendlen = 2;
yihui 3:4189a10038e6 225 break;
yihui 3:4189a10038e6 226 case FUNCTION_NOT_SUPPORTED:
yihui 3:4189a10038e6 227 buf[0] = R_APDU_SW1_FUNCTION_NOT_SUPPORTED;
yihui 3:4189a10038e6 228 buf[1] = R_APDU_SW2_FUNCTION_NOT_SUPPORTED;
yihui 3:4189a10038e6 229 *sendlen = 2;
yihui 3:4189a10038e6 230 break;
yihui 3:4189a10038e6 231 case MEMORY_FAILURE:
yihui 3:4189a10038e6 232 buf[0] = R_APDU_SW1_MEMORY_FAILURE;
yihui 3:4189a10038e6 233 buf[1] = R_APDU_SW2_MEMORY_FAILURE;
yihui 3:4189a10038e6 234 *sendlen = 2;
yihui 3:4189a10038e6 235 break;
yihui 3:4189a10038e6 236 case END_OF_FILE_BEFORE_REACHED_LE_BYTES:
yihui 3:4189a10038e6 237 buf[0] = R_APDU_SW1_END_OF_FILE_BEFORE_REACHED_LE_BYTES;
yihui 3:4189a10038e6 238 buf[1] = R_APDU_SW2_END_OF_FILE_BEFORE_REACHED_LE_BYTES;
yihui 3:4189a10038e6 239 *sendlen= 2;
yihui 3:4189a10038e6 240 break;
yihui 3:4189a10038e6 241 }
yihui 3:4189a10038e6 242 }