From 9115729213bff20de5dd76fdc6a5976291f47ce0 Mon Sep 17 00:00:00 2001 From: Callan Barrett Date: Sat, 6 Jul 2024 20:20:21 +0800 Subject: [PATCH] add pcsc support --- Taskfile.dist.yml | 2 +- go.mod | 2 +- scripts/linux_arm64/build/Dockerfile | 34 +++++-- .../patches/pcsc-initiator_poll_target.patch | 90 +++++++++++++++++++ scripts/mister/build/Dockerfile | 34 +++++-- scripts/mister/build/build.sh | 7 +- .../mister/build/patches/acr122u-fix.patch | 67 -------------- .../patches/pcsc-initiator_poll_target.patch | 90 +++++++++++++++++++ scripts/mister/build/pcsc-lite.sh | 28 ++++++ 9 files changed, 274 insertions(+), 80 deletions(-) create mode 100644 scripts/linux_arm64/build/patches/pcsc-initiator_poll_target.patch delete mode 100644 scripts/mister/build/patches/acr122u-fix.patch create mode 100644 scripts/mister/build/patches/pcsc-initiator_poll_target.patch create mode 100644 scripts/mister/build/pcsc-lite.sh diff --git a/Taskfile.dist.yml b/Taskfile.dist.yml index 393e4eb8..719fc00a 100644 --- a/Taskfile.dist.yml +++ b/Taskfile.dist.yml @@ -4,7 +4,7 @@ env: GO111MODULE: on GOPROXY: https://goproxy.io,direct CGO_ENABLED: 1 - CGO_LDFLAGS: -lnfc -lusb -lcurses + CGO_LDFLAGS: -lpcsclite -lnfc -lusb -lcurses dotenv: [".env"] diff --git a/go.mod b/go.mod index d75f88b0..e071dca3 100755 --- a/go.mod +++ b/go.mod @@ -28,7 +28,6 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/stretchr/testify v1.9.0 // indirect - go.bug.st/serial v1.6.2 // indirect golang.org/x/term v0.22.0 // indirect ) @@ -42,6 +41,7 @@ require ( github.com/hsanjuan/go-ndef v0.0.1 github.com/rs/zerolog v1.31.0 github.com/wizzomafizzo/mrext v0.0.0-20240705120538-5efdc40f9c08 + go.bug.st/serial v1.6.2 go.etcd.io/bbolt v1.3.9 golang.org/x/sync v0.7.0 ) diff --git a/scripts/linux_arm64/build/Dockerfile b/scripts/linux_arm64/build/Dockerfile index 15a77f15..39e70fea 100755 --- a/scripts/linux_arm64/build/Dockerfile +++ b/scripts/linux_arm64/build/Dockerfile @@ -11,15 +11,39 @@ RUN apt-get install -y ca-certificates openssl && \ # install go and app dependencies RUN apt-get install build-essential git curl wget ncurses-dev -y && \ apt-get install golang-doc golang-go golang-src golang -y +RUN mkdir /internal + +# install pcsc-lite and ccid dependencies +RUN apt-get install -y flex libusb-1.0-0-dev zlib1g-dev +# install custom version of pcsc-lite +RUN cd /internal && \ + wget https://pcsclite.apdu.fr/files/pcsc-lite-2.0.0.tar.bz2 && \ + tar xf pcsc-lite-2.0.0.tar.bz2 && \ + cd pcsc-lite-2.0.0 && \ + ./configure --disable-libsystemd --disable-libudev -enable-static && \ + make -j "$(nproc)" && \ + make install +# install custom version of ccid +RUN cd /internal && \ + wget https://ccid.apdu.fr/files/ccid-1.5.4.tar.bz2 && \ + tar xf ccid-1.5.4.tar.bz2 && \ + cd ccid-1.5.4 && \ + ./configure -enable-static && \ + make -j "$(nproc)" && \ + make install # install libnfc dependencies RUN apt-get install -y libusb-dev libtool autoconf automake -# install custom version of libnfc -RUN mkdir /internal && cd /internal && \ - git clone --depth 1 https://github.com/sam1902/libnfc && \ - cd libnfc && \ +RUN cd /internal && \ + git clone --depth 1 https://github.com/nfc-tools/libnfc.git +# apply patches +COPY patches/pcsc-initiator_poll_target.patch /internal/libnfc/pcsc-initiator_poll_target.patch +RUN cd /internal/libnfc && \ + patch -p1 < pcsc-initiator_poll_target.patch +# build and install libnfc +RUN cd /internal/libnfc && \ autoreconf -vis && \ - ./configure && \ + ./configure --with-drivers=all && \ make -j "$(nproc)" && \ make install diff --git a/scripts/linux_arm64/build/patches/pcsc-initiator_poll_target.patch b/scripts/linux_arm64/build/patches/pcsc-initiator_poll_target.patch new file mode 100644 index 00000000..e8b76f8d --- /dev/null +++ b/scripts/linux_arm64/build/patches/pcsc-initiator_poll_target.patch @@ -0,0 +1,90 @@ +From 1e5cd05357b11381f5505f345afa4892804986f7 Mon Sep 17 00:00:00 2001 +From: Roberto Jung Drebes +Date: Wed, 29 May 2024 15:54:42 -0400 +Subject: [PATCH] initiator_poll_target for PCSC + +--- + libnfc/drivers/pcsc.c | 42 ++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 38 insertions(+), 4 deletions(-) + +diff --git a/libnfc/drivers/pcsc.c b/libnfc/drivers/pcsc.c +index 106d99ac..0bae4ed8 100644 +--- a/libnfc/drivers/pcsc.c ++++ b/libnfc/drivers/pcsc.c +@@ -176,7 +176,8 @@ static int pcsc_get_status(struct nfc_device *pnd, int *target_present, uint8_t + + data->last_error = SCardStatus(data->hCard, NULL, &reader_len, &state, &protocol, atr, &dw_atr_len); + if (data->last_error != SCARD_S_SUCCESS +- && data->last_error != SCARD_W_RESET_CARD) { ++ && data->last_error != SCARD_W_RESET_CARD ++ && data->last_error != SCARD_W_REMOVED_CARD) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Get status failed"); + return NFC_EIO; + } +@@ -193,7 +194,8 @@ static int pcsc_reconnect(struct nfc_device *pnd, DWORD share_mode, DWORD protoc + + data->last_error = SCardReconnect(data->hCard, share_mode, protocol, disposition, &data->ioCard.dwProtocol); + if (data->last_error != SCARD_S_SUCCESS +- && data->last_error != SCARD_W_RESET_CARD) { ++ && data->last_error != SCARD_W_RESET_CARD ++ && data->last_error != SCARD_E_NO_SMARTCARD) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Reconnect failed"); + return NFC_EIO; + } +@@ -882,6 +884,38 @@ static int pcsc_initiator_transceive_bytes(struct nfc_device *pnd, const uint8_t + return resp_len; + } + ++static int ++pcsc_initiator_poll_target(struct nfc_device *pnd, ++ const nfc_modulation *pnmModulations, const size_t szModulations, ++ const uint8_t uiPollNr, const uint8_t uiPeriod, ++ nfc_target *pnt) ++{ ++ static int periodFactor = 150000; ++ int period = uiPeriod * periodFactor; ++ ++ if (pnd == NULL) ++ return 0; ++ ++ for (int j = 0; j < uiPollNr; j++) ++ { ++ for (unsigned int i = 0; i < szModulations; i++) ++ { ++ const nfc_modulation nm = pnmModulations[i]; ++ ++ nfc_target nt; ++ int res = pcsc_initiator_select_passive_target(pnd, nm, 0, 0, &nt); ++ if (res > 0 && pnt) ++ { ++ memcpy(pnt, &nt, sizeof(nfc_target)); ++ return res; ++ } ++ } ++ usleep(period); ++ } ++ ++ return 0; ++} ++ + static int pcsc_initiator_target_is_present(struct nfc_device *pnd, const nfc_target *pnt) + { + uint8_t atr[MAX_ATR_SIZE]; +@@ -938,7 +972,7 @@ static int pcsc_device_set_property_bool(struct nfc_device *pnd, const nfc_prope + case NP_ACTIVATE_FIELD: + if (bEnable == false) { + struct pcsc_data *data = pnd->driver_data; +- pcsc_reconnect(pnd, data->dwShareMode, data->ioCard.dwProtocol, SCARD_RESET_CARD); ++ pcsc_reconnect(pnd, data->dwShareMode, data->ioCard.dwProtocol, SCARD_LEAVE_CARD); + } + return NFC_SUCCESS; + default: +@@ -1053,7 +1087,7 @@ const struct nfc_driver pcsc_driver = { + .initiator_init = pcsc_initiator_init, + .initiator_init_secure_element = NULL, // No secure-element support + .initiator_select_passive_target = pcsc_initiator_select_passive_target, +- .initiator_poll_target = NULL, ++ .initiator_poll_target = pcsc_initiator_poll_target, + .initiator_select_dep_target = NULL, + .initiator_deselect_target = NULL, + .initiator_transceive_bytes = pcsc_initiator_transceive_bytes, diff --git a/scripts/mister/build/Dockerfile b/scripts/mister/build/Dockerfile index 02a1f0e5..00e5a051 100755 --- a/scripts/mister/build/Dockerfile +++ b/scripts/mister/build/Dockerfile @@ -12,15 +12,39 @@ RUN apt-get install -y ca-certificates openssl && \ # install go and app dependencies RUN apt-get install build-essential git curl wget ncurses-dev -y && \ apt-get install golang-doc/bullseye-backports golang-go/bullseye-backports golang-src/bullseye-backports golang/bullseye-backports -y +RUN mkdir /internal + +# install pcsc-lite and ccid dependencies +RUN apt-get install -y flex libusb-1.0-0-dev zlib1g-dev +# install custom version of pcsc-lite +RUN cd /internal && \ + wget https://pcsclite.apdu.fr/files/pcsc-lite-2.0.0.tar.bz2 && \ + tar xf pcsc-lite-2.0.0.tar.bz2 && \ + cd pcsc-lite-2.0.0 && \ + ./configure --disable-libsystemd --disable-libudev -enable-static && \ + make -j "$(nproc)" && \ + make install +# install custom version of ccid +RUN cd /internal && \ + wget https://ccid.apdu.fr/files/ccid-1.5.4.tar.bz2 && \ + tar xf ccid-1.5.4.tar.bz2 && \ + cd ccid-1.5.4 && \ + ./configure -enable-static && \ + make -j "$(nproc)" && \ + make install # install libnfc dependencies RUN apt-get install -y libusb-dev libtool autoconf automake -# install custom version of libnfc -RUN mkdir /internal && cd /internal && \ - git clone --depth 1 https://github.com/sam1902/libnfc && \ - cd libnfc && \ +RUN cd /internal && \ + git clone --depth 1 https://github.com/nfc-tools/libnfc.git +# apply patches +COPY patches/pcsc-initiator_poll_target.patch /internal/libnfc/pcsc-initiator_poll_target.patch +RUN cd /internal/libnfc && \ + patch -p1 < pcsc-initiator_poll_target.patch +# build and install libnfc +RUN cd /internal/libnfc && \ autoreconf -vis && \ - ./configure && \ + ./configure --with-drivers=all && \ make -j "$(nproc)" && \ make install diff --git a/scripts/mister/build/build.sh b/scripts/mister/build/build.sh index d8d0f1e8..b9ad3c85 100644 --- a/scripts/mister/build/build.sh +++ b/scripts/mister/build/build.sh @@ -1,5 +1,10 @@ #!/bin/bash -GO111MODULE=on GOPROXY=https://goproxy.io,direct CGO_ENABLED=1 CGO_LDFLAGS="-lnfc -lusb -lcurses" go build \ +export GO111MODULE=on +export GOPROXY=https://goproxy.io,direct +export CGO_ENABLED=1 +export CGO_LDFLAGS="-lpcsclite -lnfc -lusb -lcurses" + +go build \ --ldflags "-linkmode external -extldflags -static -s -w" \ -o _build/mister_arm/tapto.sh ./cmd/mister diff --git a/scripts/mister/build/patches/acr122u-fix.patch b/scripts/mister/build/patches/acr122u-fix.patch deleted file mode 100644 index 00cfcd98..00000000 --- a/scripts/mister/build/patches/acr122u-fix.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 27e26d8d1595cd83d9cb799fa85117593dc94783 Mon Sep 17 00:00:00 2001 -From: Samuel Prevost -Date: Sun, 23 Aug 2020 13:51:36 +0200 -Subject: [PATCH] Fixes error libnfc.driver.acr122_usb Invalid - RDR_to_PC_DataBlock frame - ---- - libnfc/drivers/acr122_usb.c | 18 +++++++++++++++--- - 1 file changed, 15 insertions(+), 3 deletions(-) - -diff --git a/libnfc/drivers/acr122_usb.c b/libnfc/drivers/acr122_usb.c -index 17ae5fba..640d617f 100644 ---- a/libnfc/drivers/acr122_usb.c -+++ b/libnfc/drivers/acr122_usb.c -@@ -612,6 +612,7 @@ acr122_usb_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, co - - uint8_t attempted_response = RDR_to_PC_DataBlock; - size_t len; -+ int error, status; - - if (res == NFC_ETIMEOUT) { - if (DRIVER_DATA(pnd)->abort_flag) { -@@ -623,7 +624,7 @@ acr122_usb_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, co - goto read; - } - } -- if (res < 12) { -+ if (res < 10) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Invalid RDR_to_PC_DataBlock frame"); - // try to interrupt current device state - acr122_usb_ack(pnd); -@@ -638,6 +639,17 @@ acr122_usb_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, co - offset++; - - len = abtRxBuf[offset++]; -+ status = abtRxBuf[7]; -+ error = abtRxBuf[8]; -+ if (len == 0 && error == 0xFE) { // ICC_MUTE; XXX check for more errors -+ // Do not check status; my ACR122U seemingly has status=0 in this case, -+ // even though the spec says it should have had bmCommandStatus=1 -+ // and bmICCStatus=1. -+ log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "Command timed out"); -+ pnd->last_error = NFC_ETIMEOUT; -+ return pnd->last_error; -+ } -+ - if (!((len > 1) && (abtRxBuf[10] == 0xd5))) { // In case we didn't get an immediate answer: - if (len != 2) { - log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Wrong reply"); -@@ -666,7 +678,7 @@ acr122_usb_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, co - goto read; // FIXME May cause some trouble on Touchatag, right ? - } - } -- if (res < 12) { -+ if (res < 10) { - // try to interrupt current device state - acr122_usb_ack(pnd); - pnd->last_error = NFC_EIO; -@@ -705,7 +717,7 @@ acr122_usb_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, co - - // Skip CCID remaining bytes - offset += 2; // bSlot and bSeq are not used -- offset += 2; // XXX bStatus and bError should maybe checked ? -+ offset += 2; // bStatus and bError is partially checked - offset += 1; // bRFU should be 0x00 - - // TFI + PD0 (CC+1) \ No newline at end of file diff --git a/scripts/mister/build/patches/pcsc-initiator_poll_target.patch b/scripts/mister/build/patches/pcsc-initiator_poll_target.patch new file mode 100644 index 00000000..e8b76f8d --- /dev/null +++ b/scripts/mister/build/patches/pcsc-initiator_poll_target.patch @@ -0,0 +1,90 @@ +From 1e5cd05357b11381f5505f345afa4892804986f7 Mon Sep 17 00:00:00 2001 +From: Roberto Jung Drebes +Date: Wed, 29 May 2024 15:54:42 -0400 +Subject: [PATCH] initiator_poll_target for PCSC + +--- + libnfc/drivers/pcsc.c | 42 ++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 38 insertions(+), 4 deletions(-) + +diff --git a/libnfc/drivers/pcsc.c b/libnfc/drivers/pcsc.c +index 106d99ac..0bae4ed8 100644 +--- a/libnfc/drivers/pcsc.c ++++ b/libnfc/drivers/pcsc.c +@@ -176,7 +176,8 @@ static int pcsc_get_status(struct nfc_device *pnd, int *target_present, uint8_t + + data->last_error = SCardStatus(data->hCard, NULL, &reader_len, &state, &protocol, atr, &dw_atr_len); + if (data->last_error != SCARD_S_SUCCESS +- && data->last_error != SCARD_W_RESET_CARD) { ++ && data->last_error != SCARD_W_RESET_CARD ++ && data->last_error != SCARD_W_REMOVED_CARD) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Get status failed"); + return NFC_EIO; + } +@@ -193,7 +194,8 @@ static int pcsc_reconnect(struct nfc_device *pnd, DWORD share_mode, DWORD protoc + + data->last_error = SCardReconnect(data->hCard, share_mode, protocol, disposition, &data->ioCard.dwProtocol); + if (data->last_error != SCARD_S_SUCCESS +- && data->last_error != SCARD_W_RESET_CARD) { ++ && data->last_error != SCARD_W_RESET_CARD ++ && data->last_error != SCARD_E_NO_SMARTCARD) { + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Reconnect failed"); + return NFC_EIO; + } +@@ -882,6 +884,38 @@ static int pcsc_initiator_transceive_bytes(struct nfc_device *pnd, const uint8_t + return resp_len; + } + ++static int ++pcsc_initiator_poll_target(struct nfc_device *pnd, ++ const nfc_modulation *pnmModulations, const size_t szModulations, ++ const uint8_t uiPollNr, const uint8_t uiPeriod, ++ nfc_target *pnt) ++{ ++ static int periodFactor = 150000; ++ int period = uiPeriod * periodFactor; ++ ++ if (pnd == NULL) ++ return 0; ++ ++ for (int j = 0; j < uiPollNr; j++) ++ { ++ for (unsigned int i = 0; i < szModulations; i++) ++ { ++ const nfc_modulation nm = pnmModulations[i]; ++ ++ nfc_target nt; ++ int res = pcsc_initiator_select_passive_target(pnd, nm, 0, 0, &nt); ++ if (res > 0 && pnt) ++ { ++ memcpy(pnt, &nt, sizeof(nfc_target)); ++ return res; ++ } ++ } ++ usleep(period); ++ } ++ ++ return 0; ++} ++ + static int pcsc_initiator_target_is_present(struct nfc_device *pnd, const nfc_target *pnt) + { + uint8_t atr[MAX_ATR_SIZE]; +@@ -938,7 +972,7 @@ static int pcsc_device_set_property_bool(struct nfc_device *pnd, const nfc_prope + case NP_ACTIVATE_FIELD: + if (bEnable == false) { + struct pcsc_data *data = pnd->driver_data; +- pcsc_reconnect(pnd, data->dwShareMode, data->ioCard.dwProtocol, SCARD_RESET_CARD); ++ pcsc_reconnect(pnd, data->dwShareMode, data->ioCard.dwProtocol, SCARD_LEAVE_CARD); + } + return NFC_SUCCESS; + default: +@@ -1053,7 +1087,7 @@ const struct nfc_driver pcsc_driver = { + .initiator_init = pcsc_initiator_init, + .initiator_init_secure_element = NULL, // No secure-element support + .initiator_select_passive_target = pcsc_initiator_select_passive_target, +- .initiator_poll_target = NULL, ++ .initiator_poll_target = pcsc_initiator_poll_target, + .initiator_select_dep_target = NULL, + .initiator_deselect_target = NULL, + .initiator_transceive_bytes = pcsc_initiator_transceive_bytes, diff --git a/scripts/mister/build/pcsc-lite.sh b/scripts/mister/build/pcsc-lite.sh new file mode 100644 index 00000000..59bf71ec --- /dev/null +++ b/scripts/mister/build/pcsc-lite.sh @@ -0,0 +1,28 @@ +#! /bin/bash + +# if [ ! -d pcsc-lite-2.0.0 ]; then +# wget https://pcsclite.apdu.fr/files/pcsc-lite-2.0.0.tar.bz2 +# tar xf pcsc-lite-2.0.0.tar.bz2 +# fi + +# cd pcsc-lite-2.0.0 || exit + +# ./configure --disable-libsystemd --disable-libudev -enable-static +# make -j "$(nproc)" + +cp /usr/local/sbin/pcscd . + +# cd .. + +# if [ ! -d ccid-1.5.4 ]; then +# wget https://ccid.apdu.fr/files/ccid-1.5.4.tar.bz2 +# tar xf ccid-1.5.4.tar.bz2 +# fi + +# cd ccid-1.5.4 || exit + +# ./configure --enable-static +# make -j "$(nproc)" +# make install + +cp -r /usr/local/lib/pcsc/drivers .