ASN 全名 Abstract Syntax Notation, 翻译过来就是:抽象语法标记。
ASN.1 可能是第一版的意思(?)。

asn.1 是一套国际标准,用来定义一种通用的、严谨的数据表示(标记)方法,以及对应的数据编码格式。
PS:对数据 Scheme 的定义独立于硬件架构和编程语言。

  • ITU-T Rec. X.680 (2015) | ISO/IEC 8824-1:2015
    Specification of basic notation
  • ITU-T Rec. X.681 (2015) | ISO/IEC 8824-2:2015
    Information object specification
  • ITU-T Rec. X.682 (2015) | ISO/IEC 8824-3:2015
    Constraint specification
  • ITU-T Rec. X.683 (2015) | ISO/IEC 8824-4:2015
    Parameterization of ASN.1 specifications
  • ITU-T Rec. X.690 (2015) | ISO/IEC 8825-1:2015
    BER , CER and DER
    PS:常见证书格式 der 就是来自这个 DER。
  • ITU-T Rec. X.691 (2015) | ISO/IEC 8825-2:2015
    PER (Packed Encoding Rules)
  • ITU-T Rec. X.692 (2015) | ISO/IEC 8825-3:2015
    ECN (Extended Component Notation)
  • ITU-T Rec. X.693 (2015) | ISO/IEC 8825-4:2015
    XER (XML Encoding Rules)
  • ITU-T Rec. X.694 (2015) | ISO/IEC 8825-5:2015
    Mapping W3C XML schema definitions into ASN.1
  • ITU-T Rec. X.695 (2015) | ISO/IEC 8825-6:2015
    Registration and application of PER encoding instructions
  • ITU-T Rec. X.696 (2015) | ISO/IEC 8825-7:2015
    OER (Octet Encoding Rules)
  • ITU-T Rec. X.697 (2017) | ISO/IEC 8825-8:2018
    JER (JSON Encoding Rules)
  • 一般又被称之为 X.680 系列,最早是 1995 年出第一版。最新的是 2018 年出的 5.4 版(X.680 (2015) Amd. 1)
    PS:2021 年 X.680 出了第六版。

    部分应用层的网络协议就使用了 ASN.1 格式,比如 X.500 Directory Services,LDAP,VoIP,PKCS,Kerberos,移动通信(2G/GSM,GRPS,一直到 5G)。

    它和 JSON 这种通用数据交换格式完全不同,更加类似与 protobuf,msgpack,thrift 这样,提供一个完备的数据定义语法用来声明 Schema(ASN.1 称之为模块),然后基于二进制紧凑地表示数据。所以非常适合用在 C/S 架构的网络编程上,作为服务通讯协议的一部分,负责内外数据交换,也就是 TCP/UDP 服务的接口部分。

    如果要将 ASN.1 归类的话,更贴切的应该是接口定义语言,或者叫协议定义语言。

    要是了解到 ASN.1 出现的年份(1984)的话,对照它的竞争者出现的时间,会发现它的设计确实比较超前。不管怎么说,这些晚辈确实更加流行,作为国际标准的 ASN.1 不够卖座,肯定是也有不好的地方。
    PS:可能是 ASN.1 历史包袱太重, 不够轻便 (我看到的一些评论和我的猜想比较符合)。

    先来一个示例(维基上找来的,感觉没啥意义):

    FooProtocol DEFINITIONS ::= BEGIN
        FooQuestion ::= SEQUENCE {
            -- 跟踪编号,后面括号是限制值的范围
            trackingNumber INTEGER(0..199),
            -- 问题内容,字符串
            question       IA5String
        FooAnswer ::= SEQUENCE {
            -- 问题编号
            questionNumber INTEGER(10..20),
            -- 答案内容
            answer         BOOLEAN
        FooHistory ::= SEQUENCE {
            -- 问题数组
            questions SEQUENCE(SIZE(0..10)) OF FooQuestion,
            -- 答案数组
            answers   SEQUENCE(SIZE(1..10)) OF FooAnswer,
            -- 一个整型数组
            anArray   SEQUENCE(SIZE(100))  OF INTEGER(0..1000),
    
  • 大小写字母,数字,短横杠,空格
    标识符:小写字母开头
    类型名称:大写字母开头
  • 多个空白符号(空格、换行)会当作一个空格
  • 数据类型都有一个 TagNumber
  • -- 注释
  • 结构化类型
    其他类型:CHOICEANY

  • 0 Universal 通用类型
  • 1 Application 应用协议相关类型
  • 2 Context-specific
  • 3 Private 自定义
  • 原始类型:

    Tag number
  • 基本编码规则(BER,Basic Encoding Rules)
  • 规范编码规则(CER,Canonical Encoding Rules)
  • 唯一编码规则(DER,Distinguished Encoding Rules)
  • 压缩编码规则(PER,Packed Encoding Rules)
  • XML 编码规则(XER,XML Encoding Rules)
  • Python

    https://www.cnblogs.com/20175211lyz/p/12769883.html
    https://github.com/etingof/pyasn1

    上面的示例通过 asn1ate /tmp/foo.asn > /tmp/foo.py 生成 Python 代码:
    PS:并不是一定需要定义成这样类的结构,只是 pyasn1 库适合这样用而已。

    from pyasn1.type import univ, char, namedtype, namedval, tag, constraint, useful
    class FooAnswer(univ.Sequence):
    FooAnswer.componentType = namedtype.NamedTypes(
        namedtype.NamedType('questionNumber', univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(10, 20))),
        namedtype.NamedType('answer', univ.Boolean())
    class FooQuestion(univ.Sequence):
    FooQuestion.componentType = namedtype.NamedTypes(
        namedtype.NamedType('trackingNumber', univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, 199))),
        namedtype.NamedType('question', char.IA5String())
    class FooHistory(univ.Sequence):
    FooHistory.componentType = namedtype.NamedTypes(
        namedtype.NamedType('questions', univ.SequenceOf(componentType=FooQuestion()).subtype(subtypeSpec=constraint.ValueSizeConstraint(0, 10))),
        namedtype.NamedType('answers', univ.SequenceOf(componentType=FooAnswer()).subtype(subtypeSpec=constraint.ValueSizeConstraint(1, 10))),
        namedtype.NamedType('anArray', univ.SequenceOf(componentType=univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, 1000))).subtype(subtypeSpec=constraint.ValueSizeConstraint(100, 100)))
    

    然后就可以使用了:

    import foo
    from pyasn1.codec.der.encoder import encode
    fa = foo.FooAnswer()
    fa['questionNumber'] = 10
    fa['answer'] = False
    fa_encoded = encode(fa)
    print(fa_encoded)  # b'0\x06\x02\x01\n\x01\x01\x00'
    print(binascii.b2a_hex(fa_encoded).decode())  # 300602010a010100
    from pyasn1.codec.der.decoder import decode
    obj, rest = decode(fa_encoded)
    print(obj)
    # Sequence:
    #  field-0=10
    #  field-1=False
    for k, v in obj.items():
        print([k, v])
        # ['field-0', <Integer value object, tagSet <TagSet object, tags 0:0:2>, payload [10]>]
        # ['field-1', <Boolean value object, tagSet <TagSet object, tags 0:0:1>, subtypeSpec <ConstraintsIntersection object, consts <SingleValueConstraint object, consts 0, 1>>, namedValues <NamedValues object, enums False=0, True=1>, payload [False]>]
    obj, rest = decode(fa_encoded, asn1Spec=foo.FooAnswer())
    print(obj)
    # FooAnswer:
    #  questionNumber=10
    #  answer=False
    # print(dict(obj.items()))
    print(dict([(k, str(v)) for k, v in obj.items()]))
    # {'questionNumber': '10', 'answer': 'False'}
    print(obj['questionNumber'].__dict__)
    print(obj['questionNumber']._value)  # 10
    print(obj['answer'].__dict__)
    print(obj['answer']._value)  # 0
    print([int(obj['questionNumber']), bool(obj['answer'])])
    

    GitHub 找到的几个相关库:

  • wbond/asn1crypto stars Python ASN.1 library with a focus on performance and a pythonic API
  • etingof/pyasn1 stars Generic ASN.1 library for Python
  • eerimoq/asn1tools stars ASN.1 parsing, encoding and decoding.
  • P1sec/pycrate stars A Python library to ease the development of encoders and decoders for various protocols and file formats; contains ASN.1
  • 参考资料与拓展阅读

  • https://en.wikipedia.org/wiki/ASN.1
  • https://zh.wikipedia.org/wiki/ASN.1
  • asn1playground 工具
  • https://asn1.netlify.app/
  • https://stackoverflow.com/questions/595279/how-does-google-protocol-buffers-compare-to-asn-1
  • How does ASN.1 compare to something like binary protobuf? 2013
  • 发布于码厩技术博客的所有文章,除注明转载外,均为作者原创,欢迎转载,但必须注明出处。
    尊重他人劳动,共创开源社区!转载请注明以下信息:
    转载来源码厩技术博客 []