{"id":14966121,"url":"https://github.com/altai-man/asn-ber","last_synced_at":"2026-01-15T22:58:19.552Z","repository":{"id":74299376,"uuid":"161835710","full_name":"Altai-man/ASN-BER","owner":"Altai-man","description":"A subset of ASN.1 implemented in Raku, BER-wise","archived":false,"fork":false,"pushed_at":"2021-04-01T21:03:38.000Z","size":65,"stargazers_count":3,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-01T21:04:15.870Z","etag":null,"topics":["asn","ber","encoder-decoder","perl6","raku","raku-module","rakulang"],"latest_commit_sha":null,"homepage":"","language":"Raku","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"artistic-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Altai-man.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-12-14T20:13:26.000Z","updated_at":"2022-10-25T19:54:26.000Z","dependencies_parsed_at":null,"dependency_job_id":"1cbaed1d-7b22-4d0c-b32f-3d4abc9f93aa","html_url":"https://github.com/Altai-man/ASN-BER","commit_stats":{"total_commits":76,"total_committers":2,"mean_commits":38.0,"dds":"0.052631578947368474","last_synced_commit":"5e521e5c8ecb383ce80503ef8c6b54a4a75020c0"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Altai-man%2FASN-BER","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Altai-man%2FASN-BER/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Altai-man%2FASN-BER/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Altai-man%2FASN-BER/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Altai-man","download_url":"https://codeload.github.com/Altai-man/ASN-BER/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247152576,"owners_count":20892519,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asn","ber","encoder-decoder","perl6","raku","raku-module","rakulang"],"created_at":"2024-09-24T13:35:51.189Z","updated_at":"2026-01-15T22:58:19.525Z","avatar_url":"https://github.com/Altai-man.png","language":"Raku","funding_links":[],"categories":[],"sub_categories":[],"readme":"### ASN::BER\n\nThis module is designed to allow one make Raku types support encoding and decoding based on ASN.1-driven Basic Encoding Rules.\n\n#### Warnings\n\n* This is a beta release. Number of universal types is not even described and papercuts are possible.\n* Main driving power beneath this is a desire to avoid writing every LDAP type\nparsing and serializing code by hands. As a result, while some means to have more generic support\nof ASN.1 are being prepared, contributing code to support greater variety of ASN.1 definitions\nbeing expressed and handled correctly is appreciated.\n\n#### Synopsis\n\n```perl6\n#`[\nWorld-Schema DEFINITIONS IMPLICIT TAGS ::=\nBEGIN\n  Rocket ::= SEQUENCE\n  {\n     name      UTF8String (SIZE(1..16)),\n     message   UTF8String DEFAULT \"Hello World\",\n     fuel      ENUMERATED {solid, liquid, gas},\n     speed     CHOICE\n     {\n        mph    [0] INTEGER,\n        kmph   [1] INTEGER\n     }  OPTIONAL,\n     payload   SEQUENCE OF UTF8String\n  }\nEND\n]\n\n# Necessary imports\nuse ASN::Types;\nuse ASN::Serializer;\nuse ASN::Parser;\n\n# ENUMERATED is expressed as enum\nenum Fuel \u003cSolid Liquid Gas\u003e;\n\n# Mark CHOICE type as ASNChoice\nclass SpeedChoice does ASNChoice {\n    method ASN-choice() {\n        # Description of choice names, tags, types\n        { mph =\u003e (1 =\u003e Int), kmph =\u003e (0 =\u003e Int) }\n    }\n}\n\n# Mark our SEQUENCE as ASNSequence\nclass Rocket does ASNSequence {\n    has Str $.name is UTF8String; # UTF8String\n    has Str $.message is default-value(\"Hello World\") is UTF8String; # DEFAULT\n    has Fuel $.fuel; # ENUMERATED\n    has SpeedChoice $.speed is optional; # CHOICE + OPTIONAL\n    has ASNSequenceOf[ASN::Types::UTF8String] $.payload # SEQUENCE OF UTF8String\n\n    # `ASN-order` method is a single _necessary_ method\n    # which describes an order of attributes of type (here - SEQUENCE) to be encoded/decoded\n    method ASN-order() {\n        \u003c$!name $!message $!fuel $!speed $!payload\u003e\n    }\n}\n\nmy $rocket = Rocket.new(\n        name =\u003e 'Falcon',\n        fuel =\u003e Solid,\n        speed =\u003e SpeedChoice.new((mph =\u003e 18000)),\n        payload =\u003e ASNSequenceOf[ASN::Types::UTF8String].new(seq =\u003e [\"Car\", \"GPS\"])\n);\n\nsay ASN::Serializer.serialize($rocket, :mode(Implicit)); # for now only IMPLICIT tag schema is supported and flag is not really used\n# `ASN::Serializer.serialize($rocket, :debug)` - `debug` named argument enables printing of basic debugging messages\n\n# Result: Blob.new(\n#            0x30, 0x1B, # Outermost SEQUENCE\n#            0x0C, 0x06, 0x46, 0x61, 0x6C, 0x63, 0x6F, 0x6E, # NAME, MESSAGE is missing\n#            0x0A, 0x01, 0x00, # ENUMERATED\n#            0x81, 0x02, 0x46, 0x50, # CHOICE\n#            0x30, 0x0A, # SEQUENCE OF UTF8String\n#                0x0C, 0x03, 0x43, 0x61, 0x72,  # UTF8String\n#                0x0C, 0x03, 0x47, 0x50, 0x53); # UTF8String\n\n# Will return an instance of Rocket class parsed from `$rocket-encoding-result` Buf\nsay ASN::Parser.new(:type(Rocket)).parse($rocket-encoding-result, :mode(Implicit));\n```\n\n#### ASN.1 \"traits\" handling rules\n\nThe main concept is to avoid unnecessary creation of new types that just serve as envelopes for\nactual data and avoid boilerplate related to using such intermediate types. Hence, when possible,\nwe try to use native types and traits.\n\n#### Tagging schema\n\nFor now, encoding is done as if `DEFINITIONS IMPLICIT TAGS` is applied for an outermost ASN.1 unit (i.e. \"module\").\nSetting of other schemes is expected to be able to work via named argument passed to `serialize`|`parse` methods, yet this is not yet implemented.\n\n#### Mapping from ASN.1 type to ASN::BER format\n\nDefinitions of ASN.1 types are made by use of:\n\n* Universal types (`MessageID ::= INTEGER`)\n\nUniversal types are mostly handled with Raku native types, currently implemented are:\n\n| ASN.1 type      | Perl 6 type                    |\n|-----------------|--------------------------------|\n| BOOLEAN         | Bool                           |\n| INTEGER         | Int                            |\n| NULL            | ASN-Null                       |\n| OCTET STRING    | Blob or Str                    |\n| UTF8String      | Str                            |\n| ENUMERATED      | enum                           |\n| SEQUENCE        | class implementing ASNSequence |\n| SEQUENCE OF Foo | ASNSequenceOf\\[Foo\\]           |\n| SET OF Foo      | ASNSetOf\\[Foo\\]                |\n| CHOICE          | ASNChoice                      |\n\n* User defined types (`LDAPDN ::= LDAPString`)\n\nIf it is based on ASN.1 type, just use this underlying one; So:\n\n```\nLDAPString ::= OCTET STRING\nLDAPDN ::= LDAPString\n```\n\nresults in\n\n```perl6\nhas $.ldapdn is OctetString; # Ignore level of indirectness in type\n```\n\nOne can inherit a class from `ASN::BER`'s types to make structure more strict if needed.\n\n* SEQUENCE elements (`LDAPMessage ::= SEQUENCE {...}`)\n\nSuch elements are implemented as classes with `ASNSequence` role applied and `ASN-order` method implemented.\nThey are handled correctly if nested, so `a ::= SEQUENCE { ..., b SEQUENCE {...} }` will translate `a` and include\n`b` as it's part, serializing the inner class instance.\n\n* SEQUENCE OF elements\n\nSuch elements are implemented using `ASNSequenceOf` role with type parameter being type of sequence.\n\n* SET elements (`Foo ::= SET {}`)\n\nNot yet implemented, though typed `SET OF` can be done with:\n\n```perl6\nhas ASNSetOf[Int] $.values;\nsubmethod BUILD(Set :$values) { self.bless(values =\u003e ASNSetOf[Int].new($values)) }\n```\n\n* CHOICE elements\n\nCHOICE elements are implemented by `ASNChoice` role applying.\nFor same types tagging must be used to avoid ambiguity, it is usually done using context-specific tags.\n\n```\nA ::= SEQUENCE {\n    ...,\n    authentication AuthenticationChoice\n}\n\nAuthenticationChoice ::= CHOICE {\n  simple  [0] OCTET STRING,\n            -- 1 and 2 reserved\n  sasl    [3] SaslCredentials } -- SaslCredentials begin with LDAPString, which is a OCTET STRING\n```\n\nbecomes\n\n```\nclass AuthChoice is ASNChoice {\n    # This example depicts a CHOICE with context-specific tags being provided\n    # For cases where tag has an APPLICATION class, see example below\n    # We are returning a Hash which holds a description of the CHOICE structure,\n    # (name =\u003e (tag =\u003e type))\n    method ASN-choice {\n        { simple =\u003e (0 =\u003e ASN::Types::OctetString),\n          sasl   =\u003e (3 =\u003e Cro::LDAP::Authentication::SaslCredentials) }\n    }\n}\n\nclass A {\n    ...\n    has AuthChoice $.authentication;\n}\n\nA.new(..., authentication =\u003e (simple =\u003e \"466F6F\"));\n```\n\n`simple` is a key for the internal pair, which consists of a tag to use and a CHOICE option type.\n\nAnother option, when there is no ambiguity, are usages of\n\n* Universal type - are handled using appropriate universal types for a choice value.\n\n* User-defined type with `APPLICATION`-wide tag.\n\nIf ASN.1 has APPLICATION-wide tag declared, for example:\n\n```\nBindRequest ::= [APPLICATION 0] SEQUENCE {\n    ...\n}\n```\n\nit might be expressed implementing `ASN-tag-value`:\n\n```\nclass BindRequest does ASNSequence {\n    method ASN-order {...}\n    method ASN-tag-value { 0 } # [APPLICATION 0]\n}\n```\n\nIn this case, when such type is used as a part of a CHOICE, internal pair of CHOICE values is replaced with just a type:\n\n```\nclass ProtocolChoice does ASNChoice {\n    method ASN-choice {\n        { bindRequest =\u003e Cro::LDAP::Request::Bind,\n          ...\n        }\n    }\n}\n\nclass Request does ASNSequence {\n    ...\n    has ProtocolChoice $.protocol-op;\n}\n```\n\n`ASN-tag-value` method will be called and its result will be used as an APPLICATION class tag during encoding/decoding process.\n\n#### ASN.1 type traits\n\n##### Optional\n\nApply `is optional` trait to an attribute.\n\n##### Default\n\nApply `is default-value` trait to an attribute. It additionally sets `is default` trait with the same value.\n\n#### Debugging\n\nYou can set environment variables `ASN_BER_PARSER_DEBUG` and `ASN_BER_SERIALIZER_DEBUG`\nto print parser's and serializer's debug output respectively.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faltai-man%2Fasn-ber","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faltai-man%2Fasn-ber","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faltai-man%2Fasn-ber/lists"}