10afa8e06SEd Maste /*
2*2ccfa855SEd Maste * Copyright (c) 2020-2022 Yubico AB. All rights reserved.
30afa8e06SEd Maste * Use of this source code is governed by a BSD-style
40afa8e06SEd Maste * license that can be found in the LICENSE file.
5*2ccfa855SEd Maste * SPDX-License-Identifier: BSD-2-Clause
60afa8e06SEd Maste */
70afa8e06SEd Maste
80afa8e06SEd Maste #include <sys/types.h>
90afa8e06SEd Maste #include <sys/uio.h>
100afa8e06SEd Maste #include <sys/socket.h>
110afa8e06SEd Maste
120afa8e06SEd Maste #include <linux/nfc.h>
130afa8e06SEd Maste
140afa8e06SEd Maste #include <errno.h>
150afa8e06SEd Maste #include <libudev.h>
160afa8e06SEd Maste #include <signal.h>
17f540a430SEd Maste #include <stdio.h>
18f540a430SEd Maste #include <string.h>
190afa8e06SEd Maste #include <unistd.h>
200afa8e06SEd Maste
210afa8e06SEd Maste #include "fido.h"
220afa8e06SEd Maste #include "fido/param.h"
230afa8e06SEd Maste #include "netlink.h"
240afa8e06SEd Maste #include "iso7816.h"
250afa8e06SEd Maste
260afa8e06SEd Maste struct nfc_linux {
270afa8e06SEd Maste int fd;
280afa8e06SEd Maste uint32_t dev;
290afa8e06SEd Maste uint32_t target;
300afa8e06SEd Maste sigset_t sigmask;
310afa8e06SEd Maste const sigset_t *sigmaskp;
320afa8e06SEd Maste struct fido_nl *nl;
330afa8e06SEd Maste };
340afa8e06SEd Maste
350afa8e06SEd Maste static char *
get_parent_attr(struct udev_device * dev,const char * subsystem,const char * devtype,const char * attr)360afa8e06SEd Maste get_parent_attr(struct udev_device *dev, const char *subsystem,
370afa8e06SEd Maste const char *devtype, const char *attr)
380afa8e06SEd Maste {
390afa8e06SEd Maste struct udev_device *parent;
400afa8e06SEd Maste const char *value;
410afa8e06SEd Maste
420afa8e06SEd Maste if ((parent = udev_device_get_parent_with_subsystem_devtype(dev,
430afa8e06SEd Maste subsystem, devtype)) == NULL || (value =
440afa8e06SEd Maste udev_device_get_sysattr_value(parent, attr)) == NULL)
45*2ccfa855SEd Maste return NULL;
460afa8e06SEd Maste
47*2ccfa855SEd Maste return strdup(value);
480afa8e06SEd Maste }
490afa8e06SEd Maste
500afa8e06SEd Maste static char *
get_usb_attr(struct udev_device * dev,const char * attr)510afa8e06SEd Maste get_usb_attr(struct udev_device *dev, const char *attr)
520afa8e06SEd Maste {
53*2ccfa855SEd Maste return get_parent_attr(dev, "usb", "usb_device", attr);
540afa8e06SEd Maste }
550afa8e06SEd Maste
560afa8e06SEd Maste static int
copy_info(fido_dev_info_t * di,struct udev * udev,struct udev_list_entry * udev_entry)570afa8e06SEd Maste copy_info(fido_dev_info_t *di, struct udev *udev,
580afa8e06SEd Maste struct udev_list_entry *udev_entry)
590afa8e06SEd Maste {
600afa8e06SEd Maste const char *name;
610afa8e06SEd Maste char *str;
620afa8e06SEd Maste struct udev_device *dev = NULL;
63*2ccfa855SEd Maste uint64_t id;
64*2ccfa855SEd Maste int ok = -1;
650afa8e06SEd Maste
660afa8e06SEd Maste memset(di, 0, sizeof(*di));
670afa8e06SEd Maste
680afa8e06SEd Maste if ((name = udev_list_entry_get_name(udev_entry)) == NULL ||
690afa8e06SEd Maste (dev = udev_device_new_from_syspath(udev, name)) == NULL)
700afa8e06SEd Maste goto fail;
71*2ccfa855SEd Maste if (asprintf(&di->path, "%s/%s", FIDO_NFC_PREFIX, name) == -1) {
72*2ccfa855SEd Maste di->path = NULL;
730afa8e06SEd Maste goto fail;
74*2ccfa855SEd Maste }
75*2ccfa855SEd Maste if (nfc_is_fido(di->path) == false) {
76*2ccfa855SEd Maste fido_log_debug("%s: nfc_is_fido: %s", __func__, di->path);
77*2ccfa855SEd Maste goto fail;
78*2ccfa855SEd Maste }
79f540a430SEd Maste if ((di->manufacturer = get_usb_attr(dev, "manufacturer")) == NULL)
80f540a430SEd Maste di->manufacturer = strdup("");
81f540a430SEd Maste if ((di->product = get_usb_attr(dev, "product")) == NULL)
82f540a430SEd Maste di->product = strdup("");
83f540a430SEd Maste if (di->manufacturer == NULL || di->product == NULL)
84f540a430SEd Maste goto fail;
850afa8e06SEd Maste /* XXX assumes USB for vendor/product info */
860afa8e06SEd Maste if ((str = get_usb_attr(dev, "idVendor")) != NULL &&
87*2ccfa855SEd Maste fido_to_uint64(str, 16, &id) == 0 && id <= UINT16_MAX)
880afa8e06SEd Maste di->vendor_id = (int16_t)id;
890afa8e06SEd Maste free(str);
900afa8e06SEd Maste if ((str = get_usb_attr(dev, "idProduct")) != NULL &&
91*2ccfa855SEd Maste fido_to_uint64(str, 16, &id) == 0 && id <= UINT16_MAX)
920afa8e06SEd Maste di->product_id = (int16_t)id;
930afa8e06SEd Maste free(str);
940afa8e06SEd Maste
950afa8e06SEd Maste ok = 0;
960afa8e06SEd Maste fail:
970afa8e06SEd Maste if (dev != NULL)
980afa8e06SEd Maste udev_device_unref(dev);
990afa8e06SEd Maste
1000afa8e06SEd Maste if (ok < 0) {
1010afa8e06SEd Maste free(di->path);
1020afa8e06SEd Maste free(di->manufacturer);
1030afa8e06SEd Maste free(di->product);
1040afa8e06SEd Maste explicit_bzero(di, sizeof(*di));
1050afa8e06SEd Maste }
1060afa8e06SEd Maste
107*2ccfa855SEd Maste return ok;
1080afa8e06SEd Maste }
1090afa8e06SEd Maste
1100afa8e06SEd Maste static int
sysnum_from_syspath(const char * path)1110afa8e06SEd Maste sysnum_from_syspath(const char *path)
1120afa8e06SEd Maste {
1130afa8e06SEd Maste struct udev *udev = NULL;
1140afa8e06SEd Maste struct udev_device *dev = NULL;
1150afa8e06SEd Maste const char *str;
116*2ccfa855SEd Maste uint64_t idx64;
117*2ccfa855SEd Maste int idx = -1;
1180afa8e06SEd Maste
119*2ccfa855SEd Maste if ((udev = udev_new()) != NULL &&
120*2ccfa855SEd Maste (dev = udev_device_new_from_syspath(udev, path)) != NULL &&
121*2ccfa855SEd Maste (str = udev_device_get_sysnum(dev)) != NULL &&
122*2ccfa855SEd Maste fido_to_uint64(str, 10, &idx64) == 0 && idx64 < INT_MAX)
123*2ccfa855SEd Maste idx = (int)idx64;
1240afa8e06SEd Maste
1250afa8e06SEd Maste if (dev != NULL)
1260afa8e06SEd Maste udev_device_unref(dev);
1270afa8e06SEd Maste if (udev != NULL)
1280afa8e06SEd Maste udev_unref(udev);
1290afa8e06SEd Maste
130*2ccfa855SEd Maste return idx;
1310afa8e06SEd Maste }
1320afa8e06SEd Maste
1330afa8e06SEd Maste int
fido_nfc_manifest(fido_dev_info_t * devlist,size_t ilen,size_t * olen)1340afa8e06SEd Maste fido_nfc_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
1350afa8e06SEd Maste {
1360afa8e06SEd Maste struct udev *udev = NULL;
1370afa8e06SEd Maste struct udev_enumerate *udev_enum = NULL;
1380afa8e06SEd Maste struct udev_list_entry *udev_list;
1390afa8e06SEd Maste struct udev_list_entry *udev_entry;
1400afa8e06SEd Maste int r = FIDO_ERR_INTERNAL;
1410afa8e06SEd Maste
1420afa8e06SEd Maste *olen = 0;
1430afa8e06SEd Maste
1440afa8e06SEd Maste if (ilen == 0)
145*2ccfa855SEd Maste return FIDO_OK;
1460afa8e06SEd Maste
1470afa8e06SEd Maste if (devlist == NULL)
148*2ccfa855SEd Maste return FIDO_ERR_INVALID_ARGUMENT;
1490afa8e06SEd Maste
1500afa8e06SEd Maste if ((udev = udev_new()) == NULL ||
1510afa8e06SEd Maste (udev_enum = udev_enumerate_new(udev)) == NULL)
1520afa8e06SEd Maste goto fail;
1530afa8e06SEd Maste
1540afa8e06SEd Maste if (udev_enumerate_add_match_subsystem(udev_enum, "nfc") < 0 ||
1550afa8e06SEd Maste udev_enumerate_scan_devices(udev_enum) < 0)
1560afa8e06SEd Maste goto fail;
1570afa8e06SEd Maste
1580afa8e06SEd Maste if ((udev_list = udev_enumerate_get_list_entry(udev_enum)) == NULL) {
1590afa8e06SEd Maste r = FIDO_OK; /* zero nfc devices */
1600afa8e06SEd Maste goto fail;
1610afa8e06SEd Maste }
1620afa8e06SEd Maste
1630afa8e06SEd Maste udev_list_entry_foreach(udev_entry, udev_list) {
1640afa8e06SEd Maste if (copy_info(&devlist[*olen], udev, udev_entry) == 0) {
1650afa8e06SEd Maste devlist[*olen].io = (fido_dev_io_t) {
1660afa8e06SEd Maste fido_nfc_open,
1670afa8e06SEd Maste fido_nfc_close,
1680afa8e06SEd Maste fido_nfc_read,
1690afa8e06SEd Maste fido_nfc_write,
1700afa8e06SEd Maste };
1710afa8e06SEd Maste devlist[*olen].transport = (fido_dev_transport_t) {
1720afa8e06SEd Maste fido_nfc_rx,
1730afa8e06SEd Maste fido_nfc_tx,
1740afa8e06SEd Maste };
1750afa8e06SEd Maste if (++(*olen) == ilen)
1760afa8e06SEd Maste break;
1770afa8e06SEd Maste }
1780afa8e06SEd Maste }
1790afa8e06SEd Maste
1800afa8e06SEd Maste r = FIDO_OK;
1810afa8e06SEd Maste fail:
1820afa8e06SEd Maste if (udev_enum != NULL)
1830afa8e06SEd Maste udev_enumerate_unref(udev_enum);
1840afa8e06SEd Maste if (udev != NULL)
1850afa8e06SEd Maste udev_unref(udev);
1860afa8e06SEd Maste
187*2ccfa855SEd Maste return r;
1880afa8e06SEd Maste }
1890afa8e06SEd Maste
1900afa8e06SEd Maste static int
nfc_target_connect(struct nfc_linux * ctx)1910afa8e06SEd Maste nfc_target_connect(struct nfc_linux *ctx)
1920afa8e06SEd Maste {
1930afa8e06SEd Maste struct sockaddr_nfc sa;
1940afa8e06SEd Maste
1950afa8e06SEd Maste memset(&sa, 0, sizeof(sa));
1960afa8e06SEd Maste sa.sa_family = AF_NFC;
1970afa8e06SEd Maste sa.dev_idx = ctx->dev;
1980afa8e06SEd Maste sa.target_idx = ctx->target;
1990afa8e06SEd Maste sa.nfc_protocol = NFC_PROTO_ISO14443;
2000afa8e06SEd Maste
2010afa8e06SEd Maste if ((ctx->fd = socket(AF_NFC, SOCK_SEQPACKET | SOCK_CLOEXEC,
2020afa8e06SEd Maste NFC_SOCKPROTO_RAW)) == -1) {
2030afa8e06SEd Maste fido_log_error(errno, "%s: socket", __func__);
204*2ccfa855SEd Maste return -1;
2050afa8e06SEd Maste }
2060afa8e06SEd Maste if (connect(ctx->fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
2070afa8e06SEd Maste fido_log_error(errno, "%s: connect", __func__);
2080afa8e06SEd Maste if (close(ctx->fd) == -1)
2090afa8e06SEd Maste fido_log_error(errno, "%s: close", __func__);
2100afa8e06SEd Maste ctx->fd = -1;
211*2ccfa855SEd Maste return -1;
2120afa8e06SEd Maste }
2130afa8e06SEd Maste
214*2ccfa855SEd Maste return 0;
2150afa8e06SEd Maste }
2160afa8e06SEd Maste
2170afa8e06SEd Maste static void
nfc_free(struct nfc_linux ** ctx_p)2180afa8e06SEd Maste nfc_free(struct nfc_linux **ctx_p)
2190afa8e06SEd Maste {
2200afa8e06SEd Maste struct nfc_linux *ctx;
2210afa8e06SEd Maste
2220afa8e06SEd Maste if (ctx_p == NULL || (ctx = *ctx_p) == NULL)
2230afa8e06SEd Maste return;
2240afa8e06SEd Maste if (ctx->fd != -1 && close(ctx->fd) == -1)
2250afa8e06SEd Maste fido_log_error(errno, "%s: close", __func__);
2260afa8e06SEd Maste if (ctx->nl != NULL)
2270afa8e06SEd Maste fido_nl_free(&ctx->nl);
2280afa8e06SEd Maste
2290afa8e06SEd Maste free(ctx);
2300afa8e06SEd Maste *ctx_p = NULL;
2310afa8e06SEd Maste }
2320afa8e06SEd Maste
2330afa8e06SEd Maste static struct nfc_linux *
nfc_new(uint32_t dev)2340afa8e06SEd Maste nfc_new(uint32_t dev)
2350afa8e06SEd Maste {
2360afa8e06SEd Maste struct nfc_linux *ctx;
2370afa8e06SEd Maste
2380afa8e06SEd Maste if ((ctx = calloc(1, sizeof(*ctx))) == NULL ||
2390afa8e06SEd Maste (ctx->nl = fido_nl_new()) == NULL) {
2400afa8e06SEd Maste nfc_free(&ctx);
241*2ccfa855SEd Maste return NULL;
2420afa8e06SEd Maste }
2430afa8e06SEd Maste
2440afa8e06SEd Maste ctx->fd = -1;
2450afa8e06SEd Maste ctx->dev = dev;
2460afa8e06SEd Maste
247*2ccfa855SEd Maste return ctx;
2480afa8e06SEd Maste }
2490afa8e06SEd Maste
2500afa8e06SEd Maste void *
fido_nfc_open(const char * path)2510afa8e06SEd Maste fido_nfc_open(const char *path)
2520afa8e06SEd Maste {
2530afa8e06SEd Maste struct nfc_linux *ctx = NULL;
2540afa8e06SEd Maste int idx;
2550afa8e06SEd Maste
256f540a430SEd Maste if (strncmp(path, FIDO_NFC_PREFIX, strlen(FIDO_NFC_PREFIX)) != 0) {
257f540a430SEd Maste fido_log_debug("%s: bad prefix", __func__);
258f540a430SEd Maste goto fail;
259f540a430SEd Maste }
260f540a430SEd Maste if ((idx = sysnum_from_syspath(path + strlen(FIDO_NFC_PREFIX))) < 0 ||
2610afa8e06SEd Maste (ctx = nfc_new((uint32_t)idx)) == NULL) {
2620afa8e06SEd Maste fido_log_debug("%s: nfc_new", __func__);
2630afa8e06SEd Maste goto fail;
2640afa8e06SEd Maste }
2650afa8e06SEd Maste if (fido_nl_power_nfc(ctx->nl, ctx->dev) < 0 ||
2660afa8e06SEd Maste fido_nl_get_nfc_target(ctx->nl, ctx->dev, &ctx->target) < 0 ||
2670afa8e06SEd Maste nfc_target_connect(ctx) < 0) {
2680afa8e06SEd Maste fido_log_debug("%s: netlink", __func__);
2690afa8e06SEd Maste goto fail;
2700afa8e06SEd Maste }
2710afa8e06SEd Maste
272*2ccfa855SEd Maste return ctx;
2730afa8e06SEd Maste fail:
2740afa8e06SEd Maste nfc_free(&ctx);
275*2ccfa855SEd Maste return NULL;
2760afa8e06SEd Maste }
2770afa8e06SEd Maste
2780afa8e06SEd Maste void
fido_nfc_close(void * handle)2790afa8e06SEd Maste fido_nfc_close(void *handle)
2800afa8e06SEd Maste {
2810afa8e06SEd Maste struct nfc_linux *ctx = handle;
2820afa8e06SEd Maste
2830afa8e06SEd Maste nfc_free(&ctx);
2840afa8e06SEd Maste }
2850afa8e06SEd Maste
2860afa8e06SEd Maste int
fido_nfc_set_sigmask(void * handle,const fido_sigset_t * sigmask)2870afa8e06SEd Maste fido_nfc_set_sigmask(void *handle, const fido_sigset_t *sigmask)
2880afa8e06SEd Maste {
2890afa8e06SEd Maste struct nfc_linux *ctx = handle;
2900afa8e06SEd Maste
2910afa8e06SEd Maste ctx->sigmask = *sigmask;
2920afa8e06SEd Maste ctx->sigmaskp = &ctx->sigmask;
2930afa8e06SEd Maste
294*2ccfa855SEd Maste return FIDO_OK;
2950afa8e06SEd Maste }
2960afa8e06SEd Maste
2970afa8e06SEd Maste int
fido_nfc_read(void * handle,unsigned char * buf,size_t len,int ms)2980afa8e06SEd Maste fido_nfc_read(void *handle, unsigned char *buf, size_t len, int ms)
2990afa8e06SEd Maste {
3000afa8e06SEd Maste struct nfc_linux *ctx = handle;
3010afa8e06SEd Maste struct iovec iov[2];
3020afa8e06SEd Maste uint8_t preamble;
3030afa8e06SEd Maste ssize_t r;
3040afa8e06SEd Maste
3050afa8e06SEd Maste memset(&iov, 0, sizeof(iov));
3060afa8e06SEd Maste iov[0].iov_base = &preamble;
3070afa8e06SEd Maste iov[0].iov_len = sizeof(preamble);
3080afa8e06SEd Maste iov[1].iov_base = buf;
3090afa8e06SEd Maste iov[1].iov_len = len;
3100afa8e06SEd Maste
3110afa8e06SEd Maste if (fido_hid_unix_wait(ctx->fd, ms, ctx->sigmaskp) < 0) {
3120afa8e06SEd Maste fido_log_debug("%s: fido_hid_unix_wait", __func__);
313*2ccfa855SEd Maste return -1;
3140afa8e06SEd Maste }
3150afa8e06SEd Maste if ((r = readv(ctx->fd, iov, nitems(iov))) == -1) {
3160afa8e06SEd Maste fido_log_error(errno, "%s: read", __func__);
317*2ccfa855SEd Maste return -1;
3180afa8e06SEd Maste }
3190afa8e06SEd Maste if (r < 1) {
3200afa8e06SEd Maste fido_log_debug("%s: %zd < 1", __func__, r);
321*2ccfa855SEd Maste return -1;
3220afa8e06SEd Maste }
3230afa8e06SEd Maste if (preamble != 0x00) {
3240afa8e06SEd Maste fido_log_debug("%s: preamble", __func__);
325*2ccfa855SEd Maste return -1;
3260afa8e06SEd Maste }
3270afa8e06SEd Maste
3280afa8e06SEd Maste r--;
3290afa8e06SEd Maste fido_log_xxd(buf, (size_t)r, "%s", __func__);
3300afa8e06SEd Maste
331*2ccfa855SEd Maste return (int)r;
3320afa8e06SEd Maste }
3330afa8e06SEd Maste
3340afa8e06SEd Maste int
fido_nfc_write(void * handle,const unsigned char * buf,size_t len)3350afa8e06SEd Maste fido_nfc_write(void *handle, const unsigned char *buf, size_t len)
3360afa8e06SEd Maste {
3370afa8e06SEd Maste struct nfc_linux *ctx = handle;
3380afa8e06SEd Maste ssize_t r;
3390afa8e06SEd Maste
3400afa8e06SEd Maste fido_log_xxd(buf, len, "%s", __func__);
3410afa8e06SEd Maste
3420afa8e06SEd Maste if (len > INT_MAX) {
3430afa8e06SEd Maste fido_log_debug("%s: len", __func__);
344*2ccfa855SEd Maste return -1;
3450afa8e06SEd Maste }
3460afa8e06SEd Maste if ((r = write(ctx->fd, buf, len)) == -1) {
3470afa8e06SEd Maste fido_log_error(errno, "%s: write", __func__);
348*2ccfa855SEd Maste return -1;
3490afa8e06SEd Maste }
3500afa8e06SEd Maste if (r < 0 || (size_t)r != len) {
3510afa8e06SEd Maste fido_log_debug("%s: %zd != %zu", __func__, r, len);
352*2ccfa855SEd Maste return -1;
3530afa8e06SEd Maste }
3540afa8e06SEd Maste
355*2ccfa855SEd Maste return (int)r;
3560afa8e06SEd Maste }
357