Browse Source

Add seader from https://github.com/xMasterX/all-the-plugins

git-subtree-dir: seader
git-subtree-mainline: 70a5b56bbaa8f448fad8a28371be344d444e9ab1
git-subtree-split: 4c8f2e37bcf13b37401457b4ccc4bb03206c0f83
Willy-JL 1 year ago
parent
commit
dec417bed8
100 changed files with 12841 additions and 0 deletions
  1. 191 0
      seader/.clang-format
  2. BIN
      seader/.flipcorg/banner.png
  3. BIN
      seader/.flipcorg/gallery/menu.png
  4. BIN
      seader/.flipcorg/gallery/pacs.png
  5. BIN
      seader/.flipcorg/gallery/save_menu.png
  6. 26 0
      seader/.github/workflows/main.yml
  7. 2 0
      seader/.gitignore
  8. 1 0
      seader/.gitsubtree
  9. 674 0
      seader/LICENSE
  10. 32 0
      seader/Makefile
  11. BIN
      seader/Seader.png
  12. 45 0
      seader/aeabi_uldivmod.sx
  13. 41 0
      seader/application.fam
  14. 268 0
      seader/assembly.h
  15. 101 0
      seader/bsearch.c
  16. 339 0
      seader/ccid.c
  17. 106 0
      seader/ccid.h
  18. 3 0
      seader/changelog.md
  19. BIN
      seader/fake_screenshot.pxd
  20. BIN
      seader/icons/ArrowUpEmpty_14x15.png
  21. BIN
      seader/icons/ArrowUpFilled_14x15.png
  22. BIN
      seader/icons/DolphinMafia_115x62.png
  23. BIN
      seader/icons/DolphinNice_96x59.png
  24. BIN
      seader/icons/Nfc_10px.png
  25. BIN
      seader/icons/RFIDDolphinReceive_97x61.png
  26. BIN
      seader/icons/RFIDDolphinSend_97x61.png
  27. BIN
      seader/icons/logo.png
  28. 2 0
      seader/lib/asn1/.gitignore
  29. 0 0
      seader/lib/asn1/.gitkeep
  30. 652 0
      seader/lib/asn1/BIT_STRING.c
  31. 46 0
      seader/lib/asn1/BIT_STRING.h
  32. 174 0
      seader/lib/asn1/BIT_STRING_oer.c
  33. 82 0
      seader/lib/asn1/CardDetails.c
  34. 44 0
      seader/lib/asn1/CardDetails.h
  35. 50 0
      seader/lib/asn1/CardDetected.c
  36. 40 0
      seader/lib/asn1/CardDetected.h
  37. 54 0
      seader/lib/asn1/ContentElementTag.c
  38. 50 0
      seader/lib/asn1/ContentElementTag.h
  39. 60 0
      seader/lib/asn1/ErrorResponse.c
  40. 42 0
      seader/lib/asn1/ErrorResponse.h
  41. 56 0
      seader/lib/asn1/FrameProtocol.c
  42. 49 0
      seader/lib/asn1/FrameProtocol.h
  43. 1353 0
      seader/lib/asn1/INTEGER.c
  44. 104 0
      seader/lib/asn1/INTEGER.h
  45. 179 0
      seader/lib/asn1/INTEGER_oer.c
  46. 65 0
      seader/lib/asn1/NFCCommand.c
  47. 53 0
      seader/lib/asn1/NFCCommand.h
  48. 65 0
      seader/lib/asn1/NFCResponse.c
  49. 53 0
      seader/lib/asn1/NFCResponse.h
  50. 62 0
      seader/lib/asn1/NFCRx.c
  51. 42 0
      seader/lib/asn1/NFCRx.h
  52. 82 0
      seader/lib/asn1/NFCSend.c
  53. 45 0
      seader/lib/asn1/NFCSend.h
  54. 308 0
      seader/lib/asn1/NULL.c
  55. 42 0
      seader/lib/asn1/NULL.h
  56. 226 0
      seader/lib/asn1/NativeEnumerated.c
  57. 43 0
      seader/lib/asn1/NativeEnumerated.h
  58. 149 0
      seader/lib/asn1/NativeEnumerated_oer.c
  59. 484 0
      seader/lib/asn1/NativeInteger.c
  60. 44 0
      seader/lib/asn1/NativeInteger.h
  61. 99 0
      seader/lib/asn1/NativeInteger_oer.c
  62. 2043 0
      seader/lib/asn1/OCTET_STRING.c
  63. 100 0
      seader/lib/asn1/OCTET_STRING.h
  64. 171 0
      seader/lib/asn1/OCTET_STRING_oer.c
  65. 402 0
      seader/lib/asn1/OPEN_TYPE.c
  66. 63 0
      seader/lib/asn1/OPEN_TYPE.h
  67. 92 0
      seader/lib/asn1/OPEN_TYPE_oer.c
  68. 31 0
      seader/lib/asn1/PAC.c
  69. 43 0
      seader/lib/asn1/PAC.h
  70. 85 0
      seader/lib/asn1/Payload.c
  71. 56 0
      seader/lib/asn1/Payload.h
  72. 31 0
      seader/lib/asn1/Protocol.c
  73. 43 0
      seader/lib/asn1/Protocol.h
  74. 50 0
      seader/lib/asn1/RequestPacs.c
  75. 40 0
      seader/lib/asn1/RequestPacs.h
  76. 65 0
      seader/lib/asn1/Response.c
  77. 53 0
      seader/lib/asn1/Response.h
  78. 31 0
      seader/lib/asn1/RfStatus.c
  79. 43 0
      seader/lib/asn1/RfStatus.h
  80. 75 0
      seader/lib/asn1/SamCommand.c
  81. 56 0
      seader/lib/asn1/SamCommand.h
  82. 31 0
      seader/lib/asn1/SamResponse.c
  83. 43 0
      seader/lib/asn1/SamResponse.h
  84. 70 0
      seader/lib/asn1/SamVersion.c
  85. 40 0
      seader/lib/asn1/SamVersion.h
  86. 440 0
      seader/lib/asn1/asn_application.c
  87. 169 0
      seader/lib/asn1/asn_application.h
  88. 333 0
      seader/lib/asn1/asn_bit_data.c
  89. 83 0
      seader/lib/asn1/asn_bit_data.h
  90. 108 0
      seader/lib/asn1/asn_codecs.h
  91. 317 0
      seader/lib/asn1/asn_codecs_prim.c
  92. 51 0
      seader/lib/asn1/asn_codecs_prim.h
  93. 47 0
      seader/lib/asn1/asn_internal.c
  94. 152 0
      seader/lib/asn1/asn_internal.h
  95. 50 0
      seader/lib/asn1/asn_ioc.h
  96. 56 0
      seader/lib/asn1/asn_random_fill.c
  97. 51 0
      seader/lib/asn1/asn_random_fill.h
  98. 150 0
      seader/lib/asn1/asn_system.h
  99. 283 0
      seader/lib/asn1/ber_decoder.c
  100. 66 0
      seader/lib/asn1/ber_decoder.h

+ 191 - 0
seader/.clang-format

@@ -0,0 +1,191 @@
+---
+Language:        Cpp
+AccessModifierOffset: -4
+AlignAfterOpenBracket: AlwaysBreak
+AlignArrayOfStructures: None
+AlignConsecutiveMacros: None
+AlignConsecutiveAssignments: None
+AlignConsecutiveBitFields: None
+AlignConsecutiveDeclarations: None
+AlignEscapedNewlines: Left
+AlignOperands:   Align
+AlignTrailingComments: false
+AllowAllArgumentsOnNextLine: true
+AllowAllParametersOfDeclarationOnNextLine: false
+AllowShortEnumsOnASingleLine: true
+AllowShortBlocksOnASingleLine: Never
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: None
+AllowShortLambdasOnASingleLine: All
+AllowShortIfStatementsOnASingleLine: WithoutElse
+AllowShortLoopsOnASingleLine: true
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: Yes
+AttributeMacros:
+  - __capability
+BinPackArguments: false
+BinPackParameters: false
+BraceWrapping:
+  AfterCaseLabel:  false
+  AfterClass:      false
+  AfterControlStatement: Never
+  AfterEnum:       false
+  AfterFunction:   false
+  AfterNamespace:  false
+  AfterObjCDeclaration: false
+  AfterStruct:     false
+  AfterUnion:      false
+  AfterExternBlock: false
+  BeforeCatch:     false
+  BeforeElse:      false
+  BeforeLambdaBody: false
+  BeforeWhile:     false
+  IndentBraces:    false
+  SplitEmptyFunction: true
+  SplitEmptyRecord: true
+  SplitEmptyNamespace: true
+BreakBeforeBinaryOperators: None
+BreakBeforeConceptDeclarations: true
+BreakBeforeBraces: Attach
+BreakBeforeInheritanceComma: false
+BreakInheritanceList: BeforeColon
+BreakBeforeTernaryOperators: false
+BreakConstructorInitializersBeforeComma: false
+BreakConstructorInitializers: BeforeComma
+BreakAfterJavaFieldAnnotations: false
+BreakStringLiterals: false
+ColumnLimit:     99
+CommentPragmas:  '^ IWYU pragma:'
+QualifierAlignment: Leave
+CompactNamespaces: false
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DeriveLineEnding: true
+DerivePointerAlignment: false
+DisableFormat:   false
+EmptyLineAfterAccessModifier: Never
+EmptyLineBeforeAccessModifier: LogicalBlock
+ExperimentalAutoDetectBinPacking: false
+PackConstructorInitializers: BinPack
+BasedOnStyle:    ''
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+AllowAllConstructorInitializersOnNextLine: true
+FixNamespaceComments: false
+ForEachMacros:
+  - foreach
+  - Q_FOREACH
+  - BOOST_FOREACH
+IfMacros:
+  - KJ_IF_MAYBE
+IncludeBlocks:   Preserve
+IncludeCategories:
+  - Regex:           '.*'
+    Priority:        1
+    SortPriority:    0
+    CaseSensitive:   false
+  - Regex:           '^(<|"(gtest|gmock|isl|json)/)'
+    Priority:        3
+    SortPriority:    0
+    CaseSensitive:   false
+  - Regex:           '.*'
+    Priority:        1
+    SortPriority:    0
+    CaseSensitive:   false
+IncludeIsMainRegex: '(Test)?$'
+IncludeIsMainSourceRegex: ''
+IndentAccessModifiers: false
+IndentCaseLabels: false
+IndentCaseBlocks: false
+IndentGotoLabels: true
+IndentPPDirectives: None
+IndentExternBlock: AfterExternBlock
+IndentRequires:  false
+IndentWidth:     4
+IndentWrappedFunctionNames: true
+InsertTrailingCommas: None
+JavaScriptQuotes: Leave
+JavaScriptWrapImports: true
+KeepEmptyLinesAtTheStartOfBlocks: false
+LambdaBodyIndentation: Signature
+MacroBlockBegin: ''
+MacroBlockEnd:   ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBinPackProtocolList: Auto
+ObjCBlockIndentWidth: 4
+ObjCBreakBeforeNestedBlockParam: true
+ObjCSpaceAfterProperty: true
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakAssignment: 10
+PenaltyBreakBeforeFirstCallParameter: 30
+PenaltyBreakComment: 10
+PenaltyBreakFirstLessLess: 0
+PenaltyBreakOpenParenthesis: 0
+PenaltyBreakString: 10
+PenaltyBreakTemplateDeclaration: 10
+PenaltyExcessCharacter: 100
+PenaltyReturnTypeOnItsOwnLine: 60
+PenaltyIndentedWhitespace: 0
+PointerAlignment: Left
+PPIndentWidth:   -1
+ReferenceAlignment: Pointer
+ReflowComments:  false
+RemoveBracesLLVM: false
+SeparateDefinitionBlocks: Leave
+ShortNamespaceLines: 1
+SortIncludes:    Never
+SortJavaStaticImport: Before
+SortUsingDeclarations: false
+SpaceAfterCStyleCast: false
+SpaceAfterLogicalNot: false
+SpaceAfterTemplateKeyword: true
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCaseColon: false
+SpaceBeforeCpp11BracedList: false
+SpaceBeforeCtorInitializerColon: true
+SpaceBeforeInheritanceColon: true
+SpaceBeforeParens: Never
+SpaceBeforeParensOptions:
+  AfterControlStatements: false
+  AfterForeachMacros: false
+  AfterFunctionDefinitionName: false
+  AfterFunctionDeclarationName: false
+  AfterIfMacros:   false
+  AfterOverloadedOperator: false
+  BeforeNonEmptyParentheses: false
+SpaceAroundPointerQualifiers: Default
+SpaceBeforeRangeBasedForLoopColon: true
+SpaceInEmptyBlock: false
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles:  Never
+SpacesInConditionalStatement: false
+SpacesInContainerLiterals: false
+SpacesInCStyleCastParentheses: false
+SpacesInLineCommentPrefix:
+  Minimum:         1
+  Maximum:         -1
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+SpaceBeforeSquareBrackets: false
+BitFieldColonSpacing: Both
+Standard:        c++03
+StatementAttributeLikeMacros:
+  - Q_EMIT
+StatementMacros:
+  - Q_UNUSED
+  - QT_REQUIRE_VERSION
+TabWidth:        4
+UseCRLF:         false
+UseTab:          Never
+WhitespaceSensitiveMacros:
+  - STRINGIZE
+  - PP_STRINGIZE
+  - BOOST_PP_STRINGIZE
+  - NS_SWIFT_NAME
+  - CF_SWIFT_NAME
+...
+

BIN
seader/.flipcorg/banner.png


BIN
seader/.flipcorg/gallery/menu.png


BIN
seader/.flipcorg/gallery/pacs.png


BIN
seader/.flipcorg/gallery/save_menu.png


+ 26 - 0
seader/.github/workflows/main.yml

@@ -0,0 +1,26 @@
+name: "FAP: Build and lint"
+on: [push, pull_request]
+jobs:
+  ufbt-build-action:
+    runs-on: ubuntu-latest
+    name: 'ufbt: Build for release branch'
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+      - name: Build with ufbt
+        uses: flipperdevices/flipperzero-ufbt-action@v0.1.2
+        id: build-app
+        with:
+          sdk-channel: release
+      - name: Upload app artifacts
+        uses: actions/upload-artifact@v3
+        with:
+          name: ${{ github.event.repository.name }}-${{ steps.build-app.outputs.suffix }}
+          path: ${{ steps.build-app.outputs.fap-artifacts }}
+      # You can remove this step if you don't want to check source code formatting
+      - name: Lint sources
+        uses: flipperdevices/flipperzero-ufbt-action@v0.1.2
+        with:
+          # skip SDK setup, we already did it in previous step
+          skip-setup: true
+          task: lint

+ 2 - 0
seader/.gitignore

@@ -0,0 +1,2 @@
+.vscode/
+dist/

+ 1 - 0
seader/.gitsubtree

@@ -0,0 +1 @@
+https://github.com/xMasterX/all-the-plugins dev non_catalog_apps/seader

+ 674 - 0
seader/LICENSE

@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<https://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<https://www.gnu.org/licenses/why-not-lgpl.html>.

+ 32 - 0
seader/Makefile

@@ -0,0 +1,32 @@
+lib_LTLIBRARIES=libsomething.la
+libsomething_la_SOURCES=$(ASN_MODULE_SOURCES) $(ASN_MODULE_HEADERS)
+
+ASN_CONVERTER_SOURCES+=test/parse.c
+ASN_MODULE_SOURCES=$(wildcard lib/asn1/*.c)
+ASN_MODULE_HEADERS=$(wildcard lib/asn1/*.h)
+
+TARGET = parse
+CFLAGS += -I. -Ilib/asn1
+OBJS=${ASN_MODULE_SOURCES:.c=.o} ${ASN_CONVERTER_SOURCES:.c=.o}
+
+all: regen
+
+test: $(TARGET)
+
+$(TARGET): regen ${OBJS}
+	$(CC) $(CFLAGS) -o $(TARGET) ${OBJS} $(LDFLAGS) $(LIBS)
+
+.SUFFIXES:
+.SUFFIXES: .c .o
+
+.c.o:
+	$(CC) $(CFLAGS) -o $@ -c $<
+
+regen: regenerate-from-asn1-source
+
+regenerate-from-asn1-source:
+	@asn1c -D lib/asn1 -no-gen-example -pdu=all seader.asn1
+
+clean:
+	rm -f $(TARGET)
+	rm -f $(OBJS)

BIN
seader/Seader.png


+ 45 - 0
seader/aeabi_uldivmod.sx

@@ -0,0 +1,45 @@
+//===-- aeabi_uldivmod.S - EABI uldivmod implementation -------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "assembly.h"
+
+// struct { uint64_t quot, uint64_t rem}
+//        __aeabi_uldivmod(uint64_t numerator, uint64_t denominator) {
+//   uint64_t rem, quot;
+//   quot = __udivmoddi4(numerator, denominator, &rem);
+//   return {quot, rem};
+// }
+
+#if defined(__MINGW32__)
+#define __aeabi_uldivmod __rt_udiv64
+#endif
+
+        .syntax unified
+        .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__aeabi_uldivmod)
+        push	{r6, lr}
+        sub	sp, sp, #16
+        add	r6, sp, #8
+        str	r6, [sp]
+#if defined(__MINGW32__)
+        movs    r6, r0
+        movs    r0, r2
+        movs    r2, r6
+        movs    r6, r1
+        movs    r1, r3
+        movs    r3, r6
+#endif
+        bl	SYMBOL_NAME(__udivmoddi4)
+        ldr	r2, [sp, #8]
+        ldr	r3, [sp, #12]
+        add	sp, sp, #16
+        pop	{r6, pc}
+END_COMPILERRT_FUNCTION(__aeabi_uldivmod)
+
+NO_EXEC_STACK_DIRECTIVE
+

+ 41 - 0
seader/application.fam

@@ -0,0 +1,41 @@
+# qv. https://github.com/flipperdevices/flipperzero-firmware/blob/dev/documentation/AppManifests.md
+
+App(
+    appid="seader",
+    name="Seader",
+    apptype=FlipperAppType.EXTERNAL,
+    entry_point="seader_app",
+    cdefines=["APP_SEADER"],
+    requires=[
+        "gui", "storage", "nfc",
+    ],
+    stack_size=7 * 1024,
+    order=20,
+    sources=[
+      "*.c",
+      "aeabi_uldivmod.sx",
+    ],
+    fap_icon="icons/logo.png",
+    fap_category="NFC",
+    fap_version="2.3",
+    fap_author="bettse",
+#    fap_extbuild=(
+#        ExtFile(
+#            path="${FAP_SRC_DIR}/lib/asn1/asn_system.h",
+#            command="asn1c -D ${FAP_SRC_DIR}/lib/asn1 -no-gen-example -pdu=all ${FAP_SRC_DIR}/seader.asn1"
+#        ),
+#    ),
+    fap_libs=["mbedtls"],
+    fap_private_libs=[
+        Lib(
+            name="asn1",
+            cflags=["-Wno-error"],
+        ),
+        Lib(
+            name="loclass",
+            cflags=["-O3"],
+        ),
+    ],
+    fap_weburl="https://seader.ericbetts.dev",
+    fap_icon_assets="icons",
+)

+ 268 - 0
seader/assembly.h

@@ -0,0 +1,268 @@
+//===-- assembly.h - compiler-rt assembler support macros -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines macros for use in compiler-rt assembler source.
+// This file is not part of the interface of this library.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef COMPILERRT_ASSEMBLY_H
+#define COMPILERRT_ASSEMBLY_H
+
+#if defined(__linux__) && defined(__CET__)
+#if __has_include(<cet.h>)
+#include <cet.h>
+#endif
+#endif
+
+#if defined(__APPLE__) && defined(__aarch64__)
+#define SEPARATOR % %
+#else
+#define SEPARATOR ;
+#endif
+
+#if defined(__APPLE__)
+#define HIDDEN(name) .private_extern name
+#define LOCAL_LABEL(name) L_##name
+// tell linker it can break up file at label boundaries
+#define FILE_LEVEL_DIRECTIVE .subsections_via_symbols
+#define SYMBOL_IS_FUNC(name)
+#define CONST_SECTION .const
+
+#define NO_EXEC_STACK_DIRECTIVE
+
+#elif defined(__ELF__)
+
+#define HIDDEN(name) .hidden name
+#define LOCAL_LABEL(name) .L_##name
+#define FILE_LEVEL_DIRECTIVE
+#if defined(__arm__) || defined(__aarch64__)
+#define SYMBOL_IS_FUNC(name) .type name, % function
+#else
+#define SYMBOL_IS_FUNC(name) .type name, @function
+#endif
+#define CONST_SECTION .section.rodata
+
+#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || defined(__linux__)
+#define NO_EXEC_STACK_DIRECTIVE .section.note.GNU - stack, "", % progbits
+#else
+#define NO_EXEC_STACK_DIRECTIVE
+#endif
+
+#else // !__APPLE__ && !__ELF__
+
+#define HIDDEN(name)
+#define LOCAL_LABEL(name) .L##name
+#define FILE_LEVEL_DIRECTIVE
+#define SYMBOL_IS_FUNC(name) .def name SEPARATOR.scl 2 SEPARATOR.type 32 SEPARATOR.endef
+#define CONST_SECTION .section.rdata, "rd"
+
+#define NO_EXEC_STACK_DIRECTIVE
+
+#endif
+
+#if defined(__arm__) || defined(__aarch64__)
+#define FUNC_ALIGN .text SEPARATOR.balign 16 SEPARATOR
+#else
+#define FUNC_ALIGN
+#endif
+
+// BTI and PAC gnu property note
+#define NT_GNU_PROPERTY_TYPE_0 5
+#define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000
+#define GNU_PROPERTY_AARCH64_FEATURE_1_BTI 1
+#define GNU_PROPERTY_AARCH64_FEATURE_1_PAC 2
+
+#if defined(__ARM_FEATURE_BTI_DEFAULT)
+#define BTI_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_BTI
+#else
+#define BTI_FLAG 0
+#endif
+
+#if __ARM_FEATURE_PAC_DEFAULT & 3
+#define PAC_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_PAC
+#else
+#define PAC_FLAG 0
+#endif
+
+#define GNU_PROPERTY(type, value)                                                  \
+    .pushsection.note.gnu.property,                                                \
+        "a" SEPARATOR.p2align 3 SEPARATOR.word 4 SEPARATOR.word 16 SEPARATOR       \
+            .word NT_GNU_PROPERTY_TYPE_0 SEPARATOR.asciz "GNU" SEPARATOR.word type \
+                SEPARATOR.word 4 SEPARATOR.word value SEPARATOR.word 0 SEPARATOR.popsection
+
+#if BTI_FLAG != 0
+#define BTI_C hint #34
+#define BTI_J hint #36
+#else
+#define BTI_C
+#define BTI_J
+#endif
+
+#if(BTI_FLAG | PAC_FLAG) != 0
+#define GNU_PROPERTY_BTI_PAC GNU_PROPERTY(GNU_PROPERTY_AARCH64_FEATURE_1_AND, BTI_FLAG | PAC_FLAG)
+#else
+#define GNU_PROPERTY_BTI_PAC
+#endif
+
+#if defined(__clang__) || defined(__GCC_HAVE_DWARF2_CFI_ASM)
+#define CFI_START .cfi_startproc
+#define CFI_END .cfi_endproc
+#else
+#define CFI_START
+#define CFI_END
+#endif
+
+#if defined(__arm__)
+
+// Determine actual [ARM][THUMB[1][2]] ISA using compiler predefined macros:
+// - for '-mthumb -march=armv6' compiler defines '__thumb__'
+// - for '-mthumb -march=armv7' compiler defines '__thumb__' and '__thumb2__'
+#if defined(__thumb2__) || defined(__thumb__)
+#define DEFINE_CODE_STATE .thumb SEPARATOR
+#define DECLARE_FUNC_ENCODING .thumb_func SEPARATOR
+#if defined(__thumb2__)
+#define USE_THUMB_2
+#define IT(cond) it cond
+#define ITT(cond) itt cond
+#define ITE(cond) ite cond
+#else
+#define USE_THUMB_1
+#define IT(cond)
+#define ITT(cond)
+#define ITE(cond)
+#endif // defined(__thumb__2)
+#else // !defined(__thumb2__) && !defined(__thumb__)
+#define DEFINE_CODE_STATE .arm SEPARATOR
+#define DECLARE_FUNC_ENCODING
+#define IT(cond)
+#define ITT(cond)
+#define ITE(cond)
+#endif
+
+#if defined(USE_THUMB_1) && defined(USE_THUMB_2)
+#error "USE_THUMB_1 and USE_THUMB_2 can't be defined together."
+#endif
+
+#if defined(__ARM_ARCH_4T__) || __ARM_ARCH >= 5
+#define ARM_HAS_BX
+#endif
+#if !defined(__ARM_FEATURE_CLZ) && !defined(USE_THUMB_1) && \
+    (__ARM_ARCH >= 6 || (__ARM_ARCH == 5 && !defined(__ARM_ARCH_5__)))
+#define __ARM_FEATURE_CLZ
+#endif
+
+#ifdef ARM_HAS_BX
+#define JMP(r) bx r
+#define JMPc(r, c) bx##c r
+#else
+#define JMP(r) mov pc, r
+#define JMPc(r, c) mov##c pc, r
+#endif
+
+// pop {pc} can't switch Thumb mode on ARMv4T
+#if __ARM_ARCH >= 5
+#define POP_PC() \
+    pop {        \
+        pc       \
+    }
+#else
+#define POP_PC() \
+    pop{ip};     \
+    JMP(ip)
+#endif
+
+#if defined(USE_THUMB_2)
+#define WIDE(op) op.w
+#else
+#define WIDE(op) op
+#endif
+#else // !defined(__arm)
+#define DECLARE_FUNC_ENCODING
+#define DEFINE_CODE_STATE
+#endif
+
+#define GLUE2_(a, b) a##b
+#define GLUE(a, b) GLUE2_(a, b)
+#define GLUE2(a, b) GLUE2_(a, b)
+#define GLUE3_(a, b, c) a##b##c
+#define GLUE3(a, b, c) GLUE3_(a, b, c)
+#define GLUE4_(a, b, c, d) a##b##c##d
+#define GLUE4(a, b, c, d) GLUE4_(a, b, c, d)
+
+#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
+
+#ifdef VISIBILITY_HIDDEN
+#define DECLARE_SYMBOL_VISIBILITY(name) HIDDEN(SYMBOL_NAME(name)) SEPARATOR
+#define DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name) HIDDEN(name) SEPARATOR
+#else
+#define DECLARE_SYMBOL_VISIBILITY(name)
+#define DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name)
+#endif
+
+#define DEFINE_COMPILERRT_FUNCTION(name)                                        \
+    DEFINE_CODE_STATE                                                           \
+    FILE_LEVEL_DIRECTIVE SEPARATOR.globl SYMBOL_NAME(name)                      \
+    SEPARATOR                                                                   \
+    SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR DECLARE_SYMBOL_VISIBILITY(name) \
+    DECLARE_FUNC_ENCODING                                                       \
+    SYMBOL_NAME(name)                                                           \
+        :
+
+#define DEFINE_COMPILERRT_THUMB_FUNCTION(name)                                                 \
+    DEFINE_CODE_STATE                                                                          \
+    FILE_LEVEL_DIRECTIVE SEPARATOR.globl SYMBOL_NAME(name)                                     \
+    SEPARATOR                                                                                  \
+    SYMBOL_IS_FUNC(SYMBOL_NAME(name))                                                          \
+    SEPARATOR DECLARE_SYMBOL_VISIBILITY(name) SEPARATOR.thumb_func SEPARATOR SYMBOL_NAME(name) \
+        :
+
+#define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name)                                          \
+    DEFINE_CODE_STATE                                                                     \
+    FILE_LEVEL_DIRECTIVE SEPARATOR.globl SYMBOL_NAME(name)                                \
+    SEPARATOR                                                                             \
+    SYMBOL_IS_FUNC(SYMBOL_NAME(name))                                                     \
+    SEPARATOR HIDDEN(SYMBOL_NAME(name)) SEPARATOR DECLARE_FUNC_ENCODING SYMBOL_NAME(name) \
+        :
+
+#define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name)      \
+    DEFINE_CODE_STATE.globl name SEPARATOR SYMBOL_IS_FUNC(name) \
+    SEPARATOR                                                   \
+    HIDDEN(name) SEPARATOR DECLARE_FUNC_ENCODING name:
+
+#define DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(name) \
+    DEFINE_CODE_STATE                                      \
+    FUNC_ALIGN.globl name SEPARATOR SYMBOL_IS_FUNC(name)   \
+    SEPARATOR                                              \
+    DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name)              \
+    SEPARATOR CFI_START SEPARATOR DECLARE_FUNC_ENCODING name : SEPARATOR BTI_C
+
+#define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target)                                      \
+    .globl SYMBOL_NAME(name)                                                                \
+    SEPARATOR                                                                               \
+    SYMBOL_IS_FUNC(SYMBOL_NAME(name))                                                       \
+    SEPARATOR DECLARE_SYMBOL_VISIBILITY(SYMBOL_NAME(name)) SEPARATOR.set SYMBOL_NAME(name), \
+        SYMBOL_NAME(target) SEPARATOR
+
+#if defined(__ARM_EABI__)
+#define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name) \
+    DEFINE_COMPILERRT_FUNCTION_ALIAS(aeabi_name, name)
+#else
+#define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name)
+#endif
+
+#ifdef __ELF__
+#define END_COMPILERRT_FUNCTION(name) .size SYMBOL_NAME(name), .- SYMBOL_NAME(name)
+#define END_COMPILERRT_OUTLINE_FUNCTION(name) \
+    CFI_END SEPARATOR.size SYMBOL_NAME(name), .- SYMBOL_NAME(name)
+#else
+#define END_COMPILERRT_FUNCTION(name)
+#define END_COMPILERRT_OUTLINE_FUNCTION(name) CFI_END
+#endif
+
+#endif // COMPILERRT_ASSEMBLY_H

+ 101 - 0
seader/bsearch.c

@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 1990, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bsearch.c	8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/lib/libc/stdlib/bsearch.c,v 1.4 2007/01/09 00:28:09 imp Exp $");
+
+#include <stddef.h>
+#include <stdlib.h>
+
+/*
+ * Perform a binary search.
+ *
+ * The code below is a bit sneaky.  After a comparison fails, we
+ * divide the work in half by moving either left or right. If lim
+ * is odd, moving left simply involves halving lim: e.g., when lim
+ * is 5 we look at item 2, so we change lim to 2 so that we will
+ * look at items 0 & 1.  If lim is even, the same applies.  If lim
+ * is odd, moving right again involes halving lim, this time moving
+ * the base up one item past p: e.g., when lim is 5 we change base
+ * to item 3 and make lim 2 so that we will look at items 3 and 4.
+ * If lim is even, however, we have to shrink it by one before
+ * halving: e.g., when lim is 4, we still looked at item 2, so we
+ * have to make lim 3, then halve, obtaining 1, so that we will only
+ * look at item 3.
+ */
+void* bsearch(key, base0, nmemb, size, compar) const void* key;
+const void* base0;
+size_t nmemb;
+size_t size;
+int (*compar)(const void*, const void*);
+{
+    const char* base = base0;
+    size_t lim;
+    int cmp;
+    const void* p;
+
+    for(lim = nmemb; lim != 0; lim >>= 1) {
+        p = base + (lim >> 1) * size;
+        cmp = (*compar)(key, p);
+        if(cmp == 0) return ((void*)p);
+        if(cmp > 0) { /* key > p: move right */
+            base = (char*)p + size;
+            lim--;
+        } /* else move left */
+    }
+    return (NULL);
+}
+
+#ifdef __BLOCKS__
+void* bsearch_b(key, base0, nmemb, size, compar) const void* key;
+const void* base0;
+size_t nmemb;
+size_t size;
+int (^compar)(const void*, const void*);
+{
+    const char* base = base0;
+    size_t lim;
+    int cmp;
+    const void* p;
+
+    for(lim = nmemb; lim != 0; lim >>= 1) {
+        p = base + (lim >> 1) * size;
+        cmp = compar(key, p);
+        if(cmp == 0) return ((void*)p);
+        if(cmp > 0) { /* key > p: move right */
+            base = (char*)p + size;
+            lim--;
+        } /* else move left */
+    }
+    return (NULL);
+}
+#endif /* __BLOCKS__ */

+ 339 - 0
seader/ccid.c

@@ -0,0 +1,339 @@
+#include "seader_i.h"
+
+#define TAG "SeaderCCID"
+
+bool hasSAM = false;
+const uint8_t SAM_ATR[] =
+    {0x3b, 0x95, 0x96, 0x80, 0xb1, 0xfe, 0x55, 0x1f, 0xc7, 0x47, 0x72, 0x61, 0x63, 0x65, 0x13};
+const uint8_t SAM_ATR2[] = {0x3b, 0x90, 0x96, 0x91, 0x81, 0xb1, 0xfe, 0x55, 0x1f, 0xc7, 0xd4};
+
+bool powered[2] = {false, false};
+uint8_t sam_slot = 0;
+uint8_t sequence[2] = {0, 0};
+uint8_t retries = 3;
+
+uint8_t getSequence(uint8_t slot) {
+    if(sequence[slot] > 254) {
+        sequence[slot] = 0;
+    }
+    return sequence[slot]++;
+}
+
+size_t seader_ccid_add_lrc(uint8_t* data, size_t len) {
+    uint8_t lrc = 0;
+    for(size_t i = 0; i < len; i++) {
+        lrc ^= data[i];
+    }
+    data[len] = lrc;
+    return len + 1;
+}
+
+void seader_ccid_IccPowerOn(SeaderUartBridge* seader_uart, uint8_t slot) {
+    if(powered[slot]) {
+        return;
+    }
+    powered[slot] = true;
+
+    FURI_LOG_D(TAG, "Sending Power On (%d)", slot);
+    memset(seader_uart->tx_buf, 0, SEADER_UART_RX_BUF_SIZE);
+    seader_uart->tx_buf[0] = SYNC;
+    seader_uart->tx_buf[1] = CTRL;
+    seader_uart->tx_buf[2 + 0] = CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn;
+
+    seader_uart->tx_buf[2 + 5] = slot;
+    seader_uart->tx_buf[2 + 6] = getSequence(slot);
+    seader_uart->tx_buf[2 + 7] = 2; //power
+
+    seader_uart->tx_len = seader_ccid_add_lrc(seader_uart->tx_buf, 2 + 10);
+    furi_thread_flags_set(furi_thread_get_id(seader_uart->tx_thread), WorkerEvtSamRx);
+}
+
+void seader_ccid_check_for_sam(SeaderUartBridge* seader_uart) {
+    hasSAM = false; // If someone is calling this, reset sam state
+    powered[0] = false;
+    powered[1] = false;
+    retries = 3;
+    seader_ccid_GetSlotStatus(seader_uart, 0);
+}
+
+void seader_ccid_GetSlotStatus(SeaderUartBridge* seader_uart, uint8_t slot) {
+    FURI_LOG_D(TAG, "seader_ccid_GetSlotStatus(%d)", slot);
+    memset(seader_uart->tx_buf, 0, SEADER_UART_RX_BUF_SIZE);
+    seader_uart->tx_buf[0] = SYNC;
+    seader_uart->tx_buf[1] = CTRL;
+    seader_uart->tx_buf[2 + 0] = CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus;
+    seader_uart->tx_buf[2 + 5] = slot;
+    seader_uart->tx_buf[2 + 6] = getSequence(slot);
+
+    seader_uart->tx_len = seader_ccid_add_lrc(seader_uart->tx_buf, 2 + 10);
+    furi_thread_flags_set(furi_thread_get_id(seader_uart->tx_thread), WorkerEvtSamRx);
+}
+
+void seader_ccid_SetParameters(SeaderUartBridge* seader_uart) {
+    uint8_t T1 = 1;
+    memset(seader_uart->tx_buf, 0, SEADER_UART_RX_BUF_SIZE);
+    seader_uart->tx_buf[0] = SYNC;
+    seader_uart->tx_buf[1] = CTRL;
+    seader_uart->tx_buf[2 + 0] = CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters;
+    seader_uart->tx_buf[2 + 1] = 0;
+    seader_uart->tx_buf[2 + 5] = sam_slot;
+    seader_uart->tx_buf[2 + 6] = getSequence(sam_slot);
+    seader_uart->tx_buf[2 + 7] = T1;
+    seader_uart->tx_buf[2 + 8] = 0;
+    seader_uart->tx_buf[2 + 9] = 0;
+
+    seader_uart->tx_len = seader_ccid_add_lrc(seader_uart->tx_buf, 2 + 10);
+
+    furi_thread_flags_set(furi_thread_get_id(seader_uart->tx_thread), WorkerEvtSamRx);
+}
+
+void seader_ccid_GetParameters(SeaderUartBridge* seader_uart) {
+    memset(seader_uart->tx_buf, 0, SEADER_UART_RX_BUF_SIZE);
+    seader_uart->tx_buf[0] = SYNC;
+    seader_uart->tx_buf[1] = CTRL;
+    seader_uart->tx_buf[2 + 0] = CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters;
+    seader_uart->tx_buf[2 + 1] = 0;
+    seader_uart->tx_buf[2 + 5] = sam_slot;
+    seader_uart->tx_buf[2 + 6] = getSequence(sam_slot);
+    seader_uart->tx_buf[2 + 7] = 0;
+    seader_uart->tx_buf[2 + 8] = 0;
+    seader_uart->tx_buf[2 + 9] = 0;
+
+    seader_uart->tx_len = seader_ccid_add_lrc(seader_uart->tx_buf, 2 + 10);
+
+    furi_thread_flags_set(furi_thread_get_id(seader_uart->tx_thread), WorkerEvtSamRx);
+}
+
+void seader_ccid_XfrBlock(SeaderUartBridge* seader_uart, uint8_t* data, size_t len) {
+    seader_ccid_XfrBlockToSlot(seader_uart, sam_slot, data, len);
+}
+
+void seader_ccid_XfrBlockToSlot(
+    SeaderUartBridge* seader_uart,
+    uint8_t slot,
+    uint8_t* data,
+    size_t len) {
+    memset(seader_uart->tx_buf, 0, SEADER_UART_RX_BUF_SIZE);
+    seader_uart->tx_buf[0] = SYNC;
+    seader_uart->tx_buf[1] = CTRL;
+    seader_uart->tx_buf[2 + 0] = CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock;
+    seader_uart->tx_buf[2 + 1] = len;
+    seader_uart->tx_buf[2 + 5] = slot;
+    seader_uart->tx_buf[2 + 6] = getSequence(slot);
+    seader_uart->tx_buf[2 + 7] = 5;
+    seader_uart->tx_buf[2 + 8] = 0;
+    seader_uart->tx_buf[2 + 9] = 0;
+
+    memcpy(seader_uart->tx_buf + 2 + 10, data, len);
+    seader_uart->tx_len = seader_ccid_add_lrc(seader_uart->tx_buf, 2 + 10 + len);
+    // FURI_LOG_I(TAG, "seader_ccid_XfrBlock %d bytes", seader_uart->tx_len);
+
+    furi_thread_flags_set(furi_thread_get_id(seader_uart->tx_thread), WorkerEvtSamRx);
+}
+
+size_t seader_ccid_process(Seader* seader, uint8_t* cmd, size_t cmd_len) {
+    SeaderWorker* seader_worker = seader->worker;
+    SeaderUartBridge* seader_uart = seader_worker->uart;
+    CCID_Message message;
+    message.consumed = 0;
+
+    char display[SEADER_UART_RX_BUF_SIZE * 2 + 1] = {0};
+    for(uint8_t i = 0; i < cmd_len; i++) {
+        snprintf(display + (i * 2), sizeof(display), "%02x", cmd[i]);
+    }
+    // FURI_LOG_D(TAG, "UART %d: %s", cmd_len, display);
+
+    if(cmd_len == 2) {
+        if(cmd[0] == CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange) {
+            switch(cmd[1] & SLOT_0_MASK) {
+            case 0:
+            case 1:
+                // No change, no-op
+                break;
+            case CARD_IN_1:
+                FURI_LOG_D(TAG, "Card Inserted (0)");
+                if(hasSAM && sam_slot == 0) {
+                    break;
+                }
+                sequence[0] = 0;
+                seader_ccid_IccPowerOn(seader_uart, 0);
+                break;
+            case CARD_OUT_1:
+                FURI_LOG_D(TAG, "Card Removed (0)");
+                if(hasSAM && sam_slot == 0) {
+                    powered[0] = false;
+                    hasSAM = false;
+                    retries = 3;
+                }
+                break;
+            };
+
+            switch(cmd[1] & SLOT_1_MASK) {
+            case 0:
+            case 1:
+                // No change, no-op
+                break;
+            case CARD_IN_2:
+                FURI_LOG_D(TAG, "Card Inserted (1)");
+                if(hasSAM && sam_slot == 1) {
+                    break;
+                }
+                sequence[1] = 0;
+                seader_ccid_IccPowerOn(seader_uart, 1);
+                break;
+            case CARD_OUT_2:
+                FURI_LOG_D(TAG, "Card Removed (1)");
+                if(hasSAM && sam_slot == 1) {
+                    powered[1] = false;
+                    hasSAM = false;
+                    retries = 3;
+                }
+                break;
+            };
+
+            return 2;
+        }
+    }
+
+    while(cmd_len >= 3 && cmd[0] == SYNC && cmd[1] == NAK) {
+        // 031516
+        FURI_LOG_W(TAG, "NAK");
+        cmd += 3;
+        cmd_len -= 3;
+        message.consumed += 3;
+    }
+
+    while(cmd_len > 2 && (cmd[0] != SYNC || cmd[1] != CTRL)) {
+        FURI_LOG_W(TAG, "invalid start: %02x", cmd[0]);
+        cmd += 1;
+        cmd_len -= 1;
+        message.consumed += 1;
+    }
+
+    if(cmd_len > 12 && cmd[0] == SYNC && cmd[1] == CTRL) {
+        uint8_t* ccid = cmd + 2;
+        message.bMessageType = ccid[0];
+        message.dwLength = *((uint32_t*)(ccid + 1));
+        message.bSlot = ccid[5];
+        message.bSeq = ccid[6];
+        message.bStatus = ccid[7];
+        message.bError = ccid[8];
+        message.payload = ccid + 10;
+
+        memset(display, 0, sizeof(display));
+        for(uint8_t i = 0; i < message.dwLength; i++) {
+            snprintf(display + (i * 2), sizeof(display), "%02x", message.payload[i]);
+        }
+
+        if(cmd_len < 2 + 10 + message.dwLength + 1) {
+            return message.consumed;
+        }
+        message.consumed += 2 + 10 + message.dwLength + 1;
+
+        /*
+        if(message.dwLength == 0) {
+            FURI_LOG_D(
+                TAG,
+                "CCID [%d|%d] type: %02x, status: %02x, error: %02x",
+                message.bSlot,
+                message.bSeq,
+                message.bMessageType,
+                message.bStatus,
+                message.bError);
+        } else {
+            FURI_LOG_D(
+                TAG,
+                "CCID [%d|%d] %ld: %s",
+                message.bSlot,
+                message.bSeq,
+                message.dwLength,
+                display);
+        }
+        */
+
+        //0306 81 00000000 0000 0200 01 87
+        //0306 81 00000000 0000 0100 01 84
+        if(message.bMessageType == CCID_MESSAGE_TYPE_RDR_to_PC_SlotStatus) {
+            uint8_t status = (message.bStatus & BMICCSTATUS_MASK);
+            if(status == 0 || status == 1) {
+                seader_ccid_IccPowerOn(seader_uart, message.bSlot);
+                return message.consumed;
+            } else if(status == 2) {
+                FURI_LOG_W(TAG, "No ICC is present [retries %d]", retries);
+                if(retries-- > 1 && hasSAM == false) {
+                    furi_delay_ms(100);
+                    seader_ccid_GetSlotStatus(seader_uart, retries % 2);
+                } else {
+                    if(seader_worker->callback) {
+                        seader_worker->callback(
+                            SeaderWorkerEventSamMissing, seader_worker->context);
+                    }
+                }
+                return message.consumed;
+            }
+        }
+
+        //0306 80 00000000 0001 42fe 00 38
+        if(message.bStatus == 0x41 && message.bError == 0xfe) {
+            FURI_LOG_W(TAG, "card probably upside down");
+            if(seader_worker->callback) {
+                seader_worker->callback(SeaderWorkerEventSamMissing, seader_worker->context);
+            }
+            return message.consumed;
+        }
+        if(message.bStatus == 0x42 && message.bError == 0xfe) {
+            FURI_LOG_W(TAG, "No card");
+            if(seader_worker->callback) {
+                seader_worker->callback(SeaderWorkerEventSamMissing, seader_worker->context);
+            }
+            return message.consumed;
+        }
+        if(message.bError != 0) {
+            FURI_LOG_W(TAG, "CCID error %02x", message.bError);
+            message.consumed = cmd_len;
+            if(seader_worker->callback) {
+                seader_worker->callback(SeaderWorkerEventSamMissing, seader_worker->context);
+            }
+            return message.consumed;
+        }
+
+        if(message.bMessageType == CCID_MESSAGE_TYPE_RDR_to_PC_DataBlock) {
+            if(hasSAM) {
+                if(message.bSlot == sam_slot) {
+                    seader_worker_process_sam_message(seader, &message);
+                } else {
+                    FURI_LOG_D(TAG, "Discarding message on non-sam slot");
+                }
+            } else {
+                if(memcmp(SAM_ATR, message.payload, sizeof(SAM_ATR)) == 0) {
+                    FURI_LOG_I(TAG, "SAM ATR!");
+                    hasSAM = true;
+                    sam_slot = message.bSlot;
+                    seader_worker_send_version(seader_worker);
+                    if(seader_worker->callback) {
+                        seader_worker->callback(
+                            SeaderWorkerEventSamPresent, seader_worker->context);
+                    }
+                } else if(memcmp(SAM_ATR2, message.payload, sizeof(SAM_ATR2)) == 0) {
+                    FURI_LOG_I(TAG, "SAM ATR2!");
+                    hasSAM = true;
+                    sam_slot = message.bSlot;
+                    seader_worker_send_version(seader_worker);
+                    if(seader_worker->callback) {
+                        seader_worker->callback(
+                            SeaderWorkerEventSamPresent, seader_worker->context);
+                    }
+                } else {
+                    FURI_LOG_W(TAG, "Unknown ATR");
+                    if(seader_worker->callback) {
+                        seader_worker->callback(SeaderWorkerEventSamWrong, seader_worker->context);
+                    }
+                }
+            }
+        } else {
+            FURI_LOG_W(TAG, "Unhandled CCID message type %d", message.bMessageType);
+        }
+    }
+
+    return message.consumed;
+}

+ 106 - 0
seader/ccid.h

@@ -0,0 +1,106 @@
+#pragma once
+
+#include <stdlib.h> // malloc
+#include <stdint.h> // uint32_t
+#include <stdarg.h> // __VA_ARGS__
+#include <string.h>
+#include <stdio.h>
+
+#include "seader_bridge.h"
+#include "seader_worker_i.h"
+
+#define SYNC (0x03)
+#define CTRL (0x06)
+#define NAK (0x15)
+
+#define BMICCSTATUS_MASK 0x03
+/*
+ * Bit 0 = Slot 0 current state
+ * Bit 1 = Slot 0 changed status
+ * Bit 2 = Slot 1 current state
+ * Bit 3 = Slot 1 changed status
+ */
+
+// TODO: rename/renumber
+#define SLOT_0_MASK 0x03
+#define CARD_OUT_1 0x02
+#define CARD_IN_1 0x03
+#define SLOT_1_MASK 0x0C
+#define CARD_IN_2 0x04
+#define CARD_OUT_2 0x0C
+
+/*
+ *  * BULK_OUT messages from PC to Reader
+ *   * Defined in CCID Rev 1.1 6.1 (page 26)
+ *    */
+#define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn 0x62
+#define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff 0x63
+#define CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus 0x65
+#define CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock 0x6f
+#define CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters 0x6c
+#define CCID_MESSAGE_TYPE_PC_to_RDR_ResetParameters 0x6d
+#define CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters 0x61
+#define CCID_MESSAGE_TYPE_PC_to_RDR_Escape 0x6b
+#define CCID_MESSAGE_TYPE_PC_to_RDR_IccClock 0x6e
+#define CCID_MESSAGE_TYPE_PC_to_RDR_T0APDU 0x6a
+#define CCID_MESSAGE_TYPE_PC_to_RDR_Secure 0x69
+#define CCID_MESSAGE_TYPE_PC_to_RDR_Mechanical 0x71
+#define CCID_MESSAGE_TYPE_PC_to_RDR_Abort 0x72
+#define CCID_MESSAGE_TYPE_PC_to_RDR_SetDataRateAndClockFrequency 0x73
+/*
+ *  * BULK_IN messages from Reader to PC
+ *   * Defined in CCID Rev 1.1 6.2 (page 48)
+ *    */
+#define CCID_MESSAGE_TYPE_RDR_to_PC_DataBlock 0x80
+#define CCID_MESSAGE_TYPE_RDR_to_PC_SlotStatus 0x81
+#define CCID_MESSAGE_TYPE_RDR_to_PC_Parameters 0x82
+#define CCID_MESSAGE_TYPE_RDR_to_PC_Escape 0x83
+#define CCID_MESSAGE_TYPE_RDR_to_PC_DataRateAndClockFrequency 0x84
+/*
+ *  * INTERRUPT_IN messages from Reader to PC
+ *   * Defined in CCID Rev 1.1 6.3 (page 56)
+ *    */
+#define CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange 0x50
+#define CCID_MESSAGE_TYPE_RDR_to_PC_HardwareError 0x51
+
+/* Status codes that go in bStatus (see 6.2.6) */
+enum { ICC_STATUS_PRESENT_ACTIVE = 0, ICC_STATUS_PRESENT_INACTIVE, ICC_STATUS_NOT_PRESENT };
+enum {
+    COMMAND_STATUS_NO_ERROR = 0,
+    COMMAND_STATUS_FAILED,
+    COMMAND_STATUS_TIME_EXTENSION_REQUIRED
+};
+/* Error codes that go in bError (see 6.2.6) */
+enum {
+    ERROR_CMD_NOT_SUPPORTED = 0,
+    ERROR_CMD_ABORTED = -1,
+    ERROR_ICC_MUTE = -2,
+    ERROR_XFR_PARITY_ERROR = -3,
+    ERROR_XFR_OVERRUN = -4,
+    ERROR_HW_ERROR = -5,
+};
+
+struct CCID_Message {
+    uint8_t bMessageType;
+    uint32_t dwLength;
+    uint8_t bSlot;
+    uint8_t bSeq;
+    uint8_t bStatus;
+    uint8_t bError;
+
+    uint8_t* payload;
+    size_t consumed;
+};
+
+void seader_ccid_check_for_sam(SeaderUartBridge* seader_uart);
+void seader_ccid_IccPowerOn(SeaderUartBridge* seader_uart, uint8_t slot);
+void seader_ccid_GetSlotStatus(SeaderUartBridge* seader_uart, uint8_t slot);
+void seader_ccid_SetParameters(SeaderUartBridge* seader_uart);
+void seader_ccid_GetParameters(SeaderUartBridge* seader_uart);
+void seader_ccid_XfrBlock(SeaderUartBridge* seader_uart, uint8_t* data, size_t len);
+void seader_ccid_XfrBlockToSlot(
+    SeaderUartBridge* seader_uart,
+    uint8_t slot,
+    uint8_t* data,
+    size_t len);
+size_t seader_ccid_process(Seader* seader, uint8_t* cmd, size_t cmd_len);

+ 3 - 0
seader/changelog.md

@@ -0,0 +1,3 @@
+# Changelog
+
+I don't use a changelog, check git

BIN
seader/fake_screenshot.pxd


BIN
seader/icons/ArrowUpEmpty_14x15.png


BIN
seader/icons/ArrowUpFilled_14x15.png


BIN
seader/icons/DolphinMafia_115x62.png


BIN
seader/icons/DolphinNice_96x59.png


BIN
seader/icons/Nfc_10px.png


BIN
seader/icons/RFIDDolphinReceive_97x61.png


BIN
seader/icons/RFIDDolphinSend_97x61.png


BIN
seader/icons/logo.png


+ 2 - 0
seader/lib/asn1/.gitignore

@@ -0,0 +1,2 @@
+Makefile.am.*
+converter-example.mk

+ 0 - 0
seader/lib/asn1/.gitkeep


+ 652 - 0
seader/lib/asn1/BIT_STRING.c

@@ -0,0 +1,652 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <asn_internal.h>
+#include <BIT_STRING.h>
+#include <asn_internal.h>
+
+/*
+ * BIT STRING basic type description.
+ */
+static const ber_tlv_tag_t asn_DEF_BIT_STRING_tags[] = {
+	(ASN_TAG_CLASS_UNIVERSAL | (3 << 2))
+};
+asn_OCTET_STRING_specifics_t asn_SPC_BIT_STRING_specs = {
+	sizeof(BIT_STRING_t),
+	offsetof(BIT_STRING_t, _asn_ctx),
+	ASN_OSUBV_BIT
+};
+asn_TYPE_operation_t asn_OP_BIT_STRING = {
+	OCTET_STRING_free,         /* Implemented in terms of OCTET STRING */
+	BIT_STRING_print,
+	BIT_STRING_compare,
+	OCTET_STRING_decode_ber,   /* Implemented in terms of OCTET STRING */
+	OCTET_STRING_encode_der,   /* Implemented in terms of OCTET STRING */
+	OCTET_STRING_decode_xer_binary,
+	BIT_STRING_encode_xer,
+#ifdef	ASN_DISABLE_OER_SUPPORT
+	0,
+	0,
+#else
+	BIT_STRING_decode_oer,
+	BIT_STRING_encode_oer,
+#endif  /* ASN_DISABLE_OER_SUPPORT */
+#ifdef	ASN_DISABLE_PER_SUPPORT
+	0,
+	0,
+#else
+	BIT_STRING_decode_uper,	/* Unaligned PER decoder */
+	BIT_STRING_encode_uper,	/* Unaligned PER encoder */
+#endif  /* ASN_DISABLE_PER_SUPPORT */
+	BIT_STRING_random_fill,
+	0	/* Use generic outmost tag fetcher */
+};
+asn_TYPE_descriptor_t asn_DEF_BIT_STRING = {
+	"BIT STRING",
+	"BIT_STRING",
+	&asn_OP_BIT_STRING,
+	asn_DEF_BIT_STRING_tags,
+	sizeof(asn_DEF_BIT_STRING_tags)
+	  / sizeof(asn_DEF_BIT_STRING_tags[0]),
+	asn_DEF_BIT_STRING_tags,	/* Same as above */
+	sizeof(asn_DEF_BIT_STRING_tags)
+	  / sizeof(asn_DEF_BIT_STRING_tags[0]),
+	{ 0, 0, BIT_STRING_constraint },
+	0, 0,	/* No members */
+	&asn_SPC_BIT_STRING_specs
+};
+
+/*
+ * BIT STRING generic constraint.
+ */
+int
+BIT_STRING_constraint(const asn_TYPE_descriptor_t *td, const void *sptr,
+                      asn_app_constraint_failed_f *ctfailcb, void *app_key) {
+    const BIT_STRING_t *st = (const BIT_STRING_t *)sptr;
+
+	if(st && st->buf) {
+		if((st->size == 0 && st->bits_unused)
+		|| st->bits_unused < 0 || st->bits_unused > 7) {
+			ASN__CTFAIL(app_key, td, sptr,
+				"%s: invalid padding byte (%s:%d)",
+				td->name, __FILE__, __LINE__);
+			return -1;
+		}
+	} else {
+		ASN__CTFAIL(app_key, td, sptr,
+			"%s: value not given (%s:%d)",
+			td->name, __FILE__, __LINE__);
+		return -1;
+	}
+
+	return 0;
+}
+
+static const char *_bit_pattern[16] = {
+	"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111",
+	"1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"
+};
+
+asn_enc_rval_t
+BIT_STRING_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr,
+                      int ilevel, enum xer_encoder_flags_e flags,
+                      asn_app_consume_bytes_f *cb, void *app_key) {
+    asn_enc_rval_t er;
+	char scratch[128];
+	char *p = scratch;
+	char *scend = scratch + (sizeof(scratch) - 10);
+	const BIT_STRING_t *st = (const BIT_STRING_t *)sptr;
+	int xcan = (flags & XER_F_CANONICAL);
+	uint8_t *buf;
+	uint8_t *end;
+
+	if(!st || !st->buf)
+		ASN__ENCODE_FAILED;
+
+	er.encoded = 0;
+
+	buf = st->buf;
+	end = buf + st->size - 1;	/* Last byte is special */
+
+	/*
+	 * Binary dump
+	 */
+	for(; buf < end; buf++) {
+		int v = *buf;
+		int nline = xcan?0:(((buf - st->buf) % 8) == 0);
+		if(p >= scend || nline) {
+			ASN__CALLBACK(scratch, p - scratch);
+			p = scratch;
+			if(nline) ASN__TEXT_INDENT(1, ilevel);
+		}
+		memcpy(p + 0, _bit_pattern[v >> 4], 4);
+		memcpy(p + 4, _bit_pattern[v & 0x0f], 4);
+		p += 8;
+	}
+
+	if(!xcan && ((buf - st->buf) % 8) == 0)
+		ASN__TEXT_INDENT(1, ilevel);
+	ASN__CALLBACK(scratch, p - scratch);
+	p = scratch;
+
+	if(buf == end) {
+		int v = *buf;
+		int ubits = st->bits_unused;
+		int i;
+		for(i = 7; i >= ubits; i--)
+			*p++ = (v & (1 << i)) ? 0x31 : 0x30;
+		ASN__CALLBACK(scratch, p - scratch);
+	}
+
+	if(!xcan) ASN__TEXT_INDENT(1, ilevel - 1);
+
+	ASN__ENCODED_OK(er);
+cb_failed:
+	ASN__ENCODE_FAILED;
+}
+
+
+/*
+ * BIT STRING specific contents printer.
+ */
+int
+BIT_STRING_print(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
+                 asn_app_consume_bytes_f *cb, void *app_key) {
+    const char * const h2c = "0123456789ABCDEF";
+	char scratch[64];
+	const BIT_STRING_t *st = (const BIT_STRING_t *)sptr;
+	uint8_t *buf;
+	uint8_t *end;
+	char *p = scratch;
+
+	(void)td;	/* Unused argument */
+
+	if(!st || !st->buf)
+		return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
+
+	ilevel++;
+	buf = st->buf;
+	end = buf + st->size;
+
+	/*
+	 * Hexadecimal dump.
+	 */
+	for(; buf < end; buf++) {
+		if((buf - st->buf) % 16 == 0 && (st->size > 16)
+				&& buf != st->buf) {
+			_i_INDENT(1);
+			/* Dump the string */
+			if(cb(scratch, p - scratch, app_key) < 0) return -1;
+			p = scratch;
+		}
+		*p++ = h2c[*buf >> 4];
+		*p++ = h2c[*buf & 0x0F];
+		*p++ = 0x20;
+	}
+
+	if(p > scratch) {
+		p--;	/* Eat the tailing space */
+
+		if((st->size > 16)) {
+			_i_INDENT(1);
+		}
+
+		/* Dump the incomplete 16-bytes row */
+		if(cb(scratch, p - scratch, app_key) < 0)
+			return -1;
+	}
+
+    if(st->bits_unused) {
+        int ret = snprintf(scratch, sizeof(scratch), " (%d bit%s unused)",
+                           st->bits_unused, st->bits_unused == 1 ? "" : "s");
+        assert(ret > 0 && ret < (ssize_t)sizeof(scratch));
+        if(ret > 0 && ret < (ssize_t)sizeof(scratch)
+           && cb(scratch, ret, app_key) < 0)
+            return -1;
+    }
+
+	return 0;
+}
+
+/*
+ * Non-destructively remove the trailing 0-bits from the given bit string.
+ */
+static const BIT_STRING_t *
+BIT_STRING__compactify(const BIT_STRING_t *st, BIT_STRING_t *tmp) {
+    const uint8_t *b;
+    union {
+        const uint8_t *c_buf;
+        uint8_t *nc_buf;
+    } unconst;
+
+    if(st->size == 0) {
+        assert(st->bits_unused == 0);
+        return st;
+    } else {
+        for(b = &st->buf[st->size - 1]; b > st->buf && *b == 0; b--) {
+            ;
+        }
+        /* b points to the last byte which may contain data */
+        if(*b) {
+            int unused = 7;
+            uint8_t v = *b;
+            v &= -(int8_t)v;
+            if(v & 0x0F) unused -= 4;
+            if(v & 0x33) unused -= 2;
+            if(v & 0x55) unused -= 1;
+            tmp->size = b-st->buf + 1;
+            tmp->bits_unused = unused;
+        } else {
+            tmp->size = b-st->buf;
+            tmp->bits_unused = 0;
+        }
+
+        assert(b >= st->buf);
+    }
+
+    unconst.c_buf = st->buf;
+    tmp->buf = unconst.nc_buf;
+    return tmp;
+}
+
+/*
+ * Lexicographically compare the common prefix of both strings,
+ * and if it is the same return -1 for the smallest string.
+ */
+int
+BIT_STRING_compare(const asn_TYPE_descriptor_t *td, const void *aptr,
+                   const void *bptr) {
+    /*
+     * Remove information about trailing bits, since
+     * X.680 (08/2015) #22.7 "ensure that different semantics are not"
+     * "associated with [values that differ only in] the trailing 0 bits."
+     */
+    BIT_STRING_t compact_a, compact_b;
+    const BIT_STRING_t *a = BIT_STRING__compactify(aptr, &compact_a);
+    const BIT_STRING_t *b = BIT_STRING__compactify(bptr, &compact_b);
+    const asn_OCTET_STRING_specifics_t *specs = td->specifics;
+
+    assert(specs && specs->subvariant == ASN_OSUBV_BIT);
+
+    if(a && b) {
+        size_t common_prefix_size = a->size <= b->size ? a->size : b->size;
+        int ret = memcmp(a->buf, b->buf, common_prefix_size);
+        if(ret == 0) {
+            /* Figure out which string with equal prefixes is longer. */
+            if(a->size < b->size) {
+                return -1;
+            } else if(a->size > b->size) {
+                return 1;
+            } else {
+                /* Figure out how many unused bits */
+                if(a->bits_unused > b->bits_unused) {
+                    return -1;
+                } else if(a->bits_unused < b->bits_unused) {
+                    return 1;
+                } else {
+                    return 0;
+                }
+            }
+        } else {
+            return ret;
+        }
+    } else if(!a && !b) {
+        return 0;
+    } else if(!a) {
+        return -1;
+    } else {
+        return 1;
+    }
+}
+
+#ifndef  ASN_DISABLE_PER_SUPPORT
+
+#undef  RETURN
+#define RETURN(_code)                       \
+    do {                                    \
+        asn_dec_rval_t tmprval;             \
+        tmprval.code = _code;               \
+        tmprval.consumed = consumed_myself; \
+        return tmprval;                     \
+    } while(0)
+
+static asn_per_constraint_t asn_DEF_BIT_STRING_constraint_size = {
+    APC_SEMI_CONSTRAINED, -1, -1, 0, 0};
+
+asn_dec_rval_t
+BIT_STRING_decode_uper(const asn_codec_ctx_t *opt_codec_ctx,
+                       const asn_TYPE_descriptor_t *td,
+                       const asn_per_constraints_t *constraints, void **sptr,
+                       asn_per_data_t *pd) {
+    const asn_OCTET_STRING_specifics_t *specs = td->specifics
+		? (const asn_OCTET_STRING_specifics_t *)td->specifics
+		: &asn_SPC_BIT_STRING_specs;
+    const asn_per_constraints_t *pc =
+        constraints ? constraints : td->encoding_constraints.per_constraints;
+	const asn_per_constraint_t *csiz;
+	asn_dec_rval_t rval = { RC_OK, 0 };
+	BIT_STRING_t *st = (BIT_STRING_t *)*sptr;
+	ssize_t consumed_myself = 0;
+	int repeat;
+
+	(void)opt_codec_ctx;
+
+	if(pc) {
+		csiz = &pc->size;
+	} else {
+		csiz = &asn_DEF_BIT_STRING_constraint_size;
+	}
+
+	if(specs->subvariant != ASN_OSUBV_BIT) {
+		ASN_DEBUG("Subvariant %d is not BIT OSUBV_BIT", specs->subvariant);
+		RETURN(RC_FAIL);
+    }
+
+	/*
+	 * Allocate the string.
+	 */
+	if(!st) {
+		st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size));
+		if(!st) RETURN(RC_FAIL);
+	}
+
+	ASN_DEBUG("PER Decoding %s size %ld .. %ld bits %d",
+		csiz->flags & APC_EXTENSIBLE ? "extensible" : "non-extensible",
+		csiz->lower_bound, csiz->upper_bound, csiz->effective_bits);
+
+	if(csiz->flags & APC_EXTENSIBLE) {
+		int inext = per_get_few_bits(pd, 1);
+		if(inext < 0) RETURN(RC_WMORE);
+		if(inext) {
+			csiz = &asn_DEF_BIT_STRING_constraint_size;
+		}
+	}
+
+	if(csiz->effective_bits >= 0) {
+		FREEMEM(st->buf);
+        st->size = (csiz->upper_bound + 7) >> 3;
+        st->buf = (uint8_t *)MALLOC(st->size + 1);
+		if(!st->buf) { st->size = 0; RETURN(RC_FAIL); }
+	}
+
+	/* X.691, #16.5: zero-length encoding */
+	/* X.691, #16.6: short fixed length encoding (up to 2 octets) */
+	/* X.691, #16.7: long fixed length encoding (up to 64K octets) */
+	if(csiz->effective_bits == 0) {
+		int ret;
+        ASN_DEBUG("Encoding BIT STRING size %ld", csiz->upper_bound);
+        ret = per_get_many_bits(pd, st->buf, 0, csiz->upper_bound);
+		if(ret < 0) RETURN(RC_WMORE);
+		consumed_myself += csiz->upper_bound;
+		st->buf[st->size] = 0;
+        st->bits_unused = (8 - (csiz->upper_bound & 0x7)) & 0x7;
+        RETURN(RC_OK);
+	}
+
+	st->size = 0;
+	do {
+		ssize_t raw_len;
+		ssize_t len_bytes;
+		ssize_t len_bits;
+		void *p;
+		int ret;
+
+		/* Get the PER length */
+		raw_len = uper_get_length(pd, csiz->effective_bits, csiz->lower_bound,
+		                          &repeat);
+		if(raw_len < 0) RETURN(RC_WMORE);
+        if(raw_len == 0 && st->buf) break;
+
+		ASN_DEBUG("Got PER length eb %ld, len %ld, %s (%s)",
+			(long)csiz->effective_bits, (long)raw_len,
+			repeat ? "repeat" : "once", td->name);
+        len_bits = raw_len;
+        len_bytes = (len_bits + 7) >> 3;
+        if(len_bits & 0x7) st->bits_unused = 8 - (len_bits & 0x7);
+        /* len_bits be multiple of 16K if repeat is set */
+        p = REALLOC(st->buf, st->size + len_bytes + 1);
+		if(!p) RETURN(RC_FAIL);
+		st->buf = (uint8_t *)p;
+
+        ret = per_get_many_bits(pd, &st->buf[st->size], 0, len_bits);
+        if(ret < 0) RETURN(RC_WMORE);
+		st->size += len_bytes;
+	} while(repeat);
+	st->buf[st->size] = 0;	/* nul-terminate */
+
+	return rval;
+}
+
+asn_enc_rval_t
+BIT_STRING_encode_uper(const asn_TYPE_descriptor_t *td,
+                       const asn_per_constraints_t *constraints,
+                       const void *sptr, asn_per_outp_t *po) {
+    const asn_OCTET_STRING_specifics_t *specs =
+        td->specifics ? (const asn_OCTET_STRING_specifics_t *)td->specifics
+                      : &asn_SPC_BIT_STRING_specs;
+    const asn_per_constraints_t *pc =
+        constraints ? constraints : td->encoding_constraints.per_constraints;
+	const asn_per_constraint_t *csiz;
+	const BIT_STRING_t *st = (const BIT_STRING_t *)sptr;
+	BIT_STRING_t compact_bstr;  /* Do not modify this directly! */
+	asn_enc_rval_t er = { 0, 0, 0 };
+	int inext = 0;		/* Lies not within extension root */
+	size_t size_in_bits;
+	const uint8_t *buf;
+	int ret;
+	int ct_extensible;
+
+	if(!st || (!st->buf && st->size))
+		ASN__ENCODE_FAILED;
+
+	if(specs->subvariant == ASN_OSUBV_BIT) {
+        if((st->size == 0 && st->bits_unused) || (st->bits_unused & ~7))
+            ASN__ENCODE_FAILED;
+    } else {
+		ASN__ENCODE_FAILED;
+    }
+
+	if(pc) {
+        csiz = &pc->size;
+    } else {
+		csiz = &asn_DEF_BIT_STRING_constraint_size;
+	}
+	ct_extensible = csiz->flags & APC_EXTENSIBLE;
+
+    /* Figure out the size without the trailing bits */
+    st = BIT_STRING__compactify(st, &compact_bstr);
+    size_in_bits = 8 * st->size - st->bits_unused;
+
+    ASN_DEBUG(
+        "Encoding %s into %" ASN_PRI_SIZE " bits"
+        " (%ld..%ld, effective %d)%s",
+        td->name, size_in_bits, csiz->lower_bound, csiz->upper_bound,
+        csiz->effective_bits, ct_extensible ? " EXT" : "");
+
+    /* Figure out whether size lies within PER visible constraint */
+
+    if(csiz->effective_bits >= 0) {
+        if((ssize_t)size_in_bits > csiz->upper_bound) {
+            if(ct_extensible) {
+                csiz = &asn_DEF_BIT_STRING_constraint_size;
+                inext = 1;
+            } else {
+                ASN__ENCODE_FAILED;
+            }
+        }
+    } else {
+        inext = 0;
+    }
+
+    if(ct_extensible) {
+		/* Declare whether length is [not] within extension root */
+		if(per_put_few_bits(po, inext, 1))
+			ASN__ENCODE_FAILED;
+	}
+
+    if(csiz->effective_bits >= 0 && !inext) {
+        int add_trailer = (ssize_t)size_in_bits < csiz->lower_bound;
+        ASN_DEBUG(
+            "Encoding %" ASN_PRI_SIZE " bytes (%ld), length (in %d bits) trailer %d; actual "
+            "value %" ASN_PRI_SSIZE "",
+            st->size, size_in_bits - csiz->lower_bound, csiz->effective_bits,
+            add_trailer,
+            add_trailer ? 0 : (ssize_t)size_in_bits - csiz->lower_bound);
+        ret = per_put_few_bits(
+            po, add_trailer ? 0 : (ssize_t)size_in_bits - csiz->lower_bound,
+            csiz->effective_bits);
+        if(ret) ASN__ENCODE_FAILED;
+        ret = per_put_many_bits(po, st->buf, size_in_bits);
+        if(ret) ASN__ENCODE_FAILED;
+        if(add_trailer) {
+            static const uint8_t zeros[16];
+            size_t trailing_zero_bits = csiz->lower_bound - size_in_bits;
+            while(trailing_zero_bits > 0) {
+                if(trailing_zero_bits > 8 * sizeof(zeros)) {
+                    ret = per_put_many_bits(po, zeros, 8 * sizeof(zeros));
+                    trailing_zero_bits -= 8 * sizeof(zeros);
+                } else {
+                    ret = per_put_many_bits(po, zeros, trailing_zero_bits);
+                    trailing_zero_bits = 0;
+                }
+                if(ret) ASN__ENCODE_FAILED;
+            }
+        }
+        ASN__ENCODED_OK(er);
+    }
+
+    ASN_DEBUG("Encoding %" ASN_PRI_SIZE " bytes", st->size);
+
+    buf = st->buf;
+    do {
+        int need_eom = 0;
+        ssize_t maySave = uper_put_length(po, size_in_bits, &need_eom);
+        if(maySave < 0) ASN__ENCODE_FAILED;
+
+        ASN_DEBUG("Encoding %" ASN_PRI_SSIZE " of %" ASN_PRI_SIZE "", maySave, size_in_bits);
+
+        ret = per_put_many_bits(po, buf, maySave);
+        if(ret) ASN__ENCODE_FAILED;
+
+        buf += maySave >> 3;
+        size_in_bits -= maySave;
+        assert(!(maySave & 0x07) || !size_in_bits);
+        if(need_eom && uper_put_length(po, 0, 0))
+            ASN__ENCODE_FAILED; /* End of Message length */
+    } while(size_in_bits);
+
+    ASN__ENCODED_OK(er);
+}
+
+#endif  /* ASN_DISABLE_PER_SUPPORT */
+
+asn_random_fill_result_t
+BIT_STRING_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
+                       const asn_encoding_constraints_t *constraints,
+                       size_t max_length) {
+    const asn_OCTET_STRING_specifics_t *specs =
+        td->specifics ? (const asn_OCTET_STRING_specifics_t *)td->specifics
+                      : &asn_SPC_BIT_STRING_specs;
+    asn_random_fill_result_t result_ok = {ARFILL_OK, 1};
+    asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0};
+    asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};
+    static unsigned lengths[] = {0,     1,     2,     3,     4,     8,
+                                 126,   127,   128,   16383, 16384, 16385,
+                                 65534, 65535, 65536, 65537};
+    uint8_t *buf;
+    uint8_t *bend;
+    uint8_t *b;
+    size_t rnd_bits, rnd_len;
+    BIT_STRING_t *st;
+
+    if(max_length == 0) return result_skipped;
+
+    switch(specs->subvariant) {
+    case ASN_OSUBV_ANY:
+        return result_failed;
+    case ASN_OSUBV_BIT:
+        break;
+    default:
+        break;
+    }
+
+    /* Figure out how far we should go */
+    rnd_bits = lengths[asn_random_between(
+        0, sizeof(lengths) / sizeof(lengths[0]) - 1)];
+    if(!constraints || !constraints->per_constraints)
+        constraints = &td->encoding_constraints;
+    if(constraints->per_constraints) {
+        const asn_per_constraint_t *pc = &constraints->per_constraints->size;
+        if(pc->flags & APC_CONSTRAINED) {
+            long suggested_upper_bound = pc->upper_bound < (ssize_t)max_length
+                                             ? pc->upper_bound
+                                             : (ssize_t)max_length;
+            if(max_length < (size_t)pc->lower_bound) {
+                return result_skipped;
+            }
+            if(pc->flags & APC_EXTENSIBLE) {
+                switch(asn_random_between(0, 5)) {
+                case 0:
+                    if(pc->lower_bound > 0) {
+                        rnd_bits = pc->lower_bound - 1;
+                        break;
+                    }
+                    /* Fall through */
+                case 1:
+                    rnd_bits = pc->upper_bound + 1;
+                    break;
+                case 2:
+                    /* Keep rnd_bits from the table */
+                    if(rnd_bits < max_length) {
+                        break;
+                    }
+                    /* Fall through */
+                default:
+                    rnd_bits = asn_random_between(pc->lower_bound,
+                                                  suggested_upper_bound);
+                }
+            } else {
+                rnd_bits =
+                    asn_random_between(pc->lower_bound, suggested_upper_bound);
+            }
+        } else {
+            rnd_bits = asn_random_between(0, max_length - 1);
+        }
+    } else if(rnd_bits >= max_length) {
+        rnd_bits = asn_random_between(0, max_length - 1);
+    }
+
+    rnd_len = (rnd_bits + 7) / 8;
+    buf = CALLOC(1, rnd_len + 1);
+    if(!buf) return result_failed;
+
+    bend = &buf[rnd_len];
+
+    for(b = buf; b < bend; b++) {
+        *(uint8_t *)b = asn_random_between(0, 255);
+    }
+    *b = 0; /* Zero-terminate just in case. */
+
+    if(*sptr) {
+        st = *sptr;
+        FREEMEM(st->buf);
+    } else {
+        st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size));
+        if(!st) {
+            FREEMEM(buf);
+            return result_failed;
+        }
+    }
+
+    st->buf = buf;
+    st->size = rnd_len;
+    st->bits_unused = (8 - (rnd_bits & 0x7)) & 0x7;
+    if(st->bits_unused) {
+        assert(st->size > 0);
+        st->buf[st->size-1] &= 0xff << st->bits_unused;
+    }
+
+    result_ok.length = st->size;
+    return result_ok;
+}

+ 46 - 0
seader/lib/asn1/BIT_STRING.h

@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2003-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef	_BIT_STRING_H_
+#define	_BIT_STRING_H_
+
+#include <OCTET_STRING.h>	/* Some help from OCTET STRING */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct BIT_STRING_s {
+	uint8_t *buf;	/* BIT STRING body */
+	size_t size;	/* Size of the above buffer */
+
+	int bits_unused;/* Unused trailing bits in the last octet (0..7) */
+
+	asn_struct_ctx_t _asn_ctx;	/* Parsing across buffer boundaries */
+} BIT_STRING_t;
+
+extern asn_TYPE_descriptor_t asn_DEF_BIT_STRING;
+extern asn_TYPE_operation_t asn_OP_BIT_STRING;
+extern asn_OCTET_STRING_specifics_t asn_SPC_BIT_STRING_specs;
+
+asn_struct_print_f BIT_STRING_print;	/* Human-readable output */
+asn_struct_compare_f BIT_STRING_compare;
+asn_constr_check_f BIT_STRING_constraint;
+xer_type_encoder_f BIT_STRING_encode_xer;
+oer_type_decoder_f BIT_STRING_decode_oer;
+oer_type_encoder_f BIT_STRING_encode_oer;
+per_type_decoder_f BIT_STRING_decode_uper;
+per_type_encoder_f BIT_STRING_encode_uper;
+asn_random_fill_f  BIT_STRING_random_fill;
+
+#define BIT_STRING_free              OCTET_STRING_free
+#define BIT_STRING_decode_ber        OCTET_STRING_decode_ber
+#define BIT_STRING_encode_der        OCTET_STRING_encode_der
+#define BIT_STRING_decode_xer        OCTET_STRING_decode_xer_binary
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _BIT_STRING_H_ */

+ 174 - 0
seader/lib/asn1/BIT_STRING_oer.c

@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>.
+ * All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef ASN_DISABLE_OER_SUPPORT
+
+#include <asn_internal.h>
+#include <BIT_STRING.h>
+#include <errno.h>
+
+asn_dec_rval_t
+BIT_STRING_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
+                      const asn_TYPE_descriptor_t *td,
+                      const asn_oer_constraints_t *constraints, void **sptr,
+                      const void *ptr, size_t size) {
+    BIT_STRING_t *st = (BIT_STRING_t *)*sptr;
+    const asn_oer_constraints_t *cts =
+        constraints ? constraints : td->encoding_constraints.oer_constraints;
+    ssize_t ct_size = cts ? cts->size : -1;
+    asn_dec_rval_t rval = {RC_OK, 0};
+    size_t expected_length = 0;
+
+    (void)opt_codec_ctx;
+
+    if(!st) {
+        st = (BIT_STRING_t *)(*sptr = CALLOC(1, sizeof(*st)));
+        if(!st) ASN__DECODE_FAILED;
+    }
+
+    if(ct_size >= 0) {
+        expected_length = (ct_size + 7) >> 3;
+        st->bits_unused = (8 - (ct_size & 7)) & 7;
+    } else {
+        /*
+         * X.696 (08/2015) #13.3.1
+         * Encode length determinant as _number of octets_, but only
+         * if upper bound is not equal to lower bound.
+         */
+        ssize_t len_len = oer_fetch_length(ptr, size, &expected_length);
+        if(len_len > 0) {
+            ptr = (const char *)ptr + len_len;
+            size -= len_len;
+        } else if(len_len == 0) {
+            ASN__DECODE_STARVED;
+        } else if(len_len < 0) {
+            ASN__DECODE_FAILED;
+        }
+
+        if(expected_length < 1) {
+            ASN__DECODE_FAILED;
+        } else if(expected_length > size) {
+            ASN__DECODE_STARVED;
+        }
+
+        st->bits_unused = ((const uint8_t *)ptr)[0];
+        if(st->bits_unused & ~7) {
+            ASN_DEBUG("%s: unused bits outside of 0..7 range", td->name);
+            ASN__DECODE_FAILED;
+        }
+        ptr = (const char *)ptr + 1;
+        size--;
+        expected_length--;
+        rval.consumed = len_len + 1;
+    }
+
+    if(size < expected_length) {
+        ASN__DECODE_STARVED;
+    } else {
+        uint8_t *buf = MALLOC(expected_length + 1);
+        if(buf == NULL) {
+            ASN__DECODE_FAILED;
+        } else {
+            memcpy(buf, ptr, expected_length);
+            buf[expected_length] = '\0';
+        }
+        FREEMEM(st->buf);
+        st->buf = buf;
+        st->size = expected_length;
+        if(expected_length > 0) {
+            buf[expected_length - 1] &= (0xff << st->bits_unused);
+        }
+
+        rval.consumed += expected_length;
+        return rval;
+    }
+}
+
+/*
+ * Encode as Canonical OER.
+ */
+asn_enc_rval_t
+BIT_STRING_encode_oer(const asn_TYPE_descriptor_t *td,
+                      const asn_oer_constraints_t *constraints,
+                      const void *sptr, asn_app_consume_bytes_f *cb,
+                      void *app_key) {
+    const BIT_STRING_t *st = (const BIT_STRING_t *)sptr;
+    asn_enc_rval_t erval = {0, 0, 0};
+    const asn_oer_constraints_t *cts =
+        constraints ? constraints : td->encoding_constraints.oer_constraints;
+    ssize_t ct_size = cts ? cts->size : -1;
+    size_t trailing_zeros = 0;
+    int fix_last_byte = 0;
+
+    if(!st) ASN__ENCODE_FAILED;
+
+    if(st->bits_unused & ~7) {
+        ASN_DEBUG("BIT STRING unused bits %d out of 0..7 range",
+                  st->bits_unused);
+        ASN__ENCODE_FAILED;
+    }
+    if(st->bits_unused && !(st->size && st->buf)) {
+        ASN_DEBUG("BIT STRING %s size 0 can't support unused bits %d", td->name,
+                  st->bits_unused);
+        ASN__ENCODE_FAILED;
+    }
+
+    if(ct_size >= 0) {
+        size_t ct_bytes = (ct_size + 7) >> 3;
+        if(st->size > ct_bytes) {
+            ASN_DEBUG("More bits in BIT STRING %s (%" ASN_PRI_SSIZE ") than constrained %" ASN_PRI_SSIZE "",
+                      td->name, 8 * st->size - st->bits_unused, ct_size);
+            ASN__ENCODE_FAILED;
+        }
+        trailing_zeros = ct_bytes - st->size;   /* Allow larger constraint */
+    } else {
+        uint8_t ub = st->bits_unused & 7;
+        ssize_t len_len = oer_serialize_length(1 + st->size, cb, app_key);
+        if(len_len < 0) ASN__ENCODE_FAILED;
+        if(cb(&ub, 1, app_key) < 0) {
+            ASN__ENCODE_FAILED;
+        }
+        erval.encoded += len_len + 1;
+    }
+
+    if(st->bits_unused) {
+        if(st->buf[st->size - 1] & (0xff << st->bits_unused)) {
+            fix_last_byte = 1;
+        }
+    }
+
+    if(cb(st->buf, st->size - fix_last_byte, app_key) < 0) {
+        ASN__ENCODE_FAILED;
+    }
+
+    if(fix_last_byte) {
+        uint8_t b = st->buf[st->size - 1] & (0xff << st->bits_unused);
+        if(cb(&b, 1, app_key) < 0) {
+            ASN__ENCODE_FAILED;
+        }
+    }
+
+    erval.encoded += st->size;
+
+    if(trailing_zeros) {
+        static uint8_t zeros[16];
+        while(trailing_zeros > 0) {
+            int ret;
+            if(trailing_zeros < sizeof(zeros)) {
+                ret = cb(zeros, trailing_zeros, app_key);
+                erval.encoded += trailing_zeros;
+            } else {
+                ret = cb(zeros, sizeof(zeros), app_key);
+                erval.encoded += sizeof(zeros);
+            }
+            if(ret < 0) ASN__ENCODE_FAILED;
+        }
+    }
+
+    return erval;
+}
+
+
+#endif  /* ASN_DISABLE_OER_SUPPORT */

+ 82 - 0
seader/lib/asn1/CardDetails.c

@@ -0,0 +1,82 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#include "CardDetails.h"
+
+asn_TYPE_member_t asn_MBR_CardDetails_1[] = {
+	{ ATF_NOFLAGS, 0, offsetof(struct CardDetails, protocol),
+		(ASN_TAG_CLASS_CONTEXT | (0 << 2)),
+		-1,	/* IMPLICIT tag at current level */
+		&asn_DEF_Protocol,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"protocol"
+		},
+	{ ATF_NOFLAGS, 0, offsetof(struct CardDetails, csn),
+		(ASN_TAG_CLASS_CONTEXT | (1 << 2)),
+		-1,	/* IMPLICIT tag at current level */
+		&asn_DEF_OCTET_STRING,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"csn"
+		},
+	{ ATF_POINTER, 2, offsetof(struct CardDetails, atqa),
+		(ASN_TAG_CLASS_CONTEXT | (2 << 2)),
+		-1,	/* IMPLICIT tag at current level */
+		&asn_DEF_OCTET_STRING,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"atqa"
+		},
+	{ ATF_POINTER, 1, offsetof(struct CardDetails, sak),
+		(ASN_TAG_CLASS_CONTEXT | (3 << 2)),
+		-1,	/* IMPLICIT tag at current level */
+		&asn_DEF_OCTET_STRING,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"sak"
+		},
+};
+static const int asn_MAP_CardDetails_oms_1[] = { 2, 3 };
+static const ber_tlv_tag_t asn_DEF_CardDetails_tags_1[] = {
+	(ASN_TAG_CLASS_UNIVERSAL | (16 << 2))
+};
+static const asn_TYPE_tag2member_t asn_MAP_CardDetails_tag2el_1[] = {
+    { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* protocol */
+    { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* csn */
+    { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 }, /* atqa */
+    { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 3, 0, 0 } /* sak */
+};
+asn_SEQUENCE_specifics_t asn_SPC_CardDetails_specs_1 = {
+	sizeof(struct CardDetails),
+	offsetof(struct CardDetails, _asn_ctx),
+	asn_MAP_CardDetails_tag2el_1,
+	4,	/* Count of tags in the map */
+	asn_MAP_CardDetails_oms_1,	/* Optional members */
+	2, 0,	/* Root/Additions */
+	-1,	/* First extension addition */
+};
+asn_TYPE_descriptor_t asn_DEF_CardDetails = {
+	"CardDetails",
+	"CardDetails",
+	&asn_OP_SEQUENCE,
+	asn_DEF_CardDetails_tags_1,
+	sizeof(asn_DEF_CardDetails_tags_1)
+		/sizeof(asn_DEF_CardDetails_tags_1[0]), /* 1 */
+	asn_DEF_CardDetails_tags_1,	/* Same as above */
+	sizeof(asn_DEF_CardDetails_tags_1)
+		/sizeof(asn_DEF_CardDetails_tags_1[0]), /* 1 */
+	{ 0, 0, SEQUENCE_constraint },
+	asn_MBR_CardDetails_1,
+	4,	/* Elements count */
+	&asn_SPC_CardDetails_specs_1	/* Additional specs */
+};
+

+ 44 - 0
seader/lib/asn1/CardDetails.h

@@ -0,0 +1,44 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#ifndef	_CardDetails_H_
+#define	_CardDetails_H_
+
+
+#include <asn_application.h>
+
+/* Including external dependencies */
+#include "Protocol.h"
+#include <OCTET_STRING.h>
+#include <constr_SEQUENCE.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* CardDetails */
+typedef struct CardDetails {
+	Protocol_t	 protocol;
+	OCTET_STRING_t	 csn;
+	OCTET_STRING_t	*atqa	/* OPTIONAL */;
+	OCTET_STRING_t	*sak	/* OPTIONAL */;
+	
+	/* Context for parsing across buffer boundaries */
+	asn_struct_ctx_t _asn_ctx;
+} CardDetails_t;
+
+/* Implementation */
+extern asn_TYPE_descriptor_t asn_DEF_CardDetails;
+extern asn_SEQUENCE_specifics_t asn_SPC_CardDetails_specs_1;
+extern asn_TYPE_member_t asn_MBR_CardDetails_1[4];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _CardDetails_H_ */
+#include <asn_internal.h>

+ 50 - 0
seader/lib/asn1/CardDetected.c

@@ -0,0 +1,50 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#include "CardDetected.h"
+
+asn_TYPE_member_t asn_MBR_CardDetected_1[] = {
+	{ ATF_NOFLAGS, 0, offsetof(struct CardDetected, detectedCardDetails),
+		(ASN_TAG_CLASS_CONTEXT | (0 << 2)),
+		-1,	/* IMPLICIT tag at current level */
+		&asn_DEF_CardDetails,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"detectedCardDetails"
+		},
+};
+static const ber_tlv_tag_t asn_DEF_CardDetected_tags_1[] = {
+	(ASN_TAG_CLASS_UNIVERSAL | (16 << 2))
+};
+static const asn_TYPE_tag2member_t asn_MAP_CardDetected_tag2el_1[] = {
+    { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 } /* detectedCardDetails */
+};
+asn_SEQUENCE_specifics_t asn_SPC_CardDetected_specs_1 = {
+	sizeof(struct CardDetected),
+	offsetof(struct CardDetected, _asn_ctx),
+	asn_MAP_CardDetected_tag2el_1,
+	1,	/* Count of tags in the map */
+	0, 0, 0,	/* Optional elements (not needed) */
+	-1,	/* First extension addition */
+};
+asn_TYPE_descriptor_t asn_DEF_CardDetected = {
+	"CardDetected",
+	"CardDetected",
+	&asn_OP_SEQUENCE,
+	asn_DEF_CardDetected_tags_1,
+	sizeof(asn_DEF_CardDetected_tags_1)
+		/sizeof(asn_DEF_CardDetected_tags_1[0]), /* 1 */
+	asn_DEF_CardDetected_tags_1,	/* Same as above */
+	sizeof(asn_DEF_CardDetected_tags_1)
+		/sizeof(asn_DEF_CardDetected_tags_1[0]), /* 1 */
+	{ 0, 0, SEQUENCE_constraint },
+	asn_MBR_CardDetected_1,
+	1,	/* Elements count */
+	&asn_SPC_CardDetected_specs_1	/* Additional specs */
+};
+

+ 40 - 0
seader/lib/asn1/CardDetected.h

@@ -0,0 +1,40 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#ifndef	_CardDetected_H_
+#define	_CardDetected_H_
+
+
+#include <asn_application.h>
+
+/* Including external dependencies */
+#include "CardDetails.h"
+#include <constr_SEQUENCE.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* CardDetected */
+typedef struct CardDetected {
+	CardDetails_t	 detectedCardDetails;
+	
+	/* Context for parsing across buffer boundaries */
+	asn_struct_ctx_t _asn_ctx;
+} CardDetected_t;
+
+/* Implementation */
+extern asn_TYPE_descriptor_t asn_DEF_CardDetected;
+extern asn_SEQUENCE_specifics_t asn_SPC_CardDetected_specs_1;
+extern asn_TYPE_member_t asn_MBR_CardDetected_1[1];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _CardDetected_H_ */
+#include <asn_internal.h>

+ 54 - 0
seader/lib/asn1/ContentElementTag.c

@@ -0,0 +1,54 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#include "ContentElementTag.h"
+
+/*
+ * This type is implemented using NativeEnumerated,
+ * so here we adjust the DEF accordingly.
+ */
+static asn_oer_constraints_t asn_OER_type_ContentElementTag_constr_1 CC_NOTUSED = {
+	{ 0, 0 },
+	-1};
+asn_per_constraints_t asn_PER_type_ContentElementTag_constr_1 CC_NOTUSED = {
+	{ APC_CONSTRAINED,	 0,  0,  0,  0 }	/* (0..0) */,
+	{ APC_UNCONSTRAINED,	-1, -1,  0,  0 },
+	0, 0	/* No PER value map */
+};
+static const asn_INTEGER_enum_map_t asn_MAP_ContentElementTag_value2enum_1[] = {
+	{ 4,	32,	"implicitFormatPhysicalAccessBits" }
+};
+static const unsigned int asn_MAP_ContentElementTag_enum2value_1[] = {
+	0	/* implicitFormatPhysicalAccessBits(4) */
+};
+const asn_INTEGER_specifics_t asn_SPC_ContentElementTag_specs_1 = {
+	asn_MAP_ContentElementTag_value2enum_1,	/* "tag" => N; sorted by tag */
+	asn_MAP_ContentElementTag_enum2value_1,	/* N => "tag"; sorted by N */
+	1,	/* Number of elements in the maps */
+	0,	/* Enumeration is not extensible */
+	1,	/* Strict enumeration */
+	0,	/* Native long size */
+	0
+};
+static const ber_tlv_tag_t asn_DEF_ContentElementTag_tags_1[] = {
+	(ASN_TAG_CLASS_UNIVERSAL | (10 << 2))
+};
+asn_TYPE_descriptor_t asn_DEF_ContentElementTag = {
+	"ContentElementTag",
+	"ContentElementTag",
+	&asn_OP_NativeEnumerated,
+	asn_DEF_ContentElementTag_tags_1,
+	sizeof(asn_DEF_ContentElementTag_tags_1)
+		/sizeof(asn_DEF_ContentElementTag_tags_1[0]), /* 1 */
+	asn_DEF_ContentElementTag_tags_1,	/* Same as above */
+	sizeof(asn_DEF_ContentElementTag_tags_1)
+		/sizeof(asn_DEF_ContentElementTag_tags_1[0]), /* 1 */
+	{ &asn_OER_type_ContentElementTag_constr_1, &asn_PER_type_ContentElementTag_constr_1, NativeEnumerated_constraint },
+	0, 0,	/* Defined elsewhere */
+	&asn_SPC_ContentElementTag_specs_1	/* Additional specs */
+};
+

+ 50 - 0
seader/lib/asn1/ContentElementTag.h

@@ -0,0 +1,50 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#ifndef	_ContentElementTag_H_
+#define	_ContentElementTag_H_
+
+
+#include <asn_application.h>
+
+/* Including external dependencies */
+#include <NativeEnumerated.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Dependencies */
+typedef enum ContentElementTag {
+	ContentElementTag_implicitFormatPhysicalAccessBits	= 4
+} e_ContentElementTag;
+
+/* ContentElementTag */
+typedef long	 ContentElementTag_t;
+
+/* Implementation */
+extern asn_per_constraints_t asn_PER_type_ContentElementTag_constr_1;
+extern asn_TYPE_descriptor_t asn_DEF_ContentElementTag;
+extern const asn_INTEGER_specifics_t asn_SPC_ContentElementTag_specs_1;
+asn_struct_free_f ContentElementTag_free;
+asn_struct_print_f ContentElementTag_print;
+asn_constr_check_f ContentElementTag_constraint;
+ber_type_decoder_f ContentElementTag_decode_ber;
+der_type_encoder_f ContentElementTag_encode_der;
+xer_type_decoder_f ContentElementTag_decode_xer;
+xer_type_encoder_f ContentElementTag_encode_xer;
+oer_type_decoder_f ContentElementTag_decode_oer;
+oer_type_encoder_f ContentElementTag_encode_oer;
+per_type_decoder_f ContentElementTag_decode_uper;
+per_type_encoder_f ContentElementTag_encode_uper;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _ContentElementTag_H_ */
+#include <asn_internal.h>

+ 60 - 0
seader/lib/asn1/ErrorResponse.c

@@ -0,0 +1,60 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#include "ErrorResponse.h"
+
+asn_TYPE_member_t asn_MBR_ErrorResponse_1[] = {
+	{ ATF_NOFLAGS, 0, offsetof(struct ErrorResponse, errorCode),
+		(ASN_TAG_CLASS_CONTEXT | (0 << 2)),
+		-1,	/* IMPLICIT tag at current level */
+		&asn_DEF_NativeInteger,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"errorCode"
+		},
+	{ ATF_NOFLAGS, 0, offsetof(struct ErrorResponse, data),
+		(ASN_TAG_CLASS_CONTEXT | (1 << 2)),
+		-1,	/* IMPLICIT tag at current level */
+		&asn_DEF_OCTET_STRING,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"data"
+		},
+};
+static const ber_tlv_tag_t asn_DEF_ErrorResponse_tags_1[] = {
+	(ASN_TAG_CLASS_UNIVERSAL | (16 << 2))
+};
+static const asn_TYPE_tag2member_t asn_MAP_ErrorResponse_tag2el_1[] = {
+    { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* errorCode */
+    { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* data */
+};
+asn_SEQUENCE_specifics_t asn_SPC_ErrorResponse_specs_1 = {
+	sizeof(struct ErrorResponse),
+	offsetof(struct ErrorResponse, _asn_ctx),
+	asn_MAP_ErrorResponse_tag2el_1,
+	2,	/* Count of tags in the map */
+	0, 0, 0,	/* Optional elements (not needed) */
+	-1,	/* First extension addition */
+};
+asn_TYPE_descriptor_t asn_DEF_ErrorResponse = {
+	"ErrorResponse",
+	"ErrorResponse",
+	&asn_OP_SEQUENCE,
+	asn_DEF_ErrorResponse_tags_1,
+	sizeof(asn_DEF_ErrorResponse_tags_1)
+		/sizeof(asn_DEF_ErrorResponse_tags_1[0]), /* 1 */
+	asn_DEF_ErrorResponse_tags_1,	/* Same as above */
+	sizeof(asn_DEF_ErrorResponse_tags_1)
+		/sizeof(asn_DEF_ErrorResponse_tags_1[0]), /* 1 */
+	{ 0, 0, SEQUENCE_constraint },
+	asn_MBR_ErrorResponse_1,
+	2,	/* Elements count */
+	&asn_SPC_ErrorResponse_specs_1	/* Additional specs */
+};
+

+ 42 - 0
seader/lib/asn1/ErrorResponse.h

@@ -0,0 +1,42 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#ifndef	_ErrorResponse_H_
+#define	_ErrorResponse_H_
+
+
+#include <asn_application.h>
+
+/* Including external dependencies */
+#include <NativeInteger.h>
+#include <OCTET_STRING.h>
+#include <constr_SEQUENCE.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ErrorResponse */
+typedef struct ErrorResponse {
+	long	 errorCode;
+	OCTET_STRING_t	 data;
+	
+	/* Context for parsing across buffer boundaries */
+	asn_struct_ctx_t _asn_ctx;
+} ErrorResponse_t;
+
+/* Implementation */
+extern asn_TYPE_descriptor_t asn_DEF_ErrorResponse;
+extern asn_SEQUENCE_specifics_t asn_SPC_ErrorResponse_specs_1;
+extern asn_TYPE_member_t asn_MBR_ErrorResponse_1[2];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _ErrorResponse_H_ */
+#include <asn_internal.h>

+ 56 - 0
seader/lib/asn1/FrameProtocol.c

@@ -0,0 +1,56 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#include "FrameProtocol.h"
+
+/*
+ * This type is implemented using NativeEnumerated,
+ * so here we adjust the DEF accordingly.
+ */
+static asn_oer_constraints_t asn_OER_type_FrameProtocol_constr_1 CC_NOTUSED = {
+	{ 0, 0 },
+	-1};
+static asn_per_constraints_t asn_PER_type_FrameProtocol_constr_1 CC_NOTUSED = {
+	{ APC_CONSTRAINED,	 1,  1,  0,  1 }	/* (0..1) */,
+	{ APC_UNCONSTRAINED,	-1, -1,  0,  0 },
+	0, 0	/* No PER value map */
+};
+static const asn_INTEGER_enum_map_t asn_MAP_FrameProtocol_value2enum_1[] = {
+	{ 2,	3,	"nfc" },
+	{ 4,	6,	"iclass" }
+};
+static const unsigned int asn_MAP_FrameProtocol_enum2value_1[] = {
+	1,	/* iclass(4) */
+	0	/* nfc(2) */
+};
+static const asn_INTEGER_specifics_t asn_SPC_FrameProtocol_specs_1 = {
+	asn_MAP_FrameProtocol_value2enum_1,	/* "tag" => N; sorted by tag */
+	asn_MAP_FrameProtocol_enum2value_1,	/* N => "tag"; sorted by N */
+	2,	/* Number of elements in the maps */
+	0,	/* Enumeration is not extensible */
+	1,	/* Strict enumeration */
+	0,	/* Native long size */
+	0
+};
+static const ber_tlv_tag_t asn_DEF_FrameProtocol_tags_1[] = {
+	(ASN_TAG_CLASS_UNIVERSAL | (10 << 2))
+};
+asn_TYPE_descriptor_t asn_DEF_FrameProtocol = {
+	"FrameProtocol",
+	"FrameProtocol",
+	&asn_OP_NativeEnumerated,
+	asn_DEF_FrameProtocol_tags_1,
+	sizeof(asn_DEF_FrameProtocol_tags_1)
+		/sizeof(asn_DEF_FrameProtocol_tags_1[0]), /* 1 */
+	asn_DEF_FrameProtocol_tags_1,	/* Same as above */
+	sizeof(asn_DEF_FrameProtocol_tags_1)
+		/sizeof(asn_DEF_FrameProtocol_tags_1[0]), /* 1 */
+	{ &asn_OER_type_FrameProtocol_constr_1, &asn_PER_type_FrameProtocol_constr_1, NativeEnumerated_constraint },
+	0, 0,	/* Defined elsewhere */
+	&asn_SPC_FrameProtocol_specs_1	/* Additional specs */
+};
+

+ 49 - 0
seader/lib/asn1/FrameProtocol.h

@@ -0,0 +1,49 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#ifndef	_FrameProtocol_H_
+#define	_FrameProtocol_H_
+
+
+#include <asn_application.h>
+
+/* Including external dependencies */
+#include <NativeEnumerated.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Dependencies */
+typedef enum FrameProtocol {
+	FrameProtocol_nfc	= 2,
+	FrameProtocol_iclass	= 4
+} e_FrameProtocol;
+
+/* FrameProtocol */
+typedef long	 FrameProtocol_t;
+
+/* Implementation */
+extern asn_TYPE_descriptor_t asn_DEF_FrameProtocol;
+asn_struct_free_f FrameProtocol_free;
+asn_struct_print_f FrameProtocol_print;
+asn_constr_check_f FrameProtocol_constraint;
+ber_type_decoder_f FrameProtocol_decode_ber;
+der_type_encoder_f FrameProtocol_encode_der;
+xer_type_decoder_f FrameProtocol_decode_xer;
+xer_type_encoder_f FrameProtocol_encode_xer;
+oer_type_decoder_f FrameProtocol_decode_oer;
+oer_type_encoder_f FrameProtocol_encode_oer;
+per_type_decoder_f FrameProtocol_decode_uper;
+per_type_encoder_f FrameProtocol_encode_uper;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _FrameProtocol_H_ */
+#include <asn_internal.h>

+ 1353 - 0
seader/lib/asn1/INTEGER.c

@@ -0,0 +1,1353 @@
+/*
+ * Copyright (c) 2003-2019 Lev Walkin <vlm@lionet.info>.
+ * All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <asn_internal.h>
+#include <INTEGER.h>
+#include <asn_codecs_prim.h>	/* Encoder and decoder of a primitive type */
+#include <errno.h>
+
+/*
+ * INTEGER basic type description.
+ */
+static const ber_tlv_tag_t asn_DEF_INTEGER_tags[] = {
+	(ASN_TAG_CLASS_UNIVERSAL | (2 << 2))
+};
+asn_TYPE_operation_t asn_OP_INTEGER = {
+	INTEGER_free,
+	INTEGER_print,
+	INTEGER_compare,
+	ber_decode_primitive,
+	INTEGER_encode_der,
+	INTEGER_decode_xer,
+	INTEGER_encode_xer,
+#ifdef  ASN_DISABLE_OER_SUPPORT
+	0,
+	0,
+#else
+	INTEGER_decode_oer,     /* OER decoder */
+	INTEGER_encode_oer,     /* Canonical OER encoder */
+#endif  /* ASN_DISABLE_OER_SUPPORT */
+#ifdef	ASN_DISABLE_PER_SUPPORT
+	0,
+	0,
+#else
+	INTEGER_decode_uper,	/* Unaligned PER decoder */
+	INTEGER_encode_uper,	/* Unaligned PER encoder */
+#endif	/* ASN_DISABLE_PER_SUPPORT */
+	INTEGER_random_fill,
+	0	/* Use generic outmost tag fetcher */
+};
+asn_TYPE_descriptor_t asn_DEF_INTEGER = {
+	"INTEGER",
+	"INTEGER",
+	&asn_OP_INTEGER,
+	asn_DEF_INTEGER_tags,
+	sizeof(asn_DEF_INTEGER_tags) / sizeof(asn_DEF_INTEGER_tags[0]),
+	asn_DEF_INTEGER_tags,	/* Same as above */
+	sizeof(asn_DEF_INTEGER_tags) / sizeof(asn_DEF_INTEGER_tags[0]),
+	{ 0, 0, asn_generic_no_constraint },
+	0, 0,	/* No members */
+	0	/* No specifics */
+};
+
+/*
+ * Encode INTEGER type using DER.
+ */
+asn_enc_rval_t
+INTEGER_encode_der(const asn_TYPE_descriptor_t *td, const void *sptr,
+                   int tag_mode, ber_tlv_tag_t tag, asn_app_consume_bytes_f *cb,
+                   void *app_key) {
+    const INTEGER_t *st = (const INTEGER_t *)sptr;
+    asn_enc_rval_t rval;
+    INTEGER_t effective_integer;
+
+	ASN_DEBUG("%s %s as INTEGER (tm=%d)",
+		cb?"Encoding":"Estimating", td->name, tag_mode);
+
+	/*
+	 * Canonicalize integer in the buffer.
+	 * (Remove too long sign extension, remove some first 0x00 bytes)
+	 */
+	if(st->buf) {
+		uint8_t *buf = st->buf;
+		uint8_t *end1 = buf + st->size - 1;
+		int shift;
+
+		/* Compute the number of superfluous leading bytes */
+		for(; buf < end1; buf++) {
+			/*
+			 * If the contents octets of an integer value encoding
+			 * consist of more than one octet, then the bits of the
+			 * first octet and bit 8 of the second octet:
+			 * a) shall not all be ones; and
+			 * b) shall not all be zero.
+			 */
+			switch(*buf) {
+			case 0x00: if((buf[1] & 0x80) == 0)
+					continue;
+				break;
+			case 0xff: if((buf[1] & 0x80))
+					continue;
+				break;
+			}
+			break;
+		}
+
+		/* Remove leading superfluous bytes from the integer */
+		shift = buf - st->buf;
+		if(shift) {
+            union {
+                const uint8_t *c_buf;
+                uint8_t *nc_buf;
+            } unconst;
+            unconst.c_buf = st->buf;
+            effective_integer.buf = unconst.nc_buf + shift;
+            effective_integer.size = st->size - shift;
+
+            st = &effective_integer;
+        }
+    }
+
+    rval = der_encode_primitive(td, st, tag_mode, tag, cb, app_key);
+    if(rval.structure_ptr == &effective_integer) {
+        rval.structure_ptr = sptr;
+    }
+    return rval;
+}
+
+static const asn_INTEGER_enum_map_t *INTEGER_map_enum2value(
+    const asn_INTEGER_specifics_t *specs, const char *lstart,
+    const char *lstop);
+
+/*
+ * INTEGER specific human-readable output.
+ */
+static ssize_t
+INTEGER__dump(const asn_TYPE_descriptor_t *td, const INTEGER_t *st, asn_app_consume_bytes_f *cb, void *app_key, int plainOrXER) {
+    const asn_INTEGER_specifics_t *specs =
+        (const asn_INTEGER_specifics_t *)td->specifics;
+	char scratch[32];
+	uint8_t *buf = st->buf;
+	uint8_t *buf_end = st->buf + st->size;
+	intmax_t value;
+	ssize_t wrote = 0;
+	char *p;
+	int ret;
+
+	if(specs && specs->field_unsigned)
+		ret = asn_INTEGER2umax(st, (uintmax_t *)&value);
+	else
+		ret = asn_INTEGER2imax(st, &value);
+
+	/* Simple case: the integer size is small */
+	if(ret == 0) {
+		const asn_INTEGER_enum_map_t *el;
+		el = (value >= 0 || !specs || !specs->field_unsigned)
+			? INTEGER_map_value2enum(specs, value) : 0;
+		if(el) {
+			if(plainOrXER == 0)
+				return asn__format_to_callback(cb, app_key,
+					"%" ASN_PRIdMAX " (%s)", value, el->enum_name);
+			else
+				return asn__format_to_callback(cb, app_key,
+					"<%s/>", el->enum_name);
+		} else if(plainOrXER && specs && specs->strict_enumeration) {
+			ASN_DEBUG("ASN.1 forbids dealing with "
+				"unknown value of ENUMERATED type");
+			errno = EPERM;
+			return -1;
+		} else {
+            return asn__format_to_callback(cb, app_key,
+                                           (specs && specs->field_unsigned)
+                                               ? "%" ASN_PRIuMAX
+                                               : "%" ASN_PRIdMAX,
+                                           value);
+        }
+	} else if(plainOrXER && specs && specs->strict_enumeration) {
+		/*
+		 * Here and earlier, we cannot encode the ENUMERATED values
+		 * if there is no corresponding identifier.
+		 */
+		ASN_DEBUG("ASN.1 forbids dealing with "
+			"unknown value of ENUMERATED type");
+		errno = EPERM;
+		return -1;
+	}
+
+	/* Output in the long xx:yy:zz... format */
+	/* TODO: replace with generic algorithm (Knuth TAOCP Vol 2, 4.3.1) */
+	for(p = scratch; buf < buf_end; buf++) {
+		const char * const h2c = "0123456789ABCDEF";
+		if((p - scratch) >= (ssize_t)(sizeof(scratch) - 4)) {
+			/* Flush buffer */
+			if(cb(scratch, p - scratch, app_key) < 0)
+				return -1;
+			wrote += p - scratch;
+			p = scratch;
+		}
+		*p++ = h2c[*buf >> 4];
+		*p++ = h2c[*buf & 0x0F];
+		*p++ = 0x3a;	/* ":" */
+	}
+	if(p != scratch)
+		p--;	/* Remove the last ":" */
+
+	wrote += p - scratch;
+	return (cb(scratch, p - scratch, app_key) < 0) ? -1 : wrote;
+}
+
+/*
+ * INTEGER specific human-readable output.
+ */
+int
+INTEGER_print(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
+              asn_app_consume_bytes_f *cb, void *app_key) {
+    const INTEGER_t *st = (const INTEGER_t *)sptr;
+	ssize_t ret;
+
+	(void)ilevel;
+
+	if(!st || !st->buf)
+		ret = cb("<absent>", 8, app_key);
+	else
+		ret = INTEGER__dump(td, st, cb, app_key, 0);
+
+	return (ret < 0) ? -1 : 0;
+}
+
+struct e2v_key {
+	const char *start;
+	const char *stop;
+	const asn_INTEGER_enum_map_t *vemap;
+	const unsigned int *evmap;
+};
+static int
+INTEGER__compar_enum2value(const void *kp, const void *am) {
+	const struct e2v_key *key = (const struct e2v_key *)kp;
+	const asn_INTEGER_enum_map_t *el = (const asn_INTEGER_enum_map_t *)am;
+	const char *ptr, *end, *name;
+
+	/* Remap the element (sort by different criterion) */
+	el = key->vemap + key->evmap[el - key->vemap];
+
+	/* Compare strings */
+	for(ptr = key->start, end = key->stop, name = el->enum_name;
+			ptr < end; ptr++, name++) {
+		if(*ptr != *name || !*name)
+			return *(const unsigned char *)ptr
+				- *(const unsigned char *)name;
+	}
+	return name[0] ? -1 : 0;
+}
+
+static const asn_INTEGER_enum_map_t *
+INTEGER_map_enum2value(const asn_INTEGER_specifics_t *specs, const char *lstart,
+                       const char *lstop) {
+    const asn_INTEGER_enum_map_t *el_found;
+	int count = specs ? specs->map_count : 0;
+	struct e2v_key key;
+	const char *lp;
+
+	if(!count) return NULL;
+
+	/* Guaranteed: assert(lstart < lstop); */
+	/* Figure out the tag name */
+	for(lstart++, lp = lstart; lp < lstop; lp++) {
+		switch(*lp) {
+		case 9: case 10: case 11: case 12: case 13: case 32: /* WSP */
+		case 0x2f: /* '/' */ case 0x3e: /* '>' */
+			break;
+		default:
+			continue;
+		}
+		break;
+	}
+	if(lp == lstop) return NULL;	/* No tag found */
+	lstop = lp;
+
+	key.start = lstart;
+	key.stop = lstop;
+	key.vemap = specs->value2enum;
+	key.evmap = specs->enum2value;
+	el_found = (asn_INTEGER_enum_map_t *)bsearch(&key,
+		specs->value2enum, count, sizeof(specs->value2enum[0]),
+		INTEGER__compar_enum2value);
+	if(el_found) {
+		/* Remap enum2value into value2enum */
+		el_found = key.vemap + key.evmap[el_found - key.vemap];
+	}
+	return el_found;
+}
+
+static int
+INTEGER__compar_value2enum(const void *kp, const void *am) {
+	long a = *(const long *)kp;
+	const asn_INTEGER_enum_map_t *el = (const asn_INTEGER_enum_map_t *)am;
+	long b = el->nat_value;
+	if(a < b) return -1;
+	else if(a == b) return 0;
+	else return 1;
+}
+
+const asn_INTEGER_enum_map_t *
+INTEGER_map_value2enum(const asn_INTEGER_specifics_t *specs, long value) {
+	int count = specs ? specs->map_count : 0;
+	if(!count) return 0;
+	return (asn_INTEGER_enum_map_t *)bsearch(&value, specs->value2enum,
+		count, sizeof(specs->value2enum[0]),
+		INTEGER__compar_value2enum);
+}
+
+static int
+INTEGER_st_prealloc(INTEGER_t *st, int min_size) {
+	void *p = MALLOC(min_size + 1);
+	if(p) {
+		void *b = st->buf;
+		st->size = 0;
+		st->buf = p;
+		FREEMEM(b);
+		return 0;
+	} else {
+		return -1;
+	}
+}
+
+/*
+ * Decode the chunk of XML text encoding INTEGER.
+ */
+static enum xer_pbd_rval
+INTEGER__xer_body_decode(const asn_TYPE_descriptor_t *td, void *sptr,
+                         const void *chunk_buf, size_t chunk_size) {
+    INTEGER_t *st = (INTEGER_t *)sptr;
+	intmax_t dec_value;
+	intmax_t hex_value = 0;
+	const char *lp;
+	const char *lstart = (const char *)chunk_buf;
+	const char *lstop = lstart + chunk_size;
+	enum {
+		ST_LEADSPACE,
+		ST_SKIPSPHEX,
+		ST_WAITDIGITS,
+		ST_DIGITS,
+		ST_DIGITS_TRAILSPACE,
+		ST_HEXDIGIT1,
+		ST_HEXDIGIT2,
+		ST_HEXDIGITS_TRAILSPACE,
+		ST_HEXCOLON,
+		ST_END_ENUM,
+		ST_UNEXPECTED
+	} state = ST_LEADSPACE;
+	const char *dec_value_start = 0; /* INVARIANT: always !0 in ST_DIGITS */
+	const char *dec_value_end = 0;
+
+	if(chunk_size)
+		ASN_DEBUG("INTEGER body %ld 0x%2x..0x%2x",
+			(long)chunk_size, *lstart, lstop[-1]);
+
+	if(INTEGER_st_prealloc(st, (chunk_size/3) + 1))
+		return XPBD_SYSTEM_FAILURE;
+
+	/*
+	 * We may have received a tag here. It will be processed inline.
+	 * Use strtoul()-like code and serialize the result.
+	 */
+	for(lp = lstart; lp < lstop; lp++) {
+		int lv = *lp;
+		switch(lv) {
+		case 0x09: case 0x0a: case 0x0d: case 0x20:
+			switch(state) {
+			case ST_LEADSPACE:
+			case ST_DIGITS_TRAILSPACE:
+			case ST_HEXDIGITS_TRAILSPACE:
+			case ST_SKIPSPHEX:
+				continue;
+			case ST_DIGITS:
+				dec_value_end = lp;
+				state = ST_DIGITS_TRAILSPACE;
+				continue;
+			case ST_HEXCOLON:
+				state = ST_HEXDIGITS_TRAILSPACE;
+				continue;
+			default:
+				break;
+			}
+			break;
+		case 0x2d:	/* '-' */
+			if(state == ST_LEADSPACE) {
+				dec_value = 0;
+				dec_value_start = lp;
+				state = ST_WAITDIGITS;
+				continue;
+			}
+			break;
+		case 0x2b:	/* '+' */
+			if(state == ST_LEADSPACE) {
+				dec_value = 0;
+				dec_value_start = lp;
+				state = ST_WAITDIGITS;
+				continue;
+			}
+			break;
+		case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
+		case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
+			switch(state) {
+			case ST_DIGITS: continue;
+			case ST_SKIPSPHEX:	/* Fall through */
+			case ST_HEXDIGIT1:
+				hex_value = (lv - 0x30) << 4;
+				state = ST_HEXDIGIT2;
+				continue;
+			case ST_HEXDIGIT2:
+				hex_value += (lv - 0x30);
+				state = ST_HEXCOLON;
+				st->buf[st->size++] = (uint8_t)hex_value;
+				continue;
+			case ST_HEXCOLON:
+				return XPBD_BROKEN_ENCODING;
+			case ST_LEADSPACE:
+				dec_value = 0;
+				dec_value_start = lp;
+				/* FALL THROUGH */
+			case ST_WAITDIGITS:
+				state = ST_DIGITS;
+				continue;
+			default:
+				break;
+			}
+			break;
+		case 0x3c:	/* '<', start of XML encoded enumeration */
+			if(state == ST_LEADSPACE) {
+				const asn_INTEGER_enum_map_t *el;
+				el = INTEGER_map_enum2value(
+					(const asn_INTEGER_specifics_t *)
+					td->specifics, lstart, lstop);
+				if(el) {
+					ASN_DEBUG("Found \"%s\" => %ld",
+						el->enum_name, el->nat_value);
+					dec_value = el->nat_value;
+					state = ST_END_ENUM;
+					lp = lstop - 1;
+					continue;
+				}
+				ASN_DEBUG("Unknown identifier for INTEGER");
+			}
+			return XPBD_BROKEN_ENCODING;
+		case 0x3a:	/* ':' */
+			if(state == ST_HEXCOLON) {
+				/* This colon is expected */
+				state = ST_HEXDIGIT1;
+				continue;
+			} else if(state == ST_DIGITS) {
+				/* The colon here means that we have
+				 * decoded the first two hexadecimal
+				 * places as a decimal value.
+				 * Switch decoding mode. */
+				ASN_DEBUG("INTEGER re-evaluate as hex form");
+				state = ST_SKIPSPHEX;
+				dec_value_start = 0;
+				lp = lstart - 1;
+				continue;
+			} else {
+				ASN_DEBUG("state %d at %ld", state, (long)(lp - lstart));
+				break;
+			}
+		/* [A-Fa-f] */
+		case 0x41:case 0x42:case 0x43:case 0x44:case 0x45:case 0x46:
+		case 0x61:case 0x62:case 0x63:case 0x64:case 0x65:case 0x66:
+			switch(state) {
+			case ST_SKIPSPHEX:
+			case ST_LEADSPACE: /* Fall through */
+			case ST_HEXDIGIT1:
+				hex_value = lv - ((lv < 0x61) ? 0x41 : 0x61);
+				hex_value += 10;
+				hex_value <<= 4;
+				state = ST_HEXDIGIT2;
+				continue;
+			case ST_HEXDIGIT2:
+				hex_value += lv - ((lv < 0x61) ? 0x41 : 0x61);
+				hex_value += 10;
+				st->buf[st->size++] = (uint8_t)hex_value;
+				state = ST_HEXCOLON;
+				continue;
+			case ST_DIGITS:
+				ASN_DEBUG("INTEGER re-evaluate as hex form");
+				state = ST_SKIPSPHEX;
+				dec_value_start = 0;
+				lp = lstart - 1;
+				continue;
+			default:
+				break;
+			}
+			break;
+		}
+
+		/* Found extra non-numeric stuff */
+		ASN_DEBUG("INTEGER :: Found non-numeric 0x%2x at %ld",
+			lv, (long)(lp - lstart));
+		state = ST_UNEXPECTED;
+		break;
+	}
+
+	switch(state) {
+	case ST_END_ENUM:
+		/* Got a complete and valid enumeration encoded as a tag. */
+		break;
+	case ST_DIGITS:
+		dec_value_end = lstop;
+		/* FALL THROUGH */
+	case ST_DIGITS_TRAILSPACE:
+		/* The last symbol encountered was a digit. */
+        switch(asn_strtoimax_lim(dec_value_start, &dec_value_end, &dec_value)) {
+        case ASN_STRTOX_OK:
+            if(dec_value >= LONG_MIN && dec_value <= LONG_MAX) {
+                break;
+            } else {
+                /*
+                 * We model INTEGER on long for XER,
+                 * to avoid rewriting all the tests at once.
+                 */
+                ASN_DEBUG("INTEGER exceeds long range");
+            }
+            /* Fall through */
+        case ASN_STRTOX_ERROR_RANGE:
+            ASN_DEBUG("INTEGER decode %s hit range limit", td->name);
+            return XPBD_DECODER_LIMIT;
+		case ASN_STRTOX_ERROR_INVAL:
+		case ASN_STRTOX_EXPECT_MORE:
+		case ASN_STRTOX_EXTRA_DATA:
+			return XPBD_BROKEN_ENCODING;
+		}
+		break;
+	case ST_HEXCOLON:
+	case ST_HEXDIGITS_TRAILSPACE:
+		st->buf[st->size] = 0;	/* Just in case termination */
+		return XPBD_BODY_CONSUMED;
+	case ST_HEXDIGIT1:
+	case ST_HEXDIGIT2:
+	case ST_SKIPSPHEX:
+		return XPBD_BROKEN_ENCODING;
+	case ST_LEADSPACE:
+		/* Content not found */
+		return XPBD_NOT_BODY_IGNORE;
+	case ST_WAITDIGITS:
+	case ST_UNEXPECTED:
+		ASN_DEBUG("INTEGER: No useful digits (state %d)", state);
+		return XPBD_BROKEN_ENCODING;	/* No digits */
+	}
+
+	/*
+	 * Convert the result of parsing of enumeration or a straight
+	 * decimal value into a BER representation.
+	 */
+	if(asn_imax2INTEGER(st, dec_value)) {
+                ASN_DEBUG("INTEGER decode %s conversion failed", td->name);
+		return XPBD_SYSTEM_FAILURE;
+        }
+
+	return XPBD_BODY_CONSUMED;
+}
+
+asn_dec_rval_t
+INTEGER_decode_xer(const asn_codec_ctx_t *opt_codec_ctx,
+                   const asn_TYPE_descriptor_t *td, void **sptr,
+                   const char *opt_mname, const void *buf_ptr, size_t size) {
+    return xer_decode_primitive(opt_codec_ctx, td,
+		sptr, sizeof(INTEGER_t), opt_mname,
+		buf_ptr, size, INTEGER__xer_body_decode);
+}
+
+asn_enc_rval_t
+INTEGER_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr,
+                   int ilevel, enum xer_encoder_flags_e flags,
+                   asn_app_consume_bytes_f *cb, void *app_key) {
+    const INTEGER_t *st = (const INTEGER_t *)sptr;
+	asn_enc_rval_t er;
+
+	(void)ilevel;
+	(void)flags;
+	
+	if(!st || !st->buf)
+		ASN__ENCODE_FAILED;
+
+	er.encoded = INTEGER__dump(td, st, cb, app_key, 1);
+	if(er.encoded < 0) ASN__ENCODE_FAILED;
+
+	ASN__ENCODED_OK(er);
+}
+
+#ifndef	ASN_DISABLE_PER_SUPPORT
+
+asn_dec_rval_t
+INTEGER_decode_uper(const asn_codec_ctx_t *opt_codec_ctx,
+                    const asn_TYPE_descriptor_t *td,
+                    const asn_per_constraints_t *constraints, void **sptr,
+                    asn_per_data_t *pd) {
+    const asn_INTEGER_specifics_t *specs =
+        (const asn_INTEGER_specifics_t *)td->specifics;
+    asn_dec_rval_t rval = { RC_OK, 0 };
+	INTEGER_t *st = (INTEGER_t *)*sptr;
+	const asn_per_constraint_t *ct;
+	int repeat;
+
+	(void)opt_codec_ctx;
+
+	if(!st) {
+		st = (INTEGER_t *)(*sptr = CALLOC(1, sizeof(*st)));
+		if(!st) ASN__DECODE_FAILED;
+	}
+
+	if(!constraints) constraints = td->encoding_constraints.per_constraints;
+	ct = constraints ? &constraints->value : 0;
+
+	if(ct && ct->flags & APC_EXTENSIBLE) {
+		int inext = per_get_few_bits(pd, 1);
+		if(inext < 0) ASN__DECODE_STARVED;
+		if(inext) ct = 0;
+	}
+
+	FREEMEM(st->buf);
+	st->buf = 0;
+	st->size = 0;
+	if(ct) {
+		if(ct->flags & APC_SEMI_CONSTRAINED) {
+			st->buf = (uint8_t *)CALLOC(1, 2);
+			if(!st->buf) ASN__DECODE_FAILED;
+			st->size = 1;
+		} else if(ct->flags & APC_CONSTRAINED && ct->range_bits >= 0) {
+			size_t size = (ct->range_bits + 7) >> 3;
+			st->buf = (uint8_t *)MALLOC(1 + size + 1);
+			if(!st->buf) ASN__DECODE_FAILED;
+			st->size = size;
+		}
+	}
+
+	/* X.691-2008/11, #13.2.2, constrained whole number */
+	if(ct && ct->flags != APC_UNCONSTRAINED) {
+		/* #11.5.6 */
+		ASN_DEBUG("Integer with range %d bits", ct->range_bits);
+		if(ct->range_bits >= 0) {
+			if((size_t)ct->range_bits > 8 * sizeof(unsigned long))
+				ASN__DECODE_FAILED;
+
+			if(specs && specs->field_unsigned) {
+				unsigned long uvalue = 0;
+				if(uper_get_constrained_whole_number(pd,
+					&uvalue, ct->range_bits))
+					ASN__DECODE_STARVED;
+				ASN_DEBUG("Got value %lu + low %ld",
+					uvalue, ct->lower_bound);
+				uvalue += ct->lower_bound;
+				if(asn_ulong2INTEGER(st, uvalue))
+					ASN__DECODE_FAILED;
+			} else {
+				unsigned long uvalue = 0;
+				long svalue;
+				if(uper_get_constrained_whole_number(pd,
+					&uvalue, ct->range_bits))
+					ASN__DECODE_STARVED;
+				ASN_DEBUG("Got value %lu + low %ld",
+					uvalue, ct->lower_bound);
+                if(per_long_range_unrebase(uvalue, ct->lower_bound,
+                                           ct->upper_bound, &svalue)
+                   || asn_long2INTEGER(st, svalue)) {
+                    ASN__DECODE_FAILED;
+                }
+			}
+			return rval;
+		}
+	} else {
+		ASN_DEBUG("Decoding unconstrained integer %s", td->name);
+	}
+
+	/* X.691, #12.2.3, #12.2.4 */
+	do {
+		ssize_t len = 0;
+		void *p = NULL;
+		int ret = 0;
+
+		/* Get the PER length */
+		len = uper_get_length(pd, -1, 0, &repeat);
+		if(len < 0) ASN__DECODE_STARVED;
+
+		p = REALLOC(st->buf, st->size + len + 1);
+		if(!p) ASN__DECODE_FAILED;
+		st->buf = (uint8_t *)p;
+
+		ret = per_get_many_bits(pd, &st->buf[st->size], 0, 8 * len);
+		if(ret < 0) ASN__DECODE_STARVED;
+		st->size += len;
+	} while(repeat);
+	st->buf[st->size] = 0;	/* JIC */
+
+	/* #12.2.3 */
+	if(ct && ct->lower_bound) {
+		/*
+		 * TODO: replace by in-place arithmetics.
+		 */
+		long value = 0;
+		if(asn_INTEGER2long(st, &value))
+			ASN__DECODE_FAILED;
+		if(asn_imax2INTEGER(st, value + ct->lower_bound))
+			ASN__DECODE_FAILED;
+	}
+
+	return rval;
+}
+
+asn_enc_rval_t
+INTEGER_encode_uper(const asn_TYPE_descriptor_t *td,
+                    const asn_per_constraints_t *constraints, const void *sptr,
+                    asn_per_outp_t *po) {
+    const asn_INTEGER_specifics_t *specs =
+        (const asn_INTEGER_specifics_t *)td->specifics;
+    asn_enc_rval_t er;
+	const INTEGER_t *st = (const INTEGER_t *)sptr;
+	const uint8_t *buf;
+	const uint8_t *end;
+	const asn_per_constraint_t *ct;
+	long value = 0;
+
+	if(!st || st->size == 0) ASN__ENCODE_FAILED;
+
+	if(!constraints) constraints = td->encoding_constraints.per_constraints;
+	ct = constraints ? &constraints->value : 0;
+
+	er.encoded = 0;
+
+	if(ct) {
+		int inext = 0;
+		if(specs && specs->field_unsigned) {
+			unsigned long uval;
+			if(asn_INTEGER2ulong(st, &uval))
+				ASN__ENCODE_FAILED;
+			/* Check proper range */
+			if(ct->flags & APC_SEMI_CONSTRAINED) {
+				if(uval < (unsigned long)ct->lower_bound)
+					inext = 1;
+			} else if(ct->range_bits >= 0) {
+				if(uval < (unsigned long)ct->lower_bound
+				|| uval > (unsigned long)ct->upper_bound)
+					inext = 1;
+			}
+			ASN_DEBUG("Value %lu (%02x/%" ASN_PRI_SIZE ") lb %lu ub %lu %s",
+				uval, st->buf[0], st->size,
+				ct->lower_bound, ct->upper_bound,
+				inext ? "ext" : "fix");
+			value = uval;
+		} else {
+			if(asn_INTEGER2long(st, &value))
+				ASN__ENCODE_FAILED;
+			/* Check proper range */
+			if(ct->flags & APC_SEMI_CONSTRAINED) {
+				if(value < ct->lower_bound)
+					inext = 1;
+			} else if(ct->range_bits >= 0) {
+				if(value < ct->lower_bound
+				|| value > ct->upper_bound)
+					inext = 1;
+			}
+			ASN_DEBUG("Value %ld (%02x/%" ASN_PRI_SIZE ") lb %ld ub %ld %s",
+				value, st->buf[0], st->size,
+				ct->lower_bound, ct->upper_bound,
+				inext ? "ext" : "fix");
+		}
+		if(ct->flags & APC_EXTENSIBLE) {
+			if(per_put_few_bits(po, inext, 1))
+				ASN__ENCODE_FAILED;
+			if(inext) ct = 0;
+		} else if(inext) {
+			ASN__ENCODE_FAILED;
+		}
+	}
+
+
+	/* X.691-11/2008, #13.2.2, test if constrained whole number */
+	if(ct && ct->range_bits >= 0) {
+        unsigned long v;
+		/* #11.5.6 -> #11.3 */
+		ASN_DEBUG("Encoding integer %ld (%lu) with range %d bits",
+			value, value - ct->lower_bound, ct->range_bits);
+        if(per_long_range_rebase(value, ct->lower_bound, ct->upper_bound, &v)) {
+            ASN__ENCODE_FAILED;
+        }
+        if(uper_put_constrained_whole_number_u(po, v, ct->range_bits))
+            ASN__ENCODE_FAILED;
+		ASN__ENCODED_OK(er);
+	}
+
+	if(ct && ct->lower_bound) {
+		ASN_DEBUG("Adjust lower bound to %ld", ct->lower_bound);
+		/* TODO: adjust lower bound */
+		ASN__ENCODE_FAILED;
+	}
+
+	for(buf = st->buf, end = st->buf + st->size; buf < end;) {
+        int need_eom = 0;
+        ssize_t mayEncode = uper_put_length(po, end - buf, &need_eom);
+        if(mayEncode < 0)
+			ASN__ENCODE_FAILED;
+		if(per_put_many_bits(po, buf, 8 * mayEncode))
+			ASN__ENCODE_FAILED;
+		buf += mayEncode;
+        if(need_eom && uper_put_length(po, 0, 0)) ASN__ENCODE_FAILED;
+    }
+
+	ASN__ENCODED_OK(er);
+}
+
+#endif	/* ASN_DISABLE_PER_SUPPORT */
+
+static intmax_t
+asn__integer_convert(const uint8_t *b, const uint8_t *end) {
+    uintmax_t value;
+
+    /* Perform the sign initialization */
+    /* Actually value = -(*b >> 7); gains nothing, yet unreadable! */
+    if((*b >> 7)) {
+        value = (uintmax_t)(-1);
+    } else {
+        value = 0;
+    }
+
+    /* Conversion engine */
+    for(; b < end; b++) {
+        value = (value << 8) | *b;
+    }
+
+    return value;
+}
+
+int
+asn_INTEGER2imax(const INTEGER_t *iptr, intmax_t *lptr) {
+	uint8_t *b, *end;
+	size_t size;
+
+	/* Sanity checking */
+	if(!iptr || !iptr->buf || !lptr) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	/* Cache the begin/end of the buffer */
+	b = iptr->buf;	/* Start of the INTEGER buffer */
+	size = iptr->size;
+	end = b + size;	/* Where to stop */
+
+	if(size > sizeof(intmax_t)) {
+		uint8_t *end1 = end - 1;
+		/*
+		 * Slightly more advanced processing,
+		 * able to process INTEGERs with >sizeof(intmax_t) bytes
+		 * when the actual value is small, e.g. for intmax_t == int32_t
+		 * (0x0000000000abcdef INTEGER would yield a fine 0x00abcdef int32_t)
+		 */
+		/* Skip out the insignificant leading bytes */
+		for(; b < end1; b++) {
+			switch(*b) {
+				case 0x00: if((b[1] & 0x80) == 0) continue; break;
+				case 0xff: if((b[1] & 0x80) != 0) continue; break;
+			}
+			break;
+		}
+
+		size = end - b;
+		if(size > sizeof(intmax_t)) {
+			/* Still cannot fit the sizeof(intmax_t) */
+			errno = ERANGE;
+			return -1;
+		}
+	}
+
+	/* Shortcut processing of a corner case */
+	if(end == b) {
+		*lptr = 0;
+		return 0;
+	}
+
+	*lptr = asn__integer_convert(b, end);
+	return 0;
+}
+
+/* FIXME: negative INTEGER values are silently interpreted as large unsigned ones. */
+int
+asn_INTEGER2umax(const INTEGER_t *iptr, uintmax_t *lptr) {
+	uint8_t *b, *end;
+	uintmax_t value;
+	size_t size;
+
+	if(!iptr || !iptr->buf || !lptr) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	b = iptr->buf;
+	size = iptr->size;
+	end = b + size;
+
+	/* If all extra leading bytes are zeroes, ignore them */
+	for(; size > sizeof(value); b++, size--) {
+		if(*b) {
+			/* Value won't fit into uintmax_t */
+			errno = ERANGE;
+			return -1;
+		}
+	}
+
+	/* Conversion engine */
+	for(value = 0; b < end; b++)
+		value = (value << 8) | *b;
+
+	*lptr = value;
+	return 0;
+}
+
+int
+asn_umax2INTEGER(INTEGER_t *st, uintmax_t value) {
+    uint8_t *buf;
+    uint8_t *end;
+    uint8_t *b;
+    int shr;
+
+    if(value <= ((~(uintmax_t)0) >> 1)) {
+        return asn_imax2INTEGER(st, value);
+    }
+
+    buf = (uint8_t *)MALLOC(1 + sizeof(value));
+    if(!buf) return -1;
+
+    end = buf + (sizeof(value) + 1);
+    buf[0] = 0; /* INTEGERs are signed. 0-byte indicates positive. */
+    for(b = buf + 1, shr = (sizeof(value) - 1) * 8; b < end; shr -= 8, b++)
+        *b = (uint8_t)(value >> shr);
+
+    if(st->buf) FREEMEM(st->buf);
+    st->buf = buf;
+    st->size = 1 + sizeof(value);
+
+	return 0;
+}
+
+int
+asn_imax2INTEGER(INTEGER_t *st, intmax_t value) {
+	uint8_t *buf, *bp;
+	uint8_t *p;
+	uint8_t *pstart;
+	uint8_t *pend1;
+	int littleEndian = 1;	/* Run-time detection */
+	int add;
+
+	if(!st) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	buf = (uint8_t *)(long *)MALLOC(sizeof(value));
+	if(!buf) return -1;
+
+	if(*(char *)&littleEndian) {
+		pstart = (uint8_t *)&value + sizeof(value) - 1;
+		pend1 = (uint8_t *)&value;
+		add = -1;
+	} else {
+		pstart = (uint8_t *)&value;
+		pend1 = pstart + sizeof(value) - 1;
+		add = 1;
+	}
+
+	/*
+	 * If the contents octet consists of more than one octet,
+	 * then bits of the first octet and bit 8 of the second octet:
+	 * a) shall not all be ones; and
+	 * b) shall not all be zero.
+	 */
+	for(p = pstart; p != pend1; p += add) {
+		switch(*p) {
+		case 0x00: if((*(p+add) & 0x80) == 0)
+				continue;
+			break;
+		case 0xff: if((*(p+add) & 0x80))
+				continue;
+			break;
+		}
+		break;
+	}
+	/* Copy the integer body */
+	for(bp = buf, pend1 += add; p != pend1; p += add)
+		*bp++ = *p;
+
+	if(st->buf) FREEMEM(st->buf);
+	st->buf = buf;
+	st->size = bp - buf;
+
+	return 0;
+}
+
+int
+asn_INTEGER2long(const INTEGER_t *iptr, long *l) {
+    intmax_t v;
+    if(asn_INTEGER2imax(iptr, &v) == 0) {
+        if(v < LONG_MIN || v > LONG_MAX) {
+            errno = ERANGE;
+            return -1;
+        }
+        *l = v;
+        return 0;
+    } else {
+        return -1;
+    }
+}
+
+int
+asn_INTEGER2ulong(const INTEGER_t *iptr, unsigned long *l) {
+    uintmax_t v;
+    if(asn_INTEGER2umax(iptr, &v) == 0) {
+        if(v > ULONG_MAX) {
+            errno = ERANGE;
+            return -1;
+        }
+        *l = v;
+        return 0;
+    } else {
+        return -1;
+    }
+}
+
+int
+asn_long2INTEGER(INTEGER_t *st, long value) {
+    return asn_imax2INTEGER(st, value);
+}
+
+int
+asn_ulong2INTEGER(INTEGER_t *st, unsigned long value) {
+    return asn_imax2INTEGER(st, value);
+}
+
+/*
+ * Parse the number in the given string until the given *end position,
+ * returning the position after the last parsed character back using the
+ * same (*end) pointer.
+ * WARNING: This behavior is different from the standard strtol/strtoimax(3).
+ */
+enum asn_strtox_result_e
+asn_strtoimax_lim(const char *str, const char **end, intmax_t *intp) {
+    int sign = 1;
+    intmax_t value;
+
+    const intmax_t asn1_intmax_max = ((~(uintmax_t)0) >> 1);
+    const intmax_t upper_boundary = asn1_intmax_max / 10;
+    intmax_t last_digit_max = asn1_intmax_max % 10;
+
+    if(str >= *end) return ASN_STRTOX_ERROR_INVAL;
+
+    switch(*str) {
+    case '-':
+        last_digit_max++;
+        sign = -1;
+        /* FALL THROUGH */
+    case '+':
+        str++;
+        if(str >= *end) {
+            *end = str;
+            return ASN_STRTOX_EXPECT_MORE;
+        }
+    }
+
+    for(value = 0; str < (*end); str++) {
+        if(*str >= 0x30 && *str <= 0x39) {
+            int d = *str - '0';
+            if(value < upper_boundary) {
+                value = value * 10 + d;
+            } else if(value == upper_boundary) {
+                if(d <= last_digit_max) {
+                    if(sign > 0) {
+                        value = value * 10 + d;
+                    } else {
+                        sign = 1;
+                        value = -value * 10 - d;
+                    }
+                    str += 1;
+                    if(str < *end) {
+                        // If digits continue, we're guaranteed out of range.
+                        *end = str;
+                        if(*str >= 0x30 && *str <= 0x39) {
+                            return ASN_STRTOX_ERROR_RANGE;
+                        } else {
+                            *intp = sign * value;
+                            return ASN_STRTOX_EXTRA_DATA;
+                        }
+                    }
+                    break;
+                } else {
+                    *end = str;
+                    return ASN_STRTOX_ERROR_RANGE;
+                }
+            } else {
+                *end = str;
+                return ASN_STRTOX_ERROR_RANGE;
+            }
+        } else {
+            *end = str;
+            *intp = sign * value;
+            return ASN_STRTOX_EXTRA_DATA;
+        }
+    }
+
+    *end = str;
+    *intp = sign * value;
+    return ASN_STRTOX_OK;
+}
+
+/*
+ * Parse the number in the given string until the given *end position,
+ * returning the position after the last parsed character back using the
+ * same (*end) pointer.
+ * WARNING: This behavior is different from the standard strtoul/strtoumax(3).
+ */
+enum asn_strtox_result_e
+asn_strtoumax_lim(const char *str, const char **end, uintmax_t *uintp) {
+    uintmax_t value;
+
+    const uintmax_t asn1_uintmax_max = ((~(uintmax_t)0));
+    const uintmax_t upper_boundary = asn1_uintmax_max / 10;
+    uintmax_t last_digit_max = asn1_uintmax_max % 10;
+
+    if(str >= *end) return ASN_STRTOX_ERROR_INVAL;
+
+    switch(*str) {
+    case '-':
+        return ASN_STRTOX_ERROR_INVAL;
+    case '+':
+        str++;
+        if(str >= *end) {
+            *end = str;
+            return ASN_STRTOX_EXPECT_MORE;
+        }
+    }
+
+    for(value = 0; str < (*end); str++) {
+        if(*str >= 0x30 && *str <= 0x39) {
+            unsigned int d = *str - '0';
+            if(value < upper_boundary) {
+                value = value * 10 + d;
+            } else if(value == upper_boundary) {
+                if(d <= last_digit_max) {
+                    value = value * 10 + d;
+                    str += 1;
+                    if(str < *end) {
+                        // If digits continue, we're guaranteed out of range.
+                        *end = str;
+                        if(*str >= 0x30 && *str <= 0x39) {
+                            return ASN_STRTOX_ERROR_RANGE;
+                        } else {
+                            *uintp = value;
+                            return ASN_STRTOX_EXTRA_DATA;
+                        }
+                    }
+                    break;
+                } else {
+                    *end = str;
+                    return ASN_STRTOX_ERROR_RANGE;
+                }
+            } else {
+                *end = str;
+                return ASN_STRTOX_ERROR_RANGE;
+            }
+        } else {
+            *end = str;
+            *uintp = value;
+            return ASN_STRTOX_EXTRA_DATA;
+        }
+    }
+
+    *end = str;
+    *uintp = value;
+    return ASN_STRTOX_OK;
+}
+
+enum asn_strtox_result_e
+asn_strtol_lim(const char *str, const char **end, long *lp) {
+    intmax_t value;
+    switch(asn_strtoimax_lim(str, end, &value)) {
+    case ASN_STRTOX_ERROR_RANGE:
+        return ASN_STRTOX_ERROR_RANGE;
+    case ASN_STRTOX_ERROR_INVAL:
+        return ASN_STRTOX_ERROR_INVAL;
+    case ASN_STRTOX_EXPECT_MORE:
+        return ASN_STRTOX_EXPECT_MORE;
+    case ASN_STRTOX_OK:
+        if(value >= LONG_MIN && value <= LONG_MAX) {
+            *lp = value;
+            return ASN_STRTOX_OK;
+        } else {
+            return ASN_STRTOX_ERROR_RANGE;
+        }
+    case ASN_STRTOX_EXTRA_DATA:
+        if(value >= LONG_MIN && value <= LONG_MAX) {
+            *lp = value;
+            return ASN_STRTOX_EXTRA_DATA;
+        } else {
+            return ASN_STRTOX_ERROR_RANGE;
+        }
+    }
+
+    assert(!"Unreachable");
+    return ASN_STRTOX_ERROR_INVAL;
+}
+
+enum asn_strtox_result_e
+asn_strtoul_lim(const char *str, const char **end, unsigned long *ulp) {
+    uintmax_t value;
+    switch(asn_strtoumax_lim(str, end, &value)) {
+    case ASN_STRTOX_ERROR_RANGE:
+        return ASN_STRTOX_ERROR_RANGE;
+    case ASN_STRTOX_ERROR_INVAL:
+        return ASN_STRTOX_ERROR_INVAL;
+    case ASN_STRTOX_EXPECT_MORE:
+        return ASN_STRTOX_EXPECT_MORE;
+    case ASN_STRTOX_OK:
+        if(value <= ULONG_MAX) {
+            *ulp = value;
+            return ASN_STRTOX_OK;
+        } else {
+            return ASN_STRTOX_ERROR_RANGE;
+        }
+    case ASN_STRTOX_EXTRA_DATA:
+        if(value <= ULONG_MAX) {
+            *ulp = value;
+            return ASN_STRTOX_EXTRA_DATA;
+        } else {
+            return ASN_STRTOX_ERROR_RANGE;
+        }
+    }
+
+    assert(!"Unreachable");
+    return ASN_STRTOX_ERROR_INVAL;
+}
+
+int
+INTEGER_compare(const asn_TYPE_descriptor_t *td, const void *aptr,
+                     const void *bptr) {
+    const INTEGER_t *a = aptr;
+    const INTEGER_t *b = bptr;
+
+    (void)td;
+
+    if(a && b) {
+        if(a->size && b->size) {
+            int sign_a = (a->buf[0] & 0x80) ? -1 : 1;
+            int sign_b = (b->buf[0] & 0x80) ? -1 : 1;
+
+            if(sign_a < sign_b) return -1;
+            if(sign_a > sign_b) return 1;
+
+            /* The shortest integer wins, unless comparing negatives */
+            if(a->size < b->size) {
+                return -1 * sign_a;
+            } else if(a->size > b->size) {
+                return 1 * sign_b;
+            }
+
+            return sign_a * memcmp(a->buf, b->buf, a->size);
+        } else if(a->size) {
+            int sign = (a->buf[0] & 0x80) ? -1 : 1;
+            return (1) * sign;
+        } else if(b->size) {
+            int sign = (a->buf[0] & 0x80) ? -1 : 1;
+            return (-1) * sign;
+        } else {
+            return 0;
+        }
+    } else if(!a && !b) {
+        return 0;
+    } else if(!a) {
+        return -1;
+    } else {
+        return 1;
+    }
+
+}
+
+asn_random_fill_result_t
+INTEGER_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
+                    const asn_encoding_constraints_t *constraints,
+                    size_t max_length) {
+    const asn_INTEGER_specifics_t *specs =
+        (const asn_INTEGER_specifics_t *)td->specifics;
+    asn_random_fill_result_t result_ok = {ARFILL_OK, 1};
+    asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0};
+    asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};
+    INTEGER_t *st = *sptr;
+    const asn_INTEGER_enum_map_t *emap;
+    size_t emap_len;
+    intmax_t value;
+    int find_inside_map;
+
+    if(max_length == 0) return result_skipped;
+
+    if(st == NULL) {
+        st = (INTEGER_t *)CALLOC(1, sizeof(*st));
+        if(st == NULL) {
+            return result_failed;
+        }
+    }
+
+    if(specs) {
+        emap = specs->value2enum;
+        emap_len = specs->map_count;
+        if(specs->strict_enumeration) {
+            find_inside_map = emap_len > 0;
+        } else {
+            find_inside_map = emap_len ? asn_random_between(0, 1) : 0;
+        }
+    } else {
+        emap = 0;
+        emap_len = 0;
+        find_inside_map = 0;
+    }
+
+    if(find_inside_map) {
+        assert(emap_len > 0);
+        value = emap[asn_random_between(0, emap_len - 1)].nat_value;
+    } else {
+        const asn_per_constraints_t *ct;
+
+        static const long variants[] = {
+            -65536, -65535, -65534, -32769, -32768, -32767, -16385, -16384,
+            -16383, -257,   -256,   -255,   -254,   -129,   -128,   -127,
+            -126,   -1,     0,      1,      126,    127,    128,    129,
+            254,    255,    256,    257,    16383,  16384,  16385,  32767,
+            32768,  32769,  65534,  65535,  65536,  65537};
+        if(specs && specs->field_unsigned) {
+            assert(variants[18] == 0);
+            value = variants[asn_random_between(
+                18, sizeof(variants) / sizeof(variants[0]) - 1)];
+        } else {
+            value = variants[asn_random_between(
+                0, sizeof(variants) / sizeof(variants[0]) - 1)];
+        }
+
+        if(!constraints) constraints = &td->encoding_constraints;
+        ct = constraints ? constraints->per_constraints : 0;
+        if(ct && (ct->value.flags & APC_CONSTRAINED)) {
+            if(value < ct->value.lower_bound || value > ct->value.upper_bound) {
+                value = asn_random_between(ct->value.lower_bound,
+                                           ct->value.upper_bound);
+            }
+        }
+    }
+
+    if(asn_imax2INTEGER(st, value)) {
+        if(st == *sptr) {
+            ASN_STRUCT_RESET(*td, st);
+        } else {
+            ASN_STRUCT_FREE(*td, st);
+        }
+        return result_failed;
+    } else {
+        *sptr = st;
+        result_ok.length = st->size;
+        return result_ok;
+    }
+}

+ 104 - 0
seader/lib/asn1/INTEGER.h

@@ -0,0 +1,104 @@
+/*-
+ * Copyright (c) 2003-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef	_INTEGER_H_
+#define	_INTEGER_H_
+
+#include <asn_application.h>
+#include <asn_codecs_prim.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef ASN__PRIMITIVE_TYPE_t INTEGER_t;
+
+extern asn_TYPE_descriptor_t asn_DEF_INTEGER;
+extern asn_TYPE_operation_t asn_OP_INTEGER;
+
+/* Map with <tag> to integer value association */
+typedef struct asn_INTEGER_enum_map_s {
+	long		 nat_value;	/* associated native integer value */
+	size_t		 enum_len;	/* strlen("tag") */
+	const char	*enum_name;	/* "tag" */
+} asn_INTEGER_enum_map_t;
+
+/* This type describes an enumeration for INTEGER and ENUMERATED types */
+typedef struct asn_INTEGER_specifics_s {
+	const asn_INTEGER_enum_map_t *value2enum;	/* N -> "tag"; sorted by N */
+	const unsigned int *enum2value;		/* "tag" => N; sorted by tag */
+	int map_count;				/* Elements in either map */
+	int extension;				/* This map is extensible */
+	int strict_enumeration;			/* Enumeration set is fixed */
+	int field_width;			/* Size of native integer */
+	int field_unsigned;			/* Signed=0, unsigned=1 */
+} asn_INTEGER_specifics_t;
+
+#define INTEGER_free    ASN__PRIMITIVE_TYPE_free
+#define INTEGER_decode_ber	ber_decode_primitive
+#define INTEGER_constraint	asn_generic_no_constraint
+asn_struct_print_f INTEGER_print;
+asn_struct_compare_f INTEGER_compare;
+der_type_encoder_f INTEGER_encode_der;
+xer_type_decoder_f INTEGER_decode_xer;
+xer_type_encoder_f INTEGER_encode_xer;
+oer_type_decoder_f INTEGER_decode_oer;
+oer_type_encoder_f INTEGER_encode_oer;
+per_type_decoder_f INTEGER_decode_uper;
+per_type_encoder_f INTEGER_encode_uper;
+asn_random_fill_f  INTEGER_random_fill;
+
+/***********************************
+ * Some handy conversion routines. *
+ ***********************************/
+
+/*
+ * Natiwe size-independent conversion of native integers to/from INTEGER.
+ * (l_size) is in bytes.
+ * Returns 0 if it was possible to convert, -1 otherwise.
+ * -1/EINVAL: Mandatory argument missing
+ * -1/ERANGE: Value encoded is out of range for long representation
+ * -1/ENOMEM: Memory allocation failed (in asn_*2INTEGER()).
+ */
+int asn_INTEGER2imax(const INTEGER_t *i, intmax_t *l);
+int asn_INTEGER2umax(const INTEGER_t *i, uintmax_t *l);
+int asn_imax2INTEGER(INTEGER_t *i, intmax_t l);
+int asn_umax2INTEGER(INTEGER_t *i, uintmax_t l);
+
+/*
+ * Size-specific conversion helpers.
+ */
+int asn_INTEGER2long(const INTEGER_t *i, long *l);
+int asn_INTEGER2ulong(const INTEGER_t *i, unsigned long *l);
+int asn_long2INTEGER(INTEGER_t *i, long l);
+int asn_ulong2INTEGER(INTEGER_t *i, unsigned long l);
+
+/* A version of strtol/strtoimax(3) with nicer error reporting. */
+enum asn_strtox_result_e {
+    ASN_STRTOX_ERROR_RANGE = -3,  /* Input outside of supported numeric range */
+    ASN_STRTOX_ERROR_INVAL = -2,  /* Invalid data encountered (e.g., "+-") */
+    ASN_STRTOX_EXPECT_MORE = -1,  /* More data expected (e.g. "+") */
+    ASN_STRTOX_OK          =  0,  /* Conversion succeded, number ends at (*end) */
+    ASN_STRTOX_EXTRA_DATA  =  1   /* Conversion succeded, but the string has extra stuff */
+};
+enum asn_strtox_result_e asn_strtol_lim(const char *str, const char **end,
+                                        long *l);
+enum asn_strtox_result_e asn_strtoul_lim(const char *str, const char **end,
+                                         unsigned long *l);
+enum asn_strtox_result_e asn_strtoimax_lim(const char *str, const char **end,
+                                           intmax_t *l);
+enum asn_strtox_result_e asn_strtoumax_lim(const char *str, const char **end,
+                                           uintmax_t *l);
+
+/*
+ * Convert the integer value into the corresponding enumeration map entry.
+ */
+const asn_INTEGER_enum_map_t *INTEGER_map_value2enum(
+    const asn_INTEGER_specifics_t *specs, long value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _INTEGER_H_ */

+ 179 - 0
seader/lib/asn1/INTEGER_oer.c

@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>.
+ * All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef ASN_DISABLE_OER_SUPPORT
+
+#include <asn_internal.h>
+#include <INTEGER.h>
+#include <errno.h>
+
+asn_dec_rval_t
+INTEGER_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
+                   const asn_TYPE_descriptor_t *td,
+                   const asn_oer_constraints_t *constraints, void **sptr,
+                   const void *ptr, size_t size) {
+    const asn_INTEGER_specifics_t *specs =
+        (const asn_INTEGER_specifics_t *)td->specifics;
+    asn_dec_rval_t rval = {RC_OK, 0};
+    INTEGER_t *st = (INTEGER_t *)*sptr;
+    struct asn_oer_constraint_number_s ct = {0, 0};
+    size_t req_bytes;
+
+    (void)opt_codec_ctx;
+    (void)specs;
+
+    if(!st) {
+        st = (INTEGER_t *)(*sptr = CALLOC(1, sizeof(*st)));
+        if(!st) ASN__DECODE_FAILED;
+    }
+
+    FREEMEM(st->buf);
+    st->buf = 0;
+    st->size = 0;
+
+    if(!constraints) constraints = td->encoding_constraints.oer_constraints;
+    if(constraints) ct = constraints->value;
+
+    if(ct.width) {
+        req_bytes = ct.width;
+    } else {
+        /* No lower bound and no upper bound, effectively */
+
+        ssize_t consumed = oer_fetch_length(ptr, size, &req_bytes);
+        if(consumed == 0) {
+            ASN__DECODE_STARVED;
+        } else if(consumed == -1) {
+            ASN__DECODE_FAILED;
+        }
+        rval.consumed += consumed;
+        ptr = (const char *)ptr + consumed;
+        size -= consumed;
+    }
+
+    if(req_bytes > size) {
+        ASN__DECODE_STARVED;
+    }
+
+    if(ct.positive) {
+        /* X.969 08/2015 10.2(a) */
+        unsigned msb;   /* Most significant bit */
+        size_t useful_size;
+
+        /* Check most significant bit */
+        msb = *(const uint8_t *)ptr >> 7; /* yields 0 or 1 */
+        useful_size = msb + req_bytes;
+        st->buf = (uint8_t *)MALLOC(useful_size + 1);
+        if(!st->buf) {
+            ASN__DECODE_FAILED;
+        }
+
+        /*
+         * Record a large unsigned in a way not to confuse it
+         * with signed value.
+         */
+        st->buf[0] = '\0';
+        memcpy(st->buf + msb, ptr, req_bytes);
+        st->buf[useful_size] = '\0';    /* Just in case, 0-terminate */
+        st->size = useful_size;
+
+        rval.consumed += req_bytes;
+        return rval;
+    } else {
+        /* X.969 08/2015 10.2(b) */
+        st->buf = (uint8_t *)MALLOC(req_bytes + 1);
+        if(!st->buf) {
+            ASN__DECODE_FAILED;
+        }
+
+        memcpy(st->buf, ptr, req_bytes);
+        st->buf[req_bytes] = '\0'; /* Just in case, 0-terminate */
+        st->size = req_bytes;
+
+        rval.consumed += req_bytes;
+        return rval;
+    }
+}
+
+/*
+ * Encode as Canonical OER.
+ */
+asn_enc_rval_t
+INTEGER_encode_oer(const asn_TYPE_descriptor_t *td,
+                   const asn_oer_constraints_t *constraints, const void *sptr,
+                   asn_app_consume_bytes_f *cb, void *app_key) {
+    const INTEGER_t *st = sptr;
+    asn_enc_rval_t er;
+    struct asn_oer_constraint_number_s ct = {0, 0};
+    const uint8_t *buf;
+    const uint8_t *end;
+    size_t useful_bytes;
+    size_t req_bytes = 0;
+    int sign = 0;
+
+    if(!st || st->size == 0) ASN__ENCODE_FAILED;
+
+    if(!constraints) constraints = td->encoding_constraints.oer_constraints;
+    if(constraints) ct = constraints->value;
+
+    er.encoded = 0;
+
+    buf = st->buf;
+    end = buf + st->size;
+
+    sign = (buf && buf < end) ? buf[0] & 0x80 : 0;
+
+    /* Ignore 9 leading zeroes or ones */
+    if(ct.positive) {
+        if(sign) {
+            /* The value given is a signed value. Can't proceed. */
+            ASN__ENCODE_FAILED;
+        }
+        /* Remove leading zeros. */
+        for(; buf + 1 < end; buf++) {
+            if(buf[0] != 0x0) break;
+        }
+    } else {
+        for(; buf + 1 < end; buf++) {
+            if(buf[0] == 0x0 && (buf[1] & 0x80) == 0) {
+                continue;
+            } else if(buf[0] == 0xff && (buf[1] & 0x80) != 0) {
+                continue;
+            }
+            break;
+        }
+    }
+
+    useful_bytes = end - buf;
+    if(ct.width) {
+        req_bytes = ct.width;
+    } else {
+        ssize_t r = oer_serialize_length(useful_bytes, cb, app_key);
+        if(r < 0) {
+            ASN__ENCODE_FAILED;
+        }
+        er.encoded += r;
+        req_bytes = useful_bytes;
+    }
+
+    if(req_bytes < useful_bytes) {
+        ASN__ENCODE_FAILED;
+    }
+
+    er.encoded += req_bytes;
+
+    for(; req_bytes > useful_bytes; req_bytes--) {
+        if(cb(sign?"\xff":"\0", 1, app_key) < 0) {
+            ASN__ENCODE_FAILED;
+        }
+    }
+
+    if(cb(buf, useful_bytes, app_key) < 0) {
+        ASN__ENCODE_FAILED;
+    }
+
+    ASN__ENCODED_OK(er);
+}
+
+#endif  /* ASN_DISABLE_OER_SUPPORT */

+ 65 - 0
seader/lib/asn1/NFCCommand.c

@@ -0,0 +1,65 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#include "NFCCommand.h"
+
+static asn_oer_constraints_t asn_OER_type_NFCCommand_constr_1 CC_NOTUSED = {
+	{ 0, 0 },
+	-1};
+asn_per_constraints_t asn_PER_type_NFCCommand_constr_1 CC_NOTUSED = {
+	{ APC_CONSTRAINED,	 1,  1,  0,  1 }	/* (0..1) */,
+	{ APC_UNCONSTRAINED,	-1, -1,  0,  0 },
+	0, 0	/* No PER value map */
+};
+asn_TYPE_member_t asn_MBR_NFCCommand_1[] = {
+	{ ATF_NOFLAGS, 0, offsetof(struct NFCCommand, choice.nfcSend),
+		(ASN_TAG_CLASS_CONTEXT | (1 << 2)),
+		-1,	/* IMPLICIT tag at current level */
+		&asn_DEF_NFCSend,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"nfcSend"
+		},
+	{ ATF_NOFLAGS, 0, offsetof(struct NFCCommand, choice.nfcOff),
+		(ASN_TAG_CLASS_CONTEXT | (2 << 2)),
+		-1,	/* IMPLICIT tag at current level */
+		&asn_DEF_NULL,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"nfcOff"
+		},
+};
+static const asn_TYPE_tag2member_t asn_MAP_NFCCommand_tag2el_1[] = {
+    { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 0, 0, 0 }, /* nfcSend */
+    { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 1, 0, 0 } /* nfcOff */
+};
+asn_CHOICE_specifics_t asn_SPC_NFCCommand_specs_1 = {
+	sizeof(struct NFCCommand),
+	offsetof(struct NFCCommand, _asn_ctx),
+	offsetof(struct NFCCommand, present),
+	sizeof(((struct NFCCommand *)0)->present),
+	asn_MAP_NFCCommand_tag2el_1,
+	2,	/* Count of tags in the map */
+	0, 0,
+	-1	/* Extensions start */
+};
+asn_TYPE_descriptor_t asn_DEF_NFCCommand = {
+	"NFCCommand",
+	"NFCCommand",
+	&asn_OP_CHOICE,
+	0,	/* No effective tags (pointer) */
+	0,	/* No effective tags (count) */
+	0,	/* No tags (pointer) */
+	0,	/* No tags (count) */
+	{ &asn_OER_type_NFCCommand_constr_1, &asn_PER_type_NFCCommand_constr_1, CHOICE_constraint },
+	asn_MBR_NFCCommand_1,
+	2,	/* Elements count */
+	&asn_SPC_NFCCommand_specs_1	/* Additional specs */
+};
+

+ 53 - 0
seader/lib/asn1/NFCCommand.h

@@ -0,0 +1,53 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#ifndef	_NFCCommand_H_
+#define	_NFCCommand_H_
+
+
+#include <asn_application.h>
+
+/* Including external dependencies */
+#include "NFCSend.h"
+#include <NULL.h>
+#include <constr_CHOICE.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Dependencies */
+typedef enum NFCCommand_PR {
+	NFCCommand_PR_NOTHING,	/* No components present */
+	NFCCommand_PR_nfcSend,
+	NFCCommand_PR_nfcOff
+} NFCCommand_PR;
+
+/* NFCCommand */
+typedef struct NFCCommand {
+	NFCCommand_PR present;
+	union NFCCommand_u {
+		NFCSend_t	 nfcSend;
+		NULL_t	 nfcOff;
+	} choice;
+	
+	/* Context for parsing across buffer boundaries */
+	asn_struct_ctx_t _asn_ctx;
+} NFCCommand_t;
+
+/* Implementation */
+extern asn_TYPE_descriptor_t asn_DEF_NFCCommand;
+extern asn_CHOICE_specifics_t asn_SPC_NFCCommand_specs_1;
+extern asn_TYPE_member_t asn_MBR_NFCCommand_1[2];
+extern asn_per_constraints_t asn_PER_type_NFCCommand_constr_1;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _NFCCommand_H_ */
+#include <asn_internal.h>

+ 65 - 0
seader/lib/asn1/NFCResponse.c

@@ -0,0 +1,65 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#include "NFCResponse.h"
+
+static asn_oer_constraints_t asn_OER_type_NFCResponse_constr_1 CC_NOTUSED = {
+	{ 0, 0 },
+	-1};
+asn_per_constraints_t asn_PER_type_NFCResponse_constr_1 CC_NOTUSED = {
+	{ APC_CONSTRAINED,	 1,  1,  0,  1 }	/* (0..1) */,
+	{ APC_UNCONSTRAINED,	-1, -1,  0,  0 },
+	0, 0	/* No PER value map */
+};
+asn_TYPE_member_t asn_MBR_NFCResponse_1[] = {
+	{ ATF_NOFLAGS, 0, offsetof(struct NFCResponse, choice.nfcRx),
+		(ASN_TAG_CLASS_CONTEXT | (0 << 2)),
+		-1,	/* IMPLICIT tag at current level */
+		&asn_DEF_NFCRx,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"nfcRx"
+		},
+	{ ATF_NOFLAGS, 0, offsetof(struct NFCResponse, choice.nfcAck),
+		(ASN_TAG_CLASS_CONTEXT | (2 << 2)),
+		-1,	/* IMPLICIT tag at current level */
+		&asn_DEF_NULL,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"nfcAck"
+		},
+};
+static const asn_TYPE_tag2member_t asn_MAP_NFCResponse_tag2el_1[] = {
+    { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* nfcRx */
+    { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 1, 0, 0 } /* nfcAck */
+};
+asn_CHOICE_specifics_t asn_SPC_NFCResponse_specs_1 = {
+	sizeof(struct NFCResponse),
+	offsetof(struct NFCResponse, _asn_ctx),
+	offsetof(struct NFCResponse, present),
+	sizeof(((struct NFCResponse *)0)->present),
+	asn_MAP_NFCResponse_tag2el_1,
+	2,	/* Count of tags in the map */
+	0, 0,
+	-1	/* Extensions start */
+};
+asn_TYPE_descriptor_t asn_DEF_NFCResponse = {
+	"NFCResponse",
+	"NFCResponse",
+	&asn_OP_CHOICE,
+	0,	/* No effective tags (pointer) */
+	0,	/* No effective tags (count) */
+	0,	/* No tags (pointer) */
+	0,	/* No tags (count) */
+	{ &asn_OER_type_NFCResponse_constr_1, &asn_PER_type_NFCResponse_constr_1, CHOICE_constraint },
+	asn_MBR_NFCResponse_1,
+	2,	/* Elements count */
+	&asn_SPC_NFCResponse_specs_1	/* Additional specs */
+};
+

+ 53 - 0
seader/lib/asn1/NFCResponse.h

@@ -0,0 +1,53 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#ifndef	_NFCResponse_H_
+#define	_NFCResponse_H_
+
+
+#include <asn_application.h>
+
+/* Including external dependencies */
+#include "NFCRx.h"
+#include <NULL.h>
+#include <constr_CHOICE.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Dependencies */
+typedef enum NFCResponse_PR {
+	NFCResponse_PR_NOTHING,	/* No components present */
+	NFCResponse_PR_nfcRx,
+	NFCResponse_PR_nfcAck
+} NFCResponse_PR;
+
+/* NFCResponse */
+typedef struct NFCResponse {
+	NFCResponse_PR present;
+	union NFCResponse_u {
+		NFCRx_t	 nfcRx;
+		NULL_t	 nfcAck;
+	} choice;
+	
+	/* Context for parsing across buffer boundaries */
+	asn_struct_ctx_t _asn_ctx;
+} NFCResponse_t;
+
+/* Implementation */
+extern asn_TYPE_descriptor_t asn_DEF_NFCResponse;
+extern asn_CHOICE_specifics_t asn_SPC_NFCResponse_specs_1;
+extern asn_TYPE_member_t asn_MBR_NFCResponse_1[2];
+extern asn_per_constraints_t asn_PER_type_NFCResponse_constr_1;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _NFCResponse_H_ */
+#include <asn_internal.h>

+ 62 - 0
seader/lib/asn1/NFCRx.c

@@ -0,0 +1,62 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#include "NFCRx.h"
+
+asn_TYPE_member_t asn_MBR_NFCRx_1[] = {
+	{ ATF_POINTER, 1, offsetof(struct NFCRx, data),
+		(ASN_TAG_CLASS_CONTEXT | (0 << 2)),
+		-1,	/* IMPLICIT tag at current level */
+		&asn_DEF_OCTET_STRING,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"data"
+		},
+	{ ATF_NOFLAGS, 0, offsetof(struct NFCRx, rfStatus),
+		(ASN_TAG_CLASS_CONTEXT | (1 << 2)),
+		-1,	/* IMPLICIT tag at current level */
+		&asn_DEF_RfStatus,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"rfStatus"
+		},
+};
+static const int asn_MAP_NFCRx_oms_1[] = { 0 };
+static const ber_tlv_tag_t asn_DEF_NFCRx_tags_1[] = {
+	(ASN_TAG_CLASS_UNIVERSAL | (16 << 2))
+};
+static const asn_TYPE_tag2member_t asn_MAP_NFCRx_tag2el_1[] = {
+    { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* data */
+    { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* rfStatus */
+};
+asn_SEQUENCE_specifics_t asn_SPC_NFCRx_specs_1 = {
+	sizeof(struct NFCRx),
+	offsetof(struct NFCRx, _asn_ctx),
+	asn_MAP_NFCRx_tag2el_1,
+	2,	/* Count of tags in the map */
+	asn_MAP_NFCRx_oms_1,	/* Optional members */
+	1, 0,	/* Root/Additions */
+	-1,	/* First extension addition */
+};
+asn_TYPE_descriptor_t asn_DEF_NFCRx = {
+	"NFCRx",
+	"NFCRx",
+	&asn_OP_SEQUENCE,
+	asn_DEF_NFCRx_tags_1,
+	sizeof(asn_DEF_NFCRx_tags_1)
+		/sizeof(asn_DEF_NFCRx_tags_1[0]), /* 1 */
+	asn_DEF_NFCRx_tags_1,	/* Same as above */
+	sizeof(asn_DEF_NFCRx_tags_1)
+		/sizeof(asn_DEF_NFCRx_tags_1[0]), /* 1 */
+	{ 0, 0, SEQUENCE_constraint },
+	asn_MBR_NFCRx_1,
+	2,	/* Elements count */
+	&asn_SPC_NFCRx_specs_1	/* Additional specs */
+};
+

+ 42 - 0
seader/lib/asn1/NFCRx.h

@@ -0,0 +1,42 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#ifndef	_NFCRx_H_
+#define	_NFCRx_H_
+
+
+#include <asn_application.h>
+
+/* Including external dependencies */
+#include <OCTET_STRING.h>
+#include "RfStatus.h"
+#include <constr_SEQUENCE.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* NFCRx */
+typedef struct NFCRx {
+	OCTET_STRING_t	*data	/* OPTIONAL */;
+	RfStatus_t	 rfStatus;
+	
+	/* Context for parsing across buffer boundaries */
+	asn_struct_ctx_t _asn_ctx;
+} NFCRx_t;
+
+/* Implementation */
+extern asn_TYPE_descriptor_t asn_DEF_NFCRx;
+extern asn_SEQUENCE_specifics_t asn_SPC_NFCRx_specs_1;
+extern asn_TYPE_member_t asn_MBR_NFCRx_1[2];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _NFCRx_H_ */
+#include <asn_internal.h>

+ 82 - 0
seader/lib/asn1/NFCSend.c

@@ -0,0 +1,82 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#include "NFCSend.h"
+
+asn_TYPE_member_t asn_MBR_NFCSend_1[] = {
+	{ ATF_NOFLAGS, 0, offsetof(struct NFCSend, data),
+		(ASN_TAG_CLASS_CONTEXT | (0 << 2)),
+		-1,	/* IMPLICIT tag at current level */
+		&asn_DEF_OCTET_STRING,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"data"
+		},
+	{ ATF_NOFLAGS, 0, offsetof(struct NFCSend, protocol),
+		(ASN_TAG_CLASS_CONTEXT | (1 << 2)),
+		-1,	/* IMPLICIT tag at current level */
+		&asn_DEF_Protocol,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"protocol"
+		},
+	{ ATF_NOFLAGS, 0, offsetof(struct NFCSend, timeOut),
+		(ASN_TAG_CLASS_CONTEXT | (2 << 2)),
+		-1,	/* IMPLICIT tag at current level */
+		&asn_DEF_NativeInteger,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"timeOut"
+		},
+	{ ATF_POINTER, 1, offsetof(struct NFCSend, format),
+		(ASN_TAG_CLASS_CONTEXT | (5 << 2)),
+		-1,	/* IMPLICIT tag at current level */
+		&asn_DEF_OCTET_STRING,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"format"
+		},
+};
+static const int asn_MAP_NFCSend_oms_1[] = { 3 };
+static const ber_tlv_tag_t asn_DEF_NFCSend_tags_1[] = {
+	(ASN_TAG_CLASS_UNIVERSAL | (16 << 2))
+};
+static const asn_TYPE_tag2member_t asn_MAP_NFCSend_tag2el_1[] = {
+    { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* data */
+    { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* protocol */
+    { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 }, /* timeOut */
+    { (ASN_TAG_CLASS_CONTEXT | (5 << 2)), 3, 0, 0 } /* format */
+};
+asn_SEQUENCE_specifics_t asn_SPC_NFCSend_specs_1 = {
+	sizeof(struct NFCSend),
+	offsetof(struct NFCSend, _asn_ctx),
+	asn_MAP_NFCSend_tag2el_1,
+	4,	/* Count of tags in the map */
+	asn_MAP_NFCSend_oms_1,	/* Optional members */
+	1, 0,	/* Root/Additions */
+	-1,	/* First extension addition */
+};
+asn_TYPE_descriptor_t asn_DEF_NFCSend = {
+	"NFCSend",
+	"NFCSend",
+	&asn_OP_SEQUENCE,
+	asn_DEF_NFCSend_tags_1,
+	sizeof(asn_DEF_NFCSend_tags_1)
+		/sizeof(asn_DEF_NFCSend_tags_1[0]), /* 1 */
+	asn_DEF_NFCSend_tags_1,	/* Same as above */
+	sizeof(asn_DEF_NFCSend_tags_1)
+		/sizeof(asn_DEF_NFCSend_tags_1[0]), /* 1 */
+	{ 0, 0, SEQUENCE_constraint },
+	asn_MBR_NFCSend_1,
+	4,	/* Elements count */
+	&asn_SPC_NFCSend_specs_1	/* Additional specs */
+};
+

+ 45 - 0
seader/lib/asn1/NFCSend.h

@@ -0,0 +1,45 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#ifndef	_NFCSend_H_
+#define	_NFCSend_H_
+
+
+#include <asn_application.h>
+
+/* Including external dependencies */
+#include <OCTET_STRING.h>
+#include "Protocol.h"
+#include <NativeInteger.h>
+#include <constr_SEQUENCE.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* NFCSend */
+typedef struct NFCSend {
+	OCTET_STRING_t	 data;
+	Protocol_t	 protocol;
+	long	 timeOut;
+	OCTET_STRING_t	*format	/* OPTIONAL */;
+	
+	/* Context for parsing across buffer boundaries */
+	asn_struct_ctx_t _asn_ctx;
+} NFCSend_t;
+
+/* Implementation */
+extern asn_TYPE_descriptor_t asn_DEF_NFCSend;
+extern asn_SEQUENCE_specifics_t asn_SPC_NFCSend_specs_1;
+extern asn_TYPE_member_t asn_MBR_NFCSend_1[4];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _NFCSend_H_ */
+#include <asn_internal.h>

+ 308 - 0
seader/lib/asn1/NULL.c

@@ -0,0 +1,308 @@
+/*-
+ * Copyright (c) 2003, 2005 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <asn_internal.h>
+#include <asn_codecs_prim.h>
+#include <NULL.h>
+
+/*
+ * NULL basic type description.
+ */
+static const ber_tlv_tag_t asn_DEF_NULL_tags[] = {
+	(ASN_TAG_CLASS_UNIVERSAL | (5 << 2))
+};
+asn_TYPE_operation_t asn_OP_NULL = {
+	NULL_free,
+	NULL_print,
+	NULL_compare,
+	NULL_decode_ber,
+	NULL_encode_der,	/* Special handling of DER encoding */
+	NULL_decode_xer,
+	NULL_encode_xer,
+#ifdef	ASN_DISABLE_OER_SUPPORT
+	0,
+	0,
+#else
+	NULL_decode_oer,
+	NULL_encode_oer,
+#endif  /* ASN_DISABLE_OER_SUPPORT */
+#ifdef	ASN_DISABLE_PER_SUPPORT
+	0,
+	0,
+#else
+	NULL_decode_uper,	/* Unaligned PER decoder */
+	NULL_encode_uper,	/* Unaligned PER encoder */
+#endif	/* ASN_DISABLE_PER_SUPPORT */
+	NULL_random_fill,
+	0	/* Use generic outmost tag fetcher */
+};
+asn_TYPE_descriptor_t asn_DEF_NULL = {
+	"NULL",
+	"NULL",
+	&asn_OP_NULL,
+	asn_DEF_NULL_tags,
+	sizeof(asn_DEF_NULL_tags) / sizeof(asn_DEF_NULL_tags[0]),
+	asn_DEF_NULL_tags,	/* Same as above */
+	sizeof(asn_DEF_NULL_tags) / sizeof(asn_DEF_NULL_tags[0]),
+	{ 0, 0, asn_generic_no_constraint },
+	0, 0,	/* No members */
+	0	/* No specifics */
+};
+
+void
+NULL_free(const asn_TYPE_descriptor_t *td, void *ptr,
+          enum asn_struct_free_method method) {
+    if(td && ptr) {
+        switch(method) {
+        case ASFM_FREE_EVERYTHING:
+            FREEMEM(ptr);
+            break;
+        case ASFM_FREE_UNDERLYING:
+            break;
+        case ASFM_FREE_UNDERLYING_AND_RESET:
+            memset(ptr, 0, sizeof(NULL_t));
+            break;
+        }
+    }
+}
+
+/*
+ * Decode NULL type.
+ */
+asn_dec_rval_t
+NULL_decode_ber(const asn_codec_ctx_t *opt_codec_ctx,
+                const asn_TYPE_descriptor_t *td, void **bool_value,
+                const void *buf_ptr, size_t size, int tag_mode) {
+    NULL_t *st = (NULL_t *)*bool_value;
+    asn_dec_rval_t rval;
+    ber_tlv_len_t length;
+
+    if(st == NULL) {
+        st = (NULL_t *)(*bool_value = CALLOC(1, sizeof(*st)));
+        if(st == NULL) {
+            rval.code = RC_FAIL;
+            rval.consumed = 0;
+            return rval;
+        }
+    }
+
+    ASN_DEBUG("Decoding %s as NULL (tm=%d)", td->name, tag_mode);
+
+    /*
+     * Check tags.
+     */
+    rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size, tag_mode, 0,
+                          &length, 0);
+    if(rval.code != RC_OK) {
+        return rval;
+    }
+
+    // X.690-201508, #8.8.2, length shall be zero.
+    if(length != 0) {
+        ASN_DEBUG("Decoding %s as NULL failed: too much data", td->name);
+        rval.code = RC_FAIL;
+        rval.consumed = 0;
+        return rval;
+    }
+
+    return rval;
+}
+
+asn_enc_rval_t
+NULL_encode_der(const asn_TYPE_descriptor_t *td, const void *ptr, int tag_mode,
+                ber_tlv_tag_t tag, asn_app_consume_bytes_f *cb, void *app_key) {
+    asn_enc_rval_t erval;
+
+	erval.encoded = der_write_tags(td, 0, tag_mode, 0, tag, cb, app_key);
+	if(erval.encoded == -1) {
+		erval.failed_type = td;
+		erval.structure_ptr = ptr;
+	}
+
+	ASN__ENCODED_OK(erval);
+}
+
+asn_enc_rval_t
+NULL_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
+                enum xer_encoder_flags_e flags, asn_app_consume_bytes_f *cb,
+                void *app_key) {
+    asn_enc_rval_t er;
+
+	(void)td;
+	(void)sptr;
+	(void)ilevel;
+	(void)flags;
+	(void)cb;
+	(void)app_key;
+
+	/* XMLNullValue is empty */
+	er.encoded = 0;
+	ASN__ENCODED_OK(er);
+}
+
+
+static enum xer_pbd_rval
+NULL__xer_body_decode(const asn_TYPE_descriptor_t *td, void *sptr,
+                      const void *chunk_buf, size_t chunk_size) {
+    (void)td;
+	(void)sptr;
+	(void)chunk_buf;    /* Going to be empty according to the rules below. */
+
+	/*
+	 * There must be no content in self-terminating <NULL/> tag.
+	 */
+	if(chunk_size)
+		return XPBD_BROKEN_ENCODING;
+	else
+		return XPBD_BODY_CONSUMED;
+}
+
+asn_dec_rval_t
+NULL_decode_xer(const asn_codec_ctx_t *opt_codec_ctx,
+                const asn_TYPE_descriptor_t *td, void **sptr,
+                const char *opt_mname, const void *buf_ptr, size_t size) {
+    return xer_decode_primitive(opt_codec_ctx, td,
+		sptr, sizeof(NULL_t), opt_mname, buf_ptr, size,
+		NULL__xer_body_decode);
+}
+
+int
+NULL_compare(const asn_TYPE_descriptor_t *td, const void *a, const void *b) {
+    (void)td;
+    (void)a;
+    (void)b;
+    return 0;
+}
+
+int
+NULL_print(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
+           asn_app_consume_bytes_f *cb, void *app_key) {
+    (void)td;	/* Unused argument */
+	(void)ilevel;	/* Unused argument */
+
+	if(sptr) {
+		return (cb("<present>", 9, app_key) < 0) ? -1 : 0;
+	} else {
+		return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
+	}
+}
+
+#ifndef ASN_DISABLE_OER_SUPPORT
+
+asn_dec_rval_t
+NULL_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
+                const asn_TYPE_descriptor_t *td,
+                const asn_oer_constraints_t *constraints, void **sptr,
+                const void *ptr, size_t size) {
+    asn_dec_rval_t rv = {RC_OK, 0};
+    (void)opt_codec_ctx;
+    (void)td;
+    (void)constraints;
+    (void)ptr;
+    (void)size;
+
+    if(!*sptr) {
+        *sptr = MALLOC(sizeof(NULL_t));
+        if(*sptr) {
+            *(NULL_t *)*sptr = 0;
+        } else {
+            ASN__DECODE_FAILED;
+        }
+    }
+
+    return rv;
+}
+
+asn_enc_rval_t
+NULL_encode_oer(const asn_TYPE_descriptor_t *td,
+                const asn_oer_constraints_t *constraints, const void *sptr,
+                asn_app_consume_bytes_f *cb, void *app_key) {
+    asn_enc_rval_t er;
+
+    (void)td;
+    (void)sptr;
+    (void)constraints;
+    (void)cb;
+    (void)app_key;
+
+    er.encoded = 0; /* Encoding in 0 bytes. */
+
+    ASN__ENCODED_OK(er);
+}
+
+#endif /* ASN_DISABLE_OER_SUPPORT */
+
+#ifndef ASN_DISABLE_PER_SUPPORT
+
+asn_dec_rval_t
+NULL_decode_uper(const asn_codec_ctx_t *opt_codec_ctx,
+                 const asn_TYPE_descriptor_t *td,
+                 const asn_per_constraints_t *constraints, void **sptr,
+                 asn_per_data_t *pd) {
+    asn_dec_rval_t rv;
+
+	(void)opt_codec_ctx;
+	(void)td;
+	(void)constraints;
+	(void)pd;
+
+	if(!*sptr) {
+		*sptr = MALLOC(sizeof(NULL_t));
+		if(*sptr) {
+			*(NULL_t *)*sptr = 0;
+		} else {
+			ASN__DECODE_FAILED;
+		}
+	}
+
+	/*
+	 * NULL type does not have content octets.
+	 */
+
+	rv.code = RC_OK;
+	rv.consumed = 0;
+	return rv;
+}
+
+asn_enc_rval_t
+NULL_encode_uper(const asn_TYPE_descriptor_t *td,
+                 const asn_per_constraints_t *constraints, const void *sptr,
+                 asn_per_outp_t *po) {
+    asn_enc_rval_t er;
+
+	(void)td;
+	(void)constraints;
+	(void)sptr;
+	(void)po;
+
+	er.encoded = 0;
+	ASN__ENCODED_OK(er);
+}
+
+#endif  /* ASN_DISABLE_PER_SUPPORT */
+
+asn_random_fill_result_t
+NULL_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
+                    const asn_encoding_constraints_t *constr,
+                    size_t max_length) {
+    asn_random_fill_result_t result_ok = {ARFILL_OK, 1};
+    asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0};
+    asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};
+    NULL_t *st = *sptr;
+
+    (void)td;
+    (void)constr;
+
+    if(max_length == 0) return result_skipped;
+
+    if(st == NULL) {
+        st = (NULL_t *)(*sptr = CALLOC(1, sizeof(*st)));
+        if(st == NULL) {
+            return result_failed;
+        }
+    }
+
+    return result_ok;
+}
+

+ 42 - 0
seader/lib/asn1/NULL.h

@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 2003-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef	ASN_TYPE_NULL_H
+#define	ASN_TYPE_NULL_H
+
+#include <asn_application.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The value of the NULL type is meaningless.
+ * Use the BOOLEAN type if you need to carry true/false semantics.
+ */
+typedef int NULL_t;
+
+extern asn_TYPE_descriptor_t asn_DEF_NULL;
+extern asn_TYPE_operation_t asn_OP_NULL;
+
+asn_struct_free_f NULL_free;
+asn_struct_print_f NULL_print;
+asn_struct_compare_f NULL_compare;
+ber_type_decoder_f NULL_decode_ber;
+der_type_encoder_f NULL_encode_der;
+xer_type_decoder_f NULL_decode_xer;
+xer_type_encoder_f NULL_encode_xer;
+oer_type_decoder_f NULL_decode_oer;
+oer_type_encoder_f NULL_encode_oer;
+per_type_decoder_f NULL_decode_uper;
+per_type_encoder_f NULL_encode_uper;
+asn_random_fill_f  NULL_random_fill;
+
+#define NULL_constraint	asn_generic_no_constraint
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* NULL_H */

+ 226 - 0
seader/lib/asn1/NativeEnumerated.c

@@ -0,0 +1,226 @@
+/*-
+ * Copyright (c) 2004, 2007 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+/*
+ * Read the NativeInteger.h for the explanation wrt. differences between
+ * INTEGER and NativeInteger.
+ * Basically, both are decoders and encoders of ASN.1 INTEGER type, but this
+ * implementation deals with the standard (machine-specific) representation
+ * of them instead of using the platform-independent buffer.
+ */
+#include <asn_internal.h>
+#include <NativeEnumerated.h>
+
+/*
+ * NativeEnumerated basic type description.
+ */
+static const ber_tlv_tag_t asn_DEF_NativeEnumerated_tags[] = {
+	(ASN_TAG_CLASS_UNIVERSAL | (10 << 2))
+};
+asn_TYPE_operation_t asn_OP_NativeEnumerated = {
+	NativeInteger_free,
+	NativeInteger_print,
+	NativeInteger_compare,
+	NativeInteger_decode_ber,
+	NativeInteger_encode_der,
+	NativeInteger_decode_xer,
+	NativeEnumerated_encode_xer,
+#ifdef	ASN_DISABLE_OER_SUPPORT
+	0,
+	0,
+#else
+	NativeEnumerated_decode_oer,
+	NativeEnumerated_encode_oer,
+#endif  /* ASN_DISABLE_OER_SUPPORT */
+#ifdef	ASN_DISABLE_PER_SUPPORT
+	0,
+	0,
+#else
+	NativeEnumerated_decode_uper,
+	NativeEnumerated_encode_uper,
+#endif	/* ASN_DISABLE_PER_SUPPORT */
+	NativeEnumerated_random_fill,
+	0	/* Use generic outmost tag fetcher */
+};
+asn_TYPE_descriptor_t asn_DEF_NativeEnumerated = {
+	"ENUMERATED",			/* The ASN.1 type is still ENUMERATED */
+	"ENUMERATED",
+	&asn_OP_NativeEnumerated,
+	asn_DEF_NativeEnumerated_tags,
+	sizeof(asn_DEF_NativeEnumerated_tags) / sizeof(asn_DEF_NativeEnumerated_tags[0]),
+	asn_DEF_NativeEnumerated_tags,	/* Same as above */
+	sizeof(asn_DEF_NativeEnumerated_tags) / sizeof(asn_DEF_NativeEnumerated_tags[0]),
+	{ 0, 0, asn_generic_no_constraint },
+	0, 0,	/* No members */
+	0	/* No specifics */
+};
+
+asn_enc_rval_t
+NativeEnumerated_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr,
+                            int ilevel, enum xer_encoder_flags_e flags,
+                            asn_app_consume_bytes_f *cb, void *app_key) {
+    const asn_INTEGER_specifics_t *specs =
+        (const asn_INTEGER_specifics_t *)td->specifics;
+    asn_enc_rval_t er;
+    const long *native = (const long *)sptr;
+    const asn_INTEGER_enum_map_t *el;
+
+    (void)ilevel;
+    (void)flags;
+
+    if(!native) ASN__ENCODE_FAILED;
+
+    el = INTEGER_map_value2enum(specs, *native);
+    if(el) {
+        er.encoded =
+            asn__format_to_callback(cb, app_key, "<%s/>", el->enum_name);
+        if(er.encoded < 0) ASN__ENCODE_FAILED;
+        ASN__ENCODED_OK(er);
+    } else {
+        ASN_DEBUG(
+            "ASN.1 forbids dealing with "
+            "unknown value of ENUMERATED type");
+        ASN__ENCODE_FAILED;
+    }
+}
+
+asn_dec_rval_t
+NativeEnumerated_decode_uper(const asn_codec_ctx_t *opt_codec_ctx,
+                             const asn_TYPE_descriptor_t *td,
+                             const asn_per_constraints_t *constraints,
+                             void **sptr, asn_per_data_t *pd) {
+    const asn_INTEGER_specifics_t *specs = td->specifics;
+    asn_dec_rval_t rval = { RC_OK, 0 };
+	long *native = (long *)*sptr;
+	const asn_per_constraint_t *ct;
+	long value;
+
+	(void)opt_codec_ctx;
+
+	if(constraints) ct = &constraints->value;
+	else if(td->encoding_constraints.per_constraints)
+		ct = &td->encoding_constraints.per_constraints->value;
+	else ASN__DECODE_FAILED;	/* Mandatory! */
+	if(!specs) ASN__DECODE_FAILED;
+
+	if(!native) {
+		native = (long *)(*sptr = CALLOC(1, sizeof(*native)));
+		if(!native) ASN__DECODE_FAILED;
+	}
+
+	ASN_DEBUG("Decoding %s as NativeEnumerated", td->name);
+
+	if(ct->flags & APC_EXTENSIBLE) {
+		int inext = per_get_few_bits(pd, 1);
+		if(inext < 0) ASN__DECODE_STARVED;
+		if(inext) ct = 0;
+	}
+
+	if(ct && ct->range_bits >= 0) {
+		value = per_get_few_bits(pd, ct->range_bits);
+		if(value < 0) ASN__DECODE_STARVED;
+		if(value >= (specs->extension
+			? specs->extension - 1 : specs->map_count))
+			ASN__DECODE_FAILED;
+	} else {
+		if(!specs->extension)
+			ASN__DECODE_FAILED;
+		/*
+		 * X.691, #10.6: normally small non-negative whole number;
+		 */
+		value = uper_get_nsnnwn(pd);
+		if(value < 0) ASN__DECODE_STARVED;
+		value += specs->extension - 1;
+		if(value >= specs->map_count)
+			ASN__DECODE_FAILED;
+	}
+
+	*native = specs->value2enum[value].nat_value;
+	ASN_DEBUG("Decoded %s = %ld", td->name, *native);
+
+	return rval;
+}
+
+static int
+NativeEnumerated__compar_value2enum(const void *ap, const void *bp) {
+	const asn_INTEGER_enum_map_t *a = ap;
+	const asn_INTEGER_enum_map_t *b = bp;
+	if(a->nat_value == b->nat_value)
+		return 0;
+	if(a->nat_value < b->nat_value)
+		return -1;
+	return 1;
+}
+
+asn_enc_rval_t
+NativeEnumerated_encode_uper(const asn_TYPE_descriptor_t *td,
+                             const asn_per_constraints_t *constraints,
+                             const void *sptr, asn_per_outp_t *po) {
+    const asn_INTEGER_specifics_t *specs =
+        (const asn_INTEGER_specifics_t *)td->specifics;
+    asn_enc_rval_t er;
+	long native, value;
+	const asn_per_constraint_t *ct;
+	int inext = 0;
+	asn_INTEGER_enum_map_t key;
+	const asn_INTEGER_enum_map_t *kf;
+
+	if(!sptr) ASN__ENCODE_FAILED;
+	if(!specs) ASN__ENCODE_FAILED;
+
+	if(constraints) ct = &constraints->value;
+	else if(td->encoding_constraints.per_constraints)
+		ct = &td->encoding_constraints.per_constraints->value;
+	else ASN__ENCODE_FAILED;	/* Mandatory! */
+
+	ASN_DEBUG("Encoding %s as NativeEnumerated", td->name);
+
+	er.encoded = 0;
+
+	native = *(const long *)sptr;
+
+	key.nat_value = native;
+	kf = bsearch(&key, specs->value2enum, specs->map_count,
+		sizeof(key), NativeEnumerated__compar_value2enum);
+	if(!kf) {
+		ASN_DEBUG("No element corresponds to %ld", native);
+		ASN__ENCODE_FAILED;
+	}
+	value = kf - specs->value2enum;
+
+	if(ct->range_bits >= 0) {
+		int cmpWith = specs->extension
+				? specs->extension - 1 : specs->map_count;
+		if(value >= cmpWith)
+			inext = 1;
+	}
+	if(ct->flags & APC_EXTENSIBLE) {
+		if(per_put_few_bits(po, inext, 1))
+			ASN__ENCODE_FAILED;
+		if(inext) ct = 0;
+	} else if(inext) {
+		ASN__ENCODE_FAILED;
+	}
+
+	if(ct && ct->range_bits >= 0) {
+		if(per_put_few_bits(po, value, ct->range_bits))
+			ASN__ENCODE_FAILED;
+		ASN__ENCODED_OK(er);
+	}
+
+	if(!specs->extension)
+		ASN__ENCODE_FAILED;
+
+	/*
+	 * X.691, #10.6: normally small non-negative whole number;
+	 */
+	ASN_DEBUG("value = %ld, ext = %d, inext = %d, res = %ld",
+		value, specs->extension, inext,
+		value - (inext ? (specs->extension - 1) : 0));
+	if(uper_put_nsnnwn(po, value - (inext ? (specs->extension - 1) : 0)))
+		ASN__ENCODE_FAILED;
+
+	ASN__ENCODED_OK(er);
+}
+

+ 43 - 0
seader/lib/asn1/NativeEnumerated.h

@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2004-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+/*
+ * This type differs from the standard ENUMERATED in that it is modelled using
+ * the fixed machine type (long, int, short), so it can hold only values of
+ * limited length. There is no type (i.e., NativeEnumerated_t, any integer type
+ * will do).
+ * This type may be used when integer range is limited by subtype constraints.
+ */
+#ifndef	_NativeEnumerated_H_
+#define	_NativeEnumerated_H_
+
+#include <NativeInteger.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern asn_TYPE_descriptor_t asn_DEF_NativeEnumerated;
+extern asn_TYPE_operation_t asn_OP_NativeEnumerated;
+
+xer_type_encoder_f NativeEnumerated_encode_xer;
+oer_type_decoder_f NativeEnumerated_decode_oer;
+oer_type_encoder_f NativeEnumerated_encode_oer;
+per_type_decoder_f NativeEnumerated_decode_uper;
+per_type_encoder_f NativeEnumerated_encode_uper;
+
+#define NativeEnumerated_free       NativeInteger_free
+#define NativeEnumerated_print      NativeInteger_print
+#define NativeEnumerated_compare    NativeInteger_compare
+#define NativeEnumerated_random_fill NativeInteger_random_fill
+#define NativeEnumerated_constraint asn_generic_no_constraint
+#define NativeEnumerated_decode_ber NativeInteger_decode_ber
+#define NativeEnumerated_encode_der NativeInteger_encode_der
+#define NativeEnumerated_decode_xer NativeInteger_decode_xer
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _NativeEnumerated_H_ */

+ 149 - 0
seader/lib/asn1/NativeEnumerated_oer.c

@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>.
+ * All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef ASN_DISABLE_OER_SUPPORT
+
+#include <asn_internal.h>
+#include <NativeEnumerated.h>
+#include <errno.h>
+
+static long
+asn__nativeenumerated_convert(const uint8_t *b, const uint8_t *end) {
+    unsigned long value;
+
+    /* Perform the sign initialization */
+    /* Actually value = -(*b >> 7); gains nothing, yet unreadable! */
+    if((*b >> 7)) {
+        value = (unsigned long)(-1);
+    } else {
+        value = 0;
+    }
+
+    /* Conversion engine */
+    for(; b < end; b++) {
+        value = (value << 8) | *b;
+    }
+
+    return value;
+}
+
+asn_dec_rval_t
+NativeEnumerated_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
+                            const asn_TYPE_descriptor_t *td,
+                            const asn_oer_constraints_t *constraints,
+                            void **nint_ptr, const void *ptr, size_t size) {
+    asn_dec_rval_t rval = {RC_OK, 0};
+    long *native = (long *)*nint_ptr;
+    const uint8_t *b = ptr;
+
+    (void)opt_codec_ctx;
+    (void)constraints;
+
+    if(size < 1) {
+        ASN__DECODE_STARVED;
+    }
+
+    if((*b & 0x80) == 0) {
+        /*
+         * X.696 (08/2015) #11.2 Short form for Enumerated.
+         */
+        if(!native) {
+            native = (long *)(*nint_ptr = CALLOC(1, sizeof(*native)));
+            if(!native) ASN__DECODE_FAILED;
+        }
+
+        *native = *b;
+        rval.consumed = 1;
+    } else {
+        /*
+         * X.696 (08/2015) #11.4 Long form for Enumerated.
+         */
+        size_t length = *b & 0x7f;
+        const uint8_t *bend;
+        long value;
+
+        if(length < 1 || length > sizeof(*native)) {
+            ASN__DECODE_FAILED;
+        }
+        if((1 + length) > size) {
+            ASN__DECODE_STARVED;
+        }
+        b++;
+        bend = b + length;
+
+        value = asn__nativeenumerated_convert(b, bend);
+        if(value < 0) {
+            const asn_INTEGER_specifics_t *specs =
+                (const asn_INTEGER_specifics_t *)td->specifics;
+            if(specs && specs->field_unsigned) {
+                ASN__DECODE_FAILED;
+            }
+        }
+
+        if(!native) {
+            native = (long *)(*nint_ptr = CALLOC(1, sizeof(*native)));
+            if(!native) ASN__DECODE_FAILED;
+        }
+
+        *native = value;
+
+        rval.consumed = (1 + length);
+    }
+
+    return rval;
+}
+
+/*
+ * Encode as Canonical OER.
+ */
+asn_enc_rval_t
+NativeEnumerated_encode_oer(const asn_TYPE_descriptor_t *td,
+                            const asn_oer_constraints_t *constraints,
+                            const void *sptr, asn_app_consume_bytes_f *cb,
+                            void *app_key) {
+    asn_enc_rval_t er;
+    long native;
+
+    (void)constraints;
+
+    if(!sptr) ASN__ENCODE_FAILED;
+
+    native = *(const long *)sptr;
+
+    if(native >= 0 && native <= 127) {
+        /* #11.2 Short form */
+        uint8_t b = native;
+        er.encoded = 1;
+        if(cb(&b, er.encoded, app_key) < 0) {
+            ASN__ENCODE_FAILED;
+        }
+        ASN__ENCODED_OK(er);
+    } else {
+        /* #11.2 Long form */
+        uint8_t buf[1 + sizeof(native)];
+        uint8_t *b = &buf[sizeof(native)];  /* Last addressable */
+        long final_pattern = -1 * (native < 0);
+
+        for(;;) {
+            *b-- = native;
+            native >>= 8;
+            if(native == final_pattern) {
+                if(final_pattern) {
+                    if((b[1] & 0x80)) break;
+                } else {
+                    if(!(b[1] & 0x80)) break;
+                }
+            }
+        }
+        *b = 0x80 | (&buf[sizeof(native)] - b);
+        er.encoded = 1 + (&buf[sizeof(native)] - b);
+        if(cb(b, er.encoded, app_key) < 0) {
+            ASN__ENCODE_FAILED;
+        }
+        ASN__ENCODED_OK(er);
+    }
+}
+
+#endif  /* ASN_DISABLE_OER_SUPPORT */

+ 484 - 0
seader/lib/asn1/NativeInteger.c

@@ -0,0 +1,484 @@
+/*-
+ * Copyright (c) 2004, 2005, 2006 Lev Walkin <vlm@lionet.info>.
+ * All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+/*
+ * Read the NativeInteger.h for the explanation wrt. differences between
+ * INTEGER and NativeInteger.
+ * Basically, both are decoders and encoders of ASN.1 INTEGER type, but this
+ * implementation deals with the standard (machine-specific) representation
+ * of them instead of using the platform-independent buffer.
+ */
+#include <asn_internal.h>
+#include <NativeInteger.h>
+
+/*
+ * NativeInteger basic type description.
+ */
+static const ber_tlv_tag_t asn_DEF_NativeInteger_tags[] = {
+	(ASN_TAG_CLASS_UNIVERSAL | (2 << 2))
+};
+asn_TYPE_operation_t asn_OP_NativeInteger = {
+	NativeInteger_free,
+	NativeInteger_print,
+	NativeInteger_compare,
+	NativeInteger_decode_ber,
+	NativeInteger_encode_der,
+	NativeInteger_decode_xer,
+	NativeInteger_encode_xer,
+#ifdef	ASN_DISABLE_OER_SUPPORT
+	0,
+	0,
+#else
+	NativeInteger_decode_oer,	/* OER decoder */
+	NativeInteger_encode_oer,	/* Canonical OER encoder */
+#endif  /* ASN_DISABLE_OER_SUPPORT */
+#ifdef	ASN_DISABLE_PER_SUPPORT
+	0,
+	0,
+#else
+	NativeInteger_decode_uper,	/* Unaligned PER decoder */
+	NativeInteger_encode_uper,	/* Unaligned PER encoder */
+#endif	/* ASN_DISABLE_PER_SUPPORT */
+	NativeInteger_random_fill,
+	0	/* Use generic outmost tag fetcher */
+};
+asn_TYPE_descriptor_t asn_DEF_NativeInteger = {
+	"INTEGER",			/* The ASN.1 type is still INTEGER */
+	"INTEGER",
+	&asn_OP_NativeInteger,
+	asn_DEF_NativeInteger_tags,
+	sizeof(asn_DEF_NativeInteger_tags) / sizeof(asn_DEF_NativeInteger_tags[0]),
+	asn_DEF_NativeInteger_tags,	/* Same as above */
+	sizeof(asn_DEF_NativeInteger_tags) / sizeof(asn_DEF_NativeInteger_tags[0]),
+	{ 0, 0, asn_generic_no_constraint },
+	0, 0,	/* No members */
+	0	/* No specifics */
+};
+
+/*
+ * Decode INTEGER type.
+ */
+asn_dec_rval_t
+NativeInteger_decode_ber(const asn_codec_ctx_t *opt_codec_ctx,
+                         const asn_TYPE_descriptor_t *td, void **nint_ptr,
+                         const void *buf_ptr, size_t size, int tag_mode) {
+    const asn_INTEGER_specifics_t *specs =
+        (const asn_INTEGER_specifics_t *)td->specifics;
+    long *native = (long *)*nint_ptr;
+	asn_dec_rval_t rval;
+	ber_tlv_len_t length;
+
+	/*
+	 * If the structure is not there, allocate it.
+	 */
+	if(native == NULL) {
+		native = (long *)(*nint_ptr = CALLOC(1, sizeof(*native)));
+		if(native == NULL) {
+			rval.code = RC_FAIL;
+			rval.consumed = 0;
+			return rval;
+		}
+	}
+
+	ASN_DEBUG("Decoding %s as INTEGER (tm=%d)",
+		td->name, tag_mode);
+
+	/*
+	 * Check tags.
+	 */
+	rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size,
+			tag_mode, 0, &length, 0);
+	if(rval.code != RC_OK)
+		return rval;
+
+	ASN_DEBUG("%s length is %d bytes", td->name, (int)length);
+
+	/*
+	 * Make sure we have this length.
+	 */
+	buf_ptr = ((const char *)buf_ptr) + rval.consumed;
+	size -= rval.consumed;
+	if(length > (ber_tlv_len_t)size) {
+		rval.code = RC_WMORE;
+		rval.consumed = 0;
+		return rval;
+	}
+
+	/*
+	 * ASN.1 encoded INTEGER: buf_ptr, length
+	 * Fill the native, at the same time checking for overflow.
+	 * If overflow occurred, return with RC_FAIL.
+	 */
+	{
+		INTEGER_t tmp;
+		union {
+			const void *constbuf;
+			void *nonconstbuf;
+		} unconst_buf;
+		long l;
+
+		unconst_buf.constbuf = buf_ptr;
+		tmp.buf = (uint8_t *)unconst_buf.nonconstbuf;
+		tmp.size = length;
+
+		if((specs&&specs->field_unsigned)
+			? asn_INTEGER2ulong(&tmp, (unsigned long *)&l) /* sic */
+			: asn_INTEGER2long(&tmp, &l)) {
+			rval.code = RC_FAIL;
+			rval.consumed = 0;
+			return rval;
+		}
+
+		*native = l;
+	}
+
+	rval.code = RC_OK;
+	rval.consumed += length;
+
+	ASN_DEBUG("Took %ld/%ld bytes to encode %s (%ld)",
+		(long)rval.consumed, (long)length, td->name, (long)*native);
+
+	return rval;
+}
+
+/*
+ * Encode the NativeInteger using the standard INTEGER type DER encoder.
+ */
+asn_enc_rval_t
+NativeInteger_encode_der(const asn_TYPE_descriptor_t *sd, const void *ptr,
+                         int tag_mode, ber_tlv_tag_t tag,
+                         asn_app_consume_bytes_f *cb, void *app_key) {
+    unsigned long native = *(const unsigned long *)ptr; /* Disable sign ext. */
+    asn_enc_rval_t erval;
+	INTEGER_t tmp;
+
+#ifdef	WORDS_BIGENDIAN		/* Opportunistic optimization */
+
+	tmp.buf = (uint8_t *)&native;
+	tmp.size = sizeof(native);
+
+#else	/* Works even if WORDS_BIGENDIAN is not set where should've been */
+	uint8_t buf[sizeof(native)];
+	uint8_t *p;
+
+	/* Prepare a fake INTEGER */
+	for(p = buf + sizeof(buf) - 1; p >= buf; p--, native >>= 8)
+		*p = (uint8_t)native;
+
+	tmp.buf = buf;
+	tmp.size = sizeof(buf);
+#endif	/* WORDS_BIGENDIAN */
+	
+	/* Encode fake INTEGER */
+	erval = INTEGER_encode_der(sd, &tmp, tag_mode, tag, cb, app_key);
+    if(erval.structure_ptr == &tmp) {
+        erval.structure_ptr = ptr;
+    }
+	return erval;
+}
+
+/*
+ * Decode the chunk of XML text encoding INTEGER.
+ */
+asn_dec_rval_t
+NativeInteger_decode_xer(const asn_codec_ctx_t *opt_codec_ctx,
+                         const asn_TYPE_descriptor_t *td, void **sptr,
+                         const char *opt_mname, const void *buf_ptr,
+                         size_t size) {
+    const asn_INTEGER_specifics_t *specs =
+        (const asn_INTEGER_specifics_t *)td->specifics;
+    asn_dec_rval_t rval;
+	INTEGER_t st;
+	void *st_ptr = (void *)&st;
+	long *native = (long *)*sptr;
+
+	if(!native) {
+		native = (long *)(*sptr = CALLOC(1, sizeof(*native)));
+		if(!native) ASN__DECODE_FAILED;
+	}
+
+	memset(&st, 0, sizeof(st));
+	rval = INTEGER_decode_xer(opt_codec_ctx, td, &st_ptr, 
+		opt_mname, buf_ptr, size);
+	if(rval.code == RC_OK) {
+		long l;
+		if((specs&&specs->field_unsigned)
+			? asn_INTEGER2ulong(&st, (unsigned long *)&l) /* sic */
+			: asn_INTEGER2long(&st, &l)) {
+			rval.code = RC_FAIL;
+			rval.consumed = 0;
+		} else {
+			*native = l;
+		}
+	} else {
+		/*
+		 * Cannot restart from the middle;
+		 * there is no place to save state in the native type.
+		 * Request a continuation from the very beginning.
+		 */
+		rval.consumed = 0;
+	}
+	ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &st);
+	return rval;
+}
+
+
+asn_enc_rval_t
+NativeInteger_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr,
+                         int ilevel, enum xer_encoder_flags_e flags,
+                         asn_app_consume_bytes_f *cb, void *app_key) {
+    const asn_INTEGER_specifics_t *specs =
+        (const asn_INTEGER_specifics_t *)td->specifics;
+    char scratch[32];	/* Enough for 64-bit int */
+	asn_enc_rval_t er;
+	const long *native = (const long *)sptr;
+
+	(void)ilevel;
+	(void)flags;
+
+	if(!native) ASN__ENCODE_FAILED;
+
+	er.encoded = snprintf(scratch, sizeof(scratch),
+			(specs && specs->field_unsigned)
+			? "%lu" : "%ld", *native);
+	if(er.encoded <= 0 || (size_t)er.encoded >= sizeof(scratch)
+		|| cb(scratch, er.encoded, app_key) < 0)
+		ASN__ENCODE_FAILED;
+
+	ASN__ENCODED_OK(er);
+}
+
+#ifndef  ASN_DISABLE_PER_SUPPORT
+
+asn_dec_rval_t
+NativeInteger_decode_uper(const asn_codec_ctx_t *opt_codec_ctx,
+                          const asn_TYPE_descriptor_t *td,
+                          const asn_per_constraints_t *constraints, void **sptr,
+                          asn_per_data_t *pd) {
+    const asn_INTEGER_specifics_t *specs =
+        (const asn_INTEGER_specifics_t *)td->specifics;
+    asn_dec_rval_t rval;
+	long *native = (long *)*sptr;
+	INTEGER_t tmpint;
+	void *tmpintptr = &tmpint;
+
+	(void)opt_codec_ctx;
+	ASN_DEBUG("Decoding NativeInteger %s (UPER)", td->name);
+
+	if(!native) {
+		native = (long *)(*sptr = CALLOC(1, sizeof(*native)));
+		if(!native) ASN__DECODE_FAILED;
+	}
+
+	memset(&tmpint, 0, sizeof tmpint);
+	rval = INTEGER_decode_uper(opt_codec_ctx, td, constraints,
+				   &tmpintptr, pd);
+	if(rval.code == RC_OK) {
+		if((specs&&specs->field_unsigned)
+			? asn_INTEGER2ulong(&tmpint, (unsigned long *)native)
+			: asn_INTEGER2long(&tmpint, native))
+			rval.code = RC_FAIL;
+		else
+			ASN_DEBUG("NativeInteger %s got value %ld",
+				td->name, *native);
+	}
+	ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint);
+
+	return rval;
+}
+
+asn_enc_rval_t
+NativeInteger_encode_uper(const asn_TYPE_descriptor_t *td,
+                          const asn_per_constraints_t *constraints,
+                          const void *sptr, asn_per_outp_t *po) {
+    const asn_INTEGER_specifics_t *specs =
+        (const asn_INTEGER_specifics_t *)td->specifics;
+    asn_enc_rval_t er;
+	long native;
+	INTEGER_t tmpint;
+
+	if(!sptr) ASN__ENCODE_FAILED;
+
+    native = *(const long *)sptr;
+
+    ASN_DEBUG("Encoding NativeInteger %s %ld (UPER)", td->name, native);
+
+	memset(&tmpint, 0, sizeof(tmpint));
+	if((specs&&specs->field_unsigned)
+		? asn_ulong2INTEGER(&tmpint, native)
+		: asn_long2INTEGER(&tmpint, native))
+		ASN__ENCODE_FAILED;
+	er = INTEGER_encode_uper(td, constraints, &tmpint, po);
+	ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint);
+	return er;
+}
+
+#endif  /* ASN_DISABLE_PER_SUPPORT */
+
+/*
+ * INTEGER specific human-readable output.
+ */
+int
+NativeInteger_print(const asn_TYPE_descriptor_t *td, const void *sptr,
+                    int ilevel, asn_app_consume_bytes_f *cb, void *app_key) {
+    const asn_INTEGER_specifics_t *specs =
+        (const asn_INTEGER_specifics_t *)td->specifics;
+    const long *native = (const long *)sptr;
+    char scratch[32]; /* Enough for 64-bit int */
+    int ret;
+
+    (void)td;       /* Unused argument */
+    (void)ilevel;   /* Unused argument */
+
+    if(native) {
+        long value = *native;
+        ret = snprintf(scratch, sizeof(scratch),
+                       (specs && specs->field_unsigned) ? "%lu" : "%ld", value);
+        assert(ret > 0 && (size_t)ret < sizeof(scratch));
+        if(cb(scratch, ret, app_key) < 0) return -1;
+        if(specs && (value >= 0 || !specs->field_unsigned)) {
+            const asn_INTEGER_enum_map_t *el =
+                INTEGER_map_value2enum(specs, value);
+            if(el) {
+                if(cb(" (", 2, app_key) < 0) return -1;
+                if(cb(el->enum_name, el->enum_len, app_key) < 0) return -1;
+                if(cb(")", 1, app_key) < 0) return -1;
+            }
+        }
+        return 0;
+	} else {
+		return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
+	}
+}
+
+void
+NativeInteger_free(const asn_TYPE_descriptor_t *td, void *ptr,
+                   enum asn_struct_free_method method) {
+    if(!td || !ptr)
+		return;
+
+	ASN_DEBUG("Freeing %s as INTEGER (%d, %p, Native)",
+		td->name, method, ptr);
+
+    switch(method) {
+    case ASFM_FREE_EVERYTHING:
+        FREEMEM(ptr);
+        break;
+    case ASFM_FREE_UNDERLYING:
+        break;
+    case ASFM_FREE_UNDERLYING_AND_RESET:
+        memset(ptr, 0, sizeof(long));
+        break;
+    }
+}
+
+int
+NativeInteger_compare(const asn_TYPE_descriptor_t *td, const void *aptr, const void *bptr) {
+    (void)td;
+
+    if(aptr && bptr) {
+        const asn_INTEGER_specifics_t *specs =
+            (const asn_INTEGER_specifics_t *)td->specifics;
+        if(specs && specs->field_unsigned) {
+            const unsigned long *a = aptr;
+            const unsigned long *b = bptr;
+            if(*a < *b) {
+                return -1;
+            } else if(*a > *b) {
+                return 1;
+            } else {
+                return 0;
+            }
+        } else {
+            const long *a = aptr;
+            const long *b = bptr;
+            if(*a < *b) {
+                return -1;
+            } else if(*a > *b) {
+                return 1;
+            } else {
+                return 0;
+            }
+        }
+    } else if(!aptr) {
+        return -1;
+    } else {
+        return 1;
+    }
+}
+
+asn_random_fill_result_t
+NativeInteger_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
+                          const asn_encoding_constraints_t *constraints,
+                          size_t max_length) {
+    const asn_INTEGER_specifics_t *specs =
+        (const asn_INTEGER_specifics_t *)td->specifics;
+    asn_random_fill_result_t result_ok = {ARFILL_OK, 1};
+    asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0};
+    asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};
+    long *st = *sptr;
+    const asn_INTEGER_enum_map_t *emap;
+    size_t emap_len;
+    intmax_t value;
+    int find_inside_map;
+
+    if(max_length == 0) return result_skipped;
+
+    if(st == NULL) {
+        st = (long *)CALLOC(1, sizeof(*st));
+        if(st == NULL) {
+            return result_failed;
+        }
+    }
+
+    if(specs) {
+        emap = specs->value2enum;
+        emap_len = specs->map_count;
+        if(specs->strict_enumeration) {
+            find_inside_map = emap_len > 0;
+        } else {
+            find_inside_map = emap_len ? asn_random_between(0, 1) : 0;
+        }
+    } else {
+        emap = 0;
+        emap_len = 0;
+        find_inside_map = 0;
+    }
+
+    if(find_inside_map) {
+        assert(emap_len > 0);
+        value = emap[asn_random_between(0, emap_len - 1)].nat_value;
+    } else {
+        const asn_per_constraints_t *ct;
+
+        static const long variants[] = {
+            -65536, -65535, -65534, -32769, -32768, -32767, -16385, -16384,
+            -16383, -257,   -256,   -255,   -254,   -129,   -128,   -127,
+            -126,   -1,     0,      1,      126,    127,    128,    129,
+            254,    255,    256,    257,    16383,  16384,  16385,  32767,
+            32768,  32769,  65534,  65535,  65536,  65537};
+        if(specs && specs->field_unsigned) {
+            assert(variants[18] == 0);
+            value = variants[asn_random_between(
+                18, sizeof(variants) / sizeof(variants[0]) - 1)];
+        } else {
+            value = variants[asn_random_between(
+                0, sizeof(variants) / sizeof(variants[0]) - 1)];
+        }
+
+        if(!constraints) constraints = &td->encoding_constraints;
+        ct = constraints ? constraints->per_constraints : 0;
+        if(ct && (ct->value.flags & APC_CONSTRAINED)) {
+            if(value < ct->value.lower_bound || value > ct->value.upper_bound) {
+                value = asn_random_between(ct->value.lower_bound,
+                                           ct->value.upper_bound);
+            }
+        }
+    }
+
+    *sptr = st;
+    *st = value;
+    return result_ok;
+}

+ 44 - 0
seader/lib/asn1/NativeInteger.h

@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 2004-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+/*
+ * This type differs from the standard INTEGER in that it is modelled using
+ * the fixed machine type (long, int, short), so it can hold only values of
+ * limited length. There is no type (i.e., NativeInteger_t, any integer type
+ * will do).
+ * This type may be used when integer range is limited by subtype constraints.
+ */
+#ifndef	_NativeInteger_H_
+#define	_NativeInteger_H_
+
+#include <asn_application.h>
+#include <INTEGER.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern asn_TYPE_descriptor_t asn_DEF_NativeInteger;
+extern asn_TYPE_operation_t asn_OP_NativeInteger;
+
+asn_struct_free_f  NativeInteger_free;
+asn_struct_print_f NativeInteger_print;
+asn_struct_compare_f NativeInteger_compare;
+ber_type_decoder_f NativeInteger_decode_ber;
+der_type_encoder_f NativeInteger_encode_der;
+xer_type_decoder_f NativeInteger_decode_xer;
+xer_type_encoder_f NativeInteger_encode_xer;
+oer_type_decoder_f NativeInteger_decode_oer;
+oer_type_encoder_f NativeInteger_encode_oer;
+per_type_decoder_f NativeInteger_decode_uper;
+per_type_encoder_f NativeInteger_encode_uper;
+asn_random_fill_f  NativeInteger_random_fill;
+
+#define NativeInteger_constraint  asn_generic_no_constraint
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _NativeInteger_H_ */

+ 99 - 0
seader/lib/asn1/NativeInteger_oer.c

@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>.
+ * All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef ASN_DISABLE_OER_SUPPORT
+
+#include <asn_internal.h>
+#include <NativeInteger.h>
+#include <errno.h>
+
+asn_dec_rval_t
+NativeInteger_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
+                         const asn_TYPE_descriptor_t *td,
+                         const asn_oer_constraints_t *constraints,
+                         void **nint_ptr, const void *ptr, size_t size) {
+    const asn_INTEGER_specifics_t *specs =
+        (const asn_INTEGER_specifics_t *)td->specifics;
+    asn_dec_rval_t rval = {RC_OK, 0};
+    long *native = (long *)*nint_ptr;
+    INTEGER_t tmpint;
+    INTEGER_t *tmpintptr = &tmpint;
+
+    memset(&tmpint, 0, sizeof(tmpint));
+
+    if(!native) {
+        native = (long *)(*nint_ptr = CALLOC(1, sizeof(*native)));
+        if(!native) ASN__DECODE_FAILED;
+    }
+
+    /*
+     * OPTIMIZATION: Encode directly rather than passing through INTEGER.
+     * Saves a memory allocation.
+     */
+    rval = INTEGER_decode_oer(opt_codec_ctx, td, constraints,
+                              (void **)&tmpintptr, ptr, size);
+    if(rval.code != RC_OK) {
+        ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint);
+        return rval;
+    }
+
+    if(specs && specs->field_unsigned) {
+        unsigned long ul;
+        int ok = asn_INTEGER2ulong(&tmpint, &ul) == 0;
+        ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint);
+        if(ok) {
+            *native = ul;
+        } else {
+            rval.code = RC_FAIL;
+            return rval;
+        }
+    } else {
+        long l;
+        int ok = asn_INTEGER2long(&tmpint, &l) == 0;
+        ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint);
+        if(ok) {
+            *native = l;
+        } else {
+            rval.code = RC_FAIL;
+            return rval;
+        }
+    }
+
+    return rval;
+}
+
+/*
+ * Encode as Canonical OER.
+ */
+asn_enc_rval_t
+NativeInteger_encode_oer(const asn_TYPE_descriptor_t *td,
+                         const asn_oer_constraints_t *constraints,
+                         const void *sptr, asn_app_consume_bytes_f *cb,
+                         void *app_key) {
+    const asn_INTEGER_specifics_t *specs =
+        (const asn_INTEGER_specifics_t *)td->specifics;
+    INTEGER_t tmpint;
+    long native;
+
+    if(!sptr) ASN__ENCODE_FAILED;
+
+    native = *(const long *)sptr;
+    memset(&tmpint, 0, sizeof(tmpint));
+
+    ASN_DEBUG("Encoding %s %ld as NativeInteger", td ? td->name : "", native);
+
+    if((specs && specs->field_unsigned) ? asn_ulong2INTEGER(&tmpint, native)
+                                        : asn_long2INTEGER(&tmpint, native)) {
+        ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint);
+        ASN__ENCODE_FAILED;
+    } else {
+        asn_enc_rval_t er =
+            INTEGER_encode_oer(td, constraints, &tmpint, cb, app_key);
+        ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint);
+        return er;
+    }
+}
+
+#endif  /* ASN_DISABLE_OER_SUPPORT */

+ 2043 - 0
seader/lib/asn1/OCTET_STRING.c

@@ -0,0 +1,2043 @@
+/*-
+ * Copyright (c) 2003-2017 Lev Walkin <vlm@lionet.info>.
+ * All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <asn_internal.h>
+#include <OCTET_STRING.h>
+#include <BIT_STRING.h>	/* for .bits_unused member */
+#include <errno.h>
+
+/*
+ * OCTET STRING basic type description.
+ */
+static const ber_tlv_tag_t asn_DEF_OCTET_STRING_tags[] = {
+	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))
+};
+asn_OCTET_STRING_specifics_t asn_SPC_OCTET_STRING_specs = {
+	sizeof(OCTET_STRING_t),
+	offsetof(OCTET_STRING_t, _asn_ctx),
+	ASN_OSUBV_STR
+};
+
+asn_TYPE_operation_t asn_OP_OCTET_STRING = {
+	OCTET_STRING_free,
+	OCTET_STRING_print,	/* OCTET STRING generally means a non-ascii sequence */
+	OCTET_STRING_compare,
+	OCTET_STRING_decode_ber,
+	OCTET_STRING_encode_der,
+	OCTET_STRING_decode_xer_hex,
+	OCTET_STRING_encode_xer,
+#ifdef	ASN_DISABLE_OER_SUPPORT
+	0,
+	0,
+#else
+	OCTET_STRING_decode_oer,
+	OCTET_STRING_encode_oer,
+#endif  /* ASN_DISABLE_OER_SUPPORT */
+#ifdef	ASN_DISABLE_PER_SUPPORT
+	0,
+	0,
+#else
+	OCTET_STRING_decode_uper,	/* Unaligned PER decoder */
+	OCTET_STRING_encode_uper,	/* Unaligned PER encoder */
+#endif	/* ASN_DISABLE_PER_SUPPORT */
+	OCTET_STRING_random_fill,
+	0	/* Use generic outmost tag fetcher */
+};
+asn_TYPE_descriptor_t asn_DEF_OCTET_STRING = {
+	"OCTET STRING",		/* Canonical name */
+	"OCTET_STRING",		/* XML tag name */
+	&asn_OP_OCTET_STRING,
+	asn_DEF_OCTET_STRING_tags,
+	sizeof(asn_DEF_OCTET_STRING_tags)
+	  / sizeof(asn_DEF_OCTET_STRING_tags[0]),
+	asn_DEF_OCTET_STRING_tags,	/* Same as above */
+	sizeof(asn_DEF_OCTET_STRING_tags)
+	  / sizeof(asn_DEF_OCTET_STRING_tags[0]),
+	{ 0, 0, asn_generic_no_constraint },
+	0, 0,	/* No members */
+	&asn_SPC_OCTET_STRING_specs
+};
+
+#undef	_CH_PHASE
+#undef	NEXT_PHASE
+#undef	PREV_PHASE
+#define	_CH_PHASE(ctx, inc) do {					\
+		if(ctx->phase == 0)					\
+			ctx->context = 0;				\
+		ctx->phase += inc;					\
+	} while(0)
+#define	NEXT_PHASE(ctx)	_CH_PHASE(ctx, +1)
+#define	PREV_PHASE(ctx)	_CH_PHASE(ctx, -1)
+
+#undef	ADVANCE
+#define	ADVANCE(num_bytes)	do {					\
+		size_t num = (num_bytes);				\
+		buf_ptr = ((const char *)buf_ptr) + num;		\
+		size -= num;						\
+		consumed_myself += num;					\
+	} while(0)
+
+#undef	RETURN
+#define	RETURN(_code)	do {						\
+		asn_dec_rval_t tmprval;					\
+		tmprval.code = _code;					\
+		tmprval.consumed = consumed_myself;			\
+		return tmprval;						\
+	} while(0)
+
+#undef	APPEND
+#define	APPEND(bufptr, bufsize)	do {					\
+		size_t _bs = (bufsize);		/* Append size */	\
+		size_t _ns = ctx->context;	/* Allocated now */	\
+		size_t _es = st->size + _bs;	/* Expected size */	\
+		/* int is really a typeof(st->size): */			\
+		if((int)_es < 0) RETURN(RC_FAIL);			\
+		if(_ns <= _es) {					\
+			void *ptr;					\
+			/* Be nice and round to the memory allocator */	\
+			do { _ns = _ns ? _ns << 1 : 16; }		\
+			    while(_ns <= _es);				\
+			/* int is really a typeof(st->size): */		\
+			if((int)_ns < 0) RETURN(RC_FAIL);		\
+			ptr = REALLOC(st->buf, _ns);			\
+			if(ptr) {					\
+				st->buf = (uint8_t *)ptr;		\
+				ctx->context = _ns;			\
+			} else {					\
+				RETURN(RC_FAIL);			\
+			}						\
+			ASN_DEBUG("Reallocating into %ld", (long)_ns);	\
+		}							\
+		memcpy(st->buf + st->size, bufptr, _bs);		\
+		/* Convenient nul-termination */			\
+		st->buf[_es] = '\0';					\
+		st->size = _es;						\
+	} while(0)
+
+/*
+ * The main reason why ASN.1 is still alive is that too much time and effort
+ * is necessary for learning it more or less adequately, thus creating a gut
+ * necessity to demonstrate that aquired skill everywhere afterwards.
+ * No, I am not going to explain what the following stuff is.
+ */
+struct _stack_el {
+    ber_tlv_len_t left;     /* What's left to read (or -1) */
+    ber_tlv_len_t got;      /* What was actually processed */
+    unsigned cont_level;    /* Depth of subcontainment */
+    int want_nulls;         /* Want null "end of content" octets? */
+    int bits_chopped;       /* Flag in BIT STRING mode */
+    ber_tlv_tag_t tag;      /* For debugging purposes */
+    struct _stack_el *prev;
+    struct _stack_el *next;
+};
+struct _stack {
+	struct _stack_el *tail;
+	struct _stack_el *cur_ptr;
+};
+
+static struct _stack_el *
+OS__add_stack_el(struct _stack *st) {
+	struct _stack_el *nel;
+
+	/*
+	 * Reuse the old stack frame or allocate a new one.
+	 */
+	if(st->cur_ptr && st->cur_ptr->next) {
+		nel = st->cur_ptr->next;
+		nel->bits_chopped = 0;
+		nel->got = 0;
+		/* Retain the nel->cont_level, it's correct. */
+	} else {
+		nel = (struct _stack_el *)CALLOC(1, sizeof(struct _stack_el));
+		if(nel == NULL)
+			return NULL;
+	
+		if(st->tail) {
+			/* Increase a subcontainment depth */
+			nel->cont_level = st->tail->cont_level + 1;
+			st->tail->next = nel;
+		}
+		nel->prev = st->tail;
+		st->tail = nel;
+	}
+
+	st->cur_ptr = nel;
+
+	return nel;
+}
+
+static struct _stack *
+_new_stack(void) {
+	return (struct _stack *)CALLOC(1, sizeof(struct _stack));
+}
+
+/*
+ * Decode OCTET STRING type.
+ */
+asn_dec_rval_t
+OCTET_STRING_decode_ber(const asn_codec_ctx_t *opt_codec_ctx,
+                        const asn_TYPE_descriptor_t *td, void **sptr,
+                        const void *buf_ptr, size_t size, int tag_mode) {
+    const asn_OCTET_STRING_specifics_t *specs = td->specifics
+				? (const asn_OCTET_STRING_specifics_t *)td->specifics
+				: &asn_SPC_OCTET_STRING_specs;
+	BIT_STRING_t *st = (BIT_STRING_t *)*sptr;
+	asn_dec_rval_t rval;
+	asn_struct_ctx_t *ctx;
+	ssize_t consumed_myself = 0;
+	struct _stack *stck;		/* Expectations stack structure */
+	struct _stack_el *sel = 0;	/* Stack element */
+	int tlv_constr;
+	enum asn_OS_Subvariant type_variant = specs->subvariant;
+
+	ASN_DEBUG("Decoding %s as %s (frame %ld)",
+		td->name,
+		(type_variant == ASN_OSUBV_STR) ?
+			"OCTET STRING" : "OS-SpecialCase",
+		(long)size);
+
+	/*
+	 * Create the string if does not exist.
+	 */
+	if(st == NULL) {
+		st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size));
+		if(st == NULL) RETURN(RC_FAIL);
+	}
+
+	/* Restore parsing context */
+	ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);
+
+	switch(ctx->phase) {
+	case 0:
+		/*
+		 * Check tags.
+		 */
+		rval = ber_check_tags(opt_codec_ctx, td, ctx,
+			buf_ptr, size, tag_mode, -1,
+			&ctx->left, &tlv_constr);
+		if(rval.code != RC_OK)
+			return rval;
+
+		if(tlv_constr) {
+			/*
+			 * Complex operation, requires stack of expectations.
+			 */
+			ctx->ptr = _new_stack();
+			if(!ctx->ptr) {
+				RETURN(RC_FAIL);
+			}
+		} else {
+			/*
+			 * Jump into stackless primitive decoding.
+			 */
+			_CH_PHASE(ctx, 3);
+			if(type_variant == ASN_OSUBV_ANY && tag_mode != 1)
+				APPEND(buf_ptr, rval.consumed);
+			ADVANCE(rval.consumed);
+			goto phase3;
+		}
+
+		NEXT_PHASE(ctx);
+		/* Fall through */
+	case 1:
+	phase1:
+		/*
+		 * Fill the stack with expectations.
+		 */
+		stck = (struct _stack *)ctx->ptr;
+		sel = stck->cur_ptr;
+	  do {
+		ber_tlv_tag_t tlv_tag;
+		ber_tlv_len_t tlv_len;
+		ber_tlv_tag_t expected_tag;
+		ssize_t tl, ll, tlvl;
+				/* This one works even if (sel->left == -1) */
+		size_t Left = ((!sel||(size_t)sel->left >= size)
+					?size:(size_t)sel->left);
+
+
+		ASN_DEBUG("%p, s->l=%ld, s->wn=%ld, s->g=%ld\n", (void *)sel,
+			(long)(sel?sel->left:0),
+			(long)(sel?sel->want_nulls:0),
+			(long)(sel?sel->got:0)
+		);
+		if(sel && sel->left <= 0 && sel->want_nulls == 0) {
+			if(sel->prev) {
+				struct _stack_el *prev = sel->prev;
+				if(prev->left != -1) {
+					if(prev->left < sel->got)
+						RETURN(RC_FAIL);
+					prev->left -= sel->got;
+				}
+				prev->got += sel->got;
+				sel = stck->cur_ptr = prev;
+				if(!sel) break;
+				tlv_constr = 1;
+				continue;
+			} else {
+				sel = stck->cur_ptr = 0;
+				break;	/* Nothing to wait */
+			}
+		}
+
+		tl = ber_fetch_tag(buf_ptr, Left, &tlv_tag);
+		ASN_DEBUG("fetch tag(size=%ld,L=%ld), %sstack, left=%ld, wn=%ld, tl=%ld",
+			(long)size, (long)Left, sel?"":"!",
+			(long)(sel?sel->left:0),
+			(long)(sel?sel->want_nulls:0),
+			(long)tl);
+		switch(tl) {
+		case -1: RETURN(RC_FAIL);
+		case 0: RETURN(RC_WMORE);
+		}
+
+		tlv_constr = BER_TLV_CONSTRUCTED(buf_ptr);
+
+		ll = ber_fetch_length(tlv_constr,
+				(const char *)buf_ptr + tl,Left - tl,&tlv_len);
+		ASN_DEBUG("Got tag=%s, tc=%d, left=%ld, tl=%ld, len=%ld, ll=%ld",
+			ber_tlv_tag_string(tlv_tag), tlv_constr,
+				(long)Left, (long)tl, (long)tlv_len, (long)ll);
+		switch(ll) {
+		case -1: RETURN(RC_FAIL);
+		case 0: RETURN(RC_WMORE);
+		}
+
+		if(sel && sel->want_nulls
+			&& ((const uint8_t *)buf_ptr)[0] == 0
+			&& ((const uint8_t *)buf_ptr)[1] == 0)
+		{
+
+			ASN_DEBUG("Eat EOC; wn=%d--", sel->want_nulls);
+
+			if(type_variant == ASN_OSUBV_ANY
+			&& (tag_mode != 1 || sel->cont_level))
+				APPEND("\0\0", 2);
+
+			ADVANCE(2);
+			sel->got += 2;
+			if(sel->left != -1) {
+				sel->left -= 2;	/* assert(sel->left >= 2) */
+			}
+
+			sel->want_nulls--;
+			if(sel->want_nulls == 0) {
+				/* Move to the next expectation */
+				sel->left = 0;
+				tlv_constr = 1;
+			}
+
+			continue;
+		}
+
+		/*
+		 * Set up expected tags,
+		 * depending on ASN.1 type being decoded.
+		 */
+		switch(type_variant) {
+		case ASN_OSUBV_BIT:
+			/* X.690: 8.6.4.1, NOTE 2 */
+			/* Fall through */
+		case ASN_OSUBV_STR:
+		default:
+			if(sel) {
+				unsigned level = sel->cont_level;
+				if(level < td->all_tags_count) {
+					expected_tag = td->all_tags[level];
+					break;
+				} else if(td->all_tags_count) {
+					expected_tag = td->all_tags
+						[td->all_tags_count - 1];
+					break;
+				}
+				/* else, Fall through */
+			}
+			/* Fall through */
+		case ASN_OSUBV_ANY:
+			expected_tag = tlv_tag;
+			break;
+		}
+
+
+		if(tlv_tag != expected_tag) {
+			char buf[2][32];
+			ber_tlv_tag_snprint(tlv_tag,
+				buf[0], sizeof(buf[0]));
+			ber_tlv_tag_snprint(td->tags[td->tags_count-1],
+				buf[1], sizeof(buf[1]));
+			ASN_DEBUG("Tag does not match expectation: %s != %s",
+				buf[0], buf[1]);
+			RETURN(RC_FAIL);
+		}
+
+		tlvl = tl + ll;	/* Combined length of T and L encoding */
+		if((tlv_len + tlvl) < 0) {
+			/* tlv_len value is too big */
+			ASN_DEBUG("TLV encoding + length (%ld) is too big",
+				(long)tlv_len);
+			RETURN(RC_FAIL);
+		}
+
+		/*
+		 * Append a new expectation.
+		 */
+		sel = OS__add_stack_el(stck);
+		if(!sel) RETURN(RC_FAIL);
+
+		sel->tag = tlv_tag;
+
+		sel->want_nulls = (tlv_len==-1);
+		if(sel->prev && sel->prev->left != -1) {
+			/* Check that the parent frame is big enough */
+			if(sel->prev->left < tlvl + (tlv_len==-1?0:tlv_len))
+				RETURN(RC_FAIL);
+			if(tlv_len == -1)
+				sel->left = sel->prev->left - tlvl;
+			else
+				sel->left = tlv_len;
+		} else {
+			sel->left = tlv_len;
+		}
+		if(type_variant == ASN_OSUBV_ANY
+		&& (tag_mode != 1 || sel->cont_level))
+			APPEND(buf_ptr, tlvl);
+		sel->got += tlvl;
+		ADVANCE(tlvl);
+
+		ASN_DEBUG("+EXPECT2 got=%ld left=%ld, wn=%d, clvl=%u",
+			(long)sel->got, (long)sel->left,
+			sel->want_nulls, sel->cont_level);
+
+	  } while(tlv_constr);
+		if(sel == NULL) {
+			/* Finished operation, "phase out" */
+			ASN_DEBUG("Phase out");
+			_CH_PHASE(ctx, +3);
+			break;
+		}
+
+		NEXT_PHASE(ctx);
+		/* Fall through */
+	case 2:
+		stck = (struct _stack *)ctx->ptr;
+		sel = stck->cur_ptr;
+		ASN_DEBUG("Phase 2: Need %ld bytes, size=%ld, alrg=%ld, wn=%d",
+			(long)sel->left, (long)size, (long)sel->got,
+				sel->want_nulls);
+	    {
+		ber_tlv_len_t len;
+
+		assert(sel->left >= 0);
+
+		len = ((ber_tlv_len_t)size < sel->left)
+				? (ber_tlv_len_t)size : sel->left;
+		if(len > 0) {
+			if(type_variant == ASN_OSUBV_BIT
+			&& sel->bits_chopped == 0) {
+				/* Put the unused-bits-octet away */
+				st->bits_unused = *(const uint8_t *)buf_ptr;
+				APPEND(((const char *)buf_ptr+1), (len - 1));
+				sel->bits_chopped = 1;
+			} else {
+				APPEND(buf_ptr, len);
+			}
+			ADVANCE(len);
+			sel->left -= len;
+			sel->got += len;
+		}
+
+		if(sel->left) {
+			ASN_DEBUG("OS left %ld, size = %ld, wn=%d\n",
+				(long)sel->left, (long)size, sel->want_nulls);
+			RETURN(RC_WMORE);
+		}
+
+		PREV_PHASE(ctx);
+		goto phase1;
+	    }
+		break;
+	case 3:
+	phase3:
+		/*
+		 * Primitive form, no stack required.
+		 */
+		assert(ctx->left >= 0);
+
+		if(size < (size_t)ctx->left) {
+			if(!size) RETURN(RC_WMORE);
+			if(type_variant == ASN_OSUBV_BIT && !ctx->context) {
+				st->bits_unused = *(const uint8_t *)buf_ptr;
+				ctx->left--;
+				ADVANCE(1);
+			}
+			APPEND(buf_ptr, size);
+			assert(ctx->context > 0);
+			ctx->left -= size;
+			ADVANCE(size);
+			RETURN(RC_WMORE);
+		} else {
+			if(type_variant == ASN_OSUBV_BIT
+			&& !ctx->context && ctx->left) {
+				st->bits_unused = *(const uint8_t *)buf_ptr;
+				ctx->left--;
+				ADVANCE(1);
+			}
+			APPEND(buf_ptr, ctx->left);
+			ADVANCE(ctx->left);
+			ctx->left = 0;
+
+			NEXT_PHASE(ctx);
+		}
+		break;
+	}
+
+	if(sel) {
+		ASN_DEBUG("3sel p=%p, wn=%d, l=%ld, g=%ld, size=%ld",
+			(void *)sel->prev, sel->want_nulls,
+			(long)sel->left, (long)sel->got, (long)size);
+		if(sel->prev || sel->want_nulls > 1 || sel->left > 0) {
+			RETURN(RC_WMORE);
+		}
+	}
+
+	/*
+	 * BIT STRING-specific processing.
+	 */
+	if(type_variant == ASN_OSUBV_BIT) {
+        if(st->size) {
+			if(st->bits_unused < 0 || st->bits_unused > 7) {
+				RETURN(RC_FAIL);
+			}
+			/* Finalize BIT STRING: zero out unused bits. */
+			st->buf[st->size-1] &= 0xff << st->bits_unused;
+		} else {
+			if(st->bits_unused) {
+				RETURN(RC_FAIL);
+			}
+		}
+	}
+
+	ASN_DEBUG("Took %ld bytes to encode %s: [%s]:%ld",
+		(long)consumed_myself, td->name,
+		(type_variant == ASN_OSUBV_STR) ? (char *)st->buf : "<data>",
+		(long)st->size);
+
+
+	RETURN(RC_OK);
+}
+
+/*
+ * Encode OCTET STRING type using DER.
+ */
+asn_enc_rval_t
+OCTET_STRING_encode_der(const asn_TYPE_descriptor_t *td, const void *sptr,
+                        int tag_mode, ber_tlv_tag_t tag,
+                        asn_app_consume_bytes_f *cb, void *app_key) {
+    asn_enc_rval_t er;
+	const asn_OCTET_STRING_specifics_t *specs = td->specifics
+				? (const asn_OCTET_STRING_specifics_t *)td->specifics
+				: &asn_SPC_OCTET_STRING_specs;
+	const BIT_STRING_t *st = (const BIT_STRING_t *)sptr;
+	enum asn_OS_Subvariant type_variant = specs->subvariant;
+	int fix_last_byte = 0;
+
+	ASN_DEBUG("%s %s as OCTET STRING",
+		cb?"Estimating":"Encoding", td->name);
+
+	/*
+	 * Write tags.
+	 */
+	if(type_variant != ASN_OSUBV_ANY || tag_mode == 1) {
+		er.encoded = der_write_tags(td,
+				(type_variant == ASN_OSUBV_BIT) + st->size,
+			tag_mode, type_variant == ASN_OSUBV_ANY, tag,
+			cb, app_key);
+		if(er.encoded == -1) {
+			er.failed_type = td;
+			er.structure_ptr = sptr;
+			return er;
+		}
+	} else {
+		/* Disallow: [<tag>] IMPLICIT ANY */
+		assert(type_variant != ASN_OSUBV_ANY || tag_mode != -1);
+		er.encoded = 0;
+	}
+
+	if(!cb) {
+		er.encoded += (type_variant == ASN_OSUBV_BIT) + st->size;
+		ASN__ENCODED_OK(er);
+	}
+
+	/*
+	 * Prepare to deal with the last octet of BIT STRING.
+	 */
+	if(type_variant == ASN_OSUBV_BIT) {
+		uint8_t b = st->bits_unused & 0x07;
+		if(b && st->size) fix_last_byte = 1;
+		ASN__CALLBACK(&b, 1);
+	}
+
+	/* Invoke callback for the main part of the buffer */
+	ASN__CALLBACK(st->buf, st->size - fix_last_byte);
+
+	/* The last octet should be stripped off the unused bits */
+	if(fix_last_byte) {
+		uint8_t b = st->buf[st->size-1] & (0xff << st->bits_unused);
+		ASN__CALLBACK(&b, 1);
+	}
+
+	ASN__ENCODED_OK(er);
+cb_failed:
+	ASN__ENCODE_FAILED;
+}
+
+asn_enc_rval_t
+OCTET_STRING_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr,
+                        int ilevel, enum xer_encoder_flags_e flags,
+                        asn_app_consume_bytes_f *cb, void *app_key) {
+    const char * const h2c = "0123456789ABCDEF";
+	const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
+	asn_enc_rval_t er;
+	char scratch[16 * 3 + 4];
+	char *p = scratch;
+	uint8_t *buf;
+	uint8_t *end;
+	size_t i;
+
+	if(!st || (!st->buf && st->size))
+		ASN__ENCODE_FAILED;
+
+	er.encoded = 0;
+
+	/*
+	 * Dump the contents of the buffer in hexadecimal.
+	 */
+	buf = st->buf;
+	end = buf + st->size;
+	if(flags & XER_F_CANONICAL) {
+		char *scend = scratch + (sizeof(scratch) - 2);
+		for(; buf < end; buf++) {
+			if(p >= scend) {
+				ASN__CALLBACK(scratch, p - scratch);
+				p = scratch;
+			}
+			*p++ = h2c[(*buf >> 4) & 0x0F];
+			*p++ = h2c[*buf & 0x0F];
+		}
+
+		ASN__CALLBACK(scratch, p-scratch);	/* Dump the rest */
+	} else {
+		for(i = 0; buf < end; buf++, i++) {
+			if(!(i % 16) && (i || st->size > 16)) {
+				ASN__CALLBACK(scratch, p-scratch);
+				p = scratch;
+				ASN__TEXT_INDENT(1, ilevel);
+			}
+			*p++ = h2c[(*buf >> 4) & 0x0F];
+			*p++ = h2c[*buf & 0x0F];
+			*p++ = 0x20;
+		}
+		if(p - scratch) {
+			p--;	/* Remove the tail space */
+			ASN__CALLBACK(scratch, p-scratch); /* Dump the rest */
+			if(st->size > 16)
+				ASN__TEXT_INDENT(1, ilevel-1);
+		}
+	}
+
+	ASN__ENCODED_OK(er);
+cb_failed:
+	ASN__ENCODE_FAILED;
+}
+
+static const struct OCTET_STRING__xer_escape_table_s {
+	const char *string;
+	int size;
+} OCTET_STRING__xer_escape_table[] = {
+#define	OSXET(s)	{ s, sizeof(s) - 1 }
+	OSXET("\074\156\165\154\057\076"),	/* <nul/> */
+	OSXET("\074\163\157\150\057\076"),	/* <soh/> */
+	OSXET("\074\163\164\170\057\076"),	/* <stx/> */
+	OSXET("\074\145\164\170\057\076"),	/* <etx/> */
+	OSXET("\074\145\157\164\057\076"),	/* <eot/> */
+	OSXET("\074\145\156\161\057\076"),	/* <enq/> */
+	OSXET("\074\141\143\153\057\076"),	/* <ack/> */
+	OSXET("\074\142\145\154\057\076"),	/* <bel/> */
+	OSXET("\074\142\163\057\076"),		/* <bs/> */
+	OSXET("\011"),				/* \t */
+	OSXET("\012"),				/* \n */
+	OSXET("\074\166\164\057\076"),		/* <vt/> */
+	OSXET("\074\146\146\057\076"),		/* <ff/> */
+	OSXET("\015"),				/* \r */
+	OSXET("\074\163\157\057\076"),		/* <so/> */
+	OSXET("\074\163\151\057\076"),		/* <si/> */
+	OSXET("\074\144\154\145\057\076"),	/* <dle/> */
+	OSXET("\074\144\143\061\057\076"),	/* <de1/> */
+	OSXET("\074\144\143\062\057\076"),	/* <de2/> */
+	OSXET("\074\144\143\063\057\076"),	/* <de3/> */
+	OSXET("\074\144\143\064\057\076"),	/* <de4/> */
+	OSXET("\074\156\141\153\057\076"),	/* <nak/> */
+	OSXET("\074\163\171\156\057\076"),	/* <syn/> */
+	OSXET("\074\145\164\142\057\076"),	/* <etb/> */
+	OSXET("\074\143\141\156\057\076"),	/* <can/> */
+	OSXET("\074\145\155\057\076"),		/* <em/> */
+	OSXET("\074\163\165\142\057\076"),	/* <sub/> */
+	OSXET("\074\145\163\143\057\076"),	/* <esc/> */
+	OSXET("\074\151\163\064\057\076"),	/* <is4/> */
+	OSXET("\074\151\163\063\057\076"),	/* <is3/> */
+	OSXET("\074\151\163\062\057\076"),	/* <is2/> */
+	OSXET("\074\151\163\061\057\076"),	/* <is1/> */
+	{ 0, 0 },	/* " " */
+	{ 0, 0 },	/* ! */
+	{ 0, 0 },	/* \" */
+	{ 0, 0 },	/* # */
+	{ 0, 0 },	/* $ */
+	{ 0, 0 },	/* % */
+	OSXET("\046\141\155\160\073"),	/* &amp; */
+	{ 0, 0 },	/* ' */
+	{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, /* ()*+,-./ */
+	{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, /* 01234567 */
+	{0,0},{0,0},{0,0},{0,0},			 /* 89:; */
+	OSXET("\046\154\164\073"),	/* &lt; */
+	{ 0, 0 },	/* = */
+	OSXET("\046\147\164\073"),	/* &gt; */
+};
+
+static int
+OS__check_escaped_control_char(const void *buf, int size) {
+	size_t i;
+	/*
+	 * Inefficient algorithm which translates the escape sequences
+	 * defined above into characters. Returns -1 if not found.
+	 * TODO: replace by a faster algorithm (bsearch(), hash or
+	 * nested table lookups).
+	 */
+	for(i = 0; i < 32 /* Don't spend time on the bottom half */; i++) {
+		const struct OCTET_STRING__xer_escape_table_s *el;
+		el = &OCTET_STRING__xer_escape_table[i];
+		if(el->size == size && memcmp(buf, el->string, size) == 0)
+			return i;
+	}
+	return -1;
+}
+
+static int
+OCTET_STRING__handle_control_chars(void *struct_ptr, const void *chunk_buf, size_t chunk_size) {
+	/*
+	 * This might be one of the escape sequences
+	 * for control characters. Check it out.
+	 * #11.15.5
+	 */
+	int control_char = OS__check_escaped_control_char(chunk_buf,chunk_size);
+	if(control_char >= 0) {
+		OCTET_STRING_t *st = (OCTET_STRING_t *)struct_ptr;
+		void *p = REALLOC(st->buf, st->size + 2);
+		if(p) {
+			st->buf = (uint8_t *)p;
+			st->buf[st->size++] = control_char;
+			st->buf[st->size] = '\0';	/* nul-termination */
+			return 0;
+		}
+	}
+	
+	return -1;	/* No, it's not */
+}
+
+asn_enc_rval_t
+OCTET_STRING_encode_xer_utf8(const asn_TYPE_descriptor_t *td, const void *sptr,
+                             int ilevel, enum xer_encoder_flags_e flags,
+                             asn_app_consume_bytes_f *cb, void *app_key) {
+    const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
+	asn_enc_rval_t er;
+	uint8_t *buf, *end;
+	uint8_t *ss;	/* Sequence start */
+	ssize_t encoded_len = 0;
+
+	(void)ilevel;	/* Unused argument */
+	(void)flags;	/* Unused argument */
+
+	if(!st || (!st->buf && st->size))
+		ASN__ENCODE_FAILED;
+
+	buf = st->buf;
+	end = buf + st->size;
+	for(ss = buf; buf < end; buf++) {
+		unsigned int ch = *buf;
+		int s_len;	/* Special encoding sequence length */
+
+		/*
+		 * Escape certain characters: X.680/11.15
+		 */
+		if(ch < sizeof(OCTET_STRING__xer_escape_table)
+			/sizeof(OCTET_STRING__xer_escape_table[0])
+		&& (s_len = OCTET_STRING__xer_escape_table[ch].size)) {
+			if(((buf - ss) && cb(ss, buf - ss, app_key) < 0)
+			|| cb(OCTET_STRING__xer_escape_table[ch].string, s_len,
+					app_key) < 0)
+				ASN__ENCODE_FAILED;
+			encoded_len += (buf - ss) + s_len;
+			ss = buf + 1;
+		}
+	}
+
+	encoded_len += (buf - ss);
+	if((buf - ss) && cb(ss, buf - ss, app_key) < 0)
+		ASN__ENCODE_FAILED;
+
+	er.encoded = encoded_len;
+	ASN__ENCODED_OK(er);
+}
+
+/*
+ * Convert from hexadecimal format (cstring): "AB CD EF"
+ */
+static ssize_t OCTET_STRING__convert_hexadecimal(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) {
+	OCTET_STRING_t *st = (OCTET_STRING_t *)sptr;
+	const char *chunk_stop = (const char *)chunk_buf;
+	const char *p = chunk_stop;
+	const char *pend = p + chunk_size;
+	unsigned int clv = 0;
+	int half = 0;	/* Half bit */
+	uint8_t *buf;
+
+	/* Reallocate buffer according to high cap estimation */
+	size_t new_size = st->size + (chunk_size + 1) / 2;
+	void *nptr = REALLOC(st->buf, new_size + 1);
+	if(!nptr) return -1;
+	st->buf = (uint8_t *)nptr;
+	buf = st->buf + st->size;
+
+	/*
+	 * If something like " a b c " appears here, the " a b":3 will be
+	 * converted, and the rest skipped. That is, unless buf_size is greater
+	 * than chunk_size, then it'll be equivalent to "ABC0".
+	 */
+	for(; p < pend; p++) {
+		int ch = *(const unsigned char *)p;
+		switch(ch) {
+		case 0x09: case 0x0a: case 0x0c: case 0x0d:
+		case 0x20:
+			/* Ignore whitespace */
+			continue;
+		case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: /*01234*/
+		case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: /*56789*/
+			clv = (clv << 4) + (ch - 0x30);
+			break;
+		case 0x41: case 0x42: case 0x43:	/* ABC */
+		case 0x44: case 0x45: case 0x46:	/* DEF */
+			clv = (clv << 4) + (ch - 0x41 + 10);
+			break;
+		case 0x61: case 0x62: case 0x63:	/* abc */
+		case 0x64: case 0x65: case 0x66:	/* def */
+			clv = (clv << 4) + (ch - 0x61 + 10);
+			break;
+		default:
+			*buf = 0;	/* JIC */
+			return -1;
+		}
+		if(half++) {
+			half = 0;
+			*buf++ = clv;
+			chunk_stop = p + 1;
+		}
+	}
+
+	/*
+	 * Check partial decoding.
+	 */
+	if(half) {
+		if(have_more) {
+			/*
+			 * Partial specification is fine,
+			 * because no more more PXER_TEXT data is available.
+			 */
+			*buf++ = clv << 4;
+			chunk_stop = p;
+		}
+	} else {
+		chunk_stop = p;
+	}
+
+	st->size = buf - st->buf;	/* Adjust the buffer size */
+	assert(st->size <= new_size);
+	st->buf[st->size] = 0;		/* Courtesy termination */
+
+	return (chunk_stop - (const char *)chunk_buf);	/* Converted size */
+}
+
+/*
+ * Convert from binary format: "00101011101"
+ */
+static ssize_t OCTET_STRING__convert_binary(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) {
+	BIT_STRING_t *st = (BIT_STRING_t *)sptr;
+	const char *p = (const char *)chunk_buf;
+	const char *pend = p + chunk_size;
+	int bits_unused = st->bits_unused & 0x7;
+	uint8_t *buf;
+
+	/* Reallocate buffer according to high cap estimation */
+	size_t new_size = st->size + (chunk_size + 7) / 8;
+	void *nptr = REALLOC(st->buf, new_size + 1);
+	if(!nptr) return -1;
+	st->buf = (uint8_t *)nptr;
+	buf = st->buf + st->size;
+
+	(void)have_more;
+
+	if(bits_unused == 0)
+		bits_unused = 8;
+	else if(st->size)
+		buf--;
+
+	/*
+	 * Convert series of 0 and 1 into the octet string.
+	 */
+	for(; p < pend; p++) {
+		int ch = *(const unsigned char *)p;
+		switch(ch) {
+		case 0x09: case 0x0a: case 0x0c: case 0x0d:
+		case 0x20:
+			/* Ignore whitespace */
+			break;
+		case 0x30:
+		case 0x31:
+			if(bits_unused-- <= 0) {
+				*++buf = 0;	/* Clean the cell */
+				bits_unused = 7;
+			}
+			*buf |= (ch&1) << bits_unused;
+			break;
+		default:
+			st->bits_unused = bits_unused;
+			return -1;
+		}
+	}
+
+	if(bits_unused == 8) {
+		st->size = buf - st->buf;
+		st->bits_unused = 0;
+	} else {
+		st->size = buf - st->buf + 1;
+		st->bits_unused = bits_unused;
+	}
+
+	assert(st->size <= new_size);
+	st->buf[st->size] = 0;		/* Courtesy termination */
+
+	return chunk_size;	/* Converted in full */
+}
+
+/*
+ * Something like strtod(), but with stricter rules.
+ */
+static int
+OS__strtoent(int base, const char *buf, const char *end, int32_t *ret_value) {
+	const int32_t last_unicode_codepoint = 0x10ffff;
+	int32_t val = 0;
+	const char *p;
+
+	for(p = buf; p < end; p++) {
+		int ch = *p;
+
+		switch(ch) {
+		case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: /*01234*/
+		case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: /*56789*/
+			val = val * base + (ch - 0x30);
+			break;
+		case 0x41: case 0x42: case 0x43:	/* ABC */
+		case 0x44: case 0x45: case 0x46:	/* DEF */
+			val = val * base + (ch - 0x41 + 10);
+			break;
+		case 0x61: case 0x62: case 0x63:	/* abc */
+		case 0x64: case 0x65: case 0x66:	/* def */
+			val = val * base + (ch - 0x61 + 10);
+			break;
+		case 0x3b:	/* ';' */
+			*ret_value = val;
+			return (p - buf) + 1;
+		default:
+			return -1;	/* Character set error */
+		}
+
+		/* Value exceeds the Unicode range. */
+		if(val > last_unicode_codepoint) {
+			return -1;
+		}
+	}
+
+	*ret_value = -1;
+	return (p - buf);
+}
+
+/*
+ * Convert from the plain UTF-8 format, expanding entity references: "2 &lt; 3"
+ */
+static ssize_t
+OCTET_STRING__convert_entrefs(void *sptr, const void *chunk_buf,
+                              size_t chunk_size, int have_more) {
+    OCTET_STRING_t *st = (OCTET_STRING_t *)sptr;
+	const char *p = (const char *)chunk_buf;
+	const char *pend = p + chunk_size;
+	uint8_t *buf;
+
+	/* Reallocate buffer */
+	size_t new_size = st->size + chunk_size;
+	void *nptr = REALLOC(st->buf, new_size + 1);
+	if(!nptr) return -1;
+	st->buf = (uint8_t *)nptr;
+	buf = st->buf + st->size;
+
+	/*
+	 * Convert series of 0 and 1 into the octet string.
+	 */
+	for(; p < pend; p++) {
+		int ch = *(const unsigned char *)p;
+		int len;	/* Length of the rest of the chunk */
+
+		if(ch != 0x26 /* '&' */) {
+			*buf++ = ch;
+			continue;	/* That was easy... */
+		}
+
+		/*
+		 * Process entity reference.
+		 */
+		len = chunk_size - (p - (const char *)chunk_buf);
+		if(len == 1 /* "&" */) goto want_more;
+		if(p[1] == 0x23 /* '#' */) {
+			const char *pval;	/* Pointer to start of digits */
+			int32_t val = 0;	/* Entity reference value */
+			int base;
+
+			if(len == 2 /* "&#" */) goto want_more;
+			if(p[2] == 0x78 /* 'x' */)
+				pval = p + 3, base = 16;
+			else
+				pval = p + 2, base = 10;
+			len = OS__strtoent(base, pval, p + len, &val);
+			if(len == -1) {
+				/* Invalid charset. Just copy verbatim. */
+				*buf++ = ch;
+				continue;
+			}
+			if(!len || pval[len-1] != 0x3b) goto want_more;
+			assert(val > 0);
+			p += (pval - p) + len - 1; /* Advance past entref */
+
+			if(val < 0x80) {
+				*buf++ = (char)val;
+			} else if(val < 0x800) {
+				*buf++ = 0xc0 | ((val >> 6));
+				*buf++ = 0x80 | ((val & 0x3f));
+			} else if(val < 0x10000) {
+				*buf++ = 0xe0 | ((val >> 12));
+				*buf++ = 0x80 | ((val >> 6) & 0x3f);
+				*buf++ = 0x80 | ((val & 0x3f));
+			} else if(val < 0x200000) {
+				*buf++ = 0xf0 | ((val >> 18));
+				*buf++ = 0x80 | ((val >> 12) & 0x3f);
+				*buf++ = 0x80 | ((val >> 6) & 0x3f);
+				*buf++ = 0x80 | ((val & 0x3f));
+			} else if(val < 0x4000000) {
+				*buf++ = 0xf8 | ((val >> 24));
+				*buf++ = 0x80 | ((val >> 18) & 0x3f);
+				*buf++ = 0x80 | ((val >> 12) & 0x3f);
+				*buf++ = 0x80 | ((val >> 6) & 0x3f);
+				*buf++ = 0x80 | ((val & 0x3f));
+			} else {
+				*buf++ = 0xfc | ((val >> 30) & 0x1);
+				*buf++ = 0x80 | ((val >> 24) & 0x3f);
+				*buf++ = 0x80 | ((val >> 18) & 0x3f);
+				*buf++ = 0x80 | ((val >> 12) & 0x3f);
+				*buf++ = 0x80 | ((val >> 6) & 0x3f);
+				*buf++ = 0x80 | ((val & 0x3f));
+			}
+		} else {
+			/*
+			 * Ugly, limited parsing of &amp; &gt; &lt;
+			 */
+			char *sc = (char *)memchr(p, 0x3b, len > 5 ? 5 : len);
+			if(!sc) goto want_more;
+			if((sc - p) == 4
+				&& p[1] == 0x61	/* 'a' */
+				&& p[2] == 0x6d	/* 'm' */
+				&& p[3] == 0x70	/* 'p' */) {
+				*buf++ = 0x26;
+				p = sc;
+				continue;
+			}
+			if((sc - p) == 3) {
+				if(p[1] == 0x6c) {
+					*buf = 0x3c;	/* '<' */
+				} else if(p[1] == 0x67) {
+					*buf = 0x3e;	/* '>' */
+				} else {
+					/* Unsupported entity reference */
+					*buf++ = ch;
+					continue;
+				}
+				if(p[2] != 0x74) {
+					/* Unsupported entity reference */
+					*buf++ = ch;
+					continue;
+				}
+				buf++;
+				p = sc;
+				continue;
+			}
+			/* Unsupported entity reference */
+			*buf++ = ch;
+		}
+
+		continue;
+	want_more:
+		if(have_more) {
+			/*
+			 * We know that no more data (of the same type)
+			 * is coming. Copy the rest verbatim.
+			 */
+			*buf++ = ch;
+			continue;
+		}
+		chunk_size = (p - (const char *)chunk_buf);
+		/* Processing stalled: need more data */
+		break;
+	}
+
+	st->size = buf - st->buf;
+	assert(st->size <= new_size);
+	st->buf[st->size] = 0;		/* Courtesy termination */
+
+	return chunk_size;	/* Converted in full */
+}
+
+/*
+ * Decode OCTET STRING from the XML element's body.
+ */
+static asn_dec_rval_t
+OCTET_STRING__decode_xer(
+    const asn_codec_ctx_t *opt_codec_ctx, const asn_TYPE_descriptor_t *td,
+    void **sptr, const char *opt_mname, const void *buf_ptr, size_t size,
+    int (*opt_unexpected_tag_decoder)(void *struct_ptr, const void *chunk_buf,
+                                      size_t chunk_size),
+    ssize_t (*body_receiver)(void *struct_ptr, const void *chunk_buf,
+                             size_t chunk_size, int have_more)) {
+    OCTET_STRING_t *st = (OCTET_STRING_t *)*sptr;
+	const asn_OCTET_STRING_specifics_t *specs = td->specifics
+				? (const asn_OCTET_STRING_specifics_t *)td->specifics
+				: &asn_SPC_OCTET_STRING_specs;
+	const char *xml_tag = opt_mname ? opt_mname : td->xml_tag;
+	asn_struct_ctx_t *ctx;		/* Per-structure parser context */
+	asn_dec_rval_t rval;		/* Return value from the decoder */
+	int st_allocated;
+
+	/*
+	 * Create the string if does not exist.
+	 */
+	if(!st) {
+		st = (OCTET_STRING_t *)CALLOC(1, specs->struct_size);
+		*sptr = (void *)st;
+		if(!st) goto sta_failed;
+		st_allocated = 1;
+	} else {
+		st_allocated = 0;
+	}
+	if(!st->buf) {
+		/* This is separate from above section */
+		st->buf = (uint8_t *)CALLOC(1, 1);
+		if(!st->buf) {
+			if(st_allocated) {
+				*sptr = 0;
+				goto stb_failed;
+			} else {
+				goto sta_failed;
+			}
+		}
+	}
+
+	/* Restore parsing context */
+	ctx = (asn_struct_ctx_t *)(((char *)*sptr) + specs->ctx_offset);
+
+	return xer_decode_general(opt_codec_ctx, ctx, *sptr, xml_tag,
+		buf_ptr, size, opt_unexpected_tag_decoder, body_receiver);
+
+stb_failed:
+	FREEMEM(st);
+sta_failed:
+	rval.code = RC_FAIL;
+	rval.consumed = 0;
+	return rval;
+}
+
+/*
+ * Decode OCTET STRING from the hexadecimal data.
+ */
+asn_dec_rval_t
+OCTET_STRING_decode_xer_hex(const asn_codec_ctx_t *opt_codec_ctx,
+                            const asn_TYPE_descriptor_t *td, void **sptr,
+                            const char *opt_mname, const void *buf_ptr,
+                            size_t size) {
+    return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname,
+		buf_ptr, size, 0, OCTET_STRING__convert_hexadecimal);
+}
+
+/*
+ * Decode OCTET STRING from the binary (0/1) data.
+ */
+asn_dec_rval_t
+OCTET_STRING_decode_xer_binary(const asn_codec_ctx_t *opt_codec_ctx,
+                               const asn_TYPE_descriptor_t *td, void **sptr,
+                               const char *opt_mname, const void *buf_ptr,
+                               size_t size) {
+    return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname,
+		buf_ptr, size, 0, OCTET_STRING__convert_binary);
+}
+
+/*
+ * Decode OCTET STRING from the string (ASCII/UTF-8) data.
+ */
+asn_dec_rval_t
+OCTET_STRING_decode_xer_utf8(const asn_codec_ctx_t *opt_codec_ctx,
+                             const asn_TYPE_descriptor_t *td, void **sptr,
+                             const char *opt_mname, const void *buf_ptr,
+                             size_t size) {
+    return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname,
+		buf_ptr, size,
+		OCTET_STRING__handle_control_chars,
+		OCTET_STRING__convert_entrefs);
+}
+
+#ifndef  ASN_DISABLE_PER_SUPPORT
+
+static int
+OCTET_STRING_per_get_characters(asn_per_data_t *po, uint8_t *buf,
+		size_t units, unsigned int bpc, unsigned int unit_bits,
+		long lb, long ub, const asn_per_constraints_t *pc) {
+	uint8_t *end = buf + units * bpc;
+
+	ASN_DEBUG("Expanding %d characters into (%ld..%ld):%d",
+		(int)units, lb, ub, unit_bits);
+
+	/* X.691: 27.5.4 */
+	if((unsigned long)ub <= ((unsigned long)2 << (unit_bits - 1))) {
+		/* Decode without translation */
+		lb = 0;
+	} else if(pc && pc->code2value) {
+		if(unit_bits > 16)
+			return 1;	/* FATAL: can't have constrained
+					 * UniversalString with more than
+					 * 16 million code points */
+		for(; buf < end; buf += bpc) {
+			int value;
+			int code = per_get_few_bits(po, unit_bits);
+			if(code < 0) return -1;	/* WMORE */
+			value = pc->code2value(code);
+			if(value < 0) {
+				ASN_DEBUG("Code %d (0x%02x) is"
+					" not in map (%ld..%ld)",
+					code, code, lb, ub);
+				return 1;	/* FATAL */
+			}
+			switch(bpc) {
+			case 1: *buf = value; break;
+			case 2: buf[0] = value >> 8; buf[1] = value; break;
+			case 4: buf[0] = value >> 24; buf[1] = value >> 16;
+				buf[2] = value >> 8; buf[3] = value; break;
+			}
+		}
+		return 0;
+	}
+
+	/* Shortcut the no-op copying to the aligned structure */
+	if(lb == 0 && (unit_bits == 8 * bpc)) {
+		return per_get_many_bits(po, buf, 0, unit_bits * units);
+	}
+
+	for(; buf < end; buf += bpc) {
+		int32_t code = per_get_few_bits(po, unit_bits);
+		int32_t ch = code + lb;
+		if(code < 0) return -1;	/* WMORE */
+		if(ch > ub) {
+			ASN_DEBUG("Code %d is out of range (%ld..%ld)",
+				ch, lb, ub);
+			return 1;	/* FATAL */
+		}
+		switch(bpc) {
+		case 1: *buf = ch; break;
+		case 2: buf[0] = ch >> 8; buf[1] = ch; break;
+		case 4: buf[0] = ch >> 24; buf[1] = ch >> 16;
+			buf[2] = ch >> 8; buf[3] = ch; break;
+		}
+	}
+
+	return 0;
+}
+
+static int
+OCTET_STRING_per_put_characters(asn_per_outp_t *po, const uint8_t *buf,
+		size_t units, unsigned int bpc, unsigned int unit_bits,
+		long lb, long ub, const asn_per_constraints_t *pc) {
+	const uint8_t *end = buf + units * bpc;
+
+	ASN_DEBUG("Squeezing %d characters into (%ld..%ld):%d (%d bpc)",
+		(int)units, lb, ub, unit_bits, bpc);
+
+	/* X.691: 27.5.4 */
+	if((unsigned long)ub <= ((unsigned long)2 << (unit_bits - 1))) {
+		/* Encode as is */
+		lb = 0;
+	} else if(pc && pc->value2code) {
+		for(; buf < end; buf += bpc) {
+			int code;
+			uint32_t value;
+			switch(bpc) {
+			case 1: value = *(const uint8_t *)buf; break;
+			case 2: value = (buf[0] << 8) | buf[1]; break;
+			case 4: value = (buf[0] << 24) | (buf[1] << 16)
+					| (buf[2] << 8) | buf[3]; break;
+			default: return -1;
+			}
+			code = pc->value2code(value);
+			if(code < 0) {
+				ASN_DEBUG("Character %d (0x%02x) is"
+					" not in map (%ld..%ld)",
+					*buf, *buf, lb, ub);
+				return -1;
+			}
+			if(per_put_few_bits(po, code, unit_bits))
+				return -1;
+		}
+	}
+
+	/* Shortcut the no-op copying to the aligned structure */
+	if(lb == 0 && (unit_bits == 8 * bpc)) {
+		return per_put_many_bits(po, buf, unit_bits * units);
+	}
+
+    for(ub -= lb; buf < end; buf += bpc) {
+        int ch;
+        uint32_t value;
+        switch(bpc) {
+        case 1:
+            value = *(const uint8_t *)buf;
+            break;
+        case 2:
+            value = (buf[0] << 8) | buf[1];
+            break;
+        case 4:
+            value = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+            break;
+        default:
+            return -1;
+        }
+        ch = value - lb;
+        if(ch < 0 || ch > ub) {
+            ASN_DEBUG("Character %d (0x%02x) is out of range (%ld..%ld)", *buf,
+                      value, lb, ub + lb);
+            return -1;
+        }
+        if(per_put_few_bits(po, ch, unit_bits)) return -1;
+    }
+
+    return 0;
+}
+
+static asn_per_constraints_t asn_DEF_OCTET_STRING_constraints = {
+	{ APC_CONSTRAINED, 8, 8, 0, 255 },
+	{ APC_SEMI_CONSTRAINED, -1, -1, 0, 0 },
+	0, 0
+};
+
+asn_dec_rval_t
+OCTET_STRING_decode_uper(const asn_codec_ctx_t *opt_codec_ctx,
+                         const asn_TYPE_descriptor_t *td,
+                         const asn_per_constraints_t *constraints, void **sptr,
+                         asn_per_data_t *pd) {
+    const asn_OCTET_STRING_specifics_t *specs = td->specifics
+		? (const asn_OCTET_STRING_specifics_t *)td->specifics
+		: &asn_SPC_OCTET_STRING_specs;
+    const asn_per_constraints_t *pc =
+        constraints ? constraints : td->encoding_constraints.per_constraints;
+    const asn_per_constraint_t *cval;
+	const asn_per_constraint_t *csiz;
+	asn_dec_rval_t rval = { RC_OK, 0 };
+	OCTET_STRING_t *st = (OCTET_STRING_t *)*sptr;
+	ssize_t consumed_myself = 0;
+	int repeat;
+	enum {
+		OS__BPC_CHAR	= 1,
+		OS__BPC_U16	= 2,
+		OS__BPC_U32	= 4
+	} bpc;	/* Bytes per character */
+	unsigned int unit_bits;
+	unsigned int canonical_unit_bits;
+
+	(void)opt_codec_ctx;
+
+	if(pc) {
+		cval = &pc->value;
+		csiz = &pc->size;
+	} else {
+		cval = &asn_DEF_OCTET_STRING_constraints.value;
+		csiz = &asn_DEF_OCTET_STRING_constraints.size;
+	}
+
+	switch(specs->subvariant) {
+	default:
+	case ASN_OSUBV_ANY:
+	case ASN_OSUBV_BIT:
+		ASN_DEBUG("Unrecognized subvariant %d", specs->subvariant);
+		RETURN(RC_FAIL);
+		break;
+	case ASN_OSUBV_STR:
+		canonical_unit_bits = unit_bits = 8;
+		if(cval->flags & APC_CONSTRAINED)
+			unit_bits = cval->range_bits;
+		bpc = OS__BPC_CHAR;
+		break;
+	case ASN_OSUBV_U16:
+		canonical_unit_bits = unit_bits = 16;
+		if(cval->flags & APC_CONSTRAINED)
+			unit_bits = cval->range_bits;
+		bpc = OS__BPC_U16;
+		break;
+	case ASN_OSUBV_U32:
+		canonical_unit_bits = unit_bits = 32;
+		if(cval->flags & APC_CONSTRAINED)
+			unit_bits = cval->range_bits;
+		bpc = OS__BPC_U32;
+		break;
+	}
+
+	/*
+	 * Allocate the string.
+	 */
+	if(!st) {
+		st = (OCTET_STRING_t *)(*sptr = CALLOC(1, specs->struct_size));
+		if(!st) RETURN(RC_FAIL);
+	}
+
+	ASN_DEBUG("PER Decoding %s size %ld .. %ld bits %d",
+		csiz->flags & APC_EXTENSIBLE ? "extensible" : "non-extensible",
+		csiz->lower_bound, csiz->upper_bound, csiz->effective_bits);
+
+	if(csiz->flags & APC_EXTENSIBLE) {
+		int inext = per_get_few_bits(pd, 1);
+		if(inext < 0) RETURN(RC_WMORE);
+		if(inext) {
+			csiz = &asn_DEF_OCTET_STRING_constraints.size;
+			unit_bits = canonical_unit_bits;
+		}
+	}
+
+	if(csiz->effective_bits >= 0) {
+		FREEMEM(st->buf);
+		if(bpc) {
+			st->size = csiz->upper_bound * bpc;
+		} else {
+			st->size = (csiz->upper_bound + 7) >> 3;
+		}
+		st->buf = (uint8_t *)MALLOC(st->size + 1);
+		if(!st->buf) { st->size = 0; RETURN(RC_FAIL); }
+	}
+
+	/* X.691, #16.5: zero-length encoding */
+	/* X.691, #16.6: short fixed length encoding (up to 2 octets) */
+	/* X.691, #16.7: long fixed length encoding (up to 64K octets) */
+	if(csiz->effective_bits == 0) {
+		int ret;
+		if(bpc) {
+			ASN_DEBUG("Encoding OCTET STRING size %ld",
+				csiz->upper_bound);
+			ret = OCTET_STRING_per_get_characters(pd, st->buf,
+				csiz->upper_bound, bpc, unit_bits,
+				cval->lower_bound, cval->upper_bound, pc);
+			if(ret > 0) RETURN(RC_FAIL);
+		} else {
+			ASN_DEBUG("Encoding BIT STRING size %ld",
+				csiz->upper_bound);
+			ret = per_get_many_bits(pd, st->buf, 0,
+					    unit_bits * csiz->upper_bound);
+		}
+		if(ret < 0) RETURN(RC_WMORE);
+		consumed_myself += unit_bits * csiz->upper_bound;
+		st->buf[st->size] = 0;
+		RETURN(RC_OK);
+	}
+
+	st->size = 0;
+	do {
+		ssize_t raw_len;
+		ssize_t len_bytes;
+		void *p;
+		int ret;
+
+		/* Get the PER length */
+		raw_len = uper_get_length(pd, csiz->effective_bits, csiz->lower_bound,
+		                          &repeat);
+		if(raw_len < 0) RETURN(RC_WMORE);
+		if(raw_len == 0 && st->buf) break;
+
+		ASN_DEBUG("Got PER length eb %ld, len %ld, %s (%s)",
+			(long)csiz->effective_bits, (long)raw_len,
+			repeat ? "repeat" : "once", td->name);
+        len_bytes = raw_len * bpc;
+		p = REALLOC(st->buf, st->size + len_bytes + 1);
+		if(!p) RETURN(RC_FAIL);
+		st->buf = (uint8_t *)p;
+
+        ret = OCTET_STRING_per_get_characters(pd, &st->buf[st->size], raw_len,
+                                              bpc, unit_bits, cval->lower_bound,
+                                              cval->upper_bound, pc);
+        if(ret > 0) RETURN(RC_FAIL);
+		if(ret < 0) RETURN(RC_WMORE);
+		st->size += len_bytes;
+	} while(repeat);
+	st->buf[st->size] = 0;	/* nul-terminate */
+
+	return rval;
+}
+
+asn_enc_rval_t
+OCTET_STRING_encode_uper(const asn_TYPE_descriptor_t *td,
+                         const asn_per_constraints_t *constraints,
+                         const void *sptr, asn_per_outp_t *po) {
+    const asn_OCTET_STRING_specifics_t *specs = td->specifics
+		? (const asn_OCTET_STRING_specifics_t *)td->specifics
+		: &asn_SPC_OCTET_STRING_specs;
+	const asn_per_constraints_t *pc = constraints ? constraints
+				: td->encoding_constraints.per_constraints;
+	const asn_per_constraint_t *cval;
+	const asn_per_constraint_t *csiz;
+	const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
+	asn_enc_rval_t er = { 0, 0, 0 };
+	int inext = 0;		/* Lies not within extension root */
+	unsigned int unit_bits;
+	unsigned int canonical_unit_bits;
+	size_t size_in_units;
+	const uint8_t *buf;
+	int ret;
+	enum {
+		OS__BPC_CHAR	= 1,
+		OS__BPC_U16	= 2,
+		OS__BPC_U32	= 4
+	} bpc;	/* Bytes per character */
+	int ct_extensible;
+
+	if(!st || (!st->buf && st->size))
+		ASN__ENCODE_FAILED;
+
+	if(pc) {
+		cval = &pc->value;
+		csiz = &pc->size;
+	} else {
+		cval = &asn_DEF_OCTET_STRING_constraints.value;
+		csiz = &asn_DEF_OCTET_STRING_constraints.size;
+	}
+	ct_extensible = csiz->flags & APC_EXTENSIBLE;
+
+	switch(specs->subvariant) {
+	default:
+	case ASN_OSUBV_ANY:
+	case ASN_OSUBV_BIT:
+		ASN__ENCODE_FAILED;
+	case ASN_OSUBV_STR:
+		canonical_unit_bits = unit_bits = 8;
+		if(cval->flags & APC_CONSTRAINED)
+			unit_bits = cval->range_bits;
+		bpc = OS__BPC_CHAR;
+		size_in_units = st->size;
+		break;
+	case ASN_OSUBV_U16:
+		canonical_unit_bits = unit_bits = 16;
+		if(cval->flags & APC_CONSTRAINED)
+			unit_bits = cval->range_bits;
+		bpc = OS__BPC_U16;
+		size_in_units = st->size >> 1;
+		if(st->size & 1) {
+			ASN_DEBUG("%s string size is not modulo 2", td->name);
+			ASN__ENCODE_FAILED;
+		}
+		break;
+	case ASN_OSUBV_U32:
+		canonical_unit_bits = unit_bits = 32;
+		if(cval->flags & APC_CONSTRAINED)
+			unit_bits = cval->range_bits;
+		bpc = OS__BPC_U32;
+		size_in_units = st->size >> 2;
+		if(st->size & 3) {
+			ASN_DEBUG("%s string size is not modulo 4", td->name);
+			ASN__ENCODE_FAILED;
+		}
+		break;
+	}
+
+	ASN_DEBUG("Encoding %s into %" ASN_PRI_SIZE " units of %d bits"
+		" (%ld..%ld, effective %d)%s",
+		td->name, size_in_units, unit_bits,
+		csiz->lower_bound, csiz->upper_bound,
+		csiz->effective_bits, ct_extensible ? " EXT" : "");
+
+	/* Figure out whether size lies within PER visible constraint */
+
+    if(csiz->effective_bits >= 0) {
+        if((ssize_t)size_in_units < csiz->lower_bound
+           || (ssize_t)size_in_units > csiz->upper_bound) {
+            if(ct_extensible) {
+                csiz = &asn_DEF_OCTET_STRING_constraints.size;
+                unit_bits = canonical_unit_bits;
+                inext = 1;
+            } else {
+                ASN__ENCODE_FAILED;
+            }
+        }
+    } else {
+        inext = 0;
+    }
+
+    if(ct_extensible) {
+		/* Declare whether length is [not] within extension root */
+		if(per_put_few_bits(po, inext, 1))
+			ASN__ENCODE_FAILED;
+	}
+
+    if(csiz->effective_bits >= 0 && !inext) {
+        ASN_DEBUG("Encoding %" ASN_PRI_SIZE " bytes (%ld), length in %d bits", st->size,
+                  size_in_units - csiz->lower_bound, csiz->effective_bits);
+        ret = per_put_few_bits(po, size_in_units - csiz->lower_bound,
+                               csiz->effective_bits);
+        if(ret) ASN__ENCODE_FAILED;
+        ret = OCTET_STRING_per_put_characters(po, st->buf, size_in_units, bpc,
+                                              unit_bits, cval->lower_bound,
+                                              cval->upper_bound, pc);
+        if(ret) ASN__ENCODE_FAILED;
+        ASN__ENCODED_OK(er);
+    }
+
+    ASN_DEBUG("Encoding %" ASN_PRI_SIZE " bytes", st->size);
+
+    buf = st->buf;
+    ASN_DEBUG("Encoding %" ASN_PRI_SIZE " in units", size_in_units);
+    do {
+        int need_eom = 0;
+        ssize_t may_save = uper_put_length(po, size_in_units, &need_eom);
+        if(may_save < 0) ASN__ENCODE_FAILED;
+
+        ASN_DEBUG("Encoding %" ASN_PRI_SSIZE " of %" ASN_PRI_SIZE "%s", may_save, size_in_units,
+                  need_eom ? ",+EOM" : "");
+
+        ret = OCTET_STRING_per_put_characters(po, buf, may_save, bpc, unit_bits,
+                                              cval->lower_bound,
+                                              cval->upper_bound, pc);
+        if(ret) ASN__ENCODE_FAILED;
+
+        buf += may_save * bpc;
+        size_in_units -= may_save;
+        assert(!(may_save & 0x07) || !size_in_units);
+        if(need_eom && uper_put_length(po, 0, 0))
+            ASN__ENCODE_FAILED; /* End of Message length */
+    } while(size_in_units);
+
+    ASN__ENCODED_OK(er);
+}
+
+#endif  /* ASN_DISABLE_PER_SUPPORT */
+
+int
+OCTET_STRING_print(const asn_TYPE_descriptor_t *td, const void *sptr,
+                   int ilevel, asn_app_consume_bytes_f *cb, void *app_key) {
+    const char * const h2c = "0123456789ABCDEF";
+	const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
+	char scratch[16 * 3 + 4];
+	char *p = scratch;
+	uint8_t *buf;
+	uint8_t *end;
+	size_t i;
+
+	(void)td;	/* Unused argument */
+
+	if(!st || (!st->buf && st->size))
+		return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
+
+	/*
+	 * Dump the contents of the buffer in hexadecimal.
+	 */
+	buf = st->buf;
+	end = buf + st->size;
+	for(i = 0; buf < end; buf++, i++) {
+		if(!(i % 16) && (i || st->size > 16)) {
+			if(cb(scratch, p - scratch, app_key) < 0)
+				return -1;
+			_i_INDENT(1);
+			p = scratch;
+		}
+		*p++ = h2c[(*buf >> 4) & 0x0F];
+		*p++ = h2c[*buf & 0x0F];
+		*p++ = 0x20;
+	}
+
+	if(p > scratch) {
+		p--;	/* Remove the tail space */
+		if(cb(scratch, p - scratch, app_key) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+int
+OCTET_STRING_print_utf8(const asn_TYPE_descriptor_t *td, const void *sptr,
+                        int ilevel, asn_app_consume_bytes_f *cb,
+                        void *app_key) {
+    const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
+
+	(void)td;	/* Unused argument */
+	(void)ilevel;	/* Unused argument */
+
+	if(st && (st->buf || !st->size)) {
+		return (cb(st->buf, st->size, app_key) < 0) ? -1 : 0;
+	} else {
+		return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
+	}
+}
+
+void
+OCTET_STRING_free(const asn_TYPE_descriptor_t *td, void *sptr,
+                  enum asn_struct_free_method method) {
+	OCTET_STRING_t *st = (OCTET_STRING_t *)sptr;
+	const asn_OCTET_STRING_specifics_t *specs;
+	asn_struct_ctx_t *ctx;
+	struct _stack *stck;
+
+	if(!td || !st)
+		return;
+
+	specs = td->specifics
+		    ? (const asn_OCTET_STRING_specifics_t *)td->specifics
+		    : &asn_SPC_OCTET_STRING_specs;
+	ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);
+
+	ASN_DEBUG("Freeing %s as OCTET STRING", td->name);
+
+	if(st->buf) {
+		FREEMEM(st->buf);
+		st->buf = 0;
+	}
+
+	/*
+	 * Remove decode-time stack.
+	 */
+	stck = (struct _stack *)ctx->ptr;
+	if(stck) {
+		while(stck->tail) {
+			struct _stack_el *sel = stck->tail;
+			stck->tail = sel->prev;
+			FREEMEM(sel);
+		}
+		FREEMEM(stck);
+	}
+
+    switch(method) {
+    case ASFM_FREE_EVERYTHING:
+        FREEMEM(sptr);
+        break;
+    case ASFM_FREE_UNDERLYING:
+        break;
+    case ASFM_FREE_UNDERLYING_AND_RESET:
+        memset(sptr, 0,
+               td->specifics
+                   ? ((const asn_OCTET_STRING_specifics_t *)(td->specifics))
+                         ->struct_size
+                   : sizeof(OCTET_STRING_t));
+        break;
+    }
+}
+
+/*
+ * Conversion routines.
+ */
+int
+OCTET_STRING_fromBuf(OCTET_STRING_t *st, const char *str, int len) {
+	void *buf;
+
+	if(st == 0 || (str == 0 && len)) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	/*
+	 * Clear the OCTET STRING.
+	 */
+	if(str == NULL) {
+		FREEMEM(st->buf);
+		st->buf = 0;
+		st->size = 0;
+		return 0;
+	}
+
+	/* Determine the original string size, if not explicitly given */
+	if(len < 0)
+		len = strlen(str);
+
+	/* Allocate and fill the memory */
+	buf = MALLOC(len + 1);
+	if(buf == NULL)
+		return -1;
+
+	memcpy(buf, str, len);
+	((uint8_t *)buf)[len] = '\0';	/* Couldn't use memcpy(len+1)! */
+	FREEMEM(st->buf);
+	st->buf = (uint8_t *)buf;
+	st->size = len;
+
+	return 0;
+}
+
+OCTET_STRING_t *
+OCTET_STRING_new_fromBuf(const asn_TYPE_descriptor_t *td, const char *str,
+                         int len) {
+    const asn_OCTET_STRING_specifics_t *specs =
+        td->specifics ? (const asn_OCTET_STRING_specifics_t *)td->specifics
+                      : &asn_SPC_OCTET_STRING_specs;
+    OCTET_STRING_t *st;
+
+	st = (OCTET_STRING_t *)CALLOC(1, specs->struct_size);
+	if(st && str && OCTET_STRING_fromBuf(st, str, len)) {
+		FREEMEM(st);
+		st = NULL;
+	}
+
+	return st;
+}
+
+/*
+ * Lexicographically compare the common prefix of both strings,
+ * and if it is the same return -1 for the smallest string.
+ */
+int
+OCTET_STRING_compare(const asn_TYPE_descriptor_t *td, const void *aptr,
+                     const void *bptr) {
+    const asn_OCTET_STRING_specifics_t *specs = td->specifics;
+    const OCTET_STRING_t *a = aptr;
+    const OCTET_STRING_t *b = bptr;
+
+    assert(!specs || specs->subvariant != ASN_OSUBV_BIT);
+
+    if(a && b) {
+        size_t common_prefix_size = a->size <= b->size ? a->size : b->size;
+        int ret = memcmp(a->buf, b->buf, common_prefix_size);
+        if(ret == 0) {
+            /* Figure out which string with equal prefixes is longer. */
+            if(a->size < b->size) {
+                return -1;
+            } else if(a->size > b->size) {
+                return 1;
+            } else {
+                return 0;
+            }
+        } else {
+            return ret < 0 ? -1 : 1;
+        }
+    } else if(!a && !b) {
+        return 0;
+    } else if(!a) {
+        return -1;
+    } else {
+        return 1;
+    }
+
+}
+
+/*
+ * Biased function for randomizing character values around their limits.
+ */
+static uint32_t
+OCTET_STRING__random_char(unsigned long lb, unsigned long ub) {
+    assert(lb <= ub);
+    switch(asn_random_between(0, 16)) {
+    case 0:
+        if(lb < ub) return lb + 1;
+        /* Fall through */
+    case 1:
+        return lb;
+    case 2:
+        if(lb < ub) return ub - 1;
+        /* Fall through */
+    case 3:
+        return ub;
+    default:
+        return asn_random_between(lb, ub);
+    }
+}
+
+
+size_t
+OCTET_STRING_random_length_constrained(
+    const asn_TYPE_descriptor_t *td,
+    const asn_encoding_constraints_t *constraints, size_t max_length) {
+    const unsigned lengths[] = {0,     1,     2,     3,     4,     8,
+                                126,   127,   128,   16383, 16384, 16385,
+                                65534, 65535, 65536, 65537};
+    size_t rnd_len;
+
+    /* Figure out how far we should go */
+    rnd_len = lengths[asn_random_between(
+        0, sizeof(lengths) / sizeof(lengths[0]) - 1)];
+
+    if(!constraints || !constraints->per_constraints)
+        constraints = &td->encoding_constraints;
+    if(constraints->per_constraints) {
+        const asn_per_constraint_t *pc = &constraints->per_constraints->size;
+        if(pc->flags & APC_CONSTRAINED) {
+            long suggested_upper_bound = pc->upper_bound < (ssize_t)max_length
+                                             ? pc->upper_bound
+                                             : (ssize_t)max_length;
+            if(max_length <= (size_t)pc->lower_bound) {
+                return pc->lower_bound;
+            }
+            if(pc->flags & APC_EXTENSIBLE) {
+                switch(asn_random_between(0, 5)) {
+                case 0:
+                    if(pc->lower_bound > 0) {
+                        rnd_len = pc->lower_bound - 1;
+                        break;
+                    }
+                    /* Fall through */
+                case 1:
+                    rnd_len = pc->upper_bound + 1;
+                    break;
+                case 2:
+                    /* Keep rnd_len from the table */
+                    if(rnd_len <= max_length) {
+                        break;
+                    }
+                    /* Fall through */
+                default:
+                    rnd_len = asn_random_between(pc->lower_bound,
+                                                 suggested_upper_bound);
+                }
+            } else {
+                rnd_len =
+                    asn_random_between(pc->lower_bound, suggested_upper_bound);
+            }
+        } else {
+            rnd_len = asn_random_between(0, max_length);
+        }
+    } else if(rnd_len > max_length) {
+        rnd_len = asn_random_between(0, max_length);
+    }
+
+    return rnd_len;
+}
+
+asn_random_fill_result_t
+OCTET_STRING_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
+                         const asn_encoding_constraints_t *constraints,
+                         size_t max_length) {
+	const asn_OCTET_STRING_specifics_t *specs = td->specifics
+				? (const asn_OCTET_STRING_specifics_t *)td->specifics
+				: &asn_SPC_OCTET_STRING_specs;
+    asn_random_fill_result_t result_ok = {ARFILL_OK, 1};
+    asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0};
+    asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};
+    unsigned int unit_bytes = 1;
+    unsigned long clb = 0;  /* Lower bound on char */
+    unsigned long cub = 255;  /* Higher bound on char value */
+    uint8_t *buf;
+    uint8_t *bend;
+    uint8_t *b;
+    size_t rnd_len;
+    OCTET_STRING_t *st;
+
+    if(max_length == 0 && !*sptr) return result_skipped;
+
+    switch(specs->subvariant) {
+    default:
+    case ASN_OSUBV_ANY:
+        return result_failed;
+    case ASN_OSUBV_BIT:
+        /* Handled by BIT_STRING itself. */
+        return result_failed;
+    case ASN_OSUBV_STR:
+        unit_bytes = 1;
+        clb = 0;
+        cub = 255;
+        break;
+    case ASN_OSUBV_U16:
+        unit_bytes = 2;
+        clb = 0;
+        cub = 65535;
+        break;
+    case ASN_OSUBV_U32:
+        unit_bytes = 4;
+        clb = 0;
+        cub = 0x10FFFF;
+        break;
+    }
+
+    if(!constraints || !constraints->per_constraints)
+        constraints = &td->encoding_constraints;
+    if(constraints->per_constraints) {
+        const asn_per_constraint_t *pc = &constraints->per_constraints->value;
+        if(pc->flags & APC_SEMI_CONSTRAINED) {
+            clb = pc->lower_bound;
+        } else if(pc->flags & APC_CONSTRAINED) {
+            clb = pc->lower_bound;
+            cub = pc->upper_bound;
+        }
+    }
+
+    rnd_len =
+        OCTET_STRING_random_length_constrained(td, constraints, max_length);
+
+    buf = CALLOC(unit_bytes, rnd_len + 1);
+    if(!buf) return result_failed;
+
+    bend = &buf[unit_bytes * rnd_len];
+
+    switch(unit_bytes) {
+    case 1:
+        for(b = buf; b < bend; b += unit_bytes) {
+            *(uint8_t *)b = OCTET_STRING__random_char(clb, cub);
+        }
+        *(uint8_t *)b = 0;
+        break;
+    case 2:
+        for(b = buf; b < bend; b += unit_bytes) {
+            uint32_t code = OCTET_STRING__random_char(clb, cub);
+            b[0] = code >> 8;
+            b[1] = code;
+        }
+        *(uint16_t *)b = 0;
+        break;
+    case 4:
+        for(b = buf; b < bend; b += unit_bytes) {
+            uint32_t code = OCTET_STRING__random_char(clb, cub);
+            b[0] = code >> 24;
+            b[1] = code >> 16;
+            b[2] = code >> 8;
+            b[3] = code;
+        }
+        *(uint32_t *)b = 0;
+        break;
+    }
+
+    if(*sptr) {
+        st = *sptr;
+        FREEMEM(st->buf);
+    } else {
+        st = (OCTET_STRING_t *)(*sptr = CALLOC(1, specs->struct_size));
+        if(!st) {
+            FREEMEM(buf);
+            return result_failed;
+        }
+    }
+
+    st->buf = buf;
+    st->size = unit_bytes * rnd_len;
+
+    result_ok.length = st->size;
+    return result_ok;
+}

+ 100 - 0
seader/lib/asn1/OCTET_STRING.h

@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 2003-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef	_OCTET_STRING_H_
+#define	_OCTET_STRING_H_
+
+#include <asn_application.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct OCTET_STRING {
+	uint8_t *buf;	/* Buffer with consecutive OCTET_STRING bits */
+	size_t size;	/* Size of the buffer */
+
+	asn_struct_ctx_t _asn_ctx;	/* Parsing across buffer boundaries */
+} OCTET_STRING_t;
+
+extern asn_TYPE_descriptor_t asn_DEF_OCTET_STRING;
+extern asn_TYPE_operation_t asn_OP_OCTET_STRING;
+
+asn_struct_free_f OCTET_STRING_free;
+asn_struct_print_f OCTET_STRING_print;
+asn_struct_print_f OCTET_STRING_print_utf8;
+asn_struct_compare_f OCTET_STRING_compare;
+ber_type_decoder_f OCTET_STRING_decode_ber;
+der_type_encoder_f OCTET_STRING_encode_der;
+xer_type_decoder_f OCTET_STRING_decode_xer_hex;		/* Hexadecimal */
+xer_type_decoder_f OCTET_STRING_decode_xer_binary;	/* 01010111010 */
+xer_type_decoder_f OCTET_STRING_decode_xer_utf8;	/* ASCII/UTF-8 */
+xer_type_encoder_f OCTET_STRING_encode_xer;
+xer_type_encoder_f OCTET_STRING_encode_xer_utf8;
+oer_type_decoder_f OCTET_STRING_decode_oer;
+oer_type_encoder_f OCTET_STRING_encode_oer;
+per_type_decoder_f OCTET_STRING_decode_uper;
+per_type_encoder_f OCTET_STRING_encode_uper;
+asn_random_fill_f  OCTET_STRING_random_fill;
+
+#define OCTET_STRING_constraint  asn_generic_no_constraint
+#define OCTET_STRING_decode_xer  OCTET_STRING_decode_xer_hex
+
+/******************************
+ * Handy conversion routines. *
+ ******************************/
+
+/*
+ * This function clears the previous value of the OCTET STRING (if any)
+ * and then allocates a new memory with the specified content (str/size).
+ * If size = -1, the size of the original string will be determined
+ * using strlen(str).
+ * If str equals to NULL, the function will silently clear the
+ * current contents of the OCTET STRING.
+ * Returns 0 if it was possible to perform operation, -1 otherwise.
+ */
+int OCTET_STRING_fromBuf(OCTET_STRING_t *s, const char *str, int size);
+
+/* Handy conversion from the C string into the OCTET STRING. */
+#define	OCTET_STRING_fromString(s, str)	OCTET_STRING_fromBuf(s, str, -1)
+
+/*
+ * Allocate and fill the new OCTET STRING and return a pointer to the newly
+ * allocated object. NULL is permitted in str: the function will just allocate
+ * empty OCTET STRING.
+ */
+OCTET_STRING_t *OCTET_STRING_new_fromBuf(const asn_TYPE_descriptor_t *td,
+                                         const char *str, int size);
+
+/****************************
+ * Internally useful stuff. *
+ ****************************/
+
+typedef struct asn_OCTET_STRING_specifics_s {
+    /*
+     * Target structure description.
+     */
+    unsigned struct_size;   /* Size of the structure */
+    unsigned ctx_offset;    /* Offset of the asn_struct_ctx_t member */
+
+    enum asn_OS_Subvariant {
+        ASN_OSUBV_ANY, /* The open type (ANY) */
+        ASN_OSUBV_BIT, /* BIT STRING */
+        ASN_OSUBV_STR, /* String types, not {BMP,Universal}String  */
+        ASN_OSUBV_U16, /* 16-bit character (BMPString) */
+        ASN_OSUBV_U32  /* 32-bit character (UniversalString) */
+    } subvariant;
+} asn_OCTET_STRING_specifics_t;
+
+extern asn_OCTET_STRING_specifics_t asn_SPC_OCTET_STRING_specs;
+
+size_t OCTET_STRING_random_length_constrained(
+    const asn_TYPE_descriptor_t *, const asn_encoding_constraints_t *,
+    size_t max_length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _OCTET_STRING_H_ */

+ 171 - 0
seader/lib/asn1/OCTET_STRING_oer.c

@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>.
+ * All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef ASN_DISABLE_OER_SUPPORT
+
+#include <asn_internal.h>
+#include <OCTET_STRING.h>
+#include <errno.h>
+
+asn_dec_rval_t
+OCTET_STRING_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
+                        const asn_TYPE_descriptor_t *td,
+                        const asn_oer_constraints_t *constraints, void **sptr,
+                        const void *ptr, size_t size) {
+    const asn_OCTET_STRING_specifics_t *specs =
+        td->specifics ? (const asn_OCTET_STRING_specifics_t *)td->specifics
+                      : &asn_SPC_OCTET_STRING_specs;
+    OCTET_STRING_t *st = (OCTET_STRING_t *)*sptr;
+    const asn_oer_constraints_t *cts =
+        constraints ? constraints : td->encoding_constraints.oer_constraints;
+    ssize_t ct_size = cts ? cts->size : -1;
+    asn_dec_rval_t rval = {RC_OK, 0};
+    size_t expected_length = 0;
+
+    size_t unit_bytes;
+    switch(specs->subvariant) {
+    default:
+    case ASN_OSUBV_BIT:
+        ASN_DEBUG("Invalid use of OCTET STRING to decode BIT STRING");
+        ASN__DECODE_FAILED;
+    case ASN_OSUBV_ANY:
+        /* Fall through */
+    case ASN_OSUBV_STR:
+        unit_bytes = 1;
+        break;
+    case ASN_OSUBV_U16:
+        unit_bytes = 2;
+        break;
+    case ASN_OSUBV_U32:
+        unit_bytes = 4;
+        break;
+    }
+
+    (void)opt_codec_ctx;
+
+    if(!st) {
+        st = (OCTET_STRING_t *)(*sptr = CALLOC(1, specs->struct_size));
+        if(!st) ASN__DECODE_FAILED;
+    }
+
+    if(ct_size >= 0) {
+        expected_length = unit_bytes * ct_size;
+    } else {
+        /*
+         * X.696 (08/2015) #27.2
+         * Encode length determinant as _number of octets_, but only
+         * if upper bound is not equal to lower bound.
+         */
+        ssize_t len_len = oer_fetch_length(ptr, size, &expected_length);
+        if(len_len > 0) {
+            rval.consumed = len_len;
+            ptr = (const char *)ptr + len_len;
+            size -= len_len;
+        } else if(len_len == 0) {
+            ASN__DECODE_STARVED;
+        } else if(len_len < 0) {
+            ASN__DECODE_FAILED;
+        }
+
+        if(expected_length % unit_bytes != 0) {
+            ASN_DEBUG(
+                "Data size %" ASN_PRI_SIZE " bytes is not consistent with multiplier %" ASN_PRI_SIZE "",
+                expected_length, unit_bytes);
+            ASN__DECODE_FAILED;
+        }
+    }
+
+    if(size < expected_length) {
+        ASN__DECODE_STARVED;
+    } else {
+        uint8_t *buf = MALLOC(expected_length + 1);
+        if(buf == NULL) {
+            ASN__DECODE_FAILED;
+        } else {
+            memcpy(buf, ptr, expected_length);
+            buf[expected_length] = '\0';
+        }
+        FREEMEM(st->buf);
+        st->buf = buf;
+        st->size = expected_length;
+
+        rval.consumed += expected_length;
+        return rval;
+    }
+}
+
+/*
+ * Encode as Canonical OER.
+ */
+asn_enc_rval_t
+OCTET_STRING_encode_oer(const asn_TYPE_descriptor_t *td,
+                        const asn_oer_constraints_t *constraints,
+                        const void *sptr, asn_app_consume_bytes_f *cb,
+                        void *app_key) {
+    const asn_OCTET_STRING_specifics_t *specs =
+        td->specifics ? (const asn_OCTET_STRING_specifics_t *)td->specifics
+                      : &asn_SPC_OCTET_STRING_specs;
+    const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
+    const asn_oer_constraints_t *cts =
+        constraints ? constraints : td->encoding_constraints.oer_constraints;
+    ssize_t ct_size = cts ? cts->size : -1;
+    asn_enc_rval_t er = {0, 0, 0};
+
+    if(!st) ASN__ENCODE_FAILED;
+
+    ASN_DEBUG("Encoding %s %" ASN_PRI_SIZE " as OCTET STRING", td ? td->name : "", st->size);
+
+    if(ct_size >= 0) {
+        /*
+         * Check that available data matches the constraint
+         */
+        size_t unit_bytes;
+        switch(specs->subvariant) {
+        default:
+        case ASN_OSUBV_BIT:
+            ASN_DEBUG("Invalid use of OCTET STRING to encode BIT STRING");
+            ASN__ENCODE_FAILED;
+        case ASN_OSUBV_ANY:
+            /* Fall through */
+        case ASN_OSUBV_STR:
+            unit_bytes = 1;
+            break;
+        case ASN_OSUBV_U16:
+            unit_bytes = 2;
+            break;
+        case ASN_OSUBV_U32:
+            unit_bytes = 4;
+            break;
+        }
+
+        if(st->size != unit_bytes * (size_t)ct_size) {
+            ASN_DEBUG(
+                "Trying to encode %s (%" ASN_PRI_SIZE " bytes) which doesn't fit SIZE "
+                "constraint (%" ASN_PRI_SIZE ")",
+                td->name, st->size, ct_size);
+            ASN__ENCODE_FAILED;
+        }
+    } else {
+        /*
+         * X.696 (08/2015) #27.2
+         * Encode length determinant as _number of octets_, but only
+         * if upper bound is not equal to lower bound.
+         */
+        ssize_t ret = oer_serialize_length(st->size, cb, app_key);
+        if(ret < 0) {
+            ASN__ENCODE_FAILED;
+        }
+        er.encoded += ret;
+    }
+
+    er.encoded += st->size;
+    if(cb(st->buf, st->size, app_key) < 0) {
+        ASN__ENCODE_FAILED;
+    } else {
+        ASN__ENCODED_OK(er);
+    }
+}
+
+#endif  /* ASN_DISABLE_OER_SUPPORT */

+ 402 - 0
seader/lib/asn1/OPEN_TYPE.c

@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <asn_internal.h>
+#include <OPEN_TYPE.h>
+#include <constr_CHOICE.h>
+#include <per_opentype.h>
+#include <errno.h>
+
+asn_TYPE_operation_t asn_OP_OPEN_TYPE = {
+	OPEN_TYPE_free,
+	OPEN_TYPE_print,
+	OPEN_TYPE_compare,
+	OPEN_TYPE_decode_ber,
+	OPEN_TYPE_encode_der,
+	OPEN_TYPE_decode_xer,
+	OPEN_TYPE_encode_xer,
+	0, 0,	/* No OER support, use "-gen-OER" to enable */
+#ifdef ASN_DISABLE_PER_SUPPORT
+	0, 0,
+#else
+	OPEN_TYPE_decode_uper,
+	OPEN_TYPE_encode_uper,
+#endif
+	0,  /* Random fill is not supported for open type */
+	0,	/* Use generic outmost tag fetcher */
+};
+
+#undef  ADVANCE
+#define ADVANCE(num_bytes)               \
+    do {                                 \
+        size_t num = num_bytes;          \
+        ptr = ((const char *)ptr) + num; \
+        size -= num;                     \
+        consumed_myself += num;          \
+    } while(0)
+
+asn_dec_rval_t
+OPEN_TYPE_ber_get(const asn_codec_ctx_t *opt_codec_ctx,
+                  const asn_TYPE_descriptor_t *td, void *sptr,
+                  const asn_TYPE_member_t *elm, const void *ptr, size_t size) {
+    size_t consumed_myself = 0;
+    asn_type_selector_result_t selected;
+    void *memb_ptr;   /* Pointer to the member */
+    void **memb_ptr2; /* Pointer to that pointer */
+    void *inner_value;
+    asn_dec_rval_t rv;
+
+    if(!(elm->flags & ATF_OPEN_TYPE)) {
+        ASN__DECODE_FAILED;
+    }
+
+    if(!elm->type_selector) {
+        ASN_DEBUG("Type selector is not defined for Open Type %s->%s->%s",
+                  td->name, elm->name, elm->type->name);
+        ASN__DECODE_FAILED;
+    }
+
+    selected = elm->type_selector(td, sptr);
+    if(!selected.presence_index) {
+        ASN__DECODE_FAILED;
+    }
+
+    /* Fetch the pointer to this member */
+    if(elm->flags & ATF_POINTER) {
+        memb_ptr2 = (void **)((char *)sptr + elm->memb_offset);
+    } else {
+        memb_ptr = (char *)sptr + elm->memb_offset;
+        memb_ptr2 = &memb_ptr;
+    }
+    if(*memb_ptr2 != NULL) {
+        /* Make sure we reset the structure first before encoding */
+        if(CHOICE_variant_set_presence(elm->type, *memb_ptr2, 0) != 0) {
+            ASN__DECODE_FAILED;
+        }
+    }
+
+    inner_value =
+        (char *)*memb_ptr2
+        + elm->type->elements[selected.presence_index - 1].memb_offset;
+
+    ASN_DEBUG("presence %d\n", selected.presence_index);
+
+    rv = selected.type_descriptor->op->ber_decoder(
+        opt_codec_ctx, selected.type_descriptor, &inner_value, ptr, size,
+        elm->tag_mode);
+    ADVANCE(rv.consumed);
+    rv.consumed = 0;
+    switch(rv.code) {
+    case RC_OK:
+        if(CHOICE_variant_set_presence(elm->type, *memb_ptr2,
+                                       selected.presence_index)
+           == 0) {
+            rv.code = RC_OK;
+            rv.consumed = consumed_myself;
+            return rv;
+        } else {
+            /* Oh, now a full-blown failure failure */
+        }
+        /* Fall through */
+    case RC_FAIL:
+        rv.consumed = consumed_myself;
+        /* Fall through */
+    case RC_WMORE:
+        break;
+    }
+
+    if(*memb_ptr2) {
+        const asn_CHOICE_specifics_t *specs =
+            selected.type_descriptor->specifics;
+        if(elm->flags & ATF_POINTER) {
+            ASN_STRUCT_FREE(*selected.type_descriptor, inner_value);
+            *memb_ptr2 = NULL;
+        } else {
+            ASN_STRUCT_FREE_CONTENTS_ONLY(*selected.type_descriptor,
+                                          inner_value);
+            memset(*memb_ptr2, 0, specs->struct_size);
+        }
+    }
+    return rv;
+}
+
+asn_dec_rval_t
+OPEN_TYPE_xer_get(const asn_codec_ctx_t *opt_codec_ctx,
+                  const asn_TYPE_descriptor_t *td, void *sptr,
+                  const asn_TYPE_member_t *elm, const void *ptr, size_t size) {
+    size_t consumed_myself = 0;
+    asn_type_selector_result_t selected;
+    void *memb_ptr;   /* Pointer to the member */
+    void **memb_ptr2; /* Pointer to that pointer */
+    void *inner_value;
+    asn_dec_rval_t rv;
+
+    int xer_context = 0;
+    ssize_t ch_size;
+    pxer_chunk_type_e ch_type;
+
+    if(!(elm->flags & ATF_OPEN_TYPE)) {
+        ASN__DECODE_FAILED;
+    }
+
+    if(!elm->type_selector) {
+        ASN_DEBUG("Type selector is not defined for Open Type %s->%s->%s",
+                  td->name, elm->name, elm->type->name);
+        ASN__DECODE_FAILED;
+    }
+
+    selected = elm->type_selector(td, sptr);
+    if(!selected.presence_index) {
+        ASN__DECODE_FAILED;
+    }
+
+    /* Fetch the pointer to this member */
+    assert(elm->flags == ATF_OPEN_TYPE);
+    if(elm->flags & ATF_POINTER) {
+        memb_ptr2 = (void **)((char *)sptr + elm->memb_offset);
+    } else {
+        memb_ptr = (char *)sptr + elm->memb_offset;
+        memb_ptr2 = &memb_ptr;
+    }
+    if(*memb_ptr2 != NULL) {
+        /* Make sure we reset the structure first before encoding */
+        if(CHOICE_variant_set_presence(elm->type, *memb_ptr2, 0)
+           != 0) {
+            ASN__DECODE_FAILED;
+        }
+    }
+
+    /*
+     * Confirm wrapper.
+     */
+    for(;;) {
+        ch_size = xer_next_token(&xer_context, ptr, size, &ch_type);
+        if(ch_size < 0) {
+            ASN__DECODE_FAILED;
+        } else {
+            switch(ch_type) {
+            case PXER_WMORE:
+                ASN__DECODE_STARVED;
+            case PXER_COMMENT:
+            case PXER_TEXT:
+                ADVANCE(ch_size);
+                continue;
+            case PXER_TAG:
+                break;
+            }
+            break;
+        }
+    }
+
+    /*
+     * Wrapper value confirmed.
+     */
+    switch(xer_check_tag(ptr, ch_size, elm->name)) {
+    case XCT_OPENING:
+        ADVANCE(ch_size);
+        break;
+    case XCT_BROKEN:
+    default:
+        ASN__DECODE_FAILED;
+    }
+
+    inner_value =
+        (char *)*memb_ptr2
+        + elm->type->elements[selected.presence_index - 1].memb_offset;
+
+    rv = selected.type_descriptor->op->xer_decoder(
+        opt_codec_ctx, selected.type_descriptor, &inner_value, NULL, ptr, size);
+    ADVANCE(rv.consumed);
+    rv.consumed = 0;
+    switch(rv.code) {
+    case RC_OK:
+        if(CHOICE_variant_set_presence(elm->type, *memb_ptr2,
+                                       selected.presence_index)
+           == 0) {
+            break;
+        } else {
+            rv.code = RC_FAIL;
+        }
+        /* Fall through */
+    case RC_FAIL:
+        /* Point to a best position where failure occurred */
+        rv.consumed = consumed_myself;
+        /* Fall through */
+    case RC_WMORE:
+        /* Wrt. rv.consumed==0:
+         * In case a genuine RC_WMORE, the whole Open Type decoding
+         * will have to be restarted.
+         */
+        if(*memb_ptr2) {
+            const asn_CHOICE_specifics_t *specs =
+                selected.type_descriptor->specifics;
+            if(elm->flags & ATF_POINTER) {
+                ASN_STRUCT_FREE(*selected.type_descriptor, inner_value);
+                *memb_ptr2 = NULL;
+            } else {
+                ASN_STRUCT_FREE_CONTENTS_ONLY(*selected.type_descriptor,
+                                              inner_value);
+                memset(*memb_ptr2, 0, specs->struct_size);
+            }
+        }
+        return rv;
+    }
+
+    /*
+     * Finalize wrapper.
+     */
+    for(;;) {
+        ch_size = xer_next_token(&xer_context, ptr, size, &ch_type);
+        if(ch_size < 0) {
+            ASN__DECODE_FAILED;
+        } else {
+            switch(ch_type) {
+            case PXER_WMORE:
+                ASN__DECODE_STARVED;
+            case PXER_COMMENT:
+            case PXER_TEXT:
+                ADVANCE(ch_size);
+                continue;
+            case PXER_TAG:
+                break;
+            }
+            break;
+        }
+    }
+
+    /*
+     * Wrapper value confirmed.
+     */
+    switch(xer_check_tag(ptr, ch_size, elm->name)) {
+    case XCT_CLOSING:
+        ADVANCE(ch_size);
+        break;
+    case XCT_BROKEN:
+    default:
+        ASN__DECODE_FAILED;
+    }
+
+    rv.consumed += consumed_myself;
+
+    return rv;
+}
+
+
+#ifndef  ASN_DISABLE_PER_SUPPORT
+
+asn_dec_rval_t
+OPEN_TYPE_uper_get(const asn_codec_ctx_t *opt_codec_ctx,
+                   const asn_TYPE_descriptor_t *td, void *sptr,
+                   const asn_TYPE_member_t *elm, asn_per_data_t *pd) {
+    asn_type_selector_result_t selected;
+    void *memb_ptr;   /* Pointer to the member */
+    void **memb_ptr2; /* Pointer to that pointer */
+    void *inner_value;
+    asn_dec_rval_t rv;
+
+    if(!(elm->flags & ATF_OPEN_TYPE)) {
+        ASN__DECODE_FAILED;
+    }
+
+    if(!elm->type_selector) {
+        ASN_DEBUG("Type selector is not defined for Open Type %s->%s->%s",
+                  td->name, elm->name, elm->type->name);
+        ASN__DECODE_FAILED;
+    }
+
+    selected = elm->type_selector(td, sptr);
+    if(!selected.presence_index) {
+        ASN__DECODE_FAILED;
+    }
+
+    /* Fetch the pointer to this member */
+    assert(elm->flags == ATF_OPEN_TYPE);
+    if(elm->flags & ATF_POINTER) {
+        memb_ptr2 = (void **)((char *)sptr + elm->memb_offset);
+    } else {
+        memb_ptr = (char *)sptr + elm->memb_offset;
+        memb_ptr2 = &memb_ptr;
+    }
+    if(*memb_ptr2 != NULL) {
+        /* Make sure we reset the structure first before encoding */
+        if(CHOICE_variant_set_presence(elm->type, *memb_ptr2, 0)
+           != 0) {
+            ASN__DECODE_FAILED;
+        }
+    }
+
+    inner_value =
+        (char *)*memb_ptr2
+        + elm->type->elements[selected.presence_index - 1].memb_offset;
+
+    rv = uper_open_type_get(opt_codec_ctx, selected.type_descriptor, NULL,
+                            &inner_value, pd);
+    switch(rv.code) {
+    case RC_OK:
+        if(CHOICE_variant_set_presence(elm->type, *memb_ptr2,
+                                       selected.presence_index)
+           == 0) {
+            break;
+        } else {
+            rv.code = RC_FAIL;
+        }
+        /* Fall through */
+    case RC_WMORE:
+    case RC_FAIL:
+        if(*memb_ptr2) {
+            const asn_CHOICE_specifics_t *specs =
+                selected.type_descriptor->specifics;
+            if(elm->flags & ATF_POINTER) {
+                ASN_STRUCT_FREE(*selected.type_descriptor, inner_value);
+                *memb_ptr2 = NULL;
+            } else {
+                ASN_STRUCT_FREE_CONTENTS_ONLY(*selected.type_descriptor,
+                                              inner_value);
+                memset(*memb_ptr2, 0, specs->struct_size);
+            }
+        }
+    }
+    return rv;
+}
+
+asn_enc_rval_t
+OPEN_TYPE_encode_uper(const asn_TYPE_descriptor_t *td,
+                      const asn_per_constraints_t *constraints,
+                      const void *sptr, asn_per_outp_t *po) {
+    const void *memb_ptr;   /* Pointer to the member */
+    asn_TYPE_member_t *elm; /* CHOICE's element */
+    asn_enc_rval_t er;
+    unsigned present;
+
+    (void)constraints;
+
+    present = CHOICE_variant_get_presence(td, sptr);
+    if(present == 0 || present > td->elements_count) {
+        ASN__ENCODE_FAILED;
+    } else {
+        present--;
+    }
+
+    ASN_DEBUG("Encoding %s OPEN TYPE element %d", td->name, present);
+
+    elm = &td->elements[present];
+    if(elm->flags & ATF_POINTER) {
+        /* Member is a pointer to another structure */
+        memb_ptr =
+            *(const void *const *)((const char *)sptr + elm->memb_offset);
+        if(!memb_ptr) ASN__ENCODE_FAILED;
+    } else {
+        memb_ptr = (const char *)sptr + elm->memb_offset;
+    }
+
+    if(uper_open_type_put(elm->type, NULL, memb_ptr, po) < 0) {
+        ASN__ENCODE_FAILED;
+    }
+
+    er.encoded = 0;
+    ASN__ENCODED_OK(er);
+}
+
+
+#endif  /* ASN_DISABLE_PER_SUPPORT */

+ 63 - 0
seader/lib/asn1/OPEN_TYPE.h

@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2017-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef ASN_OPEN_TYPE_H
+#define ASN_OPEN_TYPE_H
+
+#include <asn_application.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define OPEN_TYPE_free CHOICE_free
+#define OPEN_TYPE_print CHOICE_print
+#define OPEN_TYPE_compare CHOICE_compare
+#define OPEN_TYPE_constraint CHOICE_constraint
+#define OPEN_TYPE_decode_ber NULL
+#define OPEN_TYPE_encode_der CHOICE_encode_der
+#define OPEN_TYPE_decode_xer NULL
+#define OPEN_TYPE_encode_xer CHOICE_encode_xer
+#define OPEN_TYPE_decode_uper NULL
+
+extern asn_TYPE_operation_t asn_OP_OPEN_TYPE;
+
+/*
+ * Decode an Open Type which is potentially constraiend
+ * by the other members of the parent structure.
+ */
+asn_dec_rval_t OPEN_TYPE_ber_get(const asn_codec_ctx_t *opt_codec_ctx,
+                                 const asn_TYPE_descriptor_t *parent_type,
+                                 void *parent_structure,
+                                 const asn_TYPE_member_t *element,
+                                 const void *ptr, size_t size);
+
+asn_dec_rval_t OPEN_TYPE_xer_get(const asn_codec_ctx_t *opt_codec_ctx,
+                                 const asn_TYPE_descriptor_t *parent_type,
+                                 void *parent_structure,
+                                 const asn_TYPE_member_t *element,
+                                 const void *ptr, size_t size);
+
+asn_dec_rval_t OPEN_TYPE_oer_get(const asn_codec_ctx_t *opt_codec_ctx,
+                                 const asn_TYPE_descriptor_t *parent_type,
+                                 void *parent_structure,
+                                 asn_TYPE_member_t *element, const void *ptr,
+                                 size_t size);
+
+asn_dec_rval_t OPEN_TYPE_uper_get(const asn_codec_ctx_t *opt_codec_ctx,
+                                  const asn_TYPE_descriptor_t *parent_type,
+                                  void *parent_structure,
+                                  const asn_TYPE_member_t *element,
+                                  asn_per_data_t *pd);
+
+asn_enc_rval_t OPEN_TYPE_encode_uper(
+    const asn_TYPE_descriptor_t *type_descriptor,
+    const asn_per_constraints_t *constraints, const void *struct_ptr,
+    asn_per_outp_t *per_output);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* ASN_OPEN_TYPE_H */

+ 92 - 0
seader/lib/asn1/OPEN_TYPE_oer.c

@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <asn_internal.h>
+#include <OPEN_TYPE.h>
+#include <constr_CHOICE.h>
+#include <errno.h>
+
+asn_dec_rval_t
+OPEN_TYPE_oer_get(const asn_codec_ctx_t *opt_codec_ctx,
+                  const asn_TYPE_descriptor_t *td, void *sptr,
+                  asn_TYPE_member_t *elm, const void *ptr, size_t size) {
+    asn_type_selector_result_t selected;
+    void *memb_ptr;   /* Pointer to the member */
+    void **memb_ptr2; /* Pointer to that pointer */
+    void *inner_value;
+    asn_dec_rval_t rv;
+    size_t ot_ret;
+
+
+    if(!(elm->flags & ATF_OPEN_TYPE)) {
+        ASN__DECODE_FAILED;
+    }
+
+    if(!elm->type_selector) {
+        ASN_DEBUG("Type selector is not defined for Open Type %s->%s->%s",
+                  td->name, elm->name, elm->type->name);
+        ASN__DECODE_FAILED;
+    }
+
+    selected = elm->type_selector(td, sptr);
+    if(!selected.presence_index) {
+        ASN__DECODE_FAILED;
+    }
+
+    /* Fetch the pointer to this member */
+    if(elm->flags & ATF_POINTER) {
+        memb_ptr2 = (void **)((char *)sptr + elm->memb_offset);
+    } else {
+        memb_ptr = (char *)sptr + elm->memb_offset;
+        memb_ptr2 = &memb_ptr;
+    }
+    if(*memb_ptr2 != NULL) {
+        /* Make sure we reset the structure first before encoding */
+        if(CHOICE_variant_set_presence(elm->type, *memb_ptr2, 0) != 0) {
+            ASN__DECODE_FAILED;
+        }
+    }
+
+    inner_value =
+        (char *)*memb_ptr2
+        + elm->type->elements[selected.presence_index - 1].memb_offset;
+
+    ot_ret = oer_open_type_get(opt_codec_ctx, selected.type_descriptor, NULL,
+                               &inner_value, ptr, size);
+    switch(ot_ret) {
+    default:
+        if(CHOICE_variant_set_presence(elm->type, *memb_ptr2,
+                                       selected.presence_index)
+           == 0) {
+            rv.code = RC_OK;
+            rv.consumed = ot_ret;
+            return rv;
+        } else {
+            /* Oh, now a full-blown failure failure */
+        }
+        /* Fall through */
+    case -1:
+        rv.code = RC_FAIL;
+        rv.consumed = ot_ret;
+        break;
+    case 0:
+        rv.code = RC_WMORE;
+        rv.consumed = 0;
+        break;
+    }
+
+    if(*memb_ptr2) {
+        const asn_CHOICE_specifics_t *specs =
+            selected.type_descriptor->specifics;
+        if(elm->flags & ATF_POINTER) {
+            ASN_STRUCT_FREE(*selected.type_descriptor, inner_value);
+            *memb_ptr2 = NULL;
+        } else {
+            ASN_STRUCT_FREE_CONTENTS_ONLY(*selected.type_descriptor,
+                                          inner_value);
+            memset(*memb_ptr2, 0, specs->struct_size);
+        }
+    }
+    return rv;
+}

+ 31 - 0
seader/lib/asn1/PAC.c

@@ -0,0 +1,31 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#include "PAC.h"
+
+/*
+ * This type is implemented using BIT_STRING,
+ * so here we adjust the DEF accordingly.
+ */
+static const ber_tlv_tag_t asn_DEF_PAC_tags_1[] = {
+	(ASN_TAG_CLASS_UNIVERSAL | (3 << 2))
+};
+asn_TYPE_descriptor_t asn_DEF_PAC = {
+	"PAC",
+	"PAC",
+	&asn_OP_BIT_STRING,
+	asn_DEF_PAC_tags_1,
+	sizeof(asn_DEF_PAC_tags_1)
+		/sizeof(asn_DEF_PAC_tags_1[0]), /* 1 */
+	asn_DEF_PAC_tags_1,	/* Same as above */
+	sizeof(asn_DEF_PAC_tags_1)
+		/sizeof(asn_DEF_PAC_tags_1[0]), /* 1 */
+	{ 0, 0, BIT_STRING_constraint },
+	0, 0,	/* No members */
+	&asn_SPC_BIT_STRING_specs	/* Additional specs */
+};
+

+ 43 - 0
seader/lib/asn1/PAC.h

@@ -0,0 +1,43 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#ifndef	_PAC_H_
+#define	_PAC_H_
+
+
+#include <asn_application.h>
+
+/* Including external dependencies */
+#include <BIT_STRING.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* PAC */
+typedef BIT_STRING_t	 PAC_t;
+
+/* Implementation */
+extern asn_TYPE_descriptor_t asn_DEF_PAC;
+asn_struct_free_f PAC_free;
+asn_struct_print_f PAC_print;
+asn_constr_check_f PAC_constraint;
+ber_type_decoder_f PAC_decode_ber;
+der_type_encoder_f PAC_encode_der;
+xer_type_decoder_f PAC_decode_xer;
+xer_type_encoder_f PAC_encode_xer;
+oer_type_decoder_f PAC_decode_oer;
+oer_type_encoder_f PAC_encode_oer;
+per_type_decoder_f PAC_decode_uper;
+per_type_encoder_f PAC_encode_uper;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _PAC_H_ */
+#include <asn_internal.h>

+ 85 - 0
seader/lib/asn1/Payload.c

@@ -0,0 +1,85 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#include "Payload.h"
+
+static asn_oer_constraints_t asn_OER_type_Payload_constr_1 CC_NOTUSED = {
+	{ 0, 0 },
+	-1};
+static asn_per_constraints_t asn_PER_type_Payload_constr_1 CC_NOTUSED = {
+	{ APC_CONSTRAINED,	 2,  2,  0,  3 }	/* (0..3) */,
+	{ APC_UNCONSTRAINED,	-1, -1,  0,  0 },
+	0, 0	/* No PER value map */
+};
+static asn_TYPE_member_t asn_MBR_Payload_1[] = {
+	{ ATF_NOFLAGS, 0, offsetof(struct Payload, choice.samCommand),
+		(ASN_TAG_CLASS_CONTEXT | (0 << 2)),
+		+1,	/* EXPLICIT tag at current level */
+		&asn_DEF_SamCommand,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"samCommand"
+		},
+	{ ATF_NOFLAGS, 0, offsetof(struct Payload, choice.nfcCommand),
+		(ASN_TAG_CLASS_CONTEXT | (1 << 2)),
+		+1,	/* EXPLICIT tag at current level */
+		&asn_DEF_NFCCommand,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"nfcCommand"
+		},
+	{ ATF_NOFLAGS, 0, offsetof(struct Payload, choice.response),
+		(ASN_TAG_CLASS_CONTEXT | (29 << 2)),
+		+1,	/* EXPLICIT tag at current level */
+		&asn_DEF_Response,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"response"
+		},
+	{ ATF_NOFLAGS, 0, offsetof(struct Payload, choice.errorResponse),
+		(ASN_TAG_CLASS_CONTEXT | (30 << 2)),
+		-1,	/* IMPLICIT tag at current level */
+		&asn_DEF_ErrorResponse,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"errorResponse"
+		},
+};
+static const asn_TYPE_tag2member_t asn_MAP_Payload_tag2el_1[] = {
+    { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* samCommand */
+    { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* nfcCommand */
+    { (ASN_TAG_CLASS_CONTEXT | (29 << 2)), 2, 0, 0 }, /* response */
+    { (ASN_TAG_CLASS_CONTEXT | (30 << 2)), 3, 0, 0 } /* errorResponse */
+};
+static asn_CHOICE_specifics_t asn_SPC_Payload_specs_1 = {
+	sizeof(struct Payload),
+	offsetof(struct Payload, _asn_ctx),
+	offsetof(struct Payload, present),
+	sizeof(((struct Payload *)0)->present),
+	asn_MAP_Payload_tag2el_1,
+	4,	/* Count of tags in the map */
+	0, 0,
+	-1	/* Extensions start */
+};
+asn_TYPE_descriptor_t asn_DEF_Payload = {
+	"Payload",
+	"Payload",
+	&asn_OP_CHOICE,
+	0,	/* No effective tags (pointer) */
+	0,	/* No effective tags (count) */
+	0,	/* No tags (pointer) */
+	0,	/* No tags (count) */
+	{ &asn_OER_type_Payload_constr_1, &asn_PER_type_Payload_constr_1, CHOICE_constraint },
+	asn_MBR_Payload_1,
+	4,	/* Elements count */
+	&asn_SPC_Payload_specs_1	/* Additional specs */
+};
+

+ 56 - 0
seader/lib/asn1/Payload.h

@@ -0,0 +1,56 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#ifndef	_Payload_H_
+#define	_Payload_H_
+
+
+#include <asn_application.h>
+
+/* Including external dependencies */
+#include "SamCommand.h"
+#include "NFCCommand.h"
+#include "Response.h"
+#include "ErrorResponse.h"
+#include <constr_CHOICE.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Dependencies */
+typedef enum Payload_PR {
+	Payload_PR_NOTHING,	/* No components present */
+	Payload_PR_samCommand,
+	Payload_PR_nfcCommand,
+	Payload_PR_response,
+	Payload_PR_errorResponse
+} Payload_PR;
+
+/* Payload */
+typedef struct Payload {
+	Payload_PR present;
+	union Payload_u {
+		SamCommand_t	 samCommand;
+		NFCCommand_t	 nfcCommand;
+		Response_t	 response;
+		ErrorResponse_t	 errorResponse;
+	} choice;
+	
+	/* Context for parsing across buffer boundaries */
+	asn_struct_ctx_t _asn_ctx;
+} Payload_t;
+
+/* Implementation */
+extern asn_TYPE_descriptor_t asn_DEF_Payload;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _Payload_H_ */
+#include <asn_internal.h>

+ 31 - 0
seader/lib/asn1/Protocol.c

@@ -0,0 +1,31 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#include "Protocol.h"
+
+/*
+ * This type is implemented using OCTET_STRING,
+ * so here we adjust the DEF accordingly.
+ */
+static const ber_tlv_tag_t asn_DEF_Protocol_tags_1[] = {
+	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))
+};
+asn_TYPE_descriptor_t asn_DEF_Protocol = {
+	"Protocol",
+	"Protocol",
+	&asn_OP_OCTET_STRING,
+	asn_DEF_Protocol_tags_1,
+	sizeof(asn_DEF_Protocol_tags_1)
+		/sizeof(asn_DEF_Protocol_tags_1[0]), /* 1 */
+	asn_DEF_Protocol_tags_1,	/* Same as above */
+	sizeof(asn_DEF_Protocol_tags_1)
+		/sizeof(asn_DEF_Protocol_tags_1[0]), /* 1 */
+	{ 0, 0, OCTET_STRING_constraint },
+	0, 0,	/* No members */
+	&asn_SPC_OCTET_STRING_specs	/* Additional specs */
+};
+

+ 43 - 0
seader/lib/asn1/Protocol.h

@@ -0,0 +1,43 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#ifndef	_Protocol_H_
+#define	_Protocol_H_
+
+
+#include <asn_application.h>
+
+/* Including external dependencies */
+#include <OCTET_STRING.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Protocol */
+typedef OCTET_STRING_t	 Protocol_t;
+
+/* Implementation */
+extern asn_TYPE_descriptor_t asn_DEF_Protocol;
+asn_struct_free_f Protocol_free;
+asn_struct_print_f Protocol_print;
+asn_constr_check_f Protocol_constraint;
+ber_type_decoder_f Protocol_decode_ber;
+der_type_encoder_f Protocol_encode_der;
+xer_type_decoder_f Protocol_decode_xer;
+xer_type_encoder_f Protocol_encode_xer;
+oer_type_decoder_f Protocol_decode_oer;
+oer_type_encoder_f Protocol_encode_oer;
+per_type_decoder_f Protocol_decode_uper;
+per_type_encoder_f Protocol_encode_uper;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _Protocol_H_ */
+#include <asn_internal.h>

+ 50 - 0
seader/lib/asn1/RequestPacs.c

@@ -0,0 +1,50 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#include "RequestPacs.h"
+
+asn_TYPE_member_t asn_MBR_RequestPacs_1[] = {
+	{ ATF_NOFLAGS, 0, offsetof(struct RequestPacs, contentElementTag),
+		(ASN_TAG_CLASS_CONTEXT | (0 << 2)),
+		-1,	/* IMPLICIT tag at current level */
+		&asn_DEF_ContentElementTag,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"contentElementTag"
+		},
+};
+static const ber_tlv_tag_t asn_DEF_RequestPacs_tags_1[] = {
+	(ASN_TAG_CLASS_UNIVERSAL | (16 << 2))
+};
+static const asn_TYPE_tag2member_t asn_MAP_RequestPacs_tag2el_1[] = {
+    { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 } /* contentElementTag */
+};
+asn_SEQUENCE_specifics_t asn_SPC_RequestPacs_specs_1 = {
+	sizeof(struct RequestPacs),
+	offsetof(struct RequestPacs, _asn_ctx),
+	asn_MAP_RequestPacs_tag2el_1,
+	1,	/* Count of tags in the map */
+	0, 0, 0,	/* Optional elements (not needed) */
+	-1,	/* First extension addition */
+};
+asn_TYPE_descriptor_t asn_DEF_RequestPacs = {
+	"RequestPacs",
+	"RequestPacs",
+	&asn_OP_SEQUENCE,
+	asn_DEF_RequestPacs_tags_1,
+	sizeof(asn_DEF_RequestPacs_tags_1)
+		/sizeof(asn_DEF_RequestPacs_tags_1[0]), /* 1 */
+	asn_DEF_RequestPacs_tags_1,	/* Same as above */
+	sizeof(asn_DEF_RequestPacs_tags_1)
+		/sizeof(asn_DEF_RequestPacs_tags_1[0]), /* 1 */
+	{ 0, 0, SEQUENCE_constraint },
+	asn_MBR_RequestPacs_1,
+	1,	/* Elements count */
+	&asn_SPC_RequestPacs_specs_1	/* Additional specs */
+};
+

+ 40 - 0
seader/lib/asn1/RequestPacs.h

@@ -0,0 +1,40 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#ifndef	_RequestPacs_H_
+#define	_RequestPacs_H_
+
+
+#include <asn_application.h>
+
+/* Including external dependencies */
+#include "ContentElementTag.h"
+#include <constr_SEQUENCE.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* RequestPacs */
+typedef struct RequestPacs {
+	ContentElementTag_t	 contentElementTag;
+	
+	/* Context for parsing across buffer boundaries */
+	asn_struct_ctx_t _asn_ctx;
+} RequestPacs_t;
+
+/* Implementation */
+extern asn_TYPE_descriptor_t asn_DEF_RequestPacs;
+extern asn_SEQUENCE_specifics_t asn_SPC_RequestPacs_specs_1;
+extern asn_TYPE_member_t asn_MBR_RequestPacs_1[1];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _RequestPacs_H_ */
+#include <asn_internal.h>

+ 65 - 0
seader/lib/asn1/Response.c

@@ -0,0 +1,65 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#include "Response.h"
+
+static asn_oer_constraints_t asn_OER_type_Response_constr_1 CC_NOTUSED = {
+	{ 0, 0 },
+	-1};
+asn_per_constraints_t asn_PER_type_Response_constr_1 CC_NOTUSED = {
+	{ APC_CONSTRAINED,	 1,  1,  0,  1 }	/* (0..1) */,
+	{ APC_UNCONSTRAINED,	-1, -1,  0,  0 },
+	0, 0	/* No PER value map */
+};
+asn_TYPE_member_t asn_MBR_Response_1[] = {
+	{ ATF_NOFLAGS, 0, offsetof(struct Response, choice.nfcResponse),
+		(ASN_TAG_CLASS_CONTEXT | (0 << 2)),
+		+1,	/* EXPLICIT tag at current level */
+		&asn_DEF_NFCResponse,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"nfcResponse"
+		},
+	{ ATF_NOFLAGS, 0, offsetof(struct Response, choice.samResponse),
+		(ASN_TAG_CLASS_CONTEXT | (10 << 2)),
+		-1,	/* IMPLICIT tag at current level */
+		&asn_DEF_SamResponse,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"samResponse"
+		},
+};
+static const asn_TYPE_tag2member_t asn_MAP_Response_tag2el_1[] = {
+    { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* nfcResponse */
+    { (ASN_TAG_CLASS_CONTEXT | (10 << 2)), 1, 0, 0 } /* samResponse */
+};
+asn_CHOICE_specifics_t asn_SPC_Response_specs_1 = {
+	sizeof(struct Response),
+	offsetof(struct Response, _asn_ctx),
+	offsetof(struct Response, present),
+	sizeof(((struct Response *)0)->present),
+	asn_MAP_Response_tag2el_1,
+	2,	/* Count of tags in the map */
+	0, 0,
+	-1	/* Extensions start */
+};
+asn_TYPE_descriptor_t asn_DEF_Response = {
+	"Response",
+	"Response",
+	&asn_OP_CHOICE,
+	0,	/* No effective tags (pointer) */
+	0,	/* No effective tags (count) */
+	0,	/* No tags (pointer) */
+	0,	/* No tags (count) */
+	{ &asn_OER_type_Response_constr_1, &asn_PER_type_Response_constr_1, CHOICE_constraint },
+	asn_MBR_Response_1,
+	2,	/* Elements count */
+	&asn_SPC_Response_specs_1	/* Additional specs */
+};
+

+ 53 - 0
seader/lib/asn1/Response.h

@@ -0,0 +1,53 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#ifndef	_Response_H_
+#define	_Response_H_
+
+
+#include <asn_application.h>
+
+/* Including external dependencies */
+#include "NFCResponse.h"
+#include "SamResponse.h"
+#include <constr_CHOICE.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Dependencies */
+typedef enum Response_PR {
+	Response_PR_NOTHING,	/* No components present */
+	Response_PR_nfcResponse,
+	Response_PR_samResponse
+} Response_PR;
+
+/* Response */
+typedef struct Response {
+	Response_PR present;
+	union Response_u {
+		NFCResponse_t	 nfcResponse;
+		SamResponse_t	 samResponse;
+	} choice;
+	
+	/* Context for parsing across buffer boundaries */
+	asn_struct_ctx_t _asn_ctx;
+} Response_t;
+
+/* Implementation */
+extern asn_TYPE_descriptor_t asn_DEF_Response;
+extern asn_CHOICE_specifics_t asn_SPC_Response_specs_1;
+extern asn_TYPE_member_t asn_MBR_Response_1[2];
+extern asn_per_constraints_t asn_PER_type_Response_constr_1;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _Response_H_ */
+#include <asn_internal.h>

+ 31 - 0
seader/lib/asn1/RfStatus.c

@@ -0,0 +1,31 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#include "RfStatus.h"
+
+/*
+ * This type is implemented using OCTET_STRING,
+ * so here we adjust the DEF accordingly.
+ */
+static const ber_tlv_tag_t asn_DEF_RfStatus_tags_1[] = {
+	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))
+};
+asn_TYPE_descriptor_t asn_DEF_RfStatus = {
+	"RfStatus",
+	"RfStatus",
+	&asn_OP_OCTET_STRING,
+	asn_DEF_RfStatus_tags_1,
+	sizeof(asn_DEF_RfStatus_tags_1)
+		/sizeof(asn_DEF_RfStatus_tags_1[0]), /* 1 */
+	asn_DEF_RfStatus_tags_1,	/* Same as above */
+	sizeof(asn_DEF_RfStatus_tags_1)
+		/sizeof(asn_DEF_RfStatus_tags_1[0]), /* 1 */
+	{ 0, 0, OCTET_STRING_constraint },
+	0, 0,	/* No members */
+	&asn_SPC_OCTET_STRING_specs	/* Additional specs */
+};
+

+ 43 - 0
seader/lib/asn1/RfStatus.h

@@ -0,0 +1,43 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#ifndef	_RfStatus_H_
+#define	_RfStatus_H_
+
+
+#include <asn_application.h>
+
+/* Including external dependencies */
+#include <OCTET_STRING.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* RfStatus */
+typedef OCTET_STRING_t	 RfStatus_t;
+
+/* Implementation */
+extern asn_TYPE_descriptor_t asn_DEF_RfStatus;
+asn_struct_free_f RfStatus_free;
+asn_struct_print_f RfStatus_print;
+asn_constr_check_f RfStatus_constraint;
+ber_type_decoder_f RfStatus_decode_ber;
+der_type_encoder_f RfStatus_encode_der;
+xer_type_decoder_f RfStatus_decode_xer;
+xer_type_encoder_f RfStatus_encode_xer;
+oer_type_decoder_f RfStatus_decode_oer;
+oer_type_encoder_f RfStatus_encode_oer;
+per_type_decoder_f RfStatus_decode_uper;
+per_type_encoder_f RfStatus_encode_uper;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _RfStatus_H_ */
+#include <asn_internal.h>

+ 75 - 0
seader/lib/asn1/SamCommand.c

@@ -0,0 +1,75 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#include "SamCommand.h"
+
+static asn_oer_constraints_t asn_OER_type_SamCommand_constr_1 CC_NOTUSED = {
+	{ 0, 0 },
+	-1};
+asn_per_constraints_t asn_PER_type_SamCommand_constr_1 CC_NOTUSED = {
+	{ APC_CONSTRAINED,	 2,  2,  0,  2 }	/* (0..2) */,
+	{ APC_UNCONSTRAINED,	-1, -1,  0,  0 },
+	0, 0	/* No PER value map */
+};
+asn_TYPE_member_t asn_MBR_SamCommand_1[] = {
+	{ ATF_NOFLAGS, 0, offsetof(struct SamCommand, choice.requestPacs),
+		(ASN_TAG_CLASS_CONTEXT | (1 << 2)),
+		-1,	/* IMPLICIT tag at current level */
+		&asn_DEF_RequestPacs,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"requestPacs"
+		},
+	{ ATF_NOFLAGS, 0, offsetof(struct SamCommand, choice.version),
+		(ASN_TAG_CLASS_CONTEXT | (2 << 2)),
+		-1,	/* IMPLICIT tag at current level */
+		&asn_DEF_NULL,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"version"
+		},
+	{ ATF_NOFLAGS, 0, offsetof(struct SamCommand, choice.cardDetected),
+		(ASN_TAG_CLASS_CONTEXT | (13 << 2)),
+		-1,	/* IMPLICIT tag at current level */
+		&asn_DEF_CardDetected,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"cardDetected"
+		},
+};
+static const asn_TYPE_tag2member_t asn_MAP_SamCommand_tag2el_1[] = {
+    { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 0, 0, 0 }, /* requestPacs */
+    { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 1, 0, 0 }, /* version */
+    { (ASN_TAG_CLASS_CONTEXT | (13 << 2)), 2, 0, 0 } /* cardDetected */
+};
+asn_CHOICE_specifics_t asn_SPC_SamCommand_specs_1 = {
+	sizeof(struct SamCommand),
+	offsetof(struct SamCommand, _asn_ctx),
+	offsetof(struct SamCommand, present),
+	sizeof(((struct SamCommand *)0)->present),
+	asn_MAP_SamCommand_tag2el_1,
+	3,	/* Count of tags in the map */
+	0, 0,
+	-1	/* Extensions start */
+};
+asn_TYPE_descriptor_t asn_DEF_SamCommand = {
+	"SamCommand",
+	"SamCommand",
+	&asn_OP_CHOICE,
+	0,	/* No effective tags (pointer) */
+	0,	/* No effective tags (count) */
+	0,	/* No tags (pointer) */
+	0,	/* No tags (count) */
+	{ &asn_OER_type_SamCommand_constr_1, &asn_PER_type_SamCommand_constr_1, CHOICE_constraint },
+	asn_MBR_SamCommand_1,
+	3,	/* Elements count */
+	&asn_SPC_SamCommand_specs_1	/* Additional specs */
+};
+

+ 56 - 0
seader/lib/asn1/SamCommand.h

@@ -0,0 +1,56 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#ifndef	_SamCommand_H_
+#define	_SamCommand_H_
+
+
+#include <asn_application.h>
+
+/* Including external dependencies */
+#include "RequestPacs.h"
+#include <NULL.h>
+#include "CardDetected.h"
+#include <constr_CHOICE.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Dependencies */
+typedef enum SamCommand_PR {
+	SamCommand_PR_NOTHING,	/* No components present */
+	SamCommand_PR_requestPacs,
+	SamCommand_PR_version,
+	SamCommand_PR_cardDetected
+} SamCommand_PR;
+
+/* SamCommand */
+typedef struct SamCommand {
+	SamCommand_PR present;
+	union SamCommand_u {
+		RequestPacs_t	 requestPacs;
+		NULL_t	 version;
+		CardDetected_t	 cardDetected;
+	} choice;
+	
+	/* Context for parsing across buffer boundaries */
+	asn_struct_ctx_t _asn_ctx;
+} SamCommand_t;
+
+/* Implementation */
+extern asn_TYPE_descriptor_t asn_DEF_SamCommand;
+extern asn_CHOICE_specifics_t asn_SPC_SamCommand_specs_1;
+extern asn_TYPE_member_t asn_MBR_SamCommand_1[3];
+extern asn_per_constraints_t asn_PER_type_SamCommand_constr_1;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _SamCommand_H_ */
+#include <asn_internal.h>

+ 31 - 0
seader/lib/asn1/SamResponse.c

@@ -0,0 +1,31 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#include "SamResponse.h"
+
+/*
+ * This type is implemented using OCTET_STRING,
+ * so here we adjust the DEF accordingly.
+ */
+static const ber_tlv_tag_t asn_DEF_SamResponse_tags_1[] = {
+	(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))
+};
+asn_TYPE_descriptor_t asn_DEF_SamResponse = {
+	"SamResponse",
+	"SamResponse",
+	&asn_OP_OCTET_STRING,
+	asn_DEF_SamResponse_tags_1,
+	sizeof(asn_DEF_SamResponse_tags_1)
+		/sizeof(asn_DEF_SamResponse_tags_1[0]), /* 1 */
+	asn_DEF_SamResponse_tags_1,	/* Same as above */
+	sizeof(asn_DEF_SamResponse_tags_1)
+		/sizeof(asn_DEF_SamResponse_tags_1[0]), /* 1 */
+	{ 0, 0, OCTET_STRING_constraint },
+	0, 0,	/* No members */
+	&asn_SPC_OCTET_STRING_specs	/* Additional specs */
+};
+

+ 43 - 0
seader/lib/asn1/SamResponse.h

@@ -0,0 +1,43 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#ifndef	_SamResponse_H_
+#define	_SamResponse_H_
+
+
+#include <asn_application.h>
+
+/* Including external dependencies */
+#include <OCTET_STRING.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* SamResponse */
+typedef OCTET_STRING_t	 SamResponse_t;
+
+/* Implementation */
+extern asn_TYPE_descriptor_t asn_DEF_SamResponse;
+asn_struct_free_f SamResponse_free;
+asn_struct_print_f SamResponse_print;
+asn_constr_check_f SamResponse_constraint;
+ber_type_decoder_f SamResponse_decode_ber;
+der_type_encoder_f SamResponse_encode_der;
+xer_type_decoder_f SamResponse_decode_xer;
+xer_type_encoder_f SamResponse_encode_xer;
+oer_type_decoder_f SamResponse_decode_oer;
+oer_type_encoder_f SamResponse_encode_oer;
+per_type_decoder_f SamResponse_decode_uper;
+per_type_encoder_f SamResponse_encode_uper;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _SamResponse_H_ */
+#include <asn_internal.h>

+ 70 - 0
seader/lib/asn1/SamVersion.c

@@ -0,0 +1,70 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#include "SamVersion.h"
+
+static asn_TYPE_member_t asn_MBR_SamVersion_1[] = {
+	{ ATF_NOFLAGS, 0, offsetof(struct SamVersion, version),
+		(ASN_TAG_CLASS_CONTEXT | (0 << 2)),
+		-1,	/* IMPLICIT tag at current level */
+		&asn_DEF_OCTET_STRING,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"version"
+		},
+	{ ATF_NOFLAGS, 0, offsetof(struct SamVersion, firmware),
+		(ASN_TAG_CLASS_CONTEXT | (1 << 2)),
+		-1,	/* IMPLICIT tag at current level */
+		&asn_DEF_OCTET_STRING,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"firmware"
+		},
+	{ ATF_NOFLAGS, 0, offsetof(struct SamVersion, type),
+		(ASN_TAG_CLASS_CONTEXT | (2 << 2)),
+		-1,	/* IMPLICIT tag at current level */
+		&asn_DEF_OCTET_STRING,
+		0,
+		{ 0, 0, 0 },
+		0, 0, /* No default value */
+		"type"
+		},
+};
+static const ber_tlv_tag_t asn_DEF_SamVersion_tags_1[] = {
+	(ASN_TAG_CLASS_UNIVERSAL | (16 << 2))
+};
+static const asn_TYPE_tag2member_t asn_MAP_SamVersion_tag2el_1[] = {
+    { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* version */
+    { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* firmware */
+    { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* type */
+};
+static asn_SEQUENCE_specifics_t asn_SPC_SamVersion_specs_1 = {
+	sizeof(struct SamVersion),
+	offsetof(struct SamVersion, _asn_ctx),
+	asn_MAP_SamVersion_tag2el_1,
+	3,	/* Count of tags in the map */
+	0, 0, 0,	/* Optional elements (not needed) */
+	-1,	/* First extension addition */
+};
+asn_TYPE_descriptor_t asn_DEF_SamVersion = {
+	"SamVersion",
+	"SamVersion",
+	&asn_OP_SEQUENCE,
+	asn_DEF_SamVersion_tags_1,
+	sizeof(asn_DEF_SamVersion_tags_1)
+		/sizeof(asn_DEF_SamVersion_tags_1[0]), /* 1 */
+	asn_DEF_SamVersion_tags_1,	/* Same as above */
+	sizeof(asn_DEF_SamVersion_tags_1)
+		/sizeof(asn_DEF_SamVersion_tags_1[0]), /* 1 */
+	{ 0, 0, SEQUENCE_constraint },
+	asn_MBR_SamVersion_1,
+	3,	/* Elements count */
+	&asn_SPC_SamVersion_specs_1	/* Additional specs */
+};
+

+ 40 - 0
seader/lib/asn1/SamVersion.h

@@ -0,0 +1,40 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Seader"
+ * 	found in "seader.asn1"
+ * 	`asn1c -D ./lib/asn1 -no-gen-example -pdu=all`
+ */
+
+#ifndef	_SamVersion_H_
+#define	_SamVersion_H_
+
+
+#include <asn_application.h>
+
+/* Including external dependencies */
+#include <OCTET_STRING.h>
+#include <constr_SEQUENCE.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* SamVersion */
+typedef struct SamVersion {
+	OCTET_STRING_t	 version;
+	OCTET_STRING_t	 firmware;
+	OCTET_STRING_t	 type;
+	
+	/* Context for parsing across buffer boundaries */
+	asn_struct_ctx_t _asn_ctx;
+} SamVersion_t;
+
+/* Implementation */
+extern asn_TYPE_descriptor_t asn_DEF_SamVersion;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _SamVersion_H_ */
+#include <asn_internal.h>

+ 440 - 0
seader/lib/asn1/asn_application.c

@@ -0,0 +1,440 @@
+/*
+ * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <asn_internal.h>
+#include <asn_application.h>
+#include <errno.h>
+
+static asn_enc_rval_t asn_encode_internal(const asn_codec_ctx_t *opt_codec_ctx,
+                                          enum asn_transfer_syntax syntax,
+                                          const asn_TYPE_descriptor_t *td,
+                                          const void *sptr,
+                                          asn_app_consume_bytes_f *callback,
+                                          void *callback_key);
+
+
+struct callback_count_bytes_key {
+    asn_app_consume_bytes_f *callback;
+    void *callback_key;
+    size_t computed_size;
+};
+
+/*
+ * Encoder which just counts bytes that come through it.
+ */
+static int
+callback_count_bytes_cb(const void *data, size_t size, void *keyp) {
+    struct callback_count_bytes_key *key = keyp;
+    int ret;
+
+    ret = key->callback(data, size, key->callback_key);
+    if(ret >= 0) {
+        key->computed_size += size;
+    }
+
+    return ret;
+}
+
+struct overrun_encoder_key {
+    void *buffer;
+    size_t buffer_size;
+    size_t computed_size;
+};
+
+struct dynamic_encoder_key {
+    void *buffer;
+    size_t buffer_size;
+    size_t computed_size;
+};
+
+struct callback_failure_catch_key {
+    asn_app_consume_bytes_f *callback;
+    void *callback_key;
+    int callback_failed;
+};
+
+/*
+ * Encoder which doesn't stop counting bytes
+ * even if it reaches the end of the buffer.
+ */
+static int
+overrun_encoder_cb(const void *data, size_t size, void *keyp) {
+    struct overrun_encoder_key *key = keyp;
+
+    if(key->computed_size + size > key->buffer_size) {
+        /*
+         * Avoid accident on the next call:
+         * stop adding bytes to the buffer.
+         */
+        key->buffer_size = 0;
+    } else {
+        memcpy((char *)key->buffer + key->computed_size, data, size);
+    }
+    key->computed_size += size;
+
+    return 0;
+}
+
+/*
+ * Encoder which dynamically allocates output, and continues
+ * to count even if allocation failed.
+ */
+static int
+dynamic_encoder_cb(const void *data, size_t size, void *keyp) {
+    struct dynamic_encoder_key *key = keyp;
+
+    if(key->buffer) {
+        if(key->computed_size + size >= key->buffer_size) {
+            void *p;
+            size_t new_size = key->buffer_size;
+
+            do {
+                new_size *= 2;
+            } while(new_size <= key->computed_size + size);
+
+            p = REALLOC(key->buffer, new_size);
+            if(p) {
+                key->buffer = p;
+                key->buffer_size = new_size;
+            } else {
+                FREEMEM(key->buffer);
+                key->buffer = 0;
+                key->buffer_size = 0;
+                key->computed_size += size;
+                return 0;
+            }
+        }
+        memcpy((char *)key->buffer + key->computed_size, data, size);
+    }
+
+    key->computed_size += size;
+
+    return 0;
+}
+
+/*
+ * Encoder which help convert the application level encoder failure into EIO.
+ */
+static int
+callback_failure_catch_cb(const void *data, size_t size, void *keyp) {
+    struct callback_failure_catch_key *key = keyp;
+    int ret;
+
+    ret = key->callback(data, size, key->callback_key);
+    if(ret < 0) {
+        key->callback_failed = 1;
+    }
+
+    return ret;
+}
+
+asn_enc_rval_t
+asn_encode(const asn_codec_ctx_t *opt_codec_ctx,
+           enum asn_transfer_syntax syntax, const asn_TYPE_descriptor_t *td,
+           const void *sptr, asn_app_consume_bytes_f *callback, void *callback_key) {
+    struct callback_failure_catch_key cb_key;
+    asn_enc_rval_t er;
+
+    if(!callback) {
+        errno = EINVAL;
+        ASN__ENCODE_FAILED;
+    }
+
+    cb_key.callback = callback;
+    cb_key.callback_key = callback_key;
+    cb_key.callback_failed = 0;
+
+    er = asn_encode_internal(opt_codec_ctx, syntax, td, sptr,
+                             callback_failure_catch_cb, &cb_key);
+    if(cb_key.callback_failed) {
+        assert(er.encoded == -1);
+        assert(errno == EBADF);
+        errno = EIO;
+    }
+
+    return er;
+}
+
+asn_enc_rval_t
+asn_encode_to_buffer(const asn_codec_ctx_t *opt_codec_ctx,
+                     enum asn_transfer_syntax syntax,
+                     const asn_TYPE_descriptor_t *td, const void *sptr,
+                     void *buffer, size_t buffer_size) {
+    struct overrun_encoder_key buf_key;
+    asn_enc_rval_t er;
+
+    if(buffer_size > 0 && !buffer) {
+        errno = EINVAL;
+        ASN__ENCODE_FAILED;
+    }
+
+    buf_key.buffer = buffer;
+    buf_key.buffer_size = buffer_size;
+    buf_key.computed_size = 0;
+
+    er = asn_encode_internal(opt_codec_ctx, syntax, td, sptr,
+                             overrun_encoder_cb, &buf_key);
+
+    if(er.encoded >= 0 && (size_t)er.encoded != buf_key.computed_size) {
+        ASN_DEBUG("asn_encode() returned %" ASN_PRI_SSIZE
+                  " yet produced %" ASN_PRI_SIZE " bytes",
+                  er.encoded, buf_key.computed_size);
+        assert(er.encoded < 0 || (size_t)er.encoded == buf_key.computed_size);
+    }
+
+    return er;
+}
+
+asn_encode_to_new_buffer_result_t
+asn_encode_to_new_buffer(const asn_codec_ctx_t *opt_codec_ctx,
+                         enum asn_transfer_syntax syntax,
+                         const asn_TYPE_descriptor_t *td, const void *sptr) {
+    struct dynamic_encoder_key buf_key;
+    asn_encode_to_new_buffer_result_t res;
+
+    buf_key.buffer_size = 16;
+    buf_key.buffer = MALLOC(buf_key.buffer_size);
+    buf_key.computed_size = 0;
+
+    res.result = asn_encode_internal(opt_codec_ctx, syntax, td, sptr,
+                                     dynamic_encoder_cb, &buf_key);
+
+    if(res.result.encoded >= 0
+       && (size_t)res.result.encoded != buf_key.computed_size) {
+        ASN_DEBUG("asn_encode() returned %" ASN_PRI_SSIZE
+                  " yet produced %" ASN_PRI_SIZE " bytes",
+                  res.result.encoded, buf_key.computed_size);
+        assert(res.result.encoded < 0
+               || (size_t)res.result.encoded == buf_key.computed_size);
+    }
+
+    res.buffer = buf_key.buffer;
+
+    /* 0-terminate just in case. */
+    if(res.buffer) {
+        assert(buf_key.computed_size < buf_key.buffer_size);
+        ((char *)res.buffer)[buf_key.computed_size] = '\0';
+    }
+
+    return res;
+}
+
+static asn_enc_rval_t
+asn_encode_internal(const asn_codec_ctx_t *opt_codec_ctx,
+                    enum asn_transfer_syntax syntax,
+                    const asn_TYPE_descriptor_t *td, const void *sptr,
+                    asn_app_consume_bytes_f *callback, void *callback_key) {
+    asn_enc_rval_t er;
+    enum xer_encoder_flags_e xer_flags = XER_F_CANONICAL;
+
+    (void)opt_codec_ctx; /* Parameters are not checked on encode yet. */
+
+    if(!td || !sptr) {
+        errno = EINVAL;
+        ASN__ENCODE_FAILED;
+    }
+
+    switch(syntax) {
+    case ATS_NONSTANDARD_PLAINTEXT:
+        if(td->op->print_struct) {
+            struct callback_count_bytes_key cb_key;
+            cb_key.callback = callback;
+            cb_key.callback_key = callback_key;
+            cb_key.computed_size = 0;
+            if(td->op->print_struct(td, sptr, 1, callback_count_bytes_cb,
+                                    &cb_key)
+                   < 0
+               || callback_count_bytes_cb("\n", 1, &cb_key) < 0) {
+                errno = EBADF; /* Structure has incorrect form. */
+                er.encoded = -1;
+                er.failed_type = td;
+                er.structure_ptr = sptr;
+            } else {
+                er.encoded = cb_key.computed_size;
+                er.failed_type = 0;
+                er.structure_ptr = 0;
+            }
+        } else {
+            errno = ENOENT; /* Transfer syntax is not defined for this type. */
+            ASN__ENCODE_FAILED;
+        }
+        break;
+
+    case ATS_RANDOM:
+        errno = ENOENT; /* Randomization doesn't make sense on output. */
+        ASN__ENCODE_FAILED;
+
+    case ATS_BER:
+        /* BER is a superset of DER. */
+        /* Fall through. */
+    case ATS_DER:
+        if(td->op->der_encoder) {
+            er = der_encode(td, sptr, callback, callback_key);
+            if(er.encoded == -1) {
+                if(er.failed_type && er.failed_type->op->der_encoder) {
+                    errno = EBADF;  /* Structure has incorrect form. */
+                } else {
+                    errno = ENOENT; /* DER is not defined for this type. */
+                }
+            }
+        } else {
+            errno = ENOENT; /* Transfer syntax is not defined for this type. */
+            ASN__ENCODE_FAILED;
+        }
+        break;
+    case ATS_CER:
+        errno = ENOENT; /* Transfer syntax is not defined for any type. */
+        ASN__ENCODE_FAILED;
+
+#ifdef  ASN_DISABLE_OER_SUPPORT
+    case ATS_BASIC_OER:
+    case ATS_CANONICAL_OER:
+        errno = ENOENT; /* PER is not defined. */
+        ASN__ENCODE_FAILED;
+        break;
+#else /* ASN_DISABLE_OER_SUPPORT */
+    case ATS_BASIC_OER:
+        /* CANONICAL-OER is a superset of BASIC-OER. */
+        /* Fall through. */
+    case ATS_CANONICAL_OER:
+        if(td->op->oer_encoder) {
+            er = oer_encode(td, sptr, callback, callback_key);
+            if(er.encoded == -1) {
+                if(er.failed_type && er.failed_type->op->oer_encoder) {
+                    errno = EBADF;  /* Structure has incorrect form. */
+                } else {
+                    errno = ENOENT; /* OER is not defined for this type. */
+                }
+            }
+        } else {
+            errno = ENOENT; /* Transfer syntax is not defined for this type. */
+            ASN__ENCODE_FAILED;
+        }
+        break;
+#endif /* ASN_DISABLE_OER_SUPPORT */
+
+#ifdef  ASN_DISABLE_PER_SUPPORT
+    case ATS_UNALIGNED_BASIC_PER:
+    case ATS_UNALIGNED_CANONICAL_PER:
+        errno = ENOENT; /* PER is not defined. */
+        ASN__ENCODE_FAILED;
+        break;
+#else /* ASN_DISABLE_PER_SUPPORT */
+    case ATS_UNALIGNED_BASIC_PER:
+        /* CANONICAL-UPER is a superset of BASIC-UPER. */
+        /* Fall through. */
+    case ATS_UNALIGNED_CANONICAL_PER:
+        if(td->op->uper_encoder) {
+            er = uper_encode(td, 0, sptr, callback, callback_key);
+            if(er.encoded == -1) {
+                if(er.failed_type && er.failed_type->op->uper_encoder) {
+                    errno = EBADF;  /* Structure has incorrect form. */
+                } else {
+                    errno = ENOENT; /* UPER is not defined for this type. */
+                }
+            } else {
+                ASN_DEBUG("Complete encoded in %ld bits", (long)er.encoded);
+                if(er.encoded == 0) {
+                    /* Enforce "Complete Encoding" of X.691 #11.1 */
+                    if(callback("\0", 1, callback_key) < 0) {
+                        errno = EBADF;
+                        ASN__ENCODE_FAILED;
+                    }
+                    er.encoded = 8; /* Exactly 8 zero bits is added. */
+                }
+                /* Convert bits into bytes */
+                er.encoded = (er.encoded + 7) >> 3;
+            }
+        } else {
+            errno = ENOENT; /* Transfer syntax is not defined for this type. */
+            ASN__ENCODE_FAILED;
+        }
+        break;
+#endif  /* ASN_DISABLE_PER_SUPPORT */
+
+    case ATS_BASIC_XER:
+        /* CANONICAL-XER is a superset of BASIC-XER. */
+        xer_flags &= ~XER_F_CANONICAL;
+        xer_flags |= XER_F_BASIC;
+        /* Fall through. */
+    case ATS_CANONICAL_XER:
+        if(td->op->xer_encoder) {
+            er = xer_encode(td, sptr, xer_flags, callback, callback_key);
+            if(er.encoded == -1) {
+                if(er.failed_type && er.failed_type->op->xer_encoder) {
+                    errno = EBADF;  /* Structure has incorrect form. */
+                } else {
+                    errno = ENOENT; /* XER is not defined for this type. */
+                }
+            }
+        } else {
+            errno = ENOENT; /* Transfer syntax is not defined for this type. */
+            ASN__ENCODE_FAILED;
+        }
+        break;
+
+    default:
+        errno = ENOENT;
+        ASN__ENCODE_FAILED;
+    }
+
+    return er;
+}
+
+asn_dec_rval_t
+asn_decode(const asn_codec_ctx_t *opt_codec_ctx,
+           enum asn_transfer_syntax syntax, const asn_TYPE_descriptor_t *td,
+           void **sptr, const void *buffer, size_t size) {
+    if(!td || !td->op || !sptr || (size && !buffer)) {
+        ASN__DECODE_FAILED;
+    }
+
+    switch(syntax) {
+    case ATS_CER:
+    case ATS_NONSTANDARD_PLAINTEXT:
+    default:
+        errno = ENOENT;
+        ASN__DECODE_FAILED;
+
+    case ATS_RANDOM:
+        if(!td->op->random_fill) {
+            ASN__DECODE_FAILED;
+        } else {
+            if(asn_random_fill(td, sptr, 16000) == 0) {
+                asn_dec_rval_t ret = {RC_OK, 0};
+                return ret;
+            } else {
+                ASN__DECODE_FAILED;
+            }
+        }
+        break;
+
+    case ATS_DER:
+    case ATS_BER:
+        return ber_decode(opt_codec_ctx, td, sptr, buffer, size);
+
+    case ATS_BASIC_OER:
+    case ATS_CANONICAL_OER:
+#ifdef  ASN_DISABLE_OER_SUPPORT
+        errno = ENOENT;
+        ASN__DECODE_FAILED;
+#else
+        return oer_decode(opt_codec_ctx, td, sptr, buffer, size);
+#endif
+
+    case ATS_UNALIGNED_BASIC_PER:
+    case ATS_UNALIGNED_CANONICAL_PER:
+#ifdef  ASN_DISABLE_PER_SUPPORT
+        errno = ENOENT;
+        ASN__DECODE_FAILED;
+#else
+        return uper_decode_complete(opt_codec_ctx, td, sptr, buffer, size);
+#endif
+
+    case ATS_BASIC_XER:
+    case ATS_CANONICAL_XER:
+        return xer_decode(opt_codec_ctx, td, sptr, buffer, size);
+    }
+}
+

+ 169 - 0
seader/lib/asn1/asn_application.h

@@ -0,0 +1,169 @@
+/*-
+ * Copyright (c) 2004-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+/*
+ * Application-level ASN.1 callbacks.
+ */
+#ifndef	ASN_APPLICATION_H
+#define	ASN_APPLICATION_H
+
+#include "asn_system.h"		/* for platform-dependent types */
+#include "asn_codecs.h"		/* for ASN.1 codecs specifics */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * A selection of ASN.1 Transfer Syntaxes to use with generalized
+ * encoders and decoders declared further in this .h file.
+ */
+enum asn_transfer_syntax {
+    /* Avoid appearance of a default transfer syntax. */
+    ATS_INVALID = 0,
+    /* Plaintext output (not conforming to any standard), for debugging. */
+    ATS_NONSTANDARD_PLAINTEXT,
+    /* Returns a randomly generatede structure. */
+    ATS_RANDOM,
+    /*
+     * X.690:
+     * BER: Basic Encoding Rules.
+     * DER: Distinguished Encoding Rules.
+     * CER: Canonical Encoding Rules.
+     * DER and CER are more strict variants of BER.
+     */
+    ATS_BER,
+    ATS_DER,
+    ATS_CER, /* Only decoding is supported */
+    /*
+     * X.696:
+     * OER: Octet Encoding Rules.
+     * CANONICAL-OER is a more strict variant of BASIC-OER.
+     */
+    ATS_BASIC_OER,
+    ATS_CANONICAL_OER,
+    /*
+     * X.691:
+     * PER: Packed Encoding Rules.
+     * CANONICAL-PER is a more strict variant of BASIC-PER.
+     * NOTE: Produces or consumes a complete encoding (X.691 (08/2015) #11.1).
+     */
+    ATS_UNALIGNED_BASIC_PER,
+    ATS_UNALIGNED_CANONICAL_PER,
+    /*
+     * X.693:
+     * XER: XML Encoding Rules.
+     * CANONICAL-XER is a more strict variant of BASIC-XER.
+     */
+    ATS_BASIC_XER,
+    ATS_CANONICAL_XER
+};
+
+/*
+ * A generic encoder for any supported transfer syntax.
+ * RETURN VALUES:
+ * The (.encoded) field of the return value is REDEFINED to mean the following:
+ * >=0: The computed size of the encoded data. Can exceed the (buffer_size).
+ *  -1: Error encoding the structure. See the error code in (errno):
+ *      EINVAL: Incorrect parameters to the function, such as NULLs.
+ *      ENOENT: Encoding transfer syntax is not defined (for this type).
+ *      EBADF:  The structure has invalid form or content constraint failed.
+ *      The (.failed_type) and (.structure_ptr) MIGHT be set to the appropriate
+ *      values at the place of failure, if at all possible.
+ * WARNING: The (.encoded) field of the return value can exceed the buffer_size.
+ * This is similar to snprintf(3) contract which might return values
+ * greater than the buffer size.
+ */
+asn_enc_rval_t asn_encode_to_buffer(
+    const asn_codec_ctx_t *opt_codec_parameters, /* See asn_codecs.h */
+    enum asn_transfer_syntax,
+    const struct asn_TYPE_descriptor_s *type_to_encode,
+    const void *structure_to_encode, void *buffer, size_t buffer_size);
+
+/*
+ * A variant of asn_encode_to_buffer() with automatically allocated buffer.
+ * RETURN VALUES:
+ * On success, returns a newly allocated (.buffer) containing the whole message.
+ * The message size is returned in (.result.encoded).
+ * On failure:
+ *  (.buffer) is NULL,
+ *  (.result.encoded) as in asn_encode_to_buffer(),
+ *  The errno codes as in asn_encode_to_buffer(), plus the following:
+ *      ENOMEM: Memory allocation failed due to system or internal limits.
+ * The user is responsible for freeing the (.buffer).
+ */
+typedef struct asn_encode_to_new_buffer_result_s {
+    void *buffer;   /* NULL if failed to encode. */
+    asn_enc_rval_t result;
+} asn_encode_to_new_buffer_result_t;
+asn_encode_to_new_buffer_result_t asn_encode_to_new_buffer(
+    const asn_codec_ctx_t *opt_codec_parameters, /* See asn_codecs.h */
+    enum asn_transfer_syntax,
+    const struct asn_TYPE_descriptor_s *type_to_encode,
+    const void *structure_to_encode);
+
+
+/*
+ * Generic type of an application-defined callback to return various
+ * types of data to the application.
+ * EXPECTED RETURN VALUES:
+ *  -1: Failed to consume bytes. Abort the mission.
+ * Non-negative return values indicate success, and ignored.
+ */
+typedef int(asn_app_consume_bytes_f)(const void *buffer, size_t size,
+                                     void *application_specific_key);
+
+
+/*
+ * A generic encoder for any supported transfer syntax.
+ * Returns the comprehensive encoding result descriptor (see asn_codecs.h).
+ * RETURN VALUES:
+ * The negative (.encoded) field of the return values is accompanied with the
+ * following error codes (errno):
+ *      EINVAL: Incorrect parameters to the function, such as NULLs.
+ *      ENOENT: Encoding transfer syntax is not defined (for this type).
+ *      EBADF:  The structure has invalid form or content constraint failed.
+ *      EIO:    The (callback) has returned negative value during encoding.
+ */
+asn_enc_rval_t asn_encode(
+    const asn_codec_ctx_t *opt_codec_parameters, /* See asn_codecs.h */
+    enum asn_transfer_syntax,
+    const struct asn_TYPE_descriptor_s *type_to_encode,
+    const void *structure_to_encode,
+    asn_app_consume_bytes_f *callback, void *callback_key);
+
+
+/*
+ * A generic decoder for any supported transfer syntax.
+ */
+asn_dec_rval_t asn_decode(
+    const asn_codec_ctx_t *opt_codec_parameters, enum asn_transfer_syntax,
+    const struct asn_TYPE_descriptor_s *type_to_decode,
+    void **structure_ptr, /* Pointer to a target structure's pointer */
+    const void *buffer,   /* Data to be decoded */
+    size_t size           /* Size of that buffer */
+);
+
+
+/*
+ * A callback of this type is called whenever constraint validation fails
+ * on some ASN.1 type. See "constraints.h" for more details on constraint
+ * validation.
+ * This callback specifies a descriptor of the ASN.1 type which failed
+ * the constraint check, as well as human readable message on what
+ * particular constraint has failed.
+ */
+typedef void (asn_app_constraint_failed_f)(void *application_specific_key,
+	const struct asn_TYPE_descriptor_s *type_descriptor_which_failed,
+	const void *structure_which_failed_ptr,
+	const char *error_message_format, ...) CC_PRINTFLIKE(4, 5);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#include "constr_TYPE.h"	/* for asn_TYPE_descriptor_t */
+
+#endif	/* ASN_APPLICATION_H */

+ 333 - 0
seader/lib/asn1/asn_bit_data.c

@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 2005-2017 Lev Walkin <vlm@lionet.info>.
+ * All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <asn_system.h>
+#include <asn_internal.h>
+#include <asn_bit_data.h>
+
+/*
+ * Create a contiguous non-refillable bit data structure.
+ * Can be freed by FREEMEM().
+ */
+asn_bit_data_t *
+asn_bit_data_new_contiguous(const void *data, size_t size_bits) {
+    size_t size_bytes = (size_bits + 7) / 8;
+    asn_bit_data_t *pd;
+    uint8_t *bytes;
+
+    /* Get the extensions map */
+    pd = CALLOC(1, sizeof(*pd) + size_bytes + 1);
+    if(!pd) {
+        return NULL;
+    }
+    bytes = (void *)(((char *)pd) + sizeof(*pd));
+    memcpy(bytes, data, size_bytes);
+    bytes[size_bytes] = 0;
+    pd->buffer = bytes;
+    pd->nboff = 0;
+    pd->nbits = size_bits;
+
+    return pd;
+}
+
+
+char *
+asn_bit_data_string(asn_bit_data_t *pd) {
+	static char buf[2][32];
+	static int n;
+	n = (n+1) % 2;
+    snprintf(buf[n], sizeof(buf[n]),
+             "{m=%" ASN_PRI_SIZE " span %" ASN_PRI_SIZE "[%" ASN_PRI_SIZE
+             "..%" ASN_PRI_SIZE "] (%" ASN_PRI_SIZE ")}",
+             pd->moved, ((uintptr_t)(pd->buffer) & 0xf), pd->nboff, pd->nbits,
+             pd->nbits - pd->nboff);
+    return buf[n];
+}
+
+void
+asn_get_undo(asn_bit_data_t *pd, int nbits) {
+	if((ssize_t)pd->nboff < nbits) {
+		assert((ssize_t)pd->nboff < nbits);
+	} else {
+		pd->nboff -= nbits;
+		pd->moved -= nbits;
+	}
+}
+
+/*
+ * Extract a small number of bits (<= 31) from the specified PER data pointer.
+ */
+int32_t
+asn_get_few_bits(asn_bit_data_t *pd, int nbits) {
+	size_t off;	/* Next after last bit offset */
+	ssize_t nleft;	/* Number of bits left in this stream */
+	uint32_t accum;
+	const uint8_t *buf;
+
+	if(nbits < 0)
+		return -1;
+
+	nleft = pd->nbits - pd->nboff;
+	if(nbits > nleft) {
+		int32_t tailv, vhead;
+		if(!pd->refill || nbits > 31) return -1;
+		/* Accumulate unused bytes before refill */
+		ASN_DEBUG("Obtain the rest %d bits (want %d)",
+			(int)nleft, (int)nbits);
+		tailv = asn_get_few_bits(pd, nleft);
+		if(tailv < 0) return -1;
+		/* Refill (replace pd contents with new data) */
+		if(pd->refill(pd))
+			return -1;
+		nbits -= nleft;
+		vhead = asn_get_few_bits(pd, nbits);
+		/* Combine the rest of previous pd with the head of new one */
+		tailv = (tailv << nbits) | vhead;  /* Could == -1 */
+		return tailv;
+	}
+
+	/*
+	 * Normalize position indicator.
+	 */
+	if(pd->nboff >= 8) {
+		pd->buffer += (pd->nboff >> 3);
+		pd->nbits  -= (pd->nboff & ~0x07);
+		pd->nboff  &= 0x07;
+	}
+	pd->moved += nbits;
+	pd->nboff += nbits;
+	off = pd->nboff;
+	buf = pd->buffer;
+
+	/*
+	 * Extract specified number of bits.
+	 */
+	if(off <= 8)
+		accum = nbits ? (buf[0]) >> (8 - off) : 0;
+	else if(off <= 16)
+		accum = ((buf[0] << 8) + buf[1]) >> (16 - off);
+	else if(off <= 24)
+		accum = ((buf[0] << 16) + (buf[1] << 8) + buf[2]) >> (24 - off);
+	else if(off <= 31)
+		accum = (((uint32_t)buf[0] << 24) + (buf[1] << 16)
+			+ (buf[2] << 8) + (buf[3])) >> (32 - off);
+	else if(nbits <= 31) {
+		asn_bit_data_t tpd = *pd;
+		/* Here are we with our 31-bits limit plus 1..7 bits offset. */
+		asn_get_undo(&tpd, nbits);
+		/* The number of available bits in the stream allow
+		 * for the following operations to take place without
+		 * invoking the ->refill() function */
+		accum  = asn_get_few_bits(&tpd, nbits - 24) << 24;
+		accum |= asn_get_few_bits(&tpd, 24);
+	} else {
+		asn_get_undo(pd, nbits);
+		return -1;
+	}
+
+	accum &= (((uint32_t)1 << nbits) - 1);
+
+	ASN_DEBUG("  [PER got %2d<=%2d bits => span %d %+ld[%d..%d]:%02x (%d) => 0x%x]",
+		(int)nbits, (int)nleft,
+		(int)pd->moved,
+		(((long)pd->buffer) & 0xf),
+		(int)pd->nboff, (int)pd->nbits,
+		((pd->buffer != NULL)?pd->buffer[0]:0),
+		(int)(pd->nbits - pd->nboff),
+		(int)accum);
+
+	return accum;
+}
+
+/*
+ * Extract a large number of bits from the specified PER data pointer.
+ */
+int
+asn_get_many_bits(asn_bit_data_t *pd, uint8_t *dst, int alright, int nbits) {
+	int32_t value;
+
+	if(alright && (nbits & 7)) {
+		/* Perform right alignment of a first few bits */
+		value = asn_get_few_bits(pd, nbits & 0x07);
+		if(value < 0) return -1;
+		*dst++ = value;	/* value is already right-aligned */
+		nbits &= ~7;
+	}
+
+	while(nbits) {
+		if(nbits >= 24) {
+			value = asn_get_few_bits(pd, 24);
+			if(value < 0) return -1;
+			*(dst++) = value >> 16;
+			*(dst++) = value >> 8;
+			*(dst++) = value;
+			nbits -= 24;
+		} else {
+			value = asn_get_few_bits(pd, nbits);
+			if(value < 0) return -1;
+			if(nbits & 7) {	/* implies left alignment */
+				value <<= 8 - (nbits & 7),
+				nbits += 8 - (nbits & 7);
+				if(nbits > 24)
+					*dst++ = value >> 24;
+			}
+			if(nbits > 16)
+				*dst++ = value >> 16;
+			if(nbits > 8)
+				*dst++ = value >> 8;
+			*dst++ = value;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Put a small number of bits (<= 31).
+ */
+int
+asn_put_few_bits(asn_bit_outp_t *po, uint32_t bits, int obits) {
+	size_t off;	/* Next after last bit offset */
+	size_t omsk;	/* Existing last byte meaningful bits mask */
+	uint8_t *buf;
+
+	if(obits <= 0 || obits >= 32) return obits ? -1 : 0;
+
+	ASN_DEBUG("[PER put %d bits %x to %p+%d bits]",
+			obits, (int)bits, (void *)po->buffer, (int)po->nboff);
+
+	/*
+	 * Normalize position indicator.
+	 */
+	if(po->nboff >= 8) {
+		po->buffer += (po->nboff >> 3);
+		po->nbits  -= (po->nboff & ~0x07);
+		po->nboff  &= 0x07;
+	}
+
+	/*
+	 * Flush whole-bytes output, if necessary.
+	 */
+	if(po->nboff + obits > po->nbits) {
+		size_t complete_bytes;
+		if(!po->buffer) po->buffer = po->tmpspace;
+		complete_bytes = (po->buffer - po->tmpspace);
+		ASN_DEBUG("[PER output %ld complete + %ld]",
+			(long)complete_bytes, (long)po->flushed_bytes);
+		if(po->output(po->tmpspace, complete_bytes, po->op_key) < 0)
+			return -1;
+		if(po->nboff)
+			po->tmpspace[0] = po->buffer[0];
+		po->buffer = po->tmpspace;
+		po->nbits = 8 * sizeof(po->tmpspace);
+		po->flushed_bytes += complete_bytes;
+	}
+
+	/*
+	 * Now, due to sizeof(tmpspace), we are guaranteed large enough space.
+	 */
+	buf = po->buffer;
+	omsk = ~((1 << (8 - po->nboff)) - 1);
+	off = (po->nboff + obits);
+
+	/* Clear data of debris before meaningful bits */
+	bits &= (((uint32_t)1 << obits) - 1);
+
+	ASN_DEBUG("[PER out %d %u/%x (t=%d,o=%d) %x&%x=%x]", obits,
+		(int)bits, (int)bits,
+		(int)po->nboff, (int)off,
+		buf[0], (int)(omsk&0xff),
+		(int)(buf[0] & omsk));
+
+	if(off <= 8)	/* Completely within 1 byte */
+		po->nboff = off,
+		bits <<= (8 - off),
+		buf[0] = (buf[0] & omsk) | bits;
+	else if(off <= 16)
+		po->nboff = off,
+		bits <<= (16 - off),
+		buf[0] = (buf[0] & omsk) | (bits >> 8),
+		buf[1] = bits;
+	else if(off <= 24)
+		po->nboff = off,
+		bits <<= (24 - off),
+		buf[0] = (buf[0] & omsk) | (bits >> 16),
+		buf[1] = bits >> 8,
+		buf[2] = bits;
+	else if(off <= 31)
+		po->nboff = off,
+		bits <<= (32 - off),
+		buf[0] = (buf[0] & omsk) | (bits >> 24),
+		buf[1] = bits >> 16,
+		buf[2] = bits >> 8,
+		buf[3] = bits;
+	else {
+		if(asn_put_few_bits(po, bits >> (obits - 24), 24)) return -1;
+		if(asn_put_few_bits(po, bits, obits - 24)) return -1;
+	}
+
+	ASN_DEBUG("[PER out %u/%x => %02x buf+%ld]",
+		(int)bits, (int)bits, buf[0],
+		(long)(po->buffer - po->tmpspace));
+
+	return 0;
+}
+
+
+/*
+ * Output a large number of bits.
+ */
+int
+asn_put_many_bits(asn_bit_outp_t *po, const uint8_t *src, int nbits) {
+
+	while(nbits) {
+		uint32_t value;
+
+		if(nbits >= 24) {
+			value = (src[0] << 16) | (src[1] << 8) | src[2];
+			src += 3;
+			nbits -= 24;
+			if(asn_put_few_bits(po, value, 24))
+				return -1;
+		} else {
+			value = src[0];
+			if(nbits > 8)
+				value = (value << 8) | src[1];
+			if(nbits > 16)
+				value = (value << 8) | src[2];
+			if(nbits & 0x07)
+				value >>= (8 - (nbits & 0x07));
+			if(asn_put_few_bits(po, value, nbits))
+				return -1;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+
+int
+asn_put_aligned_flush(asn_bit_outp_t *po) {
+    uint32_t unused_bits = (0x7 & (8 - (po->nboff & 0x07)));
+    size_t complete_bytes =
+        (po->buffer ? po->buffer - po->tmpspace : 0) + ((po->nboff + 7) >> 3);
+
+    if(unused_bits) {
+        po->buffer[po->nboff >> 3] &= ~0u << unused_bits;
+    }
+
+    if(po->output(po->tmpspace, complete_bytes, po->op_key) < 0) {
+        return -1;
+    } else {
+        po->buffer = po->tmpspace;
+        po->nboff = 0;
+        po->nbits = 8 * sizeof(po->tmpspace);
+        po->flushed_bytes += complete_bytes;
+        return 0;
+    }
+}
+

+ 83 - 0
seader/lib/asn1/asn_bit_data.h

@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2005-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef	ASN_BIT_DATA
+#define	ASN_BIT_DATA
+
+#include <asn_system.h>		/* Platform-specific types */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This structure describes a position inside an incoming PER bit stream.
+ */
+typedef struct asn_bit_data_s {
+  const uint8_t *buffer;  /* Pointer to the octet stream */
+         size_t  nboff;   /* Bit offset to the meaningful bit */
+         size_t  nbits;   /* Number of bits in the stream */
+         size_t  moved;   /* Number of bits moved through this bit stream */
+  int (*refill)(struct asn_bit_data_s *);
+  void *refill_key;
+} asn_bit_data_t;
+
+/*
+ * Create a contiguous non-refillable bit data structure.
+ * Can be freed by FREEMEM().
+ */
+asn_bit_data_t *asn_bit_data_new_contiguous(const void *data, size_t size_bits);
+
+/*
+ * Extract a small number of bits (<= 31) from the specified PER data pointer.
+ * This function returns -1 if the specified number of bits could not be
+ * extracted due to EOD or other conditions.
+ */
+int32_t asn_get_few_bits(asn_bit_data_t *, int get_nbits);
+
+/* Undo the immediately preceeding "get_few_bits" operation */
+void asn_get_undo(asn_bit_data_t *, int get_nbits);
+
+/*
+ * Extract a large number of bits from the specified PER data pointer.
+ * This function returns -1 if the specified number of bits could not be
+ * extracted due to EOD or other conditions.
+ */
+int asn_get_many_bits(asn_bit_data_t *, uint8_t *dst, int right_align,
+			int get_nbits);
+
+/* Non-thread-safe debugging function, don't use it */
+char *asn_bit_data_string(asn_bit_data_t *);
+
+/*
+ * This structure supports forming bit output.
+ */
+typedef struct asn_bit_outp_s {
+	uint8_t *buffer;	/* Pointer into the (tmpspace) */
+	size_t nboff;		/* Bit offset to the meaningful bit */
+	size_t nbits;		/* Number of bits left in (tmpspace) */
+	uint8_t tmpspace[32];	/* Preliminary storage to hold data */
+	int (*output)(const void *data, size_t size, void *op_key);
+	void *op_key;		/* Key for (output) data callback */
+	size_t flushed_bytes;	/* Bytes already flushed through (output) */
+} asn_bit_outp_t;
+
+/* Output a small number of bits (<= 31) */
+int asn_put_few_bits(asn_bit_outp_t *, uint32_t bits, int obits);
+
+/* Output a large number of bits */
+int asn_put_many_bits(asn_bit_outp_t *, const uint8_t *src, int put_nbits);
+
+/*
+ * Flush whole bytes (0 or more) through (outper) member.
+ * The least significant bits which are not used are guaranteed to be set to 0.
+ * Returns -1 if callback returns -1. Otherwise, 0.
+ */
+int asn_put_aligned_flush(asn_bit_outp_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* ASN_BIT_DATA */

+ 108 - 0
seader/lib/asn1/asn_codecs.h

@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2003-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef	ASN_CODECS_H
+#define	ASN_CODECS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct asn_TYPE_descriptor_s;	/* Forward declaration */
+
+/*
+ * This structure defines a set of parameters that may be passed
+ * to every ASN.1 encoder or decoder function.
+ * WARNING: if max_stack_size member is set, and you are calling the
+ *   function pointers of the asn_TYPE_descriptor_t directly,
+ *   this structure must be ALLOCATED ON THE STACK!
+ *   If you can't always satisfy this requirement, use ber_decode(),
+ *   xer_decode() and uper_decode() functions instead.
+ */
+typedef struct asn_codec_ctx_s {
+	/*
+	 * Limit the decoder routines to use no (much) more stack than a given
+	 * number of bytes. Most of decoders are stack-based, and this
+	 * would protect against stack overflows if the number of nested
+	 * encodings is high.
+	 * The OCTET STRING, BIT STRING and ANY BER decoders are heap-based,
+	 * and are safe from this kind of overflow.
+	 * A value from getrlimit(RLIMIT_STACK) may be used to initialize
+	 * this variable. Be careful in multithreaded environments, as the
+	 * stack size is rather limited.
+	 */
+	size_t  max_stack_size; /* 0 disables stack bounds checking */
+} asn_codec_ctx_t;
+
+/*
+ * Type of the return value of the encoding functions (der_encode, xer_encode).
+ */
+typedef struct asn_enc_rval_s {
+	/*
+	 * Number of bytes encoded.
+	 * -1 indicates failure to encode the structure.
+	 * In this case, the members below this one are meaningful.
+	 */
+	ssize_t encoded;
+
+	/*
+	 * Members meaningful when (encoded == -1), for post mortem analysis.
+	 */
+
+	/* Type which cannot be encoded */
+	const struct asn_TYPE_descriptor_s *failed_type;
+
+	/* Pointer to the structure of that type */
+	const void *structure_ptr;
+} asn_enc_rval_t;
+#define	ASN__ENCODE_FAILED do {					\
+	asn_enc_rval_t tmp_error;				\
+	tmp_error.encoded = -1;					\
+	tmp_error.failed_type = td;				\
+	tmp_error.structure_ptr = sptr;				\
+	ASN_DEBUG("Failed to encode element %s", td ? td->name : "");	\
+	return tmp_error;					\
+} while(0)
+#define	ASN__ENCODED_OK(rval) do {				\
+	rval.structure_ptr = 0;					\
+	rval.failed_type = 0;					\
+	return rval;						\
+} while(0)
+
+/*
+ * Type of the return value of the decoding functions (ber_decode, xer_decode)
+ * 
+ * Please note that the number of consumed bytes is ALWAYS meaningful,
+ * even if code==RC_FAIL. This is to indicate the number of successfully
+ * decoded bytes, hence providing a possibility to fail with more diagnostics
+ * (i.e., print the offending remainder of the buffer).
+ */
+enum asn_dec_rval_code_e {
+	RC_OK,		/* Decoded successfully */
+	RC_WMORE,	/* More data expected, call again */
+	RC_FAIL		/* Failure to decode data */
+};
+typedef struct asn_dec_rval_s {
+	enum asn_dec_rval_code_e code;	/* Result code */
+	size_t consumed;		/* Number of bytes consumed */
+} asn_dec_rval_t;
+#define	ASN__DECODE_FAILED do {					\
+	asn_dec_rval_t tmp_error;				\
+	tmp_error.code = RC_FAIL;				\
+	tmp_error.consumed = 0;					\
+	ASN_DEBUG("Failed to decode element %s", td ? td->name : "");	\
+	return tmp_error;					\
+} while(0)
+#define	ASN__DECODE_STARVED do {				\
+	asn_dec_rval_t tmp_error;				\
+	tmp_error.code = RC_WMORE;				\
+	tmp_error.consumed = 0;					\
+	return tmp_error;					\
+} while(0)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* ASN_CODECS_H */

+ 317 - 0
seader/lib/asn1/asn_codecs_prim.c

@@ -0,0 +1,317 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <asn_internal.h>
+#include <asn_codecs_prim.h>
+#include <errno.h>
+
+/*
+ * Decode an always-primitive type.
+ */
+asn_dec_rval_t
+ber_decode_primitive(const asn_codec_ctx_t *opt_codec_ctx,
+                     const asn_TYPE_descriptor_t *td, void **sptr,
+                     const void *buf_ptr, size_t size, int tag_mode) {
+    ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)*sptr;
+	asn_dec_rval_t rval;
+	ber_tlv_len_t length = 0; /* =0 to avoid [incorrect] warning. */
+
+	/*
+	 * If the structure is not there, allocate it.
+	 */
+	if(st == NULL) {
+		st = (ASN__PRIMITIVE_TYPE_t *)CALLOC(1, sizeof(*st));
+		if(st == NULL) ASN__DECODE_FAILED;
+		*sptr = (void *)st;
+	}
+
+	ASN_DEBUG("Decoding %s as plain primitive (tm=%d)",
+		td->name, tag_mode);
+
+	/*
+	 * Check tags and extract value length.
+	 */
+	rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size,
+			tag_mode, 0, &length, 0);
+	if(rval.code != RC_OK)
+		return rval;
+
+	ASN_DEBUG("%s length is %d bytes", td->name, (int)length);
+
+	/*
+	 * Make sure we have this length.
+	 */
+	buf_ptr = ((const char *)buf_ptr) + rval.consumed;
+	size -= rval.consumed;
+	if(length > (ber_tlv_len_t)size) {
+		rval.code = RC_WMORE;
+		rval.consumed = 0;
+		return rval;
+	}
+
+	st->size = (int)length;
+	/* The following better be optimized away. */
+	if(sizeof(st->size) != sizeof(length)
+			&& (ber_tlv_len_t)st->size != length) {
+		st->size = 0;
+		ASN__DECODE_FAILED;
+	}
+
+	st->buf = (uint8_t *)MALLOC(length + 1);
+	if(!st->buf) {
+		st->size = 0;
+		ASN__DECODE_FAILED;
+	}
+
+	memcpy(st->buf, buf_ptr, length);
+	st->buf[length] = '\0';		/* Just in case */
+
+	rval.code = RC_OK;
+	rval.consumed += length;
+
+	ASN_DEBUG("Took %ld/%ld bytes to encode %s",
+		(long)rval.consumed,
+		(long)length, td->name);
+
+	return rval;
+}
+
+/*
+ * Encode an always-primitive type using DER.
+ */
+asn_enc_rval_t
+der_encode_primitive(const asn_TYPE_descriptor_t *td, const void *sptr,
+                     int tag_mode, ber_tlv_tag_t tag,
+                     asn_app_consume_bytes_f *cb, void *app_key) {
+    asn_enc_rval_t erval;
+	const ASN__PRIMITIVE_TYPE_t *st = (const ASN__PRIMITIVE_TYPE_t *)sptr;
+
+	ASN_DEBUG("%s %s as a primitive type (tm=%d)",
+		cb?"Encoding":"Estimating", td->name, tag_mode);
+
+	erval.encoded = der_write_tags(td, st->size, tag_mode, 0, tag,
+		cb, app_key);
+	ASN_DEBUG("%s wrote tags %d", td->name, (int)erval.encoded);
+	if(erval.encoded == -1) {
+		erval.failed_type = td;
+		erval.structure_ptr = sptr;
+		return erval;
+	}
+
+	if(cb && st->buf) {
+		if(cb(st->buf, st->size, app_key) < 0) {
+			erval.encoded = -1;
+			erval.failed_type = td;
+			erval.structure_ptr = sptr;
+			return erval;
+		}
+	} else {
+		assert(st->buf || st->size == 0);
+	}
+
+	erval.encoded += st->size;
+	ASN__ENCODED_OK(erval);
+}
+
+void
+ASN__PRIMITIVE_TYPE_free(const asn_TYPE_descriptor_t *td, void *sptr,
+                         enum asn_struct_free_method method) {
+    ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)sptr;
+
+	if(!td || !sptr)
+		return;
+
+	ASN_DEBUG("Freeing %s as a primitive type", td->name);
+
+	if(st->buf)
+		FREEMEM(st->buf);
+
+    switch(method) {
+    case ASFM_FREE_EVERYTHING:
+        FREEMEM(sptr);
+        break;
+    case ASFM_FREE_UNDERLYING:
+        break;
+    case ASFM_FREE_UNDERLYING_AND_RESET:
+        memset(sptr, 0, sizeof(ASN__PRIMITIVE_TYPE_t));
+        break;
+    }
+}
+
+
+/*
+ * Local internal type passed around as an argument.
+ */
+struct xdp_arg_s {
+    const asn_TYPE_descriptor_t *type_descriptor;
+    void *struct_key;
+	xer_primitive_body_decoder_f *prim_body_decoder;
+	int decoded_something;
+	int want_more;
+};
+
+/*
+ * Since some kinds of primitive values can be encoded using value-specific
+ * tags (<MINUS-INFINITY>, <enum-element>, etc), the primitive decoder must
+ * be supplied with such tags to parse them as needed.
+ */
+static int
+xer_decode__unexpected_tag(void *key, const void *chunk_buf, size_t chunk_size) {
+	struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
+	enum xer_pbd_rval bret;
+
+	/*
+	 * The chunk_buf is guaranteed to start at '<'.
+	 */
+	assert(chunk_size && ((const char *)chunk_buf)[0] == 0x3c);
+
+	/*
+	 * Decoding was performed once already. Prohibit doing it again.
+	 */
+	if(arg->decoded_something)
+		return -1;
+
+	bret = arg->prim_body_decoder(arg->type_descriptor,
+		arg->struct_key, chunk_buf, chunk_size);
+	switch(bret) {
+	case XPBD_SYSTEM_FAILURE:
+	case XPBD_DECODER_LIMIT:
+	case XPBD_BROKEN_ENCODING:
+		break;
+	case XPBD_BODY_CONSUMED:
+		/* Tag decoded successfully */
+		arg->decoded_something = 1;
+		/* Fall through */
+	case XPBD_NOT_BODY_IGNORE:	/* Safe to proceed further */
+		return 0;
+	}
+
+	return -1;
+}
+
+static ssize_t
+xer_decode__primitive_body(void *key, const void *chunk_buf, size_t chunk_size, int have_more) {
+	struct xdp_arg_s *arg = (struct xdp_arg_s *)key;
+	enum xer_pbd_rval bret;
+	size_t lead_wsp_size;
+
+	if(arg->decoded_something) {
+		if(xer_whitespace_span(chunk_buf, chunk_size) == chunk_size) {
+			/*
+			 * Example:
+			 * "<INTEGER>123<!--/--> </INTEGER>"
+			 *                      ^- chunk_buf position.
+			 */
+			return chunk_size;
+		}
+		/*
+		 * Decoding was done once already. Prohibit doing it again.
+		 */
+		return -1;
+	}
+
+	if(!have_more) {
+		/*
+		 * If we've received something like "1", we can't really
+		 * tell whether it is really `1` or `123`, until we know
+		 * that there is no more data coming.
+		 * The have_more argument will be set to 1 once something
+		 * like this is available to the caller of this callback:
+		 * "1<tag_start..."
+		 */
+		arg->want_more = 1;
+		return -1;
+	}
+
+	lead_wsp_size = xer_whitespace_span(chunk_buf, chunk_size);
+	chunk_buf = (const char *)chunk_buf + lead_wsp_size;
+	chunk_size -= lead_wsp_size;
+
+	bret = arg->prim_body_decoder(arg->type_descriptor,
+		arg->struct_key, chunk_buf, chunk_size);
+	switch(bret) {
+	case XPBD_SYSTEM_FAILURE:
+	case XPBD_DECODER_LIMIT:
+	case XPBD_BROKEN_ENCODING:
+		break;
+	case XPBD_BODY_CONSUMED:
+		/* Tag decoded successfully */
+		arg->decoded_something = 1;
+		/* Fall through */
+	case XPBD_NOT_BODY_IGNORE:	/* Safe to proceed further */
+		return lead_wsp_size + chunk_size;
+	}
+
+	return -1;
+}
+
+
+asn_dec_rval_t
+xer_decode_primitive(const asn_codec_ctx_t *opt_codec_ctx,
+                     const asn_TYPE_descriptor_t *td, void **sptr,
+                     size_t struct_size, const char *opt_mname,
+                     const void *buf_ptr, size_t size,
+                     xer_primitive_body_decoder_f *prim_body_decoder) {
+    const char *xml_tag = opt_mname ? opt_mname : td->xml_tag;
+	asn_struct_ctx_t s_ctx;
+	struct xdp_arg_s s_arg;
+	asn_dec_rval_t rc;
+
+	/*
+	 * Create the structure if does not exist.
+	 */
+	if(!*sptr) {
+		*sptr = CALLOC(1, struct_size);
+		if(!*sptr) ASN__DECODE_FAILED;
+	}
+
+	memset(&s_ctx, 0, sizeof(s_ctx));
+	s_arg.type_descriptor = td;
+	s_arg.struct_key = *sptr;
+	s_arg.prim_body_decoder = prim_body_decoder;
+	s_arg.decoded_something = 0;
+	s_arg.want_more = 0;
+
+	rc = xer_decode_general(opt_codec_ctx, &s_ctx, &s_arg,
+		xml_tag, buf_ptr, size,
+		xer_decode__unexpected_tag, xer_decode__primitive_body);
+	switch(rc.code) {
+	case RC_OK:
+		if(!s_arg.decoded_something) {
+			char ch;
+			ASN_DEBUG("Primitive body is not recognized, "
+				"supplying empty one");
+			/*
+			 * Decoding opportunity has come and gone.
+			 * Where's the result?
+			 * Try to feed with empty body, see if it eats it.
+			 */
+			if(prim_body_decoder(s_arg.type_descriptor,
+				s_arg.struct_key, &ch, 0)
+					!= XPBD_BODY_CONSUMED) {
+				/*
+				 * This decoder does not like empty stuff.
+				 */
+				ASN__DECODE_FAILED;
+			}
+		}
+		break;
+	case RC_WMORE:
+		/*
+		 * Redo the whole thing later.
+		 * We don't have a context to save intermediate parsing state.
+		 */
+		rc.consumed = 0;
+		break;
+	case RC_FAIL:
+		rc.consumed = 0;
+		if(s_arg.want_more)
+			rc.code = RC_WMORE;
+		else
+			ASN__DECODE_FAILED;
+		break;
+	}
+	return rc;
+}
+

+ 51 - 0
seader/lib/asn1/asn_codecs_prim.h

@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2004-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef	ASN_CODECS_PRIM_H
+#define	ASN_CODECS_PRIM_H
+
+#include <asn_application.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ASN__PRIMITIVE_TYPE_s {
+    uint8_t *buf;   /* Buffer with consecutive primitive encoding bytes */
+    size_t size;    /* Size of the buffer */
+} ASN__PRIMITIVE_TYPE_t;	/* Do not use this type directly! */
+
+asn_struct_free_f ASN__PRIMITIVE_TYPE_free;
+ber_type_decoder_f ber_decode_primitive;
+der_type_encoder_f der_encode_primitive;
+
+/*
+ * A callback specification for the xer_decode_primitive() function below.
+ */
+enum xer_pbd_rval {
+    XPBD_SYSTEM_FAILURE,  /* System failure (memory shortage, etc) */
+    XPBD_DECODER_LIMIT,   /* Hit some decoder limitation or deficiency */
+    XPBD_BROKEN_ENCODING, /* Encoding of a primitive body is broken */
+    XPBD_NOT_BODY_IGNORE, /* Not a body format, but safe to ignore */
+    XPBD_BODY_CONSUMED    /* Body is recognized and consumed */
+};
+typedef enum xer_pbd_rval(xer_primitive_body_decoder_f)(
+    const asn_TYPE_descriptor_t *td, void *struct_ptr, const void *chunk_buf,
+    size_t chunk_size);
+
+/*
+ * Specific function to decode simple primitive types.
+ * Also see xer_decode_general() in xer_decoder.h
+ */
+asn_dec_rval_t xer_decode_primitive(
+    const asn_codec_ctx_t *opt_codec_ctx,
+    const asn_TYPE_descriptor_t *type_descriptor, void **struct_ptr,
+    size_t struct_size, const char *opt_mname, const void *buf_ptr, size_t size,
+    xer_primitive_body_decoder_f *prim_body_decoder);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* ASN_CODECS_PRIM_H */

+ 47 - 0
seader/lib/asn1/asn_internal.c

@@ -0,0 +1,47 @@
+#include <asn_internal.h>
+
+ssize_t
+asn__format_to_callback(int (*cb)(const void *, size_t, void *key), void *key,
+                        const char *fmt, ...) {
+    char scratch[64];
+    char *buf = scratch;
+    size_t buf_size = sizeof(scratch);
+    int wrote;
+    int cb_ret;
+
+    do {
+        va_list args;
+        va_start(args, fmt);
+
+        wrote = vsnprintf(buf, buf_size, fmt, args);
+        if(wrote < (ssize_t)buf_size) {
+            if(wrote < 0) {
+                if(buf != scratch) FREEMEM(buf);
+                return -1;
+            }
+            break;
+        }
+
+        buf_size <<= 1;
+        if(buf == scratch) {
+            buf = MALLOC(buf_size);
+            if(!buf) return -1;
+        } else {
+            void *p = REALLOC(buf, buf_size);
+            if(!p) {
+                FREEMEM(buf);
+                return -1;
+            }
+            buf = p;
+        }
+    } while(1);
+
+    cb_ret = cb(buf, wrote, key);
+    if(buf != scratch) FREEMEM(buf);
+    if(cb_ret < 0) {
+        return -1;
+    }
+
+    return wrote;
+}
+

+ 152 - 0
seader/lib/asn1/asn_internal.h

@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2003-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+/*
+ * Declarations internally useful for the ASN.1 support code.
+ */
+#ifndef	ASN_INTERNAL_H
+#define	ASN_INTERNAL_H
+#ifndef __EXTENSIONS__
+#define __EXTENSIONS__          /* for Sun */
+#endif
+#include "asn_application.h"	/* Application-visible API */
+
+#ifndef	__NO_ASSERT_H__		/* Include assert.h only for internal use. */
+#include <assert.h>		/* for assert() macro */
+#endif
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/* Environment version might be used to avoid running with the old library */
+#define	ASN1C_ENVIRONMENT_VERSION	923	/* Compile-time version */
+int get_asn1c_environment_version(void);	/* Run-time version */
+
+#define	CALLOC(nmemb, size)	calloc(nmemb, size)
+#define	MALLOC(size)		malloc(size)
+#define	REALLOC(oldptr, size)	realloc(oldptr, size)
+#define	FREEMEM(ptr)		free(ptr)
+
+#define	asn_debug_indent	0
+#define ASN_DEBUG_INDENT_ADD(i) do{}while(0)
+
+#ifdef  EMIT_ASN_DEBUG
+#warning "Use ASN_EMIT_DEBUG instead of EMIT_ASN_DEBUG"
+#define ASN_EMIT_DEBUG  EMIT_ASN_DEBUG
+#endif
+
+/*
+ * A macro for debugging the ASN.1 internals.
+ * You may enable or override it.
+ */
+#ifndef	ASN_DEBUG	/* If debugging code is not defined elsewhere... */
+#if	ASN_EMIT_DEBUG == 1	/* And it was asked to emit this code... */
+#if __STDC_VERSION__ >= 199901L
+#ifdef	ASN_THREAD_SAFE
+/* Thread safety requires sacrifice in output indentation:
+ * Retain empty definition of ASN_DEBUG_INDENT_ADD. */
+#else	/* !ASN_THREAD_SAFE */
+#undef  ASN_DEBUG_INDENT_ADD
+#undef  asn_debug_indent
+int asn_debug_indent;
+#define ASN_DEBUG_INDENT_ADD(i) do { asn_debug_indent += i; } while(0)
+#endif	/* ASN_THREAD_SAFE */
+#define	ASN_DEBUG(fmt, args...)	do {			\
+		int adi = asn_debug_indent;		\
+		while(adi--) fprintf(stderr, " ");	\
+		fprintf(stderr, fmt, ##args);		\
+		fprintf(stderr, " (%s:%d)\n",		\
+			__FILE__, __LINE__);		\
+	} while(0)
+#else	/* !C99 */
+void CC_PRINTFLIKE(1, 2) ASN_DEBUG_f(const char *fmt, ...);
+#define	ASN_DEBUG	ASN_DEBUG_f
+#endif	/* C99 */
+#else	/* ASN_EMIT_DEBUG != 1 */
+#if __STDC_VERSION__ >= 199901L
+#define ASN_DEBUG(...) do{}while(0)
+#else   /* not C99 */
+static void CC_PRINTFLIKE(1, 2) ASN_DEBUG(const char *fmt, ...) { (void)fmt; }
+#endif  /* C99 or better */
+#endif	/* ASN_EMIT_DEBUG */
+#endif	/* ASN_DEBUG */
+
+/*
+ * Print to a callback.
+ * The callback is expected to return negative values on error.
+ * 0 and positive values are treated as success.
+ * RETURN VALUES:
+ *  -1: Failed to format or invoke the callback.
+ *  >0: Size of the data that got delivered to the callback.
+ */
+ssize_t CC_PRINTFLIKE(3, 4)
+asn__format_to_callback(
+    int (*callback)(const void *, size_t, void *key), void *key,
+    const char *fmt, ...);
+
+/*
+ * Invoke the application-supplied callback and fail, if something is wrong.
+ */
+#define ASN__E_cbc(buf, size) (cb((buf), (size), app_key) < 0)
+#define ASN__E_CALLBACK(size, foo) \
+    do {                           \
+        if(foo) goto cb_failed;    \
+        er.encoded += (size);      \
+    } while(0)
+#define ASN__CALLBACK(buf, size) ASN__E_CALLBACK(size, ASN__E_cbc(buf, size))
+#define ASN__CALLBACK2(buf1, size1, buf2, size2) \
+    ASN__E_CALLBACK((size1) + (size2),           \
+                    ASN__E_cbc(buf1, size1) || ASN__E_cbc(buf2, size2))
+#define ASN__CALLBACK3(buf1, size1, buf2, size2, buf3, size3)          \
+    ASN__E_CALLBACK((size1) + (size2) + (size3),                       \
+                    ASN__E_cbc(buf1, size1) || ASN__E_cbc(buf2, size2) \
+                        || ASN__E_cbc(buf3, size3))
+
+#define ASN__TEXT_INDENT(nl, level)                                          \
+    do {                                                                     \
+        int tmp_level = (level);                                             \
+        int tmp_nl = ((nl) != 0);                                            \
+        int tmp_i;                                                           \
+        if(tmp_nl) ASN__CALLBACK("\n", 1);                                   \
+        if(tmp_level < 0) tmp_level = 0;                                     \
+        for(tmp_i = 0; tmp_i < tmp_level; tmp_i++) ASN__CALLBACK("    ", 4); \
+    } while(0)
+
+#define	_i_INDENT(nl)	do {                        \
+        int tmp_i;                                  \
+        if((nl) && cb("\n", 1, app_key) < 0)        \
+            return -1;                              \
+        for(tmp_i = 0; tmp_i < ilevel; tmp_i++)     \
+            if(cb("    ", 4, app_key) < 0)          \
+                return -1;                          \
+    } while(0)
+
+/*
+ * Check stack against overflow, if limit is set.
+ */
+#define	ASN__DEFAULT_STACK_MAX	(30000)
+static int CC_NOTUSED
+ASN__STACK_OVERFLOW_CHECK(const asn_codec_ctx_t *ctx) {
+	if(ctx && ctx->max_stack_size) {
+
+		/* ctx MUST be allocated on the stack */
+		ptrdiff_t usedstack = ((const char *)ctx - (const char *)&ctx);
+		if(usedstack > 0) usedstack = -usedstack; /* grows up! */
+
+		/* double negative required to avoid int wrap-around */
+		if(usedstack < -(ptrdiff_t)ctx->max_stack_size) {
+			ASN_DEBUG("Stack limit %ld reached",
+				(long)ctx->max_stack_size);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* ASN_INTERNAL_H */

+ 50 - 0
seader/lib/asn1/asn_ioc.h

@@ -0,0 +1,50 @@
+/*
+ * Run-time support for Information Object Classes.
+ * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef	ASN_IOC_H
+#define	ASN_IOC_H
+
+#include <asn_system.h>		/* Platform-specific types */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct asn_TYPE_descriptor_s;
+struct asn_ioc_cell_s;
+
+/*
+ * X.681, #13
+ */
+typedef struct asn_ioc_set_s {
+    size_t rows_count;
+    size_t columns_count;
+    const struct asn_ioc_cell_s *rows;
+} asn_ioc_set_t;
+
+
+typedef struct asn_ioc_cell_s {
+    const char *field_name; /* Is equal to corresponding column_name */
+    enum {
+        aioc__value,
+        aioc__type,
+        aioc__open_type,
+    } cell_kind;
+    struct asn_TYPE_descriptor_s *type_descriptor;
+    const void *value_sptr;
+    struct {
+        size_t types_count;
+        struct {
+            unsigned choice_position;
+        } *types;
+    } open_type;
+} asn_ioc_cell_t;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* ASN_IOC_H */

+ 56 - 0
seader/lib/asn1/asn_random_fill.c

@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>.
+ * All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <asn_internal.h>
+#include <asn_random_fill.h>
+#include <constr_TYPE.h>
+
+int
+asn_random_fill(const struct asn_TYPE_descriptor_s *td, void **struct_ptr,
+                size_t length) {
+
+    if(td && td->op->random_fill) {
+        asn_random_fill_result_t res =
+            td->op->random_fill(td, struct_ptr, 0, length);
+        return (res.code == ARFILL_OK) ? 0 : -1;
+    } else {
+        return -1;
+    }
+}
+
+static uintmax_t
+asn__intmax_range(intmax_t lb, intmax_t ub) {
+    assert(lb <= ub);
+    if((ub < 0) == (lb < 0)) {
+        return ub - lb;
+    } else if(lb < 0) {
+        return 1 + ((uintmax_t)ub + (uintmax_t)-(lb + 1));
+    } else {
+        assert(!"Unreachable");
+        return 0;
+    }
+}
+
+intmax_t
+asn_random_between(intmax_t lb, intmax_t rb) {
+    if(lb == rb) {
+        return lb;
+    } else {
+        const uintmax_t intmax_max = ((~(uintmax_t)0) >> 1);
+        uintmax_t range = asn__intmax_range(lb, rb);
+        uintmax_t value = 0;
+        uintmax_t got_entropy = 0;
+
+        assert(RAND_MAX > 0xffffff);    /* Seen 7ffffffd! */
+        assert(range < intmax_max);
+
+        for(; got_entropy < range;) {
+            got_entropy = (got_entropy << 24) | 0xffffff;
+            value = (value << 24) | (random() % 0xffffff);
+        }
+
+        return lb + (intmax_t)(value % (range + 1));
+    }
+}

+ 51 - 0
seader/lib/asn1/asn_random_fill.h

@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef	ASN_RANDOM_FILL
+#define	ASN_RANDOM_FILL
+
+/* Forward declarations */
+struct asn_TYPE_descriptor_s;
+struct asn_encoding_constraints_s;
+
+/*
+ * Initialize a structure with random data according to the type specification
+ * and optional member constraints.
+ * ARGUMENTS:
+ *  (max_length)        - See (approx_max_length_limit).
+ *  (memb_constraints)  - Member constraints, if exist.
+ *                        The type can be constrained differently according
+ *                        to PER and OER specifications, so we find a value
+ *                        at the intersection of these constraints.
+ * In case the return differs from ARFILL_OK, the (struct_ptr) contents
+ * and (current_length) value remain in their original state.
+ */
+typedef struct asn_random_fill_result_s {
+    enum {
+        ARFILL_FAILED = -1, /* System error (memory?) */
+        ARFILL_OK = 0,      /* Initialization succeeded */
+        ARFILL_SKIPPED = 1  /* Not done due to (length?) constraint */
+    } code;
+    size_t length; /* Approximate number of bytes created. */
+} asn_random_fill_result_t;
+typedef asn_random_fill_result_t(asn_random_fill_f)(
+    const struct asn_TYPE_descriptor_s *td, void **struct_ptr,
+    const struct asn_encoding_constraints_s *memb_constraints,
+    size_t max_length);
+
+/*
+ * Returns 0 if the structure was properly initialized, -1 otherwise.
+ * The (approx_max_length_limit) specifies the approximate limit of the
+ * resulting structure in units closely resembling bytes. The actual result
+ * might be several times larger or smaller than the length limit.
+ */
+int asn_random_fill(const struct asn_TYPE_descriptor_s *td, void **struct_ptr,
+                    size_t approx_max_length_limit);
+
+/*
+ * Returns a random number between min and max.
+ */
+intmax_t asn_random_between(intmax_t min, intmax_t max);
+
+#endif	/* ASN_RANDOM_FILL */

+ 150 - 0
seader/lib/asn1/asn_system.h

@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2003-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+/*
+ * Miscellaneous system-dependent types.
+ */
+#ifndef	ASN_SYSTEM_H
+#define	ASN_SYSTEM_H
+
+#ifdef	HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef _DEFAULT_SOURCE
+#define _DEFAULT_SOURCE 1
+#endif
+
+#ifndef _BSD_SOURCE
+#define _BSD_SOURCE /* for snprintf() on some linux systems  */
+#endif
+
+#include <stdio.h>	/* For snprintf(3) */
+#include <stdlib.h>	/* For *alloc(3) */
+#include <string.h>	/* For memcpy(3) */
+#include <sys/types.h>	/* For size_t */
+#include <limits.h>	/* For LONG_MAX */
+#include <stdarg.h>	/* For va_start */
+#include <stddef.h>	/* for offsetof and ptrdiff_t */
+
+#ifdef	_WIN32
+
+#include <malloc.h>
+#define	 snprintf	_snprintf
+#define	 vsnprintf	_vsnprintf
+
+/* To avoid linking with ws2_32.lib, here's the definition of ntohl() */
+#define sys_ntohl(l)	((((l) << 24)  & 0xff000000)	\
+			| (((l) << 8) & 0xff0000)	\
+			| (((l) >> 8)  & 0xff00)	\
+			| ((l >> 24) & 0xff))
+
+#ifdef _MSC_VER			/* MSVS.Net */
+#ifndef __cplusplus
+#define inline __inline
+#endif
+#ifndef	ASSUMESTDTYPES	/* Standard types have been defined elsewhere */
+#define	ssize_t		SSIZE_T
+#if _MSC_VER < 1600
+typedef	char		int8_t;
+typedef	short		int16_t;
+typedef	int		int32_t;
+typedef	unsigned char	uint8_t;
+typedef	unsigned short	uint16_t;
+typedef	unsigned int	uint32_t;
+#else /* _MSC_VER >= 1600 */
+#include <stdint.h>
+#endif /* _MSC_VER < 1600 */
+#endif	/* ASSUMESTDTYPES */
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <float.h>
+#define isnan _isnan
+#define finite _finite
+#define copysign _copysign
+#define	ilogb	_logb
+#else	/* !_MSC_VER */
+#include <stdint.h>
+#endif	/* _MSC_VER */
+
+#else	/* !_WIN32 */
+
+#if defined(__vxworks)
+#include <types/vxTypes.h>
+#else	/* !defined(__vxworks) */
+
+#include <inttypes.h>	/* C99 specifies this file */
+#include <netinet/in.h> /* for ntohl() */
+#define	sys_ntohl(foo)	ntohl(foo)
+#endif	/* defined(__vxworks) */
+
+#endif	/* _WIN32 */
+
+#if	__GNUC__ >= 3 || defined(__clang__)
+#define CC_ATTRIBUTE(attr)    __attribute__((attr))
+#else
+#define CC_ATTRIBUTE(attr)
+#endif
+#define CC_PRINTFLIKE(fmt, var)     CC_ATTRIBUTE(format(printf, fmt, var))
+#define	CC_NOTUSED                  CC_ATTRIBUTE(unused)
+#ifndef CC_ATTR_NO_SANITIZE
+#define CC_ATTR_NO_SANITIZE(what)   CC_ATTRIBUTE(no_sanitize(what))
+#endif
+
+/* Figure out if thread safety is requested */
+#if !defined(ASN_THREAD_SAFE) && (defined(THREAD_SAFE) || defined(_REENTRANT))
+#define	ASN_THREAD_SAFE
+#endif	/* Thread safety */
+
+#ifndef	offsetof	/* If not defined by <stddef.h> */
+#define	offsetof(s, m)	((ptrdiff_t)&(((s *)0)->m) - (ptrdiff_t)((s *)0))
+#endif	/* offsetof */
+
+#ifndef	MIN		/* Suitable for comparing primitive types (integers) */
+#if defined(__GNUC__)
+#define	MIN(a,b)	({ __typeof a _a = a; __typeof b _b = b;	\
+	((_a)<(_b)?(_a):(_b)); })
+#else	/* !__GNUC__ */
+#define	MIN(a,b)	((a)<(b)?(a):(b))	/* Unsafe variant */
+#endif /* __GNUC__ */
+#endif	/* MIN */
+
+#if __STDC_VERSION__ >= 199901L
+#ifndef SIZE_MAX
+#define SIZE_MAX   ((~((size_t)0)) >> 1)
+#endif
+
+#ifndef RSIZE_MAX   /* C11, Annex K */
+#define RSIZE_MAX   (SIZE_MAX >> 1)
+#endif
+#ifndef RSSIZE_MAX   /* Halve signed size even further than unsigned */
+#define RSSIZE_MAX   ((ssize_t)(RSIZE_MAX >> 1))
+#endif
+#else   /* Old compiler */
+#undef  SIZE_MAX
+#undef  RSIZE_MAX
+#undef  RSSIZE_MAX
+#define SIZE_MAX   ((~((size_t)0)) >> 1)
+#define RSIZE_MAX   (SIZE_MAX >> 1)
+#define RSSIZE_MAX   ((ssize_t)(RSIZE_MAX >> 1))
+#endif
+
+#if __STDC_VERSION__ >= 199901L
+#define ASN_PRI_SIZE "zu"
+#define ASN_PRI_SSIZE "zd"
+#define ASN_PRIuMAX PRIuMAX
+#define ASN_PRIdMAX PRIdMAX
+#else
+#define ASN_PRI_SIZE "lu"
+#define ASN_PRI_SSIZE "ld"
+#if LLONG_MAX > LONG_MAX
+#define ASN_PRIuMAX "llu"
+#define ASN_PRIdMAX "lld"
+#else
+#define ASN_PRIuMAX "lu"
+#define ASN_PRIdMAX "ld"
+#endif
+#endif
+
+#endif	/* ASN_SYSTEM_H */

+ 283 - 0
seader/lib/asn1/ber_decoder.c

@@ -0,0 +1,283 @@
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#include <asn_internal.h>
+
+#undef	ADVANCE
+#define	ADVANCE(num_bytes)	do {					\
+		size_t num = num_bytes;					\
+		ptr = ((const char *)ptr) + num;			\
+		size -= num;						\
+		consumed_myself += num;					\
+	} while(0)
+#undef	RETURN
+#define	RETURN(_code)	do {						\
+		asn_dec_rval_t rval;					\
+		rval.code = _code;					\
+		if(opt_ctx) opt_ctx->step = step; /* Save context */	\
+		if(_code == RC_OK || opt_ctx)				\
+			rval.consumed = consumed_myself;		\
+		else							\
+			rval.consumed = 0;	/* Context-free */	\
+		return rval;						\
+	} while(0)
+
+/*
+ * The BER decoder of any type.
+ */
+asn_dec_rval_t
+ber_decode(const asn_codec_ctx_t *opt_codec_ctx,
+           const asn_TYPE_descriptor_t *type_descriptor, void **struct_ptr,
+           const void *ptr, size_t size) {
+    asn_codec_ctx_t s_codec_ctx;
+
+	/*
+	 * Stack checker requires that the codec context
+	 * must be allocated on the stack.
+	 */
+	if(opt_codec_ctx) {
+		if(opt_codec_ctx->max_stack_size) {
+			s_codec_ctx = *opt_codec_ctx;
+			opt_codec_ctx = &s_codec_ctx;
+		}
+	} else {
+		/* If context is not given, be security-conscious anyway */
+		memset(&s_codec_ctx, 0, sizeof(s_codec_ctx));
+		s_codec_ctx.max_stack_size = ASN__DEFAULT_STACK_MAX;
+		opt_codec_ctx = &s_codec_ctx;
+	}
+
+	/*
+	 * Invoke type-specific decoder.
+	 */
+	return type_descriptor->op->ber_decoder(opt_codec_ctx, type_descriptor,
+		struct_ptr,	/* Pointer to the destination structure */
+		ptr, size,	/* Buffer and its size */
+		0		/* Default tag mode is 0 */
+		);
+}
+
+/*
+ * Check the set of <TL<TL<TL...>>> tags matches the definition.
+ */
+asn_dec_rval_t
+ber_check_tags(const asn_codec_ctx_t *opt_codec_ctx,
+               const asn_TYPE_descriptor_t *td, asn_struct_ctx_t *opt_ctx,
+               const void *ptr, size_t size, int tag_mode, int last_tag_form,
+               ber_tlv_len_t *last_length, int *opt_tlv_form) {
+    ssize_t consumed_myself = 0;
+	ssize_t tag_len;
+	ssize_t len_len;
+	ber_tlv_tag_t tlv_tag;
+	ber_tlv_len_t tlv_len;
+	ber_tlv_len_t limit_len = -1;
+	int expect_00_terminators = 0;
+	int tlv_constr = -1;	/* If CHOICE, opt_tlv_form is not given */
+	int step = opt_ctx ? opt_ctx->step : 0;	/* Where we left previously */
+	int tagno;
+
+	/*
+	 * Make sure we didn't exceed the maximum stack size.
+	 */
+	if(ASN__STACK_OVERFLOW_CHECK(opt_codec_ctx))
+		RETURN(RC_FAIL);
+
+	/*
+	 * So what does all this implicit skip stuff mean?
+	 * Imagine two types,
+	 * 	A ::= [5] IMPLICIT	T
+	 * 	B ::= [2] EXPLICIT	T
+	 * Where T is defined as
+	 *	T ::= [4] IMPLICIT SEQUENCE { ... }
+	 * 
+	 * Let's say, we are starting to decode type A, given the
+	 * following TLV stream: <5> <0>. What does this mean?
+	 * It means that the type A contains type T which is,
+	 * in turn, empty.
+	 * Remember though, that we are still in A. We cannot
+	 * just pass control to the type T decoder. Why? Because
+	 * the type T decoder expects <4> <0>, not <5> <0>.
+	 * So, we must make sure we are going to receive <5> while
+	 * still in A, then pass control to the T decoder, indicating
+	 * that the tag <4> was implicitly skipped. The decoder of T
+	 * hence will be prepared to treat <4> as valid tag, and decode
+	 * it appropriately.
+	 */
+
+	tagno = step	/* Continuing where left previously */
+		+ (tag_mode==1?-1:0)
+		;
+	ASN_DEBUG("ber_check_tags(%s, size=%ld, tm=%d, step=%d, tagno=%d)",
+		td->name, (long)size, tag_mode, step, tagno);
+	/* assert(td->tags_count >= 1) May not be the case for CHOICE or ANY */
+
+	if(tag_mode == 0 && tagno == (int)td->tags_count) {
+		/*
+		 * This must be the _untagged_ ANY type,
+		 * which outermost tag isn't known in advance.
+		 * Fetch the tag and length separately.
+		 */
+		tag_len = ber_fetch_tag(ptr, size, &tlv_tag);
+		switch(tag_len) {
+		case -1: RETURN(RC_FAIL);
+		case 0: RETURN(RC_WMORE);
+		}
+		tlv_constr = BER_TLV_CONSTRUCTED(ptr);
+		len_len = ber_fetch_length(tlv_constr,
+			(const char *)ptr + tag_len, size - tag_len, &tlv_len);
+		switch(len_len) {
+		case -1: RETURN(RC_FAIL);
+		case 0: RETURN(RC_WMORE);
+		}
+		ASN_DEBUG("Advancing %ld in ANY case",
+			(long)(tag_len + len_len));
+		ADVANCE(tag_len + len_len);
+	} else {
+		assert(tagno < (int)td->tags_count);	/* At least one loop */
+	}
+	for((void)tagno; tagno < (int)td->tags_count; tagno++, step++) {
+
+		/*
+		 * Fetch and process T from TLV.
+		 */
+		tag_len = ber_fetch_tag(ptr, size, &tlv_tag);
+			ASN_DEBUG("Fetching tag from {%p,%ld}: "
+				"len %ld, step %d, tagno %d got %s",
+				ptr, (long)size,
+				(long)tag_len, step, tagno,
+				ber_tlv_tag_string(tlv_tag));
+		switch(tag_len) {
+		case -1: RETURN(RC_FAIL);
+		case 0: RETURN(RC_WMORE);
+		}
+
+		tlv_constr = BER_TLV_CONSTRUCTED(ptr);
+
+		/*
+		 * If {I}, don't check anything.
+		 * If {I,B,C}, check B and C unless we're at I.
+		 */
+		if(tag_mode != 0 && step == 0) {
+			/*
+			 * We don't expect tag to match here.
+			 * It's just because we don't know how the tag
+			 * is supposed to look like.
+			 */
+		} else {
+		    assert(tagno >= 0);	/* Guaranteed by the code above */
+		    if(tlv_tag != td->tags[tagno]) {
+			/*
+			 * Unexpected tag. Too bad.
+			 */
+		    	ASN_DEBUG("Expected: %s, "
+				"expectation failed (tn=%d, tm=%d)",
+				ber_tlv_tag_string(td->tags[tagno]),
+				tagno, tag_mode
+			);
+			RETURN(RC_FAIL);
+		    }
+		}
+
+		/*
+		 * Attention: if there are more tags expected,
+		 * ensure that the current tag is presented
+		 * in constructed form (it contains other tags!).
+		 * If this one is the last one, check that the tag form
+		 * matches the one given in descriptor.
+		 */
+		if(tagno < ((int)td->tags_count - 1)) {
+			if(tlv_constr == 0) {
+				ASN_DEBUG("tlv_constr = %d, expfail",
+					tlv_constr);
+				RETURN(RC_FAIL);
+			}
+		} else {
+			if(last_tag_form != tlv_constr
+			&& last_tag_form != -1) {
+				ASN_DEBUG("last_tag_form %d != %d",
+					last_tag_form, tlv_constr);
+				RETURN(RC_FAIL);
+			}
+		}
+
+		/*
+		 * Fetch and process L from TLV.
+		 */
+		len_len = ber_fetch_length(tlv_constr,
+			(const char *)ptr + tag_len, size - tag_len, &tlv_len);
+		ASN_DEBUG("Fetching len = %ld", (long)len_len);
+		switch(len_len) {
+		case -1: RETURN(RC_FAIL);
+		case 0: RETURN(RC_WMORE);
+		}
+
+		/*
+		 * FIXME
+		 * As of today, the chain of tags
+		 * must either contain several indefinite length TLVs,
+		 * or several definite length ones.
+		 * No mixing is allowed.
+		 */
+		if(tlv_len == -1) {
+			/*
+			 * Indefinite length.
+			 */
+			if(limit_len == -1) {
+				expect_00_terminators++;
+			} else {
+				ASN_DEBUG("Unexpected indefinite length "
+					"in a chain of definite lengths");
+				RETURN(RC_FAIL);
+			}
+			ADVANCE(tag_len + len_len);
+			continue;
+		} else {
+			if(expect_00_terminators) {
+				ASN_DEBUG("Unexpected definite length "
+					"in a chain of indefinite lengths");
+				RETURN(RC_FAIL);
+			}
+		}
+
+		/*
+		 * Check that multiple TLVs specify ever decreasing length,
+		 * which is consistent.
+		 */
+		if(limit_len == -1) {
+			limit_len    = tlv_len + tag_len + len_len;
+			if(limit_len < 0) {
+				/* Too great tlv_len value? */
+				RETURN(RC_FAIL);
+			}
+		} else if(limit_len != tlv_len + tag_len + len_len) {
+			/*
+			 * Inner TLV specifies length which is inconsistent
+			 * with the outer TLV's length value.
+			 */
+			ASN_DEBUG("Outer TLV is %ld and inner is %ld",
+				(long)limit_len, (long)tlv_len);
+			RETURN(RC_FAIL);
+		}
+
+		ADVANCE(tag_len + len_len);
+
+		limit_len -= (tag_len + len_len);
+		if((ssize_t)size > limit_len) {
+			/*
+			 * Make sure that we won't consume more bytes
+			 * from the parent frame than the inferred limit.
+			 */
+			size = limit_len;
+		}
+	}
+
+	if(opt_tlv_form)
+		*opt_tlv_form = tlv_constr;
+	if(expect_00_terminators)
+		*last_length = -expect_00_terminators;
+	else
+		*last_length = tlv_len;
+
+	RETURN(RC_OK);
+}

+ 66 - 0
seader/lib/asn1/ber_decoder.h

@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 2003-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef	_BER_DECODER_H_
+#define	_BER_DECODER_H_
+
+#include <asn_application.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct asn_TYPE_descriptor_s;	/* Forward declaration */
+struct asn_codec_ctx_s;		/* Forward declaration */
+
+/*
+ * The BER decoder of any type.
+ * This function may be invoked directly from the application.
+ * Decodes BER, DER and CER data (DER and CER are different subsets of BER).
+ *
+ * NOTE: Use the der_encode() function (der_encoder.h) to produce encoding
+ * which is compliant with ber_decode().
+ */
+asn_dec_rval_t ber_decode(
+    const struct asn_codec_ctx_s *opt_codec_ctx,
+    const struct asn_TYPE_descriptor_s *type_descriptor,
+    void **struct_ptr,  /* Pointer to a target structure's pointer */
+    const void *buffer, /* Data to be decoded */
+    size_t size         /* Size of that buffer */
+);
+
+/*
+ * Type of generic function which decodes the byte stream into the structure.
+ */
+typedef asn_dec_rval_t(ber_type_decoder_f)(
+    const struct asn_codec_ctx_s *opt_codec_ctx,
+    const struct asn_TYPE_descriptor_s *type_descriptor, void **struct_ptr,
+    const void *buf_ptr, size_t size, int tag_mode);
+
+/*******************************
+ * INTERNALLY USEFUL FUNCTIONS *
+ *******************************/
+
+/*
+ * Check that all tags correspond to the type definition (as given in head).
+ * On return, last_length would contain either a non-negative length of the
+ * value part of the last TLV, or the negative number of expected
+ * "end of content" sequences. The number may only be negative if the
+ * head->last_tag_form is non-zero.
+ */
+asn_dec_rval_t ber_check_tags(
+    const struct asn_codec_ctx_s *opt_codec_ctx, /* codec options */
+    const struct asn_TYPE_descriptor_s *type_descriptor,
+    asn_struct_ctx_t *opt_ctx, /* saved decoding context */
+    const void *ptr, size_t size,
+    int tag_mode,      /* {-1,0,1}: IMPLICIT, no, EXPLICIT */
+    int last_tag_form, /* {-1,0:1}: any, primitive, constr */
+    ber_tlv_len_t *last_length, int *opt_tlv_form /* optional tag form */
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _BER_DECODER_H_ */

Some files were not shown because too many files changed in this diff