ASN.1入门学习笔记

相遇总是猝不及防,而离别多是蓄谋已久,总有一些人会慢慢淡出你的生活,我们要学会接受而不是怀念

Posted by yishuifengxiao on 2024-12-27

一 标签编码规则详解

标签编码公式

标签的最终编码值通过以下公式计算:

Tag = Tag Class + Primitive/Constructed + Tag Number

在 ASN.1 中,标签(Tag) 的编码规则是基于 BER(Basic Encoding Rules)DER(Distinguished Encoding Rules) 的。标签的编码由以下三部分组成:

  1. Tag Class(标签类别)
  2. Primitive/Constructed(原始/构造)
  3. Tag Number(标签号)

Tag Class(标签类别)

标签类别用于标识标签的上下文,共有 4 种类别:

类别 值(二进制) 值(十六进制) 描述
Universal 00 0x00 通用标签,用于 ASN.1 内置类型(如 INTEGERSEQUENCE 等)。
Application 01 0x40 应用标签,由应用程序定义。
Context-specific 10 0x80 上下文特定标签,用于特定上下文中定义的类型。
Private 11 0xC0 私有标签,由私有协议定义。
  • 如果标签是 通用类型(如 INTEGERSEQUENCE),则 Tag Class = 0x00
  • 如果标签是 应用类型(如 [APPLICATION n]),则 Tag Class = 0x40
  • 如果标签是 上下文特定类型(如 [n]),则 Tag Class = 0x80
  • 如果标签是 私有类型,则 Tag Class = 0xC0

Primitive/Constructed(原始/构造)

Primitive/Constructed 用于标识数据的编码方式:

类型 值(二进制) 值(十六进制) 描述
Primitive 0 0x00 原始类型,表示数据是简单的值(如 INTEGEROCTET STRING)。
Constructed 1 0x20 构造类型,表示数据是复杂的结构(如 SEQUENCESEQUENCE OF)。
  • 如果数据类型是 原始类型(如 INTEGEROCTET STRING),则 Primitive/Constructed = 0x00
  • 如果数据类型是 构造类型(如 SEQUENCESET),则 Primitive/Constructed = 0x20

如何判断字段是原始类型还是构造类型?

  1. 原始类型(Primitive)

    • 简单数据类型,如 INTEGEROCTET STRINGBOOLEAN 等。
    • 编码时直接包含数据值。
  2. 构造类型(Constructed)

    • 复杂数据类型,如 SEQUENCESEQUENCE OFSETSET OF 等。
    • 编码时包含嵌套的子字段。

Tag Number(标签号)

标签号是一个具体的数值,用于区分同一类别中的不同标签。标签号的取值范围是 030(单字节标签)或更大(多字节标签)。

  • 如果标签号小于 31,则可以直接使用单字节表示。
  • 如果标签号大于或等于 31,则需要使用多字节表示(第一个字节的后 5 位为 11111,后续字节表示标签号)。

标签号是 ASN.1 类型的内置编号,用于区分不同的类型。以下是常见类型的标签号:

Tag 类型 Tag 类型 Tag 类型
0 BER保留 12 UFT8String 24 GeneralizedTime
1 BOOLEAN 13 RELATIVE-OID 25 GraphicString
2 INTEGER 14 保留 26 VisibleString,ISO646String
3 BIT STRING 15 保留 27 GeneralString
4 OCTET STRING 16 SEQUENCE,SEQUENCE OF 28 UniversalString
5 NULL 17 SET,SET OF 29 CHARACTER STRING
6 OBJECT IDENTIFIER 18 NumericString 30 BMPString
7 ObjectDescripion 19 PrintableString 31 保留
8 EXTERNAL,INSTANCE OF 20 TeletexString,T61String
9 REAL 21 VideotexString
10 ENUMERATED 22 IA5String
11 EMBEDDED PDV 23 UTCTime

这些标签号是 ASN.1 标准中定义的固定值,与具体的编码无关。


标签编码计算公式

标签的最终编码值通过以下公式计算:

Tag = Tag Class + Primitive/Constructed + Tag Number

  1. 通用标签 SEQUENCE

    • Tag Class = 0x00(Universal)
    • Primitive/Constructed = 0x20(Constructed)
    • Tag Number = 16SEQUENCE 的标签号)
    • Tag = 0x00 + 0x20 + 16 = 0x30
  2. 上下文特定标签 [2]

    • Tag Class = 0x80(Context-specific)
    • Primitive/Constructed = 0x00(Primitive)
    • Tag Number = 2
    • Tag = 0x80 + 0x00 + 2 = 0x82
  3. 应用标签 [APPLICATION 5]

    • Tag Class = 0x40(Application)
    • Primitive/Constructed = 0x00(Primitive)
    • Tag Number = 5
    • Tag = 0x40 + 0x00 + 5 = 0x45

如何确定 Tag Class 的取值

  • 查看 ASN.1 定义

    • 如果字段是 通用类型(如 INTEGERSEQUENCE),则 Tag Class = 0x00
    • 如果字段是 应用类型(如 [APPLICATION n]),则 Tag Class = 0x40
    • 如果字段是 上下文特定类型(如 [n]),则 Tag Class = 0x80
    • 如果字段是 私有类型,则 Tag Class = 0xC0
  • 查看协议文档

    • 协议文档通常会明确说明字段的标签类别和标签号。
  • 使用 ASN.1 工具

    • 使用 ASN.1 编译器(如 asn1cOSS Nokalva)可以自动生成标签编码规则。

隐式标签和显示标签

隐式和显式标记实际上是如何以DER二进制形式编码的。

基本的例子很清楚。普通整数,

基本例子

x INTEGER ::= 5

被编码为TLV三重02 01 05

隐式标签

x [2] IMPLICIT INTEGER ::= 5

隐式标记82取代现有的标记02,并形成另一个TLV:82 01 05,并在

显示标签

x [3] EXPLICIT INTEGER ::= 5

在原始TLV:A3 03 02 01 05周围添加了一个包装器。

标签编码示例

AuthenticateServerRequest ::= [56] SEQUENCE { -- Tag 'BF38'
serverSigned1 ServerSigned1,
serverSignature1 [APPLICATION 55] OCTET STRING, -- tag '5F37'
euiccCiPKIdToBeUsed SubjectKeyIdentifier OPTIONAL,
serverCertificate Certificate,
ctxParams1 CtxParams1,
otherCertsInChain [1] CertificateChain OPTIONAL,
crlList [2] SEQUENCE OF CertificateList OPTIONAL
}

AuthenticateServerRequest标签编码计算

AuthenticateServerRequestTag = 0x80 + 0x20 + 56 = 0xBF38

  • Tag Class0x80(上下文特定标签)。
  • Primitive/Constructed0x20(构造类型)。
  • Tag Number56(大于 31,需要使用多字节编码)。

多字节标签的编码步骤

  1. 第一个字节
    • 标签类别:0x80(上下文特定)。
    • 构造类型:0x20
    • 标签号:56(大于 31,后 5 位设置为 11111)。
    • 计算:0x80 + 0x20 + 0x1F = 0xBF
  2. 后续字节
    • 标签号 56 的二进制表示为 00111000
    • 按 7 位分组:00111000
    • 编码为:001110000x38
  3. 最终标签
    • 第一个字节:0xBF
    • 后续字节:0x38
    • 组合为:0xBF38

为什么不是 0xD8

  • 0xD8 是单字节标签的编码值,但标签号 56 大于 31,必须使用多字节编码。
  • 因此,AuthenticateServerRequest 的标签是 0xBF38,而不是 0xD8

