一 标签编码规则详解
标签编码公式
标签的最终编码值通过以下公式计算:Tag = Tag Class + Primitive/Constructed + Tag Number
在 ASN.1 中,标签(Tag) 的编码规则是基于 BER(Basic Encoding Rules) 或 DER(Distinguished Encoding Rules) 的。标签的编码由以下三部分组成:
- Tag Class(标签类别)
- Primitive/Constructed(原始/构造)
- Tag Number(标签号)
Tag Class(标签类别)
标签类别用于标识标签的上下文,共有 4 种类别:
| 类别 | 值(二进制) | 值(十六进制) | 描述 |
|---|---|---|---|
| Universal | 00 |
0x00 |
通用标签,用于 ASN.1 内置类型(如 INTEGER、SEQUENCE 等)。 |
| Application | 01 |
0x40 |
应用标签,由应用程序定义。 |
| Context-specific | 10 |
0x80 |
上下文特定标签,用于特定上下文中定义的类型。 |
| Private | 11 |
0xC0 |
私有标签,由私有协议定义。 |
- 如果标签是 通用类型(如
INTEGER、SEQUENCE),则Tag Class = 0x00。 - 如果标签是 应用类型(如
[APPLICATION n]),则Tag Class = 0x40。 - 如果标签是 上下文特定类型(如
[n]),则Tag Class = 0x80。 - 如果标签是 私有类型,则
Tag Class = 0xC0。
Primitive/Constructed(原始/构造)
Primitive/Constructed 用于标识数据的编码方式:
| 类型 | 值(二进制) | 值(十六进制) | 描述 |
|---|---|---|---|
| Primitive | 0 |
0x00 |
原始类型,表示数据是简单的值(如 INTEGER、OCTET STRING)。 |
| Constructed | 1 |
0x20 |
构造类型,表示数据是复杂的结构(如 SEQUENCE、SEQUENCE OF)。 |
- 如果数据类型是 原始类型(如
INTEGER、OCTET STRING),则Primitive/Constructed = 0x00。 - 如果数据类型是 构造类型(如
SEQUENCE、SET),则Primitive/Constructed = 0x20。
如何判断字段是原始类型还是构造类型?
原始类型(Primitive):
- 简单数据类型,如
INTEGER、OCTET STRING、BOOLEAN等。 - 编码时直接包含数据值。
- 简单数据类型,如
构造类型(Constructed):
- 复杂数据类型,如
SEQUENCE、SEQUENCE OF、SET、SET OF等。 - 编码时包含嵌套的子字段。
- 复杂数据类型,如
Tag Number(标签号)
标签号是一个具体的数值,用于区分同一类别中的不同标签。标签号的取值范围是 0 到 30(单字节标签)或更大(多字节标签)。
- 如果标签号小于
31,则可以直接使用单字节表示。 - 如果标签号大于或等于
31,则需要使用多字节表示(第一个字节的后 5 位为11111,后续字节表示标签号)。
标签号是 ASN.1 类型的内置编号,用于区分不同的类型。以下是常见类型的标签号:
| TAG | 类型 | TAG | 类型 |
|---|---|---|---|
| 0 (hex:00) | BER保留 | 16(hex:10) | SEQUENCE,SEQUENCE OF |
| 1 (hex:01) | BOOLEAN |
17(hex:11) | SET,SET OF |
| 2(hex:02) | INTEGER |
18(hex:12) | NumericString |
| 3(hex:03) | BIT STRING |
19(hex:13) | PrintableString |
| 4(hex:04) | OCTET STRING |
20(hex:14) | TeletexString,T61String |
| 5(hex:05) | NULL |
21(hex:15) | VideotexString |
| 6(hex:06) | OBJECT IDENTIFIER |
22(hex:16) | IA5String |
| 7(hex:07) | ObjectDescripion |
23(hex:17) | UTCTime |
| 8(hex:08) | EXTERNAL,INSTANCE OF |
24(hex:18) | GeneralizedTime |
| 9(hex:09) | REAL |
25(hex:19) | GraphicString |
| 10(hex:0A) | ENUMERATED |
26(hex:1A) | VisibleString,ISO646String |
| 11(hex:0B) | EMBEDDED PDV |
27(hex:1B) | GeneralString |
| 12(hex:0C) | UTF8String |
28(hex:1C) | UniversalString |
| 13(hex:0D) | RELATIVE-OID |
29(hex:1D) | CHARACTER STRING |
| 14(hex:0E) | 保留 | 30(hex:1E) | BMPString |
| 15(hex:0F) | 保留 | 31(hex:1F) | 保留 |
这些标签号是 ASN.1 标准中定义的固定值,与具体的编码无关。
标签编码计算公式
标签的最终编码值通过以下公式计算:Tag = Tag Class + Primitive/Constructed + Tag Number
通用标签
SEQUENCE:Tag Class = 0x00(Universal)Primitive/Constructed = 0x20(Constructed)Tag Number = 16(SEQUENCE的标签号)Tag = 0x00 + 0x20 + 16 = 0x30
上下文特定标签
[2]:Tag Class = 0x80(Context-specific)Primitive/Constructed = 0x00(Primitive)Tag Number = 2Tag = 0x80 + 0x00 + 2 = 0x82
应用标签
[APPLICATION 5]:Tag Class = 0x40(Application)Primitive/Constructed = 0x00(Primitive)Tag Number = 5Tag = 0x40 + 0x00 + 5 = 0x45
如何确定 Tag Class 的取值
查看 ASN.1 定义:
- 如果字段是 通用类型(如
INTEGER、SEQUENCE),则Tag Class = 0x00。 - 如果字段是 应用类型(如
[APPLICATION n]),则Tag Class = 0x40。 - 如果字段是 上下文特定类型(如
[n]),则Tag Class = 0x80。 - 如果字段是 私有类型,则
Tag Class = 0xC0。
- 如果字段是 通用类型(如
查看协议文档:
- 协议文档通常会明确说明字段的标签类别和标签号。
使用 ASN.1 工具:
- 使用 ASN.1 编译器(如
asn1c或OSS Nokalva)可以自动生成标签编码规则。
- 使用 ASN.1 编译器(如
隐式标签和显示标签
隐式和显式标记实际上是如何以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' |
AuthenticateServerRequest标签编码计算
AuthenticateServerRequest:Tag = 0x80 + 0x20 + 56 = 0xBF38
- Tag Class:
0x80(上下文特定标签)。 - Primitive/Constructed:
0x20(构造类型)。 - Tag Number:
56(大于 31,需要使用多字节编码)。
多字节标签的编码步骤
- 第一个字节:
- 标签类别:
0x80(上下文特定)。 - 构造类型:
0x20。 - 标签号:
56(大于 31,后 5 位设置为11111)。 - 计算:
0x80 + 0x20 + 0x1F = 0xBF。
- 标签类别:
- 后续字节:
- 标签号
56的二进制表示为00111000。 - 按 7 位分组:
0011100和0。 - 编码为:
00111000→0x38。
- 标签号
- 最终标签:
- 第一个字节:
0xBF。 - 后续字节:
0x38。 - 组合为:
0xBF38。
- 第一个字节:
为什么不是 0xD8?
0xD8是单字节标签的编码值,但标签号56大于 31,必须使用多字节编码。- 因此,
AuthenticateServerRequest的标签是0xBF38,而不是0xD8。
serverSignature1标签编码计算
- Tag Class:
0x40(应用标签)。 - Primitive/Constructed:
0x00(原始类型)。 - Tag Number:
55(大于 31,需要使用多字节编码)。
多字节标签的编码步骤
- 第一个字节:
- 标签类别:
0x40(应用标签)。 - 原始类型:
0x00。 - 标签号:
55(大于 31,后 5 位设置为11111)。 - 计算:
0x40 + 0x00 + 0x1F = 0x5F。
- 标签类别:
- 后续字节:
- 标签号
55的二进制表示为00110111。 - 按 7 位分组:
0011011和1。 - 编码为:
00110111→0x37。
- 标签号
- 最终标签:
- 第一个字节:
0x5F。 - 后续字节:
0x37。 - 组合为:
0x5F37。
- 第一个字节:
为什么不是 0x77?
0x77是单字节标签的编码值,但标签号55大于 31,必须使用多字节编码。- 因此,
serverSignature1的标签是0x5F37,而不是0x77。
otherCertsInChain标签编码计算
Tag Class = 0x80(Context-specific)Primitive/Constructed = 0x20(Constructed)Tag Number = 1Tag = 0x80 + 0x20 + 1 = 0xA1
二 前置知识
ASN.1类型系统
基本类型
| 类型 | 编码标识 | 备注 |
|---|---|---|
| BIT STRING | 0x03 | 位或二进制字符串是任意长度的位数组。 特定位可以通过带圆括号的整数和分配的名称进行标识 |
| BOOLEAN | 0x01 | 布尔类型可以包含两个值之一: TRUE 或 FALSE。 |
| 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 | 包含一个或多个类型的有序字段系列。 字段可以标记为OPTIONAL 或 DEFAULT。 此外,为了避免解码时出现歧义,连续的可选字段应通过使用唯一标识符 (括号整数(如 [1]) )和以下必填字段彼此不同。SEQUENCE 和 SEQUENCE OF 的区别在于 SEQUENCE OF 构造的元素必须属于同一类型。 请参阅以下示例。 两个构造在编码时 (0x30) 具有相同的标记值。了解 SEQUENCE 和 SEQUENCE OF 之间的差异的另一种方法是将它们与 C 编程语言中的对应项进行比较。 也就是说, SEQUENCE 大致等效于结构, SEQUENCE OF 大致等效于数组。 |
| SET 和 SET OF | 0x31 | 包含一个或多个类型的无序字段系列。 这与包含有序列表的 SEQUENCE 不同。 通过指定无序列表,应用程序可以按最合适的顺序向编码器提供结构字段。 与 SEQUENCE 一样, SET 构造的字段可以标记为 OPTIONAL 或 DEFAULT,并且必须使用唯一标识符来消除解码过程的歧义。 SET 和 SET OF 的区别在于,SET OF 构造的元素必须属于同一类型。 |
| 选择(CHOICE) | 定义替代方案之间的选择。 每个替代项都必须由带括号的整数唯一标识,以避免解码时出现歧义。 编码后, CHOICE 构造将具有所选替代项的编码标记值。 |
- 标签号:
SEQUENCE的标签号是16,这是 ASN.1 标准中定义的内置编号。 - 标签编码:
SEQUENCE的标签编码是0x30,这是根据标签类、原始/构造标志和标签号计算出的最终字节表示。
换句话说:
- 标签号:
16是SEQUENCE的内置编号。 - 标签编码:
0x30是SEQUENCE的 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 中,标签号是用于标识类型的固定值。以下是常见类型的标签号:
INTEGER:2BIT STRING:3OCTET STRING:4OBJECT IDENTIFIER:6SEQUENCE和SEQUENCE OF:16
在 X.509 证书中,字段的标签号通常基于其类型。例如:
Serial Number是INTEGER类型,因此标签号为2。Subject Key Identifier是OCTET STRING类型,因此标签号为4。Issuer是SEQUENCE类型,因此标签号为16。
X.509 证书的基本字段和扩展字段及其标签号如下:
- 基本字段:如
Version、Serial Number、Issuer、Subject等,标签号基于其类型(如INTEGER、SEQUENCE等)。- 扩展字段:如
Authority Key Identifier、Subject Key Identifier、Key Usage等,标签号也基于其类型(如OCTET STRING、BIT STRING等)。
X.509证书和证书链的 ASN.1 定义
以下是 X.509 证书 和 证书链(Certificate Chain) 的 ASN.1 定义的全部内容,包括相关字段的详细说明。
X.509证书的ASN.1定义
X.509 证书的 ASN.1 定义基于 RFC 5280 标准,以下是其完整定义:
Certificate ::= SEQUENCE { |
关键字段说明:
tbsCertificate:证书的核心部分,包含版本、序列号、颁发者、有效期、持有者、公钥等信息。signatureAlgorithm:用于签名证书的算法标识符。signatureValue:证书的签名值。version:证书的版本号(v1、v2 或 v3)。serialNumber:证书的唯一序列号。issuer:证书颁发者的名称(Distinguished Name)。validity:证书的有效期(开始时间和结束时间)。subject:证书持有者的名称(Distinguished Name)。subjectPublicKeyInfo:持有者的公钥信息。extensions:证书的扩展字段(仅 v3 证书支持)。
证书链(Certificate Chain)的 ASN.1 定义
证书链:是一个 SEQUENCE OF 类型,包含多个 Certificate。
证书链是由多个 X.509 证书组成的序列,用于构建信任链。以下是证书链的 ASN.1 定义:
CertificateChain ::= SEQUENCE OF Certificate |
关键字段说明:
CertificateChain:证书链是一个SEQUENCE OF类型,包含多个Certificate。Certificate:每个证书的 ASN.1 定义与上述 X.509 证书的定义一致。
相关字段的详细说明
AlgorithmIdentifier( 签名证书的算法标识符 )
AlgorithmIdentifier ::= SEQUENCE { |
algorithm:算法的 OID(如 SHA256WithRSA)。parameters:算法的参数(可选)。
SubjectPublicKeyInfo( 持有者的公钥信息 )
SubjectPublicKeyInfo ::= SEQUENCE { |
algorithm:公钥的算法标识符。subjectPublicKey:公钥的二进制值。
Extensions( 证书的扩展字段 )
Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension |
extnID:扩展的 OID(如id-ce-keyUsage)。critical:扩展是否关键(默认为FALSE)。extnValue:扩展的值(以OCTET STRING编码)。
TLV数据结构
java处理TLV数据
public static String toTLV(String input) { |
OID数据解析
数据解析
id-rspRole-ds-tls-v2 OBJECT IDENTIFIER ::= {id-rspRole 6} |
解释
id-rspRole-ds-tls-v2 OBJECT IDENTIFIER ::= {id-rspRole 6}- 这行定义了一个名为
id-rspRole-ds-tls-v2的 OBJECT 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。
- 这行定义了一个名为
OID 的结构
- OID 是由一系列整数组成的层次化结构,用于唯一标识某个对象或概念。
- 每个节点用点号
.分隔,例如1.2.3.4.5.6。
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 * 40 + 2 = 42(即0x2A)。 - 后续节点按以下规则编码:
- 如果节点值小于 128,则直接用一个字节表示。
- 如果节点值大于或等于 128,则使用多个字节表示,每个字节的最高位为 1,最后一个字节的最高位为 0。
编码过程
- OID:
1.2.3.4.5.6 - 编码步骤:
- 第一个节点:
1 * 40 + 2 = 42→0x2A - 第二个节点:
3→0x03 - 第三个节点:
4→0x04 - 第四个节点:
5→0x05 - 第五个节点:
6→0x06
- 第一个节点:
- 最终编码:
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对应的分解: |
| 十六进制 | 二进制 | 十进制 | 十六进制 | 二进制 | 十进制 |
|---|---|---|---|---|---|
| 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' |
- 标签
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 哈希值)。 - 示例:两个标识符
0x0102和0x0304,编码为:A9 08 -- 标签和长度
04 02 01 02 -- 第一个标识符
04 02 03 04 -- 第二个标识符
详细计算过程
Tag Class:标签
[9]是上下文特定标签,因此 Tag Class 为0x80。Primitive/Constructed:字段
euiccCiPKIdListForVerification是一个SEQUENCE OF,属于构造类型(Constructed),因此 Primitive/Constructed 为0x20。Tag Number:标签号为
9。Tag = Tag Class + Primitive/Constructed + Tag Number
= 0x80 + 0x20 + 9
= 0xA9
为什么是
0xA9而不是0x89?
- 如果字段是原始类型(Primitive),则 Primitive/Constructed 为
0x00,编码值为0x80 + 9 = 0x89。- 但
SEQUENCE OF是构造类型(Constructed),因此 Primitive/Constructed 为0x20,编码值为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) |
解析步骤:
- 识别整体结构:标签
BF20表示这是一个EUICCInfo1结构,长度0x1B(27 字节)。 - 解析字段:
82 01 01→lowestSvn = 1。A9 08→ 两个验证公钥标识符0102和0304。AA 06→ 一个签名公钥标识符0506。88 01 01→ 远程管理能力为1。93 01 03→highestSvn = 3。
- 省略字段:
euiccCiPKIdListForSigningV3未出现(OPTIONAL)。
关键注意事项
- 标签编码:每个字段的标签需按上下文特定规则处理(如
[2]→0x82)。 - 顺序性:
SEQUENCE字段必须按定义顺序出现。 - 版本约束:V3.0.0 起
euiccRspCapability必填,highestSvn可选。 - OPTIONAL 字段:若不存在,编码中直接省略。
euiccCiPKIdListForVerification 的编码示例
原始数据
A9 08 -- 标签和长度 (8 bytes) |
解析
A9:标签,表示euiccCiPKIdListForVerification是一个构造类型的上下文特定标签([9])。08:长度,表示后续数据的总长度是 8 字节。04 02 01 02:04:OCTET STRING的标签。02:长度,表示OCTET STRING的值占 2 字节。01 02:实际的标识符值。
04 02 03 04:04:OCTET 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) |
解析
AA:标签,表示euiccCiPKIdListForSigning是一个构造类型的上下文特定标签([10])。06:长度,表示后续数据的总长度是 6 字节。04 02 05 06:04:OCTET STRING的标签。02:长度,表示OCTET STRING的值占 2字节。05 06:实际的标识符值(2 字节)
java解析EUICCInfo1数据
package com.demo; |
SGP.22 eUICC信息AuthenticateServerRequest结构详解
完整的定义如下:
-- ASN1START |
AuthenticateServerRequest 标签计算
以下是 AuthenticateServerRequest 结构中所有字段的标签编码及其计算过程:
AuthenticateServerRequest 结构
AuthenticateServerRequest ::= [56] SEQUENCE { |
AuthenticateServerRequest 标签编码
- 标签类:
[56]是上下文特定类,因此标签类为10。 - 原始/构造标志:
SEQUENCE是构造值,因此标志为1。 - 标签号:
56大于 30,需要扩展编码。- 将
56转换为二进制:111000。 - 分为 7 位一组:
111000。 - 前面加
0(最后一组):0111000。 - 转换为十六进制:
0x38。
- 将
- 最终标签编码:
- 标签类和原始/构造标志:
10 1→101→0xA0。 - 标签号:
0x38。 - 组合后:
0xBF38(0xA0和0x38组合)。
- 标签类和原始/构造标志:
serverSigned1 标签编码
- 标签类:
serverSigned1是隐式标签(无显式标签),默认使用SEQUENCE的通用类,因此标签类为00。 - 原始/构造标志:
SEQUENCE是构造值,因此标志为1。 - 标签号:
SEQUENCE的标签号为16。16小于 30,直接使用 5 位二进制表示:10000。
- 最终标签编码:
- 标签类和原始/构造标志:
00 1→001→0x20。 - 标签号:
10000→0x10。 - 组合后:
0x30。
- 标签类和原始/构造标志:
注意点:
- 标签号:
16是SEQUENCE的内置编号。
serverSignature1 标签编码
- 标签类:
[APPLICATION 55]是应用类,因此标签类为01。 - 原始/构造标志:
OCTET STRING是原始值,因此标志为0。 - 标签号:
55大于 30,需要扩展编码。- 将
55转换为二进制:110111。 - 分为 7 位一组:
110111。 - 前面加
0(最后一组):0110111。 - 转换为十六进制:
0x37。
- 将
- 最终标签编码:
- 标签类和原始/构造标志:
01 0→010→0x50。 - 标签号:
0x37。 - 组合后:
0x5F37(0x50和0x37组合)。
- 标签类和原始/构造标志:
euiccCiPKIdToBeUsed 标签编码
- 标签类:
euiccCiPKIdToBeUsed是隐式标签(无显式标签),默认使用SubjectKeyIdentifier的通用类,因此标签类为00。 - 原始/构造标志:
SubjectKeyIdentifier是原始值,因此标志为0。 - 标签号:
SubjectKeyIdentifier的标签号为4。4小于 30,直接使用 5 位二进制表示:00100。
- 最终标签编码:
- 标签类和原始/构造标志:
00 0→000→0x00。 - 标签号:
00100→0x04。 - 组合后:
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):
- 原始值:直接编码值的内容。
- 构造值:将值的内容进一步分解为多个部分,每个部分单独编码。
SubjectKeyIdentifier是OCTET STRING类型,而OCTET STRING是原始类型。因此,SubjectKeyIdentifier的编码是原始值。
serverCertificate 标签编码
- 标签类:
serverCertificate是隐式标签(无显式标签),默认使用Certificate的通用类,因此标签类为00。 - 原始/构造标志:
Certificate是构造值,因此标志为1。 - 标签号:
Certificate的标签号为16。16小于 30,直接使用 5 位二进制表示:10000。
- 最终标签编码:
- 标签类和原始/构造标志:
00 1→001→0x20。 - 标签号:
10000→0x10。 - 组合后:
0x30。
- 标签类和原始/构造标志:
Certificate 是 X.509 证书的 ASN.1 定义,它是一个 SEQUENCE 类型,包含多个字段(如版本号、序列号、颁发者、有效期等)。由于 Certificate 是一个复合结构,它的值是构造值类型(Constructed),而不是原始值类型(Primitive)。
Certificate 的 ASN.1 定义如下:
Certificate ::= SEQUENCE { |
因为 Certificate 是 SEQUENCE 类型,所以它的标签编码是 0x30。
ctxParams1 标签编码
- 标签类:
ctxParams1是隐式标签(无显式标签),默认使用CtxParams1的通用类,因此标签类为00。 - 原始/构造标志:
CtxParams1是构造值,因此标志为1。 - 标签号:
CtxParams1的标签号为16。16小于 30,直接使用 5 位二进制表示:10000。
- 最终标签编码:
- 标签类和原始/构造标志:
00 1→001→0x20。 - 标签号:
10000→0x10。 - 组合后:
0x30。
- 标签类和原始/构造标志:
otherCertsInChain 标签编码
标签类:
[1]是上下文特定类,因此标签类为10。原始/构造标志:
CertificateChain是构造值,因此标志为1。标签号:
1小于 30,直接使用 5 位二进制表示:00001。最终标签编码:
- 标签类和原始/构造标志:
10 1→101→0xA0。 - 标签号:
00001→0x01。 - 组合后:
0xA1。
- 标签类和原始/构造标志:
CertificateChain 是证书链的 ASN.1 定义,它是一个 SEQUENCE OF 类型,包含多个 Certificate。由于 CertificateChain 是一个复合结构,它的值也是构造值类型(Constructed)。
CertificateChain 的 ASN.1 定义如下:
CertificateChain ::= SEQUENCE OF Certificate |
因为 CertificateChain 是 SEQUENCE OF 类型,所以它的标签编码也是 0x30。
crlList 标签编码
- 标签类:
[2]是上下文特定类,因此标签类为10。 - 原始/构造标志:
SEQUENCE OF CertificateList是构造值,因此标志为1。 - 标签号:
2小于 30,直接使用 5 位二进制表示:00010。 - 最终标签编码:
- 标签类和原始/构造标志:
10 1→101→0xA0。 - 标签号:
00010→0x02。 - 组合后:
0xA2。
- 标签类和原始/构造标志:
AuthenticateServerRequest 结构中所有字段的标签编码如下:
| 字段名 | 标签编码 |
|---|---|
| AuthenticateServerRequest | BF38 |
| serverSigned1 | 30 |
| serverSignature1 | 5F37 |
| euiccCiPKIdToBeUsed | 04 |
| serverCertificate | 30 |
| ctxParams1 | 30 |
| otherCertsInChain | A1 |
| crlList | A2 |
通过以上计算,可以准确得出每个字段的标签编码。
AuthenticateServerResponse
-- ASN1START |
以下是对 AuthenticateServerResponse ASN.1 脚本的逐行解释和说明,重点说明标签编码的计算过程,并给出详细的计算依据。
AuthenticateServerResponse 结构
AuthenticateServerResponse ::= [56] CHOICE { -- Tag 'BF38' |
- 标签
[56]:表示这是一个上下文特定的标签,编码为BF38(0x80 + 0x20 + 56 = 0xBF38)。 - 类型
CHOICE:表示这是一个选择类型,只能选择其中一个字段。 - 选项:
authenticateResponseOk:类型为[0] AuthenticateResponseOk,表示认证成功的响应。authenticateResponseError:类型为[1] AuthenticateResponseError,表示认证失败的响应。
AuthenticateResponseOk 结构
AuthenticateResponseOk ::= SEQUENCE { |
- 类型
SEQUENCE:表示这是一个有序的字段集合。 - 字段:
euiccSigned1:类型为EuiccSigned1,表示 eUICC 签名的信息。euiccSignature1:类型为[APPLICATION 55] OCTET STRING,标签为5F37,表示 eUICC 的签名值。euiccCertificate:类型为Certificate,表示 eUICC 的证书。nextCertInChain:类型为Certificate,表示证书链中的下一个证书。otherCertsInChain:类型为[0] CertificateChain,可选字段,表示证书链中的其他证书(V3.0.0 起支持)。
EuiccSigned1 结构
EuiccSigned1 ::= SEQUENCE { |
- 类型
SEQUENCE:表示这是一个有序的字段集合。 - 字段:
transactionId:类型为[0] TransactionId,表示交易 ID。serverAddress:类型为[3] UTF8String,表示 RSP 服务器的地址(FQDN)。serverChallenge:类型为[4] Octet16,表示 RSP 服务器的挑战值。euiccInfo2:类型为[34] EUICCInfo2,表示 eUICC 的信息。ctxParams1:类型为CtxParams1,表示上下文参数。
AuthenticateResponseError 结构
AuthenticateResponseError ::= SEQUENCE { |
- 类型
SEQUENCE:表示这是一个有序的字段集合。 - 字段:
transactionId:类型为[0] TransactionId,表示交易 ID。authenticateErrorCode:类型为AuthenticateErrorCode,表示认证错误代码。
AuthenticateErrorCode 结构
AuthenticateErrorCode ::= INTEGER { |
- 类型
INTEGER:表示这是一个整数类型。 - 枚举值:定义了各种认证错误代码。
标签编码的计算
AuthenticateServerResponse 的标签
- Tag Class:
0x80(上下文特定标签)。 - Primitive/Constructed:
0x20(构造类型)。 - Tag Number:
56(大于 31,需要使用多字节编码)。 - 标签值:
- 第一个字节:
0x80 + 0x20 + 0x1F = 0xBF。 - 后续字节:
56的二进制为00111000,编码为0x38。 - 最终标签:
0xBF38。
- 第一个字节:
authenticateResponseOk 的标签
- Tag Class:
0x80(上下文特定标签)。 - Primitive/Constructed:
0x00(原始类型)。 - Tag Number:
0。 - 标签值:
0x80 + 0x00 + 0 = 0x80。
authenticateResponseError 的标签
- Tag Class:
0x80(上下文特定标签)。 - Primitive/Constructed:
0x00(原始类型)。 - Tag Number:
1。 - 标签值:
0x80 + 0x00 + 1 = 0x81。
euiccSignature1 的标签
- Tag Class:
0x40(应用标签)。 - Primitive/Constructed:
0x00(原始类型)。 - Tag Number:
55(大于 31,需要使用多字节编码)。 - 标签值:
- 第一个字节:
0x40 + 0x00 + 0x1F = 0x5F。 - 后续字节:
55的二进制为00110111,编码为0x37。 - 最终标签:
0x5F37。
- 第一个字节:
otherCertsInChain 的标签
- Tag Class:
0x80(上下文特定标签)。 - Primitive/Constructed:
0x20(构造类型)。 - Tag Number:
0。 - 标签值:
0x80 + 0x20 + 0 = 0xA0。
参考网站:
https://learn.microsoft.com/zh-cn/windows/win32/seccertenroll/about-constructed-types#choice
https://learn.microsoft.com/zh-cn/windows/win32/seccertenroll/about-basic-fields