Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers iso7816.c Source File

iso7816.c

Go to the documentation of this file.
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