added basic suisse id functions; refs #28
This commit is contained in:
709
doc/doxyfile.in
709
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_DIRECTORIES = NO
|
||||
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_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.
|
||||
|
||||
GENERATE_QHP = NO
|
||||
|
||||
# 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.
|
||||
|
||||
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
|
||||
# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
|
||||
# Qt Help Project / Custom Filters</a>.
|
||||
|
||||
QHP_CUST_FILTER_ATTRS =
|
||||
|
||||
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
|
||||
# project's
|
||||
# filter section matches.
|
||||
# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
|
||||
# Qt Help Project / Filter Attributes</a>.
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
# 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.
|
||||
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
|
||||
# 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
|
||||
# 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 = png
|
||||
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.
|
||||
|
||||
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
|
||||
|
164
doc/examples/cardos-demo.cxx
Normal file
164
doc/examples/cardos-demo.cxx
Normal file
@@ -0,0 +1,164 @@
|
||||
/*! @file
|
||||
|
||||
@id $Id$
|
||||
*/
|
||||
// 1 2 3 4 5 6 7 8
|
||||
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
|
||||
// #include <pcsc.hxx>
|
||||
// #include <cryptaux.hxx>
|
||||
// #include <openssl.hxx>
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <cctype>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
#define CARDOS_LOG(X) std::cout<<X<<std::endl
|
||||
#include <cardos.hxx>
|
||||
|
||||
class Commands: public cardos::Commands {
|
||||
|
||||
public:
|
||||
|
||||
void help() {
|
||||
std::cout
|
||||
<<"Commands: "<<std::endl
|
||||
<<" COMMAND DATA PURPOSE"<<std::endl
|
||||
<<" (h)elp Show this help"<<std::endl
|
||||
<<" (q)quit Quit"<<std::endl
|
||||
<<" (l)ist List all reader"<<std::endl
|
||||
<<" (r)eader <num> Select reader by number"<<std::endl
|
||||
<<" (s)erial Show token serial number"<<std::endl
|
||||
<<" (a)pdu <hex> Send APDU hex data"<<std::endl
|
||||
<<" (m)aster(f)ile Select master file"<<std::endl
|
||||
<<" (p)kcs(15) Select PKCS#15 file"<<std::endl
|
||||
<<" (s)ig(g) Select SigG file"<<std::endl
|
||||
<<" (s)elect(f)ile <hex> Select file below master"<<std::endl
|
||||
<<" (s)elect(p)15(f)ile <hex> Select file below PKCS#15"<<std::endl
|
||||
<<" (s)elect(s)igg(f)ile <hex> Select file below SigG"<<std::endl
|
||||
<<" (r)ead(b)in(f)ile Read selected binary file"<<std::endl
|
||||
<<" (r)ead(a)bsolute(r)ecord Read absolute record"<<std::endl
|
||||
<<" (r)ead(f)irst(r)ecord Read first record"<<std::endl
|
||||
<<" (r)ead(n)ext(r)ecord Read next record"<<std::endl
|
||||
<<" (p)in(s)status <id> Query status of PIN <id>"<<std::endl
|
||||
<<" (l)ogon <id> <pin> logon to key with PIN"<<std::endl
|
||||
<<" (l)ogon(p)15 <pin> logon with user PIN"<<std::endl
|
||||
<<" (l)ogonpu(k) <pin> logon with user PUK"<<std::endl
|
||||
<<" (l)ogon(s)igg <pin> logon with SigG PIN"<<std::endl
|
||||
<<" (l)ogon(t)transport <pin> logon with transport PIN"<<std::endl
|
||||
<<" (g)et(p)in(l)engths get PIN min max lengths"<<std::endl
|
||||
<<"Note: \"(h)elp\" means: type \"help\" or simply \"h\""<<std::endl;
|
||||
}
|
||||
|
||||
int run() {
|
||||
std::string cmd;
|
||||
while (std::cout<<"cmd> ", 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()<<std::endl;
|
||||
else help();
|
||||
} catch (const std::exception& e) {
|
||||
std::cout<<"**** Error: "<<e.what()<<std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void listReader() {
|
||||
_readers = _c.scan();
|
||||
std::cout<<"Found "<<_readers.size()<<" readers"
|
||||
<<(_readers.size()?":":".")<<std::endl;
|
||||
int i(0);
|
||||
for (pcsc::Connection::Strings::const_iterator it(_readers.begin());
|
||||
it!=_readers.end(); ++it, ++i)
|
||||
std::cout<<" "<<i<<". "<<*it<<std::endl;
|
||||
}
|
||||
|
||||
void selectReader() {
|
||||
listReader();
|
||||
if (_readers.size()<0) return;
|
||||
int num(-1);
|
||||
if (std::cin>>num && num>=0 && num<_readers.size()) {
|
||||
_reader = _c.reader(_readers[num]);
|
||||
std::cout<<"Active Reader: "<<_readers[num]<<std::endl;
|
||||
} else throw std::runtime_error("no valid reader selected");
|
||||
}
|
||||
|
||||
void getPinLengths() {
|
||||
selectPkcs15File("4408");
|
||||
_ber.clear();
|
||||
while (true) {
|
||||
std::string res(send(0x00, 0xB2, 0, NEXT_RECORD));
|
||||
if (cardos::Commands::retCode(res)!=0x9000) break;
|
||||
cardos::BerValue record(cardos::Commands::retData(res).substr(2));
|
||||
_ber += record;
|
||||
std::cout<<record[0][0].value()
|
||||
<<": len="
|
||||
<<record[2][0][2].toULong()
|
||||
<<"-"<<record[2][0][4].toULong()<<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::string apdu() {
|
||||
std::string data;
|
||||
if (!(std::cin>>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."<<std::endl;
|
||||
return Commands().run();
|
||||
}
|
@@ -14,11 +14,12 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <algorithm>
|
||||
#include <tuple>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <streambuf>
|
||||
#ifndef MRW__OLD_PRE11_COMPILER
|
||||
#include <chrono>
|
||||
#endif
|
||||
|
||||
|
||||
int main(int argc, char** argv) try {
|
||||
|
@@ -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
|
||||
|
@@ -5,91 +5,12 @@
|
||||
// 1 2 3 4 5 6 7 8
|
||||
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
|
||||
#include <cryptoki.hxx>
|
||||
#include <pcsc.hxx>
|
||||
#include <mrw/args.hxx>
|
||||
#include <mrw/vector.hxx>
|
||||
#include <mrw/shared.hxx>
|
||||
#include <suisseid.hxx>
|
||||
|
||||
#include <mrw/args.hxx>
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
|
||||
namespace suisseid {
|
||||
|
||||
class Card {
|
||||
public:
|
||||
Card(mrw::Shared<pcsc::Connection::Reader> reader,
|
||||
mrw::Shared<cryptoki::Slot> slot):
|
||||
_reader(reader),
|
||||
_slot(slot) {
|
||||
}
|
||||
virtual ~Card() {}
|
||||
const std::string& name() {
|
||||
return _reader->name;
|
||||
}
|
||||
private:
|
||||
mrw::Shared<pcsc::Connection::Reader> _reader;
|
||||
mrw::Shared<cryptoki::Slot> _slot;
|
||||
};
|
||||
|
||||
class PostSuisseID: public Card {
|
||||
public:
|
||||
PostSuisseID(mrw::Shared<pcsc::Connection::Reader> reader,
|
||||
mrw::Shared<cryptoki::Slot> 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<mrw::Shared<Card> > 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<Card*>
|
||||
(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()
|
||||
<<mrw::args::param(lib, "lib")));
|
||||
|
||||
suisseid::Manager suisseid;
|
||||
suisseid::Manager::Cards cards(suisseid.scan());
|
||||
for (suisseid::Manager::Cards::iterator card(cards.begin());
|
||||
card!=cards.end(); ++card)
|
||||
std::cout<<"Found SuisseID: "<<(*card)->name()<<std::endl;
|
||||
suisseid::Cards cards(suisseid::Scanner(lib).scan());
|
||||
for (suisseid::Cards::iterator card(cards.begin()); card!=cards.end(); ++card)
|
||||
std::cout<<"Found SuisseID:"<<std::endl
|
||||
<<" Reader Name: "<<(*card)->name()<<std::endl
|
||||
<<" Version: "<<(*card)->version()<<std::endl
|
||||
<<" PIN-Length: "<<(*card)->minimalPinLength()
|
||||
<<" - "<<(*card)->maximalPinLength()<<std::endl;
|
||||
return 0;
|
||||
} catch (std::exception& x) {
|
||||
std::cerr<<"**** ERROR in "<<*argv<<": "<<x.what()<<std::endl;
|
||||
|
1649
src/cardos.hxx
Normal file
1649
src/cardos.hxx
Normal file
@@ -0,0 +1,1649 @@
|
||||
/*! @file
|
||||
|
||||
@id $Id: cardos.hxx 3826 2012-05-21 12:25:29Z marc $
|
||||
*/
|
||||
// 1 2 3 4 5 6 7 8
|
||||
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
|
||||
#ifndef __CARDOS_HXX__
|
||||
#define __CARDOS_HXX__
|
||||
|
||||
#include <pcsc.hxx>
|
||||
#include <cryptaux.hxx>
|
||||
#include <openssl.hxx>
|
||||
#include <mrw/string.hxx>
|
||||
#include <stdexcept>
|
||||
|
||||
#ifndef CARDOS_LOG
|
||||
#define CARDOS_LOG(X) // no logging by default
|
||||
// use e.g. #define CARDOS_LOG(X) std::cout<<X<<std::endl
|
||||
#endif
|
||||
|
||||
|
||||
namespace cardos {
|
||||
|
||||
/// @defgroup gcardos C++ Access to Siemens CardOS V4.4
|
||||
/** Implements APDUs for accessing Siemens CardOS V4.4 smartcards. */
|
||||
//@{
|
||||
/// @defgroup cardosexception CardOS Exceptions
|
||||
/// @defgroup cardostypes CardOS Types
|
||||
/// @defgroup cardoslib CardOS Library
|
||||
|
||||
/// @addtogroup cardosexception CardOS Exceptions
|
||||
//@{
|
||||
//============================================================================
|
||||
//----------------------------------------------------------------------------
|
||||
class exception: public pcsc::exception {
|
||||
public:
|
||||
exception(const std::string& reason) throw():
|
||||
pcsc::exception("cardos: "+reason) {
|
||||
}
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class wrong_pin: public exception {
|
||||
public:
|
||||
wrong_pin(const std::string& s) throw(): exception("wrong pin\n"+s) {}
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class user_pin_locked: public exception {
|
||||
public:
|
||||
user_pin_locked(const std::string& s) throw():
|
||||
exception("user pin locked\n"+s) {}
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class wrong_puk: public exception {
|
||||
public:
|
||||
wrong_puk(const std::string& s) throw(): exception("wrong puk\n"+s) {}
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class wrong_result: public exception {
|
||||
public:
|
||||
wrong_result(const std::string& reason, const std::string& data) throw():
|
||||
exception("wrong result,\n"+reason+":\n"+crypto::hex(data)) {}
|
||||
wrong_result(const std::string& reason) throw():
|
||||
exception("wrong result,\n"+reason) {}
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class runtime_error: public exception {
|
||||
public:
|
||||
runtime_error(const std::string& reason, const std::string& data) throw():
|
||||
exception("runtime error,\n"+reason+":\n"+crypto::hex(data)) {}
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class unexpected_challenge_length: public exception {
|
||||
public:
|
||||
unexpected_challenge_length(const std::string& data) throw():
|
||||
exception("challenge should be 8 bytes, challenge is:\n"
|
||||
+crypto::hex(data)) {}
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class card_transmission_failed: public exception {
|
||||
public:
|
||||
card_transmission_failed(const std::string& position,
|
||||
const std::string& reason) throw():
|
||||
exception("transmission to card failed:\n"+position
|
||||
+"\nreason:\n"+reason) {
|
||||
}
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class wrong_dataformat: public exception {
|
||||
public:
|
||||
wrong_dataformat(const std::string& data,
|
||||
const std::string& reason) throw():
|
||||
exception("wrong dataformat:\n"+crypto::hex(data)
|
||||
+"\nreason:\n"+reason) {
|
||||
}
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class array_range: public exception {
|
||||
public:
|
||||
array_range(unsigned int i, unsigned int j) throw():
|
||||
exception("array index out of range: "+mrw::string(i)
|
||||
+"; length: "+mrw::string(j)) {
|
||||
}
|
||||
};
|
||||
//----------------------------------------------------------------------------
|
||||
class pin_locked: public exception {
|
||||
public:
|
||||
pin_locked() throw(): exception("pin is locked and cannot be changed") {}
|
||||
};
|
||||
//@}
|
||||
|
||||
//============================================================================
|
||||
|
||||
/// @addtogroup cardostypes
|
||||
//@{
|
||||
|
||||
/// Represents the Smart Card's Tag Length Value Encoded File Format.
|
||||
class TagLengthValue {
|
||||
public:
|
||||
enum Tag {
|
||||
DIRECTORY_ENTRY = 0x6F,
|
||||
FILE_TYPE = 0x82,
|
||||
FILE_IDENTIFIER = 0x86,
|
||||
NEXT_OFFSET = 0x8A,
|
||||
VERSION_INFO_CONTAINER = 0xff,
|
||||
VERSION_INFO_STRING = 0x01
|
||||
};
|
||||
public:
|
||||
/// Initialize from a File's Content
|
||||
TagLengthValue(const std::string& content):
|
||||
_size(0), _content(content) {
|
||||
if (_content.size()<2)
|
||||
throw wrong_dataformat(_content, "not a TLV, too small");
|
||||
for (std::string::size_type pos(0); pos!=_content.size();
|
||||
pos+=_content[pos+1]+2) {
|
||||
++_size;
|
||||
if (pos+2>_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<BerValue> 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<<std::string(indent*indentStep, ' ')<<'[';
|
||||
switch (tagClass()) {
|
||||
case UNIVERSAL: ss<<"UNIVERSAL,"; break;
|
||||
case APPLICATION: ss<<"APPLICATION,"; break;
|
||||
case CONTEXT_SPECIFIC: ss<<"CONTEXT_SPECIFIC,"; break;
|
||||
case PRIVATE: ss<<"PRIVATE,"; break;
|
||||
default: ss<<(unsigned int)tagClass();
|
||||
}
|
||||
switch (tagPC()) {
|
||||
case PRIMITIVE: ss<<"PRIMITIVE,"; break;
|
||||
case CONSTRUCTED: ss<<"CONSTRUCTED,"; break;
|
||||
default: ss<<(unsigned int)tagPC();
|
||||
}
|
||||
switch (tagType()) {
|
||||
case END_OF_CONTENT: ss<<"END_OF_CONTENT"; break;
|
||||
case BOOLEAN: ss<<"BOOLEAN"; break;
|
||||
case INTEGER: ss<<"INTEGER"; break;
|
||||
case BIT_STRING: ss<<"BIT_STRING"; break;
|
||||
case OCTET_STRING: ss<<"OCTET_STRING"; break;
|
||||
case EMPTY: ss<<"EMPTY"; break;
|
||||
case OBJECT_IDENTIFIER: ss<<"OBJECT_IDENTIFIER"; break;
|
||||
case OBJECT_DESCRIPTOR: ss<<"OBJECT_DESCRIPTOR"; break;
|
||||
case EXTERNAL: ss<<"EXTERNAL"; break;
|
||||
case REAL: ss<<"REAL"; break;
|
||||
case ENUMERATED: ss<<"ENUMERATED"; break;
|
||||
case EMBEDDED_PDV: ss<<"EMBEDDED_PDV"; break;
|
||||
case UTF8_STRING: ss<<"UTF8_STRING"; break;
|
||||
case RELATIVE_OID: ss<<"RELATIVE_OID"; break;
|
||||
case SEQUENCE: ss<<"SEQUENCE"; break;
|
||||
case SET: ss<<"SET"; break;
|
||||
case NUMERIC_STRING: ss<<"NUMERIC_STRING"; break;
|
||||
case PRINTABLE_STRING: ss<<"PRINTABLE_STRING"; break;
|
||||
case T61_STRING: ss<<"T61_STRING"; break;
|
||||
case VIDEOTEX_STRING: ss<<"VIDEOTEX_STRING"; break;
|
||||
case IA5_STRING: ss<<"IA5_STRING"; break;
|
||||
case UTC_TIME: ss<<"UTC_TIME"; break;
|
||||
case GENERALIZED_TIME: ss<<"GENERALIZED_TIME"; break;
|
||||
case GRAPHIC_STRING: ss<<"GRAPHIC_STRING"; break;
|
||||
case VISIBLE_STRING: ss<<"VISIBLE_STRING"; break;
|
||||
case GENERAL_STRING: ss<<"GENERAL_STRING"; break;
|
||||
case UNIVERSAL_STRING: ss<<"UNIVERSAL_STRING"; break;
|
||||
case CHARACTER_STRING: ss<<"CHARACTER_STRING"; break;
|
||||
case BMP_STRING: ss<<"BMP_STRING"; break;
|
||||
default: ss<<(unsigned int)tagType();
|
||||
}
|
||||
ss<<"] = ";
|
||||
if (isContainer()) {
|
||||
int i(0);
|
||||
ss<<"{"<<std::endl;
|
||||
for (std::vector<BerValue>::iterator it(_sequence.begin());
|
||||
it!=_sequence.end(); ++it) {
|
||||
ss<<std::string((indent+1)*indentStep, ' ')
|
||||
<<" ["<<i++<<"]{"
|
||||
<<std::endl
|
||||
<<it->print(indent+2, indentStep)
|
||||
<<std::endl
|
||||
<<std::string((indent+1)*indentStep, ' ')<<'}'
|
||||
<<std::endl;
|
||||
}
|
||||
ss<<std::string(indent*indentStep, ' ')<<'}';
|
||||
} else {
|
||||
ss<<"0x"<<crypto::binToHex(_value)<<" = \"";
|
||||
for (std::string::const_iterator it(_value.begin());
|
||||
it!=_value.end(); ++it)
|
||||
ss<<(isprint(*it)?*it:'.');
|
||||
}
|
||||
ss<<"\"";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
unsigned char _tag;
|
||||
unsigned char _length;
|
||||
std::string _value;
|
||||
std::vector<BerValue> _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<BerValue> {
|
||||
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<<std::string(indent*indentStep, ' ')<<at(0).print();
|
||||
} else {
|
||||
int i(0);
|
||||
ss<<"{"<<std::endl;
|
||||
for (iterator it(begin()); it!=end(); ++it) {
|
||||
ss<<std::string((indent+1)*indentStep, ' ')
|
||||
<<" ["<<i++<<"]{"
|
||||
<<std::endl
|
||||
<<it->print(indent+2, indentStep)
|
||||
<<std::endl
|
||||
<<std::string((indent+1)*indentStep, ' ')<<'}'
|
||||
<<std::endl;
|
||||
}
|
||||
ss<<std::string(indent*indentStep, ' ')<<'}';
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
//@}
|
||||
|
||||
//============================================================================
|
||||
/// @addtogroup cardoslib
|
||||
//@{
|
||||
|
||||
/// Implements CardOS V4.4 commands.
|
||||
/** Directly sends CardOS V4.4 commands to a smart card using APDUs.
|
||||
|
||||
This class does not do any transaction handling. Please handle
|
||||
transactions on a higher level, when you access these
|
||||
methods. */
|
||||
class Commands {
|
||||
|
||||
public:
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/// @name Setup Smart Card Reader
|
||||
//@{
|
||||
|
||||
/// Uninitialized class, use @ref reader to setup assign smart card reader.
|
||||
Commands() {
|
||||
}
|
||||
|
||||
/// Initialize with given smart card reader.
|
||||
Commands(mrw::Shared<pcsc::Connection::Reader> reader):
|
||||
_reader(reader) {
|
||||
}
|
||||
|
||||
/// Set smart card reader.
|
||||
void reader(mrw::Shared<pcsc::Connection::Reader> 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.
|
||||
|
||||
<table>
|
||||
<caption>Bytes P1-P2</caption>
|
||||
<thead>
|
||||
<tr><td colspan="2">P1 (MODE)</td><td>P2</td><td>Meaning</td></tr>
|
||||
<tr><td>Bit 7</td><td>Bits 6 – 0</td><td/><td/></tr>
|
||||
</thead>
|
||||
<tr>
|
||||
<td>1</td><td>HI value</td><td>LO value</td>
|
||||
<td>Allocate buffer with size HI-LO</td>
|
||||
</tr><tr>
|
||||
<td>0</td><td>rfu</td><td>ID</td>
|
||||
<td>Free buffer with ID in P2</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@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
|
||||
|
||||
<table>
|
||||
<caption>Format of the input for hash value calculation</caption>
|
||||
<thead><tr>
|
||||
<th>System_Challenge</th>
|
||||
<th>Command Header<br/>CLA INS P1 P2</th>
|
||||
<th>Global Life Cycle Phase</th>
|
||||
<th>Internal Parameters</th>
|
||||
<th>Number of loaded Packages</th>
|
||||
<th>Chip Unique Identification Number (opt.)</th>
|
||||
</tr></thead>
|
||||
<tr>
|
||||
<td>xxh…xxh</td><td>80h 88h Mode 00h</td><td>xxh</td>
|
||||
<td>22h…22h</td><td>xxh</td><td>xxh…xxh</td>
|
||||
</tr><tr>
|
||||
<td>n bytes</td><td>4 bytes</td><td>1 byte</td><td>9 bytes</td>
|
||||
<td>1 byte</td><td>6 bytes/empty</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@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"<<std::hex<<ret;
|
||||
return ss.str();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)<<std::endl
|
||||
<<"RC: "
|
||||
<<crypto::binToHex(result.substr(result.size()-2, 2)));
|
||||
if (result.size()>2) {
|
||||
CARDOS_LOG("Data: "
|
||||
<<crypto::binToHex(result.substr(0, result.size()-2)));
|
||||
CARDOS_LOG("Text: "
|
||||
<<txt.substr(0, result.size()-2));
|
||||
}
|
||||
} else {
|
||||
CARDOS_LOG("RC: ?? Data: "<<crypto::binToHex(result)<<" Text: "<<txt);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string send(char cla, char ins, char p1, char p2, std::string lc) {
|
||||
if (!_reader) throw std::runtime_error("no reader selected");
|
||||
CARDOS_LOG("APDU: cla="<<crypto::binToHex(cla)
|
||||
<<" ins="<<crypto::binToHex(ins)
|
||||
<<" p1="<<crypto::binToHex(p1)
|
||||
<<" p2="<<crypto::binToHex(p2)
|
||||
<<" lc="<<crypto::binToHex(lc));
|
||||
return logResult(_reader->transmit(cla, ins, p1, p2, lc));
|
||||
}
|
||||
|
||||
std::string send(char cla, char ins, char p1, char p2) {
|
||||
if (!_reader) throw std::runtime_error("no reader selected");
|
||||
CARDOS_LOG("APDU: cla="<<crypto::binToHex(cla)
|
||||
<<" ins="<<crypto::binToHex(ins)
|
||||
<<" p1="<<crypto::binToHex(p1)
|
||||
<<" p2="<<crypto::binToHex(p2));
|
||||
return logResult(_reader->transmit(cla, ins, p1, p2));
|
||||
}
|
||||
|
||||
//@}
|
||||
|
||||
protected:
|
||||
|
||||
mrw::Shared<pcsc::Connection::Reader> _reader;
|
||||
|
||||
};
|
||||
//@}
|
||||
|
||||
//============================================================================
|
||||
|
||||
class Access {
|
||||
|
||||
public:
|
||||
|
||||
|
||||
enum TokenVersion {PZ2007, PZ2009, PZ2010};
|
||||
|
||||
private:
|
||||
|
||||
Access(); // not available, reader is required
|
||||
|
||||
public:
|
||||
|
||||
std::string serialNumber() {
|
||||
return check(_reader->transmit(0x00, 0xCA, 0x01, 0x81),
|
||||
"read serial number").substr(8, 8);
|
||||
}
|
||||
|
||||
bool firstUse() {
|
||||
#ifndef Q_OS_MAC
|
||||
pcsc::Connection::Reader::Transaction lock(_reader);
|
||||
#endif
|
||||
// SigG Part:
|
||||
// 1. select file "transport protection state" /1/ #236
|
||||
check(_reader->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 "<unknown>" 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<pcsc::Connection::Reader> _reader;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
//@}
|
||||
|
||||
#endif
|
@@ -11,6 +11,8 @@
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
|
||||
/*! @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<<std::hex<<std::setw(2)<<std::setfill('0')
|
||||
<<(unsigned int)(unsigned char)(c);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
//! Convert binary to readable hexadecimal
|
||||
inline std::string binToHex(const std::string& s) {
|
||||
std::string result;
|
||||
for (std::string::const_iterator c(s.begin()); c!=s.end(); ++c)
|
||||
result += binToHex(*c);
|
||||
return result;
|
||||
}
|
||||
|
||||
//! Convert readable lowercase hexadecimal to binary
|
||||
inline std::string hexToBin(std::string s) {
|
||||
const static std::string HEX("0123456789abcdef");
|
||||
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
|
||||
if (s.size()%2)
|
||||
throw std::runtime_error
|
||||
("input string \""+s
|
||||
+"\" must have an even number of hexadecimal numbers");
|
||||
if (s.find_first_not_of(HEX)!=std::string::npos)
|
||||
throw std::runtime_error
|
||||
("input string \""+s+"\" has non hexadecimal value at position "
|
||||
+((std::stringstream&)(std::stringstream()
|
||||
<<s.find_first_not_of(HEX))).str());
|
||||
std::string res;
|
||||
for (std::string::const_iterator it(s.begin()); it!=s.end(); ++it) {
|
||||
unsigned char c(HEX.find(*it));
|
||||
if (++it!=s.end()) (c <<= 4) += HEX.find(*it);
|
||||
res += std::string(1, (char)c);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
//@}
|
||||
|
@@ -6,7 +6,7 @@
|
||||
## 45678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
|
||||
include_HEADERS = pcsc.hxx cryptoki.hxx openssl.hxx cryptaux.hxx \
|
||||
openssl-engine.hxx
|
||||
openssl-engine.hxx suisseid.hxx cardos.hxx
|
||||
|
||||
if !MINGW32
|
||||
if MAC
|
||||
|
@@ -435,7 +435,7 @@ namespace pcsc {
|
||||
check(SCardConnect(_connection->id(), strconv(name).c_str(),
|
||||
mode, protocol,
|
||||
&_id, &_protocol),
|
||||
"connect smartcard \""+name);
|
||||
"connect smartcard \""+name+"\"");
|
||||
}
|
||||
|
||||
//! forbidden
|
||||
|
200
src/suisseid.hxx
Normal file
200
src/suisseid.hxx
Normal file
@@ -0,0 +1,200 @@
|
||||
/*! @file
|
||||
|
||||
@id $Id$
|
||||
*/
|
||||
// 1 2 3 4 5 6 7 8
|
||||
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
|
||||
#ifndef __SUISSEID_HXX__
|
||||
#define __SUISSEID_HXX__
|
||||
|
||||
#include <cardos.hxx>
|
||||
#include <cryptoki.hxx>
|
||||
#include <pcsc.hxx>
|
||||
#include <mrw/vector.hxx>
|
||||
#include <mrw/shared.hxx>
|
||||
|
||||
/*! @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<pcsc::Connection::Reader> reader,
|
||||
mrw::Shared<cryptoki::Slot> 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 "<unknown>";
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
mrw::Shared<cryptoki::Slot> _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<pcsc::Connection::Reader> reader,
|
||||
mrw::Shared<cryptoki::Slot> 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 = "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
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<mrw::Shared<Card> > Cards;
|
||||
|
||||
//! Auxiliary SuisseID card manager.
|
||||
/** Use this manager to scan your system for SuisseID cards.
|
||||
|
||||
Usage Example:
|
||||
|
||||
@code
|
||||
#include <suisseid.hxx>
|
||||
#include <iostream>
|
||||
|
||||
[...]
|
||||
|
||||
try {
|
||||
suisseid::Cards cards(suisseid::Scanner().scan());
|
||||
for (auto card(cards.begin()); card!=cards.end(); ++card)
|
||||
std::cout<<"Found SuisseID: "<<(*card)->name()<<std::endl;
|
||||
return 0;
|
||||
} catch (std::exception& x) {
|
||||
std::cerr<<"**** ERROR in "<<*argv<<": "<<x.what()<<std::endl;
|
||||
return 1;
|
||||
}
|
||||
@endcode */
|
||||
class Scanner {
|
||||
|
||||
public:
|
||||
|
||||
Scanner(const std::string& lib="libcvP11.so"):
|
||||
_cryptoki(lib) {
|
||||
}
|
||||
|
||||
Scanner(const pcsc::Connection& pcsc,
|
||||
const std::string& lib="libcvP11.so"):
|
||||
_pcsc(pcsc),
|
||||
_cryptoki(lib) {
|
||||
}
|
||||
|
||||
Scanner(const cryptoki::Library& cryptoki):
|
||||
_cryptoki(cryptoki) {
|
||||
}
|
||||
|
||||
Scanner(const pcsc::Connection& pcsc,
|
||||
const cryptoki::Library& cryptoki):
|
||||
_pcsc(pcsc),
|
||||
_cryptoki(cryptoki) {
|
||||
}
|
||||
|
||||
/// Scan for available known SuisseID cards on the system.
|
||||
/** @return List of detected SuisseID smart 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<Card*>
|
||||
(new PostSuisseID(_pcsc.reader(*reader), slots[0])));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
pcsc::Connection _pcsc;
|
||||
cryptoki::Library _cryptoki;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
//@}
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user