openct-0.6.20/ 0000777 0001750 0001750 00000000000 11336457577 010116 5 0000000 0000000 openct-0.6.20/depcomp 0000755 0001750 0001750 00000044267 11336457520 011410 0000000 0000000 #! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
scriptversion=2009-04-28.21; # UTC
# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009 Free
# Software Foundation, Inc.
# This program 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 2, or (at your option)
# any later version.
# This program 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 this program. If not, see .
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# Originally written by Alexandre Oliva .
case $1 in
'')
echo "$0: No command. Try \`$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
Run PROGRAMS ARGS to compile a file, generating dependencies
as side-effects.
Environment variables:
depmode Dependency tracking mode.
source Source file read by `PROGRAMS ARGS'.
object Object file output by `PROGRAMS ARGS'.
DEPDIR directory where to store dependencies.
depfile Dependency file to output.
tmpdepfile Temporary file to use when outputing dependencies.
libtool Whether libtool is used (yes/no).
Report bugs to .
EOF
exit $?
;;
-v | --v*)
echo "depcomp $scriptversion"
exit $?
;;
esac
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
echo "depcomp: Variables source, object and depmode must be set" 1>&2
exit 1
fi
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
depfile=${depfile-`echo "$object" |
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
rm -f "$tmpdepfile"
# Some modes work just like other modes, but use different flags. We
# parameterize here, but still list the modes in the big case below,
# to make depend.m4 easier to write. Note that we *cannot* use a case
# here, because this file can only contain one case statement.
if test "$depmode" = hp; then
# HP compiler uses -M and no extra arg.
gccflag=-M
depmode=gcc
fi
if test "$depmode" = dashXmstdout; then
# This is just like dashmstdout with a different argument.
dashmflag=-xM
depmode=dashmstdout
fi
cygpath_u="cygpath -u -f -"
if test "$depmode" = msvcmsys; then
# This is just like msvisualcpp but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u="sed s,\\\\\\\\,/,g"
depmode=msvisualcpp
fi
case "$depmode" in
gcc3)
## gcc 3 implements dependency tracking that does exactly what
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
## it if -MD -MP comes after the -MF stuff. Hmm.
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
## the command line argument order; so add the flags where they
## appear in depend2.am. Note that the slowdown incurred here
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
for arg
do
case $arg in
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
*) set fnord "$@" "$arg" ;;
esac
shift # fnord
shift # $arg
done
"$@"
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
mv "$tmpdepfile" "$depfile"
;;
gcc)
## There are various ways to get dependency output from gcc. Here's
## why we pick this rather obscure method:
## - Don't want to use -MD because we'd like the dependencies to end
## up in a subdir. Having to rename by hand is ugly.
## (We might end up doing this anyway to support other compilers.)
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
## -MM, not -M (despite what the docs say).
## - Using -M directly means running the compiler twice (even worse
## than renaming).
if test -z "$gccflag"; then
gccflag=-MD,
fi
"$@" -Wp,"$gccflag$tmpdepfile"
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
## The second -e expression handles DOS-style file names with drive letters.
sed -e 's/^[^:]*: / /' \
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
## This next piece of magic avoids the `deleted header file' problem.
## The problem is that when a header file which appears in a .P file
## is deleted, the dependency causes make to die (because there is
## typically no way to rebuild the header). We avoid this by adding
## dummy dependencies for each header file. Too bad gcc doesn't do
## this for us directly.
tr ' ' '
' < "$tmpdepfile" |
## Some versions of gcc put a space before the `:'. On the theory
## that the space means something, we add a space to the output as
## well.
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
sgi)
if test "$libtool" = yes; then
"$@" "-Wp,-MDupdate,$tmpdepfile"
else
"$@" -MDupdate "$tmpdepfile"
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
echo "$object : \\" > "$depfile"
# Clip off the initial element (the dependent). Don't try to be
# clever and replace this with sed code, as IRIX sed won't handle
# lines with more than a fixed number of characters (4096 in
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
# the IRIX cc adds comments like `#:fec' to the end of the
# dependency line.
tr ' ' '
' < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
tr '
' ' ' >> "$depfile"
echo >> "$depfile"
# The second pass generates a dummy entry for each header file.
tr ' ' '
' < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
>> "$depfile"
else
# The sourcefile does not contain any dependencies, so just
# store a dummy comment line, to avoid errors with the Makefile
# "include basename.Plo" scheme.
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
aix)
# The C for AIX Compiler uses -M and outputs the dependencies
# in a .u file. In older versions, this file always lives in the
# current directory. Also, the AIX compiler puts `$object:' at the
# start of each line; $object doesn't have directory information.
# Version 6 uses the directory in both cases.
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
test "x$dir" = "x$object" && dir=
base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.u
tmpdepfile2=$base.u
tmpdepfile3=$dir.libs/$base.u
"$@" -Wc,-M
else
tmpdepfile1=$dir$base.u
tmpdepfile2=$dir$base.u
tmpdepfile3=$dir$base.u
"$@" -M
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
# Each line is of the form `foo.o: dependent.h'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
# That's a tab and a space in the [].
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
else
# The sourcefile does not contain any dependencies, so just
# store a dummy comment line, to avoid errors with the Makefile
# "include basename.Plo" scheme.
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
icc)
# Intel's C compiler understands `-MD -MF file'. However on
# icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
# ICC 7.0 will fill foo.d with something like
# foo.o: sub/foo.c
# foo.o: sub/foo.h
# which is wrong. We want:
# sub/foo.o: sub/foo.c
# sub/foo.o: sub/foo.h
# sub/foo.c:
# sub/foo.h:
# ICC 7.1 will output
# foo.o: sub/foo.c sub/foo.h
# and will wrap long lines using \ :
# foo.o: sub/foo.c ... \
# sub/foo.h ... \
# ...
"$@" -MD -MF "$tmpdepfile"
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each line is of the form `foo.o: dependent.h',
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp2)
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
# compilers, which have integrated preprocessors. The correct option
# to use with these is +Maked; it writes dependencies to a file named
# 'foo.d', which lands next to the object file, wherever that
# happens to be.
# Much of this is similar to the tru64 case; see comments there.
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
test "x$dir" = "x$object" && dir=
base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir.libs/$base.d
"$@" -Wc,+Maked
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
"$@" +Maked
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile1" "$tmpdepfile2"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
do
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
# Add `dependent.h:' lines.
sed -ne '2,${
s/^ *//
s/ \\*$//
s/$/:/
p
}' "$tmpdepfile" >> "$depfile"
else
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile" "$tmpdepfile2"
;;
tru64)
# The Tru64 compiler uses -MD to generate dependencies as a side
# effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
# dependencies in `foo.d' instead, so we check for that too.
# Subdirectories are respected.
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
test "x$dir" = "x$object" && dir=
base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
if test "$libtool" = yes; then
# With Tru64 cc, shared objects can also be used to make a
# static library. This mechanism is used in libtool 1.4 series to
# handle both shared and static libraries in a single compilation.
# With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d.
#
# With libtool 1.5 this exception was removed, and libtool now
# generates 2 separate objects for the 2 libraries. These two
# compilations output dependencies in $dir.libs/$base.o.d and
# in $dir$base.o.d. We have to check for both files, because
# one of the two compilations can be disabled. We should prefer
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
# automatically cleaned when .libs/ is deleted, while ignoring
# the former would cause a distcleancheck panic.
tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4
tmpdepfile2=$dir$base.o.d # libtool 1.5
tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5
tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504
"$@" -Wc,-MD
else
tmpdepfile1=$dir$base.o.d
tmpdepfile2=$dir$base.d
tmpdepfile3=$dir$base.d
tmpdepfile4=$dir$base.d
"$@" -MD
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
do
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
# That's a tab and a space in the [].
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
else
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
#nosideeffect)
# This comment above is used by automake to tell side-effect
# dependency tracking mechanisms from slower ones.
dashmstdout)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout, regardless of -o.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove `-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
test -z "$dashmflag" && dashmflag=-M
# Require at least two characters before searching for `:'
# in the target name. This is to cope with DOS-style filenames:
# a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
"$@" $dashmflag |
sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
tr ' ' '
' < "$tmpdepfile" | \
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
dashXmstdout)
# This case only exists to satisfy depend.m4. It is never actually
# run, as this mode is specially recognized in the preamble.
exit 1
;;
makedepend)
"$@" || exit $?
# Remove any Libtool call
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# X makedepend
shift
cleared=no eat=no
for arg
do
case $cleared in
no)
set ""; shift
cleared=yes ;;
esac
if test $eat = yes; then
eat=no
continue
fi
case "$arg" in
-D*|-I*)
set fnord "$@" "$arg"; shift ;;
# Strip any option that makedepend may not understand. Remove
# the object too, otherwise makedepend will parse it as a source file.
-arch)
eat=yes ;;
-*|$object)
;;
*)
set fnord "$@" "$arg"; shift ;;
esac
done
obj_suffix=`echo "$object" | sed 's/^.*\././'`
touch "$tmpdepfile"
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
sed '1,2d' "$tmpdepfile" | tr ' ' '
' | \
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile" "$tmpdepfile".bak
;;
cpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove `-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
"$@" -E |
sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
sed '$ s: \\$::' > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
cat < "$tmpdepfile" >> "$depfile"
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvisualcpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
IFS=" "
for arg
do
case "$arg" in
-o)
shift
;;
$object)
shift
;;
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
set fnord "$@"
shift
shift
;;
*)
set fnord "$@" "$arg"
shift
shift
;;
esac
done
"$@" -E 2>/dev/null |
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
echo " " >> "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvcmsys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
none)
exec "$@"
;;
*)
echo "Unknown depmode $depmode" 1>&2
exit 1
;;
esac
exit 0
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:
openct-0.6.20/LGPL-2.1 0000644 0001750 0001750 00000063637 10422076714 011011 0000000 0000000
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations
below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it
becomes a de-facto standard. To achieve this, non-free programs must
be allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control
compilation and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at least
three years, to give the same user the materials specified in
Subsection 6a, above, for a charge no more than the cost of
performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply, and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License
may add an explicit geographical distribution limitation excluding those
countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms
of the ordinary General Public License).
To apply these terms, attach the following notices to the library.
It is safest to attach them to the start of each source file to most
effectively convey the exclusion of warranty; and each file should
have at least the "copyright" line and a pointer to where the full
notice is found.
Copyright (C)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or
your school, if any, to sign a "copyright disclaimer" for the library,
if necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James
Random Hacker.
, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
openct-0.6.20/src/ 0000777 0001750 0001750 00000000000 11336457577 010705 5 0000000 0000000 openct-0.6.20/src/ifd/ 0000777 0001750 0001750 00000000000 11336457577 011447 5 0000000 0000000 openct-0.6.20/src/ifd/modules.c 0000644 0001750 0001750 00000003164 10422076714 013164 0000000 0000000 /*
* Module handling
*
* Copyright (C) 2003 Olaf Kirch
*/
#include "internal.h"
#include
#include
#include
#include
#include
#include
static const char *ifd_module_path(const char *subdir)
{
static char path[PATH_MAX];
if (!ct_config.modules_dir
&& !(ct_config.modules_dir = getenv("IFD_MODULES")))
ct_config.modules_dir = OPENCT_MODULES_PATH;
snprintf(path, sizeof(path), "%s/%ss", ct_config.modules_dir, subdir);
return path;
}
int ifd_load_module(const char *type, const char *name)
{
const char *dirname;
char path[PATH_MAX];
lt_dlhandle handle;
void (*init_func) (void);
if (strstr(name, "..")) {
ct_error("Illegal module path \"%s\"", name);
return -1;
}
if (!strcmp(type, "driver")) {
dirname = ct_config.driver_modules_dir;
} else if (!strcmp(type, "protocol")) {
dirname = ct_config.protocol_modules_dir;
} else {
ct_error("Unknown module type \"%s\"", type);
return -1;
}
if (!dirname)
dirname = ifd_module_path(type);
#if defined(HAVE_DLFCN_H) && defined(__APPLE__)
snprintf(path, sizeof(path), "%s/%s.so", dirname, name);
#elif defined(__APPLE__)
snprintf(path, sizeof(path), "%s/%s.bundle", dirname, name);
#else
snprintf(path, sizeof(path), "%s/%s.so", dirname, name);
#endif
handle = lt_dlopen(path);
if (!handle) {
ct_error("Failed to load %s: %s", path, lt_dlerror());
return -1;
}
init_func = (void (*)(void))lt_dlsym(handle, "ifd_init_module");
if (!init_func) {
ct_error("%s: no function called ifd_init_module", path);
lt_dlclose(handle);
return -1;
}
init_func();
return 0;
}
openct-0.6.20/src/ifd/ifd-acr30u.c 0000644 0001750 0001750 00000031347 10625640312 013351 0000000 0000000 /*
* ACR30U driver
* Copyright (C) 2005, Laurent Pinchart
*/
#include "internal.h"
#include "usb-descriptors.h"
#include
#include
/* Maximum buffer sizes
*
* The send buffer must be able to contain a short APDU. In the worst case
* (Case 4S, Lc = 255), the APDU will be 5 (CLA + INS + P1 + P2 + Lc) +
* 255 (Data) + 1 (Le) = 261 bytes long. The send buffer must then be big
* enough to contain an extended command with 261 bytes of data, which gives
* us a total of 5 (HDR + INS + LEN) + 261 (APDU) + 1 (CHK) = 267 bytes.
*
* The receive buffer must be able to contain a short APDU response. In the
* worst case (Case 2S or Case 4S, Le = 256), the APDU will be 256 (Data) +
* 2 (SW1, SW2) = 258 bytes long. The receive buffer must then be big enough
* to contain an extended response with 258 bytes of data, which gives us a
* total of 6 (HDR + SW1 + SW2 + LEN) + 258 (APDU) + 1 (CHK) = 265 bytes.
*
* The ASCII buffer must be able to contain either the command or the reply
* with the STX and ETX bytes.
*/
typedef struct acr_priv {
int icc_proto;
unsigned char sw1, sw2;
unsigned char abuf[267 * 2 + 2];
unsigned char sbuf[267];
unsigned char rbuf[265];
unsigned int head, tail;
} acr_priv_t;
typedef int complete_fn_t(const void *, size_t);
#define ACR_GET_STATUS 0x01
#define ACR_SELECT_CARD_TYPE 0x02
#define ACR_SET_PROTOCOL 0x03
#define ACR_SET_NOTIFICATION 0x06
#define ACR_SET_OPTION 0x07
#define ACR_RESET 0x80
#define ACR_POWER_OFF 0x81
#define ACR_ACTIVATE_SAM 0X88
#define ACR_DEACTIVATE_SAM 0X89
#define ACR_READ_DATA 0x90
#define ACR_WRITE_DATA 0x91
#define ACR_PRESENT_CODE 0x92
#define ACR_CHANGE_CODE 0X93
#define ACR_WRITE_PROTECTION 0x94
#define ACR_EXCHANGE_APDU 0xa0
#define ACR_EXCHANGE_T1 0xa1
#define ACR_EXCHANGE_SAM_APDU 0xb0
#define ACR_EXCHANGE_SAM_T1 0xb1
#define ACR_CARD_AUTO 0x00
#define ACR_CARD_GPM103 0x01
#define ACR_CARD_I2C 0x02
#define ACR_CARD_SLE44x8 0x05
#define ACR_CARD_SLE44x2 0x06
#define ACR_CARD_MCU_T0 0x0c
#define ACR_CARD_MCU_T1 0x0d
#define ACR_CARD_SAM_T0 0xc0
#define ACR_CARD_SAM_T1 0xd0
#define ACR_STATUS_DATA_ERROR 0x60
#define ACR_STATUS_COMMAND_ERROR 0x67
#define ACR_STATUS_OK 0x90
#define ACR_STATUS_STATUS 0xff
#define ACR_STATUS_LENGTH 16
/*
* Send USB control message, and receive data via
* Interrupt URBs.
*/
static int
acr_usb_int(ifd_device_t * dev, int requesttype, int request,
int value, int idx,
const void *sbuf, size_t slen,
void *rbuf, size_t rlen, complete_fn_t complete, long timeout)
{
ifd_usb_capture_t *cap;
struct timeval begin;
unsigned int total = 0;
unsigned char *etx;
int rc;
if (timeout < 0)
timeout = dev->timeout;
rc = ifd_usb_begin_capture(dev,
IFD_USB_URB_TYPE_INTERRUPT, 0x81, 8, &cap);
if (rc < 0)
return rc;
gettimeofday(&begin, NULL);
ifd_debug(3, "sending %u bytes:%s", slen, ct_hexdump(sbuf, slen));
rc = ifd_usb_control(dev, requesttype, request,
value, idx, (void *)sbuf, slen, timeout);
if (rc < 0)
goto out;
/* Capture URBs until we have a complete answer */
while (rc >= 0 && total < rlen) {
unsigned char temp[8];
long wait;
wait = timeout - ifd_time_elapsed(&begin);
if (wait <= 0)
return IFD_ERROR_TIMEOUT;
memset(temp, 0, sizeof temp);
rc = ifd_usb_capture(dev, cap, temp, sizeof(temp), wait);
if (rc > 0) {
if (rc > (int)(rlen - total))
rc = rlen - total;
memcpy((caddr_t) rbuf + total, temp, rc);
total += rc;
if (complete && complete(rbuf, total))
break;
}
}
/* Why does the USB spec provide short packets if the device doesn't
* use them ? Every interrupt URB contains 8 bytes, which means we
* must discard everything after the ETX marker or we will end up
* with garbage.
*/
if ((etx = memchr(rbuf, 0x03, total)) != NULL)
total = etx - (unsigned char *)rbuf + 1;
if (rc >= 0) {
ifd_debug(3, "received %u bytes:%s", total,
ct_hexdump(rbuf, total));
rc = total;
}
out:
ifd_usb_end_capture(dev, cap);
return rc;
}
static int acr_reply_complete(const void *ptr, size_t len)
{
return memchr(ptr, 0x03, len) != NULL;
}
/*
* Transmit a command to the reader.
*/
static int
acr_transmit(ifd_reader_t * reader,
const void *sbuf, size_t slen, void *rbuf, size_t rlen)
{
static const char acr_hex[16] = "0123456789ABCDEF";
acr_priv_t *priv = (acr_priv_t *) reader->driver_data;
ifd_device_t *dev = reader->device;
unsigned char *abuf = priv->abuf;
unsigned char *cbuf = (unsigned char *)sbuf;
unsigned char checksum;
unsigned char c;
int requesttype;
int rc;
int i;
if (slen > 261)
return IFD_ERROR_GENERIC;
/* Convert the command to ascii and compute the checksum */
*abuf++ = 0x02;
checksum = 0x01;
*abuf++ = '0';
*abuf++ = '1';
for (i = 0; i < (int)slen; ++i) {
checksum ^= cbuf[i];
*abuf++ = acr_hex[cbuf[i] >> 4];
*abuf++ = acr_hex[cbuf[i] & 0x0f];
}
*abuf++ = acr_hex[checksum >> 4];
*abuf++ = acr_hex[checksum & 0x0f];
*abuf++ = 0x03;
/* Transmit the encoded command */
requesttype = IFD_USB_RECIP_DEVICE
| IFD_USB_TYPE_VENDOR | IFD_USB_ENDPOINT_OUT;
rc = acr_usb_int(dev, requesttype, 0, 0, 0, priv->abuf, slen * 2 + 6,
priv->abuf, sizeof priv->abuf, acr_reply_complete, -1);
if (rc <= 0)
return rc;
if (rc < 12) {
ct_error("acr: communication error: short response received");
return IFD_ERROR_COMM_ERROR;
}
/* Decode and verify the response */
abuf = priv->abuf;
if (abuf[0] != 0x02 || abuf[rc - 1] != 0x03) {
ifd_debug(1, "data: %s", ct_hexdump(abuf, rc));
ct_error("acr: communication error: invalid header/footer");
return IFD_ERROR_COMM_ERROR;
}
abuf++;
rc = (rc - 2) / 2;
checksum = 0;
for (i = 0; i < rc; ++i) {
*abuf -= '0';
if (*abuf > 9)
*abuf -= 'A' - '0' - 10;
c = (*abuf++ & 0x0f) << 4;
*abuf -= '0';
if (*abuf > 9)
*abuf -= 'A' - '0' - 10;
c += *abuf++ & 0x0f;
priv->abuf[i] = c;
checksum ^= c;
}
if (checksum != 0) {
ct_error("acr: communication error: invalid checksum");
return IFD_ERROR_COMM_ERROR;
}
priv->sw1 = priv->abuf[1];
priv->sw2 = priv->abuf[2];
if (priv->abuf[3] == 0xff) {
rc = (priv->abuf[4] << 8) + priv->abuf[5];
abuf = &priv->abuf[6];
} else {
rc = priv->abuf[3];
abuf = &priv->abuf[4];
}
if (rc > (int)rlen) {
ifd_debug(1, "received more data than requested, "
"discarding data: %s", ct_hexdump(abuf, rlen - rc));
}
rc = rc > (int)rlen ? (int)rlen : rc;
memcpy(rbuf, abuf, rc);
return rc;
}
/*
* Read the reader status
*/
static int acr_reader_status(ifd_reader_t * reader, void *status, size_t len)
{
unsigned char cmd[2];
int rc;
cmd[0] = ACR_GET_STATUS;
cmd[1] = 0x00;
rc = acr_transmit(reader, &cmd, sizeof cmd, status, len);
if (rc < 0)
return rc;
if (rc != ACR_STATUS_LENGTH) {
ct_error("acr: invalid status length");
return IFD_ERROR_COMM_ERROR;
}
return rc;
}
/*
* Initialize the device
*/
static int acr_open(ifd_reader_t * reader, const char *device_name)
{
ifd_device_t *dev;
acr_priv_t *priv;
ifd_device_params_t params;
unsigned char status[ACR_STATUS_LENGTH];
int rc;
if (!(dev = ifd_device_open(device_name)))
return -1;
if (ifd_device_type(dev) != IFD_DEVICE_TYPE_USB) {
ct_error("acr30u: device %s is not a USB device", device_name);
ifd_device_close(dev);
return -1;
}
params = dev->settings;
params.usb.interface = 0;
if (ifd_device_set_parameters(dev, ¶ms) < 0) {
ct_error("acr30u: setting parameters failed", device_name);
ifd_device_close(dev);
return -1;
}
priv = (acr_priv_t *) calloc(1, sizeof(acr_priv_t));
reader->driver_data = priv;
reader->device = dev;
reader->name = NULL;
reader->nslots = 1;
dev->timeout = 2000;
if ((rc = acr_reader_status(reader, status, sizeof status)) < 0)
return rc;
/* strndup is a GNU extension, so it might not be available on all
* the target platforms. Use malloc and memcpy instead.
*/
reader->name = (char *)calloc(1, 11);
memcpy((char *)reader->name, status, 10);
ifd_debug(1, "found %s reader.", reader->name);
ifd_debug(1, "supported cards: %02x%02x", status[12], status[13]);
return 0;
}
/*
* Close the device
*/
static int acr_close(ifd_reader_t * reader)
{
free((char *)reader->name);
free(reader->driver_data);
return 0;
}
/*
* Power up the reader - always powered up.
* TODO: What about an USB standby mode ?
*/
static int acr_activate(ifd_reader_t * reader)
{
ifd_debug(1, "called.");
return 0;
}
static int acr_deactivate(ifd_reader_t * reader)
{
ifd_debug(1, "called.");
return -1;
}
/*
* Card status
*/
static int acr_card_status(ifd_reader_t * reader, int slot, int *status)
{
unsigned char acr_status[ACR_STATUS_LENGTH];
int rc;
*status = 0;
if ((rc = acr_reader_status(reader, acr_status, sizeof acr_status)) < 0) {
ct_error("acr: failed to get card status");
return -1;
}
ifd_debug(2, "C_SEL: %02x C_STAT: %02x",
acr_status[14], acr_status[15]);
if (acr_status[15])
*status = IFD_CARD_PRESENT;
ifd_debug(2, "card %spresent", *status ? "" : "not ");
return 0;
}
/*
* Reset
*/
static int
acr_card_reset(ifd_reader_t * reader, int slot, void *atr, size_t size)
{
unsigned char buffer[IFD_MAX_ATR_LEN];
unsigned char cmd[2];
int rc;
cmd[0] = ACR_RESET;
cmd[1] = 0x00;
rc = acr_transmit(reader, &cmd, sizeof cmd, buffer, sizeof buffer);
if (rc < 0)
return rc;
if (rc < (int)size)
size = rc;
memcpy(atr, buffer, size);
return size;
}
/*
* Select a protocol for communication with the ICC.
*/
static int acr_set_protocol(ifd_reader_t * reader, int nslot, int proto)
{
ifd_slot_t *slot;
acr_priv_t *priv;
unsigned char cmd[3];
int rc;
ifd_debug(1, "called, proto=%d", proto);
cmd[0] = ACR_SELECT_CARD_TYPE;
cmd[1] = 0x01;
switch (proto) {
case IFD_PROTOCOL_T0:
cmd[2] = ACR_CARD_MCU_T0;
break;
case IFD_PROTOCOL_T1:
cmd[2] = ACR_CARD_MCU_T1;
break;
default:
return IFD_ERROR_NOT_SUPPORTED;
}
if ((rc = acr_transmit(reader, cmd, sizeof cmd, NULL, 0)) < 0) {
ct_error("acr: unable to set the protocol");
return IFD_ERROR_COMM_ERROR;
}
slot = &reader->slot[nslot];
slot->proto = ifd_protocol_new(proto, reader, slot->dad);
if (slot->proto == NULL) {
ct_error("acr: unable to create protocol");
return -1;
}
ifd_protocol_set_parameter(slot->proto, IFD_PROTOCOL_BLOCK_ORIENTED, 1);
priv = (acr_priv_t *) reader->driver_data;
priv->icc_proto = proto;
return 0;
}
/*
* Send/receive routines
*/
static int
acr_send_t0(ifd_reader_t * reader, unsigned int dad, const unsigned char *sbuf,
size_t slen)
{
acr_priv_t *priv = (acr_priv_t *) reader->driver_data;
ifd_iso_apdu_t iso;
int rc;
if (slen > 260)
return IFD_ERROR_GENERIC;
/* The reader expects Lc and Le to always be present, so fix the
* APDU to add a null Le byte for Case 1, Case 3S and Case 4S and
* insert a null Lc byte for Case 2S. The T=0 protocol handler already
* took care of inserting a null Lc byte for Case 1, and removed the
* Le byte for Case 4S.
*/
priv->sbuf[0] = ACR_EXCHANGE_APDU;
priv->sbuf[1] = slen + 1;
memcpy(&priv->sbuf[2], sbuf, slen);
if ((rc = ifd_iso_apdu_parse(sbuf, slen, &iso)) < 0)
return rc;
if (iso.cse == IFD_APDU_CASE_2S) {
priv->sbuf[slen + 2] = priv->sbuf[slen + 1];
priv->sbuf[slen + 1] = 0;
} else
priv->sbuf[slen + 2] = 0;
priv->head = priv->tail = 0;
rc = acr_transmit(reader, priv->sbuf, slen + 3, priv->rbuf,
sizeof priv->rbuf);
if (rc >= 0) {
priv->tail = rc;
rc = slen;
}
return rc;
}
static int
acr_send(ifd_reader_t * reader, unsigned int dad, const unsigned char *buffer,
size_t len)
{
acr_priv_t *priv = (acr_priv_t *) reader->driver_data;
switch (priv->icc_proto) {
case IFD_PROTOCOL_T0:
return acr_send_t0(reader, dad, buffer, len);
}
return IFD_ERROR_NOT_SUPPORTED;
}
static int
acr_recv(ifd_reader_t * reader, unsigned int dad, unsigned char *buffer,
size_t len, long timeout)
{
acr_priv_t *priv = (acr_priv_t *) reader->driver_data;
switch (priv->icc_proto) {
case IFD_PROTOCOL_T0:
if (priv->tail - priv->head < len)
len = priv->tail - priv->head;
memcpy(buffer, priv->rbuf + priv->head, len);
priv->head += len;
return len;
}
return IFD_ERROR_NOT_SUPPORTED; /* not yet */
}
#if 0
/*
* Set the card's baud rate etc
*/
static int acr_set_card_parameters(ifd_device_t * dev, unsigned int baudrate)
{
return 0;
}
#endif
/*
* Driver operations
*/
static struct ifd_driver_ops acr30u_driver;
/*
* Initialize this module
*/
void ifd_acr30u_register(void)
{
memset(&acr30u_driver, 0, sizeof acr30u_driver);
acr30u_driver.open = acr_open;
acr30u_driver.close = acr_close;
acr30u_driver.activate = acr_activate;
acr30u_driver.deactivate = acr_deactivate;
acr30u_driver.card_status = acr_card_status;
acr30u_driver.card_reset = acr_card_reset;
acr30u_driver.send = acr_send;
acr30u_driver.recv = acr_recv;
acr30u_driver.set_protocol = acr_set_protocol;
ifd_driver_register("acr30u", &acr30u_driver);
}
openct-0.6.20/src/ifd/ifd-cardman.c 0000644 0001750 0001750 00000023173 10625650421 013661 0000000 0000000 /*
* OMNIKEY CardMan 2020/6020/6120 driver
* This driver is not yet complete, but at least it
* spits out the ATR already.
* Needs a recentish Linux Kernel (2.4.5 does NOT work)
*
* Copyright (C) 2003, Olaf Kirch
*
* Based on information from the cm2020 driver by
* Omnikey AG.
*/
#include "internal.h"
#include
#include
typedef struct cm_priv {
int icc_proto;
unsigned char rbuf[64];
unsigned int head, tail;
} cm_priv_t;
typedef int complete_fn_t(const void *, size_t);
static int cm_set_card_parameters(ifd_device_t *, unsigned int baudRate);
static int cm_transceive_t0(ifd_reader_t * reader,
const void *sbuf, size_t slen,
void *rbuf, size_t rlen);
static int cm_usb_int(ifd_device_t * dev, int requesttype, int request,
int value, int idx,
const void *sbuf, size_t slen,
void *rbuf, size_t rlen,
complete_fn_t check, long timeout);
static int cm_anyreply(const void *, size_t);
/*
* Initialize the device
*/
static int cm_open(ifd_reader_t * reader, const char *device_name)
{
ifd_device_t *dev;
cm_priv_t *priv;
ifd_device_params_t params;
reader->name = "OMNIKEY CardMan 2020/6020/6120";
reader->nslots = 1;
if (!(dev = ifd_device_open(device_name)))
return -1;
if (ifd_device_type(dev) != IFD_DEVICE_TYPE_USB) {
ct_error("cardman: device %s is not a USB device", device_name);
ifd_device_close(dev);
return -1;
}
params = dev->settings;
params.usb.interface = 0;
if (ifd_device_set_parameters(dev, ¶ms) < 0) {
ifd_device_close(dev);
return -1;
}
priv = (cm_priv_t *) calloc(1, sizeof(cm_priv_t));
if (!priv) {
ct_error("out of memory");
return IFD_ERROR_NO_MEMORY;
}
reader->driver_data = priv;
reader->device = dev;
dev->timeout = 2000;
return 0;
}
/*
* Power up the card slot
*/
static int cm_activate(ifd_reader_t * reader)
{
ifd_device_t *dev = reader->device;
int rc;
ifd_debug(1, "called.");
/* Set async card @9600 bps, 2 stop bits, even parity */
if ((rc = cm_set_card_parameters(dev, 0x01)) < 0) {
ct_error("cardman: failed to set card parameters 9600/8E2");
return rc;
}
return 0;
}
static int cm_deactivate(ifd_reader_t * reader)
{
ifd_device_t *dev = reader->device;
int rc;
ifd_debug(1, "called.");
if ((rc = ifd_usb_control(dev, 0x42, 0x11, 0, 0, NULL, 0, -1)) < 0) {
ct_error("cardman: failed to deactivate card");
return rc;
}
return 0;
}
/*
* Card status - always present
*/
static int cm_card_status(ifd_reader_t * reader, int slot, int *status)
{
ifd_device_t *dev = reader->device;
unsigned char cm_status = 0;
int rc;
*status = 0;
if ((rc =
cm_usb_int(dev, 0x42, 0x20, 0, 0, NULL, 0, &cm_status, 1, NULL,
-1)) < 0) {
ct_error("cardman: failed to get card status");
return -1;
}
if (rc == 1 && (cm_status & 0x42))
*status = IFD_CARD_PRESENT;
ifd_debug(1, "card %spresent", *status ? "" : "not ");
return 0;
}
/*
* Reset
*/
static int cm_card_reset(ifd_reader_t * reader, int slot, void *atr,
size_t size)
{
ifd_device_t *dev = reader->device;
unsigned char buffer[IFD_MAX_ATR_LEN];
int n;
/* Request the ATR */
if ((n = cm_usb_int(dev, 0x42, 0x10, 1, 0, NULL, 0,
buffer, sizeof(buffer),
(complete_fn_t *) ifd_atr_complete, -1)) < 0) {
ct_error("cardman: failed to reset card");
return n;
}
/* XXX Handle inverse convention, odd parity, etc */
if ((size_t) n > size)
n = size;
memcpy(atr, buffer, n);
return n;
}
/*
* Select a protocol for communication with the ICC.
*/
static int cm_set_protocol(ifd_reader_t * reader, int nslot, int proto)
{
ifd_device_t *dev = reader->device;
ifd_slot_t *slot;
cm_priv_t *priv;
unsigned char pts[4], reply[4];
unsigned int baudRate;
int n;
ifd_debug(1, "called, proto=%d", proto);
pts[0] = 0xFF;
switch (proto) {
case IFD_PROTOCOL_T0:
pts[1] = 0x10;
pts[2] = 0x11;
break;
case IFD_PROTOCOL_T1:
pts[1] = 0x11;
/* XXX select Fi/Di according to TA1 */
pts[2] = 0x11;
break;
default:
return IFD_ERROR_NOT_SUPPORTED;
}
pts[3] = pts[0] ^ pts[1] ^ pts[2];
/* Send the PTS bytes */
if ((n =
cm_usb_int(dev, 0x42, 1, 0, 0, pts, 4, reply, 2, NULL, -1)) < 0) {
ct_error("cardman: failed to send PTS");
return n;
}
if (reply[0] != 4) {
ct_error("cardman: card refused PTS");
return IFD_ERROR_COMM_ERROR;
}
#ifdef notyet
/* Receive PTS response */
if ((n = ifd_usb_control(dev, 0xC2, 0, 0, 0, reply, 4, -1)) < 0) {
ct_error("cardman: failed to receive PTS response");
return n;
}
if (n != 4) {
ct_error("cardman: received short PTS response (%u bytes)", n);
return IFD_ERROR_COMM_ERROR;
}
if (memcmp(pts, reply, 4)) {
ct_error("cardman: PTS reply does not match request", n);
return IFD_ERROR_COMM_ERROR;
}
#endif
baudRate = pts[2] & 0xf;
/* Select f=5.12 MHz */
if ((pts[2] & 0xF0) == 0x90)
baudRate |= 0x10;
if ((n = cm_set_card_parameters(dev, baudRate)) < 0) {
ct_error
("cardman: failed to set card communication parameters");
return n;
}
/* T=0 goes through send/receive functions, but
* T=1 needs special massaging */
slot = &reader->slot[nslot];
if (proto == IFD_PROTOCOL_T0) {
slot->proto = ifd_protocol_new(proto, reader, slot->dad);
} else {
slot->proto = ifd_protocol_new(IFD_PROTOCOL_TRANSPARENT,
reader, slot->dad);
}
if (slot->proto == NULL) {
ct_error("cardman: internal error");
return -1;
}
priv = (cm_priv_t *) reader->driver_data;
priv->icc_proto = proto;
return 0;
}
/*
* Send/receive using the underlying protocol.
*/
static int cm_transparent(ifd_reader_t * reader, int dad,
const void *sbuf, size_t slen, void *rbuf,
size_t rlen)
{
cm_priv_t *priv = (cm_priv_t *) reader->driver_data;
switch (priv->icc_proto) {
case IFD_PROTOCOL_T0:
return cm_transceive_t0(reader, sbuf, slen, rbuf, rlen);
case IFD_PROTOCOL_T1:
return IFD_ERROR_NOT_SUPPORTED; /* not yet */
}
return IFD_ERROR_NOT_SUPPORTED;
}
static int cm_transceive_t0(ifd_reader_t * reader,
const void *sbuf, size_t slen, void *rbuf,
size_t rlen)
{
#if 0
ifd_device_t *dev = reader->device;
int rc;
if (len > 5) {
rc = ifd_usb_control(dev, 0x42, 2, 0, 0, rbuf, rlen);
} else {
unsigned char temp[5];
if (len < 4)
return IFD_ERROR_INVALID_ARG;
temp[4] = 0;
memcpy(temp, sbuf, slen);
rc = ifd_usb_control(dev, 0x42, 3, 8, (temp[1] << 8) | temp[4],
temp, 5);
}
#endif
return IFD_ERROR_NOT_SUPPORTED;
}
/*
* Send/receive routines
*/
static int cm_send_t0(ifd_reader_t * reader, unsigned int dad,
const unsigned char *sbuf, size_t slen)
{
cm_priv_t *priv = (cm_priv_t *) reader->driver_data;
ifd_device_t *dev = reader->device;
int rc;
/* XXX how can we know if this is a CASE 1 or CASE 2 APDU? */
priv->head = priv->tail = 0;
rc = cm_usb_int(dev, 0x42, 2, 0, 0, sbuf, slen,
priv->rbuf, sizeof(priv->rbuf), cm_anyreply, -1);
if (rc >= 0) {
priv->tail = rc;
rc = slen;
}
return rc;
}
static int cm_send(ifd_reader_t * reader, unsigned int dad,
const unsigned char *buffer, size_t len)
{
cm_priv_t *priv = (cm_priv_t *) reader->driver_data;
switch (priv->icc_proto) {
case IFD_PROTOCOL_T0:
return cm_send_t0(reader, dad, buffer, len);
}
return IFD_ERROR_NOT_SUPPORTED;
}
static int cm_recv(ifd_reader_t * reader, unsigned int dad,
unsigned char *buffer, size_t len, long timeout)
{
cm_priv_t *priv = (cm_priv_t *) reader->driver_data;
switch (priv->icc_proto) {
case IFD_PROTOCOL_T0:
if (priv->tail - priv->head < len)
len = priv->tail - priv->head;
memcpy(buffer, priv->rbuf + priv->head, len);
priv->head += len;
return len;
}
return IFD_ERROR_NOT_SUPPORTED; /* not yet */
}
/*
* Set the card's baud rate etc
*/
static int cm_set_card_parameters(ifd_device_t * dev, unsigned int baudrate)
{
return ifd_usb_control(dev, 0x42, 0x30, baudrate << 8, 2, NULL, 0, -1);
}
/*
* Send USB control message, and receive data via
* Interrupt URBs.
*/
static int cm_usb_int(ifd_device_t * dev, int requesttype, int request,
int value, int idx, const void *sbuf, size_t slen,
void *rbuf, size_t rlen, complete_fn_t complete,
long timeout)
{
ifd_usb_capture_t *cap;
struct timeval begin;
unsigned int total = 0;
int rc;
if (timeout < 0)
timeout = dev->timeout;
rc = ifd_usb_begin_capture(dev,
IFD_USB_URB_TYPE_INTERRUPT, 0x81, 8, &cap);
if (rc < 0)
return rc;
gettimeofday(&begin, NULL);
rc = ifd_usb_control(dev, requesttype, request,
value, idx, (void *)sbuf, slen, timeout);
if (rc < 0)
goto out;
/* Capture URBs until we have a complete answer */
while (rc >= 0 && total < rlen) {
unsigned char temp[8];
long wait;
wait = timeout - ifd_time_elapsed(&begin);
if (wait <= 0)
return IFD_ERROR_TIMEOUT;
rc = ifd_usb_capture(dev, cap, temp, sizeof(temp), wait);
if (rc > 0) {
if (rc > (int)(rlen - total))
rc = rlen - total;
memcpy((caddr_t) rbuf + total, temp, rc);
total += rc;
if (complete && complete(rbuf, total))
break;
}
}
if (rc >= 0) {
ifd_debug(3, "received %u bytes:%s", total,
ct_hexdump(rbuf, total));
rc = total;
}
out:
ifd_usb_end_capture(dev, cap);
return rc;
}
static int cm_anyreply(const void *ptr, size_t len)
{
return 1;
}
/*
* Driver operations
*/
static struct ifd_driver_ops cardman_driver;
/*
* Initialize this module
*/
void ifd_cardman_register(void)
{
cardman_driver.open = cm_open;
cardman_driver.activate = cm_activate;
cardman_driver.deactivate = cm_deactivate;
cardman_driver.card_status = cm_card_status;
cardman_driver.card_reset = cm_card_reset;
cardman_driver.send = cm_send;
cardman_driver.recv = cm_recv;
cardman_driver.set_protocol = cm_set_protocol;
cardman_driver.transparent = cm_transparent;
ifd_driver_register("cardman", &cardman_driver);
}
openct-0.6.20/src/ifd/ria.c 0000644 0001750 0001750 00000027722 10625650421 012273 0000000 0000000 /*
* RIA - remote IFD access
*
* Copyright (C) 2003, Olaf Kirch
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "internal.h"
#include "ria.h"
#define RIA_RESPONSE 255 /* pseudo command code */
#define RIA_QUEUE_LEN 256
#define RIA_SEND_CHUNK 128
#define RIA_DEFAULT_TIMEOUT 4000
static void ifd_remote_close(ifd_device_t *);
ria_client_t *ria_connect(const char *address)
{
ria_client_t *clnt;
char path[PATH_MAX];
int rc;
if (!address) {
return NULL;
}
if (!ct_format_path(path, PATH_MAX, address)) {
return NULL;
}
clnt = (ria_client_t *) calloc(1, sizeof(*clnt) + RIA_QUEUE_LEN);
if (!clnt) {
ct_error("out of memory");
return NULL;
}
ct_buf_init(&clnt->data, (clnt + 1), RIA_QUEUE_LEN);
clnt->sock = ct_socket_new(1024);
if ((rc = ct_socket_connect(clnt->sock, path)) < 0) {
ct_error("Failed to connect to RIA server \"%s\": %s",
path, ct_strerror(rc));
ria_free(clnt);
return NULL;
}
return clnt;
}
void ria_free(ria_client_t * clnt)
{
if (clnt->sock)
ct_socket_free(clnt->sock);
free(clnt);
}
int ria_send(ria_client_t * clnt, unsigned char cmd, const void *arg_buf,
size_t arg_len)
{
unsigned char buffer[512];
ct_buf_t args;
header_t header;
int rc;
ct_buf_init(&args, buffer, sizeof(buffer));
ct_buf_putc(&args, cmd);
ct_buf_put(&args, arg_buf, arg_len);
clnt->xid++;
if (clnt->xid == 0)
clnt->xid++;
memset(&header, 0, sizeof(header));
header.xid = clnt->xid;
ria_print_packet(clnt->sock, 4, "ria_send", &header, &args);
if ((rc = ct_socket_put_packet(clnt->sock, &header, &args)) < 0)
return rc;
/* Leave transmitting to the main loop */
return 0;
}
static int ria_recv(ria_client_t * clnt, unsigned char expect, uint32_t xid,
void *res_buf, size_t res_len, long timeout)
{
ct_socket_t *sock = clnt->sock;
struct timeval begin;
unsigned char buffer[512];
ct_buf_t resp;
header_t header;
int rc;
/* Flush out any pending packets */
if ((rc = ct_socket_flsbuf(sock, 1)) < 0)
return rc;
gettimeofday(&begin, NULL);
if (timeout < 0)
timeout = 0;
/* Always slap on addition timeout for round-trip */
timeout += RIA_DEFAULT_TIMEOUT;
/* Now receive packets until we get the response.
* Handle data packets properly */
ct_buf_init(&resp, buffer, sizeof(buffer));
while (1) {
unsigned char cmd;
long wait = -1;
size_t count;
ct_buf_clear(&resp);
if ((rc = ct_socket_get_packet(sock, &header, &resp)) < 0)
return rc;
/* If there's no complete packet in the receive
* buffer, we need to wait for input. */
if (rc == 0) {
wait = timeout - ifd_time_elapsed(&begin);
if (wait < 0)
return IFD_ERROR_TIMEOUT;
if ((rc = ct_socket_filbuf(sock, wait)) < 0)
return rc;
continue;
}
ria_print_packet(sock, 4, "ria_recv", &header, &resp);
/* Complete packet. Check type */
if (header.dest != 0) {
cmd = RIA_RESPONSE;
} else if (ct_buf_get(&resp, &cmd, 1) < 0)
continue;
count = ct_buf_avail(&resp);
if (cmd == RIA_DATA) {
ct_buf_put(&clnt->data, ct_buf_head(&resp), count);
if (expect == RIA_DATA)
return count;
continue;
}
if (header.xid == xid && cmd == expect) {
if (header.error < 0)
return header.error;
if (count < res_len)
res_len = count;
ct_buf_get(&resp, res_buf, res_len);
return res_len;
}
}
while (header.xid != xid) ;
}
int ria_command(ria_client_t * clnt, unsigned char cmd, const void *arg_buf,
size_t arg_len, void *res_buf, size_t res_len, long timeout)
{
int rc;
if ((rc = ria_send(clnt, cmd, arg_buf, arg_len)) < 0)
return rc;
if (timeout < 0)
timeout = RIA_DEFAULT_TIMEOUT;
rc = ria_recv(clnt, RIA_RESPONSE, clnt->xid, res_buf, res_len, timeout);
return rc;
}
static int ria_claim_device(ria_client_t * clnt, const char *name,
ria_device_t * info)
{
return ria_command(clnt, RIA_MGR_CLAIM, name, strlen(name),
info, sizeof(*info), -1);
}
/*
* Reset remote device
*/
static int ifd_remote_reset(ifd_device_t * dev)
{
ria_client_t *clnt = (ria_client_t *) dev->user_data;
ifd_debug(2, "called");
if (clnt == NULL)
return IFD_ERROR_DEVICE_DISCONNECTED;
return ria_command(clnt, RIA_RESET_DEVICE, NULL, 0, NULL, 0, -1);
}
/*
* Device specific portion of RIA client
*/
static int ifd_remote_get_params(ifd_device_t * dev,
ifd_device_params_t * params)
{
ria_client_t *clnt = (ria_client_t *) dev->user_data;
ifd_debug(2, "called");
if (clnt == NULL)
return IFD_ERROR_DEVICE_DISCONNECTED;
if (dev->type == IFD_DEVICE_TYPE_SERIAL) {
ria_serial_conf_t rconf;
int rc;
rc = ria_command(clnt, RIA_SERIAL_GET_CONFIG,
NULL, 0, &rconf, sizeof(rconf), -1);
params->serial.speed = ntohl(rconf.speed);
params->serial.bits = rconf.bits;
params->serial.stopbits = rconf.stopbits;
params->serial.parity = rconf.parity;
params->serial.check_parity = rconf.check_parity;
params->serial.rts = rconf.rts;
params->serial.dtr = rconf.dtr;
return 0;
}
return IFD_ERROR_NOT_SUPPORTED;
}
static int ifd_remote_set_params(ifd_device_t * dev,
const ifd_device_params_t * params)
{
ria_client_t *clnt = (ria_client_t *) dev->user_data;
ifd_debug(2, "called");
if (clnt == NULL)
return IFD_ERROR_DEVICE_DISCONNECTED;
if (dev->type == IFD_DEVICE_TYPE_SERIAL) {
ria_serial_conf_t rconf;
rconf.speed = htonl(params->serial.speed);
rconf.bits = params->serial.bits;
rconf.stopbits = params->serial.stopbits;
rconf.parity = params->serial.parity;
rconf.check_parity = params->serial.check_parity;
rconf.rts = params->serial.rts;
rconf.dtr = params->serial.dtr;
return ria_command(clnt, RIA_SERIAL_SET_CONFIG,
&rconf, sizeof(rconf), NULL, 0, -1);
}
return IFD_ERROR_NOT_SUPPORTED;
}
static void ifd_remote_flush(ifd_device_t * dev)
{
ria_client_t *clnt = (ria_client_t *) dev->user_data;
ifd_debug(2, "called");
if (clnt == NULL)
return;
ria_command(clnt, RIA_FLUSH_DEVICE, NULL, 0, NULL, 0, -1);
ct_buf_clear(&clnt->data);
}
static void ifd_remote_send_break(ifd_device_t * dev, unsigned int usec)
{
ria_client_t *clnt = (ria_client_t *) dev->user_data;
unsigned int wait;
ifd_debug(2, "called");
if (clnt == NULL)
return;
wait = htonl(usec);
ria_command(clnt, RIA_SEND_BREAK, &wait, sizeof(wait), NULL, 0, -1);
ct_buf_clear(&clnt->data);
}
static int ifd_remote_send(ifd_device_t * dev, const unsigned char *buffer,
size_t len)
{
ria_client_t *clnt = (ria_client_t *) dev->user_data;
unsigned int n, count = 0;
int rc;
ifd_debug(2, "called, data:%s", ct_hexdump(buffer, len));
if (clnt == NULL)
return IFD_ERROR_DEVICE_DISCONNECTED;
while (count < len) {
if ((n = len - count) > RIA_SEND_CHUNK)
n = RIA_SEND_CHUNK;
if ((rc = ria_send(clnt, RIA_DATA, buffer, n)) < 0) {
if (rc == IFD_ERROR_NOT_CONNECTED) {
ifd_remote_close(dev);
return IFD_ERROR_DEVICE_DISCONNECTED;
}
return rc;
}
count += n;
}
return count;
}
static int ifd_remote_recv(ifd_device_t * dev, unsigned char *buffer,
size_t len, long timeout)
{
ria_client_t *clnt = (ria_client_t *) dev->user_data;
size_t total = len;
struct timeval begin;
int n;
gettimeofday(&begin, NULL);
ifd_debug(2, "called, timeout=%ld, len=%u", timeout, len);
if (clnt == NULL)
return IFD_ERROR_DEVICE_DISCONNECTED;
while (len) {
long wait;
/* See if there's any data queued */
if ((n = ct_buf_avail(&clnt->data)) != 0) {
if (n > len)
n = len;
ct_buf_get(&clnt->data, buffer, n);
if (ct_config.debug >= 9)
ifd_debug(9, "got %s", ct_hexdump(buffer, n));
buffer += n;
len -= n;
continue;
}
if ((wait = timeout - ifd_time_elapsed(&begin)) < 0)
goto timeout;
ifd_debug(8, "Need another %u bytes of data, "
"remaining timeout %ld", len, wait);
n = ria_recv(clnt, RIA_DATA, 0, NULL, 0, wait);
if (n < 0) {
ct_error("%s: error while waiting for input: %s",
dev->name, ct_strerror(n));
if (n == IFD_ERROR_NOT_CONNECTED) {
ifd_remote_close(dev);
return IFD_ERROR_DEVICE_DISCONNECTED;
}
return n;
}
}
return total;
timeout: /* Timeouts are a little special; they may happen e.g.
* when trying to obtain the ATR */
if (!ct_config.suppress_errors)
ct_error("%s: timed out while waiting for input", dev->name);
ifd_debug(9, "(%u bytes received so far)", total - len);
return IFD_ERROR_TIMEOUT;
}
static int ifd_remote_poll_presence(ifd_device_t * dev, struct pollfd *pfd)
{
if (dev->user_data == NULL)
return 0;
return IFD_ERROR_NOT_SUPPORTED;
}
static void ifd_remote_close(ifd_device_t * dev)
{
ria_client_t *clnt = (ria_client_t *) dev->user_data;
dev->user_data = NULL;
if (clnt)
ria_free(clnt);
}
static struct ifd_device_ops ifd_remote_ops;
/*
* Open remote IFD
*/
ifd_device_t *ifd_open_remote(const char *ident)
{
ria_client_t *clnt;
ria_device_t devinfo;
ifd_device_t *dev;
char name[256], *addr;
int rc, type;
strncpy(name, ident, sizeof(name));
name[sizeof(name) - 1] = '\0';
if ((addr = strchr(name, '@')) == NULL) {
ct_error("remote device name must be handle@host");
return NULL;
}
*addr++ = '\0';
/* Connect to RIA server */
if (!(clnt = ria_connect(addr)))
return NULL;
if ((rc = ria_claim_device(clnt, name, &devinfo)) < 0) {
ct_error("unable to claim device \"%s\": %s",
name, ct_strerror(rc));
ria_free(clnt);
return NULL;
}
if (!strcmp(devinfo.type, "serial")) {
type = IFD_DEVICE_TYPE_SERIAL;
} else if (!strcmp(devinfo.type, "usb")) {
type = IFD_DEVICE_TYPE_USB;
} else {
ct_error("Unknown device type \"%s\"", devinfo.type);
ria_free(clnt);
return NULL;
}
ifd_remote_ops.reset = ifd_remote_reset;
ifd_remote_ops.set_params = ifd_remote_set_params;
ifd_remote_ops.get_params = ifd_remote_get_params;
ifd_remote_ops.flush = ifd_remote_flush;
ifd_remote_ops.send = ifd_remote_send;
ifd_remote_ops.send_break = ifd_remote_send_break;
ifd_remote_ops.recv = ifd_remote_recv;
ifd_remote_ops.close = ifd_remote_close;
ifd_remote_ops.poll_presence = ifd_remote_poll_presence;
dev = ifd_device_new(ident, &ifd_remote_ops, sizeof(*dev));
dev->hotplug = 1;
dev->timeout = 2000;
dev->type = type;
dev->user_data = clnt;
if ((rc = ifd_device_reset(dev)) < 0) {
ct_error("Failed to reset device: %s", ct_strerror(rc));
ifd_device_close(dev);
return NULL;
}
return dev;
}
/*
* Debugging aid: print packet
*/
void ria_print_packet(ct_socket_t * sock, int level, const char *func,
header_t * hdr, ct_buf_t * args)
{
ct_buf_t temp = *args;
char buffer[128], *msg;
unsigned char cmd;
unsigned int len;
if (level > ct_config.debug)
return;
if (hdr->dest) {
int err = hdr->error;
msg = "RESP";
if (err) {
snprintf(buffer, sizeof(buffer),
"RESP, err=%d (%s)", err, ct_strerror(err));
msg = buffer;
}
} else if (ct_buf_get(&temp, &cmd, 1) < 0) {
msg = "TRUNC-CALL";
} else {
switch (cmd) {
case RIA_MGR_LIST:
msg = "LIST";
break;
case RIA_MGR_INFO:
msg = "INFO";
break;
case RIA_MGR_CLAIM:
msg = "CLAIM";
break;
case RIA_MGR_REGISTER:
msg = "REGISTER";
break;
case RIA_RESET_DEVICE:
msg = "RESET_DEVICE";
break;
case RIA_FLUSH_DEVICE:
msg = "FLUSH_DEVICE";
break;
case RIA_SEND_BREAK:
msg = "SEND_BREAK";
break;
case RIA_SERIAL_GET_CONFIG:
msg = "SERIAL_GET_CONFIG";
break;
case RIA_SERIAL_SET_CONFIG:
msg = "SERIAL_SET_CONFIG";
break;
case RIA_DATA:
msg = "DATA";
break;
default:
snprintf(buffer, sizeof(buffer), "CALL%u", cmd);
msg = buffer;
}
}
len = ct_buf_avail(&temp);
if (len == 0) {
ct_debug("%s: [%08x] %s", func, hdr->xid, msg);
} else if (len < 16) {
ct_debug("%s: [%08x] %s, args%s", func, hdr->xid, msg,
ct_hexdump(ct_buf_head(&temp), len));
} else {
ct_debug("%s: [%08x] %s, args%s ... (%u bytes total)",
func, hdr->xid, msg,
ct_hexdump(ct_buf_head(&temp), 16), len);
}
}
openct-0.6.20/src/ifd/ifd-ccid.c 0000644 0001750 0001750 00000114011 11233772200 013142 0000000 0000000 /*
* driver for some CCID-compliant devices
*
* Copyright 2003, Chaskiel Grundman
*
* 2005-04-20: Harald Welte
* Add support for PCMCIA based CCID Device (CardMan 4040)
*
* 2005-05-22: Harald Welte
* Add suport for OmniKey Cardman 5121 RFID extensions
*/
#include "internal.h"
#include "usb-descriptors.h"
#include "atr.h"
#include
#include
#include
#include
#define CCID_ERR_ABORTED 0xFF /* CMD ABORTED */
#define CCID_ERR_ICC_MUTE 0xFE
#define CCID_ERR_XFR_PARITY 0xFD /* XFR PARITY ERROR */
#define CCID_ERR_OVERRUN 0xFC /* XFR OVERRUN */
#define CCID_ERR_HW_ERROR 0xFB
#define CCID_ERR_BAD_ATR_TS 0xF8
#define CCID_ERR_BAD_ATR_TCK 0xF7
#define CCID_ERR_PROT_NOSUP 0xF6 /* ICC PROTOCOL NOT SUPPORTED */
#define CCID_ERR_CLASS_NOSUP 0xF5 /* ICC CLASS NOT SUPPORTED */
#define CCID_ERR_BAD_PROC_BYTE 0xF4 /* PROCEDURE BYTE CONFLICT */
#define CCID_ERR_XXX 0xF3 /* DEACTIVATED PROTOCOL (?) */
#define CCID_ERR_BUSY_AUTO_SEQ 0xF2 /* BUSY WITH AUTO SEQUENCE */
#define CCID_ERR_PIN_TIMEOUT 0xF0
#define CCID_ERR_PIN_CANCELED 0xEF
#define CCID_ERR_SLOT_BUSY 0xE0 /* CMD SLOT BUSY */
#define CCID_OFFSET_MSGTYPE 0
#define CCID_OFFSET_LENGTH 1
#define CCID_OFFSET_SLOT 5
#define CCID_OFFSET_SEQ 6
#define CCID_REQ_ABORT 1
#define CCID_REQ_GETCLOCKRATE 2
#define CCID_REQ_GETDATARATE 3
#define CCID_CMD_FIRST 0x60
#define CCID_CMD_ICCPOWERON 0x62
#define CCID_CMD_ICCPOWEROFF 0x63
#define CCID_CMD_GETSLOTSTAT 0x65
#define CCID_CMD_XFRBLOCK 0x6F
#define CCID_CMD_GETPARAMS 0x6C
#define CCID_CMD_RESETPARAMS 0x6D
#define CCID_CMD_SETPARAMS 0x61
#define CCID_CMD_ESCAPE 0x6B
#define CCID_CMD_ICCCLOCK 0x6E
#define CCID_CMD_T0APDU 0x6A
#define CCID_CMD_SECURE 0x69
#define CCID_CMD_MECHANICAL 0x71
#define CCID_CMD_ABORT 0x72
#define CCID_CMD_SET_DR_FREQ 0x73
#define CCID_RESP_DATA 0x80
#define CCID_RESP_SLOTSTAT 0x81
#define CCID_RESP_PARAMS 0x82
#define CCID_RESP_ESCAPE 0x83
#define CCID_RESP_DR_FREQ 0x84
/* maximum sensical size:
* 10 bytes ccid header + 4 bytes command header +
* 1 byte Lc + 255 bytes data + 1 byte Le = 271
*/
#define CCID_MAX_MSG_LEN 271
static int msg_expected[] = {
0,
CCID_RESP_PARAMS,
CCID_RESP_DATA,
CCID_RESP_SLOTSTAT,
0,
CCID_RESP_SLOTSTAT,
0, 0, 0,
CCID_RESP_DATA,
CCID_RESP_SLOTSTAT,
CCID_RESP_ESCAPE,
CCID_RESP_PARAMS,
CCID_RESP_PARAMS,
CCID_RESP_SLOTSTAT,
CCID_RESP_DATA,
0,
CCID_RESP_SLOTSTAT,
CCID_RESP_SLOTSTAT,
CCID_RESP_DR_FREQ
};
enum {
TYPE_APDU,
TYPE_TPDU,
TYPE_CHAR
};
/* Some "ccid" devices have non-compliant descriptors. (perhaps their
design predates the approval of the standard?)
Attempt to recognize them anyway.
*/
static struct force_parse_device_st {
unsigned short vendor;
unsigned short product;
} force_parse_devices[] = {
{
0x04e6, 0xe003}, /* SCM SPR 532 */
{
0x046a, 0x003e}, /* Cherry SmartTerminal ST-2XXX */
{
0x413c, 0x2100}, /* Dell USB Smartcard Keyboard */
{
0x04e6, 0x5120}, /* SCM SCR331-DI (NTT) */
{
0x04e6, 0x5111}, /* SCM SCR331-DI */
{
0x08e6, 0x1359}, /* Verisign secure storage token */
{
0x08e6, 0xACE0}, /* Verisign secure token */
{
0, 0}
};
#define SUPPORT_T0 0x1
#define SUPPORT_T1 0x2
#define SUPPORT_ESCAPE 0x80
#define SUPPORT_50V 1
#define SUPPORT_33V 2
#define SUPPORT_18V 4
#define AUTO_VOLTAGE 0x80
#define FLAG_NO_PTS 1
#define FLAG_NO_SETPARAM 2
#define FLAG_AUTO_ACTIVATE 4
#define FLAG_AUTO_ATRPARSE 8
#define USB_CCID_DESCRIPTOR_LENGTH 54
struct usb_ccid_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdCCID;
uint8_t bMaxSlotIndex;
uint8_t bVoltageSupport;
uint32_t dwProtocols;
uint32_t dwDefaultClock;
uint32_t dwMaximumClock;
uint8_t bNumClockRatesSupported;
uint32_t dwDataRate;
uint32_t dwMaxDataRate;
uint8_t bNumDataRatesSupported;
uint32_t dwMaxIFSD;
uint32_t dwSynchProtocols;
uint32_t dwMechanical;
uint32_t dwFeatures;
uint32_t dwMaxCCIDMessageLength;
uint8_t bClassGetResponse;
uint8_t bClassEnvelope;
uint16_t wLcdLayout;
uint8_t bPINSupport;
uint8_t bMaxCCIDBusySlots;
};
static int ccid_parse_descriptor(struct usb_ccid_descriptor *ret,
unsigned char *in, size_t inlen)
{
if (inlen < USB_CCID_DESCRIPTOR_LENGTH)
return 1;
ret->bLength = in[0];
if (ret->bLength < USB_CCID_DESCRIPTOR_LENGTH)
return 1;
ret->bDescriptorType = in[1];
ret->bcdCCID = in[3] << 8 | in[2];
ret->bMaxSlotIndex = in[4];
ret->bVoltageSupport = in[5];
ret->dwProtocols = in[9] << 24 | in[8] << 16 | in[7] << 8 | in[6];
ret->dwDefaultClock =
in[13] << 24 | in[12] << 16 | in[11] << 8 | in[10];
ret->dwMaximumClock =
in[17] << 24 | in[16] << 16 | in[15] << 8 | in[14];
ret->bNumClockRatesSupported = in[18];
ret->dwDataRate = in[22] << 24 | in[21] << 16 | in[20] << 8 | in[19];
ret->dwMaxDataRate = in[26] << 24 | in[25] << 16 | in[24] << 8 | in[23];
ret->bNumDataRatesSupported = in[27];
ret->dwMaxIFSD = in[31] << 24 | in[30] << 16 | in[29] << 8 | in[28];
ret->dwSynchProtocols =
in[35] << 24 | in[34] << 16 | in[33] << 8 | in[32];
ret->dwMechanical = in[39] << 24 | in[38] << 16 | in[37] << 8 | in[36];
ret->dwFeatures = in[43] << 24 | in[42] << 16 | in[41] << 8 | in[40];
ret->dwMaxCCIDMessageLength = in[47] << 24 | in[46] << 16 |
in[45] << 8 | in[44];
ret->bClassGetResponse = in[48];
ret->bClassEnvelope = in[49];
ret->wLcdLayout = in[51] << 8 | in[50];
ret->bPINSupport = in[52];
ret->bMaxCCIDBusySlots = in[53];
return 0;
}
/*
* CT status
*/
typedef struct ccid_status {
int reader_type;
int usb_interface;
int proto_support;
int voltage_support;
int ifsd;
int maxmsg;
int flags;
unsigned char icc_present[OPENCT_MAX_SLOTS];
unsigned char icc_proto[OPENCT_MAX_SLOTS];
unsigned char *sbuf[OPENCT_MAX_SLOTS];
size_t slen[OPENCT_MAX_SLOTS];
unsigned char seq;
int support_events;
int events_active;
ifd_usb_capture_t *event_cap;
} ccid_status_t;
static int ccid_checkresponse(void *status, int r)
{
unsigned char *p = (unsigned char *)status;
if ((p[7] >> 6 & 3) == 0)
return 0;
/* XXX */
if ((p[7] >> 6 & 3) == 2) {
/*ct_error("card requests more time"); */
return -300;
}
switch (p[8]) {
case CCID_ERR_ICC_MUTE:
return IFD_ERROR_NO_CARD;
case CCID_ERR_XFR_PARITY:
case CCID_ERR_OVERRUN:
return IFD_ERROR_COMM_ERROR;
case CCID_ERR_BAD_ATR_TS:
case CCID_ERR_BAD_ATR_TCK:
return IFD_ERROR_NO_ATR;
case CCID_ERR_PROT_NOSUP:
case CCID_ERR_CLASS_NOSUP:
return IFD_ERROR_INCOMPATIBLE_DEVICE;
case CCID_ERR_BAD_PROC_BYTE:
return IFD_ERROR_INVALID_ARG;
case CCID_ERR_BUSY_AUTO_SEQ:
case CCID_ERR_SLOT_BUSY:
return IFD_ERROR_TIMEOUT;
case CCID_ERR_PIN_TIMEOUT:
return IFD_ERROR_USER_TIMEOUT;
case CCID_ERR_PIN_CANCELED:
return IFD_ERROR_USER_ABORT;
case CCID_OFFSET_MSGTYPE:
return IFD_ERROR_NOT_SUPPORTED;
case CCID_OFFSET_SLOT:
return IFD_ERROR_INVALID_SLOT;
}
return IFD_ERROR_GENERIC;
}
static int ccid_prepare_cmd(ifd_reader_t * reader, unsigned char *out,
size_t outsz, int slot, unsigned char cmd,
const void *ctl, const void *snd, size_t sendlen)
{
ccid_status_t *st = (ccid_status_t *) reader->driver_data;
unsigned char *p = out;
if (slot >= reader->nslots)
return IFD_ERROR_INVALID_SLOT;
if (sendlen + 10 > outsz) /* this probably means the apdu is larger
than the supported MaxMessageSize - 10 */
return IFD_ERROR_NOT_SUPPORTED;
*p++ = cmd;
*p++ = sendlen & 0xFF;
*p++ = (sendlen >> 8) & 0xFF;
*p++ = (sendlen >> 16) & 0xFF;
*p++ = (sendlen >> 24) & 0xFF;
*p++ = slot;
*p++ = st->seq++;
if (ctl)
memcpy(p, (unsigned char *)ctl, 3);
else
memset(p, 0, 3);
if (sendlen)
memcpy(&p[3], (unsigned char *)snd, sendlen);
return sendlen + 10;
}
static int ccid_extract_data(const void *in, size_t inlen, void *out,
size_t outlen)
{
unsigned char dlen[4];
size_t len;
if (inlen < 5) {
ct_error("short response from reader?!");
return IFD_ERROR_BUFFER_TOO_SMALL;
}
memcpy(dlen, ((char *)in) + 1, 4);
len = dlen[0] | dlen[1] << 8 | dlen[2] << 16 | dlen[3] << 24;
if (len == 0)
return 0;
if (inlen < len + 10) {
ct_error("truncated response from reader");
return IFD_ERROR_BUFFER_TOO_SMALL;
}
if (outlen < len) {
ct_error("user buffer too small (%d < %d)", outlen, len);
return IFD_ERROR_BUFFER_TOO_SMALL;
}
memcpy(out, ((char *)in) + 10, len);
return len;
}
static int ccid_command(ifd_reader_t * reader, const unsigned char *cmd,
size_t cmd_len, unsigned char *res, size_t res_len)
{
int rc;
size_t req_len;
if (!cmd_len || !res_len) {
ct_error("missing parameters to ccid_command");
return IFD_ERROR_INVALID_ARG;
}
req_len = res_len;
if (ct_config.debug >= 3)
ifd_debug(3, "sending:%s", ct_hexdump(cmd, cmd_len));
rc = ifd_device_send(reader->device, cmd, cmd_len);
if (rc < 0) {
ifd_debug(1, "ifd_device_send failed %d", rc);
return rc;
}
while (1) {
rc = ifd_device_recv(reader->device, res, req_len, 10000);
if (rc < 0)
return rc;
if (rc == 0) {
ct_error("zero length response from reader?!");
return IFD_ERROR_GENERIC;
}
if (ct_config.debug >= 3)
ifd_debug(3, "received:%s", ct_hexdump(res, rc));
if (rc < 9) {
return IFD_ERROR_GENERIC;
}
if (cmd[CCID_OFFSET_SLOT] == res[CCID_OFFSET_SLOT] &&
cmd[CCID_OFFSET_SEQ] == res[CCID_OFFSET_SEQ]) {
res_len = rc;
rc = ccid_checkresponse(res, res_len);
if (rc == -300) {
continue;
}
if (rc < 0)
return rc;
break;
}
}
return res_len;
}
static int ccid_simple_rcommand(ifd_reader_t * reader, int slot, int cmd,
void *ctl, void *res, size_t res_len)
{
ccid_status_t *st = reader->driver_data;
unsigned char cmdbuf[10];
unsigned char resbuf[CCID_MAX_MSG_LEN + 1];
int r;
r = ccid_prepare_cmd(reader, cmdbuf, 10, slot, cmd, ctl, NULL, 0);
if (r < 0)
return r;
r = ccid_command(reader, cmdbuf, 10, resbuf, st->maxmsg);
if (r < 0)
return r;
if (resbuf[0] != msg_expected[cmd - CCID_CMD_FIRST]) {
ct_error("Received a message of type x%02x instead of x%02x",
resbuf[0], msg_expected[cmd - CCID_CMD_FIRST]);
return -1;
}
if (res_len)
r = ccid_extract_data(&resbuf, r, res, res_len);
return r;
}
static int ccid_simple_wcommand(ifd_reader_t * reader, int slot, int cmd,
void *ctl, void *data, size_t data_len)
{
ccid_status_t *st = reader->driver_data;
unsigned char cmdbuf[CCID_MAX_MSG_LEN + 1];
unsigned char resbuf[CCID_MAX_MSG_LEN + 1];
int r;
r = ccid_prepare_cmd(reader, cmdbuf, st->maxmsg, slot, cmd, ctl, data,
data_len);
if (r < 0)
return r;
r = ccid_command(reader, cmdbuf, r, resbuf, st->maxmsg);
if (r < 0)
return r;
if (resbuf[0] != msg_expected[cmd - CCID_CMD_FIRST]) {
ct_error("Received a message of type x%02x instead of x%02x",
resbuf[0], msg_expected[cmd - CCID_CMD_FIRST]);
return -1;
}
return r;
}
#ifdef notyet
static int ccid_abort(ifd_reader_t * reader, int slot)
{
ccid_status_t *st = (ccid_status_t *) reader->driver_data;
int r;
if (ifd_device_type(reader->device) == IFD_DEVICE_TYPE_USB) {
r = ifd_usb_control(reader->device, 0x21
/*USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE */
,
CCID_REQ_ABORT, st->seq << 8 | slot,
st->usb_interface, NULL, 0, 10000);
if (r < 0)
return r;
r = ccid_simple_wcommand(reader, slot, CCID_CMD_ABORT, NULL,
NULL, 0);
return r;
} else
if (ifd_device_type(reader->device == IFD_DEVICE_TYPE_PCMCIA_BLOCK))
{
/* FIXME */
return IFD_ERROR_NOT_SUPPORTED;
}
return IFD_ERROR_NOT_SUPPORTED;
}
#endif
static int ccid_exchange(ifd_reader_t * reader, int slot,
const void *sbuf, size_t slen, void *rbuf, size_t rlen)
{
ccid_status_t *st = reader->driver_data;
unsigned char sendbuf[CCID_MAX_MSG_LEN + 1];
unsigned char recvbuf[CCID_MAX_MSG_LEN + 1];
int r;
unsigned char ctlbuf[3], *ctlptr=NULL;
ctlptr=NULL;
if (st->reader_type == TYPE_CHAR) {
ctlbuf[0] = 0;
ctlbuf[1] = rlen & 0xff;
ctlbuf[2] = (rlen >> 8) & 0xff;
ctlptr = ctlbuf;
}
r = ccid_prepare_cmd(reader, sendbuf, st->maxmsg,
slot, CCID_CMD_XFRBLOCK, ctlptr, sbuf, slen);
if (r < 0)
return r;
r = ccid_command(reader, &sendbuf[0], r, recvbuf, st->maxmsg);
if (r < 0)
return r;
return ccid_extract_data(&recvbuf, r, rbuf, rlen);
}
static int ccid_open_usb(ifd_device_t * dev, ifd_reader_t * reader)
{
ccid_status_t *st;
ifd_device_params_t params;
int r, i, c, ifc, alt, num_alt;
struct ifd_usb_device_descriptor de;
struct ifd_usb_config_descriptor conf;
struct ifd_usb_interface_descriptor *intf;
struct usb_ccid_descriptor ccid = { 0 };
int force_parse;
struct force_parse_device_st *force_dev;
unsigned char *_class;
unsigned char *p;
int support_events = 0;
#define PCSCLITE_FILE "/var/run/pcscd/pcscd.comm"
struct stat buf;
/* give priority to pcsc-lite for CCID devices */
if (0 == stat(PCSCLITE_FILE, &buf))
sleep(3);
if (ifd_usb_get_device(dev, &de)) {
ct_error("ccid: device descriptor not found");
ifd_device_close(dev);
return -1;
}
force_parse = 0;
for (force_dev = force_parse_devices; force_dev->vendor; force_dev++) {
if (de.idVendor == force_dev->vendor &&
de.idProduct == force_dev->product) {
force_parse = 1;
break;
}
}
intf = NULL;
p = NULL;
r = i = 0;
memset(&conf, 0, sizeof(conf));
for (c = 0; c < de.bNumConfigurations; c++) {
if (ifd_usb_get_config(dev, c, &conf)) {
ct_error("ccid: config descriptor %d not found", c);
continue;
}
if (!conf.interface)
continue;
for (ifc = 0; ifc < conf.bNumInterfaces; ifc++) {
num_alt = conf.interface[ifc].num_altsetting;
for (alt = 0; alt < num_alt; alt++) {
int typeok = 0;
int ok = 0;
intf = &conf.interface[ifc].altsetting[alt];
if (intf->bInterfaceClass == 0xb ||
intf->bInterfaceSubClass == 0 ||
intf->bInterfaceProtocol == 0)
typeok = 1;
/* accept class 0xFF if force_parse != 0 */
if (force_parse
&& intf->bInterfaceClass == 0xff)
typeok = 1;
if (intf->bNumEndpoints < 2
|| intf->bNumEndpoints > 3)
typeok = 0;
if (typeok == 0) {
intf = NULL;
continue;
}
if (intf->bNumEndpoints == 2) {
params.usb.ep_intr = 0;
ok |= 4;
}
if (intf->bNumEndpoints == 3) {
support_events = 1;
}
for (i = 0; i < intf->bNumEndpoints; i++) {
if (((intf->endpoint[i].bmAttributes &
IFD_USB_ENDPOINT_TYPE_MASK) ==
IFD_USB_ENDPOINT_TYPE_BULK) &&
(intf->endpoint[i].
bEndpointAddress &
IFD_USB_ENDPOINT_DIR_MASK) ==
IFD_USB_ENDPOINT_OUT) {
ok |= 1;
params.usb.ep_o =
intf->endpoint[i].
bEndpointAddress;
}
if (((intf->endpoint[i].bmAttributes &
IFD_USB_ENDPOINT_TYPE_MASK) ==
IFD_USB_ENDPOINT_TYPE_BULK) &&
(intf->endpoint[i].
bEndpointAddress &
IFD_USB_ENDPOINT_DIR_MASK) ==
IFD_USB_ENDPOINT_IN) {
ok |= 2;
params.usb.ep_i =
intf->endpoint[i].
bEndpointAddress;
}
if (((intf->endpoint[i].bmAttributes &
IFD_USB_ENDPOINT_TYPE_MASK) ==
IFD_USB_ENDPOINT_TYPE_INTERRUPT) &&
(intf->endpoint[i].
bEndpointAddress &
IFD_USB_ENDPOINT_DIR_MASK) ==
IFD_USB_ENDPOINT_IN) {
ok |= 4;
params.usb.ep_intr =
intf->endpoint[i].
bEndpointAddress;
}
}
if (ok == 7)
break;
intf = NULL;
}
if (!intf)
continue;
if (!intf->extralen) {
int i;
/* Buggy O2 Micro CCID SC Reader has zero extra len at interface level but not endpoint descriptor.
* Patch the interface level field and proceed.
* ProdID 7762 reader is in Dell Latitude D620 and 7772 is in D630.
*/
if( de.idVendor == 0x0b97 && (de.idProduct == 0x7762 || de.idProduct == 0x7772) ) {
ct_error("ccid: extra len is zero, patching O2 Micro support");
for (i=0; ibNumEndpoints; i++) {
/* find the extra[] array */
if( intf->endpoint[i].extralen == 54 ) {
/* get the extra[] from the endpoint */
intf->extralen = 54;
/* avoid double free on close, allocate here */
intf->extra = malloc(54);
if( intf->extra ) {
memcpy( intf->extra, intf->endpoint[i].extra, 54 );
break;
}
else {
intf = NULL;
continue;
}
}
}
}
else {
intf = NULL;
ct_error("ccid: extra len is zero, continuing");
continue;
}
}
r = intf->extralen;
_class = intf->extra;
i = 0;
p = _class + i;
/* 0x21 == USB_TYPE_CLASS | 0x1 */
/* accept descriptor type 0xFF if force_parse != 0 */
while (i < r && p[0] > 2 &&
(p[1] != 0x21 &&
(force_parse == 0 || p[1] != 0xff))) {
i += p[0];
p = _class + i;
}
if (i >= r || p[0] < 2 ||
(p[1] != 0x21 &&
(force_parse == 0 || p[1] != 0xff))) {
intf = NULL;
}
if (intf)
break;
}
if (intf)
break;
ifd_usb_free_configuration(&conf);
}
if (!intf) {
ct_error("ccid: class descriptor not found");
ifd_device_close(dev);
return -1;
}
/* Don't touch the device configuration if it's the one and only.
* The reason for this is that in multi purpose devices (eg keyboards
* with an integrated reader) some interfaces might already be in use.
* Trying to change the device configuration in such a case will produce
* this kernel message on Linux:
* usbfs: interface X claimed while 'ifdhandler' sets config #N
* and often the call will fail with EBUSY.
* Actually a bit better fix could be implemented in usb_set_params.
* The code there should check if the device is already in the requested
* configuration and thus if the change is needed after all. However
* implementing this would need a bunch of new sysdep functions to
* determine the current device configuration.
* So IMHO we should postpone this hard work until some USB device
* surfaces that really needs such magic.
*
* Antti Andreimann Thu Feb 2 2006
*/
if (de.bNumConfigurations > 1)
params.usb.configuration = conf.bConfigurationValue;
else
params.usb.configuration = -1;
params.usb.interface = intf->bInterfaceNumber;
if (num_alt > 1 || intf->bAlternateSetting > 0)
params.usb.altsetting = intf->bAlternateSetting;
else
params.usb.altsetting = -1;
r = ccid_parse_descriptor(&ccid, p, r - i);
ifd_usb_free_configuration(&conf);
if (r) {
ct_error("ccid: class descriptor is invalid");
ifd_device_close(dev);
return -1;
}
if (ccid.bcdCCID != 0x100 && ccid.bcdCCID != 0x110) {
ct_error("ccid: unknown ccid version %02x.%02x supported only 1.00, 1.10",
(ccid.bcdCCID >> 8) & 0xff,
(ccid.bcdCCID >> 0) & 0xff
);
ifd_device_close(dev);
return -1;
}
if ((st = (ccid_status_t *) calloc(1, sizeof(*st))) == NULL) {
ct_error("out of memory");
return IFD_ERROR_NO_MEMORY;
}
st->usb_interface = intf->bInterfaceNumber;
memset(st->icc_present, -1, OPENCT_MAX_SLOTS);
st->voltage_support = ccid.bVoltageSupport & 0x7;
st->proto_support = ccid.dwProtocols;
if ((st->proto_support & 3) == 0) {
ct_error
("ccid: device does not provide any supported protocols");
free(st);
ifd_device_close(dev);
return -1;
}
/* "When a CCID doesn't declare the values 00000010h and 00000020h, the
* frequency or the baud rate must be made via manufacturer proprietary
* PC_to_RDR_Escape command." - ccid class specification v1.00
*
* "The value of the lower word (=0840) indicates that the host will only
* send requests that are valid for the USB-ICC." - ISO/IEC 7816-12:2005
* 7.2/Table 8
*/
if ((ccid.dwFeatures & 0xFFFF) != 0x0840
&& ~ccid.dwFeatures & (0x10 | 0x20)) {
ct_error("ccid: required card initialization features missing");
free(st);
ifd_device_close(dev);
return -1;
}
st->reader_type = TYPE_CHAR;
if (ccid.dwFeatures & 0x10000) {
st->reader_type = TYPE_TPDU;
} else if (ccid.dwFeatures & 0x60000) {
st->reader_type = TYPE_APDU;
}
if (ccid.dwFeatures & 0x2)
st->flags |= FLAG_AUTO_ATRPARSE;
if (ccid.dwFeatures & 0x4)
st->flags |= FLAG_AUTO_ACTIVATE;
if (ccid.dwFeatures & 0x8)
st->voltage_support |= AUTO_VOLTAGE;
if (ccid.dwFeatures & 0x40)
st->flags |= FLAG_NO_PTS | FLAG_NO_SETPARAM;
if (ccid.dwFeatures & 0x80)
st->flags |= FLAG_NO_PTS;
st->ifsd = ccid.dwMaxIFSD;
/* must provide AUTO or at least one of 5/3.3/1.8 */
if (st->voltage_support == 0) {
ct_error
("ccid: device does not provide any supported voltages");
free(st);
ifd_device_close(dev);
return -1;
}
if (ccid.dwMaxCCIDMessageLength > CCID_MAX_MSG_LEN) {
st->maxmsg = CCID_MAX_MSG_LEN;
} else {
st->maxmsg = ccid.dwMaxCCIDMessageLength;
}
reader->driver_data = st;
reader->device = dev;
reader->nslots = ccid.bMaxSlotIndex + 1;
if (ifd_device_set_parameters(dev, ¶ms) < 0) {
ifd_device_close(dev);
return -1;
}
if (de.idVendor == 0x08e6 && de.idProduct == 0x3437) {
unsigned char settpdu[] = { 0xA0, 0x1 };
unsigned char setiso[] = { 0x1F, 0x1 };
r = ccid_simple_wcommand(reader, 0, CCID_CMD_ESCAPE, NULL,
settpdu, 2);
if (r < 0) {
ct_error("ccid: cannot set GemPlus TPDU mode");
ifd_device_close(dev);
return -1;
}
r = ccid_simple_wcommand(reader, 0, CCID_CMD_ESCAPE, NULL,
setiso, 2);
if (r < 0) {
ct_error("ccid: cannot set GemPlus ISO APDU mode");
ifd_device_close(dev);
return -1;
}
st->reader_type = TYPE_TPDU;
}
if (de.idVendor == 0x076b && de.idProduct == 0x5121) {
/* special handling of RFID part of OmniKey 5121 */
reader->nslots++; /* one virtual slot for RFID escape */
st->proto_support |= SUPPORT_ESCAPE;
}
st->support_events = support_events;
ifd_debug(3, "Accepted %04x:%04x with features 0x%x and protocols 0x%x events=%d", de.idVendor, de.idProduct, ccid.dwFeatures, ccid.dwProtocols, st->support_events);
return 0;
}
static int ccid_open_pcmcia_block(ifd_device_t * dev, ifd_reader_t * reader)
{
ccid_status_t *st;
/* unfortunately I know of no sanity checks that we could do with the
* hardware to confirm we're actually accessing a real pcmcia/ccid
* device -HW */
if ((st = (ccid_status_t *) calloc(1, sizeof(*st))) == NULL)
return IFD_ERROR_NO_MEMORY;
/* setup fake ccid_status_t based on totally guessed values */
memset(st->icc_present, -1, OPENCT_MAX_SLOTS);
st->voltage_support = 0x7;
st->proto_support = SUPPORT_T0 | SUPPORT_T1;
st->reader_type = TYPE_APDU;
st->voltage_support |= AUTO_VOLTAGE;
st->ifsd = 1; /* ? */
st->maxmsg = CCID_MAX_MSG_LEN;
st->flags = FLAG_AUTO_ATRPARSE | FLAG_NO_PTS; /*|FLAG_NO_SETPARAM; */
reader->driver_data = st;
reader->device = dev;
reader->nslots = 1;
return 0;
}
/*
* Initialize the device
*/
static int ccid_open(ifd_reader_t * reader, const char *device_name)
{
ifd_device_t *dev;
reader->name = "CCID Compatible";
if (!(dev = ifd_device_open(device_name)))
return -1;
if (ifd_device_type(dev) == IFD_DEVICE_TYPE_USB)
return ccid_open_usb(dev, reader);
else if (ifd_device_type(dev) == IFD_DEVICE_TYPE_PCMCIA_BLOCK)
return ccid_open_pcmcia_block(dev, reader);
else {
ct_error("ccid: device %s is not a supported device",
device_name);
ifd_device_close(dev);
return -1;
}
}
/*
* Close the device
*/
static int ccid_close(ifd_reader_t * reader)
{
ccid_status_t *st = (ccid_status_t *) reader->driver_data;
ifd_debug(1, "called.");
if (st->event_cap != NULL) {
ifd_usb_end_capture(reader->device, st->event_cap);
st->event_cap = NULL;
}
return 0;
}
static int ccid_activate(ifd_reader_t * reader)
{
ifd_debug(1, "called.");
return 0;
}
static int ccid_deactivate(ifd_reader_t * reader)
{
ifd_debug(1, "called.");
return 0;
}
static int ccid_card_status(ifd_reader_t * reader, int slot, int *status)
{
ccid_status_t *st = (ccid_status_t *) reader->driver_data;
int r, stat;
unsigned char ret[20];
unsigned char cmdbuf[10];
if (ifd_device_type(reader->device) == IFD_DEVICE_TYPE_USB &&
reader->device->settings.usb.ep_intr) {
ifd_usb_capture_t *cap;
int any = 0;
int i, j, bits;
if (st->proto_support & SUPPORT_ESCAPE
&& slot == reader->nslots - 1) {
ifd_debug(1,
"virtual escape slot, setting card present\n");
*status = IFD_CARD_PRESENT;
return 0;
}
i = 1 + (slot / 4);
j = 2 * (slot % 4);
stat = 0;
r = ifd_usb_begin_capture(reader->device,
IFD_USB_URB_TYPE_INTERRUPT,
reader->device->settings.usb.ep_intr,
8, &cap);
if (r < 0) {
ct_error("ccid: begin capture: %d", r);
return r;
}
/* read any bufferred interrupt pipe messages */
while (1) {
r = ifd_usb_capture(reader->device, cap, ret, 8, 100);
if (r < 0)
break;
if (ret[0] != 0x50)
continue;
ifd_debug(3, "status received:%s", ct_hexdump(ret, r));
bits = (ret[i] >> j) & 0x3;
if (bits & 2)
stat |= IFD_CARD_STATUS_CHANGED;
if (bits & 1)
stat |= IFD_CARD_PRESENT;
else
stat &= ~IFD_CARD_PRESENT;
any = 1;
}
ifd_usb_end_capture(reader->device, cap);
if (any) {
ifd_debug(1, "polled result: %d", stat);
st->icc_present[slot] = stat & IFD_CARD_PRESENT;
*status = stat;
return 0;
}
if (st->icc_present[slot] != 0xFF) {
ifd_debug(1, "cached result: %d",
st->icc_present[slot]);
*status = st->icc_present[slot];
return 0;
}
}
r = ccid_prepare_cmd(reader, cmdbuf, 10, 0, CCID_CMD_GETSLOTSTAT,
NULL, NULL, 0);
if (r < 0)
return r;
r = ccid_command(reader, cmdbuf, 10, ret, 10);
if (r == IFD_ERROR_NO_CARD) {
stat = 0;
}
else if (r < 0) {
return r;
}
else {
switch (ret[7] & 3) {
case 2:
stat = 0;
break;
default:
stat = IFD_CARD_PRESENT;
break;
}
}
ifd_debug(1, "probed result: %d", IFD_CARD_STATUS_CHANGED | stat);
*status = IFD_CARD_STATUS_CHANGED | stat;
st->icc_present[slot] = stat;
return 0;
}
static int ccid_set_protocol(ifd_reader_t * reader, int s, int proto);
/*
* Reset
*/
static int
ccid_card_reset(ifd_reader_t * reader, int slot, void *atr, size_t size)
{
ccid_status_t *st = (ccid_status_t *) reader->driver_data;
unsigned char buffer[IFD_MAX_ATR_LEN];
char ctlbuf[3];
int n, r, i;
int status;
r = ccid_card_status(reader, slot, &status);
if (r < 0)
return r;
if (!(status & IFD_CARD_PRESENT))
return IFD_ERROR_NO_CARD;
if (st->proto_support & SUPPORT_ESCAPE && slot == reader->nslots - 1) {
ifd_debug(1, "slot: %d, setting atr to 0xff", slot);
*((char *)atr) = 0xff;
ccid_set_protocol(reader, slot, IFD_PROTOCOL_ESCAPE);
return 1;
}
memset(ctlbuf, 0, 3);
n = -1;
if (st->voltage_support & AUTO_VOLTAGE
|| st->flags & FLAG_AUTO_ACTIVATE) {
ifd_debug(1, "called. powering on with auto voltage selection");
n = ccid_simple_rcommand(reader, slot, CCID_CMD_ICCPOWERON,
ctlbuf, buffer, IFD_MAX_ATR_LEN);
}
if (n < 0 && (st->voltage_support & AUTO_VOLTAGE) == 0) {
ifd_debug(1,
"called. powering on with manual voltage selection");
for (i = 1; i <= 3; i++) {
if ((st->voltage_support & (1 << (i - 1))) == 0)
continue;
ifd_debug(3, "Trying voltage parameter %d", i);
ctlbuf[0] = i;
n = ccid_simple_rcommand(reader, slot,
CCID_CMD_ICCPOWERON, ctlbuf,
buffer, IFD_MAX_ATR_LEN);
if (n > 0)
break;
}
}
if (n < 0)
return n;
if (n > size)
return IFD_ERROR_BUFFER_TOO_SMALL;
memcpy(atr, buffer, n);
return n;
}
static int ccid_set_protocol(ifd_reader_t * reader, int s, int proto)
{
ccid_status_t *st = (ccid_status_t *) reader->driver_data;
unsigned char parambuf[17], ctl[3];
ifd_slot_t *slot;
ifd_protocol_t *p;
ifd_atr_info_t atr_info;
int r, paramlen;
slot = &reader->slot[s];
/* If we support RFID escaping, we only allow ESCAPE protocol
* at the last (== virtual) slot */
if ((st->proto_support & SUPPORT_ESCAPE)
&& (proto != IFD_PROTOCOL_ESCAPE)
&& (s == reader->nslots - 1)) {
ct_error("reader doesn't support this protocol at this slot\n");
return IFD_ERROR_NOT_SUPPORTED;
}
switch (proto) {
case IFD_PROTOCOL_T0:
if (!(st->proto_support & SUPPORT_T0)) {
ct_error("reader does not support this protocol");
return IFD_ERROR_NOT_SUPPORTED;
}
break;
case IFD_PROTOCOL_T1:
if (!(st->proto_support & SUPPORT_T1)) {
ct_error("reader does not support this protocol");
return IFD_ERROR_NOT_SUPPORTED;
}
break;
case IFD_PROTOCOL_ESCAPE:
/* virtual "escape" fallthrough protocol for stacking RFID
* protocol stack on top of openct */
if (!(st->proto_support & SUPPORT_ESCAPE)) {
ct_error("reader does not support this protocol");
return IFD_ERROR_NOT_SUPPORTED;
}
if (s != reader->nslots - 1) {
ct_error
("reader doesn't support this protocol at this slot");
return IFD_ERROR_NOT_SUPPORTED;
}
p = ifd_protocol_new(IFD_PROTOCOL_ESCAPE, reader, slot->dad);
if (!p) {
ct_error("%s: internal error", reader->name);
return -1;
}
if (slot->proto) {
ifd_protocol_free(slot->proto);
slot->proto = NULL;
}
slot->proto = p;
st->icc_proto[s] = proto;
ifd_debug(1, "set protocol to ESCAPE\n");
return 0;
break;
default:
ct_error("protocol unknown");
return IFD_ERROR_NOT_SUPPORTED;
}
if (st->reader_type == TYPE_APDU) {
p = ifd_protocol_new(IFD_PROTOCOL_TRANSPARENT,
reader, slot->dad);
if (p == NULL) {
ct_error("%s: internal error", reader->name);
return -1;
}
if (slot->proto) {
ifd_protocol_free(slot->proto);
slot->proto = NULL;
}
slot->proto = p;
st->icc_proto[s] = proto;
return 0;
}
r = ifd_atr_parse(&atr_info, slot->atr, slot->atr_len);
if (r < 0) {
ct_error("%s: Bad ATR", reader->name);
return r;
}
/* ccid doesn't have a parameter for this */
if (atr_info.TC[0] == 255)
atr_info.TC[0] = -1;
/*
* guard time increase must precede PTS
* we don't need to do this separate step if
* a) the ccid does automatic parameter setting, or
* b) the ccid parses the atr itself, or
* c) the ccid does pts itself when we set parameters, or
* d) the ICC does not require extra guard time
* In all but the first case, we'll do parameter setting later,
* so fetch the default parameters now.
*/
if ((st->flags & FLAG_NO_SETPARAM) == 0) {
memset(parambuf, 0, sizeof(parambuf));
memset(ctl, 0, 3);
r = ccid_simple_rcommand(reader, s, CCID_CMD_GETPARAMS,
ctl, parambuf, 7);
if (r < 0)
return r;
if (proto == IFD_PROTOCOL_T0) {
paramlen = 5;
ctl[0] = 0;
}
else {
paramlen = 7;
ctl[0] = 1;
}
if ((st->flags & (FLAG_NO_PTS | FLAG_AUTO_ATRPARSE)) == 0 &&
atr_info.TC[0] != -1) {
parambuf[2] = atr_info.TC[0];
r = ccid_simple_wcommand(reader, s, CCID_CMD_SETPARAMS,
ctl, parambuf, paramlen);
if (r < 0)
return r;
}
}
if ((st->flags & FLAG_NO_PTS) == 0 &&
(proto == IFD_PROTOCOL_T1 || atr_info.TA[0] != -1)) {
unsigned char pts[7], ptsret[7];
int ptslen;
ptslen = ifd_build_pts(&atr_info, proto, pts, sizeof(pts));
if (ptslen < 0) {
ct_error("%s: Could not perform PTS: %s", reader->name,
ct_strerror(r));
return ptslen;
}
r = ccid_exchange(reader, s, pts, ptslen, ptsret,
ptslen);
if (r < 0)
return r;
r = ifd_verify_pts(&atr_info, proto, ptsret, r);
if (r) {
ct_error("%s: Bad PTS response", reader->name);
return r;
}
}
if ((st->flags & FLAG_NO_SETPARAM) == 0 &&
((st->flags & FLAG_AUTO_ATRPARSE) == 0 ||
proto != IFD_PROTOCOL_T0)) {
/* if FLAG_AUTO_ATRPARSE, only set the protocol. */
if ((st->flags & FLAG_AUTO_ATRPARSE) == 0) {
if (proto == IFD_PROTOCOL_T0) {
/* TA1 -> Fi | Di */
if (atr_info.TA[0] != -1)
parambuf[0] = atr_info.TA[0];
/* TC1 -> N */
if (atr_info.TC[0] != -1)
parambuf[2] = atr_info.TC[0];
/* TC2 -> WI */
if (atr_info.TC[1] != -1)
parambuf[3] = atr_info.TC[1];
/* TA3 -> clock stop parameter */
/* XXX check for IFD clock stop support */
if (atr_info.TA[2] != -1)
parambuf[4] = atr_info.TA[2] >> 6;
}
else if (proto == IFD_PROTOCOL_T1) {
if (atr_info.TA[0] != -1)
parambuf[0] = atr_info.TA[0];
parambuf[1] = 0x10;
/* TC3 -> LRC/CRC selection */
if (atr_info.TC[2] == 1)
parambuf[1] |= 0x1;
else
parambuf[1] &= 0xfe;
/* TC1 -> N */
if (atr_info.TC[0] != -1)
parambuf[2] = atr_info.TC[0];
/* atr_info->TB3 -> BWI/CWI */
if (atr_info.TB[2] != -1)
parambuf[3] = atr_info.TB[2];
/* TA3 -> IFSC */
if (atr_info.TA[2] != -1)
parambuf[5] = atr_info.TA[2];
/*
* XXX CCID supports setting up clock stop for T=1, but the
* T=1 ATR does not define a clock-stop byte.
*/
}
}
r = ccid_simple_wcommand(reader, s, CCID_CMD_SETPARAMS, ctl,
parambuf, paramlen);
if (r < 0)
return r;
}
memset(¶mbuf[r], 0, sizeof(parambuf) - r);
if (proto == IFD_PROTOCOL_T0) {
if (st->reader_type == TYPE_CHAR) {
p = ifd_protocol_new(proto,
reader, slot->dad);
} else {
p = ifd_protocol_new(IFD_PROTOCOL_TRANSPARENT,
reader, slot->dad);
}
} else {
p = ifd_protocol_new(proto, reader, slot->dad);
if (p) {
/* guessing that ifsc is limited by ifsd */
if (atr_info.TA[2] != -1)
ifd_protocol_set_parameter(p,
IFD_PROTOCOL_T1_IFSC,
atr_info.TA[2] >
st->ifsd ? st->
ifsd : atr_info.
TA[2]);
ifd_protocol_set_parameter(p, IFD_PROTOCOL_T1_IFSD,
st->ifsd);
if (atr_info.TC[2] == 1)
ifd_protocol_set_parameter(p,
IFD_PROTOCOL_T1_CHECKSUM_CRC,
0);
}
}
if (p == NULL) {
ct_error("%s: internal error", reader->name);
return -1;
}
/* ccid_recv needs to know the exact expected data length */
if (st->reader_type == TYPE_CHAR)
ifd_protocol_set_parameter(p, IFD_PROTOCOL_BLOCK_ORIENTED, 0);
if (slot->proto) {
ifd_protocol_free(slot->proto);
slot->proto = NULL;
}
slot->proto = p;
st->icc_proto[s] = proto;
return 0;
}
static int ccid_escape(ifd_reader_t * reader, int slot, const void *sbuf,
size_t slen, void *rbuf, size_t rlen)
{
unsigned char sendbuf[CCID_MAX_MSG_LEN];
unsigned char recvbuf[CCID_MAX_MSG_LEN];
int r;
ifd_debug(1, "slot: %d, slen %d, rlen %d", slot, slen, rlen);
r = ccid_prepare_cmd(reader, sendbuf, sizeof(sendbuf), slot,
CCID_CMD_ESCAPE, NULL, sbuf, slen);
if (r < 0)
return r;
r = ccid_command(reader, &sendbuf[0], r, recvbuf, sizeof(recvbuf));
if (r < 0)
return r;
return ccid_extract_data(&recvbuf, r, rbuf, rlen);
}
static int
ccid_transparent(ifd_reader_t * reader, int slot,
const void *sbuf, size_t slen, void *rbuf, size_t rlen)
{
ccid_status_t *st = (ccid_status_t *) reader->driver_data;
ifd_debug(1, "called.");
if (st->reader_type == TYPE_APDU ||
(st->reader_type == TYPE_TPDU &&
st->icc_proto[slot] == IFD_PROTOCOL_T0))
return ccid_exchange(reader, slot, sbuf, slen, rbuf, rlen);
return IFD_ERROR_NOT_SUPPORTED;
}
static int ccid_send(ifd_reader_t * reader, unsigned int dad,
const unsigned char *buffer, size_t len)
{
ccid_status_t *st = (ccid_status_t *) reader->driver_data;
unsigned char *apdu;
ifd_debug(1, "called.");
if (st->sbuf[dad]) {
free(st->sbuf[dad]);
st->sbuf[dad] = NULL;
st->slen[dad] = 0;
}
apdu = (unsigned char *)calloc(1, len);
if (!apdu) {
ct_error("out of memory");
return IFD_ERROR_NO_MEMORY;
}
memcpy(apdu, buffer, len);
st->sbuf[dad] = apdu;
st->slen[dad] = len;
return 0;
}
static int ccid_recv(ifd_reader_t * reader, unsigned int dad,
unsigned char *buffer, size_t len, long timeout)
{
ccid_status_t *st = (ccid_status_t *) reader->driver_data;
int r;
ifd_debug(1, "called.");
r = ccid_exchange(reader, dad, st->sbuf[dad], st->slen[dad], buffer,
len);
if (st->sbuf[dad])
free(st->sbuf[dad]);
st->sbuf[dad] = NULL;
st->slen[dad] = 0;
if (r < 0)
ifd_debug(3, "failed: %d", r);
return r;
}
static int ccid_before_command(ifd_reader_t * reader)
{
ccid_status_t *st = (ccid_status_t *) reader->driver_data;
int rc;
ifd_debug(1, "called.");
if (!st->events_active) {
return 0;
}
if (st->event_cap == NULL) {
return 0;
}
rc = ifd_usb_end_capture(reader->device, st->event_cap);
st->event_cap = NULL;
return rc;
}
static int ccid_after_command(ifd_reader_t * reader)
{
ccid_status_t *st = (ccid_status_t *) reader->driver_data;
ifd_debug(1, "called.");
if (!st->events_active) {
return 0;
}
if (st->event_cap != NULL) {
return 0;
}
return ifd_usb_begin_capture(
reader->device,
IFD_USB_URB_TYPE_INTERRUPT,
reader->device->settings.usb.ep_intr,
8, &st->event_cap
);
}
static int ccid_get_eventfd(ifd_reader_t * reader, short *events)
{
ccid_status_t *st = (ccid_status_t *) reader->driver_data;
int fd;
ifd_debug(1, "called.");
if (!st->support_events) {
return -1;
}
fd = ifd_device_get_eventfd(reader->device, events);
if (fd != -1) {
st->events_active = 1;
}
return fd;
}
static int ccid_event(ifd_reader_t * reader, int *status, size_t status_size)
{
ccid_status_t *st = (ccid_status_t *) reader->driver_data;
unsigned char ret[20];
int bytes;
ifd_debug(1, "called.");
if (status_size < reader->nslots) {
return IFD_ERROR_BUFFER_TOO_SMALL;
}
bytes = ifd_usb_capture_event(reader->device, st->event_cap, ret, 8);
if (bytes < 0) {
return bytes;
}
if (bytes > 0 && ret[0] == 0x50) {
int slot;
ifd_debug(3, "status received:%s", ct_hexdump(ret, bytes));
for (slot=0;slotnslots;slot++) {
if (1 + (slot / 4) < bytes) {
int bits = (ret[1 + (slot / 4)] >> (2 * (slot % 4))) & 0x3;
if (bits & 2)
status[slot] |= IFD_CARD_STATUS_CHANGED;
if (bits & 1)
status[slot] |= IFD_CARD_PRESENT;
else
status[slot] &= ~IFD_CARD_PRESENT;
ifd_debug(1, "slot %d event result: %08x", slot, status[slot]);
st->icc_present[slot] = status[slot] & IFD_CARD_PRESENT;
}
}
}
return 0;
}
static int ccid_error(ifd_reader_t * reader)
{
(void)reader;
ifd_debug(1, "called.");
return IFD_ERROR_DEVICE_DISCONNECTED;
}
/*
* Driver operations
*/
static struct ifd_driver_ops ccid_driver;
/*
* Initialize this module
*/
void ifd_ccid_register(void)
{
ccid_driver.open = ccid_open;
ccid_driver.close = ccid_close;
ccid_driver.activate = ccid_activate;
ccid_driver.deactivate = ccid_deactivate;
ccid_driver.card_status = ccid_card_status;
ccid_driver.card_reset = ccid_card_reset;
ccid_driver.set_protocol = ccid_set_protocol;
ccid_driver.transparent = ccid_transparent;
ccid_driver.send = ccid_send;
ccid_driver.recv = ccid_recv;
ccid_driver.escape = ccid_escape;
ccid_driver.before_command = ccid_before_command;
ccid_driver.after_command = ccid_after_command;
ccid_driver.get_eventfd = ccid_get_eventfd;
ccid_driver.event = ccid_event;
ccid_driver.error = ccid_error;
ifd_driver_register("ccid", &ccid_driver);
}
openct-0.6.20/src/ifd/proto-t0.c 0000644 0001750 0001750 00000014757 10625650421 013210 0000000 0000000 /*
* Implementation of T=0
*
* Copyright (C) 2003, Olaf Kirch
*/
#include "internal.h"
#include
#include
#include
#include
typedef struct {
ifd_protocol_t base;
int state;
long timeout;
unsigned int block_oriented;
unsigned int max_nulls;
} t0_state_t;
enum {
IDLE, SENDING, RECEIVING, CONFUSED
};
static int t0_xcv(ifd_protocol_t *, const void *, size_t, void *, size_t);
static int t0_send(ifd_protocol_t *, ct_buf_t *, int);
static int t0_recv(ifd_protocol_t *, ct_buf_t *, int, long);
static int t0_resynch(t0_state_t *);
/*
* Set default T=1 protocol parameters
*/
static void t0_set_defaults(t0_state_t * t0)
{
t0->state = IDLE;
t0->timeout = 2000;
t0->max_nulls = 800;
}
/*
* Attach t0 protocol
*/
static int t0_init(ifd_protocol_t * prot)
{
t0_set_defaults((t0_state_t *) prot);
return 0;
}
/*
* Detach t0 protocol
*/
static void t0_release(ifd_protocol_t * prot)
{
/* NOP */
}
/*
* Get/set parmaters for T1 protocol
*/
static int t0_set_param(ifd_protocol_t * prot, int type, long value)
{
t0_state_t *t0 = (t0_state_t *) prot;
switch (type) {
case IFD_PROTOCOL_RECV_TIMEOUT:
t0->timeout = value;
break;
case IFD_PROTOCOL_BLOCK_ORIENTED:
t0->block_oriented = value;
break;
default:
ct_error("Unsupported parameter %d", type);
return -1;
}
return 0;
}
static int t0_get_param(ifd_protocol_t * prot, int type, long *result)
{
t0_state_t *t0 = (t0_state_t *) prot;
long value;
switch (type) {
case IFD_PROTOCOL_RECV_TIMEOUT:
value = t0->timeout;
break;
case IFD_PROTOCOL_BLOCK_ORIENTED:
value = t0->block_oriented;
break;
default:
ct_error("Unsupported parameter %d", type);
return -1;
}
if (result)
*result = value;
return 0;
}
/*
* Send an APDU through T=0
*/
static int t0_transceive(ifd_protocol_t * prot, int dad, const void *sbuf,
size_t slen, void *rbuf, size_t rlen)
{
t0_state_t *t0 = (t0_state_t *) prot;
ifd_iso_apdu_t iso;
unsigned char sdata[5];
unsigned int cla, cse, lc, le;
int rc;
if (t0->state != IDLE) {
if (t0_resynch(t0) < 0)
return -1;
t0->state = IDLE;
}
if (slen < 4 || rlen < 2)
return -1;
/* Check the APDU case etc */
if ((rc = ifd_iso_apdu_parse(sbuf, slen, &iso)) < 0)
return rc;
cse = iso.cse;
cla = iso.cla;
lc = iso.lc;
le = iso.le;
switch (cse) {
case IFD_APDU_CASE_1:
/* Include a NUL lc byte */
memcpy(sdata, sbuf, 4);
sdata[4] = 0;
sbuf = sdata;
slen = 5;
break;
case IFD_APDU_CASE_2S:
case IFD_APDU_CASE_3S:
break;
case IFD_APDU_CASE_4S:
/* Strip off the Le byte */
slen--;
break;
default:
/* We don't handle ext APDUs */
return -1;
}
/*
if (le + 2 > slen) {
ct_error("t0_transceive: recv buffer too small");
return -1;
}
*/
if (lc) {
t0->state = SENDING;
if ((rc = t0_xcv(prot, sbuf, slen, rbuf, 2)) < 0)
return rc;
/* Can this happen? */
if (rc != 2)
return IFD_ERROR_COMM_ERROR;
/* Case 4 APDU - check whether we should
* try to get the response */
if (cse == IFD_APDU_CASE_4S) {
unsigned char *sw;
sw = (unsigned char *)rbuf;
if (sw[0] == 0x61) {
/* additional length info */
if (sw[1] != 0 && sw[1] < le)
le = sw[1];
} else if ((sw[0] & 0xF0) == 0x60) {
/* Command not accepted, do not
* retrieve response
*/
goto done;
}
/* Transmit a Get Response command */
sdata[0] = cla;
sdata[1] = 0xC0;
sdata[2] = 0x00;
sdata[3] = 0x00;
sdata[4] = le;
t0->state = RECEIVING;
rc = t0_xcv(prot, sdata, 5, rbuf, le + 2);
}
} else {
t0->state = RECEIVING;
rc = t0_xcv(prot, sbuf, slen, rbuf, le + 2);
}
done:t0->state = IDLE;
return rc;
}
static int t0_xcv(ifd_protocol_t * prot, const void *sdata, size_t slen,
void *rdata, size_t rlen)
{
t0_state_t *t0 = (t0_state_t *) prot;
ct_buf_t sbuf, rbuf;
unsigned int null_count = 0;
unsigned int ins;
/* Let the driver handle any chunking etc */
if (t0->block_oriented) {
int rc;
if ((rc = ifd_send_command(prot, sdata, slen)) >= 0)
rc = ifd_recv_response(prot, rdata, rlen, t0->timeout);
return rc;
}
/* Set up the send buffer */
ct_buf_set(&sbuf, (void *)sdata, slen);
ct_buf_init(&rbuf, rdata, rlen);
/* Get the INS */
ins = sbuf.base[1];
if (t0_send(prot, &sbuf, 5) < 0)
goto failed;
while (1) {
unsigned char byte;
int count;
if (ifd_recv_response(prot, &byte, 1, t0->timeout) < 0)
goto failed;
/* Null byte to extend wait time */
if (byte == 0x60) {
usleep(100000);
if (++null_count > t0->max_nulls)
goto failed;
continue;
}
/* ICC sends SW1 SW2 */
if ((byte & 0xF0) == 0x60 || (byte & 0xF0) == 0x90) {
/* Store SW1, then get SW2 and store it */
if (ct_buf_put(&rbuf, &byte, 1) < 0
|| t0_recv(prot, &rbuf, 1, t0->timeout) < 0)
goto failed;
break;
}
/* Send/receive data.
* ACK byte means transfer everything in one go,
* ~ACK means do it octet by octet.
* SCEZ masks off using 0xFE, but the Towitoko
* driver uses 0x0E.
* Do we need to make this configurable?
*/
if (((byte ^ ins) & 0xFE) == 0) {
/* Send/recv as much as we can */
count = -1;
} else if (((~byte ^ ins) & 0xFE) == 0) {
count = 1;
} else {
ifd_debug(2, "unexpected byte 0x%02x", byte);
return -1;
}
if (t0->state == SENDING) {
if (t0_send(prot, &sbuf, count) < 0)
goto failed;
} else {
if (t0_recv(prot, &rbuf, count, t0->timeout) < 0)
goto failed;
if (ct_buf_tailroom(&rbuf) == 0)
break;
}
}
return ct_buf_avail(&rbuf);
failed:t0->state = CONFUSED;
return -1;
}
static int t0_send(ifd_protocol_t * prot, ct_buf_t * bp, int count)
{
int n, avail;
avail = ct_buf_avail(bp);
if (count < 0)
count = avail;
if (count > avail || !avail)
return -1;
n = ifd_send_command(prot, ct_buf_head(bp), count);
if (n >= 0)
ct_buf_get(bp, NULL, count);
return n;
}
static int t0_recv(ifd_protocol_t * prot, ct_buf_t * bp, int count,
long timeout)
{
int n;
if (count < 0)
count = ct_buf_tailroom(bp);
n = ifd_recv_response(prot, ct_buf_tail(bp), count, timeout);
if (n >= 0)
ct_buf_put(bp, NULL, count);
return n;
}
static int t0_resynch(t0_state_t * t0)
{
return -1;
}
/*
* Protocol struct
*/
struct ifd_protocol_ops ifd_protocol_t0 = {
IFD_PROTOCOL_T0, /* id */
"T=0", /* name */
sizeof(t0_state_t), /* size */
t0_init, /* init */
t0_release, /* release */
t0_set_param, /* set_param */
t0_get_param, /* get_param */
NULL, /* resynchronize */
t0_transceive, /* transceive */
NULL, /* sync_read */
NULL, /* sync_write */
};
openct-0.6.20/src/ifd/ifdproxy.c 0000644 0001750 0001750 00000013046 10625650421 013356 0000000 0000000 /*
* Remote device access - debugging utility that allows to
* test smart card readers on remote hosts.
*
* Copyright (C) 2003, Olaf Kirch
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#include
#include
#ifdef HAVE_GETOPT_H
#include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "internal.h"
#include "ria.h"
static int opt_foreground = 0;
static char *opt_config = NULL;
static const char *opt_device_port = ":6666";
static const char *opt_server_port = "proxy";
static const char *opt_chroot = NULL;
static const char *opt_user = NULL;
static int get_ports(void);
static int run_server(int, char **);
static int run_client(int, char **);
static int list_devices(int, char **);
static void usage(int);
static void version(void);
int main(int argc, char **argv)
{
char *command;
int c;
if (argc < 2)
usage(1);
ct_log_destination("@stderr");
while ((c = getopt(argc, argv, "df:FR:U:v")) != -1) {
switch (c) {
case 'd':
ct_config.debug++;
break;
case 'f':
opt_config = optarg;
break;
case 'F':
opt_foreground++;
break;
case 'R':
opt_chroot = optarg;
break;
case 'U':
opt_user = optarg;
break;
case 'v':
version();
break;
default:
usage(1);
}
}
if (ifd_config_parse(opt_config) < 0)
return 1;
if (optind >= argc)
usage(1);
command = argv[optind++];
if (get_ports() < 0)
return 1;
if (!strcmp(command, "server")) {
run_server(argc - optind, argv + optind);
} else if (!strcmp(command, "export")) {
return run_client(argc - optind, argv + optind);
} else if (!strcmp(command, "list")) {
list_devices(argc - optind, argv + optind);
} else if (!strcmp(command, "version")) {
version();
} else {
ct_error("Unknown command `%s'\n", command);
return 1;
}
return 0;
}
static void enter_jail(void)
{
struct passwd *pw = NULL;
if (opt_chroot && !opt_user)
opt_user = "nobody";
if (opt_user) {
if (!(pw = getpwnam(opt_user))) {
ct_error("Unknown user %s\n", opt_user);
exit(1);
}
endpwent();
}
if (opt_chroot) {
if (chdir("/") < 0 || chroot(opt_chroot) < 0) {
ct_error("chroot(%s) failed: %m", opt_chroot);
exit(1);
}
}
if (pw) {
if (setgroups(0, NULL) < 0
|| setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
ct_error("Failed to drop privileges: %m");
exit(1);
}
}
}
static void background_process(void)
{
int fd;
if (daemon(0, 0) < 0) {
ct_error("failed to background process: %m");
exit(1);
}
if ((fd = open("/dev/null", O_RDWR)) >= 0) {
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
if (fd > 2)
close(fd);
}
ct_log_destination("@syslog");
setsid();
}
static int get_ports(void)
{
char *address;
int rc;
if ((rc = ifd_conf_get_string("ifdproxy.device-port", &address)) >= 0)
opt_device_port = address;
if ((rc = ifd_conf_get_string("ifdproxy.server-port", &address)) >= 0)
opt_server_port = address;
return 0;
}
static int run_server(int argc, char **argv)
{
int rc;
char path[PATH_MAX];
if (!ct_format_path(path, PATH_MAX, opt_server_port)) {
return -1;
}
if (argc != 0)
usage(1);
if (ct_config.debug)
ct_socket_reuseaddr(1);
if ((rc = ria_svc_listen(path, 1)) < 0) {
ct_error("Cannot bind to server port \"%s\": %s\n",
path, ct_strerror(rc));
return rc;
}
if ((rc = ria_svc_listen(opt_device_port, 0)) < 0) {
ct_error("Cannot bind to device port \"%s\": %s\n",
opt_device_port, ct_strerror(rc));
return rc;
}
enter_jail();
if (!opt_foreground)
background_process();
ct_mainloop();
return 0;
}
static int run_client(int argc, char **argv)
{
const char *name, *device, *address;
ria_client_t *ria;
int rc;
/* Initialize IFD library */
if (ifd_init())
return 1;
if (argc != 2 && argc != 3)
usage(1);
name = argv[0];
device = argv[1];
address = argc == 3 ? argv[2] : opt_device_port;
ria = ria_export_device(address, device);
ifd_debug(1, "About to register device as \"%s\"", name);
if ((rc = ria_register_device(ria, name)) < 0) {
ct_error("Unable to register device: %s\n", ct_strerror(rc));
exit(1);
}
enter_jail();
if (!opt_foreground)
background_process();
ct_mainloop();
return 0;
}
static int list_devices(int argc, char **argv)
{
unsigned char buffer[8192];
ria_device_t *info;
ria_client_t *clnt;
unsigned int n, count;
int rc;
if (argc == 1)
opt_server_port = argv[0];
else if (argc > 1)
usage(1);
if (!(clnt = ria_connect(opt_server_port)))
exit(1);
rc = ria_command(clnt, RIA_MGR_LIST, NULL, 0, buffer, sizeof(buffer),
-1);
if (rc < 0) {
ct_error("Failed to list exported devices: %s",
ct_strerror(rc));
ria_free(clnt);
return 1;
}
count = rc / sizeof(ria_device_t);
if (count == 0) {
printf("No exported devices\n");
ria_free(clnt);
return 0;
}
printf("Exported devices\n");
for (info = (ria_device_t *) buffer, n = 0; n < count; info++, n++) {
printf(" %-16s %-30s %s\n",
info->handle, info->address, info->name);
}
ria_free(clnt);
return 0;
}
static void version(void)
{
fprintf(stderr, "OpenCT " VERSION "\n");
exit(0);
}
static void usage(int exval)
{
fprintf(exval ? stderr : stdout,
"Usage:\n"
"ifdproxy server [-dF]\n"
"ifdproxy export [-dF] name device address\n"
"ifdproxy list [-dF] address\n" "ifdproxy version\n");
exit(exval);
}
openct-0.6.20/src/ifd/ctbcs.c 0000644 0001750 0001750 00000005662 10625650421 012615 0000000 0000000 /*
* Build Extended CTBCS APDUs for those readers that
* support them (such as Kobil Kaan).
*
* Copyright (C) 2003, Olaf Kirch
*/
#include "internal.h"
#include
#include
#include
#include
#include "ctbcs.h"
/*
* Start building CTBCS apdu
*/
void ctbcs_begin(ct_buf_t * bp, unsigned int ins, unsigned int p1,
unsigned int p2)
{
ct_buf_putc(bp, 0x20);
ct_buf_putc(bp, ins);
ct_buf_putc(bp, p1);
ct_buf_putc(bp, p2);
ct_buf_putc(bp, 0);
}
/*
* Finish CTBCS apdu
*/
int ctbcs_finish(ct_buf_t * bp)
{
unsigned int len;
if (ct_buf_overrun(bp))
return IFD_ERROR_BUFFER_TOO_SMALL;
len = ct_buf_avail(bp);
bp->base[4] = len - 5; /* lc */
return len;
}
/*
* Output a string to the display
*/
int ctbcs_build_output(unsigned char *cmd, size_t size, const char *message)
{
ct_buf_t buf;
if (message == NULL)
return IFD_ERROR_INVALID_ARG;
ct_buf_init(&buf, cmd, size);
ctbcs_begin(&buf, 0x17, 0x40, 0x00);
ctbcs_add_message(&buf, message);
return ctbcs_finish(&buf);
}
/*
* Generic Verify APDU
*/
static int ctbcs_build_verify_apdu(unsigned char *cmd, size_t size,
unsigned char ins, unsigned char p1,
const char *prompt, unsigned int timeout,
const unsigned char *data, size_t data_len)
{
ct_buf_t buf;
if (!data || !data_len)
return IFD_ERROR_INVALID_ARG;
if (prompt == NULL)
return IFD_ERROR_INVALID_ARG;
ct_buf_init(&buf, cmd, size);
ctbcs_begin(&buf, ins, p1, 0x00);
ctbcs_add_timeout(&buf, timeout);
ctbcs_add_message(&buf, prompt);
ct_buf_putc(&buf, 0x52);
ct_buf_putc(&buf, data_len);
ct_buf_put(&buf, data, data_len);
if (ct_buf_overrun(&buf))
return IFD_ERROR_BUFFER_TOO_SMALL;
cmd[4] = ct_buf_avail(&buf) - 5; /* lc */
return ct_buf_avail(&buf);
}
/*
* Build Perform Verify APDU
*/
int ctbcs_build_perform_verify_apdu(unsigned char *cmd, size_t size,
unsigned int p1, const char *prompt,
unsigned int timeout,
const unsigned char *data, size_t data_len)
{
return ctbcs_build_verify_apdu(cmd, size, 0x18, p1,
prompt, timeout, data, data_len);
}
/*
* Build Modify Verify APDU
*/
int ctbcs_build_modify_verify_apdu(unsigned char *cmd, size_t size,
unsigned int p1, const char *prompt,
unsigned int timeout,
const unsigned char *data, size_t data_len)
{
return ctbcs_build_verify_apdu(cmd, size, 0x19, p1,
prompt, timeout, data, data_len);
}
/*
* Helper function add message/timeout arguments to command
* buffer
*/
int ctbcs_add_timeout(ct_buf_t * bp, unsigned int timeout)
{
if (!timeout)
return 0;
ct_buf_putc(bp, 0x80);
ct_buf_putc(bp, 1);
ct_buf_putc(bp, timeout);
return ct_buf_avail(bp);
}
int ctbcs_add_message(ct_buf_t * bp, const char *message)
{
int n;
if (!message || !strcmp(message, "@"))
return 0;
if ((n = strlen(message)) > 32)
n = 32;
ct_buf_putc(bp, 0x50);
ct_buf_putc(bp, n);
ct_buf_put(bp, message, n);
return ct_buf_avail(bp);
}
openct-0.6.20/src/ifd/atr.c 0000644 0001750 0001750 00000007277 11303255320 012302 0000000 0000000 /*
* ATR parsing functions
*
* Copyright (C) 2004, Olaf Kirch
*/
#include "internal.h"
#include
#include "atr.h"
int ifd_atr_parse(ifd_atr_info_t * info, const unsigned char *atr, size_t len)
{
unsigned int m, n, k;
ifd_debug(1, "atr=%s", ct_hexdump(atr, len));
/* Initialize the atr_info struct */
memset(info, 0, sizeof(*info));
info->default_protocol = -1;
for (n = 0; n < 3; n++) {
info->TA[n] = -1;
info->TB[n] = -1;
info->TC[n] = -1;
}
if (len < 2 + (atr[1] & 0x0f))
return IFD_ERROR_INVALID_ATR;
/* Ignore hysterical bytes */
len -= atr[1] & 0x0f;
for (m = 0, n = 2; n < len; m++) {
unsigned int TDi;
/* TA1, TA2, TA3, TA4 are legal, TA5 wouldn't be */
if (m > 3)
return IFD_ERROR_INVALID_ATR;
TDi = atr[n - 1];
if (n != 2) {
int prot;
prot = TDi & 0x0f;
if (info->default_protocol < 0)
info->default_protocol = prot;
info->supported_protocols |= (1 << prot);
}
k = ifd_count_bits(TDi & 0xF0);
if (k == 0 || n + k > len)
return IFD_ERROR_INVALID_ATR;
if (TDi & 0x10)
info->TA[m] = atr[n++];
if (TDi & 0x20)
info->TB[m] = atr[n++];
if (TDi & 0x40)
info->TC[m] = atr[n++];
if (!(TDi & 0x80)) {
/* If the ATR indicates we support anything
* in addition to T=0, there'll be a TCK byte
* at the end of the string.
* For now, simply chop it off. Later we may
* want to verify it.
*/
if (info->supported_protocols & ~0x1)
len--;
if (n < len)
return IFD_ERROR_INVALID_ATR;
break;
}
n++;
}
/* ATR didn't list any supported protocols, so
* we default to T=0 */
if (info->supported_protocols == 0) {
info->supported_protocols = 0x01;
info->default_protocol = IFD_PROTOCOL_T0;
}
ifd_debug(1, "supported protocols=0x%x, default protocol=%d",
info->supported_protocols, info->default_protocol);
return 0;
}
/*
* Given the ATR info and a selected protocol, build the PTS
* string.
*/
int ifd_build_pts(const ifd_atr_info_t * info, int protocol, unsigned char *buf,
size_t len)
{
unsigned char ptsbuf[7], pck;
size_t n, ptslen = 0;
/* IFD_PROTOCOL_Tn is just n, so we take it easy here */
if (!(info->supported_protocols & (1 << protocol))) {
ct_error("Protocol not supported by card (according to ATR)");
return IFD_ERROR_NOT_SUPPORTED;
}
ptsbuf[ptslen++] = 0xFF;
ptsbuf[ptslen++] = protocol;
if (info->TA[0] != -1) {
ptsbuf[ptslen++] = info->TA[0];
ptsbuf[1] |= 0x10;
}
if (info->TC[0] == 255) {
ptsbuf[ptslen++] = 1;
ptsbuf[1] |= 0x20;
}
for (n = 0, pck = 0; n < ptslen; n++)
pck ^= ptsbuf[n];
ptsbuf[ptslen++] = pck;
if (ptslen > len)
return IFD_ERROR_BUFFER_TOO_SMALL;
memcpy(buf, ptsbuf, ptslen);
return ptslen;
}
/* validate a PTS response according to ISO7816-3 */
int
ifd_verify_pts(ifd_atr_info_t * info,
int protocol, const unsigned char *buf, size_t len)
{
int n, i;
int ptsr[3];
int pck;
if (len < 3)
return IFD_ERROR_BUFFER_TOO_SMALL;
if (buf[0] != 0xFF)
return IFD_ERROR_INCOMPATIBLE_DEVICE; /* not a pts response */
for (n = 0, pck = 0; n < len; n++)
pck ^= buf[n];
if (pck)
return IFD_ERROR_COMM_ERROR;
for (i = 0; i < 3; i++)
ptsr[i] = -1;
for (i = 0, n = 2; i < 3 && n < len - 1; i++) {
if (buf[1] & 1 << (i + 4))
ptsr[i] = buf[n++];
}
if (n < len - 1) /* extra bytes in response */
return IFD_ERROR_INCOMPATIBLE_DEVICE;
if (info->TA[0] != -1 && ptsr[0] != info->TA[0])
info->TA[0] = -1;
if (info->TC[0] == 255 && (ptsr[1] == -1 || (ptsr[1] & 1) == 0))
return IFD_ERROR_INCOMPATIBLE_DEVICE;
return 0;
}
int ifd_pts_complete(const unsigned char *pts, size_t len)
{
unsigned int j = 2;
if (j > len)
return 0;
j = +ifd_count_bits(pts[1] & 0x70);
j++;
if (j > len)
return 0;
return 1;
}
openct-0.6.20/src/ifd/ifd-smartboard.c 0000644 0001750 0001750 00000022446 10625650421 014414 0000000 0000000 /*
* Driver for Cherry smartboard
*
* This was written just by looking at the Smartboard protocol
* on the wire.
*
* Some notes on the Smartboard protocol.
* The basic message format seems to be
*
* 00 [len] [code]
*
* 00 Seems to be some general "I'm okay, you're okay" byte.
* Never seen anything else, but maybe it can be used to
* convey some critical errors etc.
* len One byte; length of following data
* code One byte; message code.
* Followed by data
*
* I have no clue yet how to use the num block for PIN entry...
*
* This driver is alpha code - it works for me with a Cryptoflex card,
* but that doesn't mean a thing :)
*
* Copyright (C) 2003 Olaf Kirch
*/
#include "internal.h"
#include
#include
#include
#include
#include
#include
#include "ctbcs.h"
static int smartboard_reset_ct(ifd_reader_t * reader);
static int smartboard_command(ifd_reader_t *,
unsigned char, const unsigned char *, size_t,
unsigned char *, void *, size_t);
static int __smartboard_cmd(ifd_reader_t *, unsigned char, const void *,
size_t);
static int __smartboard_rsp(ifd_reader_t *, unsigned char *, void *, size_t);
/*
* Initialize the device
*/
static int smartboard_open(ifd_reader_t * reader, const char *device_name)
{
ifd_device_params_t params;
ifd_device_t *dev;
int res;
reader->name = "Cherry Smartboard";
reader->nslots = 1;
reader->slot[0].dad = 0;
if (!(dev = ifd_device_open(device_name)))
return -1;
ifd_device_flush(dev);
if (ifd_device_type(dev) != IFD_DEVICE_TYPE_SERIAL) {
ct_error("Smartboard: must be a serial device");
return -1;
}
if ((res = ifd_device_get_parameters(dev, ¶ms)) < 0) {
ct_error("Smartboard: failed to get serial config");
return res;
}
params.serial.bits = 8;
params.serial.parity = IFD_SERIAL_PARITY_EVEN;
params.serial.stopbits = 2;
params.serial.speed = 115200;
params.serial.check_parity = 1;
if ((res = ifd_device_set_parameters(dev, ¶ms)) < 0) {
ct_error("Smartboard: failed to get serial line to 115200/8E2");
return res;
}
/* Toggle RTS briefly */
{
int bits = 0x4000;
usleep(230000);
ioctl(dev->fd, TIOCMSET, &bits);
usleep(230000);
bits |= TIOCM_DTR;
ioctl(dev->fd, TIOCMSET, &bits);
usleep(230000);
bits |= TIOCM_RTS;
ioctl(dev->fd, TIOCMSET, &bits);
usleep(100000);
}
ifd_serial_send_break(dev, 500000);
ifd_device_flush(dev);
reader->device = dev;
/* Reset the CT */
if ((res = smartboard_reset_ct(reader)) < 0)
return res;
return 0;
}
/*
* Reset the card reader
*/
static int smartboard_reset_ct(ifd_reader_t * reader)
{
unsigned char buffer[128], code;
int rc;
#if 1
/* shutdown reader - occasionally needed before we can init it */
rc = smartboard_command(reader, 0x6a, NULL, 0, &code, NULL, 0);
if (rc < 0)
return rc;
#endif
/* init reader */
rc = smartboard_command(reader, 0x60, NULL, 0, &code, buffer,
sizeof(buffer));
if (rc < 0)
return rc;
if (code != 0x60) {
ct_error("smartboard_reset_ct, expected status 0x60, got 0x%x",
code);
return -1;
}
ifd_debug(1, "Detected %.*s", rc, buffer);
return 0;
}
/*
* Power up the reader
*/
static int smartboard_activate(ifd_reader_t * reader)
{
ifd_debug(1, "called.");
return 0;
}
static int smartboard_deactivate(ifd_reader_t * reader)
{
ifd_debug(1, "called.");
return 0;
}
/*
* Get the card status
*/
static int smartboard_card_status(ifd_reader_t * reader, int idx, int *status)
{
unsigned char code, buffer[16];
int rc;
ifd_debug(1, "slot=%d", idx);
rc = smartboard_command(reader, 0x65, NULL, 0, &code, buffer,
sizeof(buffer));
if (rc < 0)
return rc;
*status = 0;
switch (code) {
case 0x61:
/* card absent: 00 00 00 01
* card present: 08 00 00 02
* after reset: 19 01 00 04
*/
if (rc >= 4 && (buffer[0] & 0x08))
*status = IFD_CARD_PRESENT;
break;
case 0x65:
ifd_debug(1, "event: card inserted.");
*status = IFD_CARD_PRESENT | IFD_CARD_STATUS_CHANGED;
break;
case 0x66:
ifd_debug(1, "event: card removed.");
*status = IFD_CARD_STATUS_CHANGED;
break;
default:
ct_error("smartboard_card_status: unexpected status code 0x%x",
code);
return -1;
}
return 0;
}
/*
* Reset card and get ATR
*/
static int smartboard_card_reset(ifd_reader_t * reader, int slot, void *result,
size_t size)
{
unsigned char code;
int rc;
rc = smartboard_command(reader, 0x65, NULL, 0, &code, result, size);
if (rc < 0)
return rc;
rc = smartboard_command(reader, 0x62, NULL, 0, &code, result, size);
if (rc < 0)
return rc;
if (code != 0x64) {
ct_error
("smartboard_card_reset: expected status code 0x62, got 0x%x",
code);
return -1;
}
return rc;
}
/*
* Select a protocol for communication with the ICC.
* We cannot use the T=0 driver directly, because it thinks it can
* talk over the wire.
*/
static int smartboard_set_protocol(ifd_reader_t * reader, int nslot, int proto)
{
unsigned char cmd_t0[5] = { 0x00, 0x00, 0x0a, 0x00, 0x10 };
unsigned char cmd_t1[5] = { 0x10, 0x00, 0x00, 0x75, 0x10 };
unsigned char *args, code;
ifd_slot_t *slot;
int rc;
slot = &reader->slot[nslot];
if (proto == IFD_PROTOCOL_T0) {
args = cmd_t0;
} else if (proto == IFD_PROTOCOL_T1) {
args = cmd_t1;
} else {
ct_error("%s: protocol not supported", reader->name);
return -1;
}
if ((rc =
smartboard_command(reader, 0x61, args, 5, &code, NULL, 0)) < 0)
return rc;
if (code != 0x62) {
ct_error("smartboard: unexpected status code 0x%x", code);
return -1;
}
slot->proto = ifd_protocol_new(proto, reader, slot->dad);
if (slot->proto == NULL) {
ct_error("%s: internal error", reader->name);
return -1;
}
/* Tell the protocol handler that we will do the framing */
ifd_protocol_set_parameter(slot->proto, IFD_PROTOCOL_BLOCK_ORIENTED, 1);
return 0;
}
#if 0
/*
* Perform a PIN verification
*/
static int smartboard_perform_verify(ifd_reader_t * reader, int nslot,
unsigned int timeout, const char *prompt,
const unsigned char *data, size_t data_len,
unsigned char *resp, size_t resp_len)
{
...}
#endif
/*
* Simple command
*/
static int __smartboard_cmd(ifd_reader_t * reader, unsigned char cmd,
const void *arg, size_t arg_len)
{
unsigned char buffer[257];
if (arg_len > sizeof(buffer) - 3)
return -1;
buffer[0] = 0x00; /* never seen anything other than this */
buffer[1] = 1 + arg_len;
buffer[2] = cmd;
memcpy(buffer + 3, arg, arg_len);
if (ct_config.debug > 1)
ifd_debug(3, "sending:%s", ct_hexdump(buffer, 3 + arg_len));
return ifd_device_send(reader->device, buffer, 3 + arg_len);
}
static int __smartboard_rsp(ifd_reader_t * reader, unsigned char *code,
void *res, size_t res_len)
{
unsigned char buffer[257];
unsigned int rsp_len = 0, total = 2;
int rc;
while (rsp_len < total) {
rc = ifd_device_recv(reader->device, buffer + rsp_len,
total - rsp_len, -1);
if (rc < 0)
return rc;
if (buffer[0] != 0x00)
goto bad_reply;
rsp_len += rc;
if (rsp_len == 2) {
if (buffer[1] == 0)
goto bad_reply;
total += buffer[1];
}
}
if (total < 3)
goto bad_reply;
*code = buffer[2];
if (ct_config.debug > 1)
ifd_debug(3, "received:%s", ct_hexdump(buffer, total));
rsp_len = total - 3;
if (res_len > rsp_len)
res_len = rsp_len;
if (res && res_len)
memcpy(res, buffer + 3, res_len);
return res_len;
bad_reply:
ct_error("smartboard: bad reply from device");
return -1;
}
static int smartboard_command(ifd_reader_t * reader, unsigned char cmd,
const unsigned char *arg, size_t arg_len,
unsigned char *code, void *res, size_t res_len)
{
int n = 0, rc;
do {
if ((rc = __smartboard_cmd(reader, cmd, arg, arg_len)) < 0
|| (rc = __smartboard_rsp(reader, code, res, res_len)) < 0)
ct_error("smartboard: transceive error");
} while (rc >= 0 && *code == 0x67 && n++ < 3);
return rc;
}
/*
* Send/receive APDU
*/
static int smartboard_send(ifd_reader_t * reader, unsigned int dad,
const unsigned char *buffer, size_t len)
{
ifd_debug(3, "data:%s", ct_hexdump(buffer, len));
return __smartboard_cmd(reader, 0x67, buffer, len);
}
static int smartboard_recv(ifd_reader_t * reader, unsigned int dad,
unsigned char *buffer, size_t len, long timeout)
{
unsigned char code;
int rc;
ifd_debug(4, "called.");
/* Status code 63 seems to be some sort of wait time extension */
while (1) {
if ((rc = __smartboard_rsp(reader, &code, buffer, len)) < 0)
return rc;
if (code != 0x63)
break;
}
if (code != 0x64) {
ct_error("smartboard: unexpected status code 0x%x", code);
return -1;
}
ifd_debug(3, "resp:%s", ct_hexdump(buffer, rc));
return rc;
}
/*
* Driver operations
*/
static struct ifd_driver_ops smartboard_driver;
/*
* Initialize this module
*/
void ifd_smartboard_register(void)
{
smartboard_driver.open = smartboard_open,
smartboard_driver.activate = smartboard_activate,
smartboard_driver.deactivate = smartboard_deactivate,
smartboard_driver.card_status = smartboard_card_status,
smartboard_driver.card_reset = smartboard_card_reset,
#ifdef notyet
smartboard_driver.perform_verify = smartboard_perform_verify,
#endif
smartboard_driver.send = smartboard_send,
smartboard_driver.recv = smartboard_recv,
smartboard_driver.set_protocol = smartboard_set_protocol,
ifd_driver_register("smartboard", &smartboard_driver);
}
openct-0.6.20/src/ifd/ifdhandler.c 0000644 0001750 0001750 00000022423 11151454644 013615 0000000 0000000 /*
* Manage a single reader
*
* Copyright (C) 2003 Olaf Kirch
*/
#include "internal.h"
#include
#include
#include
#ifdef HAVE_GETOPT_H
#include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "ifdhandler.h"
static int opt_debug = 0;
static int opt_hotplug = 0;
static int opt_foreground = 0;
static int opt_info = 0;
static int opt_poll = 0;
static const char *opt_reader = NULL;
static void usage(int exval);
static void version(void);
static void ifdhandler_run(ifd_reader_t *);
static int ifdhandler_poll_presence(ct_socket_t *, struct pollfd *);
static int ifdhandler_event(ct_socket_t * sock);
static int ifdhandler_accept(ct_socket_t *);
static int ifdhandler_error(ct_socket_t *);
static int ifdhandler_recv(ct_socket_t *);
static int ifdhandler_send(ct_socket_t *);
static void ifdhandler_close(ct_socket_t *);
static void print_info(void);
int main(int argc, char **argv)
{
const char *driver = NULL, *type = NULL, *device = NULL;
ifd_reader_t *reader;
ct_info_t *status;
int c;
/* Make sure the mask is good */
umask(033);
while ((c = getopt(argc, argv, "dFHhvipr:s")) != -1) {
switch (c) {
case 'd':
opt_debug++;
break;
case 'F':
opt_foreground = 1;
break;
case 'H':
opt_hotplug = 1;
break;
case 'i':
opt_info = 1;
break;
case 'p':
opt_poll = 1;
break;
case 'r':
opt_reader = optarg;
break;
case 's':
ct_log_destination("@syslog");
break;
case 'v':
version();
case 'h':
usage(0);
default:
usage(1);
}
}
if (opt_info) {
if (optind != argc)
usage(1);
if (ifd_init())
return 1;
print_info();
return 0;
}
if (optind != argc - 3)
usage(1);
driver = argv[optind++];
type = argv[optind++];
device = argv[optind++];
ct_config.debug = opt_debug;
/* Initialize IFD library */
if (ifd_init())
return 1;
/* Allocate a socket slot
* FIXME: may need to use a lock file here to
* prevent race condition
*/
{
int r = -1;
char path[PATH_MAX];
status = ct_status_alloc_slot(&r);
if (status == NULL) {
ct_error("too many readers, no reader slot available");
return 1;
}
snprintf(path, PATH_MAX, "%d", r);
opt_reader = strdup(path);
}
/* Become a daemon if needed - we do this after allocating the
* slot so openct-control can synchronize slot allocation */
if (!opt_foreground) {
pid_t pid;
int fd;
if ((pid = fork()) < 0) {
ct_error("fork: %m");
return 1;
}
if (pid) {
status->ct_pid = pid;
return 0;
}
if ((fd = open("/dev/null", O_RDWR)) >= 0) {
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
close(fd);
}
ct_log_destination("@syslog");
setsid();
}
/* Create reader */
{
char *typedev = malloc(strlen(type) + strlen(device) + 2);
if (!typedev) {
ct_error("out of memory");
return 1;
}
sprintf(typedev, "%s:%s", type, device);
if (!(reader = ifd_open(driver, typedev))) {
ct_error("unable to open reader %s %s %s", driver, type,
device);
return 1;
}
free(typedev);
}
ifd_device_set_hotplug(reader->device, opt_hotplug);
reader->status = status;
strncpy(status->ct_name, reader->name, sizeof(status->ct_name) - 1);
status->ct_slots = reader->nslots;
if (reader->flags & IFD_READER_DISPLAY)
status->ct_display = 1;
if (reader->flags & IFD_READER_KEYPAD)
status->ct_keypad = 1;
ifdhandler_run(reader);
return 0;
}
static void TERMhandler(int signo)
{
ct_mainloop_leave();
}
/*
* Spawn a new ifd handler thread
*/
static void ifdhandler_run(ifd_reader_t * reader)
{
ct_socket_t *sock;
int rc;
struct sigaction act;
char path[PATH_MAX];
if (!ct_format_path(path, PATH_MAX, opt_reader)) {
ct_error("ct_format_path failed!");
exit(1);
}
/* Activate reader */
if ((rc = ifd_activate(reader)) < 0) {
ct_error("Failed to activate reader; err=%d", rc);
exit(1);
}
sock = ct_socket_new(0);
if (ct_socket_listen(sock, path, 0666) < 0) {
ct_error("Failed to create server socket");
exit(1);
}
sock->user_data = reader;
sock->recv = ifdhandler_accept;
ct_mainloop_add_socket(sock);
/* Set an TERM signal handler for clean exit */
act.sa_handler = TERMhandler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGTERM, &act, NULL);
/* Encapsulate the reader into a socket struct */
sock = ct_socket_new(0);
if (opt_poll) {
sock->fd = -1;
}
else {
sock->fd = ifd_get_eventfd(reader, &sock->events);
}
if (sock->fd == -1) {
ifd_debug(1, "events inactive for reader %s", reader->name);
sock->fd = 0x7FFFFFFF;
sock->poll = ifdhandler_poll_presence;
}
else {
ifd_debug(1, "events active for reader %s", reader->name);
sock->error = ifdhandler_error;
sock->send = ifdhandler_event;
ifd_before_command(reader);
ifd_poll(reader);
ifd_after_command(reader);
}
sock->user_data = reader;
ct_mainloop_add_socket(sock);
/* Call the server loop */
ct_mainloop();
ct_socket_unlink(sock);
ct_socket_free(sock);
memset(reader->status, 0, sizeof(*reader->status));
ct_status_update(reader->status);
ifd_debug(1, "ifdhandler for reader %s shut down", reader->name);
exit(0);
}
static void exit_on_device_disconnect(ifd_reader_t *reader)
{
ifd_debug(1, "Reader %s detached", reader->name);
memset(reader->status, 0, sizeof(*reader->status));
exit(0);
}
/*
* Poll for presence of hotplug device
*/
static int ifdhandler_poll_presence(ct_socket_t * sock, struct pollfd *pfd)
{
ifd_reader_t *reader = (ifd_reader_t *) sock->user_data;
ifd_device_t *dev = reader->device;
ifd_poll(reader);
if (dev->hotplug && ifd_device_poll_presence(dev, pfd) == 0) {
exit_on_device_disconnect(reader);
}
return 1;
}
/*
* Error from socket
*/
static int ifdhandler_error(ct_socket_t * sock)
{
ifd_reader_t *reader = (ifd_reader_t *) sock->user_data;
if (ifd_error(reader) < 0) {
exit_on_device_disconnect(reader);
}
return 0;
}
/*
* Receive data from client
*/
static int ifdhandler_event(ct_socket_t * sock)
{
ifd_reader_t *reader = (ifd_reader_t *) sock->user_data;
if (ifd_event(reader) < 0) {
exit_on_device_disconnect(reader);
}
return 0;
}
/*
* Handle connection request from client
*/
static int ifdhandler_accept(ct_socket_t * listener)
{
ct_socket_t *sock;
if (!(sock = ct_socket_accept(listener)))
return 0;
sock->user_data = listener->user_data;
sock->recv = ifdhandler_recv;
sock->send = ifdhandler_send;
sock->close = ifdhandler_close;
return 0;
}
/*
* Receive data from client
*/
static int ifdhandler_recv(ct_socket_t * sock)
{
ifd_reader_t *reader;
char buffer[CT_SOCKET_BUFSIZ + 64];
header_t header;
ct_buf_t args, resp;
int rc;
/* Error or client closed connection? */
if ((rc = ct_socket_filbuf(sock, -1)) <= 0)
return -1;
/* If request is incomplete, go back
* and wait for more
* XXX add timeout? */
if ((rc = ct_socket_get_packet(sock, &header, &args)) < 1)
return rc;
ct_buf_init(&resp, buffer, sizeof(buffer));
reader = (ifd_reader_t *) sock->user_data;
header.error = ifdhandler_process(sock, reader, &args, &resp);
if (header.error)
ct_buf_clear(&resp);
/* Put packet into transmit buffer */
header.count = ct_buf_avail(&resp);
if (ct_socket_put_packet(sock, &header, &resp) < 0)
return -1;
/* Leave transmitting to the main server loop */
return 0;
}
/*
* Transmit data to client
*/
static int ifdhandler_send(ct_socket_t * sock)
{
return ct_socket_flsbuf(sock, 0);
}
/*
* Socket is closed - for whatever reason
* Release any locks held by this client
*/
static void ifdhandler_close(ct_socket_t * sock)
{
ifdhandler_unlock_all(sock);
}
/*
* Display ifdhandler configuration stuff
*/
static void print_list(const char **names, unsigned int n)
{
unsigned int i, width = 0, len;
for (i = 0; i < n; i++) {
len = 1 + strlen(names[i]);
if (width && width + len > 64) {
printf("\n");
width = 0;
}
if (width == 0) {
printf(" ");
width = 3;
}
printf(" %s", names[i]);
if (i < n - 1) {
printf(",");
len++;
}
width += len;
}
if (width)
printf("\n");
}
static void print_info(void)
{
const char *names[64];
unsigned int n;
n = ifd_drivers_list(names, 64);
if (n == 0) {
printf("No reader drivers configured\n");
} else {
printf("Reader drivers:\n");
print_list(names, n);
}
n = ifd_protocols_list(names, 64);
if (n == 0) {
printf("No protocols configured\n");
} else {
printf("Protocols:\n");
print_list(names, n);
}
}
/*
* Display version
*/
static void version(void)
{
fprintf(stdout, "OpenCT " VERSION "\n");
exit(0);
}
/*
* Usage message
*/
static void usage(int exval)
{
fprintf(exval ? stderr : stdout,
"usage: ifdhandler [-Hds] [-r reader] driver type device\n"
" -r specify index of reader\n"
" -F stay in foreground\n"
" -H hotplug device, monitor for detach\n"
" -p force polling device even if events supported\n"
" -s send error and debug messages to syslog\n"
" -d enable debugging; repeat to increase verbosity\n"
" -i display list of available drivers and protocols\n"
" -h display this message\n"
" -v display version and exit\n");
exit(exval);
}
openct-0.6.20/src/ifd/cardman.h 0000644 0001750 0001750 00000010733 10422076714 013126 0000000 0000000 #ifndef _CARDMAN_H_
#define _CARDMAN_H_
#define MAX_ATR 33
#define CM2020_MAX_DEV 16
#define CM4000_MAX_DEV 4
typedef struct atreq {
int atr_len;
unsigned char atr[64];
int power_act;
unsigned char bIFSD;
unsigned char bIFSC;
} atreq_t;
typedef struct ptsreq {
unsigned long protocol; /*T=0: 2^0, T=1: 2^1 */
unsigned char flags;
unsigned char pts1;
unsigned char pts2;
unsigned char pts3;
} ptsreq_t;
#define CM_IOC_MAGIC 'c'
#define CM_IOC_MAXNR 255
#define CM_IOCGSTATUS _IOR (CM_IOC_MAGIC, 0, unsigned char *)
#define CM_IOCGATR _IOWR(CM_IOC_MAGIC, 1, atreq_t *)
#define CM_IOCSPTS _IOW (CM_IOC_MAGIC, 2, ptsreq_t *)
#define CM_IOCSRDR _IO (CM_IOC_MAGIC, 3)
#define CM_IOCARDOFF _IO (CM_IOC_MAGIC, 4)
#define CM_IOSDBGLVL _IOW(CM_IOC_MAGIC, 250, int*)
/* card and device states */
#define CM_CARD_INSERTED 0x01
#define CM_CARD_POWERED 0x02
#define CM_ATR_PRESENT 0x04
#define CM_ATR_VALID 0x08
#define CM_STATE_VALID 0x0f
/* extra info only from CM4000 */
#define CM_NO_READER 0x10
#define CM_BAD_CARD 0x20
#ifdef __KERNEL__
/* USB can have 16 readers, while PCMCIA is allowed 4 slots */
#define CM4000_MAX_DEV 4
#ifdef __CM2020__
#define MODULE_NAME "cardman_usb"
#define CM2020_MAX_DEV 16
#define CM2020_MINOR 224
#define CM2020_REQT_WRITE 0x42
#define CM2020_REQT_READ 0xc2
#define CM2020_MODE_1 0x01
#define CM2020_MODE_2 0x02
#define CM2020_MODE_3 0x03
#define CM2020_MODE_4 0x08
#define CM2020_CARD_ON 0x10
#define CM2020_CARD_OFF 0x11
#define CM2020_GET_STATUS 0x20
#define CM2020_STATUS_MASK 0xc0
#define CM2020_STATUS_NO_CARD 0x00
#define CM2020_STATUS_NOT_POWERD 0x40
#define CM2020_STATUS_POWERD 0xc0
#define CM2020_SET_PARAMETER 0x30
#define CM2020_CARDON_COLD 0x00
#define CM2020_CARDON_WARM 0x01
#define CM2020_FREQUENCY_3_72MHZ 0x00
#define CM2020_FREQUENCY_5_12MHZ 0x10
#define CM2020_BAUDRATE_115200 0x0C
#define CM2020_BAUDRATE_76800 0x08
#define CM2020_BAUDRATE_57600 0x06
#define CM2020_BAUDRATE_38400 0x04
#define CM2020_BAUDRATE_28800 0x03
#define CM2020_BAUDRATE_19200 0x02
#define CM2020_BAUDRATE_9600 0x01
#define CM2020_ODD_PARITY 0x80
#define CM2020_CARD_ASYNC 0x00
enum {
CB_NOP,
CB_SET_PARAMETER,
CB_READ_STATUS,
CB_READ_ATR,
CB_WRITE_PTS,
CB_READ_PTS,
CB_WRITE_T1,
CB_PROG_T1,
CB_READ_T1,
CB_WRITE_T0,
CB_WRITE_T0_SW1SW2,
CB_READ_T0,
CB_READ_T0_DATA,
CB_CARD_OFF,
CB_T1MODE2
};
#define TIMEOUT_LEN 60000
#define MAX_RBUF 512
typedef struct usb_cardman {
struct usb_device *dev;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
struct usb_interface *interface; /* the interface for this device */
#endif
struct task_struct *owner;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20)
struct usb_ctrlrequest *dr;
#else
devrequest *dr;
#endif
struct urb *irq, *ctrl, *rctl;
unsigned char *ibuf, *cbuf, *rcbuf;
wait_queue_head_t waitq;
unsigned char atr[MAX_ATR];
unsigned char atr_csum;
unsigned char atr_len;
unsigned char bIFSD, bIFSC;
unsigned char ta1; /* TA(1) specifies Fi over b8 to b5, Di over b4 to b1 */
unsigned char pts[4];
unsigned char rbuf[MAX_RBUF];
short rlen;
int t1_reply_len;
/* length of a T=0 packet, excl. the header length */
unsigned char t0_data_len;
/* relative data offset as we proceed through the packet */
unsigned char t0_data_off;
/* byte 2 of the T=0 header (INS from CLA INS ADR...) */
unsigned char t0_ins;
/* length of T=0 reply we expcet. 2 for a WriteT0, else
* ReadT0 length + 2 (Sw1 Sw2)
*/
unsigned short t0_expected_reply_len;
int bInterval;
unsigned char ctrlendp;
unsigned char intendp;
unsigned char card_state;
int flags;
int op;
unsigned char proto;
int ttl, ttl_hi, /* CWT */
bwt, /* BWT */
ptsttl; /* PTS retry */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
int open;
int present;
struct semaphore sem;
int minor;
#endif
} usb_cardman_t;
#endif /* __CM2020__ */
#ifdef __CM4000__
#define DEVICE_NAME "cmm"
#define MODULE_NAME "cardman_cs"
/* unofficial CM4000 ioctl */
#define CM4000_IOCMONITOR _IO (CM_IOC_MAGIC, 251)
#define CM4000_IOCDUMPATR _IO (CM_IOC_MAGIC, 252)
#define CM4000_IOCDECUSECOUNT _IO (CM_IOC_MAGIC, 253)
#define CM4000_IOCPOWERON _IO (CM_IOC_MAGIC, 254)
#define CM4000_IOCGIOADDR _IOW(CM_IOC_MAGIC, 255, int*)
#endif /* __CM4000__ */
#endif /* __KERNEL__ */
#endif /* _CARDMAN_H_ */
openct-0.6.20/src/ifd/conf.c 0000644 0001750 0001750 00000021461 10625650421 012437 0000000 0000000 /*
* libifd configuration handling
*
* Copyright (C) 2003, Olaf Kirch
*/
#include "internal.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct ct_config ct_config = {
0, /* debug */
1, /* autoload */
1, /* hotplug */
0, /* suppress_errors */
OPENCT_IFDHANDLER_PATH, /* ifdhandler */
OPENCT_MODULES_PATH, /* modules_dir */
NULL, /* driver_modules_dir */
NULL, /* protocol_modules_dir */
OPENCT_SOCKET_PATH, /* socket_dir */
};
#define issepa(c) (strchr("=;,{}", (c)) != NULL)
enum {
GROUP_BEGIN = '{',
GROUP_END = '}',
COMMA = ',',
SEMICOLON = ';',
EQUALS = '=',
END_OF_FILE = -1
};
static const char *config_filename = NULL;
static ct_buf_t config_buf;
static int config_fd = -1;
static int config_line = 0;
static ifd_conf_node_t config_top;
static int conf_parse_group(ifd_conf_node_t *, char);
static void conf_dump(ifd_conf_node_t *, int);
static ifd_conf_node_t *conf_add_node(ifd_conf_node_t *, const char *);
static int get_token(char **);
static int skipws(void);
static int ateof(void);
/*
* Parse the ifd config file
*/
int ifd_config_parse(const char *filename)
{
char buffer[512];
int rc;
if ((config_filename = filename) == NULL)
config_filename = OPENCT_CONF_PATH;
/* If config file doesn't exist, quietly sneak out of here */
if ((config_fd = open(config_filename, O_RDONLY)) < 0) {
if (errno == ENOENT)
return 0;
ct_error("Unable to open %s: %m", filename);
return -1;
}
/* Init parse buffer. */
ct_buf_init(&config_buf, buffer, sizeof(buffer));
config_line = 1;
config_top.name = "";
rc = conf_parse_group(&config_top, END_OF_FILE);
close(config_fd);
config_fd = -1;
if (ct_config.debug > 2)
conf_dump(&config_top, 0);
return rc;
}
/*
* Parse list of statements
*/
static int conf_parse_group(ifd_conf_node_t * group, char closing)
{
ifd_conf_node_t *node;
char *token;
int rc = 0;
while (1) {
if (ateof()) {
if (closing == (char)END_OF_FILE)
break;
ct_error("%s:%u: unexpected end of file",
config_filename, config_line);
return -1;
}
if ((rc = get_token(&token)) < 0)
break;
/* Check if this is the closing group character; if
* so, return. No other separators allowed here */
if (*token == closing)
break;
if (issepa(*token))
goto unexpected;
node = conf_add_node(group, token);
if ((rc = get_token(&token)) < 0)
break;
/* Get the value - the following are valid
* name = value;
* name value { ... };
* name { ... };
* value, value, ...
*/
if (*token == EQUALS) {
/* name = value case */
if ((rc = get_token(&token)) < 0)
break;
}
if (!issepa(*token)) {
node->value = strdup(token);
/* Get the next token */
if ((rc = get_token(&token)) < 0)
break;
} else if (*token == GROUP_BEGIN || *token == COMMA) {
/* Do-nothing cases:
* name { ... }
* foo, bar, baz, ...
*/
} else {
/* everything else illegal here */
goto unexpected;
}
if (*token == GROUP_BEGIN) {
/* Parse the group, then get the next
* token */
if ((rc = conf_parse_group(node, GROUP_END)) < 0
|| (rc = get_token(&token)) < 0)
break;
}
if (*token != SEMICOLON && *token != COMMA)
goto unexpected;
}
return rc;
unexpected:
ct_error("%s: line %d: unexpected token \"%s\"",
config_filename, config_line, token);
return -1;
}
/*
* Debugging - dump the config tree
*/
static void conf_dump(ifd_conf_node_t * node, int indent)
{
for (; node; node = node->next) {
printf("%*.*s%s", indent, indent, "", node->name);
if (node->value) {
if (!node->children)
printf(" =");
printf(" %s", node->value);
}
if (node->children) {
printf(" %c\n", GROUP_BEGIN);
conf_dump(node->children, indent + 2);
printf("%*.*s%c", indent, indent, "", GROUP_END);
} else {
printf("%c", SEMICOLON);
}
printf("\n");
}
}
/*
* Config node handling
*/
static ifd_conf_node_t *conf_add_node(ifd_conf_node_t * parent,
const char *name)
{
ifd_conf_node_t **p, *node;
node = (ifd_conf_node_t *) calloc(1, sizeof(*node));
if (!node) {
ct_error("out of memory");
return NULL;
}
node->name = strdup(name);
for (p = &parent->children; *p; p = &(*p)->next) ;
*p = node;
return node;
}
static ifd_conf_node_t *conf_find_node(ifd_conf_node_t * node, const char *name)
{
unsigned int len;
if (!name)
return node;
while (*name == '.')
name++;
if (!*name)
return node;
len = strcspn(name, ".");
for (node = node->children; node; node = node->next) {
if (!strncmp(node->name, name, len)
&& node->name[len] == '\0')
return conf_find_node(node, name + len);
}
return NULL;
}
int ifd_conf_get_string(const char *name, char **result)
{
return ifd_conf_node_get_string(&config_top, name, result);
}
int ifd_conf_get_bool(const char *name, unsigned int *result)
{
return ifd_conf_node_get_bool(&config_top, name, result);
}
int ifd_conf_get_integer(const char *name, unsigned int *result)
{
return ifd_conf_node_get_integer(&config_top, name, result);
}
int ifd_conf_get_string_list(const char *name, char **list, size_t max)
{
return ifd_conf_node_get_string_list(&config_top, name, list, max);
}
int ifd_conf_get_nodes(const char *name, ifd_conf_node_t ** list, size_t max)
{
return ifd_conf_node_get_nodes(&config_top, name, list, max);
}
int
ifd_conf_node_get_string(ifd_conf_node_t * node,
const char *name, char **result)
{
if (!(node = conf_find_node(node, name))
|| !node->value)
return -1;
*result = node->value;
return 0;
}
int
ifd_conf_node_get_integer(ifd_conf_node_t * node,
const char *name, unsigned int *result)
{
if (!(node = conf_find_node(node, name))
|| !node->value)
return -1;
*result = strtoul(node->value, NULL, 0);
return 0;
}
int
ifd_conf_node_get_bool(ifd_conf_node_t * node,
const char *name, unsigned int *result)
{
const char *v;
if (!(node = conf_find_node(node, name))
|| !(v = node->value))
return -1;
if (!strcmp(v, "0")
|| !strcmp(v, "off")
|| !strcmp(v, "no")) {
*result = 0;
} else if (!strcmp(v, "1")
|| !strcmp(v, "on")
|| !strcmp(v, "yes")) {
*result = 1;
} else {
return -1;
}
return 0;
}
int
ifd_conf_node_get_string_list(ifd_conf_node_t * node,
const char *name, char **list, size_t max)
{
unsigned int j = 0;
if (!(node = conf_find_node(node, name)))
return -1;
for (node = node->children; node; node = node->next) {
if (list && j < max)
list[j] = node->name;
j += 1;
}
return j;
}
int
ifd_conf_node_get_nodes(ifd_conf_node_t * node,
const char *name, ifd_conf_node_t ** list, size_t max)
{
unsigned int j = 0;
for (node = node->children; node; node = node->next) {
if (strcmp(node->name, name))
continue;
if (list && j < max)
list[j] = node;
j += 1;
}
return j;
}
/*
* Tokenizer
*/
static int get_token(char **tok)
{
static char buffer[512];
unsigned int m, n, copy, retry = 1;
char *s;
/* consume initial white space */
if (skipws() < 0)
return -1;
again:
s = (char *)ct_buf_head(&config_buf);
n = ct_buf_avail(&config_buf);
if (n && issepa(*s)) {
m = 1;
} else {
for (m = 0; !isspace((int)s[m]) && !issepa(s[m]) && m < n;
m++) ;
}
/* If we hit the end of the buffer while scanning
* for white space, read more data and try
* again */
if (m >= n && retry) {
if (ct_buf_read(&config_buf, config_fd) < 0) {
ct_error("%s: error while reading file: %m",
config_filename);
return -1;
}
retry = 0;
goto again;
}
if (m == 0)
return -1;
if ((copy = m) >= sizeof(buffer))
copy = sizeof(buffer) - 1;
memcpy(buffer, s, copy);
buffer[copy] = '\0';
ct_buf_get(&config_buf, NULL, m);
ifd_debug(5, "ifd_config_parse: token=\"%s\"", buffer);
*tok = buffer;
return 0;
}
/*
* Check if we're at the end of the file
*/
static int ateof(void)
{
int retry = 1;
again:
if (skipws() < 0)
return -1;
if (ct_buf_avail(&config_buf) == 0) {
if (!retry)
return 1;
if (ct_buf_read(&config_buf, config_fd) < 0) {
ct_error("%s: error while reading file: %m",
config_filename);
return -1;
}
retry = 0;
goto again;
}
return 0;
}
/*
* Eat initial white space from buffer
*/
static int skipws(void)
{
unsigned int m, n, in_comment = 0;
char *s;
again:
s = (char *)ct_buf_head(&config_buf);
n = ct_buf_avail(&config_buf);
for (m = 0; m < n; m++, s++) {
if (*s == '#') {
in_comment = 1;
} else if (!in_comment && !isspace((int)*s)) {
break;
} else if (*s == '\n') {
config_line++;
in_comment = 0;
}
}
ct_buf_get(&config_buf, NULL, m);
if (in_comment) {
if (ct_buf_read(&config_buf, config_fd) < 0) {
ct_error("%s: error while reading file: %m",
config_filename);
return -1;
}
goto again;
}
return 0;
}
openct-0.6.20/src/ifd/usb.c 0000644 0001750 0001750 00000013511 11151454644 012304 0000000 0000000 /*
* USB device handling
*
* Copyright (C) 2003, Olaf Kirch
*/
#include "internal.h"
#include
#include
#include
#include
/*
* Send/receive USB control block
*/
int ifd_usb_control(ifd_device_t * dev, unsigned int requesttype,
unsigned int request, unsigned int value,
unsigned int idx, void *buffer, size_t len, long timeout)
{
int n;
if (dev->type != IFD_DEVICE_TYPE_USB)
return -1;
if (timeout < 0)
timeout = 10000;
if ((ct_config.debug >= 3) && !(requesttype & 0x80)) {
ifd_debug(4,
"usb req type=x%02x req=x%02x val=x%04x ind=x%04x len=%u",
requesttype, request, value, idx, len);
if (len)
ifd_debug(4, "send %s", ct_hexdump(buffer, len));
}
n = ifd_sysdep_usb_control(dev, requesttype, request, value, idx,
buffer, len, timeout);
if ((ct_config.debug >= 3) && (requesttype & 0x80)) {
ifd_debug(4,
"usb req type=x%02x req=x%02x val=x%04x ind=x%04x len=%d",
requesttype, request, value, idx, n);
if (n > 0)
ifd_debug(4, "recv %s", ct_hexdump(buffer, n));
}
return n;
}
/*
* USB frame capture
*/
int ifd_usb_begin_capture(ifd_device_t * dev, int type, int endpoint,
size_t maxpacket, ifd_usb_capture_t ** capret)
{
if (dev->type != IFD_DEVICE_TYPE_USB)
return -1;
if (ct_config.debug >= 5)
ifd_debug(5, "usb capture type=%d ep=x%x maxpacket=%u",
type, endpoint, maxpacket);
return ifd_sysdep_usb_begin_capture(dev, type, endpoint, maxpacket,
capret);
}
int ifd_usb_capture_event(ifd_device_t * dev, ifd_usb_capture_t * cap, void *buffer,
size_t len)
{
int rc;
if (dev->type != IFD_DEVICE_TYPE_USB)
return -1;
ifd_debug(5, "called.");
rc = ifd_sysdep_usb_capture_event(dev, cap, buffer, len);
if (ct_config.debug >= 3) {
if (rc < 0)
ifd_debug(1, "usb event capture: %s", ct_strerror(rc));
if (rc > 0)
ifd_debug(5, "usb event capture: recv %s",
ct_hexdump(buffer, rc));
if (rc == 0)
ifd_debug(5, "usb event capture: rc=%d (timeout?)", rc);
}
return rc;
}
int ifd_usb_capture(ifd_device_t * dev, ifd_usb_capture_t * cap, void *buffer,
size_t len, long timeout)
{
int rc;
if (dev->type != IFD_DEVICE_TYPE_USB)
return -1;
ifd_debug(5, "called, timeout=%ld ms.", timeout);
rc = ifd_sysdep_usb_capture(dev, cap, buffer, len, timeout);
if (ct_config.debug >= 3) {
if (rc < 0)
ifd_debug(1, "usb capture: %s", ct_strerror(rc));
if (rc > 0)
ifd_debug(5, "usb capture: recv %s",
ct_hexdump(buffer, rc));
if (rc == 0)
ifd_debug(5, "usb capture: rc=%d (timeout?)", rc);
}
return rc;
}
int ifd_usb_end_capture(ifd_device_t * dev, ifd_usb_capture_t * cap)
{
ifd_debug(5, "called.");
if (dev->type != IFD_DEVICE_TYPE_USB)
return -1;
return ifd_sysdep_usb_end_capture(dev, cap);
}
/*
* Set usb params (for now, endpoint for transceive)
*/
static int usb_set_params(ifd_device_t * dev,
const ifd_device_params_t * params)
{
ifd_debug(1, "called. config x%02x ifc x%02x eps x%02x/x%02x",
params->usb.configuration, params->usb.interface,
params->usb.ep_o, params->usb.ep_i);
if (params->usb.interface != -1 && params->usb.interface > 255)
return IFD_ERROR_INVALID_ARG;
if (params->usb.ep_o != -1 && (params->usb.ep_o & ~0x7F))
return IFD_ERROR_INVALID_ARG;
if ((params->usb.ep_i != -1 && (params->usb.ep_i & ~0xFF))
|| !(params->usb.ep_i & 0x80))
return IFD_ERROR_INVALID_ARG;
if (dev->settings.usb.interface != -1)
ifd_sysdep_usb_release_interface(dev,
dev->settings.usb.interface);
if (params->usb.configuration != -1
&& ifd_sysdep_usb_set_configuration(dev, params->usb.configuration))
return -1;
if (params->usb.interface != -1) {
if (ifd_sysdep_usb_claim_interface(dev, params->usb.interface))
return -1;
if (params->usb.altsetting != -1
&& ifd_sysdep_usb_set_interface(dev,
params->usb.interface,
params->usb.altsetting))
return -1;
}
dev->settings = *params;
return 0;
}
static int usb_send(ifd_device_t * dev, const unsigned char *send,
size_t sendlen)
{
if (dev->settings.usb.ep_o == -1)
return IFD_ERROR_NOT_SUPPORTED;
if (ct_config.debug >= 3) {
ifd_debug(4, "usb send to=x%02x", dev->settings.usb.ep_o);
if (sendlen)
ifd_debug(4, "send %s", ct_hexdump(send, sendlen));
}
return ifd_sysdep_usb_bulk(dev,
dev->settings.usb.ep_o,
(unsigned char *)send, sendlen, 10000);
}
static int usb_recv(ifd_device_t * dev, unsigned char *recv, size_t recvlen,
long timeout)
{
int rc;
if (dev->settings.usb.ep_i == -1)
return IFD_ERROR_NOT_SUPPORTED;
rc = ifd_sysdep_usb_bulk(dev, dev->settings.usb.ep_i,
recv, recvlen, timeout);
if (rc >= 0 && ct_config.debug >= 4) {
ifd_debug(4, "usb recv from=x%02x", dev->settings.usb.ep_i);
if (rc > 0)
ifd_debug(4, "recv %s", ct_hexdump(recv, rc));
}
return rc;
}
static int usb_reset(ifd_device_t * dev)
{
int rc;
rc = ifd_sysdep_usb_reset(dev);
return rc;
}
static int usb_get_eventfd(ifd_device_t * dev, short *events)
{
int rc;
rc = ifd_sysdep_usb_get_eventfd(dev, events);
return rc;
}
static struct ifd_device_ops ifd_usb_ops;
/*
* Open USB device
*/
ifd_device_t *ifd_open_usb(const char *device)
{
ifd_device_t *dev;
int fd;
if ((fd = ifd_sysdep_usb_open(device)) < 0) {
ct_error("Unable to open USB device %s: %m", device);
return NULL;
}
ifd_usb_ops.poll_presence = ifd_sysdep_usb_poll_presence;
ifd_usb_ops.set_params = usb_set_params;
ifd_usb_ops.send = usb_send;
ifd_usb_ops.recv = usb_recv;
ifd_usb_ops.reset = usb_reset;
ifd_usb_ops.get_eventfd = usb_get_eventfd;
dev = ifd_device_new(device, &ifd_usb_ops, sizeof(*dev));
dev->type = IFD_DEVICE_TYPE_USB;
dev->timeout = 10000;
dev->fd = fd;
dev->settings.usb.configuration = -1;
dev->settings.usb.interface = -1;
dev->settings.usb.altsetting = -1;
dev->settings.usb.ep_o = -1;
dev->settings.usb.ep_i = -1;
return dev;
}
openct-0.6.20/src/ifd/ifd-etoken64.c 0000644 0001750 0001750 00000007424 11151454644 013720 0000000 0000000 /*
* eToken 64 driver
*
* Copyright (C) 2005, Olaf Kirch
* Copyright (C) 2005, Andreas Jellinghaus .
*/
#include "internal.h"
#include
#include
#define ET64_TIMEOUT 1000
/*
* Initialize the device
*/
static int et64_open(ifd_reader_t * reader, const char *device_name)
{
ifd_device_t *dev;
ifd_device_params_t params;
reader->name = "Aladdin eToken PRO 64k";
reader->nslots = 1;
if (!(dev = ifd_device_open(device_name)))
return -1;
if (ifd_device_type(dev) != IFD_DEVICE_TYPE_USB) {
ct_error("etoken64: device %s is not a USB device",
device_name);
ifd_device_close(dev);
return -1;
}
params = dev->settings;
params.usb.interface = 0;
if (ifd_device_set_parameters(dev, ¶ms) < 0) {
ct_error("etoken64: setting parameters failed", device_name);
ifd_device_close(dev);
return -1;
}
reader->device = dev;
return 0;
}
/*
* Power up the reader
*/
static int et64_activate(ifd_reader_t * reader)
{
return 0;
}
static int et64_deactivate(ifd_reader_t * reader)
{
return -1;
}
/*
* Card status - always present
*/
static int et64_card_status(ifd_reader_t * reader, int slot, int *status)
{
*status = IFD_CARD_PRESENT;
return 0;
}
/*
* Reset - nothing to be done?
* We should do something to make it come back with all state zapped
*/
static int et64_card_reset(ifd_reader_t * reader, int slot, void *atr,
size_t size)
{
ifd_device_t *dev = reader->device;
unsigned char buffer[256];
int rc, n, atrlen;
/* Request the ATR */
rc = ifd_usb_control(dev, 0x40, 0x01, 0, 0, NULL, 0, ET64_TIMEOUT);
if (rc < 0)
goto failed;
/* Receive the ATR */
rc = ifd_usb_control(dev, 0xc0, 0x81, 0, 0, buffer, 0x23, ET64_TIMEOUT);
if (rc <= 0)
goto failed;
n = buffer[0];
if (n + 1 > rc)
goto failed;
if (n > IFD_MAX_ATR_LEN)
goto failed;
if (n > size)
n = size;
atrlen = n;
memcpy(atr, buffer + 1, atrlen);
if (ifd_usb_control(dev, 0x40, 0x08, 0, 0, NULL, 0, -1) < 0
|| ifd_usb_control(dev, 0xc0, 0x88, 0, 0, buffer, 02, -1) != 02
|| ifd_usb_control(dev, 0x40, 0x03, 0, 0, NULL, 0, -1) < 0
|| ifd_usb_control(dev, 0xc0, 0x83, 0, 0, buffer, 1, -1) != 1
|| buffer[0] != 0)
goto failed;
return atrlen;
failed:
ct_error("etoken64: failed to activate token");
return -1;
}
/*
* Send/receive routines
*/
static int et64_send(ifd_reader_t * reader, unsigned int dad,
const unsigned char *buffer, size_t len)
{
return ifd_usb_control(reader->device, 0x40, 0x06, 0, 0,
(void *)buffer, len, -1);
}
static int et64_recv(ifd_reader_t * reader, unsigned int dad,
unsigned char *buffer, size_t len, long timeout)
{
return ifd_usb_control(reader->device, 0xc0, 0x86, 0, 0,
buffer, len, timeout);
}
static int et64_get_eventfd(ifd_reader_t * reader, short *events)
{
ifd_debug(1, "called.");
return ifd_device_get_eventfd(reader->device, events);
}
static int et64_event(ifd_reader_t * reader, int *status, size_t status_size)
{
(void)reader;
(void)status;
(void)status_size;
ifd_debug(1, "called.");
return 0;
}
static int et64_error(ifd_reader_t * reader)
{
(void)reader;
ifd_debug(1, "called.");
return IFD_ERROR_DEVICE_DISCONNECTED;
}
/*
* Driver operations
*/
static struct ifd_driver_ops etoken64_driver;
/*
* Initialize this module
*/
void ifd_etoken64_register(void)
{
etoken64_driver.open = et64_open;
etoken64_driver.activate = et64_activate;
etoken64_driver.deactivate = et64_deactivate;
etoken64_driver.card_status = et64_card_status;
etoken64_driver.card_reset = et64_card_reset;
etoken64_driver.send = et64_send;
etoken64_driver.recv = et64_recv;
etoken64_driver.get_eventfd = et64_get_eventfd;
etoken64_driver.event = et64_event;
etoken64_driver.error = et64_error;
ifd_driver_register("etoken64", &etoken64_driver);
}
openct-0.6.20/src/ifd/ifd-egate.c 0000644 0001750 0001750 00000016060 10625650421 013336 0000000 0000000 /*
* e-gate driver
*
* Copyright (C) 2003, Chaskiel Grundman
*/
#include "internal.h"
#include
#include
#include
#define EG_TIMEOUT 1000
#define EGATE_CMD_SEND_APDU 0x80
#define EGATE_CMD_READ 0x81
#define EGATE_CMD_WRITE 0x82
#define EGATE_CMD_READ_ATR 0x83
#define EGATE_CMD_RESET 0x90
#define EGATE_CMD_STATUS 0xA0
#define EGATE_STATUS_READY 0x00
#define EGATE_STATUS_DATA 0x10
#define EGATE_STATUS_SW 0x20
#define EGATE_STATUS_BUSY 0x40
#define EGATE_STATUS_MASK 0xF0
#define EGATE_ATR_MAXSIZE 0x23
#ifdef IFD_USB_ENDPOINT_IN
#define EGATE_DIR_OUT (IFD_USB_ENDPOINT_OUT | \
IFD_USB_TYPE_VENDOR | \
IFD_USB_RECIP_DEVICE)
#define EGATE_DIR_IN (IFD_USB_ENDPOINT_IN | \
IFD_USB_TYPE_VENDOR | \
IFD_USB_RECIP_DEVICE)
#else
#define EGATE_DIR_OUT 0x40
#define EGATE_DIR_IN 0xc0
#endif
/*
* Initialize the device
*/
static int eg_open(ifd_reader_t * reader, const char *device_name)
{
ifd_device_t *dev;
ifd_device_params_t params;
ifd_debug(1, "device=%s", device_name);
reader->name = "Schlumberger E-Gate";
reader->nslots = 1;
if (!(dev = ifd_device_open(device_name)))
return -1;
if (ifd_device_type(dev) != IFD_DEVICE_TYPE_USB) {
ct_error("egate: device %s is not a USB device", device_name);
ifd_device_close(dev);
return -1;
}
params = dev->settings;
params.usb.interface = 0;
if (ifd_device_set_parameters(dev, ¶ms) < 0) {
ct_error("egate: setting parameters failed", device_name);
ifd_device_close(dev);
return -1;
}
reader->device = dev;
return 0;
}
/*
* Power up the reader
*/
static int eg_activate(ifd_reader_t * reader)
{
ifd_debug(1, "called.");
return 0;
}
static int eg_deactivate(ifd_reader_t * reader)
{
ifd_debug(1, "called.");
return 0;
}
/*
* Card status - always present
*/
static int eg_card_status(ifd_reader_t * reader, int slot, int *status)
{
ifd_debug(3, "slot=%d", slot);
*status = IFD_CARD_PRESENT;
return 0;
}
static int eg_card_reset(ifd_reader_t * reader, int slot, void *atr,
size_t size)
{
ifd_device_t *dev = reader->device;
unsigned char buffer[EGATE_ATR_MAXSIZE];
int rc, atrlen, stat;
ifd_debug(1, "called.");
usleep(100000);
/* Reset the device */
rc = ifd_usb_control(dev, EGATE_DIR_OUT, EGATE_CMD_RESET,
0, 0, NULL, 0, EG_TIMEOUT * 2);
if (rc < 0) {
failed:
ct_error("egate: failed to activate token");
return IFD_ERROR_COMM_ERROR;
}
usleep(100000);
rc = ifd_usb_control(reader->device, EGATE_DIR_IN, EGATE_CMD_STATUS,
0, 0, &stat, 1, EG_TIMEOUT);
if (rc != 1)
return IFD_ERROR_COMM_ERROR;
/* Fetch the ATR */
usleep(100000);
rc = ifd_usb_control(dev, EGATE_DIR_IN, EGATE_CMD_READ_ATR,
0, 0, buffer, EGATE_ATR_MAXSIZE, EG_TIMEOUT);
if (rc <= 0)
goto failed;
if (rc > IFD_MAX_ATR_LEN)
goto failed;
if (rc > size)
rc = size;
atrlen = rc;
memcpy(atr, buffer, atrlen);
return atrlen;
}
static int eg_set_protocol(ifd_reader_t * reader, int s, int proto)
{
ifd_slot_t *slot;
ifd_protocol_t *p;
ifd_debug(1, "proto=%d", proto);
if (proto != IFD_PROTOCOL_T0 && proto != IFD_PROTOCOL_TRANSPARENT) {
ct_error("%s: protocol %d not supported", reader->name, proto);
return IFD_ERROR_NOT_SUPPORTED;
}
slot = &reader->slot[s];
p = ifd_protocol_new(IFD_PROTOCOL_TRANSPARENT, reader, slot->dad);
if (p == NULL) {
ct_error("%s: internal error", reader->name);
return IFD_ERROR_GENERIC;
}
if (slot->proto) {
ifd_protocol_free(slot->proto);
slot->proto = NULL;
}
slot->proto = p;
return 0;
}
static unsigned char eg_status(ifd_reader_t * reader)
{
int rc;
unsigned char stat;
/* Shouldn't there be a retry counter that prevents the command
* from hanging indefinitely? Are there scenarios where the
* egate would be busy for more than say 180 secs? --okir
*/
while (1) {
rc = ifd_usb_control(reader->device, EGATE_DIR_IN,
EGATE_CMD_STATUS, 0, 0, &stat, 1,
EG_TIMEOUT);
if (rc != 1)
return -1;
stat &= EGATE_STATUS_MASK;
if (stat != EGATE_STATUS_BUSY) {
return stat;
}
usleep(100);
}
}
/*
* Send/receive routines
*/
static int eg_transparent(ifd_reader_t * reader, int dad, const void *inbuffer,
size_t inlen, void *outbuffer, size_t outlen)
{
int rc, bytesread;
unsigned char stat;
ifd_iso_apdu_t iso;
unsigned char cmdbuf[5];
int i;
stat = eg_status(reader);
if (stat != EGATE_STATUS_READY) {
for (i = 0; i < 4; i++) {
ifd_debug(2, "device not ready, attempting reset");
rc = ifd_usb_control(reader->device, EGATE_DIR_OUT,
EGATE_CMD_RESET, 0, 0, NULL, 0,
EG_TIMEOUT);
if (rc < 0)
return IFD_ERROR_COMM_ERROR;
usleep(100);
stat = eg_status(reader);
if (stat == EGATE_STATUS_READY) {
ifd_debug(2, "reset succeeded");
/* FIXME: we need a better error code */
return IFD_ERROR_COMM_ERROR;
}
ifd_debug(2, "reset failed");
}
ifd_debug(2, "giving up on reset");
return IFD_ERROR_COMM_ERROR;
}
if (ifd_iso_apdu_parse(inbuffer, inlen, &iso) < 0)
return IFD_ERROR_INVALID_ARG;
if (inlen >= 5 && inlen < 5 + iso.lc)
return IFD_ERROR_BUFFER_TOO_SMALL;
if (outlen < 2 + iso.le)
return IFD_ERROR_BUFFER_TOO_SMALL;
memset(cmdbuf, 0, 5);
memmove(cmdbuf, inbuffer, inlen < 5 ? inlen : 5);
rc = ifd_usb_control(reader->device, EGATE_DIR_OUT, EGATE_CMD_SEND_APDU,
0, 0, (void *)cmdbuf, 5, -1);
if (rc != 5)
return IFD_ERROR_COMM_ERROR;
stat = eg_status(reader);
if (inlen > 5 && stat == EGATE_STATUS_DATA) {
rc = ifd_usb_control(reader->device, EGATE_DIR_OUT,
EGATE_CMD_WRITE, 0, 0,
(void *)(((unsigned char *)inbuffer) + 5),
iso.lc, -1);
if (rc < 0)
return IFD_ERROR_COMM_ERROR;
if (rc != iso.lc) {
ifd_debug(1, "short USB write (%u of %u bytes)", rc,
iso.lc);
return IFD_ERROR_COMM_ERROR;
}
ifd_debug(3, "sent %d bytes of data", iso.lc);
stat = eg_status(reader);
}
bytesread = 0;
while (stat == EGATE_STATUS_DATA && bytesread < iso.le) {
rc = ifd_usb_control(reader->device, EGATE_DIR_IN,
EGATE_CMD_READ, 0, 0,
(void *)(((unsigned char *)outbuffer) +
bytesread),
iso.le - bytesread, EG_TIMEOUT);
if (rc < 0)
return IFD_ERROR_COMM_ERROR;
bytesread += rc;
ifd_debug(3, "received %d bytes of data", rc);
stat = eg_status(reader);
}
iso.le = bytesread;
if (stat != EGATE_STATUS_SW)
return IFD_ERROR_DEVICE_DISCONNECTED;
rc = ifd_usb_control(reader->device, EGATE_DIR_IN, EGATE_CMD_READ, 0, 0,
(void *)(((unsigned char *)outbuffer) + iso.le), 2,
EG_TIMEOUT);
if (rc != 2)
return IFD_ERROR_COMM_ERROR;
ifd_debug(2, "returning a %d byte response", iso.le + 2);
return iso.le + 2;
}
/*
* Driver operations
*/
static struct ifd_driver_ops egate_driver;
/*
* Initialize this module
*/
void ifd_egate_register(void)
{
egate_driver.open = eg_open;
egate_driver.activate = eg_activate;
egate_driver.deactivate = eg_deactivate;
egate_driver.card_status = eg_card_status;
egate_driver.card_reset = eg_card_reset;
egate_driver.set_protocol = eg_set_protocol;
egate_driver.transparent = eg_transparent;
ifd_driver_register("egate", &egate_driver);
}
openct-0.6.20/src/ifd/utils.c 0000644 0001750 0001750 00000011573 11141256300 012645 0000000 0000000 /*
* Utility functions
*
* Copyright (C) 2003, Olaf Kirch
*/
#include "internal.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifndef __GNUC__
void ifd_debug(int level, const char *fmt, ...)
{
va_list ap;
char str[2048];
va_start(ap, fmt);
vsnprintf(str, sizeof(str), fmt, ap);
if (level <= ct_config.debug)
ct_debug(str);
va_end(ap);
}
#endif
unsigned int ifd_count_bits(unsigned int word)
{
static unsigned int bcount[16] = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
};
unsigned int num;
for (num = 0; word; word >>= 4)
num += bcount[word & 0xF];
return num;
}
void ifd_revert_bits(unsigned char *data, size_t len)
{
unsigned char j, k, c, d;
while (len--) {
c = *data;
for (j = 1, k = 0x80, d = 0; k != 0; j <<= 1, k >>= 1) {
if (c & j)
d |= k;
}
*data++ = d ^ 0xFF;
}
}
#ifndef timersub
# define timersub(a, b, result) \
do { \
(result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
(result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
if ((result)->tv_usec < 0) { \
--(result)->tv_sec; \
(result)->tv_usec += 1000000; \
} \
} while (0)
#endif
/* return time elapsed since "then" in miliseconds */
long ifd_time_elapsed(struct timeval *then)
{
struct timeval now, delta;
gettimeofday(&now, NULL);
timersub(&now, then, &delta);
return delta.tv_sec * 1000 + (delta.tv_usec / 1000);
}
/*
* Spawn an ifdhandler
*/
int ifd_spawn_handler(const char *driver, const char *devtype, int idx)
{
const char *argv[16];
char reader[16], debug[10];
char *type, *device;
int argc, n;
pid_t pid;
char *user = NULL;
int force_poll = 1;
ifd_debug(1, "driver=%s, devtype=%s, index=%d", driver, devtype, idx);
if ((pid = fork()) < 0) {
ct_error("fork failed: %m");
return 0;
}
if (pid != 0) {
/* We're the parent process. The child process should
* call daemon(), causing the process to exit
* immediately after allocating a slot in the status
* file. We wait for it here to make sure USB devices
* don't claim a slot reserved for another device */
waitpid(pid, NULL, 0);
return 1;
}
argc = 0;
argv[argc++] = ct_config.ifdhandler;
if (idx >= 0) {
snprintf(reader, sizeof(reader), "-r%u", idx);
argv[argc++] = reader;
} else {
argv[argc++] = "-H";
}
if (ct_config.debug) {
if ((n = ct_config.debug) > 6)
n = 6;
debug[n + 1] = '\0';
while (n--)
debug[n + 1] = 'd';
debug[0] = '-';
argv[argc++] = debug;
}
ifd_conf_get_bool("ifdhandler.force_poll", &force_poll);
if (force_poll) {
argv[argc++] = "-p";
}
type = strdup(devtype);
device = strtok(type, ":");
device = strtok(NULL, ":");
if (!device || !type) {
ct_error("failed to parse devtype %s", devtype);
exit(1);
}
argv[argc++] = driver;
argv[argc++] = type;
argv[argc++] = device;
argv[argc] = NULL;
n = getdtablesize();
while (--n > 2)
close(n);
if ((n = ifd_conf_get_string_list("ifdhandler.groups", NULL, 0)) > 0) {
char **groups = (char **)calloc(n, sizeof(char *));
gid_t *gids = (gid_t *)calloc(n, sizeof(gid_t));
int j;
if (!groups || !gids) {
ct_error("out of memory");
exit(1);
}
n = ifd_conf_get_string_list("ifdhandler.groups", groups, n);
for (j = 0; j < n; j++) {
struct group *g = getgrnam(groups[j]);
if (g == NULL) {
ct_error("failed to parse group %s", groups[j]);
exit(1);
}
gids[j] = g->gr_gid;
}
if (setgroups(n-1, &gids[1]) == -1) {
ct_error("failed set groups %m");
exit(1);
}
if (setgid(gids[0]) == -1) {
ct_error("failed setgid %d %m", gids[0]);
exit(1);
}
free(groups);
free(gids);
}
if (ifd_conf_get_string("ifdhandler.user", &user) >= 0) {
struct passwd *p = getpwnam(user);
if (p == NULL) {
ct_error("failed to parse user %s", user);
exit(1);
}
if (setuid(p->pw_uid) == -1) {
ct_error("failed to set*uid user %s %m", user);
exit(1);
}
}
execv(ct_config.ifdhandler, (char **)argv);
ct_error("failed to execute %s: %m", ct_config.ifdhandler);
exit(1);
}
/*
* Replacement for the BSD daemon() function
*/
#ifndef HAVE_DAEMON
int daemon(int nochdir, int noclose)
{
pid_t pid;
pid = fork();
/* In case of fork is error. */
if (pid < 0)
return -1;
/* In case of this is parent process. */
if (pid != 0)
exit(0);
/* Become session leader and get pid. */
pid = setsid();
if (pid < -1) {
perror("setsid");
return -1;
}
/* Change directory to root. */
if (!nochdir)
chdir("/");
/* File descriptor close. */
if (!noclose) {
int fd;
fd = open("/dev/null", O_RDWR, 0);
if (fd != -1) {
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
if (fd > 2)
close(fd);
}
}
umask(0027);
return 0;
}
#endif
openct-0.6.20/src/ifd/pcmcia-block.c 0000644 0001750 0001750 00000005113 10625650421 014032 0000000 0000000 /*
* I/O routines for pcmcia devices
*
* Copyright (C) 2003 Olaf Kirch
* Copyright (C) 2005 Harald Welte
*/
#include "internal.h"
#include
#include
#include
#include
#include
#include
#include
#include
/*
* Input/output routines
*/
static int
ifd_pcmcia_block_send(ifd_device_t * dev, const unsigned char *buffer,
size_t len)
{
size_t total = len;
int n;
while (len) {
n = write(dev->fd, buffer, len);
if (n < 0) {
ct_error("Error writing to %s: %m", dev->name);
return -1;
}
buffer += n;
len -= n;
}
return total;
}
static int
ifd_pcmcia_block_recv(ifd_device_t * dev, unsigned char *buffer, size_t len,
long timeout)
{
struct timeval begin;
int n;
struct pollfd pfd;
long wait;
gettimeofday(&begin, NULL);
if ((wait = timeout - ifd_time_elapsed(&begin)) < 0)
goto timeout;
pfd.fd = dev->fd;
pfd.events = POLLIN;
n = poll(&pfd, 1, wait);
if (n < 0) {
ct_error("%s: error while waiting for input: %m", dev->name);
return -1;
}
if (n == 0)
goto timeout;
n = read(dev->fd, buffer, len);
if (n < 0) {
ct_error("%s: failed to read from device: %m", dev->name);
return -1;
}
if (ct_config.debug >= 9)
ifd_debug(9, "pcmcia recv:%s", ct_hexdump(buffer, n));
return n;
timeout: /* Timeouts are a little special; they may happen e.g.
* when trying to obtain the ATR */
if (!ct_config.suppress_errors)
ct_error("%s: timed out while waiting for input", dev->name);
return IFD_ERROR_TIMEOUT;
}
/*
* Set pcmcia params
*/
static int ifd_pcmcia_block_set_params(ifd_device_t * dev,
const ifd_device_params_t * params)
{
/* nothing to do so far */
dev->settings = *params;
return 0;
}
/*
* Close the device
*/
static void ifd_pcmcia_block_close(ifd_device_t * dev)
{
if (dev->fd >= 0)
close(dev->fd);
dev->fd = -1;
}
static struct ifd_device_ops ifd_pcmcia_block_ops;
/*
* Open serial device
*/
ifd_device_t *ifd_open_pcmcia_block(const char *name)
{
ifd_device_t *dev;
int fd;
if ((fd = open(name, O_RDWR)) < 0) {
ct_error("Unable to open %s: %m", name);
return NULL;
}
ifd_pcmcia_block_ops.send = ifd_pcmcia_block_send;
ifd_pcmcia_block_ops.recv = ifd_pcmcia_block_recv;
ifd_pcmcia_block_ops.set_params = ifd_pcmcia_block_set_params;
ifd_pcmcia_block_ops.close = ifd_pcmcia_block_close;
dev = ifd_device_new(name, &ifd_pcmcia_block_ops, sizeof(*dev));
dev->timeout = 1000; /* acceptable? */
dev->type = IFD_DEVICE_TYPE_PCMCIA_BLOCK;
dev->fd = fd;
return dev;
}
openct-0.6.20/src/ifd/proto-t1.c 0000644 0001750 0001750 00000032365 11141256300 013174 0000000 0000000 /*
* Implementation of T=1
*
* Copyright (C) 2003, Olaf Kirch
*
* improvements by:
* Copyright (C) 2004 Ludovic Rousseau
*/
#include "internal.h"
#include
#include
#include
#include
typedef struct {
ifd_protocol_t base;
int state;
int block_oriented;
unsigned char ns;
unsigned char nr;
unsigned int ifsc;
unsigned int ifsd;
unsigned int timeout, wtx;
unsigned int retries;
unsigned int rc_bytes;
unsigned int (*checksum) (const unsigned char *,
size_t, unsigned char *);
} t1_state_t;
/* T=1 protocol constants */
#define T1_I_BLOCK 0x00
#define T1_R_BLOCK 0x80
#define T1_S_BLOCK 0xC0
#define T1_MORE_BLOCKS 0x20
/* I block */
#define T1_I_SEQ_SHIFT 6
/* R block */
#define T1_IS_ERROR(pcb) ((pcb) & 0x0F)
#define T1_EDC_ERROR 0x01
#define T1_OTHER_ERROR 0x02
#define T1_R_SEQ_SHIFT 4
/* S block stuff */
#define T1_S_IS_RESPONSE(pcb) ((pcb) & T1_S_RESPONSE)
#define T1_S_TYPE(pcb) ((pcb) & 0x0F)
#define T1_S_RESPONSE 0x20
#define T1_S_RESYNC 0x00
#define T1_S_IFS 0x01
#define T1_S_ABORT 0x02
#define T1_S_WTX 0x03
#define T1_BUFFER_SIZE (3 + 254 + 2)
#define NAD 0
#define PCB 1
#define LEN 2
#define DATA 3
/* internal state, do not mess with it. */
/* should be != DEAD after reset/init */
enum {
SENDING, RECEIVING, RESYNCH, DEAD
};
static void t1_set_checksum(t1_state_t *, int);
static unsigned int t1_block_type(unsigned char);
static unsigned int t1_seq(unsigned char);
static unsigned int t1_build(t1_state_t *, unsigned char *,
unsigned char, unsigned char,
ct_buf_t *, size_t *);
static unsigned int t1_compute_checksum(t1_state_t *, unsigned char *, size_t);
static int t1_verify_checksum(t1_state_t *, unsigned char *, size_t);
static int t1_xcv(t1_state_t *, unsigned char *, size_t, size_t);
/*
* Set default T=1 protocol parameters
*/
static void t1_set_defaults(t1_state_t * t1)
{
t1->retries = 3;
/* This timeout is rather insane, but we need this right now
* to support cryptoflex keygen */
t1->timeout = 20000;
t1->ifsc = 32;
t1->ifsd = 32;
t1->nr = 0;
t1->ns = 0;
t1->wtx = 0;
}
static void t1_set_checksum(t1_state_t * t1, int csum)
{
switch (csum) {
case IFD_PROTOCOL_T1_CHECKSUM_LRC:
t1->rc_bytes = 1;
t1->checksum = csum_lrc_compute;
break;
case IFD_PROTOCOL_T1_CHECKSUM_CRC:
t1->rc_bytes = 2;
t1->checksum = csum_crc_compute;
break;
}
}
/*
* Attach t1 protocol
*/
static int t1_init(ifd_protocol_t * prot)
{
t1_state_t *t1 = (t1_state_t *) prot;
t1_set_defaults(t1);
t1_set_checksum(t1, IFD_PROTOCOL_T1_CHECKSUM_LRC);
/* If the device is attached through USB etc, assume the
* device will do the framing for us */
if (prot->reader->device->type != IFD_DEVICE_TYPE_SERIAL)
t1->block_oriented = 1;
return 0;
}
/*
* Detach t1 protocol
*/
static void t1_release(ifd_protocol_t * prot)
{
/* NOP */
}
/*
* Get/set parmaters for T1 protocol
*/
static int t1_set_param(ifd_protocol_t * prot, int type, long value)
{
t1_state_t *t1 = (t1_state_t *) prot;
switch (type) {
case IFD_PROTOCOL_RECV_TIMEOUT:
t1->timeout = value;
break;
case IFD_PROTOCOL_BLOCK_ORIENTED:
t1->block_oriented = value;
break;
case IFD_PROTOCOL_T1_CHECKSUM_LRC:
case IFD_PROTOCOL_T1_CHECKSUM_CRC:
t1_set_checksum(t1, type);
break;
case IFD_PROTOCOL_T1_IFSC:
t1->ifsc = value;
break;
case IFD_PROTOCOL_T1_IFSD:
t1->ifsd = value;
break;
default:
ct_error("Unsupported parameter %d", type);
return -1;
}
return 0;
}
static int t1_get_param(ifd_protocol_t * prot, int type, long *result)
{
t1_state_t *t1 = (t1_state_t *) prot;
long value;
switch (type) {
case IFD_PROTOCOL_RECV_TIMEOUT:
value = t1->timeout;
break;
case IFD_PROTOCOL_BLOCK_ORIENTED:
value = t1->block_oriented;
break;
default:
ct_error("Unsupported parameter %d", type);
return -1;
}
if (result)
*result = value;
return 0;
}
/*
* Send an APDU through T=1
*/
static int t1_transceive(ifd_protocol_t * prot, int dad, const void *snd_buf,
size_t snd_len, void *rcv_buf, size_t rcv_len)
{
t1_state_t *t1 = (t1_state_t *) prot;
ct_buf_t sbuf, rbuf, tbuf;
unsigned char sdata[T1_BUFFER_SIZE], sblk[5];
unsigned int slen, retries, resyncs, sent_length = 0;
size_t last_send = 0;
if (snd_len == 0)
return -1;
/* we can't talk to a dead card / reader. Reset it! */
if (t1->state == DEAD)
return -1;
t1->state = SENDING;
retries = t1->retries;
resyncs = 3;
/* Initialize send/recv buffer */
ct_buf_set(&sbuf, (void *)snd_buf, snd_len);
ct_buf_init(&rbuf, rcv_buf, rcv_len);
/* Send the first block */
slen = t1_build(t1, sdata, dad, T1_I_BLOCK, &sbuf, &last_send);
while (1) {
unsigned char pcb;
int n;
retries--;
if ((n = t1_xcv(t1, sdata, slen, sizeof(sdata))) < 0) {
ifd_debug(1, "fatal: transmit/receive failed");
t1->state = DEAD;
goto error;
}
if (!t1_verify_checksum(t1, sdata, n)) {
ifd_debug(1, "checksum failed");
if (retries == 0 || sent_length)
goto resync;
slen = t1_build(t1, sdata,
dad, T1_R_BLOCK | T1_EDC_ERROR,
NULL, NULL);
continue;
}
pcb = sdata[PCB];
switch (t1_block_type(pcb)) {
case T1_R_BLOCK:
if (T1_IS_ERROR(pcb)) {
ifd_debug(1, "received error block, err=%d",
T1_IS_ERROR(pcb));
goto resync;
}
if (t1->state == RECEIVING) {
slen = t1_build(t1, sdata,
dad, T1_R_BLOCK, NULL, NULL);
break;
}
/* If the card terminal requests the next
* sequence number, it received the previous
* block successfully */
if (t1_seq(pcb) != t1->ns) {
ct_buf_get(&sbuf, NULL, last_send);
sent_length += last_send;
last_send = 0;
t1->ns ^= 1;
}
/* If there's no data available, the ICC
* shouldn't be asking for more */
if (ct_buf_avail(&sbuf) == 0)
goto resync;
slen = t1_build(t1, sdata, dad, T1_I_BLOCK,
&sbuf, &last_send);
break;
case T1_I_BLOCK:
/* The first I-block sent by the ICC indicates
* the last block we sent was received successfully. */
if (t1->state == SENDING) {
ct_buf_get(&sbuf, NULL, last_send);
last_send = 0;
t1->ns ^= 1;
}
t1->state = RECEIVING;
/* If the block sent by the card doesn't match
* what we expected it to send, reply with
* an R block */
if (t1_seq(pcb) != t1->nr) {
slen = t1_build(t1, sdata, dad,
T1_R_BLOCK | T1_OTHER_ERROR,
NULL, NULL);
continue;
}
t1->nr ^= 1;
if (ct_buf_put(&rbuf, sdata + 3, sdata[LEN]) < 0)
goto error;
if ((pcb & T1_MORE_BLOCKS) == 0)
goto done;
slen = t1_build(t1, sdata, dad, T1_R_BLOCK, NULL, NULL);
break;
case T1_S_BLOCK:
if (T1_S_IS_RESPONSE(pcb) && t1->state == RESYNCH) {
t1->state = SENDING;
sent_length = 0;
last_send = 0;
resyncs = 3;
retries = t1->retries;
ct_buf_init(&rbuf, rcv_buf, rcv_len);
slen = t1_build(t1, sdata, dad, T1_I_BLOCK,
&sbuf, &last_send);
continue;
}
if (T1_S_IS_RESPONSE(pcb))
goto resync;
ct_buf_init(&tbuf, sblk, sizeof(sblk));
switch (T1_S_TYPE(pcb)) {
case T1_S_RESYNC:
/* the card is not allowed to send a resync. */
goto resync;
case T1_S_ABORT:
ifd_debug(1, "abort requested");
break;
case T1_S_IFS:
ifd_debug(1, "CT sent S-block with ifs=%u",
sdata[DATA]);
if (sdata[DATA] == 0)
goto resync;
t1->ifsc = sdata[DATA];
ct_buf_putc(&tbuf, sdata[DATA]);
break;
case T1_S_WTX:
/* We don't handle the wait time extension
* yet */
ifd_debug(1, "CT sent S-block with wtx=%u",
sdata[DATA]);
t1->wtx = sdata[DATA];
ct_buf_putc(&tbuf, sdata[DATA]);
break;
default:
ct_error("T=1: Unknown S block type 0x%02x",
T1_S_TYPE(pcb));
goto resync;
}
slen = t1_build(t1, sdata, dad,
T1_S_BLOCK | T1_S_RESPONSE |
T1_S_TYPE(pcb), &tbuf, NULL);
}
/* Everything went just splendid */
retries = t1->retries;
continue;
resync:
/* the number or resyncs is limited, too */
if (resyncs == 0)
goto error;
resyncs--;
t1->ns = 0;
t1->nr = 0;
slen = t1_build(t1, sdata, dad, T1_S_BLOCK | T1_S_RESYNC, NULL,
NULL);
t1->state = RESYNCH;
continue;
}
done:
return ct_buf_avail(&rbuf);
error:
t1->state = DEAD;
return -1;
}
static int t1_resynchronize(ifd_protocol_t * p, int nad)
{
t1_state_t *t1 = (t1_state_t *) p;
unsigned char block[4];
unsigned int retries = 3;
if (p->reader && p->reader->device)
ifd_device_flush(p->reader->device);
while (retries--) {
t1->ns = 0;
t1->nr = 0;
block[0] = nad;
block[1] = T1_S_BLOCK | T1_S_RESYNC;
block[2] = 0;
t1_compute_checksum(t1, block, 3);
if (t1_xcv(t1, block, 4, sizeof(block)) != 4) {
ifd_debug(1, "fatal: transmit/receive failed");
break;
}
if (!t1_verify_checksum(t1, block, 4)) {
ifd_debug(1, "checksum failed");
continue;
}
if (block[1] == (T1_S_BLOCK | T1_S_RESPONSE | T1_S_RESYNC))
return 0;
}
t1->state = DEAD;
return -1;
}
static unsigned t1_block_type(unsigned char pcb)
{
switch (pcb & 0xC0) {
case T1_R_BLOCK:
return T1_R_BLOCK;
case T1_S_BLOCK:
return T1_S_BLOCK;
default:
return T1_I_BLOCK;
}
}
static unsigned int t1_seq(unsigned char pcb)
{
switch (pcb & 0xC0) {
case T1_R_BLOCK:
return (pcb >> T1_R_SEQ_SHIFT) & 1;
case T1_S_BLOCK:
return 0;
default:
return (pcb >> T1_I_SEQ_SHIFT) & 1;
}
}
static unsigned int t1_build(t1_state_t * t1, unsigned char *block,
unsigned char dad, unsigned char pcb,
ct_buf_t * bp, size_t * lenp)
{
unsigned int len;
len = bp ? ct_buf_avail(bp) : 0;
if (len > t1->ifsc) {
pcb |= T1_MORE_BLOCKS;
len = t1->ifsc;
}
/* Add the sequence number */
switch (t1_block_type(pcb)) {
case T1_R_BLOCK:
pcb |= t1->nr << T1_R_SEQ_SHIFT;
break;
case T1_I_BLOCK:
pcb |= t1->ns << T1_I_SEQ_SHIFT;
break;
}
block[0] = dad;
block[1] = pcb;
block[2] = len;
if (len)
memcpy(block + 3, ct_buf_head(bp), len);
if (lenp)
*lenp = len;
return t1_compute_checksum(t1, block, len + 3);
}
/*
* Protocol struct
*/
struct ifd_protocol_ops ifd_protocol_t1 = {
IFD_PROTOCOL_T1, /* id */
"T=1", /* name */
sizeof(t1_state_t), /* size */
t1_init, /* init */
t1_release, /* release */
t1_set_param, /* set_param */
t1_get_param, /* get_param */
t1_resynchronize, /* resynchronize */
t1_transceive, /* transceive */
NULL, /* sync_read */
NULL, /* sync_write */
};
/*
* Build/verify checksum
*/
static unsigned int t1_compute_checksum(t1_state_t * t1, unsigned char *data,
size_t len)
{
return len + t1->checksum(data, len, data + len);
}
static int t1_verify_checksum(t1_state_t * t1, unsigned char *rbuf, size_t len)
{
unsigned char csum[2];
int m, n;
m = len - t1->rc_bytes;
n = t1->rc_bytes;
if (m < 0)
return 0;
t1->checksum(rbuf, m, csum);
if (!memcmp(rbuf + m, csum, n))
return 1;
return 0;
}
/*
* Send/receive block
*/
static int t1_xcv(t1_state_t * t1, unsigned char *block, size_t slen,
size_t rmax)
{
ifd_protocol_t *prot = &t1->base;
unsigned int rlen, timeout;
int n, m;
if (ct_config.debug >= 3)
ifd_debug(3, "sending %s", ct_hexdump(block, slen));
n = ifd_send_command(prot, block, slen);
if (n < 0)
return n;
/* Maximum amount of data we'll receive - some devices
* such as the eToken need this. If you request more, it'll
* just barf */
rlen = 3 + t1->ifsd + t1->rc_bytes;
/* timeout. For now our WTX treatment is very dumb */
timeout = t1->timeout + 1000 * t1->wtx;
t1->wtx = 0;
if (t1->block_oriented) {
/* Note - Linux USB seems to have an off by one error, you
* actually need the + 1 to get the RC byte */
rlen++;
if (rlen < rmax)
rmax = rlen;
/* Get the response en bloc */
n = ifd_recv_response(prot, block, rmax, timeout);
if (n >= 0) {
m = block[2] + 3 + t1->rc_bytes;
if (m < n)
n = m;
}
} else {
/* Get the header */
if (ifd_recv_response(prot, block, 3, timeout) < 0)
return -1;
n = block[2] + t1->rc_bytes;
if (n + 3 > rmax || block[2] >= 254) {
ct_error("receive buffer too small");
return -1;
}
/* Now get the rest */
if (ifd_recv_response(prot, block + 3, n, t1->timeout) < 0)
return -1;
n += 3;
}
if (n >= 0 && ct_config.debug >= 3)
ifd_debug(3, "received %s", ct_hexdump(block, n));
return n;
}
int t1_negotiate_ifsd(ifd_protocol_t * proto, unsigned int dad, int ifsd)
{
t1_state_t *t1 = (t1_state_t *) proto;
ct_buf_t sbuf;
unsigned char sdata[T1_BUFFER_SIZE];
unsigned int slen;
unsigned int retries;
size_t snd_len;
int n;
unsigned char snd_buf[1], pcb;
retries = t1->retries;
/* S-block IFSD request */
snd_buf[0] = ifsd;
snd_len = 1;
/* Initialize send/recv buffer */
ct_buf_set(&sbuf, (void *)snd_buf, snd_len);
while (1) {
/* Build the block */
slen =
t1_build(t1, sdata, dad, T1_S_BLOCK | T1_S_IFS, &sbuf,
NULL);
if ((n = t1_xcv(t1, sdata, slen, sizeof(sdata))) < 0) {
ifd_debug(1, "fatal: transmit/receive failed");
t1->state = DEAD;
goto error;
}
if (!t1_verify_checksum(t1, sdata, n)) {
ifd_debug(1, "checksum failed");
if (retries == 0)
goto error;
continue;
}
pcb = sdata[1];
if (t1_block_type(pcb) == T1_S_BLOCK &&
T1_S_TYPE(pcb) == T1_S_IFS && T1_S_IS_RESPONSE(pcb)) {
if (sdata[LEN] != 1 || sdata[DATA] != ifsd)
goto error;
break;
}
if (retries == 0)
goto error;
}
return n;
error:
t1_resynchronize(proto, dad);
return -1;
}
openct-0.6.20/src/ifd/ctbcs.h 0000644 0001750 0001750 00000001717 10422076714 012621 0000000 0000000 /*
* Build Extended CTBCS APDUs for those readers that
* support them (such as Kobil Kaan).
*
* Copyright (C) 2003, Olaf Kirch
*/
#ifndef IFD_CTBCS_H
#define IFD_CTBCS_H
extern int ctbcs_build_output(unsigned char *cmd, size_t size,
const char *message);
extern int ctbcs_build_perform_verify_apdu(unsigned char *cmd, size_t size,
unsigned int slot,
const char *prompt,
unsigned int timeout,
const unsigned char *data,
size_t data_len);
extern int ctbcs_build_modify_verify_apdu(unsigned char *cmd, size_t size,
unsigned int dest, const char *prompt,
unsigned int timeout,
const unsigned char *data,
size_t data_len);
extern void ctbcs_begin(ct_buf_t *, unsigned int, unsigned int, unsigned int);
extern int ctbcs_finish(ct_buf_t *);
extern int ctbcs_add_message(ct_buf_t *, const char *);
extern int ctbcs_add_timeout(ct_buf_t *, unsigned int);
#endif /* IFD_CTBCS_H */
openct-0.6.20/src/ifd/sys-bsd.c 0000644 0001750 0001750 00000036650 11252127023 013076 0000000 0000000 /*
* *BSD specific functions
*
* Copyright (C) 2003 Olaf Kirch
* Copyright (C) 2003 Andreas Jellinghaus
* Copyright (C) 2003 Markus Friedl
* Copyright (C) 2004-2005 William Wanders
*
* These functions need to be re-implemented for every
* new platform.
*/
#include "internal.h"
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
#include
#ifndef ENABLE_LIBUSB
#if defined(__DragonFly__)
#include
#else
#include
#endif
#endif /* !ENABLE_LIBUSB */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef ENABLE_LIBUSB
#include
#endif
#include "usb-descriptors.h"
#ifdef ENABLE_LIBUSB
struct usb_dev_handle *devices[128];
#endif
/*
* Poll for presence of USB device
*/
int ifd_sysdep_usb_poll_presence(ifd_device_t * dev, struct pollfd *pfd)
{
if (pfd->revents & POLLHUP)
return 0;
pfd->fd = dev->fd;
pfd->events = POLLHUP;
return 1;
}
#ifndef ENABLE_LIBUSB
typedef struct ep {
int ep_fd;
} ep_t;
typedef ep_t interface_t[128];
static interface_t interfaces[1];
#define USB_REQUEST_SIZE 8
/*
* Open interface endpoint
*/
int open_ep(char *name, int interface, int endpoint, int flags)
{
char filename[256];
if (interfaces[interface][endpoint].ep_fd) {
ifd_debug(6, "open_ep: endpoint already opened");
return 0;
}
#ifdef __OpenBSD__
snprintf(filename, sizeof(filename), "%s.%02d", name, endpoint);
#else
snprintf(filename, sizeof(filename), "%s.%d", name, endpoint);
#endif /* __OpenBSD__ */
if ((interfaces[interface][endpoint].ep_fd = open(filename, flags)) < 0) {
ifd_debug(6, "open_ep: error opening \"%s\": %s", filename,
strerror(errno));
interfaces[interface][endpoint].ep_fd = 0;
return -1;
}
return 0;
}
static void
close_ep(int interface, int endpoint)
{
if (interfaces[interface][endpoint].ep_fd) {
close(interfaces[interface][endpoint].ep_fd);
interfaces[interface][endpoint].ep_fd = 0;
}
}
#endif /* !ENABLE_LIBUSB */
int ifd_sysdep_usb_bulk(ifd_device_t * dev, int ep, void *buffer, size_t len,
long timeout)
{
int bytes_to_process;
int bytes_processed;
int direction =
(ep & IFD_USB_ENDPOINT_DIR_MASK) == IFD_USB_ENDPOINT_IN ? 1 : 0;
int endpoint = (ep & ~IFD_USB_ENDPOINT_DIR_MASK);
ct_debug("ifd_sysdep_usb_bulk: endpoint=%d direction=%d", endpoint,
direction);
if (direction) {
#ifdef ENABLE_LIBUSB
if ((bytes_to_process =
usb_bulk_read(devices[dev->fd], ep, buffer, len,
timeout)) < 0) {
ifd_debug(6, "ifd_sysdep_usb_bulk: read failed: %s",
strerror(errno));
ct_error("usb_bulk read failed: %s", strerror(errno));
return IFD_ERROR_COMM_ERROR;
}
#else
int one = 1;
if (open_ep(dev->name, 0, endpoint, O_RDONLY | O_NONBLOCK)) {
ct_debug("ifd_sysdep_usb_bulk: opening endpoint failed");
return -1;
}
if (ioctl(interfaces[0][endpoint].ep_fd, USB_SET_SHORT_XFER,
&one) < 0) {
ifd_debug(6, "ifd_sysdep_usb_bulk: USB_SET_SHORT_XFER"
" failed: %s", strerror(errno));
ct_error("usb_bulk read failed: %s", strerror(errno));
}
if ((bytes_to_process =
read(interfaces[0][endpoint].ep_fd, buffer, len)) < 0) {
ifd_debug(6, "ifd_sysdep_usb_bulk: read failed: %s",
strerror(errno));
ct_error("usb_bulk read failed: %s", strerror(errno));
return IFD_ERROR_COMM_ERROR;
}
#endif /* ENABLE_LIBUSB */
ct_debug("ifd_sysdep_usb_bulk: read %d bytes",
bytes_to_process);
return bytes_to_process;
} else {
#ifndef ENABLE_LIBUSB
if (open_ep(dev->name, 0, endpoint, O_WRONLY | O_NONBLOCK)) {
ct_debug("ifd_sysdep_usb_bulk: opening endpoint failed");
return -1;
}
#endif /* !ENABLE_LIBUSB */
bytes_to_process = len;
if ((bytes_processed =
#ifdef ENABLE_LIBUSB
usb_bulk_write(devices[dev->fd], ep, buffer,
bytes_to_process, timeout)
#else
write(interfaces[0][endpoint].ep_fd, buffer,
bytes_to_process)
#endif /* ENABLE_LIBUSB */
) != bytes_to_process) {
ifd_debug(6, "ifd_sysdep_usb_bulk: write failed: %s",
strerror(errno));
ct_error("usb_bulk write failed: %s", strerror(errno));
return IFD_ERROR_COMM_ERROR;
}
ct_debug("ifd_sysdep_usb_bulk: wrote buffer[%d]=%s",
bytes_processed, ct_hexdump(buffer, len));
return bytes_processed;
}
}
int ifd_sysdep_usb_get_eventfd(ifd_device_t * dev, short *events)
{
return -1;
}
/*
* USB URB capture
*/
struct ifd_usb_capture {
int type;
int endpoint;
size_t maxpacket;
unsigned int interface;
};
int ifd_sysdep_usb_begin_capture(ifd_device_t * dev, int type, int ep,
size_t maxpacket, ifd_usb_capture_t ** capret)
{
ifd_usb_capture_t *cap;
#ifndef ENABLE_LIBUSB
int direction =
(ep & IFD_USB_ENDPOINT_DIR_MASK) == IFD_USB_ENDPOINT_IN ? 1 : 0;
int endpoint = (ep & ~IFD_USB_ENDPOINT_DIR_MASK);
#endif /* !ENABLE_LIBUSB */
if (!(cap = (ifd_usb_capture_t *) calloc(1, sizeof(*cap) + maxpacket))) {
ct_error("out of memory");
return IFD_ERROR_NO_MEMORY;
}
cap->type = type;
cap->endpoint = ep;
cap->maxpacket = maxpacket;
#ifndef ENABLE_LIBUSB
if (!interfaces[0][endpoint].ep_fd) {
if (open_ep(dev->name, 0, endpoint, O_RDONLY | O_NONBLOCK)) {
ct_debug
("ifd_sysdep_usb_begin_capture: opening endpoint failed");
return -1;
}
}
#endif /* !ENABLE_LIBUSB */
*capret = cap;
return 0;
}
int ifd_sysdep_usb_capture_event(ifd_device_t * dev, ifd_usb_capture_t * cap,
void *buffer, size_t len)
{
return IFD_ERROR_NOT_SUPPORTED;
}
int ifd_sysdep_usb_capture(ifd_device_t * dev, ifd_usb_capture_t * cap,
void *buffer, size_t len, long timeout)
{
int bytes_to_process = 0;
#ifdef ENABLE_LIBUSB
if ((bytes_to_process =
usb_interrupt_read(devices[dev->fd], cap->endpoint, buffer, len,
timeout)) < 0) {
ifd_debug(6,
"ifd_sysdep_usb_capture: usb_interrupt_read failed: %s",
strerror(errno));
ct_error("usb_bulk read failed: %s", strerror(errno));
return IFD_ERROR_COMM_ERROR;
}
#else
struct timeval begin;
int direction =
(cap->endpoint & IFD_USB_ENDPOINT_DIR_MASK) ==
IFD_USB_ENDPOINT_IN ? 1 : 0;
int endpoint = (cap->endpoint & ~IFD_USB_ENDPOINT_DIR_MASK);
gettimeofday(&begin, NULL);
do {
struct pollfd pfd;
long wait;
if ((wait = (timeout - ifd_time_elapsed(&begin))) <= 0)
return IFD_ERROR_TIMEOUT;
pfd.fd = interfaces[0][endpoint].ep_fd;
pfd.events = POLLIN;
if (poll(&pfd, 1, wait) != 1)
continue;
if ((bytes_to_process =
read(interfaces[0][endpoint].ep_fd, buffer, len)) < 0) {
ifd_debug(6, "ifd_sysdep_usb_bulk: read failed: %s",
strerror(errno));
ct_error("usb_bulk read failed: %s", strerror(errno));
return IFD_ERROR_COMM_ERROR;
}
} while (!bytes_to_process);
#endif /* ENABLE_LIBUSB */
ct_debug("ifd_sysdep_usb_capture: read buffer[%d]=%s", bytes_to_process,
ct_hexdump(buffer, bytes_to_process));
return bytes_to_process;
}
int ifd_sysdep_usb_end_capture(ifd_device_t * dev, ifd_usb_capture_t * cap)
{
#ifndef ENABLE_LIBUSB
int direction =
(cap->endpoint & IFD_USB_ENDPOINT_DIR_MASK) ==
IFD_USB_ENDPOINT_IN ? 1 : 0;
int endpoint = (cap->endpoint & ~IFD_USB_ENDPOINT_DIR_MASK);
close_ep(0, endpoint);
#endif /* !ENABLE_LIBUSB */
if (cap)
free(cap);
return 0;
}
/*
* USB control command
*/
int ifd_sysdep_usb_control(ifd_device_t * dev, unsigned int requesttype,
unsigned int request, unsigned int value,
unsigned int index, void *data, size_t len,
long timeout)
{
int rc, val;
#ifdef ENABLE_LIBUSB
ct_debug("ifd_sysdep_usb_control: dev->fd=%d handle=0x%x", dev->fd,
devices[dev->fd]);
if ((rc =
usb_control_msg(devices[dev->fd], requesttype, request, value,
index, data, len, timeout)) < 0) {
ifd_debug(1, "usb_control_msg failed: %d", rc);
ct_error("usb_control_msg failed: %s(%d)",
strerror(errno), errno);
return IFD_ERROR_COMM_ERROR;
}
ct_debug("ifd_sysdep_usb_control: return rc=%d", rc);
return rc;
#else
struct usb_ctl_request ctrl;
int retries;
ifd_debug(1, "BSD: ifd_sysdep_usb_control(0x%x)", request);
memset(&ctrl, 0, sizeof(ctrl));
ctrl.ucr_request.bmRequestType = requesttype;
ctrl.ucr_request.bRequest = request;
USETW(ctrl.ucr_request.wValue, value);
USETW(ctrl.ucr_request.wIndex, index);
USETW(ctrl.ucr_request.wLength, len);
ctrl.ucr_data = data;
ctrl.ucr_flags = USBD_SHORT_XFER_OK;
ifd_debug(1, "BSD: CTRL bmRequestType 0x%x bRequest 0x%x "
"wValue 0x%x wIndex 0x%x wLength 0x%x",
requesttype, request, value, index, len);
if (len)
ifd_debug(5, "BSD: CTRL SEND data %s", ct_hexdump(data, len));
val = timeout;
if ((rc = ioctl(dev->fd, USB_SET_TIMEOUT, &val)) < 0) {
ifd_debug(1, "USB_SET_TIMEOUT failed: %d", rc);
ct_error("usb_set_timeout failed: %s(%d)",
strerror(errno), errno);
return IFD_ERROR_COMM_ERROR;
}
retries = 5;
while ((rc = ioctl(dev->fd, USB_DO_REQUEST, &ctrl)) < 0 && retries > 0) {
ifd_debug(1, "USB_DO_REQUEST failed: %d", rc);
ct_error("usb_do_request failed: %s (%d)",
strerror(errno), errno);
retries--;
if ((retries == 0) || (errno != EIO))
return IFD_ERROR_COMM_ERROR;
}
if (ctrl.ucr_data == NULL)
ifd_debug(1, "BSD: ctrl.ucr_data == NULL ");
if (ctrl.ucr_data && ctrl.ucr_actlen)
ifd_debug(1, "BSD: CTRL RECV data %s",
ct_hexdump(ctrl.ucr_data, ctrl.ucr_actlen));
return ctrl.ucr_actlen;
#endif /* ENABLE_LIBUSB */
}
int ifd_sysdep_usb_set_configuration(ifd_device_t * dev, int config)
{
int rc;
#ifdef ENABLE_LIBUSB
if ((rc = usb_set_configuration(devices[dev->fd], config)) < 0) {
ifd_debug(1, "usb_set_configuration failed: %d", rc);
#else
int value;
value = config;
if ((rc = ioctl(dev->fd, USB_SET_CONFIG, &value)) < 0) {
ifd_debug(1, "USB_SET_CONFIG failed: %d", rc);
#endif /* ENABLE_LIBUSB */
ct_error("usb_set_configuration failed: %s(%d)",
strerror(errno), errno);
return IFD_ERROR_COMM_ERROR;
}
return 0;
}
int ifd_sysdep_usb_set_interface(ifd_device_t * dev, int ifc, int alt)
{
int rc;
#ifdef ENABLE_LIBUSB
if ((rc = usb_set_altinterface(devices[dev->fd], alt)) < 0) {
ifd_debug(1, "usb_set_altinterface failed: %d", rc);
#else
struct usb_alt_interface {
int uai_config_index;
int uai_interface_index;
int uai_alt_no;
} value;
value.uai_config_index = ifc;
value.uai_interface_index = 0;
value.uai_alt_no = alt;
if ((rc = ioctl(dev->fd, USB_SET_ALTINTERFACE, &value)) < 0) {
ifd_debug(1, "USB_SET_ALTINTERFACE failed: %d", rc);
#endif /* ENABLE_LIBUSB */
ct_error("usb_set_interface failed: %s(%d)",
strerror(errno), errno);
return IFD_ERROR_COMM_ERROR;
}
return 0;
}
int ifd_sysdep_usb_claim_interface(ifd_device_t * dev, int interface)
{
#ifdef ENABLE_LIBUSB
int rc;
ct_debug("ifd_sysdep_usb_claim_interface: interface=%d", interface);
if ((rc = usb_claim_interface(devices[dev->fd], interface)) < 0) {
ifd_debug(1, "usb_clain_interface failed: %d", rc);
ct_error("usb_release_interface failed: %s(%d)",
strerror(errno), errno);
return IFD_ERROR_COMM_ERROR;
}
#else
ct_debug
("ifd_sysdep_usb_claim_interface: interface=%d (not yet implemented)",
interface);
#endif /* ENABLE_LIBUSB */
return 0;
}
int ifd_sysdep_usb_release_interface(ifd_device_t * dev, int interface)
{
#ifdef ENABLE_LIBUSB
int rc;
ct_debug("ifd_sysdep_usb_release_interface: interface=%d", interface);
if ((rc = usb_release_interface(devices[dev->fd], interface)) < 0) {
ifd_debug(1, "usb_release_interface failed: %d", rc);
ct_error("usb_release_interface failed: %s(%d)",
strerror(errno), errno);
return IFD_ERROR_COMM_ERROR;
}
#else
ct_debug
("ifd_sysdep_usb_release_interface: interface=%d (not yet implemented)",
interface);
#endif /* ENABLE_LIBUSB */
return 0;
}
int ifd_sysdep_usb_open(const char *device)
{
#ifdef ENABLE_LIBUSB
struct usb_bus *bus;
struct usb_device *dev;
ct_debug("ifd_sysdep_usb_open: name=%s", device);
ct_debug("ifd_sysdep_usb_open: usb_init()");
usb_init();
ct_debug("ifd_sysdep_usb_open: usb_find_busses()");
usb_find_busses();
ct_debug("ifd_sysdep_usb_open: usb_find_devices()");
usb_find_devices();
ct_debug("ifd_sysdep_usb_open: walk devices");
for (bus = usb_busses; bus; bus = bus->next) {
for (dev = bus->devices; dev; dev = dev->next) {
int i;
if (strcmp(dev->filename, device) != 0)
continue;
ct_debug
("ifd_sysdep_usb_open: found match name=%s device=%s",
device, dev->filename);
for (i = 0; i < 128; i++) {
if (devices[i] == NULL) {
devices[i] = usb_open(dev);
ct_debug
("ifd_sysdep_usb_open: usb_open index=%d handle=0x%x",
i, devices[i]);
return i;
}
}
}
}
return -1;
#else
#ifdef __OpenBSD__
char path[256];
if (snprintf(&path, sizeof(path), "%s.00", device) < 0)
return -1;
return open(path, O_RDWR);
#else
return open(device, O_RDWR);
#endif /* __OpenBSD__ */
#endif /* ENABLE_LIBUSB */
}
int ifd_sysdep_usb_reset(ifd_device_t * dev)
{
/* not implemented so far */
return -1;
}
/*
* Scan all usb devices to see if there is one we support
*/
int ifd_scan_usb(void)
{
#ifdef ENABLE_LIBUSB
struct usb_bus *bus;
struct usb_device *dev;
ifd_devid_t id;
usb_init();
usb_find_busses();
usb_find_devices();
id.type = IFD_DEVICE_TYPE_USB;
id.num = 2;
for (bus = usb_busses; bus; bus = bus->next) {
for (dev = bus->devices; dev; dev = dev->next) {
const char *driver;
char typedev[PATH_MAX];
id.val[0] = dev->descriptor.idVendor;
id.val[1] = dev->descriptor.idProduct;
/* FIXME: if we don't find a driver with vendor/product
* then check for the interface type (ccid) and use
* driver ccid... */
if (!(driver = ifd_driver_for_id(&id)))
continue;
snprintf(typedev, sizeof(typedev),
"usb:%s", dev->filename);
ifd_spawn_handler(driver, typedev, -1);
}
}
#else
int i, controller_fd;
char controller_devname[10];
ifd_debug(1, "BSD: ifd_scan_usb");
for (i = 0; i < 10; i++) {
int address;
snprintf(controller_devname, 10, "/dev/usb%d.00", i);
if ((controller_fd = open(controller_devname, O_RDONLY)) < 0)
continue;
if (controller_fd < 0) {
if (errno == ENOENT || errno == ENXIO)
continue;
/* a more suitable error recovery should be done here */
continue;
}
for (address = 1; address < USB_MAX_DEVICES; address++) {
struct usb_device_info device_info;
ifd_devid_t id;
const char *driver;
char typedev[256];
device_info.udi_addr = address;
if (ioctl(controller_fd, USB_DEVICEINFO, &device_info)) {
if (errno != ENXIO)
fprintf(stderr,
"addr %d: I/O error\n",
address);
continue;
}
if (strncmp
(device_info.udi_devnames[0], "ugen", 4) != 0)
continue;
id.type = IFD_DEVICE_TYPE_USB;
id.num = 2;
id.val[0] = device_info.udi_vendorNo;
id.val[1] = device_info.udi_productNo;
ifd_debug(1, "BSD: ifd_scan_usb: "
"ifd_driver_for(%s[0x%04x].%s[0x%04x)",
device_info.udi_vendor,
device_info.udi_vendorNo,
device_info.udi_product,
device_info.udi_productNo);
/* FIXME: if we don't find a driver with vendor/product
* then check for the interface type (ccid) and use
* driver ccid... */
if (!(driver = ifd_driver_for_id(&id)))
continue;
snprintf(typedev, sizeof(typedev),
"usb:/dev/%s", device_info.udi_devnames[0]);
ifd_spawn_handler(driver, typedev, -1);
}
close(controller_fd);
}
#endif /* ENABLE_LIBUSB */
return 0;
}
#endif /* __Net/Free/OpenBSD__ */
openct-0.6.20/src/ifd/ifd-smph.c 0000644 0001750 0001750 00000023340 10636423304 013217 0000000 0000000 /*
* Driver for SmartMouse/Phoenix readers
*
* Thanks to Alexandre Becoulet and its SCTK project ;)
* In agreement with him, this project's license has been changed to LGPL.
* URL: http://freshmeat.net/projects/sctk/
*
* 2005, Antoine Nguyen
*/
#include "internal.h"
#include
#include
#include
#include
#include
#include
#include
#include
#define PHS_CONV_DIRECT 0
#define PHS_CONV_INDIRECT 1
#define TIMEOUT 1000
/* table for indirect to direct byte mode conversion */
static const uint8_t dir_conv_table[0x100] =
{
0xff, 0x7f, 0xbf, 0x3f, 0xdf, 0x5f, 0x9f, 0x1f,
0xef, 0x6f, 0xaf, 0x2f, 0xcf, 0x4f, 0x8f, 0xf,
0xf7, 0x77, 0xb7, 0x37, 0xd7, 0x57, 0x97, 0x17,
0xe7, 0x67, 0xa7, 0x27, 0xc7, 0x47, 0x87, 0x7,
0xfb, 0x7b, 0xbb, 0x3b, 0xdb, 0x5b, 0x9b, 0x1b,
0xeb, 0x6b, 0xab, 0x2b, 0xcb, 0x4b, 0x8b, 0xb,
0xf3, 0x73, 0xb3, 0x33, 0xd3, 0x53, 0x93, 0x13,
0xe3, 0x63, 0xa3, 0x23, 0xc3, 0x43, 0x83, 0x3,
0xfd, 0x7d, 0xbd, 0x3d, 0xdd, 0x5d, 0x9d, 0x1d,
0xed, 0x6d, 0xad, 0x2d, 0xcd, 0x4d, 0x8d, 0xd,
0xf5, 0x75, 0xb5, 0x35, 0xd5, 0x55, 0x95, 0x15,
0xe5, 0x65, 0xa5, 0x25, 0xc5, 0x45, 0x85, 0x5,
0xf9, 0x79, 0xb9, 0x39, 0xd9, 0x59, 0x99, 0x19,
0xe9, 0x69, 0xa9, 0x29, 0xc9, 0x49, 0x89, 0x9,
0xf1, 0x71, 0xb1, 0x31, 0xd1, 0x51, 0x91, 0x11,
0xe1, 0x61, 0xa1, 0x21, 0xc1, 0x41, 0x81, 0x1,
0xfe, 0x7e, 0xbe, 0x3e, 0xde, 0x5e, 0x9e, 0x1e,
0xee, 0x6e, 0xae, 0x2e, 0xce, 0x4e, 0x8e, 0xe,
0xf6, 0x76, 0xb6, 0x36, 0xd6, 0x56, 0x96, 0x16,
0xe6, 0x66, 0xa6, 0x26, 0xc6, 0x46, 0x86, 0x6,
0xfa, 0x7a, 0xba, 0x3a, 0xda, 0x5a, 0x9a, 0x1a,
0xea, 0x6a, 0xaa, 0x2a, 0xca, 0x4a, 0x8a, 0xa,
0xf2, 0x72, 0xb2, 0x32, 0xd2, 0x52, 0x92, 0x12,
0xe2, 0x62, 0xa2, 0x22, 0xc2, 0x42, 0x82, 0x2,
0xfc, 0x7c, 0xbc, 0x3c, 0xdc, 0x5c, 0x9c, 0x1c,
0xec, 0x6c, 0xac, 0x2c, 0xcc, 0x4c, 0x8c, 0xc,
0xf4, 0x74, 0xb4, 0x34, 0xd4, 0x54, 0x94, 0x14,
0xe4, 0x64, 0xa4, 0x24, 0xc4, 0x44, 0x84, 0x4,
0xf8, 0x78, 0xb8, 0x38, 0xd8, 0x58, 0x98, 0x18,
0xe8, 0x68, 0xa8, 0x28, 0xc8, 0x48, 0x88, 0x8,
0xf0, 0x70, 0xb0, 0x30, 0xd0, 0x50, 0x90, 0x10,
0xe0, 0x60, 0xa0, 0x20, 0xc0, 0x40, 0x80, 0x0
};
enum prot_e
{
prot_phoenix, /* phoenix smartcard interface */
prot_smartmouse, /* smartmouse smartcard interface */
};
typedef struct smph_priv
{
enum prot_e prot;
unsigned int mode;
} smph_priv_t;
static int smph_card_reset(ifd_reader_t *, int, void *, size_t);
static int smph_recv(ifd_reader_t *, unsigned int, unsigned char *, size_t, long);
/*
* Common functions
*/
static int smph_setctrl(ifd_device_t *dev, const int ctrl)
{
int tmp;
if (ioctl(dev->fd, TIOCMGET, &tmp) == -1)
return -1;
tmp &= ~(TIOCM_RTS | TIOCM_CTS | TIOCM_DTR);
tmp |= ctrl;
return (ioctl(dev->fd, TIOCMSET, &tmp));
}
/*
* Initialize the reader
*/
static int _smph_open(ifd_reader_t *reader, const char *device_name,
smph_priv_t *privd)
{
ifd_device_params_t params;
ifd_device_t *dev;
reader->nslots = 1;
if (!(dev = ifd_device_open(device_name)))
return -1;
reader->device = dev;
if (dev->type == IFD_DEVICE_TYPE_SERIAL)
{
if (ifd_device_get_parameters(dev, ¶ms) < 0)
return -1;
params.serial.speed = 9600;
params.serial.bits = 8;
params.serial.stopbits = 1;
params.serial.parity = IFD_SERIAL_PARITY_NONE;
params.serial.dtr = 1;
params.serial.rts = 1;
if (ifd_device_set_parameters(dev, ¶ms) < 0)
return -1;
}
dev->user_data = (void *)privd;
dev->timeout = TIMEOUT;
return 0;
}
static int phx_open(ifd_reader_t * reader, const char *device_name)
{
smph_priv_t *privd = NULL;
ifd_debug(1, "device=%s", device_name);
reader->name = "Phoenix reader";
if (!(privd = (smph_priv_t *)malloc(sizeof (smph_priv_t))))
{
ct_error("out of memory");
return IFD_ERROR_NO_MEMORY;
}
privd->mode = PHS_CONV_DIRECT;
privd->prot = prot_phoenix;
return _smph_open(reader, device_name, privd);
}
static int smtm_open(ifd_reader_t * reader, const char *device_name)
{
smph_priv_t *privd = NULL;
ifd_debug(1, "device=%s", device_name);
reader->name = "SmartMouse reader";
if (!(privd = (smph_priv_t *)malloc(sizeof (smph_priv_t))))
{
ct_error("out of memory");
return IFD_ERROR_NO_MEMORY;
}
privd->mode = PHS_CONV_DIRECT;
privd->prot = prot_smartmouse;
return _smph_open(reader, device_name, privd);
}
/*
* Change the parity
*/
static int smph_change_parity(ifd_reader_t *reader, int parity)
{
ifd_device_t *dev = reader->device;
ifd_device_params_t params;
if (dev->type != IFD_DEVICE_TYPE_SERIAL)
return IFD_ERROR_NOT_SUPPORTED;
if (ifd_device_get_parameters(dev, ¶ms) < 0)
return -1;
params.serial.parity = parity;
return ifd_device_set_parameters(dev, ¶ms);
}
/*
* Activate the reader
*/
static int smph_activate(ifd_reader_t * reader)
{
ifd_device_t *dev = reader->device;
smph_priv_t *privd = (smph_priv_t *)dev->user_data;
int tmp;
uint8_t mode;
if (smph_card_reset(reader, 0, &mode, 1) < 0)
return -1;
ifd_debug(1, "Mode received: 0x%x\n", mode);
switch (mode)
{
case 0x03:
privd->mode = PHS_CONV_INDIRECT;
tmp = IFD_SERIAL_PARITY_ODD;
break;
case 0x3B:
privd->mode = PHS_CONV_DIRECT;
tmp = IFD_SERIAL_PARITY_EVEN;
break;
default:
return -1;
}
smph_change_parity(reader, tmp);
return 0;
}
static int smph_deactivate(ifd_reader_t * reader)
{
ifd_device_t *dev = reader->device;
tcflush(dev->fd, TCIOFLUSH);
if (smph_setctrl(dev, TIOCM_CTS))
return -1;
return 0;
}
/*
* Check card status
*/
static int smph_card_status(ifd_reader_t * reader, int slot, int *status)
{
ifd_device_t *dev = reader->device;
int tmp;
if (slot)
{
ct_error("smph: bad slot index %u", slot);
return IFD_ERROR_INVALID_SLOT;
}
tcflush(dev->fd, TCIOFLUSH);
if (ioctl(dev->fd, TIOCMGET, &tmp) < 0)
return -1;
*status = 0;
*status |= ((tmp & TIOCM_CTS) != TIOCM_CTS) ? IFD_CARD_PRESENT : 0;
return 0;
}
/*
* Reset the card and get the ATR
*/
static int smph_card_reset(ifd_reader_t *reader, int slot, void *atr,
size_t size)
{
ifd_device_t *dev = reader->device;
smph_priv_t *privd = dev->user_data;
int res;
if (slot)
{
ct_error("%s: bad slot index %u",
(privd->prot == prot_phoenix) ? "phoenix" : "smartmouse", slot);
return IFD_ERROR_INVALID_SLOT;
}
tcflush(dev->fd, TCIOFLUSH);
if (smph_setctrl(dev, (privd->prot == prot_phoenix)
? TIOCM_RTS | TIOCM_CTS | TIOCM_DTR
: TIOCM_CTS | TIOCM_DTR) < 0)
return -1;
/* FIXME: use ifd_serial_reset instead? */
sleep(1);
if (smph_setctrl(dev, (privd->prot == prot_phoenix)
? TIOCM_CTS | TIOCM_DTR :
TIOCM_RTS | TIOCM_CTS | TIOCM_DTR) < 0)
return -1;
/* FIXME: use ifd_serial_reset instead? */
usleep(200);
if ((res = smph_recv(reader, 0, (unsigned char *)atr, size, dev->timeout)) < 1)
return -1;
ifd_debug(1, "Bytes received %i\n", res);
return res;
}
/*
* Send command to IFD
*/
static int _smph_send(ifd_device_t *dev, const unsigned char *buffer,
size_t len)
{
unsigned char tmp;
unsigned int i;
struct pollfd pfd;
ifd_debug(3, "data:%s", ct_hexdump(buffer, len));
for (i = 0; i < len; i++)
{
if (write(dev->fd, buffer + i, 1) < 1)
return -1;
tcdrain(dev->fd);
}
for (i = 0; i < len; i++)
{
pfd.fd = dev->fd;
pfd.events = POLLIN;
if (poll(&pfd, 1, dev->timeout) < 1)
return -1;
if (read(dev->fd, &tmp, 1) < 1)
return -1;
if (tmp != *(buffer + i))
return -1;
}
return 0;
}
static int smph_send(ifd_reader_t * reader, unsigned int dad,
const unsigned char *buffer, size_t len)
{
smph_priv_t *privd;
ifd_device_t *dev = reader->device;
uint8_t *fbuff = NULL;
int i;
if (!dev)
return -1;
privd = (smph_priv_t *)dev->user_data;
if (privd->mode == PHS_CONV_INDIRECT)
{
if (!(fbuff = (uint8_t *)malloc(len * sizeof (uint8_t))))
{
ct_error("out of memory");
return IFD_ERROR_NO_MEMORY;
}
for (i = 0; i < len; i++)
fbuff[i] = dir_conv_table[buffer[i]];
i = _smph_send(dev, fbuff, len);
free(fbuff);
return i;
}
return _smph_send(dev, buffer, len);
}
/*
* Receive data from IFD
*/
static int smph_recv(ifd_reader_t * reader, unsigned int dad,
unsigned char *buffer, size_t len, long timeout)
{
ifd_device_t *dev = reader->device;
smph_priv_t *privd;
int n;
int i;
for (i = 0; i < len; i++)
{
n = ifd_device_recv(dev, buffer + i, 1, timeout);
if (n == IFD_ERROR_TIMEOUT)
break;
if (n == -1)
return -1;
}
privd = (smph_priv_t *)dev->user_data;
if (privd->mode == PHS_CONV_INDIRECT)
for (i = 0; i < len; i++)
buffer[i] = dir_conv_table[buffer[i]];
ifd_debug(3, "data:%s", ct_hexdump(buffer, len));
return i;
}
/*
* Driver operations
*/
static struct ifd_driver_ops phx_driver;
static struct ifd_driver_ops smtm_driver;
void ifd_smph_register(void)
{
phx_driver.open = phx_open;
//smph_driver.change_parity = smph_change_parity;
phx_driver.activate = smph_activate;
phx_driver.deactivate = smph_deactivate;
phx_driver.card_status = smph_card_status;
phx_driver.card_reset = smph_card_reset;
phx_driver.send = smph_send;
phx_driver.recv = smph_recv;
ifd_driver_register("phoenix", &phx_driver);
smtm_driver.open = smtm_open;
//smph_driver.change_parity = smph_change_parity;
smtm_driver.activate = smph_activate;
smtm_driver.deactivate = smph_deactivate;
smtm_driver.card_status = smph_card_status;
smtm_driver.card_reset = smph_card_reset;
smtm_driver.send = smph_send;
smtm_driver.recv = smph_recv;
ifd_driver_register("smartmouse", &smtm_driver);
}
openct-0.6.20/src/ifd/proto-trans.c 0000644 0001750 0001750 00000003063 10422076714 014002 0000000 0000000 /*
* Transparent protocol - simply pass everything to the reader driver
*
* Copyright (C) 2003, Olaf Kirch
*/
#include "internal.h"
#include
#include
#include
/*
* Attach t0 protocol
*/
static int trans_init(ifd_protocol_t * prot)
{
ifd_reader_t *reader = prot->reader;
const ifd_driver_t *drv;
if (!reader || !(drv = reader->driver)
|| !drv->ops || !drv->ops->transparent)
return -1;
return 0;
}
/*
* Detach t0 protocol
*/
static void trans_release(ifd_protocol_t * prot)
{
/* NOP */
}
/*
* Get/set parmaters for T1 protocol
*/
static int trans_set_param(ifd_protocol_t * prot, int type, long value)
{
ct_error("set_pameter not supported");
return -1;
}
static int trans_get_param(ifd_protocol_t * prot, int type, long *result)
{
ct_error("get_pameter not supported");
return -1;
}
/*
* Transceive an APDU
*/
static int trans_transceive(ifd_protocol_t * prot, int dad, const void *sbuf,
size_t slen, void *rbuf, size_t rlen)
{
ifd_reader_t *reader = prot->reader;
const ifd_driver_t *drv = reader->driver;
return drv->ops->transparent(reader, dad, sbuf, slen, rbuf, rlen);
}
/*
* Protocol struct
*/
struct ifd_protocol_ops ifd_protocol_trans = {
IFD_PROTOCOL_TRANSPARENT, /* id */
"transparent", /* name */
sizeof(ifd_protocol_t), /* size */
trans_init, /* init */
trans_release, /* release */
trans_set_param, /* set_param */
trans_get_param, /* get_param */
NULL, /* resynchronize */
trans_transceive, /* transceive */
NULL, /* sync_read */
NULL, /* sync_write */
};
openct-0.6.20/src/ifd/proto-escape.c 0000644 0001750 0001750 00000003525 10625650421 014114 0000000 0000000 /*
* Escape protocol - simply pass everything to the reader driver's escape()
*
* This is required for exporting access to vendor-specific CCID extensions,
* such as the Omnikey CardMan 5121 RFID support.
*
* The higher-level applications select a virtual slot (the last available slot
* number). This virtual slot will automatically get the IFD_PROTOCOL_ESCAPE
* assgigned to it and can then be used to transceive() data to/from the CCID.
*
* It's a bit ugly, but I was unable to come up with something cleaner.
*
* Copyright (C) 2005, Harald Welte
*/
#include "internal.h"
#include
#include
#include
static int escape_init(ifd_protocol_t * prot)
{
ifd_reader_t *reader = prot->reader;
const ifd_driver_t *drv;
if (!reader || !(drv = reader->driver)
|| !drv->ops || !drv->ops->escape)
return -1;
return 0;
}
static void escape_release(ifd_protocol_t * prot)
{
/* NOP */
}
static int escape_set_param(ifd_protocol_t * prot, int type, long value)
{
ct_error("set_pameter not supported");
return -1;
}
static int escape_get_param(ifd_protocol_t * prot, int type, long *result)
{
ct_error("get_pameter not supported");
return -1;
}
static int
escape_transceive(ifd_protocol_t * prot, int dad,
const void *sbuf, size_t slen, void *rbuf, size_t rlen)
{
ifd_reader_t *reader = prot->reader;
const ifd_driver_t *drv = reader->driver;
return drv->ops->escape(reader, dad, sbuf, slen, rbuf, rlen);
}
struct ifd_protocol_ops ifd_protocol_esc = {
IFD_PROTOCOL_ESCAPE, /* id */
"escape", /* name */
sizeof(ifd_protocol_t), /* size */
escape_init, /* init */
escape_release, /* release */
escape_set_param, /* set_param */
escape_get_param, /* get_param */
NULL, /* resynchronize */
escape_transceive, /* transceive */
NULL, /* sync_read */
NULL, /* sync_write */
};
openct-0.6.20/src/ifd/protocol.c 0000644 0001750 0001750 00000012503 10422076714 013352 0000000 0000000 /*
* Protocol selection
*
* Copyright (C) 2003, Olaf Kirch
*/
#include "internal.h"
#include
#include
struct ifd_protocol_info {
struct ifd_protocol_info *next;
struct ifd_protocol_ops *ops;
};
static struct ifd_protocol_info *list = NULL;
/*
* Register a protocol
*/
int ifd_protocol_register(struct ifd_protocol_ops *ops)
{
struct ifd_protocol_info *info, **ptr;
info = (struct ifd_protocol_info *)calloc(1, sizeof(*info));
if (!info) {
ct_error("out of memory");
return IFD_ERROR_NO_MEMORY;
}
info->ops = ops;
for (ptr = &list; *ptr; ptr = &(*ptr)->next) ;
*ptr = info;
return 0;
}
/*
* Look up protocol based on its ID
*/
static struct ifd_protocol_ops *ifd_protocol_by_id(int id)
{
struct ifd_protocol_info *info;
for (info = list; info; info = info->next) {
if (info->ops->id == id)
return info->ops;
}
/* Autoload protocols defined in external modules? */
return NULL;
}
/*
* Select a protocol
*/
ifd_protocol_t *ifd_protocol_select(ifd_reader_t * reader, int nslot,
int preferred)
{
const ifd_driver_t *drv;
ifd_slot_t *slot = &reader->slot[nslot];
unsigned char *atr, TDi;
unsigned int supported = 0;
int def_proto = -1, n, len;
ifd_debug(1, "atr=%s", ct_hexdump(slot->atr, slot->atr_len));
/* FIXME: use ifd_atr_parse() instead */
atr = slot->atr;
len = slot->atr_len;
if (len < 2)
return NULL;
/* Ignore hysterical bytes */
len -= atr[1] & 0x0f;
n = 2;
do {
int prot;
TDi = atr[n - 1];
if (n != 2) {
prot = TDi & 0x0f;
supported |= (1 << prot);
if (def_proto < 0)
def_proto = prot;
}
n += ifd_count_bits(TDi & 0xF0);
} while (n < len && (TDi & 0x80));
if (supported == 0)
supported |= 0x01;
if (def_proto < 0)
def_proto = IFD_PROTOCOL_T0;
ifd_debug(1, "default T=%d, supported protocols=0x%x",
def_proto, supported);
if (preferred >= 0
&& preferred != def_proto && (supported & (1 << preferred))) {
/* XXX perform PTS */
ifd_debug(1, "protocol selection not supported");
}
if ((drv = reader->driver) && drv->ops && drv->ops->set_protocol) {
if (drv->ops->set_protocol(reader, nslot, def_proto) < 0)
return NULL;
} else {
slot->proto = ifd_protocol_new(def_proto, reader, slot->dad);
}
return slot->proto;
}
/*
* Force the protocol driver to resynchronize
*/
int ifd_protocol_resynchronize(ifd_protocol_t * p, int nad)
{
ifd_debug(1, "called.");
if (!p || !p->ops || !p->ops->resynchronize)
return IFD_ERROR_NOT_SUPPORTED;
return p->ops->resynchronize(p, nad);
}
/*
* Protocol transceive
*/
int ifd_protocol_transceive(ifd_protocol_t * p, int dad, const void *sbuf,
size_t slen, void *rbuf, size_t rlen)
{
int rc;
if (!p || !p->ops || !p->ops->transceive)
return IFD_ERROR_NOT_SUPPORTED;
ifd_debug(1, "cmd: %s", ct_hexdump(sbuf, slen));
rc = p->ops->transceive(p, dad, sbuf, slen, rbuf, rlen);
if (rc >= 0)
ifd_debug(1, "resp:%s", ct_hexdump(rbuf, rc));
else
ifd_debug(1, "transceive error: %s", ct_strerror(rc));
return rc;
}
/*
* Read/write synchronous ICCs
*/
int ifd_protocol_read_memory(ifd_protocol_t * p, int slot, unsigned short addr,
unsigned char *rbuf, size_t rlen)
{
int rc;
if (!p || !p->ops || !p->ops->sync_read)
return IFD_ERROR_NOT_SUPPORTED;
ifd_debug(1, "read %u@%04x (%s)", (unsigned int)rlen, addr,
p->ops->name);
rc = p->ops->sync_read(p, slot, addr, rbuf, rlen);
if (rc >= 0)
ifd_debug(1, "resp:%s", ct_hexdump(rbuf, rc));
return rc;
}
int ifd_protocol_write_memory(ifd_protocol_t * p, int slot, unsigned short addr,
const unsigned char *sbuf, size_t slen)
{
int rc;
if (!p || !p->ops || !p->ops->sync_write)
return IFD_ERROR_NOT_SUPPORTED;
ifd_debug(1, "write %u@%04x (%s):%s",
(unsigned int)slen, addr,
p->ops->name, ct_hexdump(sbuf, slen));
rc = p->ops->sync_write(p, slot, addr, sbuf, slen);
ifd_debug(1, "resp = %d", rc);
return rc;
}
/*
* Create new protocol object
*/
ifd_protocol_t *ifd_protocol_new(int id, ifd_reader_t * reader,
unsigned int dad)
{
struct ifd_protocol_ops *ops;
ifd_protocol_t *p;
if (reader == NULL)
return NULL;
if (!(ops = ifd_protocol_by_id(id))) {
ct_error("unknown protocol id %d", id);
return NULL;
}
p = (ifd_protocol_t *) calloc(1, ops->size);
if (!p) {
ct_error("out of memory");
return p;
}
p->reader = reader;
p->ops = ops;
p->dad = dad;
if (ops->init && ops->init(p) < 0) {
ct_error("Protocol initialization failed");
ifd_protocol_free(p);
return NULL;
}
return p;
}
/*
* Set a protocol specific parameter
*/
int ifd_protocol_set_parameter(ifd_protocol_t * p, int type, long value)
{
if (!p || !p->ops || !p->ops->set_param)
return -1;
return p->ops->set_param(p, type, value);
}
int ifd_protocol_get_parameter(ifd_protocol_t * p, int type, long *value)
{
if (!p || !p->ops || !p->ops->get_param)
return -1;
return p->ops->get_param(p, type, value);
}
/*
* Free protocol object
*/
void ifd_protocol_free(ifd_protocol_t * p)
{
if (p->ops) {
if (p->ops->release)
p->ops->release(p);
memset(p, 0, p->ops->size);
} else {
memset(p, 0, sizeof(*p));
}
free(p);
}
/*
* List available protocols
*/
unsigned int ifd_protocols_list(const char **names, unsigned int max)
{
struct ifd_protocol_info *info;
unsigned int n;
for (info = list, n = 0; info && n < max; info = info->next, n++) {
names[n] = info->ops->name;
}
return n;
}
openct-0.6.20/src/ifd/device.c 0000644 0001750 0001750 00000011644 11151454644 012757 0000000 0000000 /*
* Generic IFD device layer
*
* Copyright (C) 2003 Olaf Kirch
*/
#include "internal.h"
#include
#include
/*
* Open a device given the name
*/
ifd_device_t *ifd_device_open(const char *name)
{
if (name == NULL) {
ct_error("Null device");
return NULL;
}
if (!strncmp(name, "serial:", 7))
return ifd_open_serial(name + 7);
if (!strncmp(name, "usb:", 4))
return ifd_open_usb(name + 4);
if (!strncmp(name, "remote:", 7))
return ifd_open_remote(name + 7);
if (!strncmp(name, "pcmcia:", 7))
return ifd_open_pcmcia(name + 7);
if (!strncmp(name, "pcmcia_block:", 13))
return ifd_open_pcmcia_block(name + 13);
ct_error("Unknown device type \"%s\"", name);
return NULL;
}
/*
* Create a new device struct
* This is an internal function called by the different device
* type handlers (serial, usb, etc)
*/
ifd_device_t *ifd_device_new(const char *name, struct ifd_device_ops * ops,
size_t size)
{
ifd_device_t *dev;
dev = (ifd_device_t *) calloc(1, size);
if (!dev) {
ct_error("out of memory");
return NULL;
}
dev->name = strdup(name);
dev->ops = ops;
return dev;
}
/*
* Destroy a device handle
*/
void ifd_device_free(ifd_device_t * dev)
{
if (dev->name)
free(dev->name);
memset(dev, 0, sizeof(*dev));
free(dev);
}
/*
* Miscellaneous device operations. These functions
* just do a consistency check on the handle, and route
* the call to the appropriate member function
*/
int ifd_device_type(ifd_device_t * dev)
{
return dev->type;
}
int ifd_device_reset(ifd_device_t * dev)
{
if (!dev || !dev->ops || !dev->ops->reset)
return IFD_ERROR_NOT_SUPPORTED;
return dev->ops->reset(dev);
}
void ifd_device_set_hotplug(ifd_device_t * dev, int hotplug)
{
if (hotplug)
dev->hotplug = 1;
}
int ifd_device_set_parameters(ifd_device_t * dev,
const ifd_device_params_t * parms)
{
if (!dev || !dev->ops || !dev->ops->set_params)
return IFD_ERROR_NOT_SUPPORTED;
return dev->ops->set_params(dev, parms);
}
int ifd_device_get_parameters(ifd_device_t * dev, ifd_device_params_t * parms)
{
if (!dev || !dev->ops || !dev->ops->get_params)
return IFD_ERROR_NOT_SUPPORTED;
return dev->ops->get_params(dev, parms);
}
void ifd_device_flush(ifd_device_t * dev)
{
if (!dev || !dev->ops || !dev->ops->flush)
return;
dev->ops->flush(dev);
}
void ifd_device_send_break(ifd_device_t * dev, unsigned int usec)
{
if (!dev || !dev->ops || !dev->ops->send_break)
return;
dev->ops->send_break(dev, usec);
}
int ifd_device_send(ifd_device_t * dev, const unsigned char *data, size_t len)
{
if (!dev || !dev->ops || !dev->ops->send)
return IFD_ERROR_NOT_SUPPORTED;
return dev->ops->send(dev, data, len);
}
int ifd_device_control(ifd_device_t * dev, void *cmsg, size_t len)
{
if (!dev || !dev->ops || !dev->ops->control)
return IFD_ERROR_NOT_SUPPORTED;
return dev->ops->control(dev, cmsg, len);
}
int ifd_device_recv(ifd_device_t * dev, unsigned char *data, size_t len,
long timeout)
{
if (timeout < 0)
timeout = dev->timeout;
if (!dev || !dev->ops || !dev->ops->recv)
return IFD_ERROR_NOT_SUPPORTED;
return dev->ops->recv(dev, data, len, timeout);
}
int ifd_device_transceive(ifd_device_t * dev, const void *sbuf, size_t slen,
void *rbuf, size_t rlen, long timeout)
{
int rc;
if (timeout < 0)
timeout = dev->timeout;
if (!dev || !dev->ops)
return -1;
if (dev->ops->transceive)
return dev->ops->transceive(dev,
sbuf, slen, rbuf, rlen, timeout);
/* Fall back to send/recv */
ifd_device_flush(dev);
if ((rc = ifd_device_send(dev, (const unsigned char *)sbuf, slen)) < 0)
return rc;
return ifd_device_recv(dev, (unsigned char *)rbuf, rlen, timeout);
}
int ifd_device_poll_presence(ifd_device_t * dev, struct pollfd *pfd)
{
if (!dev || !dev->ops || !dev->ops->poll_presence)
return 1;
return dev->ops->poll_presence(dev, pfd);
}
int ifd_device_get_eventfd(ifd_device_t * dev, short *events)
{
if (!dev || !dev->ops)
return -1;
if (!dev->ops->get_eventfd)
return -1;
return dev->ops->get_eventfd(dev, events);
}
void ifd_device_close(ifd_device_t * dev)
{
if (!dev)
return;
if (dev->ops && dev->ops->close)
dev->ops->close(dev);
ifd_device_free(dev);
}
/*
* Device ID handling
*/
int ifd_device_id_parse(const char *str, ifd_devid_t * id)
{
unsigned int n;
id->type = IFD_DEVICE_TYPE_OTHER;
n = strcspn(str, ":");
if (str[n] == ':') {
if (!strncmp(str, "usb", n))
id->type = IFD_DEVICE_TYPE_USB;
else if (!strncmp(str, "pcmcia", n))
id->type = IFD_DEVICE_TYPE_PCMCIA;
else
return -1;
str += n + 1;
}
for (n = 0; *str && n < IFD_MAX_DEVID_PARTS; n++) {
id->val[n] = strtoul(str, (char **)&str, 16);
if (*str == '/')
str++;
}
if (*str || n == 0)
return -1;
id->num = n;
return 0;
}
int ifd_device_id_match(const ifd_devid_t * match, const ifd_devid_t * id)
{
if (id->type != match->type
|| id->num < match->num
|| memcmp(id->val, match->val, match->num * sizeof(id->val[0])))
return 0;
return 1;
}
openct-0.6.20/src/ifd/ria-server.c 0000644 0001750 0001750 00000017253 10625650421 013575 0000000 0000000 /*
* Remote device access - debugging utility that allows to
* test smart card readers on remote hosts.
*
* Copyright (C) 2003, Olaf Kirch
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "internal.h"
#include "ria.h"
typedef struct ria_peer {
struct ria_peer *next;
struct ria_peer *prev;
ct_socket_t *sock;
struct ria_peer *peer;
ria_device_t device;
} ria_peer_t;
static unsigned int dev_handle = 1;
static ria_peer_t clients = { &clients, &clients };
static int ria_svc_accept(ct_socket_t *);
static int ria_svc_app_handler(ct_socket_t *, header_t *,
ct_buf_t *, ct_buf_t *);
static int ria_svc_dev_handler(ct_socket_t *, header_t *,
ct_buf_t *, ct_buf_t *);
static void ria_svc_app_close(ct_socket_t *);
static void ria_svc_dev_close(ct_socket_t *);
static ria_peer_t *ria_peer_new(ct_socket_t *);
static void ria_peer_free(ria_peer_t *, int);
static ria_peer_t *ria_find_device(const char *, size_t);
static void ria_svc_link(ria_peer_t *);
static void ria_svc_unlink(ria_peer_t *);
int ria_svc_listen(const char *address, int trusted)
{
ct_socket_t *sock;
int rc;
sock = ct_socket_new(1024);
if ((rc = ct_socket_listen(sock, address, 0666)) < 0) {
ct_error("Cannot bind to network address \"%s\"\n", address);
ct_socket_free(sock);
return rc;
}
sock->recv = ria_svc_accept;
sock->send = NULL;
if (trusted) {
sock->process = ria_svc_app_handler;
sock->close = ria_svc_app_close;
} else {
sock->process = ria_svc_dev_handler;
sock->close = ria_svc_dev_close;
}
ct_mainloop_add_socket(sock);
return 0;
}
static int ria_svc_accept(ct_socket_t * listener)
{
ria_peer_t *clnt;
ct_socket_t *sock;
int rc;
if (!(sock = ct_socket_accept(listener)))
return 0;
clnt = ria_peer_new(sock);
rc = ct_socket_getpeername(sock,
clnt->device.address,
sizeof(clnt->device.address));
if (rc < 0) {
ria_peer_free(clnt, 0);
return rc;
}
ifd_debug(1, "New connection from %s", clnt->device.address);
sock->user_data = clnt;
sock->process = listener->process;
sock->close = listener->close;
return 0;
}
static void ria_svc_app_close(ct_socket_t * sock)
{
ria_peer_t *clnt = (ria_peer_t *) sock->user_data;
ifd_debug(1, "Application on %s closed connection",
clnt->device.address);
ria_peer_free((ria_peer_t *) sock->user_data, 0);
}
static void ria_svc_dev_close(ct_socket_t * sock)
{
ria_peer_t *clnt = (ria_peer_t *) sock->user_data;
ifd_debug(1, "Device on %s closed connection", clnt->device.address);
ria_peer_free((ria_peer_t *) sock->user_data, 1);
}
/*
* Process commands from local clients (i.e. those allowed
* to claim a device).
*/
static int ria_svc_app_handler(ct_socket_t * sock, header_t * hdr,
ct_buf_t * args, ct_buf_t * resp)
{
unsigned char cmd;
ria_peer_t *clnt, *peer;
int rc;
clnt = (ria_peer_t *) sock->user_data;
ria_print_packet(sock, 2, "app >>", hdr, args);
if (ct_buf_get(args, &cmd, 1) < 0)
return IFD_ERROR_INVALID_MSG;
switch (cmd) {
case RIA_MGR_LIST:
peer = &clients;
ifd_debug(1, "%s requests a device listing",
clnt->device.address);
while ((peer = peer->next) != &clients) {
if (peer->device.name[0] != '\0')
ct_buf_put(resp, &peer->device,
sizeof(peer->device));
}
return 0;
case RIA_MGR_INFO:
peer =
ria_find_device((const char *)ct_buf_head(args),
ct_buf_avail(args));
if (peer == NULL)
return IFD_ERROR_UNKNOWN_DEVICE;
ct_buf_put(resp, &peer->device, sizeof(peer->device));
return 0;
case RIA_MGR_CLAIM:
peer =
ria_find_device((const char *)ct_buf_head(args),
ct_buf_avail(args));
if (peer == NULL)
return IFD_ERROR_UNKNOWN_DEVICE;
if (peer->peer)
return IFD_ERROR_DEVICE_BUSY;
ifd_debug(1, "%s claimed %s device %s/%s",
clnt->device.address,
peer->device.type,
peer->device.address, peer->device.name);
ct_buf_put(resp, &peer->device, sizeof(peer->device));
clnt->peer = peer;
peer->peer = clnt;
return 0;
}
if (cmd < __RIA_PEER_CMD_BASE)
return IFD_ERROR_INVALID_CMD;
/* All subsequent commands require a device */
if ((peer = clnt->peer) == NULL)
return IFD_ERROR_NOT_CONNECTED;
/* Push back the command byte */
ct_buf_push(args, &cmd, 1);
rc = ct_socket_put_packet(peer->sock, hdr, args);
/* Tell the caller not to send a response */
hdr->xid = 0;
return rc;
}
/*
* Process commands from remote clients (i.e. those offering a device).
*/
static int ria_svc_dev_handler(ct_socket_t * sock, header_t * hdr,
ct_buf_t * args, ct_buf_t * resp)
{
unsigned char cmd;
ria_peer_t *clnt, *peer;
ria_device_t devinfo;
int rc;
clnt = (ria_peer_t *) sock->user_data;
ria_print_packet(sock, 2, "dev <<", hdr, args);
/* bounce response to peer right away */
if (hdr->dest)
goto bounce_to_peer;
if (ct_buf_get(args, &cmd, 1) < 0)
return IFD_ERROR_INVALID_MSG;
switch (cmd) {
case RIA_MGR_REGISTER:
if (clnt->device.name[0])
return IFD_ERROR_INVALID_ARG;
if ((rc = ct_buf_get(args, &devinfo, sizeof(devinfo))) < 0)
return IFD_ERROR_INVALID_ARG;
if (devinfo.type[0] == '\0')
return IFD_ERROR_INVALID_ARG;
/* For security reasons, don't allow the handle counter
* to wrap around. */
if (dev_handle == 0)
return IFD_ERROR_GENERIC;
memcpy(&devinfo.address, clnt->device.address, RIA_NAME_MAX);
clnt->device = devinfo;
snprintf(clnt->device.handle, RIA_NAME_MAX,
"%s%u", clnt->device.type, dev_handle++);
ifd_debug(1,
"%s registered new %s device , handle '%s', name `%s'",
clnt->device.address, clnt->device.type,
clnt->device.handle, clnt->device.name);
return 0;
}
if (cmd < __RIA_PEER_CMD_BASE)
return IFD_ERROR_INVALID_CMD;
/* Push back the command byte */
ct_buf_push(args, &cmd, 1);
bounce_to_peer:
if ((peer = clnt->peer) == NULL)
return IFD_ERROR_NOT_CONNECTED;
rc = ct_socket_put_packet(peer->sock, hdr, args);
/* Tell the caller not to send a response */
hdr->xid = 0;
return rc;
}
static ria_peer_t *ria_peer_new(ct_socket_t * sock)
{
ria_peer_t *clnt;
clnt = (ria_peer_t *) calloc(1, sizeof(ria_peer_t));
if (!clnt) {
ct_error("out of memory");
return NULL;
}
clnt->sock = sock;
ria_svc_link(clnt);
return clnt;
}
static void ria_peer_free(ria_peer_t * clnt, int detach_peer)
{
ria_peer_t *peer;
if ((peer = clnt->peer) != NULL) {
if (detach_peer)
shutdown(peer->sock->fd, SHUT_RD);
peer->peer = NULL;
}
if (clnt->device.name[0])
ifd_debug(1, "Removing device `%s' on %s",
clnt->device.name, clnt->device.address);
ria_svc_unlink(clnt);
memset(clnt, 0, sizeof(*clnt));
free(clnt);
}
static void ria_svc_link(ria_peer_t * clnt)
{
ria_peer_t *prev;
prev = clients.prev;
clnt->next = &clients;
clnt->prev = prev;
prev->next = clnt;
clients.prev = clnt;
}
static ria_peer_t *ria_find_device(const char *handle, size_t len)
{
ria_peer_t *peer;
ifd_debug(2, "handle=%*.*s", (int)len, (int)len, handle);
if (len == 0 || len > RIA_NAME_MAX - 1)
return NULL;
peer = &clients;
while ((peer = peer->next) != &clients) {
if (!memcmp(peer->device.handle, handle, len)
&& peer->device.handle[len] == '\0')
return peer;
if (!memcmp(peer->device.name, handle, len)
&& peer->device.name[len] == '\0')
return peer;
}
return NULL;
}
static void ria_svc_unlink(ria_peer_t * clnt)
{
ria_peer_t *prev, *next;
prev = clnt->prev;
next = clnt->next;
prev->next = next;
next->prev = prev;
clnt->prev = clnt->next = clnt;
}
openct-0.6.20/src/ifd/ifd-epass3k.c 0000644 0001750 0001750 00000017215 11125447432 013627 0000000 0000000 /*
* OpenCT driver for ePass3000 device
*
* Copyright (C) 2008, EnterSafe
*/
#include "internal.h"
#include
#include
typedef struct {
unsigned char TagH;
unsigned char TagL;
unsigned char CommandH;
unsigned char CommandL;
unsigned char LengthH;
unsigned char LengthL;
unsigned char Value[1];
} epass3k_command_t;
typedef struct {
unsigned char TagH;
unsigned char TagL;
unsigned char StatusH;
unsigned char StatusL;
unsigned char LengthH;
unsigned char LengthL;
unsigned char Value[1];
} epass3k_status_t;
#define TIMEOUT 200000
#define USB_BULK_IN 0x81
#define USB_BULK_OUT 2
#define EPASS3K_COMMAND_SIZE 7
#define EPASS3K_STATUS_SIZE 7
#define TOKEN_TYPE_ID_LENGTH 64
#define EPASS3K_COMMAND_GET_ATR (unsigned char)0X01
#define EPASS3K_COMMAND_TRANSMIT_APDU (unsigned char)0X02
/*
* Initialize the device
*/
static int epass3k_open(ifd_reader_t * reader, const char *device_name)
{
ifd_device_t *dev;
ifd_device_params_t params;
ifd_debug(1, "%s:%d epass3k_open()", __FILE__, __LINE__);
reader->name = "FT SCR2000A"; /* ePass3000 reader name */
reader->nslots = 1;
if (!(dev = ifd_device_open(device_name)))
return -1;
if (ifd_device_type(dev) != IFD_DEVICE_TYPE_USB) {
ct_error("ePass3000: device %s is not a USB device",
device_name);
ifd_device_close(dev);
return -1;
}
params = dev->settings;
params.usb.ep_o = USB_BULK_OUT;
params.usb.ep_i = USB_BULK_IN;
if (ifd_device_set_parameters(dev, ¶ms) < 0) {
ct_error("ePass3000: setting parameters failed", device_name);
ifd_device_close(dev);
return -1;
}
reader->device = dev;
dev->timeout = TIMEOUT;
return 0;
}
static int epass3k_activate(ifd_reader_t * reader)
{
ifd_debug(1, "%s:%d epass3k_activate()", __FILE__, __LINE__);
return 0;
}
static int epass3k_deactivate(ifd_reader_t * reader)
{
ifd_debug(1, "%s:%d epass3k_deactivate()", __FILE__, __LINE__);
return -1;
}
static int epass3k_change_parity(ifd_reader_t * reader, int parity)
{
ifd_debug(1, "%s:%d epass3k_change_parity()", __FILE__, __LINE__);
return 0;
}
static int epass3k_change_speed(ifd_reader_t * reader, unsigned int speed)
{
ifd_debug(1, "%s:%d epass3k_change_speed()", __FILE__, __LINE__);
return 0;
}
static int epass3k_set_protocol(ifd_reader_t * reader, int nslot, int proto)
{
ifd_debug(1, "%s:%d epass3k_set_protocol()", __FILE__, __LINE__);
ifd_protocol_t *protocol;
ifd_slot_t *slot;
if (IFD_PROTOCOL_T0 != proto)
return IFD_ERROR_NOT_SUPPORTED;
slot = &reader->slot[nslot];
slot->proto = ifd_protocol_new(proto, reader, slot->dad);
if (slot->proto == NULL) {
ct_error("acr: unable to create protocol");
return -1;
}
ifd_protocol_set_parameter(slot->proto, IFD_PROTOCOL_BLOCK_ORIENTED, 1);
return 1;
}
static int epass3k_card_reset(ifd_reader_t * reader, int slot, void *atr,
size_t atr_len)
{
int ret;
epass3k_command_t *pepass3k_send = NULL;
epass3k_status_t *pepass3k_receive = NULL;
ifd_debug(1, "%s:%d epass3k_card_reset()", __FILE__, __LINE__);
pepass3k_send = (epass3k_command_t *) malloc(EPASS3K_COMMAND_SIZE);
pepass3k_receive =
(epass3k_status_t *) malloc(EPASS3K_STATUS_SIZE +
TOKEN_TYPE_ID_LENGTH);
if ((NULL == pepass3k_send) || (NULL == pepass3k_receive)) {
return -1;
}
memset(pepass3k_send, 0, EPASS3K_COMMAND_SIZE);
pepass3k_send->TagH = 'R';
pepass3k_send->TagL = '6';
pepass3k_send->CommandH = 0x00;
pepass3k_send->CommandL = EPASS3K_COMMAND_GET_ATR;
pepass3k_send->LengthH = 0x00;
pepass3k_send->LengthL = 0x00;
ret =
ifd_device_send(reader->device, (unsigned char *)pepass3k_send,
EPASS3K_COMMAND_SIZE - 1);
if (ret != EPASS3K_COMMAND_SIZE - 1) {
free(pepass3k_send);
pepass3k_send = NULL;
free(pepass3k_receive);
pepass3k_receive = NULL;
return -1;
}
memset(pepass3k_receive, 0, EPASS3K_STATUS_SIZE + TOKEN_TYPE_ID_LENGTH);
pepass3k_receive->TagH = 'R';
pepass3k_receive->TagL = '6';
pepass3k_receive->LengthH = 0x00;
pepass3k_receive->LengthL = 0x20;
ret =
ifd_device_recv(reader->device, (unsigned char *)pepass3k_receive,
EPASS3K_STATUS_SIZE + TOKEN_TYPE_ID_LENGTH,
TIMEOUT);
if (ret < EPASS3K_STATUS_SIZE) {
free(pepass3k_send);
pepass3k_send = NULL;
free(pepass3k_receive);
pepass3k_receive = NULL;
return -1;
}
if (atr_len <
pepass3k_receive->LengthH * 256 + pepass3k_receive->LengthL - 5) {
free(pepass3k_send);
pepass3k_send = NULL;
free(pepass3k_receive);
pepass3k_receive = NULL;
return -1;
}
if (NULL != atr) {
memcpy(atr, pepass3k_receive->Value + 2,
pepass3k_receive->LengthH * 256 +
pepass3k_receive->LengthL - 5);
}
ret = pepass3k_receive->LengthH * 256 + pepass3k_receive->LengthL - 5;
free(pepass3k_send);
pepass3k_send = NULL;
free(pepass3k_receive);
pepass3k_receive = NULL;
return ret;
}
static int epass3k_card_status(ifd_reader_t * reader, int slot, int *status)
{
ifd_debug(1, "%s:%d epass3k_card_status()", __FILE__, __LINE__);
*status = IFD_CARD_PRESENT;
return 0;
}
static int epass3k_send(ifd_reader_t * reader, unsigned int dad,
const unsigned char *buffer, size_t len)
{
int ret = 0;
ifd_debug(1, "%s:%d epass3k_send()", __FILE__, __LINE__);
epass3k_command_t *pepass3k_send = NULL;
pepass3k_send =
(epass3k_command_t *) malloc(EPASS3K_COMMAND_SIZE + len);
if (NULL == pepass3k_send) {
return -1;
}
memset(pepass3k_send, 0, EPASS3K_COMMAND_SIZE + len);
pepass3k_send->TagH = 'R';
pepass3k_send->TagL = '6';
pepass3k_send->CommandH = 0x00;
pepass3k_send->CommandL = EPASS3K_COMMAND_TRANSMIT_APDU;
pepass3k_send->LengthH = len / 256;
pepass3k_send->LengthL = len % 256;
memcpy(pepass3k_send->Value, buffer, len);
ret =
ifd_device_send(reader->device, (unsigned char *)pepass3k_send,
EPASS3K_COMMAND_SIZE + len - 1);
if (NULL != pepass3k_send) ;
{
free(pepass3k_send);
pepass3k_send = NULL;
}
if (ret != EPASS3K_COMMAND_SIZE + len - 1) {
return -1;
}
return 0;
}
static int epass3k_recv(ifd_reader_t * reader, unsigned int dad,
unsigned char *buffer, size_t len, long timeout)
{
int ret = 0;
ifd_debug(1, "%s:%d epass3k_recv()", __FILE__, __LINE__);
epass3k_status_t *pepass3k_receive = NULL;
pepass3k_receive =
(epass3k_status_t *) malloc(EPASS3K_STATUS_SIZE + len);
memset(pepass3k_receive, 0, EPASS3K_STATUS_SIZE + len);
if (NULL == pepass3k_receive) {
return -1;
}
memset(pepass3k_receive, 0, EPASS3K_STATUS_SIZE + len);
pepass3k_receive->TagH = 'R';
pepass3k_receive->TagL = '6';
pepass3k_receive->LengthH = len / 256;
pepass3k_receive->LengthL = len % 256;
ret =
ifd_device_recv(reader->device, (unsigned char *)pepass3k_receive,
EPASS3K_STATUS_SIZE + len, TIMEOUT);
if (ret < EPASS3K_STATUS_SIZE) {
if (pepass3k_receive)
free(pepass3k_receive);
return -1;
}
if ((NULL != buffer)
&& (pepass3k_receive->LengthH * 256 + pepass3k_receive->LengthL <=
len)) {
memcpy(buffer, pepass3k_receive->Value,
pepass3k_receive->LengthH * 256 +
pepass3k_receive->LengthL);
}
ret = pepass3k_receive->LengthH * 256 + pepass3k_receive->LengthL;
if (pepass3k_receive)
free(pepass3k_receive);
return ret;
}
static struct ifd_driver_ops epass3k_driver;
void ifd_epass3k_register(void)
{
epass3k_driver.open = epass3k_open;
epass3k_driver.activate = epass3k_activate;
epass3k_driver.deactivate = epass3k_deactivate;
epass3k_driver.card_reset = epass3k_card_reset;
epass3k_driver.card_status = epass3k_card_status;
epass3k_driver.change_parity = epass3k_change_parity;
epass3k_driver.change_speed = epass3k_change_speed;
epass3k_driver.send = epass3k_send;
epass3k_driver.recv = epass3k_recv;
epass3k_driver.set_protocol = epass3k_set_protocol;
ifd_driver_register("ePass3000", &epass3k_driver);
}
openct-0.6.20/src/ifd/ifd-eutron.c 0000644 0001750 0001750 00000017610 11043042742 013563 0000000 0000000 /*
* Eutron Crypto Idendity IT-Sec driver
*
* Copyright (C) 2003, Andreas Jellinghaus
* Copyright (C) 2003, Olaf Kirch
* Copyright 2006, Chaskiel Grundman
*/
#include "internal.h"
#include "atr.h"
#include "usb-descriptors.h"
#include
#include
#include
#include
#define EUTRON_OUT IFD_USB_ENDPOINT_OUT | IFD_USB_TYPE_VENDOR | IFD_USB_RECIP_ENDPOINT
#define EUTRON_IN IFD_USB_ENDPOINT_IN | IFD_USB_TYPE_VENDOR | IFD_USB_RECIP_ENDPOINT
#define EUTRON_CMD_WRITE 0x1
#define EUTRON_CMD_READ 0x2
#define EUTRON_CMD_ATR 0x9
#define EUTRON_CMD_SETPARAM 0x65
typedef struct eut_priv {
unsigned char readbuffer[500];
int head;
int tail;
} eut_priv_t;
/*
* Initialize the device
*/
static int eutron_open(ifd_reader_t * reader, const char *device_name)
{
ifd_device_t *dev;
eut_priv_t *priv;
ifd_device_params_t params;
reader->name = "Eutron CryptoIdendity";
reader->nslots = 1;
if (!(dev = ifd_device_open(device_name)))
return -1;
if (ifd_device_type(dev) != IFD_DEVICE_TYPE_USB) {
ct_error("eutron: device %s is not a USB device", device_name);
ifd_device_close(dev);
return -1;
}
params = dev->settings;
params.usb.interface = 0;
if (ifd_device_set_parameters(dev, ¶ms) < 0) {
ct_error("eutron: setting parameters failed", device_name);
ifd_device_close(dev);
return -1;
}
priv = (eut_priv_t *) calloc(1, sizeof(eut_priv_t));
if (!priv) {
ct_error("out of memory");
ifd_device_close(dev);
return IFD_ERROR_NO_MEMORY;
}
reader->driver_data = priv;
reader->device = dev;
return 0;
}
/*
* Power up the reader
*/
static int eutron_activate(ifd_reader_t * reader)
{
return 0;
}
static int eutron_deactivate(ifd_reader_t * reader)
{
return -1;
}
/*
* Card status - always present
*/
static int eutron_card_status(ifd_reader_t * reader, int slot, int *status)
{
*status = IFD_CARD_PRESENT;
return 0;
}
/*
* Reset - nothing to be done?
* We should do something to make it come back with all state zapped
*/
static int eutron_card_reset(ifd_reader_t * reader, int slot, void *atr,
size_t size)
{
ifd_device_t *dev = reader->device;
unsigned char buffer[IFD_MAX_ATR_LEN + 100];
int rc, lr, c, atrlen;
if (ifd_usb_control(dev, EUTRON_OUT, 0xa3, 0, 0, NULL, 0, -1) != 0
|| ifd_usb_control(dev, EUTRON_OUT, 0xa1, 0, 0, NULL, 0, -1) != 0
|| ifd_usb_control(dev, EUTRON_OUT, 0xa2, 0, 0, NULL, 0, -1) != 0
|| ifd_usb_control(dev, EUTRON_OUT, 0xa0, 0, 0, NULL, 0, -1) != 0)
goto failed;
/* flush any leftover buffered data */
while (ifd_usb_control(dev, EUTRON_IN, EUTRON_CMD_READ, 0, 0,
buffer, IFD_MAX_ATR_LEN + 100, 1000) > 0) ;
if (ifd_usb_control(dev, EUTRON_OUT, EUTRON_CMD_ATR, 0, 0, NULL, 0, -1)
!= 0)
goto failed;
for (lr = 0, c = 0; c < 20; c++) {
rc = ifd_usb_control(dev, EUTRON_IN, EUTRON_CMD_READ, 0, 0,
&buffer[lr], IFD_MAX_ATR_LEN - lr, 1000);
if (rc < 0)
goto failed;
lr += rc;
rc = ifd_atr_complete(buffer, lr);
if (rc)
break;
if (lr > IFD_MAX_ATR_LEN)
goto failed;
usleep(100000);
}
if (c >= 20)
goto failed;
atrlen = lr;
memcpy(atr, buffer, atrlen);
return atrlen;
failed:
ct_error("eutron: failed to activate token");
return -1;
}
/*
* Send/receive routines
*/
static int eutron_send(ifd_reader_t * reader, unsigned int dad,
const unsigned char *buffer, size_t len)
{
return ifd_usb_control(reader->device, EUTRON_OUT, EUTRON_CMD_WRITE, 0,
0, (void *)buffer, len, 1000);
}
static int eutron_recv(ifd_reader_t * reader, unsigned int dad,
unsigned char *buffer, size_t len, long timeout)
{
int rc, c, rbs;
eut_priv_t *priv = reader->driver_data;
ct_debug("eutron_recv: len=%d", len);
if (len <= priv->head - priv->tail) {
memcpy(buffer, priv->readbuffer + priv->tail, len);
priv->tail += len;
ct_debug("eutron_recv: returning buffered data, %d bytes left",
priv->head - priv->tail);
return len;
}
/* move the data to the beginning of the buffer, so there's a big
* contiguous chunk */
memmove(priv->readbuffer, &priv->readbuffer[priv->tail],
priv->head - priv->tail);
priv->head -= priv->tail;
/* since we set tail=0 here, the rest of the function can ignore it */
priv->tail = 0;
for (c = 0; c < 30; c++) {
rbs = 499 - priv->head;
if (rbs == 0)
break;
rc = ifd_usb_control(reader->device, EUTRON_IN, EUTRON_CMD_READ,
0, 0, &priv->readbuffer[priv->head], rbs,
timeout);
if (rc < 0)
goto failed;
priv->head += rc;
if (priv->head >= len)
break;
usleep(100000);
}
if (len > priv->head)
return -1;
memcpy(buffer, priv->readbuffer, len);
priv->tail += len;
if (priv->head - priv->tail)
ct_debug("eutron_recv: buffering %d bytes of data",
priv->head - priv->tail);
return len;
failed:
ct_error("eutron: receive failed");
return -1;
}
static int eutron_set_protocol(ifd_reader_t * reader, int nslot, int proto)
{
ifd_slot_t *slot;
ifd_atr_info_t atr_info;
unsigned char pts[7], ptsret[7];
int ptslen, ptsrlen, r, c, speedparam;
slot = &reader->slot[nslot];
if (proto != IFD_PROTOCOL_T0 && proto != IFD_PROTOCOL_T1) {
ct_error("%s: protocol not supported", reader->name);
return -1;
}
r = ifd_atr_parse(&atr_info, slot->atr, slot->atr_len);
if (r < 0) {
ct_error("%s: Bad ATR", reader->name);
return r;
}
/* if the card supports T=1, prefer it, even if
* it is not the default protocol */
if (atr_info.supported_protocols & 0x2) {
proto = IFD_PROTOCOL_T1;
}
/* XXX disable baud change */
atr_info.TA[0] = -1;
/* ITSEC-P does not respond correctly to request with PTS2 present */
atr_info.TC[0] = -1;
ptslen = ifd_build_pts(&atr_info, proto, pts, 7);
if (ptslen < 0) {
return r;
}
if (eutron_send(reader, slot->dad, pts, ptslen) != ptslen)
return IFD_ERROR_COMM_ERROR;
for (ptsrlen = 0, c = 0; c < 20; c++) {
r = ifd_usb_control(reader->device, EUTRON_IN, EUTRON_CMD_READ,
0, 0, &ptsret[ptsrlen],
sizeof(ptsret) - ptsrlen, 1000);
if (r < 0)
return IFD_ERROR_COMM_ERROR;
ptsrlen += r;
if (ifd_pts_complete(ptsret, ptsrlen))
break;
if (ptsrlen >= 7)
return IFD_ERROR_COMM_ERROR;
usleep(100000);
}
if (c >= 20)
return IFD_ERROR_TIMEOUT;
r = ifd_verify_pts(&atr_info, proto, ptsret, ptsrlen);
if (r < 0) {
ct_error("%s: Protocol selection failed", reader->name);
return r;
}
if (atr_info.TA[0] != -1)
speedparam = atr_info.TA[0];
else
speedparam = 1;
if (ifd_usb_control
(reader->device, EUTRON_OUT, EUTRON_CMD_SETPARAM, speedparam, 0,
NULL, 0, -1) != 0
|| ifd_usb_control(reader->device, EUTRON_OUT, 0xa1, 0, 0, NULL, 0,
-1) != 0
|| ifd_usb_control(reader->device, EUTRON_OUT, 0xa0, 0, 0, NULL, 0,
-1) != 0)
return IFD_ERROR_COMM_ERROR;
slot->proto = ifd_protocol_new(proto, reader, slot->dad);
if (slot->proto == NULL) {
ct_error("%s: internal error", reader->name);
return -1;
}
/* device is not guaranteed to return whole frames */
ifd_protocol_set_parameter(slot->proto, IFD_PROTOCOL_BLOCK_ORIENTED, 0);
/* Enable larger transfers */
if (proto == IFD_PROTOCOL_T1 && atr_info.TA[2] != -1) {
ifd_protocol_set_parameter(slot->proto, IFD_PROTOCOL_T1_IFSC,
atr_info.TA[2]);
if (t1_negotiate_ifsd(slot->proto, slot->dad, atr_info.TA[2]) >
0)
ifd_protocol_set_parameter(slot->proto,
IFD_PROTOCOL_T1_IFSD,
atr_info.TA[2]);
}
return 0;
}
/*
* Driver operations
*/
static struct ifd_driver_ops eutron_driver;
/*
* Initialize this module
*/
void ifd_eutron_register(void)
{
eutron_driver.open = eutron_open;
eutron_driver.activate = eutron_activate;
eutron_driver.deactivate = eutron_deactivate;
eutron_driver.card_status = eutron_card_status;
eutron_driver.card_reset = eutron_card_reset;
eutron_driver.send = eutron_send;
eutron_driver.recv = eutron_recv;
eutron_driver.set_protocol = eutron_set_protocol;
ifd_driver_register("eutron", &eutron_driver);
}
openct-0.6.20/src/ifd/ifd-kaan.c 0000644 0001750 0001750 00000065377 10625640312 013200 0000000 0000000 /*
* Driver for Kobil Kaan Professional and Telesec B1
*
* Copyright (C) 2003 Olaf Kirch
* Copyright (C) 2003 Michael Haardt (B1 support)
*/
#include "internal.h"
#include
#include
#include
#include
#include
#include "ctbcs.h"
/* Freeze after that many seconds of inactivity */
#define FREEZE_DELAY 5
enum {
TYPE_KAAN,
TYPE_B1
};
/*
* CT status
*/
typedef struct kaan_status {
int reader_type;
ifd_protocol_t *p;
time_t last_activity;
unsigned int frozen:1;
int icc_proto[OPENCT_MAX_SLOTS];
} kaan_status_t;
static int kaan_reset_ct(ifd_reader_t * reader);
static int kaan_get_units(ifd_reader_t * reader);
static int kaan_freeze(ifd_reader_t * reader);
static int kaan_sync_detect(ifd_reader_t * reader, int nslot);
static int kaan_set_protocol(ifd_reader_t *, int, int);
static int __kaan_apdu_xcv(ifd_reader_t *,
const unsigned char *, size_t,
unsigned char *, size_t, time_t, int);
static int kaan_get_tlv_from_file(ifd_reader_t *,
unsigned int, unsigned int,
unsigned char, unsigned char *, size_t);
static int kaan_get_tlv(unsigned char *, size_t,
unsigned char tag, unsigned char **ptr);
static int kaan_select_file(ifd_reader_t *, unsigned char,
unsigned int, size_t *);
static int kaan_read_binary(ifd_reader_t *, unsigned char,
unsigned int, unsigned char *, size_t);
static int kaan_update_binary(ifd_reader_t *, unsigned char,
unsigned int, const unsigned char *, size_t);
static int kaan_check_sw(const char *, const unsigned char *, int);
static int kaan_get_sw(const unsigned char *, unsigned int, unsigned short *);
static int kaan_select_app(ifd_reader_t * reader, int nad,
const void *, size_t);
#define kaan_apdu_xcv(reader, sbuf, slen, rbug, rlen, timeout) \
__kaan_apdu_xcv(reader, sbuf, slen, rbug, rlen, timeout, 1)
/*
* Initialize the device
*/
static int kaan_open(ifd_reader_t * reader, const char *device_name)
{
kaan_status_t *st;
ifd_device_t *dev;
ifd_device_params_t params;
int r;
reader->name = "Kobil Kaan PRO";
reader->nslots = 1;
if (!(dev = ifd_device_open(device_name)))
return -1;
if (ifd_device_type(dev) == IFD_DEVICE_TYPE_SERIAL
&& ifd_device_get_parameters(dev, ¶ms) >= 0) {
/* The default configuration for Kobil serial
* readers is 8E1 at 9600bps */
params.serial.bits = 8;
params.serial.parity = IFD_SERIAL_PARITY_EVEN;
params.serial.stopbits = 1;
ifd_device_set_parameters(dev, ¶ms);
}
if (ifd_device_type(dev) == IFD_DEVICE_TYPE_USB) {
params = dev->settings;
params.usb.interface = 0;
if (ifd_device_set_parameters(dev, ¶ms) < 0) {
ct_error("kaan: setting parameters failed", device_name);
ifd_device_close(dev);
return -1;
}
}
reader->device = dev;
if ((st = (kaan_status_t *) calloc(1, sizeof(*st))) == NULL) {
ct_error("out of memory");
return IFD_ERROR_NO_MEMORY;
}
st->reader_type = TYPE_KAAN;
st->icc_proto[0] = -1;
st->icc_proto[1] = -1;
reader->driver_data = st;
if (!(st->p = ifd_protocol_new(IFD_PROTOCOL_T1, reader, 0x12))) {
/* Something is badly hosed */
ct_error("unable to get T1 protocol handler");
return IFD_ERROR_GENERIC;
}
/* Force a T=1 resync. We don't know what state the reader's
* T=1 engine is in. */
if ((r = ifd_protocol_resynchronize(st->p, 0x12)) < 0)
return r;
/* Reset the CT */
if ((r = kaan_reset_ct(reader)) < 0)
return r;
/* Get list of functional units */
if ((r = kaan_get_units(reader)) < 0)
return r;
#if 0
/* Clear the display */
reader->ops->display(reader, "");
#endif
return 0;
}
/*
* Initialize the device
*/
static int b1_open(ifd_reader_t * reader, const char *device_name)
{
kaan_status_t *st;
ifd_device_t *dev;
ifd_device_params_t params;
unsigned long w;
int r;
reader->name = "DTAG/T-TeleSec B1 standard";
reader->nslots = 1;
if (!(dev = ifd_device_open(device_name)))
return -1;
if (ifd_device_type(dev) == IFD_DEVICE_TYPE_SERIAL) {
if (ifd_device_get_parameters(dev, ¶ms) >= 0) {
/* The default configuration for B1 serial
* readers is 8E1 at 9600 bps */
params.serial.bits = 8;
params.serial.parity = IFD_SERIAL_PARITY_EVEN;
params.serial.stopbits = 1;
params.serial.dtr = 0;
params.serial.rts = 0;
ifd_device_set_parameters(dev, ¶ms);
/* wait 35+-15 = 50 ms for DSR low */
poll((struct pollfd *)0, 0, 50);
if (ifd_serial_get_dsr(dev))
return -1;
/* wait further 300 ms until setting DTR */
poll((struct pollfd *)0, 0, 300);
/* set DTR */
params.serial.dtr = 1;
ifd_device_set_parameters(dev, ¶ms);
/* wait until DSR is set, which may take up to 5 s (typically 0.8 s) */
for (w = 0; w <= 5000; w += 210) {
poll((struct pollfd *)0, 0, 210);
if (ifd_serial_get_dsr(dev))
break;
}
if (w > 5000)
return -1;
} else
return -1;
}
reader->device = dev;
if ((st = (kaan_status_t *) calloc(1, sizeof(*st))) == NULL) {
ct_error("out of memory");
return IFD_ERROR_NO_MEMORY;
}
st->reader_type = TYPE_B1;
st->icc_proto[0] = -1;
st->icc_proto[1] = -1;
reader->driver_data = st;
if (!(st->p = ifd_protocol_new(IFD_PROTOCOL_T1, reader, 0x12))) {
ct_error("unable to get T1 protocol handler");
return IFD_ERROR_GENERIC;
}
/* Reset the CT */
if ((r = kaan_reset_ct(reader)) < 0)
return r;
/* Get list of functional units */
if ((r = kaan_get_units(reader)) < 0)
return r;
return 0;
}
/*
* Reset the card reader
*/
static int kaan_reset_ct(ifd_reader_t * reader)
{
unsigned char cmd1[] = { 0x20, 0x10, 0x00, 0x00 };
unsigned char cmd2[] = { 0x20, 0x11, 0x00, 0x00 };
unsigned char resp[2];
int rc;
unsigned short sw;
if ((rc =
kaan_apdu_xcv(reader, cmd1, sizeof(cmd1), resp, sizeof(resp),
0)) < 0) {
ct_error("kaan_reset_ct: %s", ct_strerror(rc));
return rc;
}
ifd_debug(1, "kaan_reset_ct: rc=%d", rc);
if ((rc = kaan_get_sw(resp, rc, &sw)) < 0)
return rc;
if (sw == 0x6b00) {
/* Reset for older readers */
if ((rc =
kaan_apdu_xcv(reader, cmd2, sizeof(cmd2), resp,
sizeof(resp), 0)) < 0) {
ct_error("kaan_reset_ct: %s", ct_strerror(rc));
return rc;
}
if ((rc = kaan_get_sw(resp, rc, &sw)) < 0)
return rc;
}
if (sw != 0x9000) {
ct_error("kaan_reset_ct: failure, status code %04X", sw);
return IFD_ERROR_COMM_ERROR;
}
return rc;
}
/*
* Get functional units
*/
static int kaan_get_units(ifd_reader_t * reader)
{
unsigned char cmd[] = { 0x20, 0x13, 0x00, 0x81, 0x00 };
unsigned char buffer[16], *units;
int rc, n;
unsigned short sw;
reader->slot[0].dad = 0x02;
if ((rc =
kaan_apdu_xcv(reader, cmd, sizeof(cmd), buffer, sizeof(buffer),
0)) < 0) {
ct_error("kaan_get_units: %s", ct_strerror(rc));
return rc;
}
if ((rc = kaan_get_sw(buffer, rc, &sw)) < 0)
return rc;
if (sw != 0x9000) {
return 0;
}
if ((n = kaan_get_tlv(buffer, rc, 0x81, &units)) < 0)
return 0;
while (n--) {
switch (units[n]) {
case 0x01: /* ICC1 */
break;
case 0x02: /* ICC2 */
reader->slot[1].dad = 0x32;
reader->nslots = 2;
break;
case 0x40: /* Display */
reader->flags |= IFD_READER_KEYPAD;
break;
case 0x50: /* Display */
reader->flags |= IFD_READER_DISPLAY;
break;
}
}
return 0;
}
/*
* Power up the reader
*/
static int kaan_activate(ifd_reader_t * reader)
{
ifd_debug(1, "called.");
return 0;
}
static int kaan_deactivate(ifd_reader_t * reader)
{
ifd_debug(1, "called.");
return 0;
}
/*
* Get the card status
*/
static int kaan_card_status(ifd_reader_t * reader, int slot, int *status)
{
kaan_status_t *st = (kaan_status_t *) reader->driver_data;
unsigned char buffer[16] = { 0x20, 0x13, 0x00, 0x80, 0x00 };
unsigned char *byte;
int rc, n;
buffer[2] = slot + 1;
ifd_debug(1, "slot=%d", slot);
if (!st->frozen && st->last_activity + FREEZE_DELAY < time(NULL)
&& ifd_device_type(reader->device) == IFD_DEVICE_TYPE_SERIAL) {
if ((rc = kaan_freeze(reader)) < 0)
return rc;
usleep(10000);
st->frozen = 1;
}
if (st->frozen) {
/* Get the DSR status */
if (!ifd_serial_get_dsr(reader->device)) {
*status = reader->slot[slot].status;
return 0;
}
/* Activity detected - go on an get status */
st->last_activity = time(NULL);
st->frozen = 0;
}
rc = __kaan_apdu_xcv(reader, buffer, 5, buffer, sizeof(buffer), 0, 0);
if ((rc = kaan_check_sw("kaan_card_status", buffer, rc)) < 0)
return rc;
if (buffer[0] == 0x80) {
if ((n = kaan_get_tlv(buffer, rc, 0x80, &byte)) >= 0) {
if (*byte & 0x01)
*status |= IFD_CARD_PRESENT;
}
} else /* older implementations may return only value part */
if (buffer[0] & 0x01)
*status |= IFD_CARD_PRESENT;
return 0;
}
/*
* Get the card status
*/
static int b1_card_status(ifd_reader_t * reader, int slot, int *status)
{
kaan_status_t *st = (kaan_status_t *) reader->driver_data;
unsigned char buffer[16];
int rc;
buffer[2] = slot + 1;
ifd_debug(1, "slot=%d", slot);
if (!st->frozen && st->last_activity + FREEZE_DELAY < time(NULL)
&& ifd_device_type(reader->device) == IFD_DEVICE_TYPE_SERIAL) {
if ((rc = kaan_freeze(reader)) < 0)
return rc;
usleep(10000);
st->frozen = 1;
}
if (st->frozen) {
/* Get the DSR status */
if (!ifd_serial_get_dsr(reader->device)) {
*status = reader->slot[slot].status;
return 0;
}
/* Activity detected - go on an get status */
st->last_activity = time(NULL);
st->frozen = 0;
}
rc = kaan_get_tlv_from_file(reader,
0x7F70 | (slot),
0x7021 | (slot << 8), 0x21, buffer, 1);
if (rc < 0)
return rc;
ct_error("buffer[0] = %i\n", buffer[0] );
if (buffer[0]) {
*status |= IFD_CARD_PRESENT;
}
return 0;
}
/*
* Send the Freeze command to the reader
*/
static int kaan_freeze(ifd_reader_t * reader)
{
unsigned char freeze[16] = { 0x80, 0x70, 0x00, 0x00, 0x00, 0x30, 00 };
unsigned int m, n;
int rc;
ifd_debug(1, "trying to freeze reader");
for (n = 0, m = 7; n < reader->nslots; n++, m++) {
freeze[m] = n + 1;
if (reader->slot[n].status != 0)
freeze[m] |= 0x02;
}
freeze[6] = n;
freeze[4] = n + 2;
rc = __kaan_apdu_xcv(reader, freeze, m, freeze, sizeof(freeze), 0, 0);
return kaan_check_sw("kaan_card_freeze", freeze, rc);
}
/*
* Common code for card_reset and card_request
*/
static int kaan_do_reset(ifd_reader_t * reader, int nslot,
const unsigned char *cmd, size_t cmd_len,
unsigned char *atr, size_t atr_len,
unsigned int timeout)
{
kaan_status_t *st = (kaan_status_t *) reader->driver_data;
unsigned char buffer[64];
unsigned short sw;
size_t got;
int rc;
st->icc_proto[nslot] = -1;
if ((rc =
kaan_apdu_xcv(reader, cmd, cmd_len, buffer, sizeof(buffer),
timeout)) < 0)
return rc;
if ((rc = kaan_get_sw(buffer, rc, &sw)) < 0)
return rc;
if ((got = rc) > atr_len)
got = atr_len;
switch (sw) {
case 0x9000:
case 0x62a6:
/* Synchronous ICC, CT has already done everything we need
* to know. Now just get the info from the CT. */
memcpy(atr, buffer, got);
if ((rc = kaan_sync_detect(reader, nslot)) < 0)
return rc;
if (got == 4 && st->reader_type == TYPE_B1) {
/* Try to select KVK file. This is required for
* B1 readers and failure is ignored.
*/
static unsigned char aid[] =
{ 0xd2, 0x80, 0x00, 0x00, 0x01, 0x01 };
kaan_select_app(reader, 0x02, aid, sizeof(aid));
}
break;
case 0x62a5:
/* ATR was read, but protocol is unknown. B1 readers */
/* use that for phone cards, because their size can not */
/* automatically be detected. Chose the largest possible */
/* size. */
memcpy(atr, buffer, got);
if (got == 4 && st->reader_type == TYPE_B1)
kaan_set_protocol(reader, nslot, IFD_PROTOCOL_EUROCHIP);
if ((rc = kaan_sync_detect(reader, nslot)) < 0)
return rc;
break;
case 0x9001:
/* asynchronous ICC, just copy the ATR */
memcpy(atr, buffer, got);
break;
case 0x62a7:
/* synchronous ICC, unknown proto - try to detect
* the standard way */
return ifd_sync_detect_icc(reader, nslot, atr, atr_len);
default:
ifd_debug(1, "kaan_card_reset: unable to reset card, sw=0x%04x",
sw);
return IFD_ERROR_COMM_ERROR;
}
return got;
}
/*
* Reset card and get ATR
*/
static int kaan_card_reset(ifd_reader_t * reader, int nslot, void *result,
size_t size)
{
unsigned char cmd[5] = { 0x20, 0x10, 0x00, 0x01, 0x00 };
cmd[2] = nslot + 1;
ifd_debug(1, "called.");
return kaan_do_reset(reader, nslot, cmd, 5, (unsigned char *)result,
size, 0);
}
/*
* Request ICC
*/
static int kaan_card_request(ifd_reader_t * reader, int slot, time_t timeout,
const char *message, void *atr, size_t atr_len)
{
ct_buf_t buf;
unsigned char buffer[256] = { 0x20, 0x17, 0x00, 0x01, 0x00 };
int n;
buffer[2] = slot + 1;
/* Build the APDU, which is basically a modified CTBCS OUTPUT command */
ct_buf_init(&buf, buffer, sizeof(buffer) - 1);
ctbcs_begin(&buf, 0x17, slot + 1, 0x01);
ctbcs_add_timeout(&buf, timeout);
ctbcs_add_message(&buf, message);
if ((n = ctbcs_finish(&buf)) < 0)
return n;
buffer[n++] = 0x00;
return kaan_do_reset(reader, slot, buffer, n, (unsigned char *)atr,
atr_len, timeout);
}
/*
* Select a protocol for communication with the ICC.
* Note that we continue to communicate with the terminal
* using T=1; internally, the terminal talks to the
* card using whatever protocol we selected.
*/
static int kaan_set_protocol(ifd_reader_t * reader, int nslot, int proto)
{
kaan_status_t *st = (kaan_status_t *) reader->driver_data;
unsigned char cmd[] =
{ 0x80, 0x60, 0x00, 0x00, 0x03, 0x22, 0x01, 0x00 };
unsigned char buffer[2];
unsigned short sw;
ifd_slot_t *slot;
int rc;
cmd[2] = nslot + 1;
ifd_debug(1, "proto=%d", proto);
switch (proto) {
case IFD_PROTOCOL_T0:
cmd[7] = 0x01;
break;
case IFD_PROTOCOL_T1:
cmd[7] = 0x02;
break;
case IFD_PROTOCOL_I2C_SHORT:
cmd[7] = 0x80;
break;
case IFD_PROTOCOL_I2C_LONG:
cmd[7] = 0x80;
break;
case IFD_PROTOCOL_3WIRE:
cmd[7] = 0x81;
break;
case IFD_PROTOCOL_2WIRE:
cmd[7] = 0x82;
break;
case IFD_PROTOCOL_EUROCHIP:
cmd[7] = 0x93;
break;
default:
ifd_debug(1, "kaan_set_protocol: protocol %d not supported",
proto);
return -1;
}
if ((rc =
kaan_apdu_xcv(reader, cmd, sizeof(cmd), buffer, sizeof(buffer),
0)) < 0 || (rc = kaan_get_sw(buffer, rc, &sw)) < 0)
return rc;
/* B1 returns 6985 for German KVK health care cards */
if (sw != 0x9000 && sw != 0x6985) {
ifd_debug(1,
"kaan_set_protocol: protocol %d not supported, sw=%04hx",
proto, sw);
return -1;
}
slot = &reader->slot[nslot];
slot->proto = ifd_protocol_new(IFD_PROTOCOL_TRANSPARENT,
reader, slot->dad);
if (slot->proto == NULL) {
ct_error("%s: internal error", reader->name);
return -1;
}
st->icc_proto[nslot] = proto;
return 0;
}
/*
* APDU exchange with ICC
*/
static int kaan_transparent(ifd_reader_t * reader, int dad, const void *sbuf,
size_t slen, void *rbuf, size_t rlen)
{
kaan_status_t *st = (kaan_status_t *) reader->driver_data;
ifd_iso_apdu_t iso;
int rc, nslot, n, prot;
nslot = (dad == 0x02) ? 0 : 1;
prot = st->icc_proto[nslot];
/* Parse the APDU; extract class byte, case, etc */
if ((rc = ifd_iso_apdu_parse(sbuf, slen, &iso)) < 0)
return rc;
if (prot == IFD_PROTOCOL_T0) {
if (iso.cse == IFD_APDU_CASE_4S)
slen--;
}
n = ifd_protocol_transceive(st->p, dad, sbuf, slen, rbuf, rlen);
if (iso.cse == IFD_APDU_CASE_4S && n == 2) {
unsigned char cmd[5], *sw;
sw = (unsigned char *)rbuf;
if (sw[0] == 0x61) {
cmd[0] = iso.cla;
cmd[1] = 0xC0;
cmd[2] = 0x00;
cmd[3] = 0x00;
cmd[4] = sw[1];
n = ifd_protocol_transceive(st->p, dad,
cmd, 5, rbuf, rlen);
}
}
if (n < 0)
return n;
if (n < 2) {
ct_error("kaan: T=1 protocol failure, not enough bytes for SW");
return IFD_ERROR_COMM_ERROR;
}
return n;
}
/*
* Output a string to the display
*/
static int kaan_display(ifd_reader_t * reader, const char *string)
{
unsigned char buffer[256] = { 0x20, 0x17, 0x40, 00 };
int rc, n;
if (!(reader->flags & IFD_READER_DISPLAY))
return 0;
n = ctbcs_build_output(buffer, sizeof(buffer), string);
if (n < 0)
return n;
rc = kaan_apdu_xcv(reader, buffer, n, buffer, sizeof(buffer), 0);
return kaan_check_sw("kaan_display", buffer, rc);
}
/*
* Perform a PIN verification
*/
static int kaan_perform_verify(ifd_reader_t * reader, int nslot,
unsigned int timeout, const char *prompt,
const unsigned char *data, size_t data_len,
unsigned char *resp, size_t resp_len)
{
unsigned char buffer[256];
int n;
unsigned short sw;
if (!(reader->flags & IFD_READER_KEYPAD))
return 0;
n = ctbcs_build_perform_verify_apdu(buffer, sizeof(buffer),
nslot + 1, prompt, timeout,
data, data_len);
if (n < 0)
return n;
n = kaan_apdu_xcv(reader, buffer, n, resp, resp_len, 0);
if (n < 0) {
ct_error("perform_verify failed: %s", ct_strerror(n));
return n;
}
if ((n = kaan_get_sw(resp, n, &sw)) < 0)
return n;
switch (sw) {
case 0x6400:
ct_error("perform_verify failed: timeout");
return IFD_ERROR_USER_TIMEOUT;
case 0x6401:
ct_error("perform_verify failed: user pressed cancel");
return IFD_ERROR_USER_ABORT;
case 0x6402:
ct_error("perform_verify failed: PIN mismatch");
return IFD_ERROR_PIN_MISMATCH;
}
return 2;
}
/*
* Read from synchronous ICC
*/
static int kaan_sync_read(ifd_reader_t * reader, int slot, int proto,
unsigned short addr, unsigned char *data, size_t len)
{
kaan_status_t *st = (kaan_status_t *) reader->driver_data;
int r;
ifd_debug(1, "called, addr=0x%04x, len=%u", addr, len);
if (st->icc_proto[slot] != proto) {
r = kaan_set_protocol(reader, slot, proto);
if (r < 0)
return r;
}
return kaan_read_binary(reader, reader->slot[slot].dad, addr, data,
len);
}
static int kaan_sync_write(ifd_reader_t * reader, int slot, int proto,
unsigned short addr, const unsigned char *buffer,
size_t len)
{
kaan_status_t *st = (kaan_status_t *) reader->driver_data;
int r;
ifd_debug(1, "called, addr=0x%04x, len=%u", addr, len);
if (st->icc_proto[slot] != proto) {
r = kaan_set_protocol(reader, slot, proto);
if (r < 0)
return r;
}
return kaan_update_binary(reader, reader->slot[slot].dad,
addr, buffer, len);
}
/*
* Detect type and size of synchronous card.
* When we get here, the CT has done most of the work for us
* already, we just need to get the information from it.
*
* XXX - there does not seem to be a way to find out the size
* of the card, so we have to resort to poking around the
* card.
*/
static int kaan_sync_detect(ifd_reader_t * reader, int nslot)
{
kaan_status_t *st = (kaan_status_t *) reader->driver_data;
ifd_slot_t *slot = &reader->slot[nslot];
unsigned char protocol;
int rc;
rc = kaan_get_tlv_from_file(reader,
0x7F70 | nslot,
0x7021 | (nslot << 8), 0x22, &protocol, 1);
if (rc < 0)
return rc;
switch (protocol) {
case 0x80:
protocol = IFD_PROTOCOL_I2C_LONG;
break;
case 0x81:
protocol = IFD_PROTOCOL_3WIRE;
break;
case 0x82:
protocol = IFD_PROTOCOL_2WIRE;
break;
case 0x90:
case 0x91:
case 0x92:
case 0x93:
protocol = IFD_PROTOCOL_EUROCHIP;
break;
default:
ct_error("kaan_sync_detect: unknown card protocol 0x%x",
protocol);
return IFD_ERROR_NOT_SUPPORTED;
}
slot->proto = ifd_protocol_new(protocol, reader, slot->dad);
st->icc_proto[nslot] = protocol;
return 0;
}
/*
* Read from config/status file
*/
static int kaan_get_tlv_from_file(ifd_reader_t * reader, unsigned int df_id,
unsigned int ef_id, unsigned char tag,
unsigned char *data, size_t len)
{
unsigned char buffer[256 + 2], *ptr;
size_t size;
int rc;
if ((rc = kaan_select_file(reader, 0x12, 0x3F00, &size)) < 0
|| (rc = kaan_select_file(reader, 0x12, df_id, &size)) < 0
|| (rc = kaan_select_file(reader, 0x12, ef_id, &size)) < 0)
return rc;
if (size > 256)
size = 256;
if ((rc = kaan_read_binary(reader, 0x12, 0, buffer, 256)) < 0)
return rc;
if ((rc = kaan_get_tlv(buffer, rc, tag, &ptr)) < 0)
return rc;
if ((size_t) rc > len)
rc = len;
memcpy(data, ptr, rc);
return rc;
}
/*
* Stuff to interface with the Kaan's internal file system
*/
static int kaan_select_file(ifd_reader_t * reader, unsigned char nad,
unsigned int fid, size_t * sizep)
{
unsigned char cmd[] = { 0x00, 0xa4, 0x00, 0x00, 2, 0x00, 0x00 };
unsigned char resp[64];
int r;
ifd_debug(1, "called, fid=0x%04x", fid);
cmd[5] = fid >> 8;
cmd[6] = fid & 0xFF;
r = kaan_transparent(reader, nad, cmd, sizeof(cmd), resp, sizeof(resp));
if (r < 0)
return r;
if ((r = kaan_check_sw("kaan_select_file", resp, r)) < 0)
return r;
if (sizep)
*sizep = (resp[0] << 8) | resp[1];
return 0;
}
static int kaan_select_app(ifd_reader_t * reader, int nad, const void *aid,
size_t len)
{
unsigned char cmd[32] = { 0x00, 0xa4, 0x04, 0x00 };
unsigned char resp[64];
int r;
if (len > sizeof(cmd) - 5)
return IFD_ERROR_BUFFER_TOO_SMALL;
cmd[4] = len;
memcpy(cmd + 5, aid, len);
r = kaan_transparent(reader, nad, cmd, len + 5, resp, sizeof(resp));
if (r < 0)
return r;
return kaan_check_sw("kaan_select_app", resp, r);
}
static int kaan_read_binary(ifd_reader_t * reader, unsigned char nad,
unsigned int offset, unsigned char *data, size_t len)
{
unsigned char cmd[] = { 0x00, 0xB0, 0x00, 0x00, 0x00 };
unsigned char buffer[258];
size_t count, total = 0, got;
unsigned short sw;
int r;
ifd_debug(1, "called, offset=0x%04x, len=%u", offset, len);
while (total < len) {
if ((count = len) > 256)
count = 256;
cmd[2] = offset >> 8;
cmd[3] = offset & 0xFF;
cmd[4] = count;
r = kaan_transparent(reader, nad, cmd, sizeof(cmd), buffer,
sizeof(buffer));
if (r < 0)
return r;
got = r - 2;
if ((r = kaan_get_sw(buffer, r, &sw)) < 0)
return r;
switch (sw) {
case 0x6B00: /* offset outside of file */
goto done;
case 0x9000:
case 0x6282: /* EOF reached */
memcpy(data + total, buffer, got);
offset += got;
total += got;
break;
default:
ct_error("kaan_read_binary: "
"failure, status code %04X", sw);
return IFD_ERROR_COMM_ERROR;
}
/* end of file? */
if (got == 0 || sw == 0x6282)
break;
}
done:
return total;
}
static int kaan_update_binary(ifd_reader_t * reader, unsigned char nad,
unsigned int offset, const unsigned char *data,
size_t len)
{
unsigned char cmd[256 + 5] = { 0x00, 0xD0, 0x00, 0x00, 0x00 };
unsigned char resp[2];
size_t count, total = 0;
int r;
ifd_debug(2, "called, offset=0x%04x, len=%u", offset, len);
while (total < len) {
if ((count = len) > 256)
count = 256;
cmd[2] = offset >> 8;
cmd[3] = offset & 0xFF;
cmd[4] = count;
memcpy(cmd + 5, data + total, count);
r = kaan_transparent(reader, nad, cmd, 5 + count, resp,
sizeof(resp));
if (r < 0)
return r;
if ((r = kaan_check_sw("kaan_update_binary", resp, r)) < 0)
return r;
if (r == 0)
break;
offset += r;
total += r;
}
return total;
}
/*
* APDU exchange with terminal
*/
static int __kaan_apdu_xcv(ifd_reader_t * reader, const unsigned char *sbuf,
size_t slen, unsigned char *rbuf, size_t rlen,
time_t timeout, int activity)
{
kaan_status_t *st = (kaan_status_t *) reader->driver_data;
long orig_timeout = 0;
int rc;
/* Override timeout if needed */
if (timeout) {
ifd_protocol_get_parameter(st->p,
IFD_PROTOCOL_RECV_TIMEOUT,
&orig_timeout);
ifd_protocol_set_parameter(st->p,
IFD_PROTOCOL_RECV_TIMEOUT,
timeout * 1000);
}
rc = ifd_protocol_transceive(st->p, 0x12, sbuf, slen, rbuf, rlen);
if (rc < 0)
return rc;
if (rc < 2) {
ct_error("kaan: T=1 protocol failure, rc=%d", rc);
rc = IFD_ERROR_COMM_ERROR;
}
if (timeout) {
ifd_protocol_set_parameter(st->p,
IFD_PROTOCOL_RECV_TIMEOUT,
orig_timeout);
}
if (activity) {
st->last_activity = time(NULL);
st->frozen = 0;
}
return rc;
}
/*
* Check status word returned by Kaan
*/
static int kaan_check_sw(const char *msg, const unsigned char *buf, int rc)
{
unsigned short sw;
if (rc < 0) {
ct_error("%s: %s", msg, ct_strerror(rc));
} else if ((rc = kaan_get_sw(buf, rc, &sw)) >= 0) {
if (sw != 0x9000) {
ct_error("%s: failure, status code %04X", msg, sw);
rc = IFD_ERROR_COMM_ERROR;
}
}
return rc;
}
static int kaan_get_sw(const unsigned char *buf, unsigned int n,
unsigned short *sw)
{
if (n < 2) {
ifd_debug(1, "response too short (%d bytes)", n);
return IFD_ERROR_COMM_ERROR;
}
n -= 2;
*sw = (buf[n] << 8) | buf[n + 1];
return n;
}
/*
* Send/receive T=1 apdu
* This is just for the communication with the card reader.
*/
static int kaan_send(ifd_reader_t * reader, unsigned int dad,
const unsigned char *buffer, size_t len)
{
return ifd_device_send(reader->device, buffer, len);
}
static int kaan_recv(ifd_reader_t * reader, unsigned int dad,
unsigned char *buffer, size_t len, long timeout)
{
return ifd_device_recv(reader->device, buffer, len, timeout);
}
/*
* Extract data from TLV encoded result.
* The length is encoded as a single byte in the range 0 to 254.
* A value of 255 means a big endian two byte length value follows.
*/
static int kaan_get_tlv(unsigned char *buf, size_t len, unsigned char tag,
unsigned char **res)
{
unsigned char *p = buf;
unsigned int n;
n = len;
while (n >= 2) {
len = p[1];
if (len + 2 > n)
break;
if (p[0] == tag) {
*res = p + 2;
return len;
}
p += len + 2;
n -= len + 2;
}
return -1;
}
/*
* Driver operations
*/
static struct ifd_driver_ops kaan_driver, b1_driver;
/*
* Initialize this module
*/
void ifd_kaan_register(void)
{
kaan_driver.open = kaan_open;
kaan_driver.activate = kaan_activate;
kaan_driver.deactivate = kaan_deactivate;
kaan_driver.card_status = kaan_card_status;
kaan_driver.card_reset = kaan_card_reset;
kaan_driver.card_request = kaan_card_request;
kaan_driver.output = kaan_display;
kaan_driver.perform_verify = kaan_perform_verify;
kaan_driver.send = kaan_send;
kaan_driver.recv = kaan_recv;
kaan_driver.set_protocol = kaan_set_protocol;
kaan_driver.transparent = kaan_transparent;
kaan_driver.sync_read = kaan_sync_read;
kaan_driver.sync_write = kaan_sync_write;
b1_driver.open = b1_open;
b1_driver.activate = kaan_activate;
b1_driver.deactivate = kaan_deactivate;
b1_driver.card_status = b1_card_status;
b1_driver.card_reset = kaan_card_reset;
b1_driver.card_request = kaan_card_request;
b1_driver.output = kaan_display;
b1_driver.perform_verify = kaan_perform_verify;
b1_driver.send = kaan_send;
b1_driver.recv = kaan_recv;
b1_driver.set_protocol = kaan_set_protocol;
b1_driver.transparent = kaan_transparent;
b1_driver.sync_read = kaan_sync_read;
b1_driver.sync_write = kaan_sync_write;
ifd_driver_register("kaan", &kaan_driver);
ifd_driver_register("b1", &b1_driver);
}
openct-0.6.20/src/ifd/usb-descriptors.c 0000644 0001750 0001750 00000025436 11143001716 014641 0000000 0000000 /* from libusb 0.1.6a: descriptors.c
* Copyright (c) 2001 Johannes Erdfelt
*
* This library is covered by the LGPL, read LICENSE for details.
*/
/*
* This code looks surprisingly similar to the code I wrote for the Linux
* kernel. It's not a coincidence :)
*/
#include "internal.h"
#include
#include
#include
#include "usb-descriptors.h"
static int ifd_usb_parse_endpoint(struct ifd_usb_endpoint_descriptor *endpoint,
unsigned char *buffer, int size)
{
struct ifd_usb_descriptor_header *header;
unsigned char *begin;
int parsed = 0, len, numskipped;
header = (struct ifd_usb_descriptor_header *)buffer;
/* Everything should be fine being passed into here, but we sanity */
/* check JIC */
if (header->bLength > size) {
ct_debug("ran out of descriptors parsing");
return -1;
}
if (header->bDescriptorType != IFD_USB_DT_ENDPOINT) {
ct_debug
("unexpected descriptor 0x%X, expecting endpoint descriptor, type 0x%X",
endpoint->bDescriptorType, IFD_USB_DT_ENDPOINT);
return parsed;
}
if (header->bLength == IFD_USB_DT_ENDPOINT_AUDIO_SIZE)
memcpy(endpoint, buffer, IFD_USB_DT_ENDPOINT_AUDIO_SIZE);
else
memcpy(endpoint, buffer, IFD_USB_DT_ENDPOINT_SIZE);
IFD_USB_LE16_TO_CPU(endpoint->wMaxPacketSize);
buffer += header->bLength;
size -= header->bLength;
parsed += header->bLength;
/* Skip over the rest of the Class Specific or Vendor Specific */
/* descriptors */
begin = buffer;
numskipped = 0;
while (size >= sizeof(struct ifd_usb_descriptor_header)) {
header = (struct ifd_usb_descriptor_header *)buffer;
if (header->bLength < 2) {
ct_debug("invalid descriptor length of %d",
header->bLength);
return -1;
}
/* If we find another "proper" descriptor then we're done */
if ((header->bDescriptorType == IFD_USB_DT_ENDPOINT) ||
(header->bDescriptorType == IFD_USB_DT_INTERFACE) ||
(header->bDescriptorType == IFD_USB_DT_CONFIG) ||
(header->bDescriptorType == IFD_USB_DT_DEVICE))
break;
ct_debug("in p_ep: skipping descriptor 0x%X",
header->bDescriptorType);
numskipped++;
buffer += header->bLength;
size -= header->bLength;
parsed += header->bLength;
}
if (numskipped)
ct_debug
("skipped %d class/vendor specific endpoint descriptors",
numskipped);
/* Copy any unknown descriptors into a storage area for drivers */
/* to later parse */
len = (int)(buffer - begin);
if (!len) {
endpoint->extra = NULL;
endpoint->extralen = 0;
return parsed;
}
endpoint->extra = (unsigned char *)malloc(len);
if (!endpoint->extra) {
ct_error("out of memory");
endpoint->extralen = 0;
return parsed;
}
memcpy(endpoint->extra, begin, len);
endpoint->extralen = len;
return parsed;
}
static int ifd_usb_parse_interface(struct ifd_usb_interface *interface,
unsigned char *buffer, int size)
{
int i, len, numskipped, retval, parsed = 0;
struct ifd_usb_descriptor_header *header;
struct ifd_usb_interface_descriptor *ifp;
unsigned char *begin;
interface->num_altsetting = 0;
while (size > 0) {
interface->altsetting = (struct ifd_usb_interface_descriptor *)
realloc(interface->altsetting,
sizeof(struct ifd_usb_interface_descriptor)
* (interface->num_altsetting + 1)
);
if (!interface->altsetting) {
ct_error("out of memory");
return -1;
}
ifp = interface->altsetting + interface->num_altsetting;
interface->num_altsetting++;
memcpy(ifp, buffer, IFD_USB_DT_INTERFACE_SIZE);
/* Skip over the interface */
buffer += ifp->bLength;
parsed += ifp->bLength;
size -= ifp->bLength;
begin = buffer;
numskipped = 0;
/* Skip over any interface, class or vendor descriptors */
while (size >= sizeof(struct ifd_usb_descriptor_header)) {
header = (struct ifd_usb_descriptor_header *)buffer;
if (header->bLength < 2) {
ct_debug("invalid descriptor length of %d",
header->bLength);
return -1;
}
/* If we find another "proper" descriptor then we're done */
if ((header->bDescriptorType == IFD_USB_DT_INTERFACE) ||
(header->bDescriptorType == IFD_USB_DT_ENDPOINT) ||
(header->bDescriptorType == IFD_USB_DT_CONFIG) ||
(header->bDescriptorType == IFD_USB_DT_DEVICE))
break;
numskipped++;
buffer += header->bLength;
parsed += header->bLength;
size -= header->bLength;
}
if (numskipped)
ct_debug
("skipped %d class/vendor specific interface descriptors",
numskipped);
/* Copy any unknown descriptors into a storage area for */
/* drivers to later parse */
len = (int)(buffer - begin);
if (!len) {
ifp->extra = NULL;
ifp->extralen = 0;
} else {
ifp->extra = (unsigned char *)malloc(len);
if (!ifp->extra) {
ct_error("out of memory");
ifp->extralen = 0;
return -1;
}
memcpy(ifp->extra, begin, len);
ifp->extralen = len;
}
/* Did we hit an unexpected descriptor? */
header = (struct ifd_usb_descriptor_header *)buffer;
if ((size >= sizeof(struct ifd_usb_descriptor_header)) &&
((header->bDescriptorType == IFD_USB_DT_CONFIG) ||
(header->bDescriptorType == IFD_USB_DT_DEVICE)))
return parsed;
if (ifp->bNumEndpoints > IFD_USB_MAXENDPOINTS) {
ct_debug("too many endpoints");
return -1;
}
ifp->endpoint = (struct ifd_usb_endpoint_descriptor *)
malloc(ifp->bNumEndpoints *
sizeof(struct ifd_usb_endpoint_descriptor));
if (!ifp->endpoint) {
ct_debug("couldn't allocate memory for ifp->endpoint");
return -1;
}
memset(ifp->endpoint, 0, ifp->bNumEndpoints *
sizeof(struct ifd_usb_endpoint_descriptor));
for (i = 0; i < ifp->bNumEndpoints; i++) {
header = (struct ifd_usb_descriptor_header *)buffer;
if (header->bLength > size) {
ct_debug("ran out of descriptors parsing");
return -1;
}
retval =
ifd_usb_parse_endpoint(ifp->endpoint + i, buffer,
size);
if (retval < 0)
return retval;
buffer += retval;
parsed += retval;
size -= retval;
}
/* We check to see if it's an alternate to this one */
ifp = (struct ifd_usb_interface_descriptor *)buffer;
if (size < IFD_USB_DT_INTERFACE_SIZE ||
ifp->bDescriptorType != IFD_USB_DT_INTERFACE ||
!ifp->bAlternateSetting)
return parsed;
}
return parsed;
}
static int ifd_usb_parse_configuration(struct ifd_usb_config_descriptor *config,
unsigned char *buffer)
{
int i, retval, size;
struct ifd_usb_descriptor_header *header;
memcpy(config, buffer, IFD_USB_DT_CONFIG_SIZE);
IFD_USB_LE16_TO_CPU(config->wTotalLength);
size = config->wTotalLength;
if (config->bNumInterfaces > IFD_USB_MAXINTERFACES) {
ct_debug("too many interfaces");
return -1;
}
config->interface = (struct ifd_usb_interface *)
malloc(config->bNumInterfaces * sizeof(struct ifd_usb_interface));
if (!config->interface) {
ct_debug("out of memory");
return -1;
}
memset(config->interface, 0,
config->bNumInterfaces * sizeof(struct ifd_usb_interface));
buffer += config->bLength;
size -= config->bLength;
config->extra = NULL;
config->extralen = 0;
for (i = 0; i < config->bNumInterfaces; i++) {
int numskipped, len;
unsigned char *begin;
/* Skip over the rest of the Class Specific or Vendor */
/* Specific descriptors */
begin = buffer;
numskipped = 0;
while (size >= sizeof(struct ifd_usb_descriptor_header)) {
header = (struct ifd_usb_descriptor_header *)buffer;
if ((header->bLength > size) || (header->bLength < 2)) {
ct_debug("invalid descriptor length of %d",
header->bLength);
return -1;
}
/* If we find another "proper" descriptor then we're done */
if ((header->bDescriptorType == IFD_USB_DT_ENDPOINT) ||
(header->bDescriptorType == IFD_USB_DT_INTERFACE) ||
(header->bDescriptorType == IFD_USB_DT_CONFIG) ||
(header->bDescriptorType == IFD_USB_DT_DEVICE))
break;
ct_debug("skipping descriptor 0x%X",
header->bDescriptorType);
numskipped++;
buffer += header->bLength;
size -= header->bLength;
}
if (numskipped)
ct_debug
("skipped %d class/vendor specific endpoint descriptors",
numskipped);
/* Copy any unknown descriptors into a storage area for */
/* drivers to later parse */
len = (int)(buffer - begin);
if (len) {
/* FIXME: We should realloc and append here */
if (!config->extralen) {
config->extra = (unsigned char *)malloc(len);
if (!config->extra) {
ct_debug
("couldn't allocate memory for config extra descriptors");
config->extralen = 0;
return -1;
}
memcpy(config->extra, begin, len);
config->extralen = len;
}
}
retval =
ifd_usb_parse_interface(config->interface + i, buffer,
size);
if (retval < 0)
return retval;
buffer += retval;
size -= retval;
}
return size;
}
int ifd_usb_get_device(ifd_device_t * dev, struct ifd_usb_device_descriptor *d)
{
unsigned char devd[18];
int r;
/* 0x6 == USB_REQ_GET_DESCRIPTOR
* 0x1 == USB_DT_DEVICE
*/
r = ifd_usb_control(dev, 0x80, 0x6, 0x100, 0, devd, 18, 10000);
if (r <= 0) {
ct_error("cannot get descriptors");
return 1;
}
memcpy(d, devd, sizeof(devd));
d->bcdUSB = devd[3] << 8 | devd[2];
d->idVendor = devd[9] << 8 | devd[8];
d->idProduct = devd[11] << 8 | devd[10];
d->bcdDevice = devd[13] << 8 | devd[12];
return 0;
}
int ifd_usb_get_config(ifd_device_t * dev, int n,
struct ifd_usb_config_descriptor *ret)
{
unsigned char *b;
unsigned short len;
int r;
memset(ret, 0, sizeof(struct ifd_usb_config_descriptor));
/* 0x6 == USB_REQ_GET_DESCRIPTOR
* 0x2 == USB_DT_CONFIG
*/
r = ifd_usb_control(dev, 0x80, 0x6, 0x200 | n, 0, ret, 8, 1000);
if (r <= 0) {
ct_error("cannot get descriptors");
return 1;
}
IFD_USB_LE16_TO_CPU(ret->wTotalLength);
len = ret->wTotalLength;
b = (unsigned char *)malloc(len);
if (!b) {
ct_error("cannot malloc descriptor buffer");
return 1;
}
r = ifd_usb_control(dev, 0x80, 0x6, 0x200 | n, 0, b, len, 1000);
if (r < len) {
ct_error("cannot get descriptors");
free(b);
return 1;
}
r = ifd_usb_parse_configuration(ret, b);
free(b);
if (r < 0) {
return 1;
}
return 0;
}
void ifd_usb_free_configuration(struct ifd_usb_config_descriptor *cf)
{
int i, j, k;
if (!cf->interface)
return;
for (i = 0; i < cf->bNumInterfaces; i++) {
struct ifd_usb_interface *ifp = &cf->interface[i];
if (!ifp->altsetting)
break;
for (j = 0; j < ifp->num_altsetting; j++) {
struct ifd_usb_interface_descriptor *as =
&ifp->altsetting[j];
if (as->extra) {
free(as->extra);
as->extra = NULL;
}
if (!as->endpoint)
break;
for (k = 0; k < as->bNumEndpoints; k++) {
if (as->endpoint[k].extra) {
free(as->endpoint[k].extra);
as->endpoint[k].extra = NULL;
}
}
free(as->endpoint);
as->endpoint = NULL;
}
free(ifp->altsetting);
ifp->altsetting = NULL;
}
free(cf->interface);
cf->interface = NULL;
}
openct-0.6.20/src/ifd/atr.h 0000644 0001750 0001750 00000001367 10422076714 012312 0000000 0000000 /*
* ATR type definitions
*
* Copyright (C) 2004, Olaf Kirch
*/
#ifndef OPENCT_ATR_H
#define OPENCT_ATR_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct ifd_atr_info {
/* The following contain -1 if the field wasn't present */
int TA[4];
int TB[4];
int TC[4];
unsigned int supported_protocols;
int default_protocol;
} ifd_atr_info_t;
extern int ifd_atr_parse(ifd_atr_info_t *, const unsigned char *,
size_t);
extern int ifd_build_pts(const ifd_atr_info_t *, int, unsigned char *,
size_t);
extern int ifd_verify_pts(ifd_atr_info_t *, int,
const unsigned char *, size_t);
extern int ifd_pts_complete(const unsigned char *pts, size_t len);
#ifdef __cplusplus
}
#endif
#endif /* OPENCT_ATR_H */
openct-0.6.20/src/ifd/proto-sync.c 0000644 0001750 0001750 00000012654 10625640312 013631 0000000 0000000 /*
* Implementation of synchronous protocols
*
* Copyright (C) 2003, Olaf Kirch
*/
#include "internal.h"
#include
#include
#include
#include
typedef struct {
ifd_protocol_t base;
} sync_state_t;
/*
* Detach protocol
*/
static void sync_release(ifd_protocol_t * prot)
{
/* NOP */
}
/*
* Read/write operations
*/
static int sync_read(ifd_protocol_t * prot, int slot, unsigned short addr,
unsigned char *rbuf, size_t rlen)
{
ifd_reader_t *reader = prot->reader;
const ifd_driver_t *drv;
if (!(drv = reader->driver) || !drv->ops || !drv->ops->sync_read)
return IFD_ERROR_NOT_SUPPORTED;
return drv->ops->sync_read(reader, slot, prot->ops->id,
addr, rbuf, rlen);
}
static int sync_write(ifd_protocol_t * prot, int slot, unsigned short addr,
const unsigned char *sbuf, size_t slen)
{
ifd_reader_t *reader = prot->reader;
const ifd_driver_t *drv;
unsigned int retries = 1;
int prot_id;
if (!(drv = reader->driver) || !drv->ops || !drv->ops->sync_read)
return IFD_ERROR_NOT_SUPPORTED;
prot_id = prot->ops->id;
if ((prot_id == IFD_PROTOCOL_I2C_SHORT
|| prot_id == IFD_PROTOCOL_I2C_LONG) && slen > 1)
retries = 2;
while (slen) {
unsigned char temp[256];
size_t count;
int r;
/* All bytes must be within a 256 page.
* Is this generic, or a Towitoko requirement?
*/
count = 256 - (addr & 255);
if (count > slen)
count = slen;
ifd_debug(2, "writing %u@%04x", count, addr);
r = drv->ops->sync_write(reader, slot,
prot_id, addr, sbuf, count);
if (r < 0)
return r;
/* Verify that data was written correctly */
ifd_debug(2, "verifying %u@%04x", count, addr);
r = drv->ops->sync_read(reader, slot,
prot_id, addr, temp, count);
if (memcmp(sbuf, temp, count)) {
ifd_debug(2, "failed to verify write");
if (retries--)
continue;
return -1;
}
addr += count;
sbuf += count;
slen -= count;
}
return 0;
}
/*
* Probe for sync ICC type
*/
static ifd_protocol_t *ifd_sync_probe_icc(ifd_reader_t * reader, int slot,
int proto)
{
ifd_protocol_t *p;
unsigned char byte;
int res = 0;
if (ifd_deactivate(reader) < 0 || ifd_activate(reader) < 0)
return NULL;
if (!(p = ifd_protocol_new(proto, reader, slot)))
return NULL;
if (ifd_protocol_read_memory(p, slot, 0, &byte, 1) != 1)
goto out;
if (proto == IFD_PROTOCOL_2WIRE || proto == IFD_PROTOCOL_3WIRE) {
if (byte != 0x00 && byte != 0x0FF)
res = 1;
} else {
byte = ~byte;
if (ifd_protocol_write_memory(p, slot, 0, &byte, 1) >= 0) {
byte = ~byte;
ifd_protocol_write_memory(p, slot, 0, &byte, 1);
res = 1;
}
}
out:
if (!res) {
ifd_protocol_free(p);
p = NULL;
}
return p;
}
/*
* Detect synchronous ICC
*/
int ifd_sync_detect_icc(ifd_reader_t * reader, int slot, void *atr, size_t size)
{
ifd_protocol_t *p = NULL;
int n;
if ((p = ifd_sync_probe_icc(reader, slot, IFD_PROTOCOL_I2C_SHORT))
|| (p = ifd_sync_probe_icc(reader, slot, IFD_PROTOCOL_I2C_LONG))) {
/* I2C card. Empty ATR */
n = 0;
} else if ((p = ifd_sync_probe_icc(reader, slot, IFD_PROTOCOL_2WIRE))
|| (p =
ifd_sync_probe_icc(reader, slot, IFD_PROTOCOL_3WIRE))) {
/* Try to read the ATR */
if (ifd_deactivate(reader) < 0 || ifd_activate(reader) < 0)
goto failed;
n = ifd_protocol_read_memory(p, slot, 0, (unsigned char *)atr,
size);
if (n < 0)
goto failed;
} else {
goto failed;
}
reader->slot[slot].proto = p;
ifd_debug(1, "Detected synchronous card (%s), %satr%s",
p->ops->name, n ? "" : "no ", ct_hexdump(atr, n));
return n;
failed:
if (p != NULL)
ifd_protocol_free(p);
return IFD_ERROR_NO_ATR;
}
/*
* Protocol structs
*/
struct ifd_protocol_ops ifd_protocol_i2c_short = {
IFD_PROTOCOL_I2C_SHORT, /* id */
"I2C short", /* name */
sizeof(sync_state_t), /* size */
NULL, /* init */
sync_release, /* release */
NULL, /* set_param */
NULL, /* get_param */
NULL, /* resynchronize */
NULL, /* transceive */
sync_read, /* sync_read */
sync_write, /* sync_write */
};
struct ifd_protocol_ops ifd_protocol_i2c_long = {
IFD_PROTOCOL_I2C_LONG, /* id */
"I2C long", /* name */
sizeof(sync_state_t), /* size */
NULL, /* init */
sync_release, /* release */
NULL, /* set_param */
NULL, /* get_param */
NULL, /* resynchronize */
NULL, /* transceive */
sync_read, /* sync_read */
sync_write, /* sync_write */
};
struct ifd_protocol_ops ifd_protocol_2wire = {
IFD_PROTOCOL_2WIRE, /* id */
"2Wire", /* name */
sizeof(sync_state_t), /* size */
NULL, /* init */
sync_release, /* release */
NULL, /* set_param */
NULL, /* get_param */
NULL, /* resynchronize */
NULL, /* transceive */
sync_read, /* sync_read */
sync_write, /* sync_write */
};
struct ifd_protocol_ops ifd_protocol_3wire = {
IFD_PROTOCOL_3WIRE, /* id */
"3Wire", /* name */
sizeof(sync_state_t), /* size */
NULL, /* init */
sync_release, /* release */
NULL, /* set_param */
NULL, /* get_param */
NULL, /* resynchronize */
NULL, /* transceive */
sync_read, /* sync_read */
sync_write, /* sync_write */
};
struct ifd_protocol_ops ifd_protocol_eurochip = {
IFD_PROTOCOL_EUROCHIP, /* id */
"Eurochip Countercard", /* name */
sizeof(sync_state_t), /* size */
NULL, /* init */
sync_release, /* release */
NULL, /* set_param */
NULL, /* get_param */
NULL, /* resynchronize */
NULL, /* transceive */
sync_read, /* sync_read */
sync_write, /* sync_write */
};
openct-0.6.20/src/ifd/ifd-ikey3k.c 0000644 0001750 0001750 00000010133 10625650421 013443 0000000 0000000 /*
* driver for Rainbow iKey 3000 devices
*
* Copyright (C) 2003, Andreas Jellinghaus
* Copyright (C) 2003, Olaf Kirch
*/
#include "internal.h"
#include
#include
/*
* Initialize the device
*/
static int ikey3k_open(ifd_reader_t * reader, const char *device_name)
{
ifd_device_t *dev;
ifd_device_params_t params;
reader->name = "Rainbow iKey 3000";
reader->nslots = 1;
if (!(dev = ifd_device_open(device_name)))
return -1;
if (ifd_device_type(dev) != IFD_DEVICE_TYPE_USB) {
ct_error("ikey3k: device %s is not a USB device", device_name);
ifd_device_close(dev);
return -1;
}
params = dev->settings;
params.usb.interface = 0;
if (ifd_device_set_parameters(dev, ¶ms) < 0) {
ct_error("ikey3k: setting parameters failed", device_name);
ifd_device_close(dev);
return -1;
}
reader->device = dev;
return 0;
}
/*
* Power up the reader
*/
static int ikey3k_activate(ifd_reader_t * reader)
{
return 0;
}
static int ikey3k_deactivate(ifd_reader_t * reader)
{
return -1;
}
/*
* Card status - always present
*/
static int ikey3k_card_status(ifd_reader_t * reader, int slot, int *status)
{
*status = IFD_CARD_PRESENT;
return 0;
}
/*
* Reset - nothing to be done?
* We should do something to make it come back with all state zapped
*/
static int ikey3k_card_reset(ifd_reader_t * reader, int slot, void *atr,
size_t size)
{
ifd_device_t *dev = reader->device;
unsigned char buffer[256];
int rc, n, atrlen;
unsigned char expect5[] =
{ 0x0a, 0x61, 0x00, 0x07, 0x2d, 0x2d, 0xc0, 0x80, 0x80, 0x60 };
unsigned char expect11[] = { 0xff, 0x11, 0x11, 0xff };
if (ifd_usb_control(dev, 0xc1, 0x00, 0, 0, buffer, 0x40, -1) != 10
|| memcmp(buffer, expect5, sizeof(expect5)) != 0
|| ifd_usb_control(dev, 0x41, 0x16, 0, 0, buffer, 00, -1) != 0
|| ifd_usb_control(dev, 0xc1, 0x01, 0, 0, buffer, 02, -1) != 1
|| buffer[0] != 00)
goto failed;
rc = ifd_usb_control(dev, 0x41, 0x16, 0x2005, 0, buffer, 0, 1000);
if (rc < 0)
goto failed;
rc = ifd_usb_control(dev, 0xc1, 0x01, 0, 0, buffer, 0x20, 1000);
if (rc <= 0)
goto failed;
n = buffer[0];
if (n + 1 > rc)
goto failed;
if (n > IFD_MAX_ATR_LEN)
goto failed;
if (n > size)
n = size;
atrlen = n;
memcpy(atr, buffer + 1, atrlen);
if (ifd_usb_control(dev, 0x41, 0x16, 0x0002, 0, buffer, 0, -1) != 0
|| ifd_usb_control(dev, 0xc1, 0x01, 0, 0, buffer, 04, -1) != 4
|| memcmp(buffer, expect11, sizeof(expect11)) != 0)
goto failed;
return atrlen;
failed:
ct_error("ikey3k: failed to activate token");
return -1;
}
/*
* Select a protocol. We override this function to be able to set the T=1 IFSC
*/
static int ikey3k_set_protocol(ifd_reader_t * reader, int nslot, int proto)
{
ifd_slot_t *slot = &reader->slot[nslot];
int r;
if (!(slot->proto = ifd_protocol_new(proto, reader, slot->dad)))
return -1;
if (proto == IFD_PROTOCOL_T1) {
r = ifd_protocol_set_parameter(slot->proto,
IFD_PROTOCOL_T1_IFSC, 256);
if (r < 0)
return r;
}
return 0;
}
/*
* Send/receive routines
*/
static int ikey3k_send(ifd_reader_t * reader, unsigned int dad,
const unsigned char *buffer, size_t len)
{
int value, idx;
value = buffer[1] << 8 | buffer[0];
idx = buffer[3] << 8 | buffer[2];
return ifd_usb_control(reader->device, 0x41, 0x17, value, idx,
(void *)&buffer[4], len - 4, -1);
}
static int ikey3k_recv(ifd_reader_t * reader, unsigned int dad,
unsigned char *buffer, size_t len, long timeout)
{
return ifd_usb_control(reader->device, 0xc1, 0x01, 0, 0,
buffer, 255, timeout);
}
/*
* Driver operations
*/
static struct ifd_driver_ops ikey3k_driver;
/*
* Initialize this module
*/
void ifd_ikey3k_register(void)
{
ikey3k_driver.open = ikey3k_open;
ikey3k_driver.activate = ikey3k_activate;
ikey3k_driver.deactivate = ikey3k_deactivate;
ikey3k_driver.card_status = ikey3k_card_status;
ikey3k_driver.card_reset = ikey3k_card_reset;
ikey3k_driver.set_protocol = ikey3k_set_protocol;
ikey3k_driver.send = ikey3k_send;
ikey3k_driver.recv = ikey3k_recv;
ifd_driver_register("ikey3k", &ikey3k_driver);
}
openct-0.6.20/src/ifd/manager.c 0000644 0001750 0001750 00000003127 10625640312 013121 0000000 0000000 /*
* IFD manager
*
* Copyright (C) 2003, Olaf Kirch
*/
#include "internal.h"
#include
#include
static ifd_reader_t *ifd_readers[OPENCT_MAX_READERS];
static unsigned int ifd_reader_handle = 1;
/*
* Return number of readers available
*/
int ifd_reader_count(void)
{
return OPENCT_MAX_READERS;
}
/*
* Register a reader
*/
int ifd_attach(ifd_reader_t * reader)
{
unsigned int slot;
if (!reader)
return -1;
if (reader->num)
return 0;
for (slot = 0; slot < OPENCT_MAX_READERS; slot++) {
if (!ifd_readers[slot])
break;
}
if (slot >= OPENCT_MAX_READERS) {
ct_error("Too many readers");
return -1;
}
reader->handle = ifd_reader_handle++;
reader->num = slot;
ifd_readers[slot] = reader;
return 0;
}
/*
* Functions to look up registered readers
*/
ifd_reader_t *ifd_reader_by_handle(unsigned int handle)
{
ifd_reader_t *reader;
unsigned int i;
for (i = 0; i < OPENCT_MAX_READERS; i++) {
if ((reader = ifd_readers[i])
&& reader->handle == handle)
return reader;
}
return NULL;
}
ifd_reader_t *ifd_reader_by_index(unsigned int idx)
{
ifd_reader_t *reader;
if (idx >= OPENCT_MAX_READERS) {
ct_error("ifd_reader_by_index: invalid index %u", idx);
return NULL;
}
if (!(reader = ifd_readers[idx]))
return NULL;
return reader;
}
/*
* Unregister a reader
*/
void ifd_detach(ifd_reader_t * reader)
{
unsigned int slot;
if (reader->num == 0)
return;
if ((slot = reader->num) >= OPENCT_MAX_READERS
|| ifd_readers[slot] != reader) {
ct_error("ifd_detach: unknown reader");
return;
}
ifd_readers[slot] = NULL;
}
openct-0.6.20/src/ifd/sys-sunray.c 0000644 0001750 0001750 00000020702 11151454644 013650 0000000 0000000 /*
* Sunray specific functions
*
* Copyright (C) 2005 William Wanders
*
* These functions need to be re-implemented for every
* new platform.
*/
#include "internal.h"
#if defined(sunray)
#include