serverSignature1标签编码计算

  • Tag Class0x40(应用标签)。
  • Primitive/Constructed0x00(原始类型)。
  • Tag Number55(大于 31,需要使用多字节编码)。

多字节标签的编码步骤

  1. 第一个字节
    • 标签类别:0x40(应用标签)。
    • 原始类型:0x00
    • 标签号:55(大于 31,后 5 位设置为 11111)。
    • 计算:0x40 + 0x00 + 0x1F = 0x5F
  2. 后续字节
    • 标签号 55 的二进制表示为 00110111
    • 按 7 位分组:00110111
    • 编码为:001101110x37
  3. 最终标签
    • 第一个字节:0x5F
    • 后续字节:0x37
    • 组合为:0x5F37

为什么不是 0x77

  • 0x77 是单字节标签的编码值,但标签号 55 大于 31,必须使用多字节编码。
  • 因此,serverSignature1 的标签是 0x5F37,而不是 0x77

otherCertsInChain标签编码计算

  • Tag Class = 0x80(Context-specific)
  • Primitive/Constructed = 0x20(Constructed)
  • Tag Number = 1
  • Tag = 0x80 + 0x20 + 1 = 0xA1

二 前置知识

ASN.1类型系统

基本类型

类型 编码标识 备注
BIT STRING 0x03 位或二进制字符串是任意长度的位数组。 特定位可以通过带圆括号的整数和分配的名称进行标识
BOOLEAN 0x01 布尔类型可以包含两个值之一: TRUEFALSE
INTEGER 0x02 整数通常可以是任何正整数值或负整数值
Null 0x05 NULL 类型包含单个字节0x00。 它可用于证书请求必须指示空值的任何位置。 例如, AlgorithmIdentifier 是一个序列,其中包含对象标识符 (OID) 和可选参数。
对象标识符(OBJECT_ID) 0x06 证书注册 API 使用对象标识符 (OID) 作为一种指向算法标识符、属性和其他 PKI 元素的通用指针。 OID 通常以点状十进制字符串表示,例如“2.16.840.1.101.3.4.1.42”。 字符串中的单个元素(用句点分隔)表示注册机构树中的弧形和叶,该树唯一标识对象和注册它的组织。 例如,前面的 OID 可以扩展到 joint-iso-itu-t (2) 国家/地区 (16,) 我们 (840) 组织 (1) gov (101) csor (3) nistAlgorithms (4) aesAlgs (1) 追加了 0.42,用于唯一标识 256 位 AES 密码块链 (CBC) 模式算法。
八进制字符串(OCTET_STRING) 0x04 八进制字符串是任意大的字节数组。 但是,与 BIT STRING 类型不同,无法为字符串中的特定位和字节分配名称。 八位字节一词是一种独立于平台的方式来引用内存词。 在证书注册 API 的上下文中,八位字节和字节可互换。

字符串类型

类型 编码标识 备注
BMPString(UNICODE_STRING) 0x1E 基本多语言平面 (BMP) 是一种字符编码,包含通用字符集 (UCS) 的第一个平面。 共有17架编号为 0 到 16 的飞机。 BMP 占用平面 0,包含从 0x0000 到 0xFFFF 的 65,536 个码位。 这是 Unicode 字符映射的一部分,到目前为止,大多数字符分配都已在此处。 它包括拉丁语、中东语、亚洲语、非洲语和其他语言。
IA5String(IA5_STRING) 0x16 国际字母数字 5 (IA5) 通常等效于 ASCII 字母表,但不同的版本可以包括特定于区域语言的重音或其他字符。 以下示例演示 AlternativeNames 证书扩展的 ASN.1 定义中使用的 IA5String 类型
PrintableString(PRINTABLE_STRING) 0x13 PrintableString 数据类型最初旨在表示可用于大型机输入终端的有限字符集,但仍常用。 它包含以下字符:A-Z a-z 0-9 ' ( ) + , - . / : = ? [space]
TeletexString 0x14 TeletexString 和相关 T61String 数据类型在 8 位 (编码,或复合字符) 的 16 位编码。 它们都有0x14的标记号。 它们未得到广泛使用。
UTF8String(UTF8_STRING) 0x0C 8 位 UCS/Unicode 转换格式 (UTF-8) 是一种长度可变的字符编码,可以将任何通用字符表示为 Unicode 字符,同时允许初始码位与 ASCII 保持一致。 UTF-8 使用 1 到 4 个字节。 标记号为0x0C。

构造类型

类型 编码标识 备注
SEQUENCE 和 SEQUENCE OF 0x30 包含一个或多个类型的有序字段系列。 字段可以标记为OPTIONALDEFAULT。 此外,为了避免解码时出现歧义,连续的可选字段应通过使用唯一标识符 (括号整数(如 [1]) )和以下必填字段彼此不同。SEQUENCESEQUENCE OF 的区别在于 SEQUENCE OF 构造的元素必须属于同一类型。 请参阅以下示例。 两个构造在编码时 (0x30) 具有相同的标记值。了解 SEQUENCESEQUENCE OF 之间的差异的另一种方法是将它们与 C 编程语言中的对应项进行比较。 也就是说, SEQUENCE 大致等效于结构, SEQUENCE OF 大致等效于数组。
SET 和 SET OF 0x31 包含一个或多个类型的无序字段系列。 这与包含有序列表的 SEQUENCE 不同。 通过指定无序列表,应用程序可以按最合适的顺序向编码器提供结构字段。 与 SEQUENCE 一样, SET 构造的字段可以标记为 OPTIONALDEFAULT,并且必须使用唯一标识符来消除解码过程的歧义。 SETSET OF 的区别在于,SET OF 构造的元素必须属于同一类型。
选择(CHOICE) 定义替代方案之间的选择。 每个替代项都必须由带括号的整数唯一标识,以避免解码时出现歧义。 编码后, CHOICE 构造将具有所选替代项的编码标记值。
  • 标签号SEQUENCE 的标签号是 16,这是 ASN.1 标准中定义的内置编号。
  • 标签编码SEQUENCE 的标签编码是 0x30,这是根据标签类、原始/构造标志和标签号计算出的最终字节表示。

换句话说:

  • 标签号16SEQUENCE 的内置编号。
  • 标签编码0x30SEQUENCE 的 BER 编码结果。

X.509 证书

在 X.509 证书中,字段分为 基本字段(Basic Fields)扩展字段(Extensions)。以下是这些字段的定义及其标签号的详细说明:


基本字段(Basic Fields)

基本字段是 X.509 证书的核心部分,包含证书的基本信息。以下是主要的基本字段及其标签号:

字段名 定义 标签号(Tag Number)
Version 证书版本号,表示证书的格式版本(如 v1、v2、v3)。 0(上下文特定)
Serial Number 证书的唯一序列号,由证书颁发机构(CA)分配。 2(INTEGER)
Signature Algorithm 用于签名证书的算法标识符(如 SHA256WithRSA)。 6(OBJECT IDENTIFIER)
Issuer 证书颁发者(CA)的名称,使用 Distinguished Name(DN)表示。 16(SEQUENCE)
Validity 证书的有效期,包含开始时间和结束时间。 16(SEQUENCE)
Subject 证书持有者的名称,使用 Distinguished Name(DN)表示。 16(SEQUENCE)
Subject Public Key Info 证书持有者的公钥信息,包含公钥算法和公钥值。 16(SEQUENCE)
Issuer Unique ID 证书颁发者的唯一标识符(可选,仅 v2 和 v3 证书支持)。 1(BIT STRING)
Subject Unique ID 证书持有者的唯一标识符(可选,仅 v2 和 v3 证书支持)。 2(BIT STRING)

