|
From: <lu...@us...> - 2014-12-11 11:22:26
|
Revision: 649
http://sourceforge.net/p/pyscard/code/649
Author: ludov
Date: 2014-12-11 11:22:22 +0000 (Thu, 11 Dec 2014)
Log Message:
-----------
Add documentation in Sphinx format
Added Paths:
-----------
trunk/pyscard/src/smartcard/doc/Makefile
trunk/pyscard/src/smartcard/doc/conf.py
trunk/pyscard/src/smartcard/doc/index.rst
trunk/pyscard/src/smartcard/doc/license.rst
trunk/pyscard/src/smartcard/doc/main.rst
trunk/pyscard/src/smartcard/doc/pyscard-framework.rst
trunk/pyscard/src/smartcard/doc/pyscard-wrapper.rst
trunk/pyscard/src/smartcard/doc/user-guide.rst
Added: trunk/pyscard/src/smartcard/doc/Makefile
===================================================================
--- trunk/pyscard/src/smartcard/doc/Makefile (rev 0)
+++ trunk/pyscard/src/smartcard/doc/Makefile 2014-12-11 11:22:22 UTC (rev 649)
@@ -0,0 +1,153 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = _build
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " singlehtml to make a single large HTML file"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " texinfo to make Texinfo files"
+ @echo " info to make Texinfo files and run them through makeinfo"
+ @echo " gettext to make PO message catalogs"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ -rm -rf $(BUILDDIR)/*
+
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/pyscard.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/pyscard.qhc"
+
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/pyscard"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/pyscard"
+ @echo "# devhelp"
+
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo
+ @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+ @echo "Run \`make' in that directory to run these through makeinfo" \
+ "(use \`make info' here to do that automatically)."
+
+info:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo "Running Texinfo files through makeinfo..."
+ make -C $(BUILDDIR)/texinfo info
+ @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+ $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+ @echo
+ @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
Added: trunk/pyscard/src/smartcard/doc/conf.py
===================================================================
--- trunk/pyscard/src/smartcard/doc/conf.py (rev 0)
+++ trunk/pyscard/src/smartcard/doc/conf.py 2014-12-11 11:22:22 UTC (rev 649)
@@ -0,0 +1,244 @@
+# -*- coding: utf-8 -*-
+#
+# pyscard documentation build configuration file, created by
+# sphinx-quickstart on Thu Dec 4 14:38:51 2014.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+sys.path.insert(0, os.path.abspath('../..'))
+sys.path.insert(0, os.path.abspath('../../build/lib.linux-x86_64-2.7'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'pyscard'
+copyright = u'2014, Jean-Daniel Aussel, Ludovic Rousseau'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '1.6.16'
+# The full version, including alpha/beta/rc tags.
+release = '1.6.16'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+#html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'pyscarddoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'pyscard.tex', u'pyscard Documentation',
+ u'Ludovic Rousseau', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'pyscard', u'pyscard Documentation',
+ [u'Ludovic Rousseau'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ ('index', 'pyscard', u'pyscard Documentation',
+ u'Ludovic Rousseau', 'pyscard', 'One line description of project.',
+ 'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
Added: trunk/pyscard/src/smartcard/doc/index.rst
===================================================================
--- trunk/pyscard/src/smartcard/doc/index.rst (rev 0)
+++ trunk/pyscard/src/smartcard/doc/index.rst 2014-12-11 11:22:22 UTC (rev 649)
@@ -0,0 +1,26 @@
+.. pyscard documentation master file, created by
+ sphinx-quickstart on Thu Dec 4 14:38:51 2014.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+Welcome to pyscard's documentation!
+===================================
+
+Contents:
+
+.. toctree::
+ :maxdepth: 4
+
+ main
+ user-guide
+ pyscard-framework
+ pyscard-wrapper
+ license
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
Added: trunk/pyscard/src/smartcard/doc/license.rst
===================================================================
--- trunk/pyscard/src/smartcard/doc/license.rst (rev 0)
+++ trunk/pyscard/src/smartcard/doc/license.rst 2014-12-11 11:22:22 UTC (rev 649)
@@ -0,0 +1,18 @@
+License
+#######
+
+pyscard 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.
+
+pyscard 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 pyscard; if not, write to the Free Software Foundation, Inc.,
+51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+.. literalinclude:: ../LICENSE
Added: trunk/pyscard/src/smartcard/doc/main.rst
===================================================================
--- trunk/pyscard/src/smartcard/doc/main.rst (rev 0)
+++ trunk/pyscard/src/smartcard/doc/main.rst 2014-12-11 11:22:22 UTC (rev 649)
@@ -0,0 +1,42 @@
+pyscard - python for smart cards
+################################
+
+pyscard - python smart card library - is a python module adding smart
+cards support to `python <http://www.python.org/>`_.
+
+`download <http://sourceforge.net/projects/pyscard/>`_ pyscard from sourceforge.net.
+
+Report bugs, patches and feature requests using the `sourceforge pyscard
+bug tracking system <https://sourceforge.net/p/pyscard/_list/tickets>`_.
+
+Pyscard consists of:
+
+* `smartcard.scard
+ <http://pyscard.sourceforge.net/epydoc/smartcard.scard.scard-module.html>`_,
+ an extension module wrapping the WinSCard API (smart card base
+ components) also known as PC/SC, and
+
+* `smartcard <http://pyscard.sourceforge.net/epydoc/index.html>`_, a
+ higher level python framework built on top of the raw PC/SC API.
+
+.. image:: ../doc/images/pyscard.jpg
+ :align: center
+
+Documentation Index
+*******************
+
+ :ref:`pyscard_user_guide`
+
+ `smartcard reference (python smart card library)
+ <http://pyscard.sourceforge.net/epydoc/index.html>`_
+
+ `scard reference (python PCSC wrapper)
+ <http://pyscard.sourceforge.net/epydoc/smartcard.scard.scard-module.html>`_,
+ the python wrapper around PCSC
+
+Samples
+*******
+
+ High level API samples: See :ref:`framework_samples`
+
+ Low level API samples: See :ref:`wrapper_samples`
Added: trunk/pyscard/src/smartcard/doc/pyscard-framework.rst
===================================================================
--- trunk/pyscard/src/smartcard/doc/pyscard-framework.rst (rev 0)
+++ trunk/pyscard/src/smartcard/doc/pyscard-framework.rst 2014-12-11 11:22:22 UTC (rev 649)
@@ -0,0 +1,76 @@
+.. _framework_samples:
+
+pyscard smartcard framework samples
+===================================
+
+pyscard is a python module adding smart cards support to python.
+
+It consists of smartcard.scard, an extension module wrapping Windows
+smart card base components (also known as PCSC), and smartcard, a python
+framework library hiding PCSC complexity.
+
+Display the ATR of inserted cards
+"""""""""""""""""""""""""""""""""
+
+.. literalinclude:: ../Examples/simple/getATR.py
+
+
+Selecting the DF_TELECOM of a card
+""""""""""""""""""""""""""""""""""
+
+.. literalinclude:: ../Examples/simple/selectDF_TELECOM.py
+
+
+A simple apdu tracer and interpreter
+""""""""""""""""""""""""""""""""""""
+
+.. literalinclude:: ../Examples/framework/sample_apduTracerInterpreter.py
+
+
+Tracing connection events
+"""""""""""""""""""""""""
+
+.. literalinclude:: ../Examples/framework/sample_ConsoleConnectionTracer.py
+
+
+Decorating Card Connections to add custom behavior
+""""""""""""""""""""""""""""""""""""""""""""""""""
+
+.. literalinclude:: ../Examples/framework/sample_CardConnectionDecorator.py
+
+
+Detecting response apdu errors
+""""""""""""""""""""""""""""""
+
+.. literalinclude:: ../Examples/framework/sample_ErrorChecking.py
+
+
+Implementing a custom ErrorChecker
+""""""""""""""""""""""""""""""""""
+
+.. literalinclude:: ../Examples/framework/sample_CustomErrorChecker.py
+
+
+Implementing a custom card type
+"""""""""""""""""""""""""""""""
+
+.. literalinclude:: ../Examples/framework/sample_CustomCardType.py
+
+
+Monitoring smartcard readers
+""""""""""""""""""""""""""""
+
+.. literalinclude:: ../Examples/framework/sample_MonitorReaders.py
+
+
+Monitoring smartcard insertion/removal
+""""""""""""""""""""""""""""""""""""""
+
+.. literalinclude:: ../Examples/framework/sample_MonitorCards.py
+
+
+APDU/ATR byte to string utilities
+"""""""""""""""""""""""""""""""""
+
+.. literalinclude:: ../Examples/framework/sample_toHexString.py
+
Added: trunk/pyscard/src/smartcard/doc/pyscard-wrapper.rst
===================================================================
--- trunk/pyscard/src/smartcard/doc/pyscard-wrapper.rst (rev 0)
+++ trunk/pyscard/src/smartcard/doc/pyscard-wrapper.rst 2014-12-11 11:22:22 UTC (rev 649)
@@ -0,0 +1,80 @@
+.. _wrapper_samples:
+
+PCSC wrapper samples
+====================
+
+Using the smartcard framework is the preferred way to write python smart
+card application. You can however use the smartcard.scard library to
+write your python smart card application if you want to write your own
+python framework, or if you want to access some features of the SCardXXX
+C API not available in the smartcard framework.
+
+The smartcard.scard module is a native extension module wrapping Windows
+smart card base components (also known as PCSC) on Windows, and
+pcsc-lite on linux and Mac OS X, whereas the smartcard framework is a
+pure python framework hiding scard complexity and PCSC.
+
+send a Control Code to a card or reader
+"""""""""""""""""""""""""""""""""""""""
+
+.. literalinclude:: ../Examples/scard-api/sample_control.py
+
+
+get the ATR of a card
+"""""""""""""""""""""
+
+.. literalinclude:: ../Examples/scard-api/sample_getATR.py
+
+
+get the attributes of a card
+""""""""""""""""""""""""""""
+
+.. literalinclude:: ../Examples/scard-api/sample_getAttrib.py
+
+
+wait for card insertion/removal
+"""""""""""""""""""""""""""""""
+
+.. literalinclude:: ../Examples/scard-api/sample_getStatusChange.py
+
+
+list the cards introduced in the system
+"""""""""""""""""""""""""""""""""""""""
+
+.. literalinclude:: ../Examples/scard-api/sample_listCards.py
+
+
+list the interfaces supported by a card
+"""""""""""""""""""""""""""""""""""""""
+
+.. literalinclude:: ../Examples/scard-api/sample_listInterfaces.py
+
+
+locate cards in the system
+""""""""""""""""""""""""""
+
+.. literalinclude:: ../Examples/scard-api/sample_locateCards.py
+
+
+manage readers and reader groups
+""""""""""""""""""""""""""""""""
+
+.. literalinclude:: ../Examples/scard-api/sample_readerGroups.py
+
+
+list smart card readers
+"""""""""""""""""""""""
+
+.. literalinclude:: ../Examples/scard-api/sample_readers.py
+
+
+select the DF_TELECOM of a SIM card
+"""""""""""""""""""""""""""""""""""
+
+.. literalinclude:: ../Examples/scard-api/sample_selectDFTelecom.py
+
+
+perform a simple smart card transaction
+"""""""""""""""""""""""""""""""""""""""
+
+.. literalinclude:: ../Examples/scard-api/sample_transaction.py
Added: trunk/pyscard/src/smartcard/doc/user-guide.rst
===================================================================
--- trunk/pyscard/src/smartcard/doc/user-guide.rst (rev 0)
+++ trunk/pyscard/src/smartcard/doc/user-guide.rst 2014-12-11 11:22:22 UTC (rev 649)
@@ -0,0 +1,1637 @@
+.. _pyscard_user_guide:
+
+pyscard user's guide
+####################
+
+Copyright
+*********
+
+| Copyright 2001-2009 `Gemalto <http://www.gemalto.com/>`_
+| Author: Jean-Daniel Aussel, mailto:jea...@ge...
+
+This file is part of pyscard.
+
+pyscard 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.
+
+pyscard 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 pyscard; if not, write to the Free Software Foundation, Inc.,
+51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Introduction
+************
+
+The pyscard smartcard library is a framework for building smart card
+aware applications in Python. The smartcard module is built on top of
+the PCSC API Python wrapper module.
+
+pyscard supports Windows 2000 and XP by using the `Microsoft Smart Card
+Base <http://msdn2.microsoft.com/en-us/library/aa374731.aspx#smart_card_functions>`_ components, and linux and Mac OS X by using `PCSC-lite <http://pcsclite.alioth.debian.org/>`_.
+
+
+Smart Cards
+***********
+
+Smart cards are plastic cards having generally the size of a credit card
+and embedding a microprocessor. Smart cards communicate with the outside
+world thru a serial port interface and an half-duplex protocol.
+Smartcards usually interface with a dedicated terminal, such as a
+point-of-sale terminal or a mobile phone. Sometime, smart cards have to
+be interfaced with personal computers. This is the case for some
+applications such as secure login, mail cyphering or digital signature,
+but also for some PC based smart card tools used to personnalize or edit
+the content of smart cards. Smart cards are interfaced with a personnal
+computer using a smart card reader. The smart card reader connects on
+one side to the serial port of the smart card, and on the other side to
+the PC, often nowadays thru a USB port.
+
+The PCSC workgroup has defined a standard API to interface smart card
+and smart card readers to a PC. The resulting reference implementation
+on linux and Mac OS X operating systems is `PC/SC-lite
+<http://pcsclite.alioth.debian.org/>`_. All windows operating systems
+also include out of the box smart card support, usually called `PCSC
+<http://msdn2.microsoft.com/en-us/library/aa374731.aspx#smart_card_functions>`_.
+
+The PCSC API is implemented in C language, and several bridges are
+provided to access the PCSC API from different languages such as java or
+visual basic. pyscard is a python framework to develop smart card PC
+applications on linux, Mac OS X and windows. pyscard lower layers
+interface to the PCSC API to access the smart cards and smart card
+readers.
+
+
+Quick-start
+***********
+
+We will see in this section some variations on how to send APDU commands
+to a smart card.
+
+
+The reader-centric approach
+===========================
+
+A PC application interacts with a card by sending list of bytes, known
+as Application Protocol Data Units (APDU). The format of these APDUs is
+defined in the ISO7816-4 standard. To send APDUs to a card, the
+application needs first to connect to a card thru a smart card reader.
+Smart card aware applications that first select a smart card reader,
+then connect to the card inserted in the smart card reader use the
+reader-centric approach.
+
+In the reader-centric approach, we open a connection with a card thru a
+smart card reader, and send APDU commands to the card using the
+connection:
+
+.. sourcecode:: python
+
+ >>> from smartcard.System import readers
+ >>> from smartcard.util import toHexString
+ >>>
+ >>> r=readers()
+ >>> print r
+ ['SchlumbergerSema Reflex USB v.2 0', 'Utimaco CardManUSB 0']
+ >>> connection = r[0].createConnection()
+ >>> connection.connect()
+ >>> SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
+ >>> DF_TELECOM = [0x7F, 0x10]
+ >>> data, sw1, sw2 = connection.transmit( SELECT + DF_TELECOM )
+ >>> print "%x %x" % (sw1, sw2)
+ 9f 1a
+ >>>
+
+The list of available readers is retrieved with the readers() function.
+We create a connection with the first reader (index 0 for reader 1, 1
+for reader 2, ...) with the r[0].createConnection() call and connect to
+the card with the connect() method of the connection. We can then send
+APDU commands to the card with the transmit() method.
+
+Scripts written with the reader centric approach however have the
+following drawbacks:
+
+* the reader index or reader name is hardcoded in the scripts; the
+ scripts must be edited to match each user configuration; for example
+ in the previous script, we would have to edit the script and change
+ r[0] to r[1] for using the second reader
+
+* there is no a-priori knowledge that the card is in the reader; to
+ detect card insertion, we would have to execute the script and
+ eventually catch a CardConnectionException that would indicate that
+ there is no card in the reader.
+
+* there is no built-in check that the card in the reader is of the card
+ type we expect; in the previous example, we might try to select the
+ DF_TELECOM of an EMV card.
+
+Most of these issues are solved with the card-centric approach, based on
+card type detection techniques, such as using the Answer To Reset (ATR)
+of the card.
+
+
+The Answer To Reset (ATR)
+=========================
+
+The first answer of a smart card inserted in a smart card reader is call
+the ATR. The purpose of the ATR is to describe the supported
+communication parameters. The smart card reader, smart card reader
+driver, and operating system will use these parameters to establish a
+communication with the card. The ATR is described in the ISO7816-3
+standard. The first bytes of the ATR describe the voltage convention
+(direct or inverse), followed by bytes describing the available
+communication interfaces and their respective parameters. These
+interface bytes are then followed by Historical Bytes which are not
+standardized, and are useful for transmitting proprietary informations
+such as the card type, the version of the embedded software, or the card
+state. Finally these historical bytes are eventually followd by a
+checksum byte.
+
+The class `smartcard.ATR
+<http://pyscard.sourceforge.net/epydoc/smartcard.ATR.ATR-class.html>`_
+is a pyscard utility class that can interpret the content of an ATR:
+
+.. sourcecode:: python
+
+ #! /usr/bin/env python
+ from smartcard.ATR import ATR
+ from smartcard.util import toHexString
+
+ atr = ATR([0x3B, 0x9E, 0x95, 0x80, 0x1F, 0xC3, 0x80, 0x31, 0xA0,
+ 0x73, 0xBE, 0x21, 0x13, 0x67, 0x29, 0x02, 0x01, 0x01, 0x81,0xCD,0xB9] )
+ print atr
+ print 'historical bytes: ', toHexString( atr.getHistoricalBytes() )
+ print 'checksum:', "0x%X" % atr.getChecksum()
+ print 'checksum OK:', atr.checksumOK
+ print 'T0 supported:', atr.isT0Supported()
+ print 'T1 supported:', atr.isT1Supported()
+ print 'T15 supported:', atr.isT15Supported()
+
+Which results in the following output::
+
+ 3B 9E 95 80 1F C3 80 31 A0 73 BE 21 13 67 29 02 01 01 81 CD B9
+ historical bytes: 80 31 A0 73 BE 21 13 67 29 02 01 01 81 CD
+ checksum: 0xB9
+ checksum OK: True
+ T0 supported: True
+ T1 supported: False
+ T15 supported: True
+
+In practice, the ATR can be used to detect a particular card, either by
+trying to match a card with a complete ATR, or by matching a card with
+some data in the historical bytes. Smart card aware PC applications that
+detects smart cards based on the content of the ATR use the card-centric
+approach, independently on the smart card reader in which the card is
+inserted..
+
+
+The card-centric approach
+=========================
+
+In the card-centric approach, we create a request for a specific type of
+card and wait until a card matching the request is inserted. Once a
+matching card is introduced, a connection to the card is automatically
+created and we can send APDU commands to the card using this connection.
+
+Requesting a card by ATR
+------------------------
+
+The following scripts requests a card with a known ATR::
+
+ >>> from smartcard.CardType import ATRCardType
+ >>> from smartcard.CardRequest import CardRequest
+ >>> from smartcard.util import toHexString, toBytes
+ >>>
+ >>> cardtype = ATRCardType( toBytes( "3B 16 94 20 02 01 00 00 0D" ) )
+ >>> cardrequest = CardRequest( timeout=1, cardType=cardtype )
+ >>> cardservice = cardrequest.waitforcard()
+ >>>
+ >>> cardservice.connection.connect()
+ >>> print toHexString( cardservice.connection.getATR() )
+ 3B 16 94 20 02 01 00 00 0D
+ >>>
+ >>> SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
+ >>> DF_TELECOM = [0x7F, 0x10]
+ >>> data, sw1, sw2 = cardservice.connection.transmit( SELECT + DF_TELECOM )
+ >>> print "%x %x" % (sw1, sw2)
+ 9f 1a
+ >>>
+
+To request a card with a know ATR, you must first create an `ATRCardType
+<http://pyscard.sourceforge.net/epydoc/smartcard.CardType.ATRCardType-class.html>`_
+object with the desired ATR::
+
+ >>> cardtype = ATRCardType( toBytes( "3B 16 94 20 02 01 00 00 0D" ) )
+
+And then create a `CardRequest
+<http://pyscard.sourceforge.net/epydoc/smartcard.CardRequest.CardRequest-class.html>`_
+for this card type. In the sample, we request a time-out of 1 second.
+
+ >>> cardrequest = CardRequest( timeout=1, cardType=cardtype )
+ >>> cardservice = cardrequest.waitforcard()
+
+The waitforcard() will either return with a card service or a time-out.
+The card service connection attribute can be used thereafter to transmit
+APDU commands to the card, as with the reader centric approach.
+
+ >>> cardservice.connection.connect()
+ >>> print toHexString( cardservice.connection.getATR() )
+
+If necessary, the reader used for the connection can be accessed thru
+the `CardConnection
+<http://pyscard.sourceforge.net/epydoc/smartcard.CardConnection.CardConnection-class.html>`_
+object:
+
+ >>> print cardservice.connection.getReader()
+ SchlumbergerSema Reflex USB v.2 0
+
+The `ATRCardType
+<http://pyscard.sourceforge.net/epydoc/smartcard.CardType.ATRCardType-class.html>`_
+also supports masks:
+
+ >>> from smartcard.CardType import ATRCardType
+ >>> from smartcard.CardRequest import CardRequest
+ >>> from smartcard.util import toHexString, toBytes
+ >>>
+ >>> cardtype = ATRCardType( toBytes( "3B 15 94 20 02 01 00 00 0F" ), toBytes( "00 00 FF FF FF FF FF FF 00" ) )
+ >>> cardrequest = CardRequest( timeout=1, cardType=cardtype )
+ >>> cardservice = cardrequest.waitforcard()
+ >>>
+ >>> cardservice.connection.connect()
+ >>> print toHexString( cardservice.connection.getATR() )
+ 3B 16 94 20 02 01 00 00 0D
+
+Other CardTypes are available, and new CardTypes can be created, as
+described below.
+
+Requesting any card
+-------------------
+
+The `AnyCardType
+<http://pyscard.sourceforge.net/epydoc/smartcard.CardType.AnyCardType-class.html>`_
+is useful for requesting any card in any reader:
+
+ >>> from smartcard.CardType import AnyCardType
+ >>> from smartcard.CardRequest import CardRequest
+ >>> from smartcard.util import toHexString
+ >>>
+ >>> cardtype = AnyCardType()
+ >>> cardrequest = CardRequest( timeout=1, cardType=cardtype )
+ >>> cardservice = cardrequest.waitforcard()
+ >>>
+ >>> cardservice.connection.connect()
+ >>> print toHexString( cardservice.connection.getATR() )
+ 3B 16 94 20 02 01 00 00 0D
+ >>> print cardservice.connection.getReader()
+ SchlumbergerSema Reflex USB v.2 0
+
+Custom CardTypes
+----------------
+
+Custom CardTypes can be created, e.g. a card type that checks the ATR
+and the historical bytes of the card. To create a custom CardType,
+deriver your CardType class from the `CardType
+<http://pyscard.sourceforge.net/epydoc/smartcard.CardType.CardType-class.html>`_
+base class (or any other CardType) and override the matches() method.
+For exemple to create a DCCardType that will match cards with the direct
+convention (first byte of ATR to 0x3b):
+
+ >>> from smartcard.CardType import CardType
+ >>> from smartcard.CardRequest import CardRequest
+ >>> from smartcard.util import toHexString
+ >>>
+ >>> class DCCardType(CardType):
+ ... def matches( self, atr, reader=None ):
+ ... return atr[0]==0x3B
+ ...
+ >>> cardtype = DCCardType()
+ >>> cardrequest = CardRequest( timeout=1, cardType=cardtype )
+ >>> cardservice = cardrequest.waitforcard()
+ >>>
+ >>> cardservice.connection.connect()
+ >>> print toHexString( cardservice.connection.getATR() )
+ 3B 16 94 20 02 01 00 00 0D
+ >>> print cardservice.connection.getReader()
+ SchlumbergerSema Reflex USB v.2 0
+ >>>
+
+Scripts written with the card-centric approach fixes the problems of the
+reader-centric approach:
+
+* there is no assumption concerning the reader index or reader name; the
+ desired card will be located in any reader
+
+* the request will block or time-out if the desired card type is not
+ inserted since we request the desired card type, the script is not
+ played on an unknown or uncompatible card
+
+Scripts written with the card-centric approach have however the
+following drawbacks:
+
+* the script is limited to a specific card type; we have to modify the
+ script if we want to execute the script on another card type. For
+ exemple, we have to modify the ATR of the card if we are using the
+ ATRCardType. This can be partially solved by having a custom CardType
+ that matches several ATRs, though.
+
+Selecting the card communication protocol
+-----------------------------------------
+
+Communication parameters are mostly important for the protocol
+negociation between the smart card reader and the card. The main
+smartcard protocols are the T=0 protocol and the T=1 protocol, for byte
+or block transmission, respectively. The required protocol can be
+specified at card connection or card transmission.
+
+By defaults, the connect() method of the CardConnection object.will try
+to connect using either the T=0 or T=1 protocol. To force a connection
+protocol, you can pass the required protocol to the connect() method.
+
+ >>> from smartcard.CardType import AnyCardType
+ >>> from smartcard.CardConnection import CardConnection
+ >>> from smartcard.CardRequest import CardRequest
+ >>> from smartcard.util import toHexString
+ >>>
+ >>> cardtype = AnyCardType()
+ >>> cardrequest = CardRequest( timeout=1, cardType=cardtype )
+ >>> cardservice = cardrequest.waitforcard()
+ >>>
+ >>> cardservice.connection.connect( CardConnection.T1_protocol )
+ >>> print toHexString( cardservice.connection.getATR() )
+ 3B 16 94 20 02 01 00 00 0D
+ >>> print cardservice.connection.getReader()
+ SchlumbergerSema Reflex USB v.2 0
+
+Alternatively, you can specify the required protocol in the
+CardConnection transmit() method:
+
+ >>> from smartcard.CardType import AnyCardType
+ >>> from smartcard.CardConnection import CardConnection
+ >>> from smartcard.CardRequest import CardRequest
+ >>> from smartcard.util import toHexString, toBytes
+ >>>
+ >>> cardtype = AnyCardType()
+ >>> cardrequest = CardRequest( timeout=1, cardType=cardtype )
+ >>> cardservice = cardrequest.waitforcard()
+ >>>
+ >>> cardservice.connection.connect()
+ >>>
+ >>> SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
+ >>> DF_TELECOM = [0x7F, 0x10]
+ >>>
+ >>> apdu = SELECT+DF_TELECOM
+ >>> print 'sending ' + toHexString(apdu)
+ sending A0 A4 00 00 02 7F 10
+ >>> response, sw1, sw2 = cardservice.connection.transmit( apdu, CardConnection.T1_protocol )
+ >>> print 'response: ', response, ' status words: ', "%x %x" % (sw1, sw2)
+ response: [] status words: 9f 1a
+ >>>
+ >>> if sw1 == 0x9F:
+ ... GET_RESPONSE = [0XA0, 0XC0, 00, 00 ]
+ ... apdu = GET_RESPONSE + [sw2]
+ ... print 'sending ' + toHexString(apdu)
+ ... response, sw1, sw2 = cardservice.connection.transmit( apdu )
+ ... print 'response: ', toHexString(response), ' status words: ', "%x %x" % (sw1, sw2)
+ ...
+ sending A0 C0 00 00 1A
+ response: 00 00 00 00 7F 10 02 00 00 00 00 00 0D 13 00 0A 04 00 83 8A 83 8A 00 01 00 00 status words: 90 0
+ >>>
+
+The object-centric approach
+===========================
+
+In the object-centric approach, we associate a high-level object with a
+set of smart cards supported by the object. For example we associate a
+javacard loader class with a set of javacard smart cards. We create a
+request for the specific object, and wait until a card supported by the
+object is inserted. Once a card supported by the object is inserted, we
+perform the required function by calling the objec methods.
+
+To be written...
+
+Tracing APDUs
+*************
+
+The brute force
+===============
+
+A straightforward way of tracing command and response APDUs is to insert
+print statements around the transmit() method calls:
+
+ >>> from smartcard.CardType import ATRCardType
+ >>> from smartcard.CardRequest import CardRequest
+ >>> from smartcard.util import toHexString, toBytes
+ >>>
+ >>> cardtype = ATRCardType( toBytes( "3B 16 94 20 02 01 00 00 0D" ) )
+ >>> cardrequest = CardRequest( timeout=1, cardType=cardtype )
+ >>> cardservice = cardrequest.waitforcard()
+ >>>
+ >>> cardservice.connection.connect()
+ >>>
+ >>> SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
+ >>> DF_TELECOM = [0x7F, 0x10]
+ >>>
+ >>> apdu = SELECT+DF_TELECOM
+ >>> print 'sending ' + toHexString(apdu)
+ sending A0 A4 00 00 02 7F 10
+ >>> response, sw1, sw2 = cardservice.connection.transmit( apdu )
+ >>> print 'response: ', response, ' status words: ', "%x %x" % (sw1, sw2)
+ response: [] status words: 9f 1a
+ >>>
+ >>> if sw1 == 0x9F:
+ ... GET_RESPONSE = [0XA0, 0XC0, 00, 00 ]
+ ... apdu = GET_RESPONSE + [sw2]
+ ... print 'sending ' + toHexString(apdu)
+ ... response, sw1, sw2 = cardservice.connection.transmit( apdu )
+ ... print 'response: ', toHexString(response), ' status words: ', "%x %x" % (sw1, sw2)
+ ...
+ sending A0 C0 00 00 1A
+ response: 00 00 00 00 7F 10 02 00 00 00 00 00 0D 13 00 0A 04 00 83 8A 83 8A 00 01 00 00 status words: 90 0
+ >>>
+
+Scripts written this way are quite difficult to read, because there are
+more tracing statements than actual apdu transmits..
+
+A small improvement in visibility would be to replace the print
+instructions by functions, e.g.:
+
+ >>> from smartcard.CardType import ATRCardType
+ >>> from smartcard.CardRequest import CardRequest
+ >>> from smartcard.util import toHexString, toBytes
+ >>>
+ >>> cardtype = ATRCardType( toBytes( "3B 16 94 20 02 01 00 00 0D" ) )
+ >>> cardrequest = CardRequest( timeout=1, cardType=cardtype )
+ >>> cardservice = cardrequest.waitforcard()
+ >>>
+ >>> cardservice.connection.connect()
+ >>>
+ >>> SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
+ >>> DF_TELECOM = [0x7F, 0x10]
+ >>>
+ >>> def trace_command(apdu):
+ ... print 'sending ' + toHexString(apdu)
+ ...
+ >>> def trace_response( response, sw1, sw2 ):
+ ... if None==response: response=[]
+ ... print 'response: ', toHexString(response), ' status words: ', "%x %x" % (sw1, sw2)
+ ...
+ >>> apdu = SELECT+DF_TELECOM
+ >>> trace_command(apdu)
+ sending A0 A4 00 00 02 7F 10
+ >>> response, sw1, sw2 = cardservice.connection.transmit( apdu )
+ >>> trace_response( response, sw1, sw2 )
+ response: status words: 9f 1a
+ >>>
+ >>> if sw1 == 0x9F:
+ ... GET_RESPONSE = [0XA0, 0XC0, 00, 00 ]
+ ... apdu = GET_RESPONSE + [sw2]
+ ... trace_command(apdu)
+ ... response, sw1, sw2 = cardservice.connection.transmit( apdu )
+ ... trace_response( response, sw1, sw2 )
+ ...
+ sending A0 C0 00 00 1A
+ response: 00 00 00 00 7F 10 02 00 00 00 00 00 0D 13 00 0A 04 00 83 8A 83 8A 00 01 00 00 status words: 90 0
+ >>>
+
+Using card connection observers to trace apdu transmission
+==========================================================
+
+The prefered solution is to implement a card connection observer, and
+register the observer with the card connection. The card connection will
+then notify the observer when card connection events occur (e.g.
+connection, disconnection, apdu command or apdu response). This is
+illustrated in the following script:
+
+ >>> from smartcard.CardType import AnyCardType
+ >>> from smartcard.CardRequest import CardRequest
+ >>> from smartcard.CardConnectionObserver import ConsoleCardConnectionObserver
+ >>>
+ >>> GET_RESPONSE = [0XA0, 0XC0, 00, 00 ]
+ >>> SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
+ >>> DF_TELECOM = [0x7F, 0x10]
+ >>>
+ >>>
+ >>> cardtype = AnyCardType()
+ >>> cardrequest = CardRequest( timeout=10, cardType=cardtype )
+ >>> cardservice = cardrequest.waitforcard()
+ >>>
+ >>> observer=ConsoleCardConnectionObserver()
+ >>> cardservice.connection.addObserver( observer )
+ >>>
+ >>> cardservice.connection.connect()
+ connecting to SchlumbergerSema Reflex USB v.2 0
+ >>>
+ >>> apdu = SELECT+DF_TELECOM
+ >>> response, sw1, sw2 = cardservice.connection.transmit( apdu )
+ > A0 A4 00 00 02 7F 10
+ < [] 9F 1A
+ >>> if sw1 == 0x9F:
+ ... apdu = GET_RESPONSE + [sw2]
+ ... response, sw1, sw2 = cardservice.connection.transmit( apdu )
+ ... else:
+ ... print 'no DF_TELECOM'
+ ...
+ > A0 C0 00 00 1A
+ < 00 00 00 00 7F 10 02 00 00 00 00 00 0D 13 00 0A 04 00 83 8A 83 8A 00 01 00 00 90 0
+ >>>
+
+In this script, a `ConsoleCardConnectionObserver
+<http://pyscard.sourceforge.net/epydoc/smartcard.CardConnectionObserver.ConsoleCardConnectionObserver-class.html>`_
+is attached to the card service connection once the watiforcard() call
+returns.
+
+ >>> observer=ConsoleCardConnectionObserver()
+ >>> cardservice.connection.addObserver( observer )
+
+On card connection events (connect, disconnect, transmit command apdu,
+receive response apdu), the card connection notifies its obersers with a
+`CarConnectionEvent
+<http://pyscard.sourceforge.net/epydoc/smartcard.CardConnectionEvent.CardConnectionEvent-class.html>`_
+including the event type and the event data. The
+`ConsoleCardConnectionObserver
+<http://pyscard.sourceforge.net/epydoc/smartcard.CardConnectionObserver.ConsoleCardConnectionObserver-class.html>`_
+is a simple observer that will print on the console the card connection
+events. The class definition is the following:
+
+.. sourcecode:: python
+
+ class ConsoleCardConnectionObserver( CardConnectionObserver ):
+ def update( self, cardconnection, ccevent ):
+
+ if 'connect'==ccevent.type:
+ print 'connecting to ' + cardconnection.getReader()
+
+ elif 'disconnect'==ccevent.type:
+ print 'disconnecting from ' + cardconnection.getReader()
+
+ elif 'command'==ccevent.type:
+ print '> ', toHexString( ccevent.args[0] )
+
+ elif 'response'==ccevent.type:
+ if []==ccevent.args[0]:
+ print '< [] ', "%-2X %-2X" % tuple(ccevent.args[-2:])
+ else:
+ print '< ', toHexString(ccevent.args[0]), "%-2X %-2X" % tuple(ccevent.args[-2:])
+
+The console card connection observer is thus printing the connect,
+disconnect, command and response apdu events:
+
+ >>> cardservice.connection.connect()
+ connecting to SchlumbergerSema Reflex USB v.2 0
+ >>>
+ >>> apdu = SELECT+DF_TELECOM
+ >>> response, sw1, sw2 = cardservice.connection.transmit( apdu )
+ > A0 A4 00 00 02 7F 10
+ < [] 9F 1A
+ >>> if sw1 == 0x9F:
+ ... apdu = GET_RESPONSE + [sw2]
+ ... response, sw1, sw2 = cardservice.connection.transmit( apdu )
+ ... else:
+ ... print 'no DF_TELECOM'
+ ...
+ > A0 C0 00 00 1A
+ < 00 00 00 00 7F 10 02 00 00 00 00 00 0D 13 00 0A 04 00 83 8A 83 8A 00 01 00 00 90 0
+
+A card connection observer's update methode is called upon card
+connection event, with the connection and the connection event as
+parameters. The `CardConnectionEvent
+<http://pyscard.sourceforge.net/epydoc/smartcard.CardConnectionEvent.CardConnectionEvent-class.html>`_
+class definition is the following:
+
+.. sourcecode:: python
+
+ class CardConnectionEvent:
+ """Base class for card connection events.
+
+ This event is notified by CardConnection objects.
+
+ type: 'connect', 'disconnect', 'command', 'response'
+ args: None for 'connect' or 'disconnect'
+ command APDU byte list for 'command'
+ [response data, sw1, sw2] for 'response'
+ type: 'connect' args:"""
+ def __init__( self, type, args=None):
+ self.type=type
+ self.args=args
+
+You can write your own card connection observer, for example to perform
+fancy output in a wxWindows frame, or apdu interpretation. The following
+scripts defines a small SELECT and GET RESPONSE apdu interpreter:
+
+ >>> from smartcard.CardType import AnyCardType
+ >>> from smartcard.CardRequest import CardRequest
+ >>> from smartcard.CardConnectionObserver import CardConnectionObserver
+ >>> from smartcard.util import toHexString
+ >>>
+ >>> from string import replace
+ >>>
+ >>> class TracerAndSELECTInterpreter( CardConnectionObserver ):
+ ... def update( self, cardconnection, ccevent ):
+ ... if 'connect'==ccevent.type:
+ ... print 'connecting to ' + cardconnection.getReader()
+ ... elif 'disconnect'==ccevent.type:
+ ... print 'disconnecting from ' + cardconnection.getReader()
+ ... elif 'command'==ccevent.type:
+ ... str=toHexString(ccevent.args[0])
+ ... str = replace( str , "A0 A4 00 00 02", "SELECT" )
+ ... str = replace( str , "A0 C0 00 00", "GET RESPONSE" )
+ ... print '> ', str
+ ... elif 'response'==ccevent.type:
+ ... if []==ccevent.args[0]:
+ ... print '< [] ', "%-2X %-2X" % tuple(ccevent.args[-2:])
+ ... else:
+ ... print '< ', toHexString(ccevent.args[0]), "%-2X %-2X" % tuple(ccevent.args[-2:])
+ ...
+ >>>
+ >>> GET_RESPONSE = [0XA0, 0XC0, 00, 00 ]
+ >>> SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
+ >>> DF_TELECOM = [0x7F, 0x10]
+ >>>
+ >>>
+ >>> cardtype = AnyCardType()
+ >>> cardrequest = CardRequest( timeout=10, cardType=cardtype )
+ >>> cardservice = cardrequest.waitforcard()
+ >>>
+ >>> observer=TracerAndSELECTInterpreter()
+ >>> cardservice.connection.addObserver( observer )
+ >>>
+ >>> cardservice.connection.connect()
+ connecting to SchlumbergerSema Reflex USB v.2 0
+ >>>
+ >>> apdu = SELECT+DF_TELECOM
+ >>> response, sw1, sw2 = cardservice.connection.transmit( apdu )
+ > SELECT 7F 10
+ < [] 9F 1A
+ >>> if sw1 == 0x9F:
+ ... apdu = GET_RESPONSE + [sw2]
+ ... response, sw1, sw2 = cardservice.connection.transmit( apdu )
+ ... else:
+ ... print 'no DF_TELECOM'
+ ...
+ > GET RESPONSE 1A
+ < 00 00 00 00 7F 10 02 00 00 00 00 00 0D 13 00 0A 04 00 83 8A 83 8A 00 01 00 00 90 0
+ >>>
+
+Testing for APDU transmission errors
+************************************
+
+Upon transmission and processing of an APDU, the smart card returns a
+pair of status words, SW1 and SW2, to report various success or error
+codes following the required processing. Some of these success or error
+codes are standardized in ISO7816-4, ISO7816-8 or ISO7816-9, for
+example. Other status word codes are standardized by standardization
+bodies such as Open Platform (e.g. javacard), 3GPP (e.g. SIM or USIM
+cards), or Eurocard-Mastercard-Visa (EMV) (e.g. banking cards). Finally,
+any smart card application developper can defined application related
+proprietary codes; for example the MUSCLE applet defines a set of
+prioprietary codes related to the MUSCLE applet features.
+
+Some of these status word codes are uniques, but others have a different
+meaning depending on the card type and its supported standards. For
+example, ISO7816-4 defines the error code 0x62 0x82 as "File
+Invalidated", whereas in Open Platform 2.1 the same error code is
+defined as "Card life cycle is CARD_LOCKED". As a result, the list of
+error codes that can be returned by a smart card and they interpretation
+depend on the card type. The following discussion outlines possible
+strategies to check and report smart card status word errors.
+
+The brute force for testing APDU transmission errors
+====================================================
+
+As for APDU tracing, a straightforward way of checking for errors in response APDUs during the execution of scripts is to insert testt statements after the transmit() method calls:
+
+ >>> from smartcard.CardType import AnyCardType
+ >>> from smartcard.CardRequest import CardRequest
+ >>> from smartcard.CardConnectionObserver import ConsoleCardConnectionObserver
+ >>>
+ >>> GET_RESPONSE = [0XA0, 0XC0, 00, 00 ]
+ >>> SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
+ >>> DF_TELECOM = [0x7F, 0x10]
+ >>>
+ >>> cardtype = AnyCardType()
+ >>> cardrequest = CardRequest( timeout=10, cardType=cardtype )
+ >>> cardservice = cardrequest.waitforcard()
+ >>>
+ >>> observer=ConsoleCardConnectionObserver()
+ >>> cardservice.connection.addObserver( observer )
+ >>>
+ >>> cardservice.connection.connect()
+ connecting to Utimaco CardManUSB 0
+ >>>
+ >>> apdu = SELECT+DF_TELECOM
+ >>> response, sw1, sw2 = cardservice.connection.transmit( apdu )
+ > A0 A4 00 00 02 7F 10
+ < [] 6E 0
+ >>>
+ >>> if sw1 in range(0x61, 0x6f):
+ ... print "Error: sw1: %x sw2: %x" % (sw1, sw2)
+ ...
+ Error: sw1: 6e sw2: 0
+ >>> if sw1 == 0x9F:
+ ... apdu = GET_RESPONSE + [sw2]
+ ... response, sw1, sw2 = cardservice.connection.transmit( apdu )
+ ...
+ >>> cardservice.connection.disconnect()
+ disconnecting from Utimaco CardManUSB 0
+ >>>
+
+Scripts written this way are quite difficult to read, because there are
+more error detection statements than actual apdu transmits.
+
+An improvement in visibility is to wrap the transmit instruction inside
+a function mytransmit, e.g.:
+
+ >>> from smartcard.CardType import AnyCardType
+ >>> from smartcard.CardRequest import CardRequest
+ >>> from smartcard.CardConnectionObserver import ConsoleCardConnectionObserver
+ >>>
+ >>> def mytransmit( connection, apdu ):
+ ... response, sw1, sw2 = connection.transmit( apdu )
+ ... if sw1 in range(0x61, 0x6f):
+ ... print "Error: sw1: %x sw2: %x" % (sw1, sw2)
+ ... return response, sw1, sw2
+ ...
+ >>>
+ >>> GET_RESPONSE = [0XA0, 0XC0, 00, 00 ]
+ >>> SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
+ >>> DF_TELECOM = [0x7F, 0x10]
+ >>>
+ >>>
+ >>> cardtype = AnyCardType()
+ >>> cardrequest = CardRequest( timeout=10, cardType=cardtype )
+ >>> cardservice = cardrequest.waitforcard()
+ >>>
+ >>> observer=ConsoleCardConnectionObserver()
+ >>> cardservice.connection.addObserver( observer )
+ >>>
+ >>> cardservice.connection.connect()
+ connecting to Utimaco CardManUSB 0
+ >>>
+ >>> apdu = SELECT+DF_TELECOM
+ >>> response, sw1, sw2 = mytransmit( cardservice.connection, apdu )
+ > A0 A4 00 00 02 7F 10
+ < [] 6E 0
+ Error: sw1: 6e sw2: 0
+ >>>
+ >>> if sw1 == 0x9F:
+ ... apdu = GET_RESPONSE + [sw2]
+ ... response, sw1, sw2 = mytransmit( cardservice.connection, apdu )
+ ...
+ >>> cardservice.connection.disconnect()
+ disconnecting from Utimaco CardManUSB 0
+ >>>
+
+The prefered solution is for testing errors is to use
+smarcard.sw.ErrorChecker, as described in the following section.
+
+Checking APDU transmission errors with error checkers
+=====================================================
+
+Status word errors can occur from different sources. The ISO7816-4
+standards defines status words for sw1 in the range 0x62 to 0x6F and
+some values of sw2, except for 0x66 which is reserved for security
+related issues. The ISO7816-8 standards define other status words, e.g.
+sw1=0x68 and sw2=0x83 or 0x84 for command chaining errors. Other
+standards, like Open Platform, define additional status words error,
+e.g. sw1=0x94 and sw2=0x84.
+
+The prefered strategy for status word error checking is based around
+individual error checkers (smartcard.sw.ErrorChecker) that can be
+chained into an error checking chain (smartcars.sw.ErrorCheckingChain).
+
+Error checkers
+--------------
+
+An error checker is a class deriving from `ErrorChecker
+<http://pyscard.sourceforge.net/epydoc/smartcard.sw.ErrorChecker.ErrorChecker-class.html>`_
+that checks for recognized sw1, sw2 error conditions when called, and
+raises an exception when finding such condition. This is illustrated in
+the following sample:
+
+ >>> from smartcard.sw.ISO7816_4ErrorChecker import ISO7816_4ErrorChecker
+ >>>
+ >>> errorchecker=ISO7816_4ErrorChecker()
+ >>> errorchecker( [], 0x90, 0x00 )
+ >>> errorchecker( [], 0x6A, 0x80 )
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in ?
+ File "D:\projects\pyscard-install\factory\python\lib\site-packages\smartcard\sw\ISO7816_4ErrorChecker.py", line 137, in __call__
+ raise exception( data, sw1, sw2, message )
+ smartcard.sw.SWExceptions.CheckingErrorException: 'Status word exception: checking error - Incorrect parameters in the data field!'
+ >>>
+
+The first call to error checker does not raise an exception, since 90 00
+does not report any error. The second calls however raises a
+CheckingErrorException.
+
+Error checking chains
+---------------------
+
+Error checkers can be chained into `error checking chain
+<http://pyscard.sourceforge.net/epydoc/smartcard.sw.ErrorCheckingChain.ErrorCheckingChain-class.html>`_.
+Each checker in the chain is called until an error condition is met, in
+which case an exception is raised. This is illustrated in the following
+sample:
+
+ >>> from smartcard.sw.ISO7816_4ErrorChecker import ISO7816_4ErrorChecker
+ >>> from smartcard.sw.ISO7816_8ErrorChecker import ISO7816_8ErrorChecker
+ >>> from smartcard.sw.ISO7816_9ErrorChecker import ISO7816_9ErrorChecker
+ >>>
+ >>> from smartcard.sw.ErrorCheckingChain import ErrorCheckingChain
+ >>>
+ >>> errorchain = []
+ >>> errorchain=[ ErrorCheckingChain( errorchain, ISO7816_9ErrorChecker() ),
+ ... ErrorCheckingChain( errorchain, ISO7816_8ErrorChecker() ),
+ ... ErrorCheckingChain( errorchain, ISO7816_4ErrorChecker() ) ]
+ >>>
+ >>> errorchain[0]( [], 0x90, 0x00 )
+ >>> errorchain[0]( [], 0x6A, 0x8a )
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in ?
+ File "D:\projects\pyscard-install\factory\python\lib\site-packages\smartcard\sw\ErrorCheckingChain.py", line 60,
+ in __call__
+ self.strategy( data, sw1, sw2 )
+ File "D:\projects\pyscard-install\factory\python\lib\site-packages\smartcard\sw\ISO7816_9ErrorChecker.py", line 74, in __call__
+ raise exception( data, sw1, sw2, message )
+ smartcard.sw.SWExceptions.CheckingErrorException: 'Status word exception: checking error - DF name already exists!'
+ >>>
+
+In this sample, an error checking chain is created that will check first
+for iso 7816-9 errors, then iso7816-8 errors, and finally iso7816-4
+errors.
+
+The first call to the error chain does not raise an exception, since 90
+00 does not report any error. The second calls however raises a
+CheckingErrorException, caused by the iso7816-9 error checker.
+
+Filtering exceptions
+--------------------
+
+You can filter undesired exceptions in a chain by adding a filtered
+exception to the error checking chain::
+
+ >>> from smartcard.sw.ISO7816_4ErrorChecker import ISO7816_4ErrorChecker
+ >>> from smartcard.sw.ISO7816_8ErrorChecker import ISO7816_8ErrorChecker
+ >>> from smartcard.sw.ISO7816_9ErrorChecker import ISO7816_9ErrorChecker
+ >>>
+ >>> from smartcard.sw.ErrorCheckingChain import ErrorCheckingChain
+ >>>
+ >>> errorchain = []
+ >>> errorchain=[ ErrorCheckingChain( errorchain, ISO7816_9ErrorChecker() ),
+ ... ErrorCheckingChain( errorchain, ISO7816_8ErrorChecker() ),
+ ... ErrorCheckingChain( errorchain, ISO7816_4ErrorChecker() ) ]
+ >>>
+ >>>
+ >>> errorchain[0]( [], 0x90, 0x00 )
+ >>> errorchain[0]( ...
[truncated message content] |