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.
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 Aug 9 2022 00:37:09 by
1.7.2