扩展字段(Extensions)

扩展字段是 X.509 v3 证书中的可选部分,用于提供额外的信息。以下是主要的扩展字段及其标签号:

字段名 定义 标签号(Tag Number)
Authority Key Identifier 标识证书颁发者的公钥,用于证书链验证。 2(OCTET STRING)
Subject Key Identifier 标识证书持有者的公钥,用于证书链验证。 4(OCTET STRING)
Key Usage 定义证书的公钥用途(如数字签名、加密等)。 3(BIT STRING)
Extended Key Usage 定义证书的公钥扩展用途(如 TLS 客户端认证、代码签名等)。 6(SEQUENCE)
Basic Constraints 定义证书是否为 CA 证书以及证书链的最大深度。 16(SEQUENCE)
Subject Alternative Name 证书持有者的备用名称(如电子邮件、DNS 名称等)。 2(SEQUENCE)
Issuer Alternative Name 证书颁发者的备用名称(如电子邮件、DNS 名称等)。 2(SEQUENCE)
CRL Distribution Points 证书吊销列表(CRL)的分布点,用于检查证书是否被吊销。 16(SEQUENCE)
Certificate Policies 证书的策略信息,描述证书的使用策略。 16(SEQUENCE)
Policy Mappings 定义不同 CA 之间的策略映射(仅用于 CA 证书)。 16(SEQUENCE)
Name Constraints 定义证书中名称的限制(仅用于 CA 证书)。 16(SEQUENCE)
Policy Constraints 定义证书策略的限制(仅用于 CA 证书)。 16(SEQUENCE)
Authority Information Access 提供访问 CA 信息的途径(如 OCSP 服务地址)。 1(SEQUENCE)
Subject Information Access 提供访问证书持有者信息的途径。 1(SEQUENCE)

IX509AttributeExtensions 接口可用于定义一组 X.509 版本 3 证书扩展。 支持以下扩展。 有关详细信息,请参阅扩展接口主题。

展开表

分机 说明
AlternativeNames 包含与证书关联的颁发者的一个或多个备用名称形式。
AuthorityKeyIdentifier 包含唯一密钥标识符,用于区分证书颁发机构 (CA) 的多个 证书 签名密钥。
BasicConstraints 指示使用者是否可以充当 CA。
CertificatePolicies 标识与证书关联的策略和可选限定符信息。
MSApplicationPolicies 标识证书的一个或多个用途。 此扩展类似于 EnhancedKeyUsage 扩展,但由 Microsoft 定义。
EnhancedKeyUsage 标识证书中包含的公钥的一个或多个用法。 除了或取代密钥用法扩展之外,还可以使用增强的密钥用法扩展。
KeyUsage 标识对可由证书中包含的公钥执行的操作的限制。
SmimeCapabilities 向电子邮件发件人报告电子邮件收件人的解密功能,使发件人能够选择双方支持的最安全对称算法。
SubjectKeyIdentifier 包含可用于区分与证书所有者关联的多个签名密钥的唯一密钥标识符。
模板 标识颁发或续订证书时要使用的模板。 该扩展包含模板的 OID) (对象标识符。
TemplateName 标识颁发或续订证书时要使用的模板。 扩展包含模板的名称。

标签号(Tag Number)的说明

在 ASN.1 中,标签号是用于标识类型的固定值。以下是常见类型的标签号:

  • INTEGER2
  • BIT STRING3
  • OCTET STRING4
  • OBJECT IDENTIFIER6
  • SEQUENCESEQUENCE OF16

在 X.509 证书中,字段的标签号通常基于其类型。例如:

  • Serial NumberINTEGER 类型,因此标签号为 2
  • Subject Key IdentifierOCTET STRING 类型,因此标签号为 4
  • IssuerSEQUENCE 类型,因此标签号为 16

X.509 证书的基本字段和扩展字段及其标签号如下:

  • 基本字段:如 VersionSerial NumberIssuerSubject 等,标签号基于其类型(如 INTEGERSEQUENCE 等)。
  • 扩展字段:如 Authority Key IdentifierSubject Key IdentifierKey Usage 等,标签号也基于其类型(如 OCTET STRINGBIT STRING 等)。

X.509证书和证书链的 ASN.1 定义

以下是 X.509 证书证书链(Certificate Chain) 的 ASN.1 定义的全部内容,包括相关字段的详细说明。

X.509证书的ASN.1定义

X.509 证书的 ASN.1 定义基于 RFC 5280 标准,以下是其完整定义:

Certificate ::= SEQUENCE {
tbsCertificate TBSCertificate,
signatureAlgorithm AlgorithmIdentifier,
signatureValue BIT STRING
}

TBSCertificate ::= SEQUENCE {
version [0] EXPLICIT Version DEFAULT v1,
serialNumber CertificateSerialNumber,
signature AlgorithmIdentifier,
issuer Name,
validity Validity,
subject Name,
subjectPublicKeyInfo SubjectPublicKeyInfo,
issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
extensions [3] EXPLICIT Extensions OPTIONAL
}

Version ::= INTEGER { v1(0), v2(1), v3(2) }

CertificateSerialNumber ::= INTEGER

AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL
}

Name ::= CHOICE {
rdnSequence RDNSequence
}

RDNSequence ::= SEQUENCE OF RelativeDistinguishedName

RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue

AttributeTypeAndValue ::= SEQUENCE {
type AttributeType,
value AttributeValue
}

AttributeType ::= OBJECT IDENTIFIER

AttributeValue ::= ANY DEFINED BY AttributeType

Validity ::= SEQUENCE {
notBefore Time,
notAfter Time
}

Time ::= CHOICE {
utcTime UTCTime,
generalTime GeneralizedTime
}

SubjectPublicKeyInfo ::= SEQUENCE {
algorithm AlgorithmIdentifier,
subjectPublicKey BIT STRING
}

UniqueIdentifier ::= BIT STRING

Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension

Extension ::= SEQUENCE {
extnID OBJECT IDENTIFIER,
critical BOOLEAN DEFAULT FALSE,
extnValue OCTET STRING
}

关键字段说明:

  1. tbsCertificate:证书的核心部分,包含版本、序列号、颁发者、有效期、持有者、公钥等信息。
  2. signatureAlgorithm:用于签名证书的算法标识符。
  3. signatureValue:证书的签名值。
  4. version:证书的版本号(v1、v2 或 v3)。
  5. serialNumber:证书的唯一序列号。
  6. issuer:证书颁发者的名称(Distinguished Name)。
  7. validity:证书的有效期(开始时间和结束时间)。
  8. subject:证书持有者的名称(Distinguished Name)。
  9. subjectPublicKeyInfo:持有者的公钥信息。
  10. extensions:证书的扩展字段(仅 v3 证书支持)。

证书链(Certificate Chain)的 ASN.1 定义

证书链:是一个 SEQUENCE OF 类型,包含多个 Certificate

证书链是由多个 X.509 证书组成的序列,用于构建信任链。以下是证书链的 ASN.1 定义:

CertificateChain ::= SEQUENCE OF Certificate

关键字段说明:

  1. CertificateChain:证书链是一个 SEQUENCE OF 类型,包含多个 Certificate
  2. Certificate:每个证书的 ASN.1 定义与上述 X.509 证书的定义一致。

相关字段的详细说明

AlgorithmIdentifier( 签名证书的算法标识符 )

AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL
}
  • algorithm:算法的 OID(如 SHA256WithRSA)。
  • parameters:算法的参数(可选)。

SubjectPublicKeyInfo( 持有者的公钥信息 )

SubjectPublicKeyInfo ::= SEQUENCE {
algorithm AlgorithmIdentifier,
subjectPublicKey BIT STRING
}
  • algorithm:公钥的算法标识符。
  • subjectPublicKey:公钥的二进制值。

Extensions( 证书的扩展字段 )

Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension

Extension ::= SEQUENCE {
extnID OBJECT IDENTIFIER,
critical BOOLEAN DEFAULT FALSE,
extnValue OCTET STRING
}
  • extnID:扩展的 OID(如 id-ce-keyUsage)。
  • critical:扩展是否关键(默认为 FALSE)。
  • extnValue:扩展的值(以 OCTET STRING 编码)。

TLV数据结构

java处理TLV数据

public static String toTLV(String input) {
int inputLen = input.length() / 2;
StringBuilder sb = new StringBuilder();
String strInputLenString = toHex(String.valueOf(inputLen));
if (inputLen > 65535) {
// len <65535
sb.append("83").append(strInputLenString).append(input);
} else if (inputLen > 255) {
// 255<len<=65535 65535==0xFFFF
sb.append("82").append(strInputLenString).append(input);
} else if (inputLen > 127) {
// 127<len<=255 255==0xFF
sb.append("81").append(strInputLenString).append(input);
} else {
// len < 127
sb.append(strInputLenString).append(input);
}

return sb.toString();
}

private static String toHex(String num) {
String hex = Integer.toHexString(Integer.parseInt(num));
if (hex.length() % 2 != 0) {
hex = "0" + hex;
}
return hex.toUpperCase();
}

public String fetchValueFromTlv(String tag, String tlv) {
String nextLenFlag = tlv.substring(tag.length(), tag.length() + 2);
String val = tlv.substring(tlv.indexOf(tag) + tag.length());
String result;
String lenText;
int lenVal;
switch (nextLenFlag) {
case "83":
lenText = val.substring(nextLenFlag.length(), nextLenFlag.length() + 6);
lenVal = Integer.valueOf(lenText, 16) * 2;
result = val.substring(nextLenFlag.length() + 6, nextLenFlag.length() + 6 + lenVal);
break;
case "82":
lenText = val.substring(nextLenFlag.length(), nextLenFlag.length() + 4);
lenVal = Integer.valueOf(lenText, 16) * 2;
result = val.substring(nextLenFlag.length() + 4, nextLenFlag.length() + 4 + lenVal);
break;
case "81":
lenText = val.substring(nextLenFlag.length(), nextLenFlag.length() + 2);
lenVal = Integer.valueOf(lenText, 16) * 2;
result = val.substring(nextLenFlag.length() + 2, nextLenFlag.length() + 2 + lenVal);
break;
case "00":
result = "";
break;
default:
lenVal = Integer.valueOf(nextLenFlag, 16) * 2;
result = val.substring(nextLenFlag.length(), nextLenFlag.length() + lenVal);
}

return result;
}

OID数据解析

数据解析

id-rspRole-ds-tls-v2 OBJECT IDENTIFIER ::= {id-rspRole 6}

解释

  1. id-rspRole-ds-tls-v2 OBJECT IDENTIFIER ::= {id-rspRole 6}

    • 这行定义了一个名为 id-rspRole-ds-tls-v2OBJECT IDENTIFIER (OID)
    • 它的值是 id-rspRole 这个 OID 的扩展,具体是在 id-rspRole 的基础上追加了一个节点 6
    • 假设 id-rspRole 是一个已知的 OID,例如 1.2.3.4.5,那么 id-rspRole-ds-tls-v2 的值就是 1.2.3.4.5.6
  2. OID 的结构

    • OID 是由一系列整数组成的层次化结构,用于唯一标识某个对象或概念。
    • 每个节点用点号 . 分隔,例如 1.2.3.4.5.6
  3. id-rspRole 的含义

    • id-rspRole 是一个父 OID,可能是某个标准或协议中定义的根 OID。
    • 具体含义需要查看上下文或相关文档。

16 进制示例数据

假设 id-rspRole 的值为 1.2.3.4.5,那么 id-rspRole-ds-tls-v2 的值就是 1.2.3.4.5.6

编码规则

OID 的编码规则如下:

  1. 第一个字节编码前两个节点:1 * 40 + 2 = 42(即 0x2A)。
  2. 后续节点按以下规则编码:
    • 如果节点值小于 128,则直接用一个字节表示。
    • 如果节点值大于或等于 128,则使用多个字节表示,每个字节的最高位为 1,最后一个字节的最高位为 0。

编码过程

  • OID: 1.2.3.4.5.6
  • 编码步骤:
    1. 第一个节点:1 * 40 + 2 = 420x2A
    2. 第二个节点:30x03
    3. 第三个节点:40x04
    4. 第四个节点:50x05
    5. 第五个节点:60x06
  • 最终编码:2A 03 04 05 06

完整的 DER 编码

  • Tag: 0x06(表示 OBJECT IDENTIFIER)
  • Length: 0x05(值占用 5 个字节)
  • Value: 2A 03 04 05 06
  • 完整的 16 进制数据:06 05 2A 03 04 05 06

总结

  • id-rspRole-ds-tls-v2 的 OID 值是 1.2.3.4.5.6
  • 其 DER 编码的 16 进制数据是:06 05 2A 03 04 05 06

如果 id-rspRole 的值不同,只需替换 2A 03 04 05 部分即可。

解析示例

具体来说,2A864886F70D01010C对应的分解:

2A 86 48 86 F7 0D 01 01 0C


1. 前两个数字是1.2(由2A=42=1*40 +2)。
2. 0x86 0x48。根据OID编码规则,86 48的分解:
- 0x86的二进制是10000110,去掉最高位得到0000110(6),
剩下的部分需要与下一个字节0x48(01001000)组合。
因为0x86的最高位是1,表示后续的字节属于同一个数字。
所以计算方式为:6 << 7(因为每个后续字节贡献7位)加上 0x48(72),
即6*128 +72= 768 +72= 840。
即 6 << 7+72 =840

3. 接下来的字节是86 F7 0D
- 0x86的二进制10000110,去掉最高位得到0000110(6),
然后下一个字节0xF7是11110111,去掉最高位得到1110111(0x77=119),
因为最高位是1,继续下一个字节0x0D(00001101)。
此时,前面的部分组合为:6 << 14(因为两个后续字节)+ 119 <<7 + 13。

即 6 << 14+119 <<7+13 =113519

4. 接下来的01 01对应的是1.1,因为0x01转换为十进制是1。
5. 最后的0C对应的是12,所以整个OID是1.2.840.113549.1.1.12,
十六进制 二进制 十进制 十六进制 二进制 十进制
86 1000 0110 134(0b0110=0d6) 48 0100 1000 72
86 1000 0110 134 F7 1111 0111 247
0D 0000 1101 13 01 0000 0001 1
01 0000 0001 1 0C 0000 1100 12

SGP.22 eUICC信息 EUICCInfo1 结构详解

整体定义

EUICCInfo1 ::= [32] SEQUENCE { -- Tag 'BF20'
lowestSvn [2] VersionType,
euiccCiPKIdListForVerification [9] SEQUENCE OF SubjectKeyIdentifier,
euiccCiPKIdListForSigning [10] SEQUENCE OF SubjectKeyIdentifier,
euiccCiPKIdListForSigningV3 [17] SEQUENCE OF SubjectKeyIdentifier OPTIONAL,
euiccRspCapability [8] EuiccRspCapability OPTIONAL,
highestSvn [19] VersionType OPTIONAL
}
  • 标签 BF20(十六进制):表示此结构的唯一标识,编码时需按 ASN.1 规则处理(32==0x20)。
  • 类型 SEQUENCE:字段按定义顺序排列,不可乱序。

字段逐行解析

lowestSvn

lowestSvn [2] VersionType
  • 含义:eUICC 支持的最低安全版本号(SVN)。
  • 标签 [2]:上下文特定标签,编码为 0x82(隐式标签)。
  • 类型 VersionType:通常为 INTEGER,表示版本号。
    • 示例:版本号为 1,编码为 82 01 01
    • 公式:0x80 + 0x00 + 2 = 0x82

euiccCiPKIdListForVerification

euiccCiPKIdListForVerification  [9]  SEQUENCE OF SubjectKeyIdentifier
  • 含义:用于验证签名的 eSIM CA 根证书公钥标识符列表。
  • 标签 [9]:编码为 0xA9(构造类型)。
  • 类型 SubjectKeyIdentifier:通常为 OCTET STRING(如 SHA-1 哈希值)。
  • 示例:两个标识符 0x01020x0304,编码为:
    A9 08          -- 标签和长度
    04 02 01 02 -- 第一个标识符
    04 02 03 04 -- 第二个标识符

详细计算过程

  1. Tag Class:标签 [9] 是上下文特定标签,因此 Tag Class0x80

  2. Primitive/Constructed:字段 euiccCiPKIdListForVerification 是一个 SEQUENCE OF,属于构造类型(Constructed),因此 Primitive/Constructed0x20

  3. Tag Number:标签号为 9

    Tag = Tag Class + Primitive/Constructed + Tag Number
    = 0x80 + 0x20 + 9
    = 0xA9

为什么是 0xA9 而不是 0x89

  • 如果字段是原始类型(Primitive),则 Primitive/Constructed0x00,编码值为 0x80 + 9 = 0x89
  • SEQUENCE OF 是构造类型(Constructed),因此 Primitive/Constructed0x20,编码值为 0xA0 + 9 = 0xA9

euiccCiPKIdListForSigning

euiccCiPKIdListForSigning [10] SEQUENCE OF SubjectKeyIdentifier
  • 含义:用于签名且可通过 Variant O 验证的 eSIM CA 根证书公钥标识符列表。
  • 标签 [10]:编码为 0xAA(构造类型)。
  • 示例:单个标识符 0x0506,编码为:
    AA 06          -- 标签和长度
    04 04 05 06 -- 标识符

euiccCiPKIdListForSigningV3

euiccCiPKIdListForSigningV3 [17] SEQUENCE OF SubjectKeyIdentifier OPTIONAL
  • 含义:支持 Variant Ov3/A/B/C 签名的公钥标识符列表(V3.0.0 起支持)。

  • 标签 [17]:编码为 0xB1(构造类型)。

  • OPTIONAL:如果不存在,则省略此字段。

  • 公式:0x80 + 0x20 + 17 = 0xB1

euiccRspCapability

euiccRspCapability [8] EuiccRspCapability OPTIONAL
  • 含义:eUICC 的远程管理能力(V3.0.0 起必填)。
  • 标签 [8]:编码为 0x88
  • 类型 EuiccRspCapability:可能是枚举或位字符串(如 01 表示支持)。
  • 公式:0x80 + 0x00 + 8 = 0x88

highestSvn

highestSvn [19] VersionType OPTIONAL
  • 含义:eUICC 支持的最高安全版本号(V3.0.0 起支持)。
  • 标签 [19]:编码为 0x93
  • 示例:版本号为 3,编码为 93 01 03
  • 公式:0x80 + 0x00 + 19 = 0x93

示例解析

假设一个 V3.0.0 实例的编码数据(BER 格式):

BF20 1B          -- 标签和总长度 (27 bytes)
82 01 01 -- lowestSvn=1
A9 08 -- euiccCiPKIdListForVerification (长度 8)
04 02 01 02
04 02 03 04
AA 06 -- euiccCiPKIdListForSigning (长度 6)
04 02 05 06
88 01 01 -- euiccRspCapability=1
93 01 03 -- highestSvn=3

解析步骤:

  1. 识别整体结构:标签 BF20 表示这是一个 EUICCInfo1 结构,长度 0x1B(27 字节)。
  2. 解析字段
    • 82 01 01lowestSvn = 1
    • A9 08 → 两个验证公钥标识符 01020304
    • AA 06 → 一个签名公钥标识符 0506
    • 88 01 01 → 远程管理能力为 1
    • 93 01 03highestSvn = 3
  3. 省略字段euiccCiPKIdListForSigningV3 未出现(OPTIONAL)。

关键注意事项

  1. 标签编码:每个字段的标签需按上下文特定规则处理(如 [2]0x82)。
  2. 顺序性SEQUENCE 字段必须按定义顺序出现。
  3. 版本约束:V3.0.0 起 euiccRspCapability 必填,highestSvn 可选。
  4. OPTIONAL 字段:若不存在,编码中直接省略。

euiccCiPKIdListForVerification 的编码示例

原始数据

A9 08          -- 标签和长度 (8 bytes)
04 02 01 02 -- 第一个标识符 (长度 2,值 0102)
04 02 03 04 -- 第二个标识符 (长度 2,值 0304)

解析

  • A9:标签,表示 euiccCiPKIdListForVerification 是一个构造类型的上下文特定标签([9])。
  • 08:长度,表示后续数据的总长度是 8 字节。
  • 04 02 01 02
    • 04OCTET STRING 的标签。
    • 02:长度,表示 OCTET STRING 的值占 2 字节。
    • 01 02:实际的标识符值。
  • 04 02 03 04
    • 04OCTET STRING 的标签。
    • 02:长度,表示 OCTET STRING 的值占 2 字节。
    • 03 04:实际的标识符值。

长度计算

  • 总长度 = 标签(1 字节) + 长度(1 字节) + 数据(6 字节) = 8 字节。
  • 数据部分:
    • 第一个标识符:04 02 01 02(4 字节)。
    • 第二个标识符:04 02 03 04(4 字节)。
    • 总计:4 + 4 = 8 字节。

euiccCiPKIdListForSigning 的编码示例

原始数据

AA 06          -- 标签和长度 (6 bytes)
04 02 05 06 -- 标识符 (长度 2,值 0506)

解析

  • AA:标签,表示 euiccCiPKIdListForSigning 是一个构造类型的上下文特定标签([10])。
  • 06:长度,表示后续数据的总长度是 6 字节。
  • 04 02 05 06
    • 04OCTET STRING 的标签。
    • 02:长度,表示 OCTET STRING 的值占 2字节。
    • 05 06:实际的标识符值(2 字节)

java解析EUICCInfo1数据

package com.demo;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class DemoMain {

static String text = "BF20 6C \n" +
" 82 03 020200\n" +
" A9 2C 0414F54172BDF98A95D65CBEB88A38A1C11D800A85C3041416F1DE9DEAA1DEBC8F61C8E6C1243DFB54781851\n" +
" AA 00\n" +
" B1 2C 0414F54172BDF98A95D65CBEB88A38A1C11D800A85C3041416F1DE9DEAA1DEBC8F61C8E6C1243DFB54781851\n" +
" 88 02 0490\n" +
" 93 03 030000";

public static void main(String[] args) {
String paramString = text.replaceAll("\\s", "").trim();
String str1 = paramString;
System.out.println(str1);

String BF20_val = (new ToTLV()).fetchValueFromTlv("BF20", str1);
//8203020200A92C0414F54172BDF98A95D65CBEB88A38A1C11D800A85C3041416F1DE9DEAA1DEBC8F61C8E6C1243DFB54781851AA00B12C0414F54172BDF98A95D65CBEB88A38A1C11D800A85C3041416F1DE9DEAA1DEBC8F61C8E6C1243DFB54781851880204909303030000
log.info("BF20_val的值为:"+BF20_val);

String svnVal = (new ToTLV()).fetchValueFromTlv("82", BF20_val);
// 020200
log.info("svnVal : " + svnVal);

String str4 = (new ToTLV()).O000000o("82", BF20_val);
//A92C0414F54172BDF98A95D65CBEB88A38A1C11D800A85C3041416F1DE9DEAA1DEBC8F61C8E6C1243DFB54781851AA00B12C0414F54172BDF98A95D65CBEB88A38A1C11D800A85C3041416F1DE9DEAA1DEBC8F61C8E6C1243DFB54781851880204909303030000
log.info("str4 : " + str4);

String euiccCipkidListForVerificationVal = (new ToTLV()).fetchValueFromTlv("A9", str4);
//0414F54172BDF98A95D65CBEB88A38A1C11D800A85C3041416F1DE9DEAA1DEBC8F61C8E6C1243DFB54781851
log.info("euiccCipkidListForVerificationVal : " + euiccCipkidListForVerificationVal);

String str6 = (new ToTLV()).O000000o("A9", str4);
//AA00B12C0414F54172BDF98A95D65CBEB88A38A1C11D800A85C3041416F1DE9DEAA1DEBC8F61C8E6C1243DFB54781851880204909303030000
log.info("str6 : " + str6);

String euiccCipkidListForSigningVal = (new ToTLV()).fetchValueFromTlv("AA", str6);
log.info("euiccCipkidListForSigningVal : " + euiccCipkidListForSigningVal);

String str8 = (new ToTLV()).O000000o("AA", str6);
String euiccCipkidListForSigningV3Val = (new ToTLV()).fetchValueFromTlv("B1", str8);
//0414F54172BDF98A95D65CBEB88A38A1C11D800A85C3041416F1DE9DEAA1DEBC8F61C8E6C1243DFB54781851
log.info("euiccCipkidListForSigningV3Val : " + euiccCipkidListForSigningV3Val);

String str10 = (new ToTLV()).O000000o("B1", str8);
String euiccRspCapabilityVal = (new ToTLV()).fetchValueFromTlv("88", str10);
//0490
log.info("euiccRspCapabilityVal : " + euiccRspCapabilityVal);

String str12 = (new ToTLV()).O000000o("88", str10);
String highestSvnVal = (new ToTLV()).fetchValueFromTlv("93", str12);
//030000
log.info("highestSvnVal : " + highestSvnVal);
}
}

SGP.22 eUICC信息AuthenticateServerRequest结构详解

完整的定义如下:

-- ASN1START
AuthenticateServerRequest ::= [56] SEQUENCE { -- Tag 'BF38'
serverSigned1 ServerSigned1, -- Signed information
serverSignature1 [APPLICATION 55] OCTET STRING, -- tag '5F37'
euiccCiPKIdToBeUsed SubjectKeyIdentifier OPTIONAL, -- eSIM CA RootCA Public Key
Identifier to be used; MAY also have zero length
serverCertificate Certificate, -- RSP Server Certificate CERT.XXauth.SIG
ctxParams1 CtxParams1,
otherCertsInChain [1] CertificateChain OPTIONAL, -- #SupportedFromV3.0.0# The
remaining part of the CERT.XXauth.SIG certificate chain (if any)
crlList [2] SEQUENCE OF CertificateList OPTIONAL -- #SupportedFromV3.0.0# as
specified in RFC 5280
}

ServerSigned1 ::= SEQUENCE {
transactionId [0] TransactionId, -- The Transaction ID generated by
the RSP Server
euiccChallenge [1] Octet16, -- The eUICC Challenge
serverAddress [3] UTF8String, -- The RSP Server address as an FQDN
serverChallenge [4] Octet16, -- The RSP Server Challenge
sessionContext [5] SessionContext OPTIONAL, -- #SupportedFromV3.0.0#
serverRspCapability [6] ServerRspCapability OPTIONAL -- #SupportedFromV3.0.0#
}

CtxParams1 ::= CHOICE {
ctxParamsForCommonAuthentication[0] CtxParamsForCommonAuthentication,
ctxParamsForDeviceChange [1] CtxParamsForDeviceChange,
ctxParamsForProfileRecovery [2] CtxParamsForProfileRecovery,
ctxParamsForPushServiceRegistration [3] CtxParamsForPushServiceRegistration
-- New contextual data objects MAY be defined for extensibility.
}

CtxParamsForCommonAuthentication ::= SEQUENCE {
matchingId [0] UTF8String OPTIONAL, -- The MatchingId could be the Activation
code token or EventID or empty
deviceInfo [1] DeviceInfo, -- The Device information
operationType [2] OperationType DEFAULT {profileDownload}, --
#SupportedFromV3.0.0#
iccid Iccid OPTIONAL, -- ICCID, tag '5A' #SupportedForRpmV3.0.0#
matchingIdSource [3] MatchingIdSource OPTIONAL, -- #SupportedFromV3.0.0#
vendorSpecificExtension [4] VendorSpecificExtension OPTIONAL --
#SupportedFromV3.0.0#
}

CtxParamsForDeviceChange ::= SEQUENCE { -- #SupportedForDcV3.0.0#
iccid Iccid,
deviceInfo [1] DeviceInfo,
GSM Association Non-confidential
RSP Technical Specification
SGP.22 v3.1 Page 337 of 501
targetEidValue [APPLICATION 26] Octet16 OPTIONAL,
targetTacValue [2] Octet4 OPTIONAL,
vendorSpecificExtension [3] VendorSpecificExtension OPTIONAL
}

CtxParamsForProfileRecovery ::= SEQUENCE { -- #SupportedForDcV3.0.0#
iccid Iccid,
deviceInfo [1] DeviceInfo,
vendorSpecificExtension [2] VendorSpecificExtension OPTIONAL
}

CtxParamsForPushServiceRegistration ::= SEQUENCE { --
#SupportedForPushServiceV3.0.0#
selectedPushService [0] OBJECT IDENTIFIER,
pushToken [1] UTF8String
}

MatchingIdSource ::= CHOICE {
none [0] NULL,
activationCode [1] NULL,
smdsOid [2] OBJECT IDENTIFIER
}

OperationType ::= BIT STRING {
profileDownload(0),
rpm(1)
}

-- Records information agreed along the session
SessionContext ::= SEQUENCE {
serverSvn [0] VersionType, -- RSP Server SVN (provided for information only)
crlStaplingV3Used [1] BOOLEAN, -- Indicates CRLs were attached to the RSP Server
response
euiccCiPKIdToBeUsedV3 [2] SubjectKeyIdentifier OPTIONAL,
supportedPushServices [3] SEQUENCE OF OBJECT IDENTIFIER OPTIONAL
}

-- Definition of ServerRspCapability
ServerRspCapability ::= BIT STRING {
crlStaplingV3Support (0), -- support for CRL stapling
eventListSigningV3Support (1), -- support for Event Record signing
pushServiceV3Support (2), -- support for Push Service
cancelForEmptySpnPnSupport (3),
cancelForSessionAbortedSupport (4)
}
-- ASN1STOP

AuthenticateServerRequest 标签计算

以下是 AuthenticateServerRequest 结构中所有字段的标签编码及其计算过程:


AuthenticateServerRequest 结构

AuthenticateServerRequest ::= [56] SEQUENCE { 
serverSigned1 ServerSigned1,
serverSignature1 [APPLICATION 55] OCTET STRING,
euiccCiPKIdToBeUsed SubjectKeyIdentifier OPTIONAL,
serverCertificate Certificate,
ctxParams1 CtxParams1,
otherCertsInChain [1] CertificateChain OPTIONAL,
crlList [2] SEQUENCE OF CertificateList OPTIONAL
}

AuthenticateServerRequest 标签编码

  • 标签类[56] 是上下文特定类,因此标签类为 10
  • 原始/构造标志SEQUENCE 是构造值,因此标志为 1
  • 标签号56 大于 30,需要扩展编码。
    • 56 转换为二进制:111000
    • 分为 7 位一组:111000
    • 前面加 0(最后一组):0111000
    • 转换为十六进制:0x38
  • 最终标签编码
    • 标签类和原始/构造标志:10 11010xA0
    • 标签号:0x38
    • 组合后:0xBF380xA00x38 组合)。

serverSigned1 标签编码

  • 标签类serverSigned1 是隐式标签(无显式标签),默认使用 SEQUENCE 的通用类,因此标签类为 00
  • 原始/构造标志SEQUENCE 是构造值,因此标志为 1
  • 标签号SEQUENCE 的标签号为 16
    • 16 小于 30,直接使用 5 位二进制表示:10000
  • 最终标签编码
    • 标签类和原始/构造标志:00 10010x20
    • 标签号:100000x10
    • 组合后:0x30

注意点:

  • 标签号16SEQUENCE 的内置编号。

serverSignature1 标签编码

  • 标签类[APPLICATION 55] 是应用类,因此标签类为 01
  • 原始/构造标志OCTET STRING 是原始值,因此标志为 0
  • 标签号55 大于 30,需要扩展编码。
    • 55 转换为二进制:110111
    • 分为 7 位一组:110111
    • 前面加 0(最后一组):0110111
    • 转换为十六进制:0x37
  • 最终标签编码
    • 标签类和原始/构造标志:01 00100x50
    • 标签号:0x37
    • 组合后:0x5F370x500x37 组合)。

euiccCiPKIdToBeUsed 标签编码

  • 标签类euiccCiPKIdToBeUsed 是隐式标签(无显式标签),默认使用 SubjectKeyIdentifier 的通用类,因此标签类为 00
  • 原始/构造标志SubjectKeyIdentifier 是原始值,因此标志为 0
  • 标签号SubjectKeyIdentifier 的标签号为 4
    • 4 小于 30,直接使用 5 位二进制表示:00100
  • 最终标签编码
    • 标签类和原始/构造标志:00 00000x00
    • 标签号:001000x04
    • 组合后:0x04

注意点:

SubjectKeyIdentifier 的类型

SubjectKeyIdentifier 是 X.509 证书扩展中的一个字段,用于标识证书的公钥。根据 X.509 标准(RFC 5280),SubjectKeyIdentifier 被定义为 OCTET STRING 类型。

  • OCTET STRING 是 ASN.1 中的一种基本类型,用于表示任意字节序列。
  • 标签号OCTET STRING 的标签号是 4,这是 ASN.1 标准中定义的固定值。

为什么 SubjectKeyIdentifier 是原始值

在 ASN.1 中,值的编码可以是 原始值(Primitive)构造值(Constructed)

  • 原始值:直接编码值的内容。
  • 构造值:将值的内容进一步分解为多个部分,每个部分单独编码。

SubjectKeyIdentifierOCTET STRING 类型,而 OCTET STRING 是原始类型。因此,SubjectKeyIdentifier 的编码是原始值。


serverCertificate 标签编码

  • 标签类serverCertificate 是隐式标签(无显式标签),默认使用 Certificate 的通用类,因此标签类为 00
  • 原始/构造标志Certificate 是构造值,因此标志为 1
  • 标签号Certificate 的标签号为 16
    • 16 小于 30,直接使用 5 位二进制表示:10000
  • 最终标签编码
    • 标签类和原始/构造标志:00 10010x20
    • 标签号:100000x10
    • 组合后:0x30

Certificate 是 X.509 证书的 ASN.1 定义,它是一个 SEQUENCE 类型,包含多个字段(如版本号、序列号、颁发者、有效期等)。由于 Certificate 是一个复合结构,它的值是构造值类型(Constructed),而不是原始值类型(Primitive)。

Certificate 的 ASN.1 定义如下:

Certificate ::= SEQUENCE {  
tbsCertificate TBSCertificate,
signatureAlgorithm AlgorithmIdentifier,
signatureValue BIT STRING
}

因为 CertificateSEQUENCE 类型,所以它的标签编码是 0x30


ctxParams1 标签编码

  • 标签类ctxParams1 是隐式标签(无显式标签),默认使用 CtxParams1 的通用类,因此标签类为 00
  • 原始/构造标志CtxParams1 是构造值,因此标志为 1
  • 标签号CtxParams1 的标签号为 16
    • 16 小于 30,直接使用 5 位二进制表示:10000
  • 最终标签编码
    • 标签类和原始/构造标志:00 10010x20
    • 标签号:100000x10
    • 组合后:0x30

otherCertsInChain 标签编码

  • 标签类[1] 是上下文特定类,因此标签类为 10

  • 原始/构造标志CertificateChain 是构造值,因此标志为 1

  • 标签号1 小于 30,直接使用 5 位二进制表示:00001

  • 最终标签编码

    • 标签类和原始/构造标志:10 11010xA0
    • 标签号:000010x01
    • 组合后:0xA1

CertificateChain 是证书链的 ASN.1 定义,它是一个 SEQUENCE OF 类型,包含多个 Certificate。由于 CertificateChain 是一个复合结构,它的值也是构造值类型(Constructed)。

CertificateChain 的 ASN.1 定义如下:

CertificateChain ::= SEQUENCE OF Certificate

因为 CertificateChainSEQUENCE OF 类型,所以它的标签编码也是 0x30


crlList 标签编码

  • 标签类[2] 是上下文特定类,因此标签类为 10
  • 原始/构造标志SEQUENCE OF CertificateList 是构造值,因此标志为 1
  • 标签号2 小于 30,直接使用 5 位二进制表示:00010
  • 最终标签编码
    • 标签类和原始/构造标志:10 11010xA0
    • 标签号:000100x02
    • 组合后:0xA2

AuthenticateServerRequest 结构中所有字段的标签编码如下:

字段名 标签编码
AuthenticateServerRequest BF38
serverSigned1 30
serverSignature1 5F37
euiccCiPKIdToBeUsed 04
serverCertificate 30
ctxParams1 30
otherCertsInChain A1
crlList A2

通过以上计算,可以准确得出每个字段的标签编码。

AuthenticateServerResponse

-- ASN1START
AuthenticateServerResponse ::= [56] CHOICE { -- Tag 'BF38'
authenticateResponseOk [0] AuthenticateResponseOk,
authenticateResponseError [1] AuthenticateResponseError
}
AuthenticateResponseOk ::= SEQUENCE {
euiccSigned1 EuiccSigned1, -- Signed information
euiccSignature1 [APPLICATION 55] OCTET STRING, --EUICC_Sign1, tag 5F37
euiccCertificate Certificate, -- eUICC Certificate (CERT.EUICC.SIG)
nextCertInChain Certificate, -- The Certificate certifying the eUICC
Certificate
otherCertsInChain [0] CertificateChain OPTIONAL -- #SupportedFromV3.0.0# Other
Certificates in the eUICC certificate chain, if any
}
EuiccSigned1 ::= SEQUENCE {
transactionId [0] TransactionId,
serverAddress [3] UTF8String, -- The RSP Server address as an FQDN
serverChallenge [4] Octet16, -- The RSP Server Challenge
euiccInfo2 [34] EUICCInfo2,
ctxParams1 CtxParams1
}
AuthenticateResponseError ::= SEQUENCE {
transactionId [0] TransactionId,
authenticateErrorCode AuthenticateErrorCode
}
AuthenticateErrorCode ::= INTEGER {
invalidCertificate(1), invalidSignature(2),
unsupportedCurve(3), noSession(4), invalidOid(5), euiccChallengeMismatch(6),
ciPKUnknown(7),
transactionIdError (8), -- #SupportedFromV3.0.0#
missingCrl(9), -- #SupportedFromV3.0.0#
invalidCrlSignature(10), -- #SupportedFromV3.0.0#
revokedCert(11), -- #SupportedFromV3.0.0#
invalidCertOrCrlTime(12), -- #SupportedFromV3.0.0#
invalidCertOrCrlConfiguration(13), -- #SupportedFromV3.0.0#
invalidIccid(14), -- #SupportedForDcV3.0.0#
undefinedError(127)
}
-- ASN1STOP

以下是对 AuthenticateServerResponse ASN.1 脚本的逐行解释和说明,重点说明标签编码的计算过程,并给出详细的计算依据。


AuthenticateServerResponse 结构

AuthenticateServerResponse ::= [56] CHOICE { -- Tag 'BF38'
authenticateResponseOk [0] AuthenticateResponseOk,
authenticateResponseError [1] AuthenticateResponseError
}
  • 标签 [56]:表示这是一个上下文特定的标签,编码为 BF380x80 + 0x20 + 56 = 0xBF38)。
  • 类型 CHOICE:表示这是一个选择类型,只能选择其中一个字段。
  • 选项
    1. authenticateResponseOk:类型为 [0] AuthenticateResponseOk,表示认证成功的响应。
    2. authenticateResponseError:类型为 [1] AuthenticateResponseError,表示认证失败的响应。

AuthenticateResponseOk 结构

AuthenticateResponseOk ::= SEQUENCE {
euiccSigned1 EuiccSigned1, -- Signed information
euiccSignature1 [APPLICATION 55] OCTET STRING, -- EUICC_Sign1, tag 5F37
euiccCertificate Certificate, -- eUICC Certificate (CERT.EUICC.SIG)
nextCertInChain Certificate, -- The Certificate certifying the eUICC Certificate
otherCertsInChain [0] CertificateChain OPTIONAL -- #SupportedFromV3.0.0# Other Certificates in the eUICC certificate chain, if any
}
  • 类型 SEQUENCE:表示这是一个有序的字段集合。
  • 字段
    1. euiccSigned1:类型为 EuiccSigned1,表示 eUICC 签名的信息。
    2. euiccSignature1:类型为 [APPLICATION 55] OCTET STRING,标签为 5F37,表示 eUICC 的签名值。
    3. euiccCertificate:类型为 Certificate,表示 eUICC 的证书。
    4. nextCertInChain:类型为 Certificate,表示证书链中的下一个证书。
    5. otherCertsInChain:类型为 [0] CertificateChain,可选字段,表示证书链中的其他证书(V3.0.0 起支持)。

EuiccSigned1 结构

EuiccSigned1 ::= SEQUENCE {
transactionId [0] TransactionId,
serverAddress [3] UTF8String, -- The RSP Server address as an FQDN
serverChallenge [4] Octet16, -- The RSP Server Challenge
euiccInfo2 [34] EUICCInfo2,
ctxParams1 CtxParams1
}
  • 类型 SEQUENCE:表示这是一个有序的字段集合。
  • 字段
    1. transactionId:类型为 [0] TransactionId,表示交易 ID。
    2. serverAddress:类型为 [3] UTF8String,表示 RSP 服务器的地址(FQDN)。
    3. serverChallenge:类型为 [4] Octet16,表示 RSP 服务器的挑战值。
    4. euiccInfo2:类型为 [34] EUICCInfo2,表示 eUICC 的信息。
    5. ctxParams1:类型为 CtxParams1,表示上下文参数。

AuthenticateResponseError 结构

AuthenticateResponseError ::= SEQUENCE {
transactionId [0] TransactionId,
authenticateErrorCode AuthenticateErrorCode
}
  • 类型 SEQUENCE:表示这是一个有序的字段集合。
  • 字段
    1. transactionId:类型为 [0] TransactionId,表示交易 ID。
    2. authenticateErrorCode:类型为 AuthenticateErrorCode,表示认证错误代码。

AuthenticateErrorCode 结构

AuthenticateErrorCode ::= INTEGER {
invalidCertificate(1),
invalidSignature(2),
unsupportedCurve(3),
noSession(4),
invalidOid(5),
euiccChallengeMismatch(6),
ciPKUnknown(7),
transactionIdError (8), -- #SupportedFromV3.0.0#
missingCrl(9), -- #SupportedFromV3.0.0#
invalidCrlSignature(10), -- #SupportedFromV3.0.0#
revokedCert(11), -- #SupportedFromV3.0.0#
invalidCertOrCrlTime(12), -- #SupportedFromV3.0.0#
invalidCertOrCrlConfiguration(13), -- #SupportedFromV3.0.0#
invalidIccid(14), -- #SupportedForDcV3.0.0#
undefinedError(127)
}
  • 类型 INTEGER:表示这是一个整数类型。
  • 枚举值:定义了各种认证错误代码。

标签编码的计算

AuthenticateServerResponse 的标签

  • Tag Class0x80(上下文特定标签)。
  • Primitive/Constructed0x20(构造类型)。
  • Tag Number56(大于 31,需要使用多字节编码)。
  • 标签值
    • 第一个字节:0x80 + 0x20 + 0x1F = 0xBF
    • 后续字节:56 的二进制为 00111000,编码为 0x38
    • 最终标签:0xBF38

authenticateResponseOk 的标签

  • Tag Class0x80(上下文特定标签)。
  • Primitive/Constructed0x00(原始类型)。
  • Tag Number0
  • 标签值0x80 + 0x00 + 0 = 0x80

authenticateResponseError 的标签

  • Tag Class0x80(上下文特定标签)。
  • Primitive/Constructed0x00(原始类型)。
  • Tag Number1
  • 标签值0x80 + 0x00 + 1 = 0x81

euiccSignature1 的标签

  • Tag Class0x40(应用标签)。
  • Primitive/Constructed0x00(原始类型)。
  • Tag Number55(大于 31,需要使用多字节编码)。
  • 标签值
    • 第一个字节:0x40 + 0x00 + 0x1F = 0x5F
    • 后续字节:55 的二进制为 00110111,编码为 0x37
    • 最终标签:0x5F37

otherCertsInChain 的标签

  • Tag Class0x80(上下文特定标签)。
  • Primitive/Constructed0x20(构造类型)。
  • Tag Number0
  • 标签值0x80 + 0x20 + 0 = 0xA0

参考网站: