added basic suisse id functions; refs #28
This commit is contained in:
		
							
								
								
									
										685
									
								
								doc/doxyfile.in
									
									
									
									
									
								
							
							
						
						
									
										685
									
								
								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 | # This file describes the settings to be used by the documentation system | ||||||
| # doxygen (www.doxygen.org) for a project | # doxygen (www.doxygen.org) for a project | ||||||
| @@ -22,8 +22,9 @@ | |||||||
|  |  | ||||||
| DOXYFILE_ENCODING      = UTF-8 | DOXYFILE_ENCODING      = UTF-8 | ||||||
|  |  | ||||||
| # The PROJECT_NAME tag is a single word (or a sequence of words surrounded  | # The PROJECT_NAME tag is a single word (or sequence of words) that should  | ||||||
| # by quotes) that should identify the project. | # 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@" | PROJECT_NAME           = "Projektdokumentation @PACKAGENAME@" | ||||||
|  |  | ||||||
| @@ -33,6 +34,19 @@ PROJECT_NAME           = "Projektdokumentation @PACKAGENAME@" | |||||||
|  |  | ||||||
| PROJECT_NUMBER         = "Version @MAJOR@.@MINOR@.@LEAST@" | 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)  | # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)  | ||||||
| # base path where the generated documentation will be put.  | # base path where the generated documentation will be put.  | ||||||
| # If a relative path is entered, it will be relative to the location  | # 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.  | # information to generate all constant output in the proper language.  | ||||||
| # The default language is English, other supported languages are:  | # The default language is English, other supported languages are:  | ||||||
| # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,  | # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,  | ||||||
| # Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek,  | # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,  | ||||||
| # Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages),  | # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English  | ||||||
| # Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish,  | # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,  | ||||||
| # Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish,  | # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,  | ||||||
| # and Ukrainian. | # 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  | # 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  | # 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  | # members were ordinary class members. Constructors, destructors and assignment  | ||||||
| # operators of the base classes will not be shown. | # 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  | # 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  | # 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    =  | STRIP_FROM_INC_PATH    =  | ||||||
|  |  | ||||||
| # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter  | # 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. | # doesn't support long names like on DOS, Mac, or CD-ROM. | ||||||
|  |  | ||||||
| SHORT_NAMES            = NO | SHORT_NAMES            = NO | ||||||
| @@ -155,13 +169,6 @@ QT_AUTOBRIEF           = NO | |||||||
|  |  | ||||||
| MULTILINE_CPP_IS_BRIEF = YES | 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  | # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented  | ||||||
| # member inherits the documentation from any documented member that it  | # member inherits the documentation from any documented member that it  | ||||||
| # re-implements. | # re-implements. | ||||||
| @@ -193,6 +200,13 @@ ALIASES                = "id=\par File-ID\n" \ | |||||||
|                          "instancemutex=\par Reentrant:\nAccess is locked with per instance mutex @c " \ |                          "instancemutex=\par Reentrant:\nAccess is locked with per instance mutex @c " \ | ||||||
|                          "mutex=\par Reentrant:\nAccess is locked with 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  | # 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.  | # 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  | # For instance, some of the names that are used will be different. The list  | ||||||
| @@ -219,14 +233,35 @@ OPTIMIZE_FOR_FORTRAN   = NO | |||||||
|  |  | ||||||
| OPTIMIZE_OUTPUT_VHDL   = 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  | # 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  | # 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  | # 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.  | # 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. | # 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. | # enable parsing support. | ||||||
| @@ -239,6 +274,15 @@ CPP_CLI_SUPPORT        = NO | |||||||
|  |  | ||||||
| SIP_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  | # 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  | # 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  | # 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 | 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  | # 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  | # 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  | # typedef struct TypeS {} TypeT, will appear in the documentation as a struct  | ||||||
| @@ -264,6 +324,33 @@ SUBGROUPING            = YES | |||||||
|  |  | ||||||
| TYPEDEF_HIDES_STRUCT   = NO | 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 | # 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  | # If the EXTRACT_PRIVATE tag is set to YES all private members of a class  | ||||||
| # will be included in the documentation. | # 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  | # If the EXTRACT_STATIC tag is set to YES all static members of a file  | ||||||
| # will be included in the documentation. | # 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)  | # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)  | ||||||
| # defined locally in source files will be included in the documentation.  | # defined locally in source files will be included in the documentation.  | ||||||
| # If set to NO only classes defined in header files are included. | # 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  | # 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  | # 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  | # extracted and appear in the documentation as a namespace called  | ||||||
| # 'anonymous_namespace{file}', where file will be replaced with the base  | # 'anonymous_namespace{file}', where file will be replaced with the base  | ||||||
| # name of the file that contains the anonymous namespace. By default  | # name of the file that contains the anonymous namespace. By default  | ||||||
| # anonymous namespace are hidden. | # anonymous namespaces are hidden. | ||||||
|  |  | ||||||
| EXTRACT_ANON_NSPACES   = NO | 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  | # will put a list of the files that are included by a file in the documentation  | ||||||
| # of that file. | # 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]  | # If the INLINE_INFO tag is set to YES (the default) then a tag [inline]  | ||||||
| # is inserted in the documentation for inline members. | # is inserted in the documentation for inline members. | ||||||
| @@ -381,6 +479,16 @@ SORT_MEMBER_DOCS       = YES | |||||||
|  |  | ||||||
| SORT_BRIEF_DOCS        = NO | 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  | # 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)  | # hierarchy of group names into alphabetical order. If set to NO (the default)  | ||||||
| # the group names will appear in their defined order. | # the group names will appear in their defined order. | ||||||
| @@ -397,6 +505,15 @@ SORT_GROUP_NAMES       = NO | |||||||
|  |  | ||||||
| SORT_BY_SCOPE_NAME     = NO | 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  | # The GENERATE_TODOLIST tag can be used to enable (YES) or  | ||||||
| # disable (NO) the todo list. This list is created by putting \todo  | # disable (NO) the todo list. This list is created by putting \todo  | ||||||
| # commands in the documentation. | # commands in the documentation. | ||||||
| @@ -427,10 +544,10 @@ GENERATE_DEPRECATEDLIST= YES | |||||||
| ENABLED_SECTIONS       =  | ENABLED_SECTIONS       =  | ||||||
|  |  | ||||||
| # The MAX_INITIALIZER_LINES tag determines the maximum number of lines  | # 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  | # 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.  | # 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  | # documentation can be controlled using \showinitializer or \hideinitializer  | ||||||
| # command in the documentation regardless of this setting. | # command in the documentation regardless of this setting. | ||||||
|  |  | ||||||
| @@ -442,11 +559,17 @@ MAX_INITIALIZER_LINES  = 30 | |||||||
|  |  | ||||||
| SHOW_USED_FILES        = YES | SHOW_USED_FILES        = YES | ||||||
|  |  | ||||||
| # If the sources in your project are distributed over multiple directories  | # Set the SHOW_FILES tag to NO to disable the generation of the Files page.  | ||||||
| # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy  | # This will remove the Files entry from the Quick Index and from the  | ||||||
| # in the documentation. The default is NO. | # 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  | # 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  | # doxygen should invoke to get the current version for each file (typically from  | ||||||
| @@ -458,6 +581,25 @@ SHOW_DIRECTORIES       = NO | |||||||
|  |  | ||||||
| FILE_VERSION_FILTER    =  | 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 | # configuration options related to warning and progress messages | ||||||
| #--------------------------------------------------------------------------- | #--------------------------------------------------------------------------- | ||||||
| @@ -486,7 +628,7 @@ WARN_IF_UNDOCUMENTED   = NO | |||||||
|  |  | ||||||
| WARN_IF_DOC_ERROR      = YES | 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  | # 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  | # 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  | # 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  | # 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  | # and *.h) to filter out the source-files in the directories. If left  | ||||||
| # blank the following patterns are tested:  | # blank the following patterns are tested:  | ||||||
| # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx  | # *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh  | ||||||
| # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 | # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py  | ||||||
|  | # *.f90 *.f *.for *.vhd *.vhdl | ||||||
|  |  | ||||||
| FILE_PATTERNS          = *.[ch]xx \ | FILE_PATTERNS          = *.[ch]xx \ | ||||||
|                          *.doc |                          *.doc | ||||||
| @@ -544,14 +687,16 @@ FILE_PATTERNS          = *.[ch]xx \ | |||||||
|  |  | ||||||
| RECURSIVE              = NO | 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  | # 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                =  | EXCLUDE                =  | ||||||
|  |  | ||||||
| # The EXCLUDE_SYMLINKS tag can be used select whether or not files or  | # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or  | ||||||
| # directories that are symbolic links (a Unix filesystem feature) are excluded  | # directories that are symbolic links (a Unix file system feature) are excluded  | ||||||
| # from the input. | # from the input. | ||||||
|  |  | ||||||
| EXCLUDE_SYMLINKS       = NO | EXCLUDE_SYMLINKS       = NO | ||||||
| @@ -614,8 +759,8 @@ INPUT_FILTER           = | |||||||
| # basis.  Doxygen will compare the file name with each pattern and apply the  | # 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:  | # 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  | # 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  | # info on how filters are used. If FILTER_PATTERNS is empty or if  | ||||||
| # is applied to all files. | # non of the patterns match the file name, INPUT_FILTER is applied. | ||||||
|  |  | ||||||
| FILTER_PATTERNS        =  | FILTER_PATTERNS        =  | ||||||
|  |  | ||||||
| @@ -625,6 +770,14 @@ FILTER_PATTERNS        = | |||||||
|  |  | ||||||
| FILTER_SOURCE_FILES    = NO | 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 | # 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  | # Note: To get rid of all source code in the generated output, make sure also  | ||||||
| # VERBATIM_HEADERS is set to NO. | # VERBATIM_HEADERS is set to NO. | ||||||
|  |  | ||||||
| SOURCE_BROWSER         = YES | SOURCE_BROWSER         = NO | ||||||
|  |  | ||||||
| # Setting the INLINE_SOURCES tag to YES will include the body  | # Setting the INLINE_SOURCES tag to YES will include the body  | ||||||
| # of functions and classes directly in the documentation. | # 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  | # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct  | ||||||
| # doxygen to hide any special comment blocks from generated source code  | # 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 | 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  | # then for each documented function all documented  | ||||||
| # functions referencing it will be listed. | # 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  | # then for each documented function all documented entities  | ||||||
| # called/used by that function will be listed. | # 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)  | # If the REFERENCES_LINK_SOURCE tag is set to YES (the default)  | ||||||
| # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from  | # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from  | ||||||
| # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will  | # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will  | ||||||
| # link to the source code.  Otherwise they will link to the documentstion. | # link to the source code.  Otherwise they will link to the documentation. | ||||||
|  |  | ||||||
| REFERENCES_LINK_SOURCE = YES | 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  | # 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  | # 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            =  | HTML_HEADER            =  | ||||||
|  |  | ||||||
| @@ -741,22 +901,66 @@ HTML_FOOTER            = | |||||||
| # fine-tune the look of the HTML output. If the tag is left blank doxygen  | # 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  | # 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  | # 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        =  | HTML_STYLESHEET        =  | ||||||
|  |  | ||||||
| # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,  | # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or  | ||||||
| # files or namespaces will be aligned in HTML using tables. If set to  | # other source files which should be copied to the HTML output directory. Note  | ||||||
| # NO a bullet list will be used. | # 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  | # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.  | ||||||
| # will be generated that can be used as input for tools like the  | # Doxygen will adjust the colors in the style sheet and background images  | ||||||
| # Microsoft HTML help workshop to generate a compiled HTML help file (.chm)  | # according to this color. Hue is specified as an angle on a colorwheel,  | ||||||
| # of the generated HTML documentation. | # 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  | # 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  | # will be generated that can be used as input for Apple's Xcode 3  | ||||||
| @@ -766,6 +970,8 @@ GENERATE_HTMLHELP      = NO | |||||||
| # directory and running "make install" will install the docset in  | # directory and running "make install" will install the docset in  | ||||||
| # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find  | # ~/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 | GENERATE_DOCSET        = NO | ||||||
|  |  | ||||||
| @@ -783,13 +989,22 @@ DOCSET_FEEDNAME        = "Doxygen generated docs" | |||||||
|  |  | ||||||
| DOCSET_BUNDLE_ID       = org.doxygen.Project | DOCSET_BUNDLE_ID       = org.doxygen.Project | ||||||
|  |  | ||||||
| # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML  | # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify  | ||||||
| # documentation will contain sections that can be hidden and shown after the  | # the documentation publisher. This should be a reverse domain-name style  | ||||||
| # page has loaded. For this to work a browser that supports  | # string, e.g. com.mycompany.MyDocSet.documentation. | ||||||
| # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox  |  | ||||||
| # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). |  | ||||||
|  |  | ||||||
| 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  | # 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  | # be used to specify the file name of the resulting .chm file. You  | ||||||
| @@ -811,6 +1026,12 @@ HHC_LOCATION           = | |||||||
|  |  | ||||||
| GENERATE_CHI           = NO | 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  | # 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  | # controls whether a binary table of contents is generated (YES) or a  | ||||||
| # normal table of contents (NO) in the .chm file. | # normal table of contents (NO) in the .chm file. | ||||||
| @@ -822,32 +1043,175 @@ BINARY_TOC             = NO | |||||||
|  |  | ||||||
| TOC_EXPAND             = NO | TOC_EXPAND             = NO | ||||||
|  |  | ||||||
| # The DISABLE_INDEX tag can be used to turn on/off the condensed index at  | # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and  | ||||||
| # top of each HTML page. The value NO (the default) enables the index and  | # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated  | ||||||
| # the value YES disables it. | # 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 | DISABLE_INDEX          = NO | ||||||
|  |  | ||||||
| # This tag can be used to set the number of enum values (range [1..20])  | # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index  | ||||||
| # that doxygen will group on one line in the generated HTML documentation. | # structure should be generated to display hierarchical information.  | ||||||
|  | # If the tag value is set to YES, a side panel will be generated  | ||||||
| ENUM_VALUES_PER_LINE   = 4 | # containing a tree-like index structure (just like the one that  | ||||||
|  |  | ||||||
| # 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  |  | ||||||
| # is generated for HTML Help). For this to work a browser that supports  | # 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+,  | # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).  | ||||||
| # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are  | # Windows users are probably better off using the HTML help feature.  | ||||||
| # 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 | 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  | # 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  | # used to set the initial width (in pixels) of the frame in which the tree  | ||||||
| # is shown. | # is shown. | ||||||
|  |  | ||||||
| TREEVIEW_WIDTH         = 250 | 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 | # configuration options related to the LaTeX output | ||||||
| #--------------------------------------------------------------------------- | #--------------------------------------------------------------------------- | ||||||
| @@ -865,6 +1229,9 @@ LATEX_OUTPUT           = latex | |||||||
|  |  | ||||||
| # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be  | # 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 | LATEX_CMD_NAME         = latex | ||||||
|  |  | ||||||
| @@ -881,7 +1248,7 @@ MAKEINDEX_CMD_NAME     = makeindex | |||||||
| COMPACT_LATEX          = NO | COMPACT_LATEX          = NO | ||||||
|  |  | ||||||
| # The PAPER_TYPE tag can be used to set the paper type that is used  | # 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. | # executive. If left blank a4wide will be used. | ||||||
|  |  | ||||||
| PAPER_TYPE             = a4 | PAPER_TYPE             = a4 | ||||||
| @@ -898,6 +1265,13 @@ EXTRA_PACKAGES         = | |||||||
|  |  | ||||||
| LATEX_HEADER           =  | 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  | # 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  | # is prepared for conversion to pdf (using ps2pdf). The pdf file will  | ||||||
| # contain links (just like the HTML output) instead of page references  | # contain links (just like the HTML output) instead of page references  | ||||||
| @@ -924,6 +1298,19 @@ LATEX_BATCHMODE        = NO | |||||||
|  |  | ||||||
| LATEX_HIDE_INDICES     = YES | 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 | # configuration options related to the RTF output | ||||||
| #--------------------------------------------------------------------------- | #--------------------------------------------------------------------------- | ||||||
| @@ -955,7 +1342,7 @@ COMPACT_RTF            = YES | |||||||
|  |  | ||||||
| RTF_HYPERLINKS         = 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  | # config file, i.e. a series of assignments. You only have to provide  | ||||||
| # replacements, missing definitions are set to their default value. | # replacements, missing definitions are set to their default value. | ||||||
|  |  | ||||||
| @@ -1098,7 +1485,7 @@ MACRO_EXPANSION        = NO | |||||||
| EXPAND_ONLY_PREDEF     = NO | EXPAND_ONLY_PREDEF     = NO | ||||||
|  |  | ||||||
| # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files  | # 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 | SEARCH_INCLUDES        = YES | ||||||
|  |  | ||||||
| @@ -1128,15 +1515,15 @@ PREDEFINED             = HAVE_STACKTRACE | |||||||
| # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then  | # 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.  | # 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.  | # 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      =  | EXPAND_AS_DEFINED      =  | ||||||
|  |  | ||||||
| # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then  | # 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  | # doxygen's preprocessor will remove all references to function-like macros  | ||||||
| # on a line, have an all uppercase name, and do not end with a semicolon. Such  | # that are alone on a line, have an all uppercase name, and do not end with a  | ||||||
| # function macros are typically used for boiler-plate code, and will confuse  | # semicolon, because these will confuse the parser if not removed. | ||||||
| # the parser if not removed. |  | ||||||
|  |  | ||||||
| SKIP_FUNCTION_MACROS   = YES | SKIP_FUNCTION_MACROS   = YES | ||||||
|  |  | ||||||
| @@ -1144,20 +1531,16 @@ 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.  | # The TAGFILES option can be used to specify one or more tagfiles. For each  | ||||||
| # Optionally an initial location of the external documentation  | # tag file the location of the external documentation should be added. The  | ||||||
| # can be added for each tagfile. The format of a tag file without  | # format of a tag file without this location is as follows:  | ||||||
| # this location is as follows:  |  | ||||||
| #   TAGFILES = file1 file2 ...  | #   TAGFILES = file1 file2 ...  | ||||||
| # Adding location for the tag files is done as follows:  | # Adding location for the tag files is done as follows:  | ||||||
| #   TAGFILES = file1=loc1 "file2 = loc2" ...  | #   TAGFILES = file1=loc1 "file2 = loc2" ...  | ||||||
| # where "loc1" and "loc2" can be relative or absolute paths or  | # where "loc1" and "loc2" can be relative or absolute paths  | ||||||
| # URLs. If a location is present for each tag, the installdox tool  | # or URLs. Note that each tag file must have a unique name (where the name does  | ||||||
| # does not have to be run to correct the links. | # NOT include the path). If a tag file is not located in the directory in which  | ||||||
| # Note that each tag file must have a unique name | # doxygen is run, you must also specify the path to the tagfile here. | ||||||
| # (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               =  | TAGFILES               =  | ||||||
|  |  | ||||||
| @@ -1190,9 +1573,8 @@ PERL_PATH              = /usr/bin/perl | |||||||
| # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will  | # 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  | # 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  | # 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  | # this option also works with HAVE_DOT disabled, but it is recommended to  | ||||||
| # fallback. It is recommended to install and use dot, since it yields more  | # install and use dot, since it yields more powerful graphs. | ||||||
| # powerful graphs. |  | ||||||
|  |  | ||||||
| CLASS_DIAGRAMS         = YES | 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  | # the mscgen tool resides. If left empty the tool is assumed to be found in the  | ||||||
| # default search path. | # default search path. | ||||||
|  |  | ||||||
| MSCGEN_PATH            =  | MSCGEN_PATH            = /usr/bin/mscgen | ||||||
|  |  | ||||||
| # If set to YES, the inheritance and collaboration graphs will hide  | # If set to YES, the inheritance and collaboration graphs will hide  | ||||||
| # inheritance and usage relations if the target is undocumented  | # 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  | # 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 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  | # 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  | # will generate a graph for each documented class showing the direct and  | ||||||
| # indirect inheritance relations. Setting this tag to YES will force the  | # 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 | CLASS_GRAPH            = YES | ||||||
|  |  | ||||||
| @@ -1230,7 +1640,7 @@ CLASS_GRAPH            = YES | |||||||
| # indirect implementation dependencies (inheritance, containment, and  | # indirect implementation dependencies (inheritance, containment, and  | ||||||
| # class references variables) of the class with other documented classes. | # 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  | # 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 | # 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  | # collaboration diagrams in a style similar to the OMG's Unified Modeling  | ||||||
| # Language. | # 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  | # If set to YES, the inheritance and collaboration graphs will show the  | ||||||
| # relations between templates and their instances. | # 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  | # file showing the direct and indirect include dependencies of the file with  | ||||||
| # other documented files. | # other documented files. | ||||||
|  |  | ||||||
| INCLUDE_GRAPH          = NO | INCLUDE_GRAPH          = YES | ||||||
|  |  | ||||||
| # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and  | # 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  | # 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  | # documented header file showing the documented files that directly or  | ||||||
| # indirectly include this file. | # 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  | # If the CALL_GRAPH and HAVE_DOT options are set to YES then  | ||||||
| # doxygen will generate a call dependency graph for every global function  | # 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  | # 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. | # 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  | # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then  | ||||||
| # doxygen will generate a caller dependency graph for every global function  | # doxygen will generate a caller dependency graph for every global function  | ||||||
| @@ -1276,14 +1695,14 @@ CALL_GRAPH             = NO | |||||||
| # the time of a run. So in most cases it will be better to enable caller  | # 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. | # 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  | # 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 | 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  | # 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. | # relations between the files in the directories. | ||||||
| @@ -1291,15 +1710,26 @@ GRAPHICAL_HIERARCHY    = YES | |||||||
| DIRECTORY_GRAPH        = YES | DIRECTORY_GRAPH        = YES | ||||||
|  |  | ||||||
| # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images  | # 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 | # generated by dot. Possible values are svg, png, jpg, or gif.  | ||||||
| # If left blank png will be used. | # 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  | # 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. | # 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  | # 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  | # contain dot files that are included in the documentation (see the  | ||||||
| @@ -1307,7 +1737,13 @@ DOT_PATH               = | |||||||
|  |  | ||||||
| DOTFILE_DIRS           =  | 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  | # 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  | # 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  | # 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 | MAX_DOT_GRAPH_DEPTH    = 0 | ||||||
|  |  | ||||||
| # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent  | # 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. This is disabled by default, because dot on Windows does not  | ||||||
| # background. Warning: Depending on the platform used, enabling this option  | # seem to support this out of the box. Warning: Depending on the platform used,  | ||||||
| # may lead to badly anti-aliased labels on the edges of a graph (i.e. they  | # enabling this option may lead to badly anti-aliased labels on the edges of  | ||||||
| # become hard to read). | # a graph (i.e. they become hard to read). | ||||||
|  |  | ||||||
| DOT_TRANSPARENT        = YES | DOT_TRANSPARENT        = YES | ||||||
|  |  | ||||||
| @@ -1340,7 +1776,7 @@ DOT_TRANSPARENT        = YES | |||||||
| # makes dot run faster, but since only newer versions of dot (>1.8.10)  | # makes dot run faster, but since only newer versions of dot (>1.8.10)  | ||||||
| # support this, this feature is disabled by default. | # 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  | # 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  | # generate a legend page explaining the meaning of the various boxes and  | ||||||
| @@ -1353,12 +1789,3 @@ GENERATE_LEGEND        = YES | |||||||
| # the various graphs. | # the various graphs. | ||||||
|  |  | ||||||
| DOT_CLEANUP            = YES | 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 <iostream> | ||||||
| #include <iomanip> | #include <iomanip> | ||||||
| #include <algorithm> | #include <algorithm> | ||||||
| #include <tuple> |  | ||||||
| #include <sstream> | #include <sstream> | ||||||
| #include <fstream> | #include <fstream> | ||||||
| #include <streambuf> | #include <streambuf> | ||||||
|  | #ifndef MRW__OLD_PRE11_COMPILER | ||||||
| #include <chrono> | #include <chrono> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
| int main(int argc, char** argv) try { | int main(int argc, char** argv) try { | ||||||
|   | |||||||
| @@ -5,77 +5,34 @@ | |||||||
|  |  | ||||||
| noinst_PROGRAMS = pcsc-demo cryptoki-sign-demo cryptoki-demo		\ | noinst_PROGRAMS = pcsc-demo cryptoki-sign-demo cryptoki-demo		\ | ||||||
|                   openssl-tcp-demo openssl-ssl-demo			\ |                   openssl-tcp-demo openssl-ssl-demo			\ | ||||||
|                   openssl-engine-demo suisse-id-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 | if MAC | ||||||
| AM_CPPFLAGS+=-I/Library/OpenSC/include | 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 | endif | ||||||
| if !MINGW32 | if !MINGW32 | ||||||
| if !MAC | if !MAC | ||||||
| LDFLAGS += -lpcsclite | AM_LDFLAGS += -lpcsclite | ||||||
| endif | endif | ||||||
| endif | endif | ||||||
| if !MINGW32 | if !MINGW32 | ||||||
| LDFLAGS += -ldl -lpthread -lssl -lcrypto | AM_LDFLAGS += -ldl -lpthread -lssl -lcrypto | ||||||
| endif | endif | ||||||
|  |  | ||||||
| pcsc_demo_SOURCES = pcsc-demo.cxx | 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_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_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_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_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_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_SOURCES = suisse-id-demo.cxx | ||||||
| suisse_id_demo_CPPFLAGS = -I${top_srcdir}/src -I/usr/include/PCSC | cardos_demo_SOURCES = cardos-demo.cxx | ||||||
| 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 |  | ||||||
|  |  | ||||||
| MAINTAINERCLEANFILES = makefile.in | MAINTAINERCLEANFILES = makefile.in | ||||||
|   | |||||||
| @@ -5,91 +5,12 @@ | |||||||
| //       1         2         3         4         5         6         7         8 | //       1         2         3         4         5         6         7         8 | ||||||
| // 45678901234567890123456789012345678901234567890123456789012345678901234567890 | // 45678901234567890123456789012345678901234567890123456789012345678901234567890 | ||||||
|  |  | ||||||
| #include <cryptoki.hxx> | #include <suisseid.hxx> | ||||||
| #include <pcsc.hxx> |  | ||||||
| #include <mrw/args.hxx> |  | ||||||
| #include <mrw/vector.hxx> |  | ||||||
| #include <mrw/shared.hxx> |  | ||||||
|  |  | ||||||
|  | #include <mrw/args.hxx> | ||||||
| #include <stdexcept> | #include <stdexcept> | ||||||
| #include <iostream> | #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 { | int main(int argc, char** argv) try { | ||||||
|    |    | ||||||
|   std::string lib("libcvP11.so"); |   std::string lib("libcvP11.so"); | ||||||
| @@ -105,11 +26,13 @@ int main(int argc, char** argv) try { | |||||||
|                                      mrw::args::decl::param_list() |                                      mrw::args::decl::param_list() | ||||||
|                                      <<mrw::args::param(lib, "lib"))); |                                      <<mrw::args::param(lib, "lib"))); | ||||||
|  |  | ||||||
|   suisseid::Manager suisseid; |   suisseid::Cards cards(suisseid::Scanner(lib).scan()); | ||||||
|   suisseid::Manager::Cards cards(suisseid.scan()); |   for (suisseid::Cards::iterator card(cards.begin()); card!=cards.end(); ++card) | ||||||
|   for (suisseid::Manager::Cards::iterator card(cards.begin()); |     std::cout<<"Found SuisseID:"<<std::endl | ||||||
|        card!=cards.end(); ++card) |              <<"  Reader Name: "<<(*card)->name()<<std::endl | ||||||
|     std::cout<<"Found SuisseID: "<<(*card)->name()<<std::endl; |              <<"  Version:     "<<(*card)->version()<<std::endl | ||||||
|  |              <<"  PIN-Length:  "<<(*card)->minimalPinLength() | ||||||
|  |              <<" - "<<(*card)->maximalPinLength()<<std::endl; | ||||||
|   return 0; |   return 0; | ||||||
|  } catch (std::exception& x) { |  } catch (std::exception& x) { | ||||||
|   std::cerr<<"**** ERROR in "<<*argv<<": "<<x.what()<<std::endl; |   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 <string> | ||||||
| #include <sstream> | #include <sstream> | ||||||
| #include <iomanip> | #include <iomanip> | ||||||
|  | #include <stdexcept> | ||||||
|  | #include <algorithm> | ||||||
|  |  | ||||||
| /*! @defgroup gcrypto Auxiliary Crypto-Functions */ | /*! @defgroup gcrypto Auxiliary Crypto-Functions */ | ||||||
| //@{ | //@{ | ||||||
| @@ -65,6 +67,44 @@ namespace crypto { | |||||||
|     else |     else | ||||||
|       return "\""+data+"\""; |       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 | ## 45678901234567890123456789012345678901234567890123456789012345678901234567890 | ||||||
|  |  | ||||||
| include_HEADERS = pcsc.hxx cryptoki.hxx openssl.hxx cryptaux.hxx	\ | include_HEADERS = pcsc.hxx cryptoki.hxx openssl.hxx cryptaux.hxx	\ | ||||||
|                   openssl-engine.hxx |                   openssl-engine.hxx suisseid.hxx cardos.hxx | ||||||
|  |  | ||||||
| if !MINGW32 | if !MINGW32 | ||||||
| if MAC | if MAC | ||||||
|   | |||||||
| @@ -435,7 +435,7 @@ namespace pcsc { | |||||||
|             check(SCardConnect(_connection->id(), strconv(name).c_str(), |             check(SCardConnect(_connection->id(), strconv(name).c_str(), | ||||||
|                                mode, protocol, |                                mode, protocol, | ||||||
|                                &_id, &_protocol), |                                &_id, &_protocol), | ||||||
|                   "connect smartcard \""+name); |                   "connect smartcard \""+name+"\""); | ||||||
|           } |           } | ||||||
|  |  | ||||||
|           //! forbidden |           //! 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