diff options
Diffstat (limited to 'usr/src/test/os-tests')
19 files changed, 2121 insertions, 0 deletions
diff --git a/usr/src/test/os-tests/runfiles/default.run b/usr/src/test/os-tests/runfiles/default.run index 9489c2faf6..940b9bf97a 100644 --- a/usr/src/test/os-tests/runfiles/default.run +++ b/usr/src/test/os-tests/runfiles/default.run @@ -87,3 +87,11 @@ tests = ['ldt', 'badseg'] [/opt/os-tests/tests/imc_test] arch = i86pc + +# +# Except atrparse all tests require special hardware (CCID YubiKey) to run, +# hence they aren't included in the default runfile. +# +[/opt/os-tests/tests/uccid] +arch = i86pc +tests = ['atrparse'] diff --git a/usr/src/test/os-tests/tests/Makefile b/usr/src/test/os-tests/tests/Makefile index e3e756c946..3107af540c 100644 --- a/usr/src/test/os-tests/tests/Makefile +++ b/usr/src/test/os-tests/tests/Makefile @@ -29,6 +29,7 @@ SUBDIRS = \ stress \ timer \ tmpfs \ + uccid \ $(SUBDIRS_$(MACH)) PROGS = \ diff --git a/usr/src/test/os-tests/tests/uccid/Makefile b/usr/src/test/os-tests/tests/uccid/Makefile new file mode 100644 index 0000000000..55fd96bfd5 --- /dev/null +++ b/usr/src/test/os-tests/tests/uccid/Makefile @@ -0,0 +1,82 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2019, Joyent, Inc. +# + +include $(SRC)/Makefile.master + +ROOTOPTPKG = $(ROOT)/opt/os-tests +TESTDIR = $(ROOTOPTPKG)/tests/uccid + +PROGS = \ + atrparse \ + excl-basic \ + excl-badread \ + excl-close \ + excl-loop \ + excl-nonblock \ + excl-reset \ + modify \ + notxn-poll \ + status \ + pollin \ + pollout \ + txn-pollerr \ + yk \ + yk-poll \ + yk-readonly + +COMMON_OBJS = \ + atr.o + +atrparse := EXTRA_OBJS = $(COMMON_OBJS) + +include $(SRC)/cmd/Makefile.cmd +include $(SRC)/test/Makefile.com + +CMDS = $(PROGS:%=$(TESTDIR)/%) +$(CMDS) := FILEMODE = 0555 + +CPPFLAGS += -D_REENTRANT -I$(SRC)/common/ccid/ + +all: $(PROGS) + +install: all $(CMDS) + +clobber: clean + -$(RM) $(PROGS) + +clean: + -$(RM) *.o + +$(PROGS): $(COMMON_OBJS) + +$(CMDS): $(TESTDIR) $(PROGS) + +$(TESTDIR): + $(INS.dir) + +$(TESTDIR)/%: % + $(INS.file) + +%.o: $(SRC)/common/ccid/%.c + $(COMPILE.c) -o $@ -c $< + $(POST_PROCESS_O) + +%.o: %.c + $(COMPILE.c) -o $@ -c $< + $(POST_PROCESS_O) + +%: %.o + $(LINK.c) -o $@ $< $(EXTRA_OBJS) + $(POST_PROCESS) diff --git a/usr/src/test/os-tests/tests/uccid/atrparse.c b/usr/src/test/os-tests/tests/uccid/atrparse.c new file mode 100644 index 0000000000..f14bbfd34d --- /dev/null +++ b/usr/src/test/os-tests/tests/uccid/atrparse.c @@ -0,0 +1,731 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2019, Joyent, Inc. + */ + +/* + * Verify that we can parse various forms of ATR data and detect invalid data. + */ + +#include <err.h> +#include <stdlib.h> + +#include <atr.h> + +typedef struct atr_vals { +} atr_vals_t; + +typedef struct atr_test { + const char *ar_test; + uint8_t ar_len; + uint8_t ar_buf[64]; + atr_parsecode_t ar_retval; + /* Everything after this is data from the ATR */ + atr_protocol_t ar_sup; + atr_protocol_t ar_def; + boolean_t ar_neg; + uint8_t ar_fi; + uint8_t ar_di; + atr_convention_t ar_conv; + uint8_t ar_guard; + atr_clock_stop_t ar_stop; + /* These will be checked based on sup prot */ + uint8_t ar_t0_wi; + atr_t1_checksum_t ar_t1_cksum; + uint8_t ar_t1_bwi; + uint8_t ar_t1_cwi; + uint8_t ar_t1_ifsc; +} atr_test_t; + +atr_test_t atr_tests[] = { + { "zero-length data", 0, { 0 }, ATR_CODE_TOO_SHORT }, + { "No T0", 1, { 0x3f }, ATR_CODE_TOO_SHORT }, + { "Too much data", 34, { 0 }, ATR_CODE_TOO_LONG }, + { "Overrun T0 (1)", 2, { 0x3b, 0x10 }, ATR_CODE_OVERRUN }, + { "Overrun T0 (2)", 2, { 0x3b, 0x80 }, ATR_CODE_OVERRUN }, + { "Overrun T0 (3)", 2, { 0x3b, 0x01 }, ATR_CODE_OVERRUN }, + { "Overrun T0 (4)", 2, { 0x3b, 0x11 }, ATR_CODE_OVERRUN }, + { "Overrun T0 (5)", 2, { 0x3b, 0xff }, ATR_CODE_OVERRUN }, + { "Overrun TD1", 3, { 0x3b, 0x80, 0x10 }, ATR_CODE_OVERRUN }, + { "Overrun TD2", 4, { 0x3b, 0x80, 0x80, 0x10 }, ATR_CODE_OVERRUN }, + { "Overrun TD", 33, { 0x3b, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80 }, ATR_CODE_OVERRUN }, + { "T0 w/ T=15 and no cksum", 5, { 0x3b, 0x80, 0x80, 0x1f, 0x00 }, + ATR_CODE_OVERRUN }, + { "Bad TS (1)", 2, { 0x3a, 0x00 }, ATR_CODE_INVALID_TS }, + { "Bad TS (2)", 2, { 0xff, 0x00 }, ATR_CODE_INVALID_TS }, + { "T0 w/ T=15 and bad cksum", 6, { 0x3b, 0x80, 0x80, 0x1f, 0x00, 0x00 }, + ATR_CODE_CHECKSUM_ERROR }, + { "T0 w/ T=15 and bad cksum (make sure no TS)", 6, + { 0x3b, 0x80, 0x80, 0x1f, 0x00, 0x24 }, + ATR_CODE_CHECKSUM_ERROR }, + { "T=15 in TD1", 4, { 0x3b, 0x80, 0x0f, 0x8f }, ATR_CODE_INVALID_TD1 }, + { + .ar_test = "Minimal T0 Direct", + .ar_len = 2, + .ar_buf = { 0x3b, 0x00 }, + .ar_sup = ATR_P_T0, + .ar_def = ATR_P_T0, + .ar_neg = B_TRUE, + .ar_fi = 1, + .ar_di = 1, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t0_wi = 10, + }, { + .ar_test = "Minimal T0 Inverse", + .ar_len = 2, + .ar_buf = { 0x3f, 0x00 }, + .ar_sup = ATR_P_T0, + .ar_def = ATR_P_T0, + .ar_neg = B_TRUE, + .ar_fi = 1, + .ar_di = 1, + .ar_conv = ATR_CONVENTION_INVERSE, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t0_wi = 10, + }, { + .ar_test = "T0 Fi/Di (1)", + .ar_len = 3, + .ar_buf = { 0x3b, 0x10, 0x24 }, + .ar_sup = ATR_P_T0, + .ar_def = ATR_P_T0, + .ar_neg = B_TRUE, + .ar_fi = 2, + .ar_di = 4, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t0_wi = 10, + }, { + .ar_test = "T0 Fi/Di (2)", + .ar_len = 3, + .ar_buf = { 0x3b, 0x10, 0x93 }, + .ar_sup = ATR_P_T0, + .ar_def = ATR_P_T0, + .ar_neg = B_TRUE, + .ar_fi = 9, + .ar_di = 3, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t0_wi = 10, + }, { + .ar_test = "T0 Ignore deprecated TB1", + .ar_len = 3, + .ar_buf = { 0x3b, 0x20, 0x42 }, + .ar_sup = ATR_P_T0, + .ar_def = ATR_P_T0, + .ar_neg = B_TRUE, + .ar_fi = 1, + .ar_di = 1, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t0_wi = 10, + }, { + .ar_test = "T0 Ignore deprecated TB2", + .ar_len = 4, + .ar_buf = { 0x3b, 0x80, 0x20, 0x42 }, + .ar_sup = ATR_P_T0, + .ar_def = ATR_P_T0, + .ar_neg = B_TRUE, + .ar_fi = 1, + .ar_di = 1, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t0_wi = 10, + }, { + .ar_test = "T0 Ignore deprecated TB1/TB2", + .ar_len = 5, + .ar_buf = { 0x3b, 0xa0, 0x55, 0x20, 0x42 }, + .ar_sup = ATR_P_T0, + .ar_def = ATR_P_T0, + .ar_neg = B_TRUE, + .ar_fi = 1, + .ar_di = 1, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t0_wi = 10, + }, { + .ar_test = "T0 Encode TC1", + .ar_len = 3, + .ar_buf = { 0x3b, 0x40, 0x23 }, + .ar_sup = ATR_P_T0, + .ar_def = ATR_P_T0, + .ar_neg = B_TRUE, + .ar_fi = 1, + .ar_di = 1, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0x23, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t0_wi = 10, + }, { + .ar_test = "T0 TA2 says neg", + .ar_len = 4, + .ar_buf = { 0x3b, 0x80, 0x10, 0x00 }, + .ar_sup = ATR_P_T0, + .ar_def = ATR_P_T0, + .ar_neg = B_TRUE, + .ar_fi = 1, + .ar_di = 1, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t0_wi = 10, + }, { + .ar_test = "T0 TA2 says not neg", + .ar_len = 4, + .ar_buf = { 0x3b, 0x80, 0x10, 0x80 }, + .ar_sup = ATR_P_T0, + .ar_def = ATR_P_T0, + .ar_neg = B_FALSE, + .ar_fi = 1, + .ar_di = 1, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t0_wi = 10, + }, { + .ar_test = "T0 TA2 says not neg, honor Fi/Di", + .ar_len = 5, + .ar_buf = { 0x3b, 0x90, 0x24, 0x10, 0x80 }, + .ar_sup = ATR_P_T0, + .ar_def = ATR_P_T0, + .ar_neg = B_FALSE, + .ar_fi = 2, + .ar_di = 4, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t0_wi = 10, + }, { + .ar_test = "T0 TA2 says not neg, don't honor Fi/Di", + .ar_len = 5, + .ar_buf = { 0x3b, 0x90, 0x24, 0x10, 0x90 }, + .ar_sup = ATR_P_T0, + .ar_def = ATR_P_T0, + .ar_neg = B_FALSE, + .ar_fi = 1, + .ar_di = 1, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t0_wi = 10, + }, { + .ar_test = "T0 TC2 set", + .ar_len = 4, + .ar_buf = { 0x3b, 0x80, 0x40, 0x35 }, + .ar_sup = ATR_P_T0, + .ar_def = ATR_P_T0, + .ar_neg = B_TRUE, + .ar_fi = 1, + .ar_di = 1, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t0_wi = 0x35, + }, { + .ar_test = "T0 T15 empty (requires checksum)", + .ar_len = 5, + .ar_buf = { 0x3b, 0x80, 0x80, 0x0f, 0x0f }, + .ar_sup = ATR_P_T0, + .ar_def = ATR_P_T0, + .ar_neg = B_TRUE, + .ar_fi = 1, + .ar_di = 1, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t0_wi = 10, + }, { + .ar_test = "T0 T15 Clock Stop (1)", + .ar_len = 6, + .ar_buf = { 0x3b, 0x80, 0x80, 0x1f, 0x07, 0x18 }, + .ar_sup = ATR_P_T0, + .ar_def = ATR_P_T0, + .ar_neg = B_TRUE, + .ar_fi = 1, + .ar_di = 1, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t0_wi = 10, + }, { + .ar_test = "T0 T15 Clock Stop (2)", + .ar_len = 6, + .ar_buf = { 0x3b, 0x80, 0x80, 0x1f, 0x47, 0x58 }, + .ar_sup = ATR_P_T0, + .ar_def = ATR_P_T0, + .ar_neg = B_TRUE, + .ar_fi = 1, + .ar_di = 1, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_LOW, + .ar_t0_wi = 10, + }, { + .ar_test = "T0 T15 Clock Stop (3)", + .ar_len = 6, + .ar_buf = { 0x3b, 0x80, 0x80, 0x1f, 0x87, 0x98 }, + .ar_sup = ATR_P_T0, + .ar_def = ATR_P_T0, + .ar_neg = B_TRUE, + .ar_fi = 1, + .ar_di = 1, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_HI, + .ar_t0_wi = 10, + }, { + .ar_test = "T0 T15 Clock Stop (4)", + .ar_len = 6, + .ar_buf = { 0x3b, 0x80, 0x80, 0x1f, 0xc7, 0xd8 }, + .ar_sup = ATR_P_T0, + .ar_def = ATR_P_T0, + .ar_neg = B_TRUE, + .ar_fi = 1, + .ar_di = 1, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_BOTH, + .ar_t0_wi = 10, + }, { + .ar_test = "T0 with random prots", + .ar_len = 7, + .ar_buf = { 0x3b, 0x80, 0x84, 0x85, 0x88, 0x0f, 0x06 }, + .ar_sup = ATR_P_T0, + /* + * This comes from the fact that TD1 is T=4 and that isn't + * supported in the system. + */ + .ar_def = ATR_P_NONE, + .ar_neg = B_TRUE, + .ar_fi = 1, + .ar_di = 1, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t0_wi = 10, + }, { + .ar_test = "Actual ATR (1, Yubikey4)", + .ar_len = 18, + .ar_buf = { 0x3b, 0xf8, 0x13, 0x00, 0x00, 0x81, 0x31, 0xfe, + 0x15, 0x59, 0x75, 0x62, 0x69, 0x6b, 0x65, 0x79, 0x34, + 0xd4 }, + .ar_sup = ATR_P_T1, + .ar_def = ATR_P_T1, + .ar_neg = B_TRUE, + .ar_fi = 1, + .ar_di = 3, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t1_cksum = ATR_T1_CHECKSUM_LRC, + .ar_t1_bwi = 1, + .ar_t1_cwi = 5, + .ar_t1_ifsc = 254 + }, { + .ar_test = "Actual ATR (2)", + .ar_len = 19, + .ar_buf = { 0x3b, 0xf9, 0x18, 0x00, 0x00, 0x81, 0x31, 0xfe, + 0x45, 0x4a, 0x32, 0x44, 0x30, 0x38, 0x31, 0x5f, 0x50, 0x56, + 0xb6 }, + .ar_sup = ATR_P_T1, + .ar_def = ATR_P_T1, + .ar_neg = B_TRUE, + .ar_fi = 1, + .ar_di = 8, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t1_cksum = ATR_T1_CHECKSUM_LRC, + .ar_t1_bwi = 4, + .ar_t1_cwi = 5, + .ar_t1_ifsc = 254 + }, { + .ar_test = "Actual ATR (3)", + .ar_len = 22, + .ar_buf = { 0x3b, 0xfc, 0x18, 0x00, 0x00, 0x81, 0x31, 0x80, + 0x45, 0x90, 0x67, 0x46, 0x4a, 0x00, 0x64, 0x16, 0x6, 0xf2, + 0x72, 0x7e, 0x00, 0xe0 }, + .ar_sup = ATR_P_T1, + .ar_def = ATR_P_T1, + .ar_neg = B_TRUE, + .ar_fi = 1, + .ar_di = 8, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t1_cksum = ATR_T1_CHECKSUM_LRC, + .ar_t1_bwi = 4, + .ar_t1_cwi = 5, + .ar_t1_ifsc = 128 + }, { + .ar_test = "Minimal T=1", + .ar_len = 4, + .ar_buf = { 0x3b, 0x80, 0x01, 0x81 }, + .ar_sup = ATR_P_T1, + .ar_def = ATR_P_T1, + .ar_neg = B_TRUE, + .ar_fi = 1, + .ar_di = 1, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t1_cksum = ATR_T1_CHECKSUM_LRC, + .ar_t1_bwi = 4, + .ar_t1_cwi = 13, + .ar_t1_ifsc = 32 + }, { + .ar_test = "T=1 Fi/Di", + .ar_len = 5, + .ar_buf = { 0x3b, 0x90, 0x34, 0x01, 0xa5 }, + .ar_sup = ATR_P_T1, + .ar_def = ATR_P_T1, + .ar_neg = B_TRUE, + .ar_fi = 3, + .ar_di = 4, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t1_cksum = ATR_T1_CHECKSUM_LRC, + .ar_t1_bwi = 4, + .ar_t1_cwi = 13, + .ar_t1_ifsc = 32 + }, { + .ar_test = "T=1 TA2 says neg, T=1 def", + .ar_len = 5, + .ar_buf = { 0x3b, 0x80, 0x11, 0x11, 0x80 }, + .ar_sup = ATR_P_T1, + .ar_def = ATR_P_T1, + .ar_neg = B_TRUE, + .ar_fi = 1, + .ar_di = 1, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t1_cksum = ATR_T1_CHECKSUM_LRC, + .ar_t1_bwi = 4, + .ar_t1_cwi = 13, + .ar_t1_ifsc = 32 + }, { + .ar_test = "T=0, T=1 TA2 says neg, T=0 def", + .ar_len = 6, + .ar_buf = { 0x3b, 0x80, 0x90, 0x10, 0x01, 0x01 }, + .ar_sup = ATR_P_T0 | ATR_P_T1, + .ar_def = ATR_P_T0, + .ar_neg = B_TRUE, + .ar_fi = 1, + .ar_di = 1, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t0_wi = 10, + .ar_t1_cksum = ATR_T1_CHECKSUM_LRC, + .ar_t1_bwi = 4, + .ar_t1_cwi = 13, + .ar_t1_ifsc = 32 + }, { + .ar_test = "T=0, T=1 TA2 says neg, T=1 def", + .ar_len = 6, + .ar_buf = { 0x3b, 0x80, 0x90, 0x11, 0x01, 0x00 }, + .ar_sup = ATR_P_T0 | ATR_P_T1, + .ar_def = ATR_P_T1, + .ar_neg = B_TRUE, + .ar_fi = 1, + .ar_di = 1, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t0_wi = 10, + .ar_t1_cksum = ATR_T1_CHECKSUM_LRC, + .ar_t1_bwi = 4, + .ar_t1_cwi = 13, + .ar_t1_ifsc = 32 + }, { + .ar_test = "T=0, T=1 TA2 says not neg, T=0 def", + .ar_len = 6, + .ar_buf = { 0x3b, 0x80, 0x90, 0x90, 0x01, 0x81 }, + .ar_sup = ATR_P_T0 | ATR_P_T1, + .ar_def = ATR_P_T0, + .ar_neg = B_FALSE, + .ar_fi = 1, + .ar_di = 1, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t0_wi = 10, + .ar_t1_cksum = ATR_T1_CHECKSUM_LRC, + .ar_t1_bwi = 4, + .ar_t1_cwi = 13, + .ar_t1_ifsc = 32 + }, { + .ar_test = "T=0, T=1 TA2 says not neg, T=1 def", + .ar_len = 6, + .ar_buf = { 0x3b, 0x80, 0x90, 0x81, 0x01, 0x90 }, + .ar_sup = ATR_P_T0 | ATR_P_T1, + .ar_def = ATR_P_T1, + .ar_neg = B_FALSE, + .ar_fi = 1, + .ar_di = 1, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t0_wi = 10, + .ar_t1_cksum = ATR_T1_CHECKSUM_LRC, + .ar_t1_bwi = 4, + .ar_t1_cwi = 13, + .ar_t1_ifsc = 32 + }, { + .ar_test = "T=1, BWI/CWI", + .ar_len = 6, + .ar_buf = { 0x3b, 0x80, 0x81, 0x21, 0x59, 0x79 }, + .ar_sup = ATR_P_T1, + .ar_def = ATR_P_T1, + .ar_neg = B_TRUE, + .ar_fi = 1, + .ar_di = 1, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t1_cksum = ATR_T1_CHECKSUM_LRC, + .ar_t1_bwi = 5, + .ar_t1_cwi = 9, + .ar_t1_ifsc = 32 + }, { + .ar_test = "T=1, IFSC", + .ar_len = 6, + .ar_buf = { 0x3b, 0x80, 0x81, 0x11, 0x49, 0x59 }, + .ar_sup = ATR_P_T1, + .ar_def = ATR_P_T1, + .ar_neg = B_TRUE, + .ar_fi = 1, + .ar_di = 1, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t1_cksum = ATR_T1_CHECKSUM_LRC, + .ar_t1_bwi = 4, + .ar_t1_cwi = 13, + .ar_t1_ifsc = 73 + }, { + .ar_test = "T=1, Checksum (LRC)", + .ar_len = 6, + .ar_buf = { 0x3b, 0x80, 0x81, 0x41, 0x00, 0x40 }, + .ar_sup = ATR_P_T1, + .ar_def = ATR_P_T1, + .ar_neg = B_TRUE, + .ar_fi = 1, + .ar_di = 1, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t1_cksum = ATR_T1_CHECKSUM_LRC, + .ar_t1_bwi = 4, + .ar_t1_cwi = 13, + .ar_t1_ifsc = 32 + }, { + .ar_test = "T=1, Checksum (CRC)", + .ar_len = 6, + .ar_buf = { 0x3b, 0x80, 0x81, 0x41, 0x01, 0x41 }, + .ar_sup = ATR_P_T1, + .ar_def = ATR_P_T1, + .ar_neg = B_TRUE, + .ar_fi = 1, + .ar_di = 1, + .ar_conv = ATR_CONVENTION_DIRECT, + .ar_guard = 0, + .ar_stop = ATR_CLOCK_STOP_NONE, + .ar_t1_cksum = ATR_T1_CHECKSUM_CRC, + .ar_t1_bwi = 4, + .ar_t1_cwi = 13, + .ar_t1_ifsc = 32 + } +}; + +static void +atr_parse_failed(atr_test_t *test, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + (void) fprintf(stderr, "Test \"%s\" failed: ", test->ar_test); + (void) vfprintf(stderr, fmt, ap); + (void) fprintf(stderr, "\n"); + va_end(ap); +} + +static uint_t +atr_parse_one(atr_data_t *data, atr_test_t *test) +{ + uint_t err = 0; + atr_parsecode_t ret; + atr_protocol_t sup, def; + boolean_t neg; + uint8_t fi, di, guard; + atr_convention_t conv; + atr_clock_stop_t stop; + + ret = atr_parse(test->ar_buf, test->ar_len, data); + if (ret != test->ar_retval) { + atr_parse_failed(test, "found unexpected return " + "value: %u (%s), expected: %u", ret, atr_strerror(ret), + test->ar_retval); + return (1); + } + + /* Don't test anything else if it's not OK */ + if (ret != ATR_CODE_OK) + return (0); + + sup = atr_supported_protocols(data); + def = atr_default_protocol(data); + neg = atr_params_negotiable(data); + fi = atr_fi_index(data); + di = atr_di_index(data); + conv = atr_convention(data); + guard = atr_extra_guardtime(data); + stop = atr_clock_stop(data); + + if (sup != test->ar_sup) { + atr_parse_failed(test, "Found mismatched supported " + "protocols: %u, expected: %u", sup, test->ar_sup); + err++; + } + + if (def != test->ar_def) { + atr_parse_failed(test, "Found mismatched default " + "protocols: %u, expected: %u", def, test->ar_def); + err++; + } + + if (neg != test->ar_neg) { + atr_parse_failed(test, "Found mismatched negotiable bit: " + "%u, expected %u", neg, test->ar_neg); + err++; + } + + if (fi != test->ar_fi) { + atr_parse_failed(test, "Found mismatched fi index: " + "%u, expected: %u", fi, test->ar_fi); + err++; + } + + if (di != test->ar_di) { + atr_parse_failed(test, "Found mismatched di index: " + "%u, expected: %u", di, test->ar_di); + err++; + } + + if (conv != test->ar_conv) { + atr_parse_failed(test, "Found mismatched TS convention: " + "%u, expected: %u", conv, test->ar_conv); + err++; + } + + if (guard != test->ar_guard) { + atr_parse_failed(test, "Found mismatched extra guardtime: " + "%u, expected: %u", guard, test->ar_guard); + err++; + } + + if (stop != test->ar_stop) { + atr_parse_failed(test, "Found mismatched clock stop: " + "%u, expected: %u", stop, test->ar_stop); + err++; + } + + if ((sup & ATR_P_T0) != 0) { + uint8_t wi; + + wi = atr_t0_wi(data); + if (wi != test->ar_t0_wi) { + atr_parse_failed(test, "Found mismatched T0 wi: " + "%u, expected: %u", wi, test->ar_t0_wi); + err++; + } + } + + if ((sup & ATR_P_T1) != 0) { + atr_t1_checksum_t cksum; + uint8_t bwi, cwi, ifsc; + + cksum = atr_t1_checksum(data); + bwi = atr_t1_bwi(data); + cwi = atr_t1_cwi(data); + ifsc = atr_t1_ifsc(data); + + if (cksum != test->ar_t1_cksum) { + atr_parse_failed(test, "Found mistmatched T1 checksum: " + "%u, expected: %u", cksum, test->ar_t1_cksum); + err++; + } + + if (bwi != test->ar_t1_bwi) { + atr_parse_failed(test, "Found mistmatched T1 bwi: " + "%u, expected: %u", bwi, test->ar_t1_bwi); + err++; + } + + if (cwi != test->ar_t1_cwi) { + atr_parse_failed(test, "Found mistmatched T1 cwi: " + "%u, expected: %u", cwi, test->ar_t1_cwi); + err++; + } + + if (ifsc != test->ar_t1_ifsc) { + atr_parse_failed(test, "Found mistmatched T1 ifsc: " + "%u, expected: %u", ifsc, test->ar_t1_ifsc); + err++; + } + } + + if (err > 0) { + atr_data_dump(data, stderr); + return (1); + } + + return (0); +} + +int +main(void) +{ + uint_t i; + uint_t errs = 0; + atr_data_t *data; + + data = atr_data_alloc(); + if (data == NULL) { + errx(EXIT_FAILURE, "failed to allocate atr_data_t"); + } + + for (i = 0; i < sizeof (atr_tests) / sizeof (atr_test_t); i++) { + atr_data_reset(data); + errs += atr_parse_one(data, &atr_tests[i]); + } + + atr_data_free(data); + + if (errs != 0) { + warnx("%d test(s) failed", errs); + } + return (errs != 0 ? EXIT_FAILURE : EXIT_SUCCESS); +} diff --git a/usr/src/test/os-tests/tests/uccid/excl-badread.c b/usr/src/test/os-tests/tests/uccid/excl-badread.c new file mode 100644 index 0000000000..e5f265d1e7 --- /dev/null +++ b/usr/src/test/os-tests/tests/uccid/excl-badread.c @@ -0,0 +1,80 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2019, Joyent, Inc. + */ + +/* + * Verify various bad read conditions fail successfully. + */ + +#include <err.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <strings.h> +#include <unistd.h> +#include <errno.h> + +#include <sys/usb/clients/ccid/uccid.h> + +int +main(int argc, char *argv[]) +{ + int fd; + uccid_cmd_txn_begin_t begin; + ssize_t ret; + char buf[500]; + + if (argc != 2) { + errx(EXIT_FAILURE, "missing required ccid path"); + } + + if ((fd = open(argv[1], O_RDWR)) < 0) { + err(EXIT_FAILURE, "failed to open %s", argv[1]); + } + + bzero(&begin, sizeof (begin)); + begin.uct_version = UCCID_CURRENT_VERSION; + + /* + * Read without having a transaction + */ + ret = read(fd, buf, sizeof (buf)); + if (ret != -1) { + errx(EXIT_FAILURE, "read succeeded when it should have failed " + "(EACCES case), returned %ld", ret); + } + + if (errno != EACCES) { + errx(EXIT_FAILURE, "found wrong value for errno. Expected " + "%d, received %d", EACCES, errno); + } + + if (ioctl(fd, UCCID_CMD_TXN_BEGIN, &begin) != 0) { + err(EXIT_FAILURE, "failed to issue begin ioctl"); + } + + ret = read(fd, buf, sizeof (buf)); + if (ret != -1) { + errx(EXIT_FAILURE, "read succeeded when it should have failed " + "(ENODATA case), returned %ld", ret); + } + + if (errno != ENODATA) { + errx(EXIT_FAILURE, "found wrong value for errno. Expected " + "%d, received %d", ENODATA, errno); + } + + return (0); +} diff --git a/usr/src/test/os-tests/tests/uccid/excl-basic.c b/usr/src/test/os-tests/tests/uccid/excl-basic.c new file mode 100644 index 0000000000..c6cf30dd5e --- /dev/null +++ b/usr/src/test/os-tests/tests/uccid/excl-basic.c @@ -0,0 +1,65 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2019, Joyent, Inc. + */ + +/* + * Verify that we can grab a basic exclusive lock through an ioctl on the slot. + * Then that we can release it afterwards. + */ + +#include <err.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <strings.h> +#include <unistd.h> + +#include <sys/usb/clients/ccid/uccid.h> + +int +main(int argc, char *argv[]) +{ + int fd; + uint_t i; + uccid_cmd_txn_begin_t begin; + uccid_cmd_txn_end_t end; + + if (argc != 2) { + errx(EXIT_FAILURE, "missing required ccid path"); + } + + if ((fd = open(argv[1], O_RDWR)) < 0) { + err(EXIT_FAILURE, "failed to open %s", argv[1]); + } + + bzero(&begin, sizeof (begin)); + bzero(&end, sizeof (end)); + + begin.uct_version = UCCID_CURRENT_VERSION; + end.uct_version = UCCID_CURRENT_VERSION; + end.uct_flags = UCCID_TXN_END_RELEASE; + + for (i = 0; i < 10; i++) { + if (ioctl(fd, UCCID_CMD_TXN_BEGIN, &begin) != 0) { + err(EXIT_FAILURE, "failed to issue begin ioctl"); + } + + if (ioctl(fd, UCCID_CMD_TXN_END, &end) != 0) { + err(EXIT_FAILURE, "failed to issue end ioctl"); + } + } + + return (0); +} diff --git a/usr/src/test/os-tests/tests/uccid/excl-close.c b/usr/src/test/os-tests/tests/uccid/excl-close.c new file mode 100644 index 0000000000..3936c73ab0 --- /dev/null +++ b/usr/src/test/os-tests/tests/uccid/excl-close.c @@ -0,0 +1,81 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2019, Joyent, Inc. + */ + +/* + * Verify that if a child grabs an exclusive lock and calls exit, we can grab it + * again. + */ + +#include <err.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <strings.h> +#include <unistd.h> +#include <errno.h> +#include <sys/wait.h> + +#include <sys/usb/clients/ccid/uccid.h> + +int +main(int argc, char *argv[]) +{ + int fd, estat; + pid_t pid; + uccid_cmd_txn_begin_t begin; + + if (argc != 2) { + errx(EXIT_FAILURE, "missing required ccid path"); + } + + bzero(&begin, sizeof (begin)); + begin.uct_version = UCCID_CURRENT_VERSION; + + pid = fork(); + if (pid == 0) { + fd = open(argv[1], O_RDWR); + if (fd < 0) { + err(EXIT_FAILURE, "failed to open %s", argv[1]); + } + + if (ioctl(fd, UCCID_CMD_TXN_BEGIN, &begin) != 0) { + err(EXIT_FAILURE, "failed to issue begin ioctl"); + } + + _exit(0); + } + + estat = -1; + if (waitpid(pid, &estat, 0) == -1) { + err(EXIT_FAILURE, "failed to wait for pid %d", pid); + } + + if (estat != 0) { + errx(EXIT_FAILURE, "child exited with non-zero value (%d)", + estat); + } + + fd = open(argv[1], O_RDWR); + if (fd < 0) { + err(EXIT_FAILURE, "failed to open %s", argv[1]); + } + + if (ioctl(fd, UCCID_CMD_TXN_BEGIN, &begin) != 0) { + err(EXIT_FAILURE, "failed to issue begin ioctl"); + } + + return (0); +} diff --git a/usr/src/test/os-tests/tests/uccid/excl-loop.c b/usr/src/test/os-tests/tests/uccid/excl-loop.c new file mode 100644 index 0000000000..f31fc81a34 --- /dev/null +++ b/usr/src/test/os-tests/tests/uccid/excl-loop.c @@ -0,0 +1,84 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2019, Joyent, Inc. + */ + +/* + * Verify that we can grab a basic exclusive lock and then if we try to get + * another lock it fails. Regardless of whether we do so through open(2) or + * ioctl(2). + */ + +#include <err.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <strings.h> +#include <unistd.h> +#include <errno.h> +#include <sys/debug.h> + +#include <sys/usb/clients/ccid/uccid.h> + +int +main(int argc, char *argv[]) +{ + int fd, ret; + uccid_cmd_txn_begin_t begin; + uccid_cmd_txn_end_t end; + + if (argc != 2) { + errx(EXIT_FAILURE, "missing required ccid path"); + } + + if ((fd = open(argv[1], O_RDWR)) < 0) { + err(EXIT_FAILURE, "failed to open %s", argv[1]); + } + + bzero(&begin, sizeof (begin)); + bzero(&end, sizeof (end)); + + begin.uct_version = UCCID_CURRENT_VERSION; + end.uct_version = UCCID_CURRENT_VERSION; + end.uct_flags = UCCID_TXN_END_RELEASE; + + if (ioctl(fd, UCCID_CMD_TXN_BEGIN, &begin) != 0) { + err(EXIT_FAILURE, "failed to issue begin ioctl"); + } + + ret = ioctl(fd, UCCID_CMD_TXN_BEGIN, &begin); + VERIFY3S(ret, ==, -1); + VERIFY3S(errno, ==, EEXIST); + + if (ioctl(fd, UCCID_CMD_TXN_END, &end) != 0) { + err(EXIT_FAILURE, "failed to issue end ioctl"); + } + + VERIFY0(close(fd)); + + if ((fd = open(argv[1], O_RDWR)) < 0) { + err(EXIT_FAILURE, "failed to open %s", argv[1]); + } + + ret = ioctl(fd, UCCID_CMD_TXN_BEGIN, &begin); + VERIFY0(ret); + + ret = ioctl(fd, UCCID_CMD_TXN_BEGIN, &begin); + VERIFY3S(ret, ==, -1); + VERIFY3S(errno, ==, EEXIST); + + VERIFY0(close(fd)); + + return (0); +} diff --git a/usr/src/test/os-tests/tests/uccid/excl-nonblock.c b/usr/src/test/os-tests/tests/uccid/excl-nonblock.c new file mode 100644 index 0000000000..ee4f1edbd1 --- /dev/null +++ b/usr/src/test/os-tests/tests/uccid/excl-nonblock.c @@ -0,0 +1,99 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2019, Joyent, Inc. + */ + +/* + * Verify that if we've grabbed an exclusive lock, another thread fails to grab + * it as a non-blocking lock. + */ + +#include <err.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <strings.h> +#include <unistd.h> +#include <sys/debug.h> +#include <thread.h> +#include <errno.h> + +#include <sys/usb/clients/ccid/uccid.h> + +void * +nonblock_thread(void *arg) +{ + uccid_cmd_txn_begin_t begin; + int ret; + int fd = (uintptr_t)arg; + + + bzero(&begin, sizeof (begin)); + + begin.uct_version = UCCID_CURRENT_VERSION; + begin.uct_flags = UCCID_TXN_DONT_BLOCK; + + ret = ioctl(fd, UCCID_CMD_TXN_BEGIN, &begin); + VERIFY3S(ret, ==, -1); + VERIFY3S(errno, ==, EBUSY); + + return (NULL); +} + +int +main(int argc, char *argv[]) +{ + int fda, fdb; + uccid_cmd_txn_begin_t begin; + uccid_cmd_txn_end_t end; + thread_t thr; + + if (argc != 2) { + errx(EXIT_FAILURE, "missing required ccid path"); + } + + if ((fda = open(argv[1], O_RDWR)) < 0) { + err(EXIT_FAILURE, "failed to open %s", argv[1]); + } + + if ((fdb = open(argv[1], O_RDWR)) < 0) { + err(EXIT_FAILURE, "failed to open %s", argv[1]); + } + + bzero(&begin, sizeof (begin)); + bzero(&end, sizeof (end)); + + begin.uct_version = UCCID_CURRENT_VERSION; + end.uct_version = UCCID_CURRENT_VERSION; + end.uct_flags = UCCID_TXN_END_RELEASE; + + if (ioctl(fda, UCCID_CMD_TXN_BEGIN, &begin) != 0) { + err(EXIT_FAILURE, "failed to issue begin ioctl"); + } + + if (thr_create(NULL, 0, nonblock_thread, (void *)(uintptr_t)fdb, 0, + &thr) != 0) { + err(EXIT_FAILURE, "failed to create thread"); + } + + if (thr_join(thr, NULL, NULL) != 0) { + err(EXIT_FAILURE, "failed to join therad"); + } + + if (ioctl(fda, UCCID_CMD_TXN_END, &end) != 0) { + err(EXIT_FAILURE, "failed to issue end ioctl"); + } + + return (0); +} diff --git a/usr/src/test/os-tests/tests/uccid/excl-reset.c b/usr/src/test/os-tests/tests/uccid/excl-reset.c new file mode 100644 index 0000000000..7ab1718475 --- /dev/null +++ b/usr/src/test/os-tests/tests/uccid/excl-reset.c @@ -0,0 +1,65 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2019, Joyent, Inc. + */ + +/* + * Verify that we can grab a basic exclusive lock through an ioctl on the slot. + * Then that we can release it afterwards and reset the ICC. + */ + +#include <err.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <strings.h> +#include <unistd.h> + +#include <sys/usb/clients/ccid/uccid.h> + +int +main(int argc, char *argv[]) +{ + int fd; + uint_t i; + uccid_cmd_txn_begin_t begin; + uccid_cmd_txn_end_t end; + + if (argc != 2) { + errx(EXIT_FAILURE, "missing required ccid path"); + } + + if ((fd = open(argv[1], O_RDWR)) < 0) { + err(EXIT_FAILURE, "failed to open %s", argv[1]); + } + + bzero(&begin, sizeof (begin)); + bzero(&end, sizeof (end)); + + begin.uct_version = UCCID_CURRENT_VERSION; + end.uct_version = UCCID_CURRENT_VERSION; + end.uct_flags = UCCID_TXN_END_RESET; + + for (i = 0; i < 10; i++) { + if (ioctl(fd, UCCID_CMD_TXN_BEGIN, &begin) != 0) { + err(EXIT_FAILURE, "failed to issue begin ioctl"); + } + + if (ioctl(fd, UCCID_CMD_TXN_END, &end) != 0) { + err(EXIT_FAILURE, "failed to issue end ioctl"); + } + } + + return (0); +} diff --git a/usr/src/test/os-tests/tests/uccid/modify.c b/usr/src/test/os-tests/tests/uccid/modify.c new file mode 100644 index 0000000000..1ac44f3ba4 --- /dev/null +++ b/usr/src/test/os-tests/tests/uccid/modify.c @@ -0,0 +1,181 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2019, Joyent, Inc. + */ + +/* + * Verify that we can issue ICC_MODIFY ioctls. Also, check some of the failure + * modes. + */ + +#include <err.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <strings.h> +#include <unistd.h> +#include <sys/debug.h> +#include <errno.h> +#include <sys/mman.h> +#include <sys/param.h> + +#include <sys/usb/clients/ccid/uccid.h> + +static const uint8_t yk_req[] = { + 0x00, 0xa4, 0x04, 0x00, 0x07, 0xa0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x01 +}; + +int +main(int argc, char *argv[]) +{ + int fd, ret; + uccid_cmd_icc_modify_t uci; + uccid_cmd_status_t ucs; + uccid_cmd_txn_begin_t begin; + uint8_t buf[UCCID_APDU_SIZE_MAX]; + + if (argc != 2) { + errx(EXIT_FAILURE, "missing required ccid path"); + } + + if ((fd = open(argv[1], O_RDWR)) < 0) { + err(EXIT_FAILURE, "failed to open %s", argv[1]); + } + + /* try power off the card outside of a transaction */ + bzero(&uci, sizeof (uci)); + uci.uci_version = UCCID_CURRENT_VERSION; + uci.uci_action = UCCID_ICC_POWER_OFF; + ret = ioctl(fd, UCCID_CMD_ICC_MODIFY, &uci); + VERIFY3S(ret, ==, -1); + VERIFY3S(errno, ==, EACCES); + + bzero(&begin, sizeof (begin)); + begin.uct_version = UCCID_CURRENT_VERSION; + if (ioctl(fd, UCCID_CMD_TXN_BEGIN, &begin) != 0) { + err(EXIT_FAILURE, "failed to issue begin ioctl"); + } + + /* make sure the card is active (power on) */ + bzero(&ucs, sizeof (ucs)); + ucs.ucs_version = UCCID_CURRENT_VERSION; + ret = ioctl(fd, UCCID_CMD_STATUS, &ucs); + VERIFY3S(ret, ==, 0); + VERIFY3U(ucs.ucs_status & UCCID_STATUS_F_CARD_ACTIVE, !=, 0); + + /* power off the card */ + bzero(&uci, sizeof (uci)); + uci.uci_version = UCCID_CURRENT_VERSION; + uci.uci_action = UCCID_ICC_POWER_OFF; + ret = ioctl(fd, UCCID_CMD_ICC_MODIFY, &uci); + VERIFY3S(ret, ==, 0); + + /* make sure the card is inactive now */ + bzero(&ucs, sizeof (ucs)); + ucs.ucs_version = UCCID_CURRENT_VERSION; + ret = ioctl(fd, UCCID_CMD_STATUS, &ucs); + VERIFY3S(ret, ==, 0); + VERIFY3U(ucs.ucs_status & UCCID_STATUS_F_CARD_ACTIVE, ==, 0); + + /* power on the card */ + bzero(&uci, sizeof (uci)); + uci.uci_version = UCCID_CURRENT_VERSION; + uci.uci_action = UCCID_ICC_POWER_ON; + ret = ioctl(fd, UCCID_CMD_ICC_MODIFY, &uci); + VERIFY3S(ret, ==, 0); + + /* make sure the card is active again */ + bzero(&ucs, sizeof (ucs)); + ucs.ucs_version = UCCID_CURRENT_VERSION; + ret = ioctl(fd, UCCID_CMD_STATUS, &ucs); + VERIFY3S(ret, ==, 0); + VERIFY3U(ucs.ucs_status & UCCID_STATUS_F_CARD_ACTIVE, !=, 0); + + /* do a warm reset of the card */ + bzero(&uci, sizeof (uci)); + uci.uci_version = UCCID_CURRENT_VERSION; + uci.uci_action = UCCID_ICC_WARM_RESET; + ret = ioctl(fd, UCCID_CMD_ICC_MODIFY, &uci); + VERIFY3S(ret, ==, 0); + + /* make sure the card is still active */ + bzero(&ucs, sizeof (ucs)); + ucs.ucs_version = UCCID_CURRENT_VERSION; + ret = ioctl(fd, UCCID_CMD_STATUS, &ucs); + VERIFY3S(ret, ==, 0); + VERIFY3U(ucs.ucs_status & UCCID_STATUS_F_CARD_ACTIVE, !=, 0); + + /* write a command to the card, which is assumed to be a YubiKey */ + if ((ret = write(fd, yk_req, sizeof (yk_req))) < 0) { + err(EXIT_FAILURE, "failed to write data"); + } + + /* power off the card */ + bzero(&uci, sizeof (uci)); + uci.uci_version = UCCID_CURRENT_VERSION; + uci.uci_action = UCCID_ICC_POWER_OFF; + ret = ioctl(fd, UCCID_CMD_ICC_MODIFY, &uci); + VERIFY3S(ret, ==, 0); + + /* make sure the card is inactive now */ + bzero(&ucs, sizeof (ucs)); + ucs.ucs_version = UCCID_CURRENT_VERSION; + ret = ioctl(fd, UCCID_CMD_STATUS, &ucs); + VERIFY3S(ret, ==, 0); + VERIFY3U(ucs.ucs_status & UCCID_STATUS_F_CARD_ACTIVE, ==, 0); + + /* try to read the answer from the YubiKey. */ + ret = read(fd, buf, sizeof (buf)); + VERIFY3S(ret, ==, -1); + VERIFY3S(errno, ==, ENXIO); + + /* power on the card */ + bzero(&uci, sizeof (uci)); + uci.uci_version = UCCID_CURRENT_VERSION; + uci.uci_action = UCCID_ICC_POWER_ON; + ret = ioctl(fd, UCCID_CMD_ICC_MODIFY, &uci); + VERIFY3S(ret, ==, 0); + + /* make sure the card is active again */ + bzero(&ucs, sizeof (ucs)); + ucs.ucs_version = UCCID_CURRENT_VERSION; + ret = ioctl(fd, UCCID_CMD_STATUS, &ucs); + VERIFY3S(ret, ==, 0); + VERIFY3U(ucs.ucs_status & UCCID_STATUS_F_CARD_ACTIVE, !=, 0); + + /* test various failure modes */ + uci.uci_version = UCCID_VERSION_ONE - 1; + ret = ioctl(fd, UCCID_CMD_ICC_MODIFY, &uci); + VERIFY3S(ret, ==, -1); + VERIFY3S(errno, ==, EINVAL); + + uci.uci_version = UCCID_VERSION_ONE + 1; + ret = ioctl(fd, UCCID_CMD_ICC_MODIFY, &uci); + VERIFY3S(ret, ==, -1); + VERIFY3S(errno, ==, EINVAL); + + uci.uci_version = UCCID_CURRENT_VERSION; + uci.uci_action = 0; + ret = ioctl(fd, UCCID_CMD_ICC_MODIFY, &uci); + VERIFY3S(ret, ==, -1); + VERIFY3S(errno, ==, EINVAL); + + uci.uci_version = UCCID_CURRENT_VERSION; + uci.uci_action = -1; + ret = ioctl(fd, UCCID_CMD_ICC_MODIFY, &uci); + VERIFY3S(ret, ==, -1); + VERIFY3S(errno, ==, EINVAL); + + return (0); +} diff --git a/usr/src/test/os-tests/tests/uccid/notxn-poll.c b/usr/src/test/os-tests/tests/uccid/notxn-poll.c new file mode 100644 index 0000000000..b45f06b218 --- /dev/null +++ b/usr/src/test/os-tests/tests/uccid/notxn-poll.c @@ -0,0 +1,57 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2019, Joyent, Inc. + */ + +/* + * Verify that trying to poll without a transaction / excl access works but + * returns no events. + */ + +#include <err.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/debug.h> +#include <fcntl.h> +#include <strings.h> +#include <unistd.h> +#include <errno.h> +#include <poll.h> + +#include <sys/usb/clients/ccid/uccid.h> + +int +main(int argc, char *argv[]) +{ + int fd, ret; + struct pollfd pfds[1]; + + if (argc != 2) { + errx(EXIT_FAILURE, "missing required ccid path"); + } + + if ((fd = open(argv[1], O_RDWR)) < 0) { + err(EXIT_FAILURE, "failed to open %s", argv[1]); + } + + pfds[0].fd = fd; + pfds[0].events = POLLIN; + pfds[0].revents = 0; + + ret = poll(pfds, 1, 0); + VERIFY3S(ret, ==, 0); + VERIFY3S(pfds[0].revents, ==, 0); + + return (0); +} diff --git a/usr/src/test/os-tests/tests/uccid/pollin.c b/usr/src/test/os-tests/tests/uccid/pollin.c new file mode 100644 index 0000000000..dd81c245cc --- /dev/null +++ b/usr/src/test/os-tests/tests/uccid/pollin.c @@ -0,0 +1,64 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2019, Joyent, Inc. + */ + +/* + * Open up a device and make sure we get pollout by default. + */ + +#include <err.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <strings.h> +#include <unistd.h> +#include <errno.h> +#include <poll.h> + +#include <sys/usb/clients/ccid/uccid.h> + +int +main(int argc, char *argv[]) +{ + int fd, ret; + struct pollfd pfds[1]; + uccid_cmd_txn_begin_t begin; + + if (argc != 2) { + errx(EXIT_FAILURE, "missing required ccid path"); + } + + if ((fd = open(argv[1], O_RDWR)) < 0) { + err(EXIT_FAILURE, "failed to open %s", argv[1]); + } + + bzero(&begin, sizeof (begin)); + begin.uct_version = UCCID_CURRENT_VERSION; + if (ioctl(fd, UCCID_CMD_TXN_BEGIN, &begin) != 0) { + err(EXIT_FAILURE, "failed to issue begin ioctl"); + } + + pfds[0].fd = fd; + pfds[0].events = POLLIN; + pfds[0].revents = 0; + + ret = poll(pfds, 1, 0); + if (ret != 0) { + err(EXIT_FAILURE, "poll didn't return 0, returned %d " + "(errno %d)", ret, errno); + } + + return (0); +} diff --git a/usr/src/test/os-tests/tests/uccid/pollout.c b/usr/src/test/os-tests/tests/uccid/pollout.c new file mode 100644 index 0000000000..a9928a6fe2 --- /dev/null +++ b/usr/src/test/os-tests/tests/uccid/pollout.c @@ -0,0 +1,68 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2019, Joyent, Inc. + */ + +/* + * Open up a device and make sure we get pollout by default. + */ + +#include <err.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <strings.h> +#include <unistd.h> +#include <errno.h> +#include <poll.h> + +#include <sys/usb/clients/ccid/uccid.h> + +int +main(int argc, char *argv[]) +{ + int fd, ret; + struct pollfd pfds[1]; + uccid_cmd_txn_begin_t begin; + + if (argc != 2) { + errx(EXIT_FAILURE, "missing required ccid path"); + } + + if ((fd = open(argv[1], O_RDWR)) < 0) { + err(EXIT_FAILURE, "failed to open %s", argv[1]); + } + + bzero(&begin, sizeof (begin)); + begin.uct_version = UCCID_CURRENT_VERSION; + if (ioctl(fd, UCCID_CMD_TXN_BEGIN, &begin) != 0) { + err(EXIT_FAILURE, "failed to issue begin ioctl"); + } + + pfds[0].fd = fd; + pfds[0].events = POLLOUT; + pfds[0].revents = 0; + + ret = poll(pfds, 1, 0); + if (ret != 1) { + err(EXIT_FAILURE, "poll didn't return 1, returned %d " + "(errno %d)", ret, errno); + } + + if (!(pfds[0].revents & POLLOUT)) { + err(EXIT_FAILURE, "missing pollout, got %d", pfds[0].revents); + } + + return (0); +} diff --git a/usr/src/test/os-tests/tests/uccid/status.c b/usr/src/test/os-tests/tests/uccid/status.c new file mode 100644 index 0000000000..ae2a51226f --- /dev/null +++ b/usr/src/test/os-tests/tests/uccid/status.c @@ -0,0 +1,97 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2019, Joyent, Inc. + */ + +/* + * Verify that we can issue various status ioctls regardless of whether or not + * we have exclusive access on our handle. Also, check some of the failure + * modes. + */ + +#include <err.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <strings.h> +#include <unistd.h> +#include <sys/debug.h> +#include <errno.h> +#include <sys/mman.h> +#include <sys/param.h> + +#include <sys/usb/clients/ccid/uccid.h> + +int +main(int argc, char *argv[]) +{ + int fd, efd, ret; + uccid_cmd_status_t ucs; + uccid_cmd_txn_begin_t begin; + void *badaddr; + + if (argc != 2) { + errx(EXIT_FAILURE, "missing required ccid path"); + } + + if ((fd = open(argv[1], O_RDWR)) < 0) { + err(EXIT_FAILURE, "failed to open %s", argv[1]); + } + + if ((efd = open(argv[1], O_RDWR)) < 0) { + err(EXIT_FAILURE, "failed to open %s", argv[1]); + } + + bzero(&begin, sizeof (begin)); + begin.uct_version = UCCID_CURRENT_VERSION; + if (ioctl(efd, UCCID_CMD_TXN_BEGIN, &begin) != 0) { + err(EXIT_FAILURE, "failed to issue begin ioctl"); + } + + bzero(&ucs, sizeof (ucs)); + ucs.ucs_version = UCCID_CURRENT_VERSION; + + ret = ioctl(fd, UCCID_CMD_STATUS, &ucs); + VERIFY3S(ret, ==, 0); + + ret = ioctl(efd, UCCID_CMD_STATUS, &ucs); + VERIFY3S(ret, ==, 0); + + ucs.ucs_version = UCCID_VERSION_ONE - 1; + ret = ioctl(efd, UCCID_CMD_STATUS, &ucs); + VERIFY3S(ret, ==, -1); + VERIFY3S(errno, ==, EINVAL); + + ucs.ucs_version = UCCID_VERSION_ONE + 1; + ret = ioctl(efd, UCCID_CMD_STATUS, &ucs); + VERIFY3S(ret, ==, -1); + VERIFY3S(errno, ==, EINVAL); + + ucs.ucs_version = UCCID_VERSION_ONE - 1; + ret = ioctl(fd, UCCID_CMD_STATUS, &ucs); + VERIFY3S(ret, ==, -1); + VERIFY3S(errno, ==, EINVAL); + + ucs.ucs_version = UCCID_VERSION_ONE + 1; + ret = ioctl(fd, UCCID_CMD_STATUS, &ucs); + VERIFY3S(ret, ==, -1); + VERIFY3S(errno, ==, EINVAL); + + badaddr = mmap(NULL, PAGESIZE, PROT_READ, MAP_PRIVATE | MAP_ANON, -1, + 0); + VERIFY3P(badaddr, !=, MAP_FAILED); + VERIFY0(munmap(badaddr, PAGESIZE)); + + return (0); +} diff --git a/usr/src/test/os-tests/tests/uccid/txn-pollerr.c b/usr/src/test/os-tests/tests/uccid/txn-pollerr.c new file mode 100644 index 0000000000..b19598f711 --- /dev/null +++ b/usr/src/test/os-tests/tests/uccid/txn-pollerr.c @@ -0,0 +1,88 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2019, Joyent, Inc. + */ + +/* + * Verify that closing a transaction while polling generates POLLERR. + */ + +#include <err.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <strings.h> +#include <unistd.h> +#include <errno.h> +#include <sys/debug.h> +#include <poll.h> +#include <port.h> + +#include <sys/usb/clients/ccid/uccid.h> + +int +main(int argc, char *argv[]) +{ + int fd, port; + uccid_cmd_txn_end_t end; + uccid_cmd_txn_begin_t begin; + port_event_t pe; + timespec_t to; + + if (argc != 2) { + errx(EXIT_FAILURE, "missing required ccid path"); + } + + if ((port = port_create()) == -1) { + err(EXIT_FAILURE, "failed to create event port: %d", + port); + } + + if ((fd = open(argv[1], O_RDWR | O_EXCL)) < 0) { + err(EXIT_FAILURE, "failed to open %s", argv[1]); + } + + bzero(&begin, sizeof (begin)); + begin.uct_version = UCCID_CURRENT_VERSION; + if (ioctl(fd, UCCID_CMD_TXN_BEGIN, &begin) != 0) { + err(EXIT_FAILURE, "failed to issue begin ioctl"); + } + + /* + * Do not poll for pollout here, since by default, after grabbing a + * transaction, the device is writeable. + */ + if (port_associate(port, PORT_SOURCE_FD, fd, POLLIN, NULL) != 0) { + err(EXIT_FAILURE, "failed to associate"); + } + + bzero(&end, sizeof (end)); + end.uct_version = UCCID_CURRENT_VERSION; + end.uct_flags = UCCID_TXN_END_RELEASE; + + if (ioctl(fd, UCCID_CMD_TXN_END, &end) != 0) { + err(EXIT_FAILURE, "failed to issue end ioctl"); + } + + bzero(&to, sizeof (timespec_t)); + if (port_get(port, &pe, &to) != 0) { + err(EXIT_FAILURE, "failed to port_get()"); + } + + VERIFY3S(pe.portev_source, ==, PORT_SOURCE_FD); + VERIFY3S(pe.portev_object, ==, fd); + VERIFY3S(pe.portev_events & POLLERR, !=, 0); + + return (0); +} diff --git a/usr/src/test/os-tests/tests/uccid/yk-poll.c b/usr/src/test/os-tests/tests/uccid/yk-poll.c new file mode 100644 index 0000000000..fb52949f38 --- /dev/null +++ b/usr/src/test/os-tests/tests/uccid/yk-poll.c @@ -0,0 +1,108 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2019, Joyent, Inc. + */ + +/* + * Open a YubiKey class device and get the basic information applet + * through an APDU while using poll(2) to check device readyness. + */ + +#include <err.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <strings.h> +#include <unistd.h> +#include <errno.h> +#include <poll.h> + +#include <sys/usb/clients/ccid/uccid.h> + +static const uint8_t yk_req[] = { + 0x00, 0xa4, 0x04, 0x00, 0x07, 0xa0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x01 +}; + +int +main(int argc, char *argv[]) +{ + int fd, ret; + struct pollfd pfds[1]; + uccid_cmd_txn_begin_t begin; + uint8_t buf[UCCID_APDU_SIZE_MAX]; + + if (argc != 2) { + errx(EXIT_FAILURE, "missing required ccid path"); + } + + if ((fd = open(argv[1], O_RDWR)) < 0) { + err(EXIT_FAILURE, "failed to open %s", argv[1]); + } + + bzero(&begin, sizeof (begin)); + begin.uct_version = UCCID_CURRENT_VERSION; + if (ioctl(fd, UCCID_CMD_TXN_BEGIN, &begin) != 0) { + err(EXIT_FAILURE, "failed to issue begin ioctl"); + } + + pfds[0].fd = fd; + pfds[0].events = POLLOUT | POLLIN | POLLRDNORM; + pfds[0].revents = 0; + + ret = poll(pfds, 1, 0); + if (ret != 1) { + err(EXIT_FAILURE, "poll didn't return 1, returned %d " + "(errno %d)", ret, errno); + } + + if ((pfds[0].revents & POLLOUT) != POLLOUT) { + err(EXIT_FAILURE, "expecting pollout, got %d", pfds[0].revents); + } + + if ((ret = write(fd, yk_req, sizeof (yk_req))) < 0) { + err(EXIT_FAILURE, "failed to write data"); + } + + pfds[0].revents = 0; + + ret = poll(pfds, 1, -1); + if (ret != 1) { + err(EXIT_FAILURE, "poll didn't return 1, returned %d " + "(errno %d)", ret, errno); + } + + if ((pfds[0].revents & (POLLIN | POLLRDNORM)) != + (POLLIN | POLLRDNORM)) { + err(EXIT_FAILURE, "expecting pollin|pollrdnorm, got %d", + pfds[0].revents); + } + + if ((ret = read(fd, buf, sizeof (buf))) < 0) { + err(EXIT_FAILURE, "failed to read data"); + } + + pfds[0].revents = 0; + + ret = poll(pfds, 1, 0); + if (ret != 1) { + err(EXIT_FAILURE, "poll didn't return 1, returned %d " + "(errno %d)", ret, errno); + } + + if ((pfds[0].revents & POLLOUT) != POLLOUT) { + err(EXIT_FAILURE, "expecting pollout, got %d", pfds[0].revents); + } + + return (0); +} diff --git a/usr/src/test/os-tests/tests/uccid/yk-readonly.c b/usr/src/test/os-tests/tests/uccid/yk-readonly.c new file mode 100644 index 0000000000..dfe7390ea1 --- /dev/null +++ b/usr/src/test/os-tests/tests/uccid/yk-readonly.c @@ -0,0 +1,84 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2019, Joyent, Inc. + */ + +/* + * Open a YubiKey class device read-only and try to get the basic information + * applet through an APDU, which should fail. Try to get the status, which + * should succeed, and attempt to power off, which should fail. + */ + +#include <err.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <strings.h> +#include <unistd.h> +#include <errno.h> + +#include <sys/usb/clients/ccid/uccid.h> + +static const uint8_t yk_req[] = { + 0x00, 0xa4, 0x04, 0x00, 0x07, 0xa0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x01 +}; + +int +main(int argc, char *argv[]) +{ + int fd, ret; + uccid_cmd_icc_modify_t uci; + uccid_cmd_txn_begin_t begin; + uccid_cmd_status_t ucs; + uint8_t buf[UCCID_APDU_SIZE_MAX]; + + if (argc != 2) { + errx(EXIT_FAILURE, "missing required ccid path"); + } + + if ((fd = open(argv[1], O_RDONLY)) < 0) { + err(EXIT_FAILURE, "failed to open %s", argv[1]); + } + + bzero(&begin, sizeof (begin)); + begin.uct_version = UCCID_CURRENT_VERSION; + if (ioctl(fd, UCCID_CMD_TXN_BEGIN, &begin) == 0) { + err(EXIT_FAILURE, "didn't fail to issue begin ioctl"); + } + + if ((ret = write(fd, yk_req, sizeof (yk_req))) != -1) { + err(EXIT_FAILURE, "didn't fail to write data"); + } + + if ((ret = read(fd, buf, sizeof (buf))) != -1) { + err(EXIT_FAILURE, "didn't fail to read data"); + } + + bzero(&ucs, sizeof (ucs)); + ucs.ucs_version = UCCID_CURRENT_VERSION; + if ((ret = ioctl(fd, UCCID_CMD_STATUS, &ucs)) != 0) { + err(EXIT_FAILURE, "failed to get status"); + } + + /* try power off the card outside of a transaction */ + bzero(&uci, sizeof (uci)); + uci.uci_version = UCCID_CURRENT_VERSION; + uci.uci_action = UCCID_ICC_POWER_OFF; + if ((ret = ioctl(fd, UCCID_CMD_ICC_MODIFY, &uci)) == 0) { + err(EXIT_FAILURE, "didn't fail to power off ICC"); + } + + + return (0); +} diff --git a/usr/src/test/os-tests/tests/uccid/yk.c b/usr/src/test/os-tests/tests/uccid/yk.c new file mode 100644 index 0000000000..45bdfd059e --- /dev/null +++ b/usr/src/test/os-tests/tests/uccid/yk.c @@ -0,0 +1,78 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2019, Joyent, Inc. + */ + +/* + * Attempt to open a YubiKey class device and get the basic information applet + * through an APDU. + */ + +#include <err.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <strings.h> +#include <unistd.h> +#include <errno.h> + +#include <sys/usb/clients/ccid/uccid.h> + +static const uint8_t yk_req[] = { + 0x00, 0xa4, 0x04, 0x00, 0x07, 0xa0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x01 +}; + +int +main(int argc, char *argv[]) +{ + int fd; + ssize_t ret, i; + uccid_cmd_txn_begin_t begin; + uint8_t buf[UCCID_APDU_SIZE_MAX]; + + if (argc != 2) { + errx(EXIT_FAILURE, "missing required ccid path"); + } + + if ((fd = open(argv[1], O_RDWR)) < 0) { + err(EXIT_FAILURE, "failed to open %s", argv[1]); + } + + bzero(&begin, sizeof (begin)); + begin.uct_version = UCCID_CURRENT_VERSION; + + if (ioctl(fd, UCCID_CMD_TXN_BEGIN, &begin) != 0) { + err(EXIT_FAILURE, "failed to issue begin ioctl"); + } + + if ((ret = write(fd, yk_req, sizeof (yk_req))) < 0) { + err(EXIT_FAILURE, "failed to write data"); + } + + if ((ret = read(fd, buf, sizeof (buf))) < 0) { + err(EXIT_FAILURE, "failed to read data"); + } + + (void) printf("read %d bytes\n", ret); + for (i = 0; i < ret; i++) { + (void) printf("%02x", buf[i]); + if (i == (ret - 1) || (i % 16) == 15) { + (void) printf("\n"); + } else { + (void) printf(" "); + } + } + + return (0); +} |