1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2019, Joyent, Inc. 14 */ 15 16 /* 17 * Open a YubiKey class device and get the basic information applet 18 * through an APDU while using poll(2) to check device readyness. 19 */ 20 21 #include <err.h> 22 #include <stdlib.h> 23 #include <sys/types.h> 24 #include <sys/stat.h> 25 #include <fcntl.h> 26 #include <strings.h> 27 #include <unistd.h> 28 #include <errno.h> 29 #include <poll.h> 30 31 #include <sys/usb/clients/ccid/uccid.h> 32 33 static const uint8_t yk_req[] = { 34 0x00, 0xa4, 0x04, 0x00, 0x07, 0xa0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x01 35 }; 36 37 int 38 main(int argc, char *argv[]) 39 { 40 int fd, ret; 41 struct pollfd pfds[1]; 42 uccid_cmd_txn_begin_t begin; 43 uint8_t buf[UCCID_APDU_SIZE_MAX]; 44 45 if (argc != 2) { 46 errx(EXIT_FAILURE, "missing required ccid path"); 47 } 48 49 if ((fd = open(argv[1], O_RDWR)) < 0) { 50 err(EXIT_FAILURE, "failed to open %s", argv[1]); 51 } 52 53 bzero(&begin, sizeof (begin)); 54 begin.uct_version = UCCID_CURRENT_VERSION; 55 if (ioctl(fd, UCCID_CMD_TXN_BEGIN, &begin) != 0) { 56 err(EXIT_FAILURE, "failed to issue begin ioctl"); 57 } 58 59 pfds[0].fd = fd; 60 pfds[0].events = POLLOUT | POLLIN | POLLRDNORM; 61 pfds[0].revents = 0; 62 63 ret = poll(pfds, 1, 0); 64 if (ret != 1) { 65 err(EXIT_FAILURE, "poll didn't return 1, returned %d " 66 "(errno %d)", ret, errno); 67 } 68 69 if ((pfds[0].revents & POLLOUT) != POLLOUT) { 70 err(EXIT_FAILURE, "expecting pollout, got %d", pfds[0].revents); 71 } 72 73 if ((ret = write(fd, yk_req, sizeof (yk_req))) < 0) { 74 err(EXIT_FAILURE, "failed to write data"); 75 } 76 77 pfds[0].revents = 0; 78 79 ret = poll(pfds, 1, -1); 80 if (ret != 1) { 81 err(EXIT_FAILURE, "poll didn't return 1, returned %d " 82 "(errno %d)", ret, errno); 83 } 84 85 if ((pfds[0].revents & (POLLIN | POLLRDNORM)) != 86 (POLLIN | POLLRDNORM)) { 87 err(EXIT_FAILURE, "expecting pollin|pollrdnorm, got %d", 88 pfds[0].revents); 89 } 90 91 if ((ret = read(fd, buf, sizeof (buf))) < 0) { 92 err(EXIT_FAILURE, "failed to read data"); 93 } 94 95 pfds[0].revents = 0; 96 97 ret = poll(pfds, 1, 0); 98 if (ret != 1) { 99 err(EXIT_FAILURE, "poll didn't return 1, returned %d " 100 "(errno %d)", ret, errno); 101 } 102 103 if ((pfds[0].revents & POLLOUT) != POLLOUT) { 104 err(EXIT_FAILURE, "expecting pollout, got %d", pfds[0].revents); 105 } 106 107 return (0); 108 } 109