Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
iso7816.c
00001 /* 00002 * Copyright (c) 2015-2018, ARM Limited, All Rights Reserved 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); you may 00006 * not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 00013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 /** 00018 * \file iso7816.c 00019 * \copyright Copyright (c) ARM Ltd 2015 00020 * \author Donatien Garnier 00021 */ 00022 00023 #define __DEBUG__ 0 00024 #ifndef __MODULE__ 00025 #define __MODULE__ "iso7816.c" 00026 #endif 00027 00028 #include "stack/nfc_errors.h" 00029 00030 #include "iso7816.h" 00031 #include "iso7816_app.h" 00032 #include "iso7816_defs.h" 00033 #include "tech/isodep/isodep_target.h" 00034 #include "platform/nfc_debug.h" 00035 00036 static void iso7816_disconnected(nfc_tech_iso7816_t *pIso7816, bool deselected); 00037 00038 static nfc_err_t iso7816_parse(nfc_tech_iso7816_t *pIso7816); 00039 00040 static void iso7816_receive(nfc_tech_iso7816_t *pIso7816); 00041 static nfc_err_t iso7816_transmit(nfc_tech_iso7816_t *pIso7816); 00042 00043 static bool iso7816_mf_command(nfc_tech_iso7816_t *pIso7816); 00044 00045 static void iso_dep_received_cb(nfc_tech_isodep_t *pIsodep, nfc_err_t ret, void *pUserData); 00046 static void iso_dep_transmitted_cb(nfc_tech_isodep_t *pIsodep, nfc_err_t ret, void *pUserData); 00047 static void iso_dep_disconnected_cb(nfc_tech_isodep_t *pIsodep, bool deselected, void *pUserData); 00048 00049 static void iso_dep_stream_transmit_cb(ac_buffer_t *ppDataIn, bool *pClose, size_t maxLength, void *pUserParam); 00050 static void iso_dep_stream_receive_cb(ac_buffer_t *pDataOut, bool closed, void *pUserParam); 00051 00052 void nfc_tech_iso7816_init(nfc_tech_iso7816_t *pIso7816, nfc_transceiver_t *pTransceiver, nfc_tech_iso7816_disconnected_cb disconnectedCb, void *pUserData) 00053 { 00054 ac_buffer_init(&pIso7816->hist, NULL, 0); 00055 nfc_tech_isodep_target_init(&pIso7816->isoDepTarget, pTransceiver, &pIso7816->hist, iso_dep_disconnected_cb, pIso7816); 00056 pIso7816->pAppList = NULL; 00057 pIso7816->pSelectedApp = NULL; 00058 pIso7816->disconnectedCb = disconnectedCb; 00059 00060 ac_istream_init(&pIso7816->inputStream, iso_dep_stream_transmit_cb, pIso7816); 00061 ac_ostream_init(&pIso7816->outputStream, iso_dep_stream_receive_cb, pIso7816); 00062 00063 ac_buffer_builder_init(&pIso7816->txBldr, pIso7816->txBuf, 2); //Just enough to fit sw 00064 00065 ac_buffer_builder_init(&pIso7816->rxBldr, pIso7816->rxBuf, ISO7816_RX_BUFFER_SIZE); 00066 00067 pIso7816->pUserData = pUserData; 00068 } 00069 00070 void nfc_tech_iso7816_connect(nfc_tech_iso7816_t *pIso7816) 00071 { 00072 pIso7816->disconnected = false; 00073 pIso7816->responseReady = true; 00074 00075 iso7816_receive(pIso7816); 00076 nfc_tech_isodep_target_connect(&pIso7816->isoDepTarget); 00077 } 00078 00079 void nfc_tech_iso7816_disconnect(nfc_tech_iso7816_t *pIso7816) 00080 { 00081 nfc_tech_isodep_target_disconnect(&pIso7816->isoDepTarget); 00082 } 00083 00084 void nfc_tech_iso7816_add_app(nfc_tech_iso7816_t *pIso7816, nfc_tech_iso7816_app_t *pIso7816App) 00085 { 00086 nfc_tech_iso7816_app_t **ppPrevApp = &pIso7816->pAppList; 00087 while (*ppPrevApp != NULL) { 00088 ppPrevApp = &((*ppPrevApp)->pNext); 00089 } 00090 *ppPrevApp = pIso7816App; 00091 pIso7816App->pNext = NULL; 00092 } 00093 00094 nfc_err_t nfc_tech_iso7816_reply(nfc_tech_iso7816_t *pIso7816) 00095 { 00096 nfc_err_t ret; 00097 00098 //Serialize APDU and send 00099 ac_buffer_builder_reset(&pIso7816->txBldr); 00100 ac_buffer_builder_write_nu16(&pIso7816->txBldr, pIso7816->rApdu.sw); 00101 00102 ac_buffer_append(&pIso7816->rApdu.dataOut, ac_buffer_builder_buffer(&pIso7816->txBldr)); 00103 00104 NFC_DBG("R-ADPU: (LE):%02X SW:%04X", ac_buffer_reader_readable(&pIso7816->rApdu.dataOut), pIso7816->rApdu.sw); 00105 NFC_DBG_BLOCK(ac_buffer_dump(&pIso7816->rApdu.dataOut);) 00106 00107 ret = iso7816_transmit(pIso7816); 00108 if (ret) { 00109 return ret; 00110 } 00111 00112 return NFC_OK; 00113 } 00114 00115 void iso7816_disconnected(nfc_tech_iso7816_t *pIso7816, bool deselected) 00116 { 00117 pIso7816->disconnected = true; 00118 if (pIso7816->pSelectedApp != NULL) { 00119 //Deselect previous app 00120 pIso7816->pSelectedApp->deselected(pIso7816->pSelectedApp, pIso7816->pSelectedApp->pUserData); 00121 pIso7816->pSelectedApp = NULL; 00122 } 00123 if (!deselected) { 00124 pIso7816->disconnectedCb(pIso7816, pIso7816->pUserData); 00125 } 00126 } 00127 00128 nfc_err_t iso7816_parse(nfc_tech_iso7816_t *pIso7816) 00129 { 00130 //Reset R-APDU 00131 ac_buffer_init(&pIso7816->rApdu.dataOut, NULL, 0); 00132 pIso7816->rApdu.sw = ISO7816_SW_OK; 00133 00134 NFC_DBG_BLOCK(ac_buffer_dump(ac_buffer_builder_buffer(&pIso7816->rxBldr));) 00135 00136 if (ac_buffer_reader_readable(ac_buffer_builder_buffer(&pIso7816->rxBldr)) < 4) { 00137 NFC_ERR("C-APDU is too small"); 00138 pIso7816->rApdu.sw = ISO7816_SW_INVALID_CLASS; 00139 nfc_tech_iso7816_reply(pIso7816); 00140 return NFC_ERR_PROTOCOL; 00141 } 00142 00143 pIso7816->cApdu.cla = ac_buffer_read_nu8(ac_buffer_builder_buffer(&pIso7816->rxBldr)); 00144 pIso7816->cApdu.ins = ac_buffer_read_nu8(ac_buffer_builder_buffer(&pIso7816->rxBldr)); 00145 pIso7816->cApdu.p1 = ac_buffer_read_nu8(ac_buffer_builder_buffer(&pIso7816->rxBldr)); 00146 pIso7816->cApdu.p2 = ac_buffer_read_nu8(ac_buffer_builder_buffer(&pIso7816->rxBldr)); 00147 ac_buffer_init(&pIso7816->cApdu.dataIn, NULL, 0); 00148 pIso7816->cApdu.maxRespLength = 0; 00149 00150 if (ac_buffer_reader_readable(ac_buffer_builder_buffer(&pIso7816->rxBldr)) > 1) { 00151 size_t lc = ac_buffer_read_nu8(ac_buffer_builder_buffer(&pIso7816->rxBldr)); 00152 if (ac_buffer_reader_readable(ac_buffer_builder_buffer(&pIso7816->rxBldr)) >= lc) { 00153 ac_buffer_split(&pIso7816->cApdu.dataIn, ac_buffer_builder_buffer(&pIso7816->rxBldr), ac_buffer_builder_buffer(&pIso7816->rxBldr), lc); 00154 } else { 00155 pIso7816->rApdu.sw = ISO7816_SW_WRONG_LENGTH; 00156 nfc_tech_iso7816_reply(pIso7816); 00157 return NFC_ERR_LENGTH; //Not a valid frame 00158 } 00159 } 00160 00161 if (ac_buffer_reader_readable(ac_buffer_builder_buffer(&pIso7816->rxBldr)) >= 1) { 00162 pIso7816->cApdu.maxRespLength = ac_buffer_read_nu8(ac_buffer_builder_buffer(&pIso7816->rxBldr)); 00163 } 00164 00165 NFC_DBG("C-APDU: CLA:%02X INS:%02X P1:%02X P2:%02X LC:%02X LE:%02X", pIso7816->cApdu.cla, pIso7816->cApdu.ins, pIso7816->cApdu.p1, pIso7816->cApdu.p2, 00166 ac_buffer_reader_readable(&pIso7816->cApdu.dataIn), pIso7816->cApdu.maxRespLength); 00167 00168 if (ac_buffer_reader_readable(ac_buffer_builder_buffer(&pIso7816->rxBldr)) > 0) { 00169 pIso7816->rApdu.sw = ISO7816_SW_WRONG_LENGTH; 00170 nfc_tech_iso7816_reply(pIso7816); 00171 return NFC_ERR_LENGTH; //Not a valid frame 00172 } 00173 00174 //See if can select an app 00175 if (iso7816_mf_command(pIso7816)) { 00176 nfc_tech_iso7816_reply(pIso7816); 00177 return NFC_OK; 00178 } 00179 00180 //Pass command to selected app 00181 if (pIso7816->pSelectedApp == NULL) { 00182 pIso7816->rApdu.sw = ISO7816_SW_NOT_FOUND; 00183 nfc_tech_iso7816_reply(pIso7816); 00184 return NFC_ERR_NOT_FOUND; //Not a valid frame 00185 } 00186 00187 pIso7816->pSelectedApp->apdu(pIso7816->pSelectedApp, pIso7816->pSelectedApp->pUserData); 00188 00189 return NFC_OK; 00190 } 00191 00192 void iso7816_receive(nfc_tech_iso7816_t *pIso7816) 00193 { 00194 ac_buffer_builder_reset(&pIso7816->rxBldr); 00195 nfc_tech_isodep_target_receive(&pIso7816->isoDepTarget, &pIso7816->outputStream, iso_dep_received_cb, pIso7816); 00196 } 00197 00198 nfc_err_t iso7816_transmit(nfc_tech_iso7816_t *pIso7816) 00199 { 00200 return nfc_tech_isodep_target_transmit(&pIso7816->isoDepTarget, &pIso7816->inputStream, iso_dep_transmitted_cb, pIso7816); 00201 } 00202 00203 /** Handle ISO7816-4 command 00204 * \param pTarget pointer to target instance 00205 * \param CLA ISO7816-4 class byte 00206 * \param INS ISO7816-4 instruction byte 00207 * \param P1 ISO7816-4 P1 byte 00208 * \param P2 ISO7816-4 P2 byte 00209 * \param pDataIn ISO7816-4 command payload 00210 * \param pDataOut ISO7816-4 response payload 00211 * \param SW status word 00212 * \return true if command was handled, false if it should be passed to the selected application 00213 */ 00214 bool iso7816_mf_command(nfc_tech_iso7816_t *pIso7816) 00215 { 00216 nfc_tech_iso7816_app_t *pApp; 00217 if (pIso7816->cApdu.cla != 0x00) { 00218 return false; 00219 } 00220 switch (pIso7816->cApdu.ins) { 00221 case ISO7816_INS_SELECT: 00222 switch (pIso7816->cApdu.p1) { 00223 case 0x04: //Selection by DF name 00224 pApp = pIso7816->pAppList; 00225 while (pApp != NULL) { 00226 if (ac_buffer_reader_readable(&pIso7816->cApdu.dataIn) <= pApp->aidSize) { 00227 if (ac_buffer_reader_cmp_bytes(&pIso7816->cApdu.dataIn, pApp->aid, ac_buffer_reader_readable(&pIso7816->cApdu.dataIn))) { 00228 if (pIso7816->pSelectedApp != NULL) { 00229 //Deselect previous app 00230 pIso7816->pSelectedApp->deselected(pIso7816->pSelectedApp, pIso7816->pSelectedApp->pUserData); 00231 } 00232 pIso7816->pSelectedApp = pApp; 00233 pIso7816->pSelectedApp->selected(pIso7816->pSelectedApp, pIso7816->pSelectedApp->pUserData); 00234 pIso7816->rApdu.sw = ISO7816_SW_OK; 00235 return true; 00236 } 00237 } 00238 pApp = pApp->pNext; 00239 } 00240 pIso7816->rApdu.sw = ISO7816_SW_NOT_FOUND; 00241 return true; 00242 default: 00243 if (pIso7816->pSelectedApp == NULL) { 00244 pIso7816->rApdu.sw = ISO7816_SW_NOT_FOUND; 00245 return true; 00246 } else { 00247 return false; 00248 } 00249 } 00250 break; 00251 default: 00252 if (pIso7816->pSelectedApp == NULL) { 00253 pIso7816->rApdu.sw = ISO7816_SW_INVALID_INS; 00254 return true; 00255 } else { 00256 return false; 00257 } 00258 break; 00259 } 00260 } 00261 00262 void iso_dep_received_cb(nfc_tech_isodep_t *pIsodep, nfc_err_t ret, void *pUserData) 00263 { 00264 nfc_tech_iso7816_t *pIso7816 = (nfc_tech_iso7816_t *) pUserData; 00265 00266 (void) pIsodep; 00267 00268 if (ret) { 00269 NFC_WARN("Got error %d", ret); 00270 return; 00271 } 00272 00273 //Parse received APDU 00274 ret = iso7816_parse(pIso7816); 00275 if (ret) { 00276 NFC_WARN("Got error %d", ret); 00277 return; 00278 } 00279 } 00280 00281 void iso_dep_transmitted_cb(nfc_tech_isodep_t *pIsodep, nfc_err_t ret, void *pUserData) 00282 { 00283 nfc_tech_iso7816_t *pIso7816 = (nfc_tech_iso7816_t *) pUserData; 00284 00285 (void) pIsodep; 00286 00287 if (ret) { 00288 NFC_WARN("Got error %d", ret); 00289 return; 00290 } 00291 00292 //Advertise that we have space in our buffer? 00293 00294 //Switch to receive mode! 00295 iso7816_receive(pIso7816); 00296 } 00297 00298 void iso_dep_disconnected_cb(nfc_tech_isodep_t *pIsodep, bool deselected, void *pUserData) 00299 { 00300 nfc_tech_iso7816_t *pIso7816 = (nfc_tech_iso7816_t *) pUserData; 00301 00302 (void) pIsodep; 00303 00304 NFC_DBG("ISO DEP %s", deselected ? "deselected" : "disconnected"); 00305 iso7816_disconnected(pIso7816, deselected); 00306 00307 if (deselected) { 00308 // Re-connect immediately 00309 nfc_tech_iso7816_connect(pIso7816); 00310 } 00311 } 00312 00313 void iso_dep_stream_transmit_cb(ac_buffer_t *pDataIn, bool *pClose, size_t maxLength, void *pUserParam) 00314 { 00315 nfc_tech_iso7816_t *pIso7816 = (nfc_tech_iso7816_t *) pUserParam; 00316 00317 //Only close if buffer fits in this frame 00318 if (maxLength >= ac_buffer_reader_readable(&pIso7816->rApdu.dataOut)) 00319 //if( ac_buffer_total_length(&pLlcp->tx) <= maxLength ) 00320 { 00321 maxLength = ac_buffer_reader_readable(&pIso7816->rApdu.dataOut); 00322 *pClose = true; 00323 } else { 00324 *pClose = false; 00325 } 00326 00327 ac_buffer_split(pDataIn, &pIso7816->rApdu.dataOut, &pIso7816->rApdu.dataOut, maxLength); 00328 } 00329 00330 void iso_dep_stream_receive_cb(ac_buffer_t *pDataOut, bool closed, void *pUserParam) 00331 { 00332 nfc_tech_iso7816_t *pIso7816 = (nfc_tech_iso7816_t *) pUserParam; 00333 00334 (void) closed; 00335 00336 if (ac_buffer_reader_readable(pDataOut) > ac_buffer_builder_writable(&pIso7816->rxBldr)) { 00337 NFC_ERR("Frame will not fit (%u > %u)", ac_buffer_reader_readable(pDataOut), ac_buffer_builder_writable(&pIso7816->rxBldr)); 00338 } 00339 00340 //Feed rx buffer 00341 ac_buffer_builder_copy_n_bytes(&pIso7816->rxBldr, pDataOut, ac_buffer_reader_readable(pDataOut)); 00342 } 00343
Generated on Tue Jul 12 2022 13:54:25 by
