diff --git a/ccid/ChangeLog b/ccid/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/ccid/INSTALL b/ccid/INSTALL index e7b601a..d3c5b40 100644 --- a/ccid/INSTALL +++ b/ccid/INSTALL @@ -1,19 +1,237 @@ -Installation is simple; type `make install`. If you want to customize the -compilation or install process, you will need to pass variables to make. +Installation Instructions +************************* - DESTDIR prefix for installation - OPENSC_CFLAGS compiler flags for libopensc usage (needed if no - pkg-config is available) - OPENSSL_CFLAGS compiler flags for libssl usage (needed if no - pkg-config is available) - PACE set it to something (e.g. "yes") to enable PACE, make - sure that your openssl is compiled with the OpenPACE - patch +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, +2006, 2007 Free Software Foundation, Inc. -See the Makefile for more details. +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. -Example: - make DESTDIR=/tmp/stage install +Basic Installation +================== + +Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 6. Often, you can also type `make uninstall' to remove the installed + files again. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about. Run `./configure --help' for +details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + +Installation Names +================== + +By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: + + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. -Note: If you want to uninstall the binary, you need to pass the same DESTDIR -to make, for example `make DESTDIR=/tmp/stage uninstall`. diff --git a/ccid/Makefile b/ccid/Makefile deleted file mode 100644 index 7cab1ba..0000000 --- a/ccid/Makefile +++ /dev/null @@ -1,66 +0,0 @@ -MAKEFLAGS += -rR --no-print-directory - -# Directories -prefix = -exec_prefix = $(prefix) -bindir = $(exec_prefix)/bin - - -# Compiler -CC = gcc -CFLAGS = -Wall -g - -OPENSSL_CFLAGS = `pkg-config --cflags --libs libssl` -OPENSC_CFLAGS = `pkg-config --cflags --libs libopensc` -PTHREAD_CFLAGS = -pthread -a_flags = $(CFLAGS) $(OPENSC_CFLAGS) $(PTHREAD_CFLAGS) - -INSTALL = install -INSTALL_PROGRAM = $(INSTALL) - - -TARGETS = ccid -CCID_OBJ = ccid.o usbstring.o usb.o binutil.o scutil.o -PTOOL_OBJ = sm.o pace-tool.o binutil.o scutil.o pace.o pace_lib.o - -ifdef PACE - TARGETS += pace-tool - a_flags += $(OPENSSL_CFLAGS) -else - a_flags += -DNO_PACE -endif - -# top-level rule -all: $(TARGETS) - - -ccid: $(CCID_OBJ) - $(CC) $^ -o $@ $(a_flags) -pace-tool: $(PTOOL_OBJ) - $(CC) $^ -o $@ $(a_flags) -%.o: %.c %.h - $(CC) $< -o $@ -c $(a_flags) -%.o: %.c - $(CC) $< -o $@ -c $(a_flags) - - -install: $(TARGETS) installdirs - $(INSTALL_PROGRAM) ccid $(DESTDIR)$(bindir) - $(INSTALL_PROGRAM) pace-tool $(DESTDIR)$(bindir) - -.PHONY: installdirs -installdirs: - $(INSTALL) -d $(DESTDIR)$(bindir) - -.PHONY: install-strip -install-strip: - $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install - -.PHONY: uninstall -uninstall: - rm -f $(DESTDIR)$(bindir)/ccid - rm -f $(DESTDIR)$(bindir)/pace-tool - -.PHONY: clean -clean: - rm -f $(TARGETS) $(CCID_OBJ) pace-tool $(PTOOL_OBJ) diff --git a/ccid/NEWS b/ccid/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/ccid/configure.ac b/ccid/configure.ac new file mode 100644 index 0000000..7d1839b --- /dev/null +++ b/ccid/configure.ac @@ -0,0 +1,140 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ([2.63]) +AC_INIT([ccid], [0.2], [morgner@informatik.hu-berlin.de]) +AC_CONFIG_SRCDIR([src/ccid.c]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) +AM_INIT_AUTOMAKE + +# Checks for programs. +AC_PROG_CC +AC_PROG_INSTALL +AC_PROG_LN_S +AM_PROG_CC_C_O +PKG_PROG_PKG_CONFIG + +# Checks for libraries. +PKG_CHECK_EXISTS([libopensc], + [PKG_CHECK_MODULES([OPENSC], [libopensc])], + [AC_MSG_WARN([libopensc not found by pkg-config])]) + +saved_CPPFLAGS="$CPPFLAGS" +saved_LIBS="$LIBS" +CPPFLAGS="$CPPFLAGS $OPENSC_CFLAGS" +LIBS="$LDFLAGS $OPENSC_LIBS" +AC_CHECK_HEADERS(opensc/opensc.h,, + [ AC_MSG_ERROR([opensc/opensc.h not found, install libopensc or use ./configure OPENSC_CFLAGS=...]) ]) +AC_MSG_CHECKING([for sc_context_create]) +AC_TRY_LINK_FUNC(sc_context_create, [ AC_MSG_RESULT([yes]) ], + [ AC_MSG_ERROR([libopensc not found, use ./configure OPENSC_LIBS=...]) ]) +CPPFLAGS="$saved_CPPFLAGS" +LIBS="$saved_LIBS" + +# --disable-ccid +AC_ARG_ENABLE(ccid, + AS_HELP_STRING([--disable-ccid], [Disable USB CCID emulator]), + [enable_ccid="${enableval}"], [enable_ccid=yes]) +if test "x$enable_ccid" != xno ; then + AC_CHECK_HEADERS(linux/usb/gadgetfs.h, [], + [ AC_MSG_ERROR([linux/usb/gadgetfs.h not found]) ]) + + ACX_PTHREAD + + saved_CPPFLAGS="$CPPFLAGS" + saved_LIBS="$LIBS" + CPPFLAGS="$CPPFLAGS $PTHREAD_CFLAGS" + LIBS="$LDFLAGS $PTHREAD_LIBS" + + AC_CHECK_HEADERS(pthread.h, [], + [ AC_MSG_ERROR([pthread.h not found, use ./configure PTHREAD_CFLAGS=...]) ]) + AC_MSG_CHECKING([for parse_ef_card_access]) + AC_TRY_LINK_FUNC(pthread_create, [ AC_MSG_RESULT([yes]) ], + [ AC_MSG_ERROR([pthread not found, use ./configure PTHREAD_LIBS=...]) ]) + + CPPFLAGS="$saved_CPPFLAGS" + LIBS="$saved_LIBS" + + enable_ccid=yes +fi +AC_SUBST(PTHREAD_CFLAGS) +AC_SUBST(PTHREAD_LIBS) +AM_CONDITIONAL(WITH_CCID, test "${enable_ccid}" != "no") + +# --enable-pace +AC_ARG_ENABLE(pace, + AS_HELP_STRING([--enable-pace], [Enable Password Authenticated Connection Establishment (PACE)]), + [enable_pace="${enableval}"], [enable_pace=no]) +if test "x$enable_pace" != xno ; then + PKG_CHECK_EXISTS([libssl], + [PKG_CHECK_MODULES([OPENSSL], [libssl])], + [AC_MSG_WARN([libssl not found by pkg-config])]) + + saved_CPPFLAGS="$CPPFLAGS" + saved_LIBS="$LIBS" + CPPFLAGS="$CPPFLAGS $OPENSSL_CFLAGS" + LIBS="$LDFLAGS $OPENSSL_LIBS" + + AC_CHECK_HEADERS(openssl/pace.h, [], [ AC_MSG_ERROR([openssl/pace.h not found, install OpenPACE or use ./configure OPENSSL_CFLAGS=...]) ]) + AC_MSG_CHECKING([for parse_ef_card_access]) + AC_TRY_LINK_FUNC(parse_ef_card_access, [ AC_MSG_RESULT([yes]) ], [ AC_MSG_ERROR([OpenPACE not found, use ./configure OPENSSL_LIBS=...]) ]) + + CPPFLAGS="$saved_CPPFLAGS" + LIBS="$saved_LIBS" + + enable_pace=yes +fi +AC_SUBST(OPENSSL_CFLAGS) +AC_SUBST(OPENSSL_LIBS) +AM_CONDITIONAL(WITH_PACE, test "${enable_pace}" != "no") + + +# Checks for header files. +AC_CHECK_HEADERS([arpa/inet.h fcntl.h memory.h stdint.h stdlib.h string.h sys/ioctl.h unistd.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_INLINE +AC_TYPE_SIZE_T +AC_TYPE_SSIZE_T +AC_TYPE_UINT16_T +AC_TYPE_UINT32_T +AC_TYPE_UINT8_T + +# Checks for library functions. +AC_FUNC_MALLOC +AC_FUNC_REALLOC +AC_CHECK_FUNCS([memmove memset strerror]) + +cat << EOF + +ccid has been configured with following options: + +Version: ${PACKAGE_VERSION} +User binaries: $(eval eval eval echo "${bindir}") +Configuration files: $(eval eval eval echo "${sysconfdir}") + + +Host: ${host} +Compiler: ${CC} +Preprocessor flags: ${CPPFLAGS} +Compiler flags: ${CFLAGS} +Preprocessor flags: ${CPPFLAGS} +Linker flags: ${LDFLAGS} +Libraries: ${LIBS} +PTHREAD_CFLAGS: ${PTHREAD_CFLAGS} +PTHREAD_LIBS: ${PTHREAD_LIBS} +OPENSC_CFLAGS: ${OPENSC_CFLAGS} +OPENSC_LIBS: ${OPENSC_LIBS} +OPENSSL_CFLAGS: ${OPENSSL_CFLAGS} +OPENSSL_LIBS: ${OPENSSL_LIBS} + +ccid support: ${enable_ccid} +pace support: ${enable_pace} + +EOF + +AC_CONFIG_FILES([Makefile + m4/Makefile + src/Makefile]) +AC_OUTPUT diff --git a/ccid/m4/Makefile.am b/ccid/m4/Makefile.am new file mode 100644 index 0000000..58bdc59 --- /dev/null +++ b/ccid/m4/Makefile.am @@ -0,0 +1,3 @@ +# Process this file with automake to create Makefile.in + +EXTRA_DIST = acx_pthread.m4 diff --git a/ccid/m4/acx_pthread.m4 b/ccid/m4/acx_pthread.m4 new file mode 100644 index 0000000..e4e91d3 --- /dev/null +++ b/ccid/m4/acx_pthread.m4 @@ -0,0 +1,242 @@ +dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +dnl +dnl @summary figure out how to build C programs using POSIX threads +dnl +dnl This macro figures out how to build C programs using POSIX threads. +dnl It sets the PTHREAD_LIBS output variable to the threads library and +dnl linker flags, and the PTHREAD_CFLAGS output variable to any special +dnl C compiler flags that are needed. (The user can also force certain +dnl compiler flags/libs to be tested by setting these environment +dnl variables.) +dnl +dnl Also sets PTHREAD_CC to any special C compiler that is needed for +dnl multi-threaded programs (defaults to the value of CC otherwise). +dnl (This is necessary on AIX to use the special cc_r compiler alias.) +dnl +dnl NOTE: You are assumed to not only compile your program with these +dnl flags, but also link it with them as well. e.g. you should link +dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS +dnl $LIBS +dnl +dnl If you are only building threads programs, you may wish to use +dnl these variables in your default LIBS, CFLAGS, and CC: +dnl +dnl LIBS="$PTHREAD_LIBS $LIBS" +dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +dnl CC="$PTHREAD_CC" +dnl +dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute +dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to +dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). +dnl +dnl ACTION-IF-FOUND is a list of shell commands to run if a threads +dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to +dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the +dnl default action will define HAVE_PTHREAD. +dnl +dnl Please let the authors know if this macro fails on any platform, or +dnl if you have any other suggestions or comments. This macro was based +dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with +dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros +dnl posted by Alejandro Forero Cuervo to the autoconf macro repository. +dnl We are also grateful for the helpful feedback of numerous users. +dnl +dnl @category InstalledPackages +dnl @author Steven G. Johnson +dnl @version 2006-05-29 +dnl @license GPLWithACException + +AC_DEFUN([ACX_PTHREAD], [ +AC_REQUIRE([AC_CANONICAL_HOST]) +AC_LANG_SAVE +AC_LANG_C +acx_pthread_ok=no + +# We used to check for pthread.h first, but this fails if pthread.h +# requires special compiler flags (e.g. on True64 or Sequent). +# It gets checked for in the link test anyway. + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) + AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) + AC_MSG_RESULT($acx_pthread_ok) + if test x"$acx_pthread_ok" = xno; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" +fi + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# Create a list of thread flags to try. Items starting with a "-" are +# C compiler flags, and other items are library names, except for "none" +# which indicates that we try without any flags at all, and "pthread-config" +# which is a program returning the flags for the Pth emulation library. + +acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) +# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) +# -pthreads: Solaris/gcc +# -mthreads: Mingw32/gcc, Lynx/gcc +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads too; +# also defines -D_REENTRANT) +# ... -mt is also the pthreads flag for HP/aCC +# pthread: Linux, etcetera +# --thread-safe: KAI C++ +# pthread-config: use pthread-config program (for GNU Pth library) + +case "${host_cpu}-${host_os}" in + *solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (We need to link with -pthreads/-mt/ + # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather + # a function called by this macro, so we could check for that, but + # who knows whether they'll stub that too in a future libc.) So, + # we'll just look for -pthreads and -lpthread first: + + acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags" + ;; +esac + +if test x"$acx_pthread_ok" = xno; then +for flag in $acx_pthread_flags; do + + case $flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; + + -*) + AC_MSG_CHECKING([whether pthreads work with $flag]) + PTHREAD_CFLAGS="$flag" + ;; + + pthread-config) + AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no) + if test x"$acx_pthread_config" = xno; then continue; fi + PTHREAD_CFLAGS="`pthread-config --cflags`" + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; + + *) + AC_MSG_CHECKING([for the pthreads library -l$flag]) + PTHREAD_LIBS="-l$flag" + ;; + esac + + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + AC_TRY_LINK([#include ], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [acx_pthread_ok=yes]) + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + AC_MSG_RESULT($acx_pthread_ok) + if test "x$acx_pthread_ok" = xyes; then + break; + fi + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" +done +fi + +# Various other checks: +if test "x$acx_pthread_ok" = xyes; then + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. + AC_MSG_CHECKING([for joinable pthread attribute]) + attr_name=unknown + for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + AC_TRY_LINK([#include ], [int attr=$attr; return attr;], + [attr_name=$attr; break]) + done + AC_MSG_RESULT($attr_name) + if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then + AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, + [Define to necessary symbol if this constant + uses a non-standard name on your system.]) + fi + + AC_MSG_CHECKING([if more special flags are required for pthreads]) + flag=no + case "${host_cpu}-${host_os}" in + *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; + *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; + esac + AC_MSG_RESULT(${flag}) + if test "x$flag" != xno; then + PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" + fi + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + # More AIX lossage: must compile with xlc_r or cc_r + if test x"$GCC" != xyes; then + AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC}) + else + PTHREAD_CC=$CC + fi +else + PTHREAD_CC="$CC" +fi + +AC_SUBST(PTHREAD_LIBS) +AC_SUBST(PTHREAD_CFLAGS) +AC_SUBST(PTHREAD_CC) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test x"$acx_pthread_ok" = xyes; then + ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) + : +else + acx_pthread_ok=no + $2 +fi +AC_LANG_RESTORE +])dnl ACX_PTHREAD diff --git a/ccid/pace.c b/ccid/pace.c deleted file mode 100644 index 5a34ec7..0000000 --- a/ccid/pace.c +++ /dev/null @@ -1,1230 +0,0 @@ -/* - * Copyright (C) 2010 Frank Morgner - * - * This file is part of ccid. - * - * ccid is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later - * version. - * - * ccid is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * ccid. If not, see . - */ -#include "pace.h" -#include "sm.h" -#include "util.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#define ASN1_APP_EXP_OPT(stname, field, type, tag) ASN1_EX_TYPE(ASN1_TFLG_EXPTAG|ASN1_TFLG_APPLICATION|ASN1_TFLG_OPTIONAL, tag, stname, field, type) - -/* - * MSE:Set AT - */ - -typedef struct pace_mse_set_at_cd_st { - ASN1_OBJECT *cryptographic_mechanism_reference; - ASN1_INTEGER *key_reference1; - ASN1_INTEGER *key_reference2; - ASN1_OCTET_STRING *auxiliary_data; - ASN1_OCTET_STRING *eph_pub_key; - ASN1_OCTET_STRING *cha_template; -} PACE_MSE_SET_AT_C; -ASN1_SEQUENCE(PACE_MSE_SET_AT_C) = { - /* 0x80 - * Cryptographic mechanism reference */ - ASN1_IMP_OPT(PACE_MSE_SET_AT_C, cryptographic_mechanism_reference, ASN1_OBJECT, 0), - /* 0x83 - * Reference of a public key / secret key */ - ASN1_IMP_OPT(PACE_MSE_SET_AT_C, key_reference1, ASN1_INTEGER, 3), - /* 0x84 - * Reference of a private key / Reference for computing a session key */ - ASN1_IMP_OPT(PACE_MSE_SET_AT_C, key_reference2, ASN1_INTEGER, 4), - /* 0x67 - * Auxiliary authenticated data */ - ASN1_APP_EXP_OPT(PACE_MSE_SET_AT_C, auxiliary_data, ASN1_OCTET_STRING, 7), - /* 0x91 - * Ephemeral Public Key */ - ASN1_IMP_OPT(PACE_MSE_SET_AT_C, eph_pub_key, ASN1_OCTET_STRING, 0x11), - /* 0x7F4C - * Certificate Holder Authorization Template */ - ASN1_APP_EXP_OPT(PACE_MSE_SET_AT_C, cha_template, ASN1_OCTET_STRING, 0x4c), -} ASN1_SEQUENCE_END(PACE_MSE_SET_AT_C) -IMPLEMENT_ASN1_FUNCTIONS(PACE_MSE_SET_AT_C) - - -/* - * General Authenticate - */ - -/* Protocol Command Data */ -typedef struct pace_gen_auth_cd_st { - ASN1_OCTET_STRING *mapping_data; - ASN1_OCTET_STRING *eph_pub_key; - ASN1_OCTET_STRING *auth_token; -} PACE_GEN_AUTH_C_BODY; -ASN1_SEQUENCE(PACE_GEN_AUTH_C_BODY) = { - /* 0x81 - * Mapping Data */ - ASN1_IMP_OPT(PACE_GEN_AUTH_C_BODY, mapping_data, ASN1_OCTET_STRING, 1), - /* 0x83 - * Ephemeral Public Key */ - ASN1_IMP_OPT(PACE_GEN_AUTH_C_BODY, eph_pub_key, ASN1_OCTET_STRING, 3), - /* 0x85 - * Authentication Token */ - ASN1_IMP_OPT(PACE_GEN_AUTH_C_BODY, auth_token, ASN1_OCTET_STRING, 5), -} ASN1_SEQUENCE_END(PACE_GEN_AUTH_C_BODY) -IMPLEMENT_ASN1_FUNCTIONS(PACE_GEN_AUTH_C_BODY) - -typedef PACE_GEN_AUTH_C_BODY PACE_GEN_AUTH_C; -/* 0x7C - * Dynamic Authentication Data */ -ASN1_ITEM_TEMPLATE(PACE_GEN_AUTH_C) = - ASN1_EX_TEMPLATE_TYPE( - ASN1_TFLG_IMPTAG|ASN1_TFLG_APPLICATION, - 0x1c, PACE_GEN_AUTH_C, PACE_GEN_AUTH_C_BODY) -ASN1_ITEM_TEMPLATE_END(PACE_GEN_AUTH_C) -IMPLEMENT_ASN1_FUNCTIONS(PACE_GEN_AUTH_C) - -/* Protocol Response Data */ -typedef struct pace_gen_auth_rapdu_body_st { - ASN1_OCTET_STRING *enc_nonce; - ASN1_OCTET_STRING *mapping_data; - ASN1_OCTET_STRING *eph_pub_key; - ASN1_OCTET_STRING *auth_token; - ASN1_OCTET_STRING *cert_auth1; - ASN1_OCTET_STRING *cert_auth2; -} PACE_GEN_AUTH_R_BODY; -ASN1_SEQUENCE(PACE_GEN_AUTH_R_BODY) = { - /* 0x80 - * Encrypted Nonce */ - ASN1_IMP_OPT(PACE_GEN_AUTH_R_BODY, enc_nonce, ASN1_OCTET_STRING, 0), - /* 0x82 - * Mapping Data */ - ASN1_IMP_OPT(PACE_GEN_AUTH_R_BODY, mapping_data, ASN1_OCTET_STRING, 2), - /* 0x84 - * Ephemeral Public Key */ - ASN1_IMP_OPT(PACE_GEN_AUTH_R_BODY, eph_pub_key, ASN1_OCTET_STRING, 4), - /* 0x86 - * Authentication Token */ - ASN1_IMP_OPT(PACE_GEN_AUTH_R_BODY, auth_token, ASN1_OCTET_STRING, 6), - /* 0x87 - * Certification Authority Reference */ - ASN1_IMP_OPT(PACE_GEN_AUTH_R_BODY, cert_auth1, ASN1_OCTET_STRING, 7), - /* 0x88 - * Certification Authority Reference */ - ASN1_IMP_OPT(PACE_GEN_AUTH_R_BODY, cert_auth2, ASN1_OCTET_STRING, 8), -} ASN1_SEQUENCE_END(PACE_GEN_AUTH_R_BODY) -IMPLEMENT_ASN1_FUNCTIONS(PACE_GEN_AUTH_R_BODY) - -typedef PACE_GEN_AUTH_R_BODY PACE_GEN_AUTH_R; -/* 0x7C - * Dynamic Authentication Data */ -ASN1_ITEM_TEMPLATE(PACE_GEN_AUTH_R) = - ASN1_EX_TEMPLATE_TYPE( - ASN1_TFLG_IMPTAG|ASN1_TFLG_APPLICATION, - 0x1c, PACE_GEN_AUTH_R, PACE_GEN_AUTH_R_BODY) -ASN1_ITEM_TEMPLATE_END(PACE_GEN_AUTH_R) -IMPLEMENT_ASN1_FUNCTIONS(PACE_GEN_AUTH_R) - - - -const size_t maxresp = SC_MAX_APDU_BUFFER_SIZE - 2; - -int GetReadersPACECapabilities(sc_card_t *card, - const __u8 *in, __u8 **out, size_t *outlen) { - if (!out || !outlen) - SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_INVALID_ARGUMENTS); - - __u8 *result = realloc(*out, 2); - if (!result) - SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_OUT_OF_MEMORY); - *out = result; - *outlen = 2; - - /* lengthBitMap */ - *result = 1; - result++; - /* BitMap */ - *result = PACE_BITMAP_PACE|PACE_BITMAP_EID; - - SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, SC_SUCCESS); -} - -/** select and read EF.CardAccess */ -static int get_ef_card_access(sc_card_t *card, - __u8 **ef_cardaccess, size_t *length_ef_cardaccess) -{ - int r; - /* we read less bytes than possible. this is a workaround for acr 122, - * which only supports apdus of max 250 bytes */ - size_t read = maxresp - 8; - sc_path_t path; - sc_file_t *file = NULL; - __u8 *p; - - memset(&path, 0, sizeof path); - r = sc_append_file_id(&path, FID_EF_CARDACCESS); - if (r < 0) { - sc_error(card->ctx, "Could not create path object."); - goto err; - } - r = sc_concatenate_path(&path, sc_get_mf_path(), &path); - if (r < 0) { - sc_error(card->ctx, "Could not create path object."); - goto err; - } - - r = sc_select_file(card, &path, &file); - if (r < 0) { - sc_error(card->ctx, "Could not select EF.CardAccess."); - goto err; - } - - *length_ef_cardaccess = 0; - while(1) { - p = realloc(*ef_cardaccess, *length_ef_cardaccess + read); - if (!p) { - r = SC_ERROR_OUT_OF_MEMORY; - goto err; - } - *ef_cardaccess = p; - - r = sc_read_binary(card, *length_ef_cardaccess, - *ef_cardaccess + *length_ef_cardaccess, read, 0); - - if (r > 0 && r != read) { - *length_ef_cardaccess += r; - break; - } - - if (r < 0) { - sc_error(card->ctx, "Could not read EF.CardAccess."); - goto err; - } - - *length_ef_cardaccess += r; - } - - /* test cards only return an empty FCI template, - * so we can't determine any file proberties */ - if (*length_ef_cardaccess < file->size) { - r = SC_ERROR_FILE_TOO_SMALL; - goto err; - } - - r = SC_SUCCESS; - -err: - if (file) { - free(file); - } - - SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, r); -} - -static int pace_mse_set_at(sc_card_t *card, - int protocol, int secret_key, int reference) -{ - sc_apdu_t apdu; - unsigned char *d = NULL; - PACE_MSE_SET_AT_C *data = NULL; - int r; - - memset(&apdu, 0, sizeof apdu); - apdu.ins = 0x22; - apdu.p1 = 0xc1; - apdu.p2 = 0xa4; - apdu.cse = SC_APDU_CASE_3; - apdu.flags = SC_APDU_FLAGS_NO_GET_RESP|SC_APDU_FLAGS_NO_RETRY_WL; - - data = PACE_MSE_SET_AT_C_new(); - if (!data) { - r = SC_ERROR_OUT_OF_MEMORY; - goto err; - } - data->cryptographic_mechanism_reference = OBJ_nid2obj(protocol); - data->key_reference1 = ASN1_INTEGER_new(); - //data->key_reference2 = ASN1_INTEGER_new(); - if (!data->cryptographic_mechanism_reference - || !data->key_reference1 - //|| !data->key_reference2 - ) { - r = SC_ERROR_OUT_OF_MEMORY; - goto err; - } - if (!ASN1_INTEGER_set(data->key_reference1, secret_key) - //|| !ASN1_INTEGER_set(data->key_reference2, reference) - ) { - r = SC_ERROR_INTERNAL; - goto err; - } - r = i2d_PACE_MSE_SET_AT_C(data, &d); - if (r < 0) { - r = SC_ERROR_INTERNAL; - goto err; - } - /* The tag/length for the sequence (0x30) is omitted in the command apdu. */ - /* FIXME is there a OpenSSL way to get the value only or even a define for - * the tag? */ - apdu.data = sc_asn1_find_tag(card->ctx, d, r, 0x30, &apdu.datalen); - apdu.lc = apdu.datalen; - - bin_log(card->ctx, "MSE:Set AT command data", apdu.data, apdu.datalen); - - r = sc_transmit_apdu(card, &apdu); - if (r < 0) - goto err; - - if (apdu.resplen) { - sc_error(card->ctx, "MSE:Set AT response data should be empty"); - r = SC_ERROR_UNKNOWN_DATA_RECEIVED; - goto err; - } - - if (apdu.sw1 == 0x63) { - if ((apdu.sw2 & 0xc0) == 0xc0) { - sc_error(card->ctx, "Verification failed (remaining tries: %d%s)\n", - apdu.sw2 & 0x0f, - (apdu.sw2 & 0x0f) == 1? ", password must be resumed": (apdu.sw2 & 0x0f) == 0? ", password must be unblocked": - ""); - /* this is only a warning */ - r = SC_SUCCESS; - } else { - sc_error(card->ctx, "Unknown SWs; SW1=%02X, SW2=%02X\n", - apdu.sw1, apdu.sw2); - r = SC_ERROR_CARD_CMD_FAILED; - goto err; - } - } else if (apdu.sw1 == 0x62 && apdu.sw2 == 0x83) { - sc_error(card->ctx, "Password is deactivated\n"); - r = SC_ERROR_AUTH_METHOD_BLOCKED; - goto err; - } else { - r = sc_check_sw(card, apdu.sw1, apdu.sw2); - } - -err: - if (apdu.resp) - free(apdu.resp); - if (data) { - // XXX - //if (data->cryptographic_mechanism_reference) - //ASN1_OBJECT_free(data->cryptographic_mechanism_reference); - //if (data->key_reference1) - //ASN1_INTEGER_free(data->key_reference1); - //if (data->key_reference2) - //ASN1_INTEGER_free(data->key_reference2); - PACE_MSE_SET_AT_C_free(data); - } - if (d) - free(d); - - SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, r); -} - -static int pace_gen_auth(sc_card_t *card, - int step, const u8 *in, size_t in_len, u8 **out, size_t *out_len) -{ - sc_apdu_t apdu; - PACE_GEN_AUTH_C *c_data = NULL; - PACE_GEN_AUTH_R *r_data = NULL; - unsigned char *d = NULL, *p; - int r, l; - - memset(&apdu, 0, sizeof apdu); - apdu.cla = 0x10; - apdu.ins = 0x86; - apdu.cse = SC_APDU_CASE_4; - apdu.flags = SC_APDU_FLAGS_NO_GET_RESP|SC_APDU_FLAGS_NO_RETRY_WL; - - c_data = PACE_GEN_AUTH_C_new(); - if (!c_data) { - r = SC_ERROR_OUT_OF_MEMORY; - goto err; - } - switch (step) { - case 1: - break; - case 2: - c_data->mapping_data = ASN1_OCTET_STRING_new(); - if (!c_data->mapping_data - || !M_ASN1_OCTET_STRING_set( - c_data->mapping_data, in, in_len)) { - r = SC_ERROR_INTERNAL; - goto err; - } - break; - case 3: - c_data->eph_pub_key = ASN1_OCTET_STRING_new(); - if (!c_data->eph_pub_key - || !M_ASN1_OCTET_STRING_set( - c_data->eph_pub_key, in, in_len)) { - r = SC_ERROR_INTERNAL; - goto err; - } - break; - case 4: - apdu.cla = 0; - c_data->auth_token = ASN1_OCTET_STRING_new(); - if (!c_data->auth_token - || !M_ASN1_OCTET_STRING_set( - c_data->auth_token, in, in_len)) { - r = SC_ERROR_INTERNAL; - goto err; - } - break; - default: - r = SC_ERROR_INVALID_ARGUMENTS; - goto err; - } - r = i2d_PACE_GEN_AUTH_C(c_data, &d); - if (r < 0) { - r = SC_ERROR_INTERNAL; - goto err; - } - apdu.data = (const u8 *) d; - apdu.datalen = r; - apdu.lc = r; - - bin_log(card->ctx, "General authenticate command data", apdu.data, apdu.datalen); - - /* sanity checks in sc_transmit_apdu forbid case 4 apdus with le == 0 */ - apdu.resplen = maxresp; - apdu.resp = malloc(apdu.resplen); - r = sc_transmit_apdu(card, &apdu); - if (r < 0) - goto err; - - r = sc_check_sw(card, apdu.sw1, apdu.sw2); - if (r < 0) - goto err; - - bin_log(card->ctx, "General authenticate response data", apdu.resp, apdu.resplen); - - if (!d2i_PACE_GEN_AUTH_R(&r_data, - (const unsigned char **) &apdu.resp, apdu.resplen)) { - sc_error(card->ctx, "Could not parse general authenticate response data."); - r = SC_ERROR_INTERNAL; - goto err; - } - - switch (step) { - case 1: - if (!r_data->enc_nonce - || r_data->mapping_data - || r_data->eph_pub_key - || r_data->auth_token) { - sc_error(card->ctx, "Response data of general authenticate for " - "step %d should (only) contain the " - "encrypted nonce.", step); - r = SC_ERROR_UNKNOWN_DATA_RECEIVED; - goto err; - } - p = r_data->enc_nonce->data; - l = r_data->enc_nonce->length; - break; - case 2: - if (r_data->enc_nonce - || !r_data->mapping_data - || r_data->eph_pub_key - || r_data->auth_token) { - sc_error(card->ctx, "Response data of general authenticate for " - "step %d should (only) contain the " - "mapping data.", step); - r = SC_ERROR_UNKNOWN_DATA_RECEIVED; - goto err; - } - p = r_data->mapping_data->data; - l = r_data->mapping_data->length; - break; - case 3: - if (r_data->enc_nonce - || r_data->mapping_data - || !r_data->eph_pub_key - || r_data->auth_token) { - sc_error(card->ctx, "Response data of general authenticate for " - "step %d should (only) contain the " - "ephemeral public key.", step); - r = SC_ERROR_UNKNOWN_DATA_RECEIVED; - goto err; - } - p = r_data->eph_pub_key->data; - l = r_data->eph_pub_key->length; - break; - case 4: - if (r_data->enc_nonce - || r_data->mapping_data - || r_data->eph_pub_key - || !r_data->auth_token) { - sc_error(card->ctx, "Response data of general authenticate for " - "step %d should (only) contain the " - "authentication token.", step); - r = SC_ERROR_UNKNOWN_DATA_RECEIVED; - goto err; - } - p = r_data->auth_token->data; - l = r_data->auth_token->length; - break; - default: - r = SC_ERROR_INVALID_ARGUMENTS; - goto err; - } - - *out = malloc(l); - if (!*out) { - r = SC_ERROR_OUT_OF_MEMORY; - goto err; - } - memcpy(*out, p, l); - *out_len = l; - -err: - if (c_data) { - /* FIXME - if (c_data->mapping_data) - ASN1_OCTET_STRING_free(c_data->mapping_data); - if (c_data->eph_pub_key) - ASN1_OCTET_STRING_free(c_data->eph_pub_key); - if (c_data->auth_token) - ASN1_OCTET_STRING_free(c_data->auth_token);*/ - PACE_GEN_AUTH_C_free(c_data); - } - if (d) - free(d); - if (r_data) { - /* FIXME - if (r_data->mapping_data) - ASN1_OCTET_STRING_free(r_data->mapping_data); - if (r_data->eph_pub_key) - ASN1_OCTET_STRING_free(r_data->eph_pub_key); - if (r_data->auth_token) - ASN1_OCTET_STRING_free(r_data->auth_token);*/ - PACE_GEN_AUTH_R_free(r_data); - } - /* XXX */ - /*if (apdu.resp)*/ - /*free(apdu.resp);*/ - - SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, r); -} - -int -pace_reset_retry_counter(struct sm_ctx *ctx, sc_card_t *card, - enum s_type pin_id, const char *new, size_t new_len) -{ - sc_apdu_t apdu; - - memset(&apdu, 0, sizeof apdu); - apdu.ins = 0x2C; - apdu.p2 = pin_id; - apdu.data = (u8 *) new; - apdu.datalen = new_len; - apdu.lc = apdu.datalen; - apdu.flags = SC_APDU_FLAGS_NO_GET_RESP|SC_APDU_FLAGS_NO_RETRY_WL; - - if (new_len) { - apdu.p1 = 0x02; - apdu.cse = SC_APDU_CASE_3_SHORT; - } else { - apdu.p1 = 0x03; - apdu.cse = SC_APDU_CASE_1; - } - - return pace_transmit_apdu(ctx, card, &apdu); -} - -static PACE_SEC * -get_psec(sc_card_t *card, const char *pin, size_t length_pin, enum s_type pin_id) -{ - sc_ui_hints_t hints; - char *p = NULL; - PACE_SEC *r; - int sc_result; - - if (!length_pin || !pin) { - memset(&hints, 0, sizeof(hints)); - hints.dialog_name = "ccid.PACE"; - hints.card = card; - hints.prompt = NULL; - hints.obj_label = pace_secret_name(pin_id); - hints.usage = SC_UI_USAGE_OTHER; - sc_result = sc_ui_get_pin(&hints, &p); - if (sc_result < 0) { - sc_error(card->ctx, "Could not read PACE secret (%s).\n", - sc_strerror(sc_result)); - return NULL; - } - length_pin = strlen(p); - pin = p; - } - - r = PACE_SEC_new(pin, length_pin, pin_id); - - if (p) { - OPENSSL_cleanse(p, length_pin); - free(p); - } - - return r; -} - -void debug_ossl(sc_context_t *ctx) { - unsigned long r; - for (r = ERR_get_error(); r; r = ERR_get_error()) { - sc_error(ctx, ERR_error_string(r, NULL)); - } -} - -int EstablishPACEChannel(sc_card_t *card, const __u8 *in, - __u8 **out, size_t *outlen, struct sm_ctx *sctx) -{ - __u8 pin_id; - size_t length_chat, length_pin, length_cert_desc, length_ef_cardaccess; - const __u8 *chat, *pin, *certificate_description; - __u8 *ef_cardaccess = NULL; - PACEInfo *info = NULL; - PACEDomainParameterInfo *static_dp = NULL, *eph_dp = NULL; - BUF_MEM *enc_nonce, *nonce = NULL, *mdata = NULL, *mdata_opp = NULL, - *k_enc = NULL, *k_mac = NULL, *token_opp = NULL, - *token = NULL, *pub = NULL, *pub_opp = NULL, *key = NULL; - PACE_SEC *sec = NULL; - PACE_CTX *pctx = NULL; - int r; - - if (!in || !out || !outlen) - SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_INVALID_ARGUMENTS); - - pin_id = *in; - in++; - - length_chat = *in; - in++; - chat = in; - in += length_chat; - - length_pin = *in; - in++; - pin = in; - in += length_pin; - - length_cert_desc = (__le16_to_cpu((__le16) *in)); - in += sizeof (__le16); - certificate_description = in; - - enc_nonce = BUF_MEM_new(); - if (!enc_nonce) { - r = SC_ERROR_INTERNAL; - debug_ossl(card->ctx); - goto err; - } - r = get_ef_card_access(card, &ef_cardaccess, &length_ef_cardaccess); - if (r < 0) { - sc_error(card->ctx, "Could not get EF.CardAccess."); - goto err; - } - bin_log(card->ctx, "EF.CardAccess", ef_cardaccess, length_ef_cardaccess); - if (!parse_ef_card_access(ef_cardaccess, length_ef_cardaccess, - &info, &static_dp)) { - r = SC_ERROR_INTERNAL; - debug_ossl(card->ctx); - sc_error(card->ctx, "Could not parse EF.CardAccess."); - goto err; - } - r = pace_mse_set_at(card, info->protocol, pin_id, 1); - if (r < 0) { - sc_error(card->ctx, "Could not select protocol proberties " - "(MSE: Set AT)."); - goto err; - } - r = pace_gen_auth(card, 1, NULL, 0, (u8 **) &enc_nonce->data, - &enc_nonce->length); - if (r < 0) { - sc_error(card->ctx, "Could not get encrypted nonce from card " - "(General Authenticate step 1 failed)."); - goto err; - } - bin_log(card->ctx, "Encrypted nonce from MRTD", (u8 *)enc_nonce->data, enc_nonce->length); - enc_nonce->max = enc_nonce->length; - - sec = get_psec(card, (char *) pin, length_pin, pin_id); - if (!sec) { - r = SC_ERROR_INTERNAL; - debug_ossl(card->ctx); - goto err; - } - pctx = PACE_CTX_new(); - if (!pctx || !PACE_CTX_init(pctx, info)) { - r = SC_ERROR_INTERNAL; - debug_ossl(card->ctx); - goto err; - } - pctx->tr_version = PACE_TR_VERSION_2_01; - - nonce = PACE_STEP2_dec_nonce(sec, enc_nonce, pctx); - - mdata_opp = BUF_MEM_new(); - mdata = PACE_STEP3A_generate_mapping_data(static_dp, pctx); - if (!nonce || !mdata || !mdata_opp) { - r = SC_ERROR_INTERNAL; - debug_ossl(card->ctx); - goto err; - } - r = pace_gen_auth(card, 2, (u8 *) mdata->data, mdata->length, - (u8 **) &mdata_opp->data, &mdata_opp->length); - if (r < 0) { - sc_error(card->ctx, "Could not exchange mapping data with card " - "(General Authenticate step 2 failed)."); - goto err; - } - mdata_opp->max = mdata_opp->length; - bin_log(card->ctx, "Mapping data from MRTD", (u8 *) mdata_opp->data, mdata_opp->length); - - eph_dp = PACE_STEP3A_map_dp(static_dp, pctx, nonce, mdata_opp); - pub = PACE_STEP3B_generate_ephemeral_key(eph_dp, pctx); - pub_opp = BUF_MEM_new(); - if (!eph_dp || !pub || !pub_opp) { - r = SC_ERROR_INTERNAL; - debug_ossl(card->ctx); - goto err; - } - r = pace_gen_auth(card, 3, (u8 *) pub->data, pub->length, - (u8 **) &pub_opp->data, &pub_opp->length); - if (r < 0) { - sc_error(card->ctx, "Could not exchange ephemeral public key with card " - "(General Authenticate step 3 failed)."); - goto err; - } - pub_opp->max = pub_opp->length; - bin_log(card->ctx, "Public key from MRTD", (u8 *) pub_opp->data, pub_opp->length); - - key = PACE_STEP3B_compute_ephemeral_key(eph_dp, pctx, pub_opp); - if (!key || - !PACE_STEP3C_derive_keys(key, pctx, info, &k_mac, &k_enc)) { - r = SC_ERROR_INTERNAL; - debug_ossl(card->ctx); - goto err; - } - token = PACE_STEP3D_compute_authentication_token(pctx, - eph_dp, info, pub_opp, k_mac); - token_opp = BUF_MEM_new(); - if (!token || !token_opp) { - r = SC_ERROR_INTERNAL; - debug_ossl(card->ctx); - goto err; - } - r = pace_gen_auth(card, 4, (u8 *) token->data, token->length, - (u8 **) &token_opp->data, &token_opp->length); - if (r < 0) { - sc_error(card->ctx, "Could not exchange authentication token with card " - "(General Authenticate step 4 failed)."); - goto err; - } - token_opp->max = token_opp->length; - - if (!PACE_STEP3D_verify_authentication_token(pctx, - eph_dp, info, k_mac, token_opp)) { - r = SC_ERROR_INTERNAL; - debug_ossl(card->ctx); - goto err; - } - - /* XXX parse CHAT to check role of terminal */ - - sctx->authenticate = pace_sm_authenticate; - sctx->encrypt = pace_sm_encrypt; - sctx->decrypt = pace_sm_decrypt; - sctx->verify_authentication = pace_sm_verify_authentication; - sctx->padding_indicator = SM_ISO_PADDING; - sctx->block_length = EVP_CIPHER_block_size(pctx->cipher); - sctx->authentication_ctx = pace_sm_ctx_create(k_mac, - k_enc, pctx); - sctx->cipher_ctx = sctx->authentication_ctx; - if (!sctx->authentication_ctx) { - r = SC_ERROR_OUT_OF_MEMORY; - goto err; - } - r = reset_ssc(sctx->authentication_ctx); - -err: - if (ef_cardaccess) - free(ef_cardaccess); - if (info) - PACEInfo_free(info); - if (static_dp) - PACEDomainParameterInfo_clear_free(static_dp); - if (eph_dp) - PACEDomainParameterInfo_clear_free(eph_dp); - if (enc_nonce) - BUF_MEM_free(enc_nonce); - if (nonce) { - OPENSSL_cleanse(nonce->data, nonce->length); - BUF_MEM_free(nonce); - } - if (mdata) - BUF_MEM_free(mdata); - if (mdata_opp) - BUF_MEM_free(mdata_opp); - if (token_opp) - BUF_MEM_free(token_opp); - if (token) - BUF_MEM_free(token); - if (pub) - BUF_MEM_free(pub); - if (pub_opp) - BUF_MEM_free(pub_opp); - if (key) { - OPENSSL_cleanse(key->data, key->length); - BUF_MEM_free(key); - } - if (sec) - PACE_SEC_clean_free(sec); - - if (r < 0) { - if (k_enc) { - OPENSSL_cleanse(k_enc->data, k_enc->length); - BUF_MEM_free(k_enc); - } - if (k_mac) { - OPENSSL_cleanse(k_mac->data, k_mac->length); - BUF_MEM_free(k_mac); - } - if (pctx) - PACE_CTX_clear_free(pctx); - if (sctx->authentication_ctx) - pace_sm_ctx_free(sctx->authentication_ctx); - } - - SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, r); -} - -static const char *MRZ_name = "MRZ"; -static const char *PIN_name = "PIN"; -static const char *PUK_name = "PUK"; -static const char *CAN_name = "CAN"; -static const char *UNDEF_name = "UNDEF"; -const char *pace_secret_name(enum s_type pin_id) { - switch (pin_id) { - case PACE_MRZ: - return MRZ_name; - case PACE_PUK: - return PUK_name; - case PACE_PIN: - return PIN_name; - case PACE_CAN: - return CAN_name; - default: - return UNDEF_name; - } -} - -static int -encode_ssc(const BIGNUM *ssc, const PACE_CTX *ctx, u8 **encoded) -{ - u8 *p; - size_t en_len, bn_len; - - if (!ctx) - return SC_ERROR_INVALID_ARGUMENTS; - - en_len = EVP_CIPHER_block_size(ctx->cipher); - p = realloc(*encoded, en_len); - if (!p) - return SC_ERROR_OUT_OF_MEMORY; - *encoded = p; - - bn_len = BN_num_bytes(ssc); - - if (bn_len <= en_len) { - memset(*encoded, 0, en_len - bn_len); - BN_bn2bin(ssc, *encoded + en_len - bn_len); - } else { - p = malloc(bn_len); - if (!p) - return SC_ERROR_OUT_OF_MEMORY; - BN_bn2bin(ssc, p); - memcpy(*encoded, p + bn_len - en_len, en_len); - free(p); - } - - return en_len; -} - -static int -update_iv(struct pace_sm_ctx *psmctx) -{ - BUF_MEM *sscbuf = NULL, *ivbuf = NULL; - const EVP_CIPHER *ivcipher = NULL, *oldcipher; - u8 *ssc = NULL; - unsigned char *p; - int r; - - if (!psmctx) - return SC_ERROR_INVALID_ARGUMENTS; - - switch (EVP_CIPHER_nid(psmctx->ctx->cipher)) { - case NID_aes_128_cbc: - if (!ivcipher) - ivcipher = EVP_aes_128_ecb(); - /* fall through */ - case NID_aes_192_cbc: - if (!ivcipher) - ivcipher = EVP_aes_192_ecb(); - /* fall through */ - case NID_aes_256_cbc: - if (!ivcipher) - ivcipher = EVP_aes_256_ecb(); - - /* For AES decryption the IV is not needed, - * so we always set it to the encryption IV=E(K_Enc, SSC) */ - r = encode_ssc(psmctx->ssc, psmctx->ctx, &ssc); - if (r < 0) - goto err; - sscbuf = BUF_MEM_create_init(ssc, r); - if (!sscbuf) { - r = SC_ERROR_OUT_OF_MEMORY; - goto err; - } - oldcipher = psmctx->ctx->cipher; - psmctx->ctx->cipher = ivcipher; - ivbuf = PACE_encrypt(psmctx->ctx, psmctx->key_enc, sscbuf); - psmctx->ctx->cipher = oldcipher; - if (!ivbuf) { - r = SC_ERROR_INTERNAL; - goto err; - } - p = realloc(psmctx->ctx->iv, ivbuf->length); - if (!p) { - r = SC_ERROR_OUT_OF_MEMORY; - goto err; - } - psmctx->ctx->iv = p; - memcpy(psmctx->ctx->iv, ivbuf->data, ivbuf->length); - break; - case NID_des_ede_cbc: - /* For 3DES encryption or decryption the IV is always NULL */ - free(psmctx->ctx->iv); - psmctx->ctx->iv = NULL; - break; - default: - r = SC_ERROR_INVALID_ARGUMENTS; - goto err; - } - - r = SC_SUCCESS; - -err: - if (ssc) - free(ssc); - if (sscbuf) - BUF_MEM_free(sscbuf); - if (ivbuf) - BUF_MEM_free(ivbuf); - - return r; -} - -int -increment_ssc(struct pace_sm_ctx *psmctx) -{ - if (!psmctx) - return SC_ERROR_INVALID_ARGUMENTS; - - BN_add_word(psmctx->ssc, 1); - - return update_iv(psmctx); -} - -int -decrement_ssc(struct pace_sm_ctx *psmctx) -{ - if (!psmctx) - return SC_ERROR_INVALID_ARGUMENTS; - - BN_sub_word(psmctx->ssc, 1); - - return update_iv(psmctx); -} - -int -reset_ssc(struct pace_sm_ctx *psmctx) -{ - if (!psmctx) - return SC_ERROR_INVALID_ARGUMENTS; - - BN_zero(psmctx->ssc); - - return update_iv(psmctx); -} - -int pace_sm_encrypt(sc_card_t *card, const struct sm_ctx *ctx, - const u8 *data, size_t datalen, u8 **enc) -{ - BUF_MEM *encbuf = NULL, *databuf = NULL; - u8 *p = NULL; - int r; - - if (!ctx || !enc || !ctx->cipher_ctx) { - r = SC_ERROR_INVALID_ARGUMENTS; - goto err; - } - struct pace_sm_ctx *psmctx = ctx->cipher_ctx; - - /* The send sequence counter is extended to the block length of the cipher, - * so it is no problem that we get padded data */ - databuf = BUF_MEM_create_init(data, datalen); - encbuf = PACE_encrypt(psmctx->ctx, psmctx->key_enc, databuf); - if (!databuf || !encbuf) { - r = SC_ERROR_INTERNAL; - goto err; - } - - if (!encbuf) { - r = SC_ERROR_INTERNAL; - goto err; - } - - p = realloc(*enc, encbuf->length); - if (!p) { - r = SC_ERROR_OUT_OF_MEMORY; - goto err; - } - *enc = p; - memcpy(*enc, encbuf->data, encbuf->length); - r = encbuf->length; - -err: - if (databuf) { - OPENSSL_cleanse(databuf->data, databuf->max); - BUF_MEM_free(databuf); - } - if (encbuf) - BUF_MEM_free(encbuf); - - SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, r); -} - -int pace_sm_decrypt(sc_card_t *card, const struct sm_ctx *ctx, - const u8 *enc, size_t enclen, u8 **data) -{ - BUF_MEM *encbuf = NULL, *databuf = NULL; - u8 *p = NULL; - int r; - - if (!ctx || !enc || !ctx->cipher_ctx) { - r = SC_ERROR_INVALID_ARGUMENTS; - goto err; - } - struct pace_sm_ctx *psmctx = ctx->cipher_ctx; - - encbuf = BUF_MEM_create_init(enc, enclen); - databuf = PACE_decrypt(psmctx->ctx, psmctx->key_enc, encbuf); - if (!encbuf || !databuf) { - r = SC_ERROR_INTERNAL; - goto err; - } - - p = realloc(*data, databuf->length); - if (!p) { - r = SC_ERROR_OUT_OF_MEMORY; - goto err; - } - *data = p; - memcpy(*data, databuf->data, databuf->length); - r = databuf->length; - -err: - if (databuf) { - OPENSSL_cleanse(databuf->data, databuf->max); - BUF_MEM_free(databuf); - } - if (encbuf) - BUF_MEM_free(encbuf); - - SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, r); -} - -int pace_sm_authenticate(sc_card_t *card, const struct sm_ctx *ctx, - const u8 *data, size_t datalen, u8 **macdata) -{ - BUF_MEM *databuf = NULL, *macbuf = NULL; - u8 *p = NULL, *ssc = NULL; - int r; - - if (!ctx || !ctx->cipher_ctx) { - r = SC_ERROR_INVALID_ARGUMENTS; - goto err; - } - struct pace_sm_ctx *psmctx = ctx->cipher_ctx; - - r = encode_ssc(psmctx->ssc, psmctx->ctx, &ssc); - if (r < 0) { - sc_error(card->ctx, "Could not get send sequence counter\n"); - goto err; - } - bin_log(card->ctx, "Encoded Send Sequence Counter", - ssc, r); - - databuf = BUF_MEM_create(r + datalen); - if (!databuf) { - r = SC_ERROR_OUT_OF_MEMORY; - goto err; - } - memcpy(databuf->data, ssc, r); - memcpy(databuf->data + r, data, datalen); - databuf->length = r + datalen; - bin_log(card->ctx, "Data to authenticate (PACE)", - (u8 *) databuf->data, databuf->length); - - macbuf = PACE_authenticate(psmctx->ctx, psmctx->key_mac, databuf); - if (!macbuf) { - sc_error(card->ctx, "Could not get MAC\n"); - r = SC_ERROR_INTERNAL; - goto err; - } - - p = realloc(*macdata, macbuf->length); - if (!p) { - r = SC_ERROR_OUT_OF_MEMORY; - goto err; - } - *macdata = p; - memcpy(*macdata, macbuf->data, macbuf->length); - r = macbuf->length; - -err: - if (databuf) { - OPENSSL_cleanse(databuf->data, databuf->max); - BUF_MEM_free(databuf); - } - if (macbuf) - BUF_MEM_free(macbuf); - if (ssc) - free(ssc); - - SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, r); -} - -int pace_sm_verify_authentication(sc_card_t *card, const struct sm_ctx *ctx, - const u8 *mac, size_t maclen, - const u8 *macdata, size_t macdatalen) -{ - int r; - char *p; - BUF_MEM authdata, *my_mac = NULL; - authdata.data = NULL; - - if (!ctx || !ctx->cipher_ctx) { - r = SC_ERROR_INVALID_ARGUMENTS; - goto incerr; - } - struct pace_sm_ctx *psmctx = ctx->cipher_ctx; - - r = increment_ssc(psmctx); - if (r < 0) - goto incerr; - - r = encode_ssc(psmctx->ssc, psmctx->ctx, (u8 **) &authdata.data); - if (r < 0) - goto err; - authdata.length = r; - - p = realloc(authdata.data, authdata.length + macdatalen); - if (!p) { - r = SC_ERROR_OUT_OF_MEMORY; - goto err; - } - authdata.data = p; - memcpy(authdata.data + authdata.length, macdata, macdatalen); - authdata.length += macdatalen; - bin_log(card->ctx, "Authentication data to verify (PACE)", - (u8 *) authdata.data, authdata.length); - - authdata.max = authdata.length; - my_mac = PACE_authenticate(psmctx->ctx, psmctx->key_mac, &authdata); - if (!my_mac) { - r = SC_ERROR_INTERNAL; - goto err; - } - - if (my_mac->length != maclen || - memcmp(my_mac->data, mac, maclen) != 0) { - r = SC_ERROR_OBJECT_NOT_VALID; - sc_debug(card->ctx, "Authentication data not verified"); - goto err; - } - - sc_debug(card->ctx, "Authentication data verified"); - -err: - if (authdata.data) - free(authdata.data); - if (my_mac) - BUF_MEM_free(my_mac); - if (r >= 0) - decrement_ssc(psmctx); - else - r = decrement_ssc(psmctx); - -incerr: - SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, r); -} - -int pace_transmit_apdu(struct sm_ctx *ctx, sc_card_t *card, - sc_apdu_t *apdu) -{ - int r; - - if ((apdu->cla & 0x0C) == 0x0C) { - sc_debug(card->ctx, "Given APDU is already protected with some secure messaging."); - SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, sc_transmit_apdu(card, apdu)); - } - - if (!ctx || !ctx->cipher_ctx) { - SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_INVALID_ARGUMENTS); - } - - /* SW1 and SW2 are used to determine if really something has been sent and - * received. Only if this is the case, the send sequence counter needs to - * be incremented. */ - - apdu->sw1 = 0; - apdu->sw2 = 0; - - SC_TEST_RET(card->ctx, increment_ssc(ctx->cipher_ctx), - "Could not increment send sequence counter"); - - r = sm_transmit_apdu(ctx, card, apdu); - - if (apdu->sw1 || apdu->sw2) { - if (r < 0) { - if (increment_ssc(ctx->cipher_ctx) < 0) - sc_error(card->ctx, - "Could not increment send sequence counter"); - } else - r = increment_ssc(ctx->cipher_ctx); - } else - if (decrement_ssc(ctx->cipher_ctx) < 0) - sc_error(card->ctx, - "Could not decrement send sequence counter"); - - SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, r); -} diff --git a/ccid/src/Makefile.am b/ccid/src/Makefile.am new file mode 100644 index 0000000..1ad83d1 --- /dev/null +++ b/ccid/src/Makefile.am @@ -0,0 +1,17 @@ +IFDNFC_LIB = libifdnfc.$(DYN_LIB_EXT) + +bin_PROGRAMS = +if WITH_CCID +bin_PROGRAMS += ccid +endif +if WITH_PACE +bin_PROGRAMS += pace-tool +endif + +ccid_SOURCES = ccid.c usbstring.c usb.c binutil.c scutil.c +ccid_LDADD = $(OPENSC_LIBS) $(PTHREAD_LIBS) +ccid_CFLAGS = $(OPENSC_CFLAGS) $(PTHREAD_CFLAGS) + +pace_tool_SOURCES = sm.c pace-tool.c binutil.c scutil.c pace.c pace_lib.c +pace_tool_LDADD = $(OPENSC_LIBS) $(OPENSSL_LIBS) +pace_tool_CFLAGS = $(OPENSC_CFLAGS) $(OPENSSL_CFLAGS) diff --git a/ccid/binutil.c b/ccid/src/binutil.c similarity index 100% rename from ccid/binutil.c rename to ccid/src/binutil.c diff --git a/ccid/binutil.h b/ccid/src/binutil.h similarity index 100% rename from ccid/binutil.h rename to ccid/src/binutil.h diff --git a/ccid/ccid.c b/ccid/src/ccid.c similarity index 100% rename from ccid/ccid.c rename to ccid/src/ccid.c diff --git a/ccid/ccid.h b/ccid/src/ccid.h similarity index 100% rename from ccid/ccid.h rename to ccid/src/ccid.h diff --git a/ccid/pace-tool.c b/ccid/src/pace-tool.c similarity index 100% rename from ccid/pace-tool.c rename to ccid/src/pace-tool.c diff --git a/ccid/pace.h b/ccid/src/pace.h similarity index 100% rename from ccid/pace.h rename to ccid/src/pace.h diff --git a/ccid/pace_lib.c b/ccid/src/pace_lib.c similarity index 100% rename from ccid/pace_lib.c rename to ccid/src/pace_lib.c diff --git a/ccid/pace_lib.h b/ccid/src/pace_lib.h similarity index 100% rename from ccid/pace_lib.h rename to ccid/src/pace_lib.h diff --git a/ccid/scutil.c b/ccid/src/scutil.c similarity index 100% rename from ccid/scutil.c rename to ccid/src/scutil.c diff --git a/ccid/scutil.h b/ccid/src/scutil.h similarity index 100% rename from ccid/scutil.h rename to ccid/src/scutil.h diff --git a/ccid/sm.c b/ccid/src/sm.c similarity index 100% rename from ccid/sm.c rename to ccid/src/sm.c diff --git a/ccid/sm.h b/ccid/src/sm.h similarity index 100% rename from ccid/sm.h rename to ccid/src/sm.h diff --git a/ccid/usb.c b/ccid/src/usb.c similarity index 100% rename from ccid/usb.c rename to ccid/src/usb.c diff --git a/ccid/usbstring.c b/ccid/src/usbstring.c similarity index 100% rename from ccid/usbstring.c rename to ccid/src/usbstring.c diff --git a/ccid/usbstring.h b/ccid/src/usbstring.h similarity index 100% rename from ccid/usbstring.h rename to ccid/src/usbstring.h