From cbef3c6e8c95928093d01da3896d9b229ba62cb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20W=C3=A4ckerlin?= Date: Mon, 21 Oct 2013 07:10:46 +0000 Subject: [PATCH] added basic suisse id functions; refs #28 --- doc/doxyfile.in | 707 +++++++++--- doc/examples/cardos-demo.cxx | 164 +++ doc/examples/cryptoki-sign-demo.cxx | 3 +- doc/examples/makefile.am | 67 +- doc/examples/suisse-id-demo.cxx | 95 +- src/cardos.hxx | 1649 +++++++++++++++++++++++++++ src/cryptaux.hxx | 40 + src/makefile.am | 2 +- src/pcsc.hxx | 2 +- src/suisseid.hxx | 200 ++++ 10 files changed, 2645 insertions(+), 284 deletions(-) create mode 100644 doc/examples/cardos-demo.cxx create mode 100644 src/cardos.hxx create mode 100644 src/suisseid.hxx diff --git a/doc/doxyfile.in b/doc/doxyfile.in index 4d56495..d6140ce 100644 --- a/doc/doxyfile.in +++ b/doc/doxyfile.in @@ -1,4 +1,4 @@ -# Doxyfile 1.5.5 +# Doxyfile 1.8.1.2 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project @@ -22,8 +22,9 @@ DOXYFILE_ENCODING = UTF-8 -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. PROJECT_NAME = "Projektdokumentation @PACKAGENAME@" @@ -33,6 +34,19 @@ PROJECT_NAME = "Projektdokumentation @PACKAGENAME@" PROJECT_NUMBER = "Version @MAJOR@.@MINOR@.@LEAST@" +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location @@ -54,13 +68,13 @@ CREATE_SUBDIRS = NO # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, -# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, -# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, -# and Ukrainian. +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. -OUTPUT_LANGUAGE = German +OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in @@ -99,7 +113,7 @@ ALWAYS_DETAILED_SEC = NO # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. -INLINE_INHERITED_MEMB = NO +INLINE_INHERITED_MEMB = YES # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set @@ -126,7 +140,7 @@ STRIP_FROM_PATH = STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems +# (but less readable) file names. This can be useful if your file system # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO @@ -155,13 +169,6 @@ QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = YES -# If the DETAILS_AT_TOP tag is set to YES then Doxygen -# will output the detailed description near the top, like JavaDoc. -# If set to NO, the detailed description appears after the member -# documentation. - -DETAILS_AT_TOP = YES - # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. @@ -193,6 +200,13 @@ ALIASES = "id=\par File-ID\n" \ "instancemutex=\par Reentrant:\nAccess is locked with per instance mutex @c " \ "mutex=\par Reentrant:\nAccess is locked with mutex @c " +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list @@ -219,16 +233,37 @@ OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also make the inheritance and collaboration +# func(std::string) {}). This also makes the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. -BUILTIN_STL_SUPPORT = NO +BUILTIN_STL_SUPPORT = YES -# If you use Microsoft's C++/CLI language, you should set this option to YES to +# If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO @@ -239,6 +274,15 @@ CPP_CLI_SUPPORT = NO SIP_SUPPORT = NO +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default @@ -254,6 +298,22 @@ DISTRIBUTE_GROUP_DOC = YES SUBGROUPING = YES +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct @@ -264,6 +324,33 @@ SUBGROUPING = YES TYPEDEF_HIDES_STRUCT = NO +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +SYMBOL_CACHE_SIZE = 0 + +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- @@ -278,18 +365,23 @@ EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. -EXTRACT_PRIVATE = YES +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. + +EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. -EXTRACT_STATIC = YES +EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. -EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_CLASSES = NO # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in @@ -302,7 +394,7 @@ EXTRACT_LOCAL_METHODS = NO # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default -# anonymous namespace are hidden. +# anonymous namespaces are hidden. EXTRACT_ANON_NSPACES = NO @@ -360,7 +452,13 @@ HIDE_SCOPE_NAMES = NO # will put a list of the files that are included by a file in the documentation # of that file. -SHOW_INCLUDE_FILES = NO +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. @@ -381,6 +479,16 @@ SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = YES + # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. @@ -391,12 +499,21 @@ SORT_GROUP_NAMES = NO # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. @@ -427,10 +544,10 @@ GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in +# the initial value of a variable or macro consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the +# The appearance of the initializer of individual variables and macros in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. @@ -442,11 +559,17 @@ MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. The default is NO. +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. -SHOW_DIRECTORIES = NO +SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from @@ -458,6 +581,25 @@ SHOW_DIRECTORIES = NO FILE_VERSION_FILTER = +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. + +CITE_BIB_FILES = + #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- @@ -486,7 +628,7 @@ WARN_IF_UNDOCUMENTED = NO WARN_IF_DOC_ERROR = YES -# This WARN_NO_PARAMDOC option can be abled to get warnings for +# The WARN_NO_PARAMDOC option can be enabled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of @@ -532,8 +674,9 @@ INPUT_ENCODING = UTF-8 # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl FILE_PATTERNS = *.[ch]xx \ *.doc @@ -544,14 +687,16 @@ FILE_PATTERNS = *.[ch]xx \ RECURSIVE = NO -# The EXCLUDE tag can be used to specify files and/or directories that should +# The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. EXCLUDE = -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO @@ -614,8 +759,8 @@ INPUT_FILTER = # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER -# is applied to all files. +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = @@ -625,6 +770,14 @@ FILTER_PATTERNS = FILTER_SOURCE_FILES = NO +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- @@ -634,35 +787,35 @@ FILTER_SOURCE_FILES = NO # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. -SOURCE_BROWSER = YES +SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. -INLINE_SOURCES = YES +INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. +# fragments. Normal C, C++ and Fortran comments will always remain visible. STRIP_CODE_COMMENTS = YES -# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. -REFERENCED_BY_RELATION = YES +REFERENCED_BY_RELATION = NO -# If the REFERENCES_RELATION tag is set to YES (the default) +# If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. -REFERENCES_RELATION = YES +REFERENCES_RELATION = NO -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. Otherwise they will link to the documentstion. +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES @@ -726,7 +879,14 @@ HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a -# standard header. +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! HTML_HEADER = @@ -741,22 +901,66 @@ HTML_FOOTER = # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! +# style sheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. -HTML_ALIGN_MEMBERS = YES +HTML_EXTRA_FILES = -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) -# of the generated HTML documentation. +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. -GENERATE_HTMLHELP = NO +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 @@ -765,7 +969,9 @@ GENERATE_HTMLHELP = NO # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find -# it at startup. +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. GENERATE_DOCSET = NO @@ -783,13 +989,22 @@ DOCSET_FEEDNAME = "Doxygen generated docs" DOCSET_BUNDLE_ID = org.doxygen.Project -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. For this to work a browser that supports -# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox -# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. -HTML_DYNAMIC_SECTIONS = NO +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You @@ -811,6 +1026,12 @@ HHC_LOCATION = GENERATE_CHI = NO +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. @@ -822,32 +1043,175 @@ BINARY_TOC = NO TOC_EXPAND = NO -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. -DISABLE_INDEX = NO +GENERATE_QHP = NO -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. -ENUM_VALUES_PER_LINE = 4 +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. -# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be -# generated containing a tree-like index structure (just like the one that +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, -# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are -# probably better off using the HTML help feature. +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. GENERATE_TREEVIEW = NO +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = NO + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- @@ -864,7 +1228,10 @@ GENERATE_LATEX = YES LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. LATEX_CMD_NAME = latex @@ -881,7 +1248,7 @@ MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and +# by the printer. Possible values are: a4, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4 @@ -898,6 +1265,13 @@ EXTRA_PACKAGES = LATEX_HEADER = +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references @@ -924,6 +1298,19 @@ LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = YES +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- @@ -955,7 +1342,7 @@ COMPACT_RTF = YES RTF_HYPERLINKS = YES -# Load stylesheet definitions from file. Syntax is similar to doxygen's +# Load style sheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. @@ -1075,7 +1462,7 @@ PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- -# Configuration options related to the preprocessor +# Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will @@ -1098,7 +1485,7 @@ MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. +# pointed to by INCLUDE_PATH will be searched when a #include is found. SEARCH_INCLUDES = YES @@ -1128,36 +1515,32 @@ PREDEFINED = HAVE_STACKTRACE # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all function-like macros that are alone -# on a line, have an all uppercase name, and do not end with a semicolon. Such -# function macros are typically used for boiler-plate code, and will confuse -# the parser if not removed. +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- -# Configuration::additions related to external references +# Configuration::additions related to external references #--------------------------------------------------------------------------- -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. TAGFILES = @@ -1184,15 +1567,14 @@ EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- -# Configuration options related to the dot tool +# Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option is superseded by the HAVE_DOT option below. This is only a -# fallback. It is recommended to install and use dot, since it yields more -# powerful graphs. +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = YES @@ -1203,7 +1585,7 @@ CLASS_DIAGRAMS = YES # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. -MSCGEN_PATH = +MSCGEN_PATH = /usr/bin/mscgen # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented @@ -1216,12 +1598,40 @@ HIDE_UNDOC_RELATIONS = NO # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) -HAVE_DOT = @HAVE_DOT@ +HAVE_DOT = YES + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. +# CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES @@ -1230,7 +1640,7 @@ CLASS_GRAPH = YES # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. -COLLABORATION_GRAPH = NO +COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies @@ -1241,7 +1651,16 @@ GROUP_GRAPHS = YES # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. -UML_LOOK = NO +UML_LOOK = YES + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# managable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. @@ -1253,14 +1672,14 @@ TEMPLATE_RELATIONS = YES # file showing the direct and indirect include dependencies of the file with # other documented files. -INCLUDE_GRAPH = NO +INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. -INCLUDED_BY_GRAPH = NO +INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function @@ -1268,7 +1687,7 @@ INCLUDED_BY_GRAPH = NO # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. -CALL_GRAPH = NO +CALL_GRAPH = YES # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function @@ -1276,30 +1695,41 @@ CALL_GRAPH = NO # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. -CALLER_GRAPH = NO +CALLER_GRAPH = YES # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will graphical hierarchy of all classes instead of a textual one. +# will generate a graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include +# in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are png, jpg, or gif -# If left blank png will be used. +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = svg + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. -DOT_IMAGE_FORMAT = png +INTERACTIVE_SVG = YES # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. -DOT_PATH = +DOT_PATH = /usr/bin/dot # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the @@ -1307,7 +1737,13 @@ DOT_PATH = DOTFILE_DIRS = -# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the @@ -1328,10 +1764,10 @@ DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is enabled by default, which results in a transparent -# background. Warning: Depending on the platform used, enabling this option -# may lead to badly anti-aliased labels on the edges of a graph (i.e. they -# become hard to read). +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). DOT_TRANSPARENT = YES @@ -1340,7 +1776,7 @@ DOT_TRANSPARENT = YES # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. -DOT_MULTI_TARGETS = NO +DOT_MULTI_TARGETS = YES # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and @@ -1353,12 +1789,3 @@ GENERATE_LEGEND = YES # the various graphs. DOT_CLEANUP = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to the search engine -#--------------------------------------------------------------------------- - -# The SEARCHENGINE tag specifies whether or not a search engine should be -# used. If set to NO the values of all tags below this one will be ignored. - -SEARCHENGINE = NO diff --git a/doc/examples/cardos-demo.cxx b/doc/examples/cardos-demo.cxx new file mode 100644 index 0000000..15a6a05 --- /dev/null +++ b/doc/examples/cardos-demo.cxx @@ -0,0 +1,164 @@ +/*! @file + + @id $Id$ +*/ +// 1 2 3 4 5 6 7 8 +// 45678901234567890123456789012345678901234567890123456789012345678901234567890 + +// #include +// #include +// #include + +#include +#include +#include +#include +#include +#include +#include + +#define CARDOS_LOG(X) std::cout< + +class Commands: public cardos::Commands { + + public: + + void help() { + std::cout + <<"Commands: "< Select reader by number"< Send APDU hex data"< Select file below master"< Select file below PKCS#15"< Select file below SigG"< Query status of PIN "< logon to key with PIN"< logon with user PIN"< logon with user PUK"< logon with SigG PIN"< logon with transport PIN"< ", std::cin>>cmd) try { + if (cmd=="help"||cmd=="h") help(); + else if (cmd=="quit"||cmd=="q") return 0; + else if (cmd=="list"||cmd=="l") listReader(); + else if (cmd=="reader"||cmd=="r") selectReader(); + else if (cmd=="serial"||cmd=="s") serial(); + else if (cmd=="apdu"||cmd=="a") sendAPDU(apdu()); + else if (cmd=="masterfile"||cmd=="mf") selectMF(); + else if (cmd=="pkcs15"||cmd=="p15") selectPkcs15(); + else if (cmd=="sigg"||cmd=="sg") selectSigG(); + else if (cmd=="selectfile"||cmd=="sf") selectMfFile(apdu()); + else if (cmd=="selectp15file"||cmd=="spf") selectPkcs15File(apdu()); + else if (cmd=="selectsiggfile"||cmd=="ssf") selectSigGFile(apdu()); + else if (cmd=="readbinfile"||cmd=="rbf") _ber=readBinFile(); + else if (cmd=="readabsoluterecord"||cmd=="rar") _ber=readRecord(); + else if (cmd=="readfirstrecord"||cmd=="rfr") + _ber=readRecord(0, 0, FIRST_RECORD); + else if (cmd=="readnextrecord"||cmd=="rnr") + _ber=readRecord(0, 0, NEXT_RECORD); + else if (cmd=="pinstatus"||cmd=="ps") pinStatus(id()); + else if (cmd=="logon"||cmd=="l") logon(id(), pin()); + else if (cmd=="logonp15"||cmd=="lp") logonPkcs15(pin()); + else if (cmd=="logonppuk"||cmd=="lk") logonPuk(pin()); + else if (cmd=="logonsigg"||cmd=="ls") logonSigG(pin()); + else if (cmd=="logontransport"||cmd=="lt") logonTransport(pin()); + else if (cmd=="getpinlengths"||cmd=="gpl") getPinLengths(); + else if (cmd=="print"||cmd=="p") std::cout<<_ber.print()<>num && num>=0 && num<_readers.size()) { + _reader = _c.reader(_readers[num]); + std::cout<<"Active Reader: "<<_readers[num]<>data)) + throw std::runtime_error("please enter bytes in hex"); + return data; + } + + std::string pin() { + std::string data; + if (!(std::cin>>data)) + throw std::runtime_error("please enter pin"); + return data; + } + + unsigned char id() { + std::string data; + if (!(std::cin>>data) || data.size()!=2 || + data.find_first_not_of("0123456789abcdef")!=std::string::npos) + throw std::runtime_error("please enter one byte in hex"); + return crypto::hexToBin(data)[0]; + } + + private: + + pcsc::Connection _c; + pcsc::Connection::Strings _readers; + + cardos::BerValues _ber; + +}; + +int main(int, char**) { + std::cout<<"Type \"help\" for help."< #include #include -#include #include #include #include +#ifndef MRW__OLD_PRE11_COMPILER #include +#endif int main(int argc, char** argv) try { diff --git a/doc/examples/makefile.am b/doc/examples/makefile.am index 94eb925..e2b75bc 100644 --- a/doc/examples/makefile.am +++ b/doc/examples/makefile.am @@ -3,79 +3,36 @@ ## 1 2 3 4 5 6 7 8 ## 45678901234567890123456789012345678901234567890123456789012345678901234567890 -noinst_PROGRAMS = pcsc-demo cryptoki-sign-demo cryptoki-demo \ - openssl-tcp-demo openssl-ssl-demo \ - openssl-engine-demo suisse-id-demo +noinst_PROGRAMS = pcsc-demo cryptoki-sign-demo cryptoki-demo \ + openssl-tcp-demo openssl-ssl-demo \ + openssl-engine-demo suisse-id-demo cardos-demo -AM_CPPFLAGS += -I/usr/include/PCSC +AM_CPPFLAGS += -I${top_srcdir}/src -I/usr/include/PCSC +AM_LDFLAGS = -L${top_builddir}/src -lpcscxx +if MINGW32 +AM_LDFLAGS += /opt/local/i586-mingw32msvc/lib/winscard.a -leay32 +endif if MAC AM_CPPFLAGS+=-I/Library/OpenSC/include -LDFLAGS += -F/System/Library/Frameworks/PCSC.framework -framework PCSC -L/opt/local/lib -lcrypto +AM_LDFLAGS += -F/System/Library/Frameworks/PCSC.framework -framework PCSC -L/opt/local/lib -lcrypto endif if !MINGW32 if !MAC -LDFLAGS += -lpcsclite +AM_LDFLAGS += -lpcsclite endif endif if !MINGW32 -LDFLAGS += -ldl -lpthread -lssl -lcrypto +AM_LDFLAGS += -ldl -lpthread -lssl -lcrypto endif pcsc_demo_SOURCES = pcsc-demo.cxx -pcsc_demo_CPPFLAGS = -I${top_srcdir}/src -I/usr/include/PCSC -pcsc_demo_LDFLAGS = -L${top_builddir}/src -pcsc_demo_LDADD = -lpcscxx -if MINGW32 -pcsc_demo_LDADD += /opt/local/i586-mingw32msvc/lib/winscard.a -endif - cryptoki_demo_SOURCES = cryptoki-demo.cxx -cryptoki_demo_CPPFLAGS = -I${top_srcdir}/src -I/usr/include/PCSC -cryptoki_demo_LDADD = -lpcscxx -cryptoki_demo_LDFLAGS = -L${top_builddir}/src -if MINGW32 -cryptoki_demo_LDADD += -leay32 -endif - cryptoki_sign_demo_SOURCES = cryptoki-sign-demo.cxx -cryptoki_sign_demo_CPPFLAGS = -std=c++0x -I${top_srcdir}/src -I/usr/include/PCSC -cryptoki_sign_demo_LDADD = -lpcscxx -cryptoki_sign_demo_LDFLAGS = -L${top_builddir}/src -if MINGW32 -cryptoki_demo_LDADD += -leay32 -endif - openssl_tcp_demo_SOURCES = openssl-tcp-demo.cxx -openssl_tcp_demo_CPPFLAGS = -I${top_srcdir}/src -I/usr/include/PCSC -openssl_tcp_demo_LDFLAGS = -L${top_builddir}/src -openssl_tcp_demo_LDADD = -lpcscxx -if MINGW32 -openssl_tcp_demo_LDADD += /opt/local/i586-mingw32msvc/lib/ssleay32.a /opt/local/i586-mingw32msvc/lib/libeay32.a -endif - openssl_ssl_demo_SOURCES = openssl-ssl-demo.cxx -openssl_ssl_demo_CPPFLAGS = -I${top_srcdir}/src -I/usr/include/PCSC -openssl_ssl_demo_LDFLAGS = -L${top_builddir}/src -openssl_ssl_demo_LDADD = -lpcscxx -if MINGW32 -openssl_ssl_demo_LDADD += /opt/local/i586-mingw32msvc/lib/ssleay32.a /opt/local/i586-mingw32msvc/lib/libeay32.a -endif - openssl_engine_demo_SOURCES = openssl-engine-demo.cxx -openssl_engine_demo_CPPFLAGS = -I${top_srcdir}/src -I/usr/include/PCSC -openssl_engine_demo_LDFLAGS = -L${top_builddir}/src -openssl_engine_demo_LDADD = -lpcscxx -if MINGW32 -openssl_engine_demo_LDADD += /opt/local/i586-mingw32msvc/lib/ssleay32.a /opt/local/i586-mingw32msvc/lib/libeay32.a -endif - suisse_id_demo_SOURCES = suisse-id-demo.cxx -suisse_id_demo_CPPFLAGS = -I${top_srcdir}/src -I/usr/include/PCSC -suisse_id_demo_LDFLAGS = -L${top_builddir}/src -suisse_id_demo_LDADD = -lpcscxx -if MINGW32 -suisse_id_demo_LDADD += /opt/local/i586-mingw32msvc/lib/ssleay32.a /opt/local/i586-mingw32msvc/lib/libeay32.a -endif +cardos_demo_SOURCES = cardos-demo.cxx MAINTAINERCLEANFILES = makefile.in diff --git a/doc/examples/suisse-id-demo.cxx b/doc/examples/suisse-id-demo.cxx index b94c5aa..9eeb41b 100644 --- a/doc/examples/suisse-id-demo.cxx +++ b/doc/examples/suisse-id-demo.cxx @@ -5,91 +5,12 @@ // 1 2 3 4 5 6 7 8 // 45678901234567890123456789012345678901234567890123456789012345678901234567890 -#include -#include -#include -#include -#include +#include +#include #include #include -namespace suisseid { - - class Card { - public: - Card(mrw::Shared reader, - mrw::Shared slot): - _reader(reader), - _slot(slot) { - } - virtual ~Card() {} - const std::string& name() { - return _reader->name; - } - private: - mrw::Shared _reader; - mrw::Shared _slot; - }; - - class PostSuisseID: public Card { - public: - PostSuisseID(mrw::Shared reader, - mrw::Shared slot): - Card(reader, slot) { - } - }; - - class Manager { - - public: - - Manager(const std::string& lib="libcvP11.so"): - _cryptoki(lib) { - } - - Manager(const pcsc::Connection& pcsc, - const std::string& lib="libcvP11.so"): - _pcsc(pcsc), - _cryptoki(lib) { - } - - Manager(const cryptoki::Library& cryptoki): - _cryptoki(cryptoki) { - } - - Manager(const pcsc::Connection& pcsc, - const cryptoki::Library& cryptoki): - _pcsc(pcsc), - _cryptoki(cryptoki) { - } - - typedef std::vector > Cards; - - Cards scan() { - Cards res; - // By now, scan only for PostSuisseID; in future use factory pattern - pcsc::Connection::Strings readers - (_pcsc.getReadersWithAtr("4b53776973735369676e")); - for (pcsc::Connection::Strings::iterator reader(readers.begin()); - reader!=readers.end(); ++reader) { - cryptoki::SlotList slots(_cryptoki.slotList(true, *reader)); - if (slots.size()==1) - res.push_back(dynamic_cast - (new PostSuisseID(_pcsc.reader(*reader), slots[0]))); - } - return res; - } - - private: - - pcsc::Connection _pcsc; - cryptoki::Library _cryptoki; - - }; - -} - int main(int argc, char** argv) try { std::string lib("libcvP11.so"); @@ -105,11 +26,13 @@ int main(int argc, char** argv) try { mrw::args::decl::param_list() <name()<name()<version()<minimalPinLength() + <<" - "<<(*card)->maximalPinLength()< +#include +#include +#include +#include + +#ifndef CARDOS_LOG +#define CARDOS_LOG(X) // no logging by default +// use e.g. #define CARDOS_LOG(X) std::cout<_content.size()) + throw wrong_dataformat(_content, "not a TLV, wrong size"); + } + } + /// Return RAW File Content + std::string raw() { + return _content; + } + TagLengthValue at(unsigned int i) { + if (i>=_size) throw array_range(i, _size); + std::string::size_type pos(0); + for (unsigned int j(0); j!=i; ++j) { + pos+=_content[pos+1]+2; + } + return TagLengthValue(_content.substr(pos, _content[pos+1]+2)); + } + std::string str() { + switch ((int)_content[0]) { + case VERSION_INFO_STRING: + return _content.substr(2, (int)_content[1]); + default: + throw wrong_dataformat(_content, "not a string"); + } + } + TagLengthValue tlv() { + switch ((int)_content[0]) { + case VERSION_INFO_CONTAINER: + return TagLengthValue(_content.substr(2, (int)_content[1])); + default: + throw wrong_dataformat(_content, "not a container"); + } + } + private: + unsigned int _size; + std::string _content; + }; + + class BerValue { + public: + enum Class { + UNIVERSAL = 0x00, + APPLICATION = 0x40, + CONTEXT_SPECIFIC = 0x80, + PRIVATE = 0xC0 + }; + enum PC { + PRIMITIVE = 0x00, + CONSTRUCTED = 0x20 + }; + enum Type { + END_OF_CONTENT = 0x00, + BOOLEAN = 0x01, + INTEGER = 0x02, + BIT_STRING = 0x03, + OCTET_STRING = 0x04, + EMPTY = 0x05, + OBJECT_IDENTIFIER = 0x06, + OBJECT_DESCRIPTOR = 0x07, + EXTERNAL = 0x08, + REAL = 0x09, + ENUMERATED = 0x0A, + EMBEDDED_PDV = 0x0B, + UTF8_STRING = 0x0C, + RELATIVE_OID = 0x0D, + SEQUENCE = 0x10, + SET = 0x11, + NUMERIC_STRING = 0x12, + PRINTABLE_STRING = 0x13, + T61_STRING = 0x14, + VIDEOTEX_STRING = 0x15, + IA5_STRING = 0x16, + UTC_TIME = 0x17, + GENERALIZED_TIME = 0x18, + GRAPHIC_STRING = 0x19, + VISIBLE_STRING = 0x1A, + GENERAL_STRING = 0x1B, + UNIVERSAL_STRING = 0x1C, + CHARACTER_STRING = 0x1D, + BMP_STRING = 0x1E, + }; + public: + + BerValue(std::vector sequence): + _tag(PRIVATE|CONSTRUCTED|SEQUENCE), + _length(0), + _sequence(sequence) { + } + + BerValue(const std::string& content) { + if (content.size()<2) + throw wrong_dataformat(content, "not a BER, header size too small: \"" + +crypto::binToHex(content)+"\""); + _tag = content[0]; + _length = content[1]; + _value = content.substr(2, _length); + if (_length+2>content.size()) + throw wrong_dataformat(content, "not a BER, content size too" + " small: \""+crypto::binToHex(_value)+"\""); + if (tagType()==END_OF_CONTENT) return; // done + if (isContainer()) { + for (std::string::size_type pos(0); pos+1<_value.size(); + pos+=2+_value[pos+1]) { // recursively extract value + _sequence.push_back(BerValue(_value.substr(pos, 2+_value[pos+1]))); + } + } + } + + unsigned char tagClass() { + return _tag&0xC0; + } + + unsigned char tagPC() { + return _tag&0x20; + } + + unsigned char tagType() { + return _tag&0x1F; + } + + bool isContainer() { + return tagPC()==CONSTRUCTED; + } + + unsigned int size() { + return _sequence.size(); + } + + unsigned char tag() { + return _tag; + } + + BerValue operator[](unsigned int i) { + if (i>=_sequence.size()) throw array_range(i, _sequence.size()); + return _sequence[i]; + } + + std::string value() { + return _value; + } + + unsigned long toULong() { + unsigned long res(0); + for (std::string::reverse_iterator it(_value.rbegin()); + it!=_value.rend(); ++it) + (res<<=8)+=(unsigned)*it; + return res; + } + + std::string print(int indent=0, int indentStep = 4) { + std::stringstream ss; + ss<::iterator it(_sequence.begin()); + it!=_sequence.end(); ++it) { + ss<print(indent+2, indentStep) + < _sequence; + + // BerValue(const std::string& content) { + // if (content.size()<2 || + // content.size()<2+(std::string::size_type)content[1]) + // throw wrong_dataformat(content, "not a BER, value too small"); + // if (content.size()>2+(std::string::size_type)content[1]) { + // _tag = UNIVERSAL|CONSTRUCTED|SEQUENCE; + // _length = content.size()-2; + // _value = content.substr(2, _length); + // for (std::string::size_type pos(0); pos!=content.size(); + // pos+=content[pos+1]+2) { + // if (pos+2>content.size() || + // (std::string::size_type)content[pos+1]+2>content.size()) + // throw wrong_dataformat(content, "not a BER, wrong size"); + // _sequence.push_back + // (BerValue(content.substr(pos, content[pos+1]+2))); + // } + // } else { + // _tag = content[0]; + // _length = content[1]; + // _value = content.substr(2, _length); + // if (isContainer()) { + // for (std::string::size_type pos(2); pos!=content.size(); + // pos+=content[pos+1]+2) { + // if (pos+2>content.size() || + // (std::string::size_type)content[pos+1]+2>content.size()) + // throw wrong_dataformat(content, "not a BER, wrong size"); + // _sequence.push_back + // (BerValue(content.substr(pos, content[pos+1]+2))); + // } + // } else { + // _value = content.substr(2, _length); + // } + // } + // } + + }; + + /// Store a sequence of BerValue + class BerValues: public std::vector { + public: + BerValues& operator=(const std::string& content) { + clear(); + push_back(BerValue(content)); + return *this; + } + BerValues& operator+=(const BerValue& value) { + push_back(value); + return *this; + } + std::string print(int indent=0, int indentStep = 4) { + std::stringstream ss; + if (size()==1) { + ss<print(indent+2, indentStep) + < reader): + _reader(reader) { + } + + /// Set smart card reader. + void reader(mrw::Shared reader) { + _reader = reader; + } + + //@} + + //------------------------------------------------------------------------ + /// @name Basic CardOS Commands + //@{ + + //! Activates a deactivated file or file tree. + /*! This command reactivates the current file in the file + system. If there were any child files (file tree), they can + subsequently be selected and thus used again. The command + will not return an error, if the current file is already + active. + + @prereq The command can only be executed, if the right + referenced by the file’s AC ACTIVATE is granted in + the security status of the current DF. The command + cannot be applied to CODE files. */ + void activateFile() { + check(send(0x00, 0x44, 0x00, 0x00)); + } + + //! Manages the transaction buffer for command transactions + //! and/or command sequence transactions + /*! The command allocates or frees a transaction buffer + + In case of mode Allocate a possibly existing old buffer + block is marked as unused and a new block with size HI-LO is + initialized. The ID of the new buffer is returned as + response. After the command has been executed successfully, + all the EEPROM contents, which will be affected by a command + with the setting AutoTR=ON, will be stored in the allocated + EEPROM buffer, so that in case of an unforeseen interruption + the former EEPROM state can be restored after the next reset + (see also SET TRANSACTION STATE command). + + In case of mode Free, the buffer with the ID in P2 will not + be used anymore. + + The recommended buffer size is 300 bytes. A small buffer + will increase the EEPROM stress. + + Buffers should be allocated and freed again by the + application to reduce the EEPROM stress. + + + + + + + + + + + + + + +
Bytes P1-P2
P1 (MODE)P2Meaning
Bit 7Bits 6 – 0
1HI valueLO valueAllocate buffer with size HI-LO
0rfuIDFree buffer with ID in P2
+ + @prereq The command can only be executed, if the right + referenced by the MF’s AC ALLOCATE is granted. + + @returns 1 byte: ID of allocated buffer + + @see freeTransactionBuffer */ + std::string allocateTransactionBuffer(unsigned short size) { + if (size>0x7FFF) throw std::runtime_error("requested buffer too large"); + return check(send(0x80, 0x12, 8|size>>8, size&0xFF)); + } + + //! Free transaction buffer + /*! @see allocateTransactionBuffer */ + void freeTransactionBuffer(unsigned char id) { + check(send(0x80, 0x12, 0x00, id)); + } + + //! Creates a new record in a record oriented file + /*! This command creates a new record in the currently selected + file, or, if P2 is not 00h, in the file, which is referenced + by the Short File Identifier (SFI). The command can only be + used on LINEAR FIXED, CYCLIC FIXED and LINEAR TLV files. + + In the parameter EF-ID a file ID can be specified with an + SFI. See table 3.4-1 for its format. The thus referenced + file will then be selected. + + EF-ID Byte P2: + - 0x00 → use current EF + - bits 7-3 = ppppp, bits 2-0=0 → use SFI ppppp (11111 not allowed) + - other value → rfu + + If an SFI is present the actual FID to be used is built by + adding the constant value FE00h to the specified SFI. + + The Record_Data contain the contents of the new record. The + length of the Record_Data must not be more than 254 bytes. + + For LINEAR FIXED or CYCLIC FIXED files the length of the + Record_Data must match the length, which was specified by + the belonging CREATE FILE command. + + For LINEAR TLV files the command data field must have a + valid TLV format. + + If there is not sufficient file memory to store the new + record, an error message is generated for all files, except + for a CYCLIC FIXED file, where the previous record will be + overwritten (same behavior as UPDATE RECORD in PREV mode). + + For all of file types the newly written record becomes the + current record. For CYCLIC FIXED files the newly written + record becomes the logical first record. + + For LINEAR TLV files it is assumed that the length field of + the record consists of one byte. The tag byte is not + interpreted by APPEND RECORD. + + @prereq The command can only be executed, if the right + referenced by the file’s AC APPEND is granted in the + security status of the current DF. */ + void appendRecord(unsigned char efId, std::string data) { + check(send(0x00, 0xE2, 0x00, efId, data)); + } + + //! Computes a digital signature of internally hashed data + //! provided by the application and the card itself in order to + //! authenticate the card to the application. + /*! The CARD AUTHENTICATE command allows to check a card’s + authenticity before personalization takes place. It returns + a digital signature, which is computed over an internal hash + value. + + Inputs for the hash value calculation are: + - The System_Challenge (s. Command Data Field) + - the command header of the CARD AUTHENTICATE command + (CLA, INS, P1, P2) + - the global life cycle phase (s. GET DATA command, mode 83h) + - the number of loaded Packages (s. GET DATA command, mode 88h) + - the system internal parameters (9 bytes consisting 22h) and + - optionally, the Chip Unique Identification Number + (as indicated in mode byte P1, @refs getData, mode 81h, + Bytes 11-16). + + The commands supports 2 modes indicated by the parameter P1: + - 0x01: The Chip Unique Identification Number is not used for + the calculation of the hash value + - 0x02: Include the Chip Unique Identification Number for the + calculation of hash value + + The mode 01h can be used to compute a constant signature for + different cards of the same CardOS version, depending on + their global life cycle phase and loaded system packages + that use the system internal data The command uses a + 1536-bit private RSA2_SIG_SHA-1 key stored in ROM, see + chapter 2.4.2.4 + + + + + + + + + + + + + + + + + + +
Format of the input for hash value calculation
System_ChallengeCommand Header
CLA INS P1 P2
Global Life Cycle PhaseInternal ParametersNumber of loaded PackagesChip Unique Identification Number (opt.)
xxh…xxh80h 88h Mode 00hxxh22h…22hxxhxxh…xxh
n bytes4 bytes1 byte9 bytes1 byte6 bytes/empty
+ + @prereq The System_Challenge provided by the application + must be greater or equal to 16 bytes. Since the + command does not support chaining, the length of the + System_Challenge is limited by the IO buffer size. + + @note The application must use the corresponding RSA2 public + key to verify the Digital Signature received from the + card and thus establishes the card’s authenticity. The + RSA2 public key is contained in the CardOS V4.4 PRNs. + + @return Digital Signature */ + std::string cardAuthenticate(bool hashInclIdentNum, + std::string systemChallange) { + return check(send(0x80, 0x88, hashInclIdentNum?0x01:0x02, 0x00, + systemChallange)); + } + + //! Changes the object data of any BS object except for PIN TEST objects + void changeKeyData() { + assert(!"not implemented"); + } + + //! Changes the object data of a PIN TEST object + /** Changes a PIN. */ + void changeReferenceData(unsigned char id, std::string newData, + std::string oldData=std::string()) { + check(send(0x00, 0x24, oldData.size()?0x00:0x01, id, oldData+newData)); + } + + //! Changes the data of a system key to the new key data + //! provided with the command. + void changeSystemKey() { + assert(!"not implemented"); + } + + //! Creates a file (only EF or DF) + void createFile(BerValue) { + // check(send(0x00, 0xE0, 0x00, 0x00, BerValue(0x62h, + // data).raw())); + assert(!"not implemented"); + } + + //! Deactivates a file or a file tree + void deactivateFile() { + assert(!"not implemented"); + } + + //! Decreases a record value + void decrease() { + assert(!"not implemented"); + } + + //! Deletes a file (DF or EF) + void deleteFile() { + assert(!"not implemented"); + } + + enum FileTypes {DF=0x00, EF=0x01, DF_EF=0x02}; + + //! Reads file information of EFs and/or DFs in the current DF + BerValue directory(FileTypes types, unsigned char offset=0) { + return BerValue(check(send(0x80, 0x16, types, offset))); + } + + //! Enables an already loaded and activated but disabled license package. + void enablePackage() { + assert(!"not implemented"); + } + + //! Erases the file system in the EEPROM. + void eraseFiles() { + assert(!"not implemented"); + } + + //! Performs a challenge/response test + void externalAuthenticate() { + assert(!"not implemented"); + } + + //! Changes the life cycle phase from MANUFACTURING to + //! ADMINISTRATION after creation of the MF or changes only from + //! MANUFACTURING to INITIALIZATION. + void format() { + assert(!"not implemented"); + } + + //! Generates a key pair for the RSA/RSA2 algorithms within the card + void generateKeyPair() { + assert(!"not implemented"); + } + + //! Generates an internal random number (i.e. SC_Challenge) + void getChallange() { + assert(!"not implemented"); + } + + //! Reads system information + std::string getData(unsigned char mode) { + return check(send(0x00, 0xCA, 0x01, mode)); + } + + //! Product name, version, release date, copyright string + std::string getDataProductName() { + return getData(0x80); + } + + struct ChipProductionData { + std::string serial; + unsigned char type; + std::string id; + }; + + //! Chip production data as supplied by Infineon, PROM area + ChipProductionData getDataChipProduction() { + std::string code(getData(0x81)); + ChipProductionData res = { + code.substr(8, 8), + (unsigned char)code[9], + code.substr(11, 6) + }; + return res; + } + + //! Transmits an external random number (i.e. System_Random) to + //! the smart card + /*! The command transmits an external random number of n bytes + the so-called System_Random to the smart card. System_Random + will be used for the next response- SM (SIG or ENC_SIG) + calculation. Valid values for n in short APDU mode are in + the range 1 – 256. In extended APDU mode nmax is dependent + on the preset data field length (nmax = data field length). + + The external random number System_Random can be used only + once. System_Random is valid during the same smart card + session until it has been used by response-SM or until it is + overwritten by a new GIVE RANDOM command. + + The external random number is stored in the XRAM of the + smart card. */ + void giveRandom(std::string random) { + check(send(0x80, 0x86, 0x00, 0x00, random)); + } + + //! Increases a record value + /** This command increases the value of the current record of a + cyclic fixed file by the @p size. + + EF-ID Byte P2: + - 0x00 → use current EF + - bits 7-3 = ppppp, bits 2-0=0 → use SFI ppppp (11111 not allowed) + - other value → rfu */ + std::string increase(unsigned char efId=0, unsigned short size=1) { + std::string data; + data.resize(2); + data[0] = size>>8; + data[1] = size&0xff; + return check(send(0x08, 0x32, 0x00, efId, data)); // 0x08 or 0x80? + // old code was 0x80, manual says 0x08 (manual exactly says: "8xh") + } + + //! Manufacturer use only + void initializeEeprom() { + assert(!"not implemented"); + } + + //! Manufacturer use only + void initializeEnd() { + assert(!"not implemented"); + } + + //! Performs cryptographic algorithms for authentication + void internalAuthenticate() { + assert(!"not implemented"); + } + + //! Activates a package + void loadExecutable() { + assert(!"not implemented"); + } + + //! Opens or closes a logical channel + std::string manageChannel(unsigned char mode, unsigned char channelId) { + return check(send(0x00, 0x70, mode, channelId)); + } + + //! Loads a CSE (RESTORE) or sets a component of the CSE (SET) + //! and/or sets an extended headerlist + void manageSecureEnvironment() { + assert(!"not implemented"); + } + + //! Performs a challenge/response test and a subsequent + //! MAC/Signature calculation and, depending on the input, a + //! session key derivation. + void mutualAuthenticate() { + assert(!"not implemented"); + } + + //! Performs a cryptographic operation + void performSecurityOperation() { + assert(!"not implemented"); + } + + //! Controls the command sequence transactions + void performTransactonOperation() { + assert(!"not implemented"); + } + + //! Personalizer use only + void personalize() { + assert(!"not implemented"); + } + + //! Changes from life cycle phase ADMINISTRATION to OPERATIONAL + //! and vice versa. + /*! The command changes theglobal life cycle phase of the smart + card from ADMINISTRATION to OPERATIONAL. This change is + permanently valid for all DFs and will be stored in EEPROM, + i.e. this life cycle phase is still valid after a reset of + the smart card. + + The change from life cycle phase OPERATIONAL to + ADMINISTRATION, however, is only temporary and valid only + for the current DF (current life cycle phase) The life cycle + phase is set back to OPERATIONAL when a context change + (selection of a different DF) occurs or after a reset of the + smart card. If the current life cycle phase shall be changed + to ADMINISTRATION in several DFs, a PHASE CONTROL command + has to be issued each time after the selection of one of + those DFs. The temporary change to ADMINISTRATION in one DF + can also be undone (without reset) with another PHASE + CONTROL command. + + @prereq Changing from ADMINISTRATION to OPERATIONAL is not + protected. Changing from OPERATIONAL to + ADMINISTRATION is controlled by the right referenced + by the current DF’s AC LCYCLE. + + @prereq The command can be executed in the life cycle phases + ADMINISTRATION and OPERATIONAL. */ + void phaseControl() { + check(send(0x80, 0x10, 0x00, 0x00)); + } + + //! Installs / administrates / overwrites different objects + void putData() { + assert(!"not implemented"); + } + + //! Read a BINARY file + std::string readBinary(unsigned short offset = 0) { + return check(send(0x00, 0xB0, offset>>8, offset&0xFF)); + } + + enum ReadRecordMode { + FIRST_RECORD =0, + LAST_RECORD = 1, + NEXT_RECORD = 2, + PREVIOUS_RECORD = 3, + CURRENT_RECORD = 4, + ABSOLUTE_RECORD = 4 + }; + + //! Read a record oriented file + std::string readRecord(unsigned char record = 0, + unsigned char sfi = 0, + ReadRecordMode mode = ABSOLUTE_RECORD) { + return check(send(0x00, 0xB2, record, (sfi&0xF8)|mode)); + } + + /// Read all records from a record oriented file + BerValues readBerFile() { + BerValues content; + while (true) { + std::string res(send(0x00, 0xB2, 0, NEXT_RECORD)); + if (cardos::Commands::retCode(res)!=0x9000) break; + content += BerValue(retData(res).substr(2)); + } + return content; + } + + //! Resets the error counter of a BS object to its maximum + void resetRetryCounter() { + assert(!"not implemented"); + } + + //! Resets the security status of the current DF + void resetSecurityCounter() { + assert(!"not implemented"); + } + + enum FileSelectionMode { + DF_OR_EF_DIRECTLY_BELOW_CURRENT_DF_USING_FILE_ID = 0x00, + DF_DIRECTLY_BELOW_CURRENT_DF_USING_FILE_ID = 0x01, + EF_DIRECTLY_BELOW_CURRENT_DF_USING_FILE_ID = 0x02, + PARENT_DF_OF_CURRENT_DF = 0x03, + DF_BY_NAME = 0x04, + DF_OR_EF_USING_PATH_FROM_MF = 0x08, + DF_OR_EF_USING_PATH_FROM_CURRENT_DF = 0x09 + }; + + enum FileSelectionReturn { + RETURN_FCI_DATA = 0x00, + RETURN_FCP_DATA = 0x04, + RETURN_NOTHING = 0x0C + }; + + //! Selects a file + BerValue selectFile(std::string file, + FileSelectionMode mode + = DF_OR_EF_USING_PATH_FROM_MF, + FileSelectionReturn ret + = RETURN_NOTHING) { + return BerValue(check(send(0x00, 0xA4, mode, ret, file))); + } + + //! Sets the so-called Data_Field_Length parameter relevant for + //! the effective Command Data Field Length / Response Data + //! Field Length. + void setDataFieldLength() { + assert(!"not implemented"); + } + + //! Enables or disables the usage of an existing transaction buffer + void setTransactionState() { + assert(!"not implemented"); + } + + //! Signs a hashed input using a decryption key with the RSA_SIG + //! algorithm. + void signByDecryptionKey() { + assert(!"not implemented"); + } + + //! Uninstalls a package of the smart card + void uninstallPackage() { + assert(!"not implemented"); + } + + /// Read the previously file from smart card + std::string readBinFile() { + return check(send(0x00, 0xB0, 0x00, 0x00)); + } + + //! Updates a BINARY file + void updateBinary(std::string data, unsigned short offset=0) { + check(send(0x00, 0xD6, offset>>8, offset&0xFF, data)); + } + + //! Overwrites an existing record. + std::string updateRecord(std::string data, + unsigned char record = 0, + unsigned char sfi = 0, + ReadRecordMode mode = ABSOLUTE_RECORD) { + return check(send(0x00, 0xDC, record, (sfi&0xF8)|mode, data)); + } + + enum VerifyMode { + SEARCH_IN_MF = 0, + SEARCH_FROM_DF = 0x80 + }; + + //! Performs a PIN test (CHV test) + void verify(std::string pin, unsigned char id, + VerifyMode mode = SEARCH_FROM_DF) { + check(send(0x00, 0x20, 0x00, id|mode, pin)); + } + + //! Performs a PIN test (CHV test) + /*! @return number of remaining PIN retries or -1 if PIN is locked */ + int verify(unsigned char id, VerifyMode mode = SEARCH_FROM_DF) { + std::string res(send(0x00, 0x20, 0x00, id|mode)); + unsigned int value((((unsigned int)(unsigned char)res[0])*256) + +((unsigned int)(unsigned char)res[1])); + if ((value&0x63C0)==0x63C0) return value&0x0F; + return -1; + } + + //@} + + //------------------------------------------------------------------------ + /// @name Files and IDs on a Smart Card + //@{ + + /// Path to MF + std::string mf() { + return crypto::hexToBin("3f00"); + } + + /// Path to PKCS#15 + std::string pkcs15() { + return crypto::hexToBin("5015"); + } + + /// Path to SigG (Signaturgesetz) + std::string sigg() { + return crypto::hexToBin("1fff"); + } + + /// ID of transport PIN + unsigned char transportPin() { + return 0x71; + } + + /// ID of PKCS#15 user PIN + unsigned char pkcs15Pin() { + return 0x01; + } + + /// ID of SigG (Signaturgesetz) secure PIN + unsigned char sigGPin() { + return 0x01; + } + + /// ID of PUK to unlock PKCS#15 user PIN + unsigned char puk() { + return 0x02; + } + + //@} + + //------------------------------------------------------------------------ + /// @name High Level Smart Card Access + //@{ + + /// Logon with transport PIN + void logonTransport(std::string pin) { + selectSigG(); + logon(transportPin(), pin); + } + + /// Logon with SigG (Signaturgesetz) secure PIN + void logonSigG(std::string pin) { + selectSigG(); + logon(sigGPin(), pin); + } + + /// Logon with PKCS#15 user PUK to unlock user PIN + void logonPuk(std::string pin) { + selectMF(); + logon(puk(), pin); + } + + /// Logon with PKCS#15 user PIN + void logonPkcs15(std::string pin) { + selectMF(); + logon(pkcs15Pin(), pin); + } + + /// Change SigG (Signaturgesetz) secure PIN + /** If smart card is in transport state, @p oldPin must be + transport PIN and then the card is unlocked and the + transport state is unset. */ + void changeSigGPin(std::string newPin, std::string oldPin) { + selectSigG(); + if (transportState()) { // first time use, reset transport state + logonTransport(oldPin); + changeReferenceData(sigGPin(), newPin); + unsetTransportState(); + } else { // ordinary PIN change + changeReferenceData(sigGPin(), newPin, oldPin); + } + } + + /// Change PKCS#15 user PIN + void changePkcs15Pin(std::string newPin, std::string oldPin) { + selectMF(); + changeReferenceData(pkcs15Pin(), newPin, oldPin); + } + + /// Change PKCS#15 user PIN + /** To keep all PINs synchronized: Detect if it is in transport + state, if so, old PIN must be transport PIN. in any case, + change PIN on PKCS#15 and SigG from the same old PIN to the + same new PIN. */ + void changePin(std::string newPin, std::string oldPin) { + try { + changePkcs15Pin(newPin, oldPin); + try { + changeSigGPin(newPin, oldPin); + } catch (...) { + changePkcs15Pin(oldPin, newPin); // undo PKCS#15 PIN change + throw; // change SigG PIN failed + } + } catch (...) { + throw; // change PKCS#15 PIN failed + } + } + + /// Select a file in the PKCS#15 part on the smart card + void selectPkcs15File(std::string file) { + check(send(0x00, 0xA4, 0x08, 0x0C, crypto::hexToBin("3f005015"+file))); + } + + /// Select a file in the SigG (Signaturgesetz) part on the smart card + void selectSigGFile(std::string file) { + check(send(0x00, 0xA4, 0x08, 0x0C, crypto::hexToBin("3f001fff"+file))); + } + + /// Select a file in the MF part on the smart card + void selectMfFile(std::string file) { + check(send(0x00, 0xA4, 0x08, 0x0C, crypto::hexToBin("3f00"+file))); + } + + /// Select the PKCS#15 part on the smart card + void selectPkcs15() { + check(send(0x00, 0xA4, 0x08, 0x0C, crypto::hexToBin("3f005015"))); + } + + /// Select the SigG (Signaturgesetz) part on the smart card + void selectSigG() { + check(send(0x00, 0xA4, 0x08, 0x0C, crypto::hexToBin("3f001fff"))); + } + + /// Select the MFpart on the smart card + void selectMF() { + check(send(0x00, 0xA4, 0x00, 0x0C)); + } + + /// @return binary serial number + std::string serial() { + return getDataChipProduction().serial; + } + + /// @return @c true if card is still in transport state + bool transportState() { + selectSigGFile("fe15"); + return std::string(4, '\0')==readBinary(); + } + + /// Mark card as initiakized and no more in transport state + void unsetTransportState() { + selectSigGFile("fe15"); + increase(); + } + + /*! @return number of remaining transport PIN retries or -1 if locked */ + int transportPinRetries() { + selectSigG(); + return verify(transportPin()); + } + + /*! @return number of remaining PKCS#15 PIN retries or -1 if locked */ + int pkcs15PinRetries() { + selectMF(); + return verify(pkcs15Pin()); + } + + /*! @return number of remaining SigG PIN retries or -1 if locked */ + int sigGPinRetries() { + selectSigG(); + return verify(sigGPin()); + } + + /*! @return number of remaining PUK retries or -1 if locked */ + int pukRetries() { + selectMF(); + return verify(puk()); + } + + //@} + + protected: + + /// @name More Generic Internal Auxiliary Methods + //@{ + + void logon(unsigned char id, std::string pin) { + verify(pin, id); + } + + int pinStatus(unsigned char id) { + std::string res(send(0x00, 0x20, 0x00, id|0x80)); + unsigned int value((((unsigned int)(unsigned char)res[0])*256) + +((unsigned int)(unsigned char)res[1])); + switch (value) { + case 0x6983: CARDOS_LOG("LOCKED"); return -1; + case 0x63Ca: CARDOS_LOG("TEN"); return 10; + case 0x63C9: CARDOS_LOG("NINE"); return 9; + case 0x63C8: CARDOS_LOG("EIGHT"); return 8; + case 0x63C7: CARDOS_LOG("SEVEN"); return 7; + case 0x63C6: CARDOS_LOG("SIX"); return 6; + case 0x63C5: CARDOS_LOG("FIVE"); return 5; + case 0x63C4: CARDOS_LOG("FOUR"); return 4; + case 0x63C3: CARDOS_LOG("THREE"); return 3; + case 0x63C2: CARDOS_LOG("TWO"); return 2; + case 0x63C1: CARDOS_LOG("ONE"); return 1; + case 0x63C0: CARDOS_LOG("ZERO"); return 0; + case 0x6300: CARDOS_LOG("LOCKED"); return -1; + default: CARDOS_LOG("UNKNOWN"); return -1; + } + } + + std::string sendAPDU(std::string data) { + if (data.size()==4) + return send(data[0], data[1], data[2], data[3]); + else if (data.size()>4) + return send(data[0], data[1], data[2], data[3], data.substr(4)); + else + throw std::runtime_error("wrong APDU pass at least 4 bytes in hex"); + } + + //! @return error text of APDU result string + static std::string error(std::string res) { + return error(retCode(res)); + } + + //! @return error text of return code evaluated by @ref retCode + static std::string error(int ret) { + switch (ret) { + case 0x6283: + return "File is deactivated (see DEACTIVATE FILE command)"; + case 0x6285: + return "File is terminated"; + case 0x6300: + return "Authentication failed"; + case 0x6581: + return "EEPROM error; command aborted"; + case 0x6700: + return "LC invalid"; + case 0x6881: + return "Logical channel not supported"; + case 0x6882: + return "SM mode not supported"; + case 0x6884: + return "Chaining Error"; + case 0x6981: + return "Command cannot be used for file structure"; + case 0x6982: + return "Required access right not granted"; + case 0x6983: + return "BS object blocked"; + case 0x6984: + return "BS object has invalid format"; + case 0x6985: + return + "Conditions of use not satisfied; no random number available"; + case 0x6986: + return "no current EF selected"; + case 0x6987: + return "Key object for SM not found"; + case 0x6988: + return "Key object used for SM has invalid format"; + case 0x6a80: + return "Invalid parameters in data field"; + case 0x6a81: + return "Function / mode not supported"; + case 0x6a82: + return "File not found"; + case 0x6a83: + return "Record / object not found"; + case 0x6a84: + return + "Not enough memory in file / in file system (e.g. CREATE FILE)" + " available"; + case 0x6a85: + return "LC does not fit the TLV structure of the data field"; + case 0x6a86: + return "P1 / P2 invalid"; + case 0x6a87: + return "LC does not fit P1 /P2"; + case 0x6a88: + return "Object not found (GET DATA)"; + case 0x6a89: + return "File already exists"; + case 0x6a8a: + return "DF name already exists"; + case 0x6c00: + return "LE does not fit the data to be sent (e.g. SM)"; + case 0x6d00: + return "INS invalid"; + case 0x6e00: + return "CLA invalid (Hi nibble)"; + case 0x6f00: + return + "Technical Error:\n" + " 1 Attempt to create more than 254 records in a file.\n" + " 2 Package uses SDK version which is not compatible to" + " API version\n" + " 3 Package contains invalid statements (LOAD EXECUTABLE)"; + case 0x6f81: + return "File is invalidated because of checksum error (prop.)"; + case 0x6f82: + return "Not enough memory available in XRAM"; + case 0x6f83: + return + "Transaction error (i.e. command must not be used in a" + " transaction)"; + case 0x6f84: + return "General protection fault (prop.)"; + case 0x6f85: + return "Internal failure of PK-API (e.g. wrong CCMS format)"; + case 0x6f86: + return "Key Object not found"; + case 0x6f87: + return + "Internal hardware attack detected, change to life cycle death"; + case 0x6f88: + return "Transaction buffer too small"; + case 0x6fff: + return + "Internal assertion (invalid internal error)\n" + "This error is no runtime error but an internal error which can" + " occur because of a programming error only."; + case 0x9000: + return "Command executed correctly"; + case 0x9001: + return + "Command executed correctly; EEPROM weakness detected" + " (EEPROM written with second trial; the EEPROM area" + " overwritten has a limited life time only.)"; + case 0x9850: + return "Overflow through INCREASE / underflow through DECREASE"; + case -1: + return "No return code received"; + default: + std::stringstream ss; + if ((ret&&0xff00)==0x6100) + ss<<(ret&&0xff)<<" bytes of response data can be received" + <<" with GET RESPONSE (only T=0 transmission protocol)"; + else + ss<<"Unknown CardOS error code: 0x"<=2) + return ((((unsigned int)(unsigned char)res[res.size()-2])*256) + +((unsigned int)(unsigned char)res[res.size()-1])); + else + return -1; + } + + static std::string retData(const std::string& res) { + if (res.size()>=2) + return res.substr(0, res.size()-2); + else + return std::string(); + } + + std::string check(std::string res) { + unsigned int value(retCode(res)); + if (value!=0x9000) throw std::runtime_error(error(value)); + return retData(res); + } + + std::string logResult(const std::string& result) { + std::string txt; + for (std::string::const_iterator it(result.begin()); + it!=result.end(); ++it) + txt += isprint(*it)?*it:'.'; + if (result.size()>=2) { + CARDOS_LOG(error(result)<2) { + CARDOS_LOG("Data: " + <transmit(0x00, 0xA4, 0x08, 0x0C, "\x1F\xFF\xFE\x15", 4), + "select file \"transport protection state\""); + // 2. read PIN_T's current use counter value + std::string res(check(_reader->transmit(0x00, 0xB2, 0x00, 0x04), + "read PIN_T counter")); + if (res.size()!=6) throw wrong_result("cannot check for first use"); + return res.substr(0, 4)==std::string("\0\0\0\0", 4); // uninitialized: 0 + } + + //! get file version info + /*! @return Content of file "Version Info" or "" if + there's no such file */ + + + void unlock(const std::string puk, const std::string pin, + bool force=false) { +// #ifndef Q_OS_MAC +// pcsc::Connection::Reader::Transaction lock(_reader); +// #endif +// check(_reader->transmit(0x00, 0xA4, 0x00, 0x0C), "select MF"); +// try { +// check(_reader->transmit(0x00, 0x20, 0x00, 0x02, puk), "verify PUK"); +// } catch (std::exception& e) { +// throw wrong_puk(std::string("verify user PUK failed: ")+e.what()); +// } +// if (force) { // kill old dig sig +// while (checkDigSigPin().valid()) +// try { +// check(_reader->transmit(0x00, 0xA4, 0x08, 0x0C, +// "\x1F\xFF\xFE\x15", 4), +// "select SigG"); +// check(_reader->transmit(0x00, 0x20, 0x00, 0x81, pin), +// "verify for correct old PIN in SigG"); +// break; // ok, pin still vaild, user is a winner +// } catch (...) {} // normally ends up here, retry until broken +// } else { +// if (checkDigSigPin().valid()) try { +// check(_reader->transmit(0x00, 0xA4, 0x08, 0x0C, +// "\x1F\xFF\xFE\x15", 4), +// "select SigG"); +// check(_reader->transmit(0x00, 0x20, 0x00, 0x81, pin), +// "verify for correct old PIN in SigG"); +// } catch (std::exception& e) { +// throw wrong_pin(std::string("verify SigG PIN failed: ")+e.what()); +// } +// } +// check(_reader->transmit(0x00, 0xA4, 0x00, 0x0C), "select MF"); +// check(_reader->transmit(0x00, 0x24, 0x01, 0x81, pin), "reset user PIN"); + } + + void changePin(const std::string oldPin, const std::string newPin) { +// #ifndef Q_OS_MAC +// pcsc::Connection::Reader::Transaction lock(_reader); +// #endif +// if (version()==PZ2007||firstUse()) { +// changePinSigG(oldPin, newPin); +// changePinPkcs15(oldPin, newPin); +// } else { +// if (checkUserPin().locked()) +// throw user_pin_locked("pin change is not possible"); +// changePinPkcs15(oldPin, newPin); +// if (!checkDigSigPin().locked()) +// changePinSigG(oldPin, newPin); +// } + } + + void changePinSigG(const std::string oldPin, const std::string newPin) { +// #ifndef Q_OS_MAC +// pcsc::Connection::Reader::Transaction lock(_reader); +// #endif +// bool first(firstUse()); +// // select DF SigG /1/ #236 +// check(_reader->transmit(0x00, 0xA4, 0x08, 0x0C, "\x1F\xFF\xFE\x15", 4), +// "select DF SigG"); +// try { +// if (first) // verify PIN_T /1/ #248 (optional!) +// check(_reader->transmit(0x00, 0x20, 0x00, 0xF1, oldPin), +// "verify PIN_T"); +// else // verify PIN (not in transport state) +// check(_reader->transmit(0x00, 0x20, 0x00, 0x81, oldPin), +// "verify PIN"); +// } catch (const std::exception& e) { +// throw wrong_pin(std::string("verify SigG-PIN failed: ")+e.what()); +// } +// // change reference data SigG-PIN /1/ #125,81 +// if (first) +// check(_reader->transmit(0x00, 0x24, 0x01, 0x81, newPin), +// "change reference data SigG-PIN first time"); +// else +// check(_reader->transmit(0x00, 0x24, 0x00, 0x81, oldPin+newPin), +// "change reference data SigG-PIN"); +// // mark pin as changed, no more transport state +// for (int i(0); true; ++i) try { // «bugfix» for freddy: multiple tries +// if (first) +// check(_reader->transmit(0x80, 0x32, 0x00, 0x00, "\x01", 1), +// "mark pin as changed"); +// break; // jump out of the loop, all everything is ok +// } catch (...) { // retry up to 10 times +// if (i>=10) throw; +// } + } + + void changePinPkcs15(const std::string oldPin, const std::string newPin) { +// #ifndef Q_OS_MAC +// pcsc::Connection::Reader::Transaction lock(_reader); +// #endif +// // select MF +// check(_reader->transmit(0x00, 0xA4, 0x08, 0x0C, "\x3F\x00", 2), +// "select MF"); +// try { +// // change reference data | Use PIN ID +// check(_reader->transmit(0x00, 0x24, 0x00, 0x01, oldPin+newPin), +// "set new PIN"); +// } catch (const std::exception& e) { +// throw wrong_pin(std::string("verify PKCS#15-PIN failed: ") +// +e.what()); +// } +// // select DF PKCS#15 +// check(_reader->transmit(0x00, 0xA4, 0x08, 0x0C, "\x50\x15", 2), +// "select DF PKCS#15"); + } + + static unsigned int retCode(const std::string& res) { + if (res.size()>=2) + return ((((unsigned int)(unsigned char)res[res.size()-2])*256) + +((unsigned int)(unsigned char)res[res.size()-1])); + else + return -1; + } + + private: + + friend class CardOsTest; + + //! ANSI Padding: Fill to 8 byte blocks with @c 0x00 + static std::string ansiPadding(std::string data) { + while (data.size()%8!=0) data += (char)0x00; + return data; + } + + //! ISO Padding: mark end with @c 0x80, then do @ref ansiPadding + static std::string isoPadding(std::string data) { + data += (char)0x80; // command+ISO_Padding_Byte(0x80) + return ansiPadding(data); + } + + static std::string des3enc(const std::string& data, + const openssl::CBlock8& key1, + const openssl::CBlock8& key2) { + // initial vector is always 0 + return openssl::des2edeCbcEnc(isoPadding(data), key1, key2); + } + + // retail mac signature + static std::string sign(const std::string& data, + const openssl::CBlock8& key1, + const openssl::CBlock8& key2) { + // initial vector is 0 anyway... + openssl::CBlock8 ivec; + openssl::desCbcEnc(isoPadding(data), key1, ivec); + return openssl::desCbcEnc(openssl::desCbcDec(ivec, key2), key1); + } + + const std::string& check(const std::string& res, + const std::string& position) const { + // static unsigned long SUCCESS(0x9000); + // unsigned long c(retCode(res)); + // if (c!=SUCCESS) throw card_transmission_failed(position, + // Commands::error(c)); + return res; + } + + //======================================================================== + + private: + + mrw::Shared _reader; + + }; + +} +//@} + +#endif diff --git a/src/cryptaux.hxx b/src/cryptaux.hxx index eaa9a72..f113c36 100644 --- a/src/cryptaux.hxx +++ b/src/cryptaux.hxx @@ -11,6 +11,8 @@ #include #include #include +#include +#include /*! @defgroup gcrypto Auxiliary Crypto-Functions */ //@{ @@ -65,6 +67,44 @@ namespace crypto { else return "\""+data+"\""; } + + //! Convert binary to readable hexadecimal + inline std::string binToHex(char c) { + std::stringstream ss; + ss<id(), strconv(name).c_str(), mode, protocol, &_id, &_protocol), - "connect smartcard \""+name); + "connect smartcard \""+name+"\""); } //! forbidden diff --git a/src/suisseid.hxx b/src/suisseid.hxx new file mode 100644 index 0000000..edd7847 --- /dev/null +++ b/src/suisseid.hxx @@ -0,0 +1,200 @@ +/*! @file + + @id $Id$ +*/ +// 1 2 3 4 5 6 7 8 +// 45678901234567890123456789012345678901234567890123456789012345678901234567890 + +#ifndef __SUISSEID_HXX__ +#define __SUISSEID_HXX__ + +#include +#include +#include +#include +#include + +/*! @defgroup gsuisseid C+ Wrapper to access SuisseID smart cards + + This library allows access to the Swiss digital identity cards + (SuisseID). + + You need to include @ref suisseid.hxx, then start with class @ref + suisseid::Scanner to scan for a list of SuisseID cards on the system. + + @see http://www.suisseid.ch + @see http://postsuisseid.ch */ +//@{ +namespace suisseid { + + //! Represents a SuisseID Card + /*! This is the parent class for special classes for the respecive + SuisseID providers. */ + class Card: public cardos::Commands { + + public: + + enum Status { + TRANSPORT + }; + + public: + + Card(mrw::Shared reader, + mrw::Shared slot): + cardos::Commands(reader), + _slot(slot) { + } + virtual ~Card() {} + + virtual unsigned int minimalPinLength() = 0; + virtual unsigned int maximalPinLength() = 0; + + //! Name of the token/slot + const std::string& name() { + return _reader->name; + } + + /// Version of the card + virtual std::string version() { + return ""; + } + + private: + + mrw::Shared _slot; + + }; + + //! Instance of a Post SuisseID smartcard. + /*! A SuisseID card issued by Swiss Post. + @see http://postsuisseid.ch */ + class PostSuisseID: public Card { + + public: + + PostSuisseID(mrw::Shared reader, + mrw::Shared slot): + Card(reader, slot), _minPinLen(0), _maxPinLen(-1) { + } + + virtual unsigned int minimalPinLength() { + if (_minPinLen==0) evaluatePinLengths(); + return _minPinLen; + } + + virtual unsigned int maximalPinLength() { + if (_maxPinLen==-1) evaluatePinLengths(); + return _maxPinLen; + } + + std::string version() { + if (_version.size()) return _version; // cache the version + pcsc::Connection::Reader::Transaction lock(_reader); + try { + selectMfFile("5649"); + return _version = cardos::BerValue(readBinary())[0].value(); + } catch (...) { + return _version = ""; + } + } + + private: + + void evaluatePinLengths() { + pcsc::Connection::Reader::Transaction lock(_reader); + selectPkcs15File("4408"); + cardos::BerValues res(readBerFile()); + for (cardos::BerValues::iterator it(res.begin()); it!=res.end(); ++it) + if ((*it)[0][0].value()=="PIN" || + (*it)[0][0].value()=="Digital Signature PIN") { + if ((*it)[2][0][2].toULong()>_minPinLen) + _minPinLen = (*it)[2][0][2].toULong(); + if ((*it)[2][0][4].toULong()<_maxPinLen) + _maxPinLen = (*it)[2][0][4].toULong(); + } + } + + private: + + std::string _version; // version is cached + unsigned int _minPinLen; // minimal PIN length is cached + unsigned int _maxPinLen; // maximal PIN length is cached + }; + + //! List of cards, returned by @ref suisseid::Scanner::scan. + typedef std::vector > Cards; + + //! Auxiliary SuisseID card manager. + /** Use this manager to scan your system for SuisseID cards. + + Usage Example: + + @code + #include + #include + + [...] + + try { + suisseid::Cards cards(suisseid::Scanner().scan()); + for (auto card(cards.begin()); card!=cards.end(); ++card) + std::cout<<"Found SuisseID: "<<(*card)->name()< + (new PostSuisseID(_pcsc.reader(*reader), slots[0]))); + } + return res; + } + + private: + + pcsc::Connection _pcsc; + cryptoki::Library _cryptoki; + + }; + +} +//@} + +#endif