encoding/asn1 - ASN.1 编解码
概述
encoding/asn1 包提供了 ASN.1(Abstract Syntax Notation One)数据的编解码功能。
ASN.1 是什么:
- 📋 抽象语法记法:描述数据结构的国际标准(X.680)
- 🔧 多种编码规则:支持 DER、BER、PER 等编码方式
- 📦 广泛应用:X.509 证书、SSL/TLS、加密密钥、LDAP 等
- 🛠️ Go 使用 DER:Go 主要支持 DER(Distinguished Encoding Rules)编码
主要用途:
- 🔐 X.509 证书:解析和生成证书结构
- 🔑 加密密钥:RSA、EC 密钥的 ASN.1 格式
- 📝 数字签名:签名值的 ASN.1 编码
- 🌐 SSL/TLS:证书链和握手消息
- 📇 LDAP:目录服务协议的数据格式
重要说明:
- ⚠️ DER 编码:Go 主要使用 DER(确定性编码规则)
- ⚠️ BER 子集:支持 BER 解码的一个子集
- ⚠️ 标签系统:使用结构体标签控制编码
- ✅ 标准库支持:Go 标准库提供完整支持
- ✅ 与 crypto 集成:与 crypto/x509 紧密配合
ASN.1 基础概念
ASN.1 数据结构
ASN.1 定义了多种数据类型:
基本类型:
BOOLEAN - 布尔值
INTEGER - 整数
BIT STRING - 位字符串
OCTET STRING - 字节字符串
NULL - 空值
OBJECT IDENTIFIER - 对象标识符(OID)
ENUMERATED - 枚举
UTF8String - UTF-8 字符串
PrintableString - 可打印字符串
IA5String - ASCII 字符串
UTCTime - UTC 时间
GeneralizedTime - 通用时间
构造类型:
SEQUENCE - 有序字段序列(类似 struct)
SEQUENCE OF - 同类型元素的序列(类似 slice)
SET - 无序字段集合
SET OF - 同类型元素的无序集合
CHOICE - 选择类型(类似 interface)
编码规则
DER(Distinguished Encoding Rules):
- ✅ Go 主要使用的编码规则
- ✅ 确定性编码(相同数据产生相同编码)
- ✅ BER 的严格子集
- ✅ 用于 X.509 证书
BER(Basic Encoding Rules):
- ✅ 基础编码规则
- ⚠️ 非确定性(同一数据可能有多种编码)
- ✅ Go 支持解码 BER 子集
PER(Packed Encoding Rules):
- ❌ Go 不支持
- ✅ 更紧凑的编码
- ❌ 用于电信协议
TLV 编码格式
ASN.1 使用 TLV(Tag-Length-Value)格式:
+-----+-----+-----+-----+-----+
| Tag | Length | Value |
+-----+-----+-----+-----+-----+
1 字节 可变长度 可变长度
Tag 结构:
Bit 8-7: 类别(Class)
00 = Universal(通用)
01 = Application(应用)
10 = Context-specific(上下文特定)
11 = Private(私有)
Bit 6: 构造标志
0 = 基本类型(Primitive)
1 = 构造类型(Constructed)
Bit 5-1: 标签号(Tag Number)
常见标签:
0x01 - BOOLEAN
0x02 - INTEGER
0x03 - BIT STRING
0x04 - OCTET STRING
0x05 - NULL
0x06 - OBJECT IDENTIFIER
0x0C - UTF8String
0x13 - PrintableString
0x16 - IA5String
0x17 - UTCTime
0x18 - GeneralizedTime
0x30 - SEQUENCE
0x31 - SET
核心类型
1. ObjectIdentifier - 对象标识符
type ObjectIdentifier []int
功能:表示 ASN.1 对象标识符(OID)。
示例 OID:
// RSA 加密算法
oidRSAEncryption = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
// EC 公钥算法
oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
// SHA-256 哈希算法
oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1}
// 国家名称
oidCountry = asn1.ObjectIdentifier{2, 5, 4, 6}
方法:
// 转换为字符串
func (oi ObjectIdentifier) String() string
// 从字符串解析
func ParseObjectIdentifier(oid string) (ObjectIdentifier, error)
// 比较
func (oi ObjectIdentifier) Equal(other ObjectIdentifier) bool
使用示例:
oid := asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
fmt.Println(oid.String()) // 输出:1.2.840.113549.1.1.1
// 解析字符串
parsed, err := asn1.ParseObjectIdentifier("1.2.840.113549.1.1.1")
if err != nil {
log.Fatal(err)
}
fmt.Println(parsed.Equal(oid)) // 输出:true
2. BitString - 位字符串
type BitString struct {
Bytes []byte // 字节数据
BitLength int // 实际位数
}
功能:表示 ASN.1 BIT STRING 类型。
方法:
// 创建位字符串
func NewBitString(bytes []byte, bitLength int) BitString
// 设置指定位
func (b *BitString) SetAt(bit int, value int)
// 获取指定位
func (b *BitString) GetAt(bit int) int
// 转换为字节切片
func (b BitString) RightAlign() []byte
使用示例:
// 创建位字符串
data := []byte{0xFF, 0x00}
bitString := asn1.NewBitString(data, 16)
// 设置位
bitString.SetAt(0, 1)
bitString.SetAt(7, 0)
// 读取位
value := bitString.GetAt(0)
fmt.Printf("位 0: %d\n", value)
// 转换为字节
bytes := bitString.RightAlign()
3. RawValue - 原始值
type RawValue struct {
Class int // 类别
Tag int // 标签
IsCompound bool // 是否构造类型
Bytes []byte // 原始字节
FullBytes []byte // 包含 Tag-Length 的完整字节
}
功能:表示原始的 ASN.1 值,用于处理未知或复杂类型。
使用场景:
- ✅ 解析未知类型
- ✅ 保留原始编码
- ✅ 处理扩展字段
- ✅ 延迟解码
使用示例:
// 保留原始数据
type Certificate struct {
TBSCertificate RawValue // 保留原始 TBS 数据
SignatureAlgorithm AlgorithmIdentifier
SignatureValue BitString
}
// 稍后手动解析
var cert Certificate
asn1.Unmarshal(data, &cert)
// 使用 cert.TBSCertificate.Bytes 进行进一步处理
4. Enumerated - 枚举
type Enumerated int
功能:表示 ASN.1 ENUMERATED 类型。
使用示例:
type AlgorithmType asn1.Enumerated
const (
AlgorithmRSA AlgorithmType = iota
AlgorithmECDSA
AlgorithmEd25519
)
type Signature struct {
Algorithm AlgorithmType `asn1:"enumerated"`
Value []byte
}
结构体标签
标签语法
type Field struct {
Value int `asn1:"tag,options"`
}
常用标签选项
类型标签:
`asn1:"boolean"` // BOOLEAN
`asn1:"integer"` // INTEGER
`asn1:"bitstring"` // BIT STRING
`asn1:"octetstring"` // OCTET STRING
`asn1:null"` // NULL
`asn1:"oid"` // OBJECT IDENTIFIER
`asn1:"enumerated"` // ENUMERATED
`asn1:"utf8string"` // UTF8String
`asn1:"printablestring"` // PrintableString
`asn1:"ia5string"` // IA5String
`asn1:"utctime"` // UTCTime
`asn1:"generalizedtime"` // GeneralizedTime
`asn1:"sequence"` // SEQUENCE
`asn1:"set"` // SET
修饰选项:
`asn1:"optional"` // 可选字段
`asn1:"default:value"` // 默认值
`asn1:"tag:N"` // 显式指定标签号
`asn1:"application"` // Application 类别
`asn1:"context"` // Context-specific 类别
`asn1:"private"` // Private 类别
标签示例
type Person struct {
Name string `asn1:"utf8string"`
Age int `asn1:"integer"`
Email string `asn1:"ia5string,optional"`
ID int `asn1:"tag:1,optional"`
Data []byte `asn1:"octetstring"`
}
type Certificate struct {
Version int `asn1:"tag:0,optional,default:0"`
SerialNumber *big.Int `asn1:"integer"`
Signature AlgorithmIdentifier
Issuer RDNSequence
Validity Validity
Subject RDNSequence
SubjectPKI SubjectPublicKeyInfo
}
核心函数
1. Marshal - 编码
func Marshal(val interface{}) ([]byte, error)
功能:将 Go 值编码为 ASN.1 DER 格式。
支持的类型:
- ✅ 基本类型(int、bool、string)
- ✅ 结构体(SEQUENCE)
- ✅ 切片(SEQUENCE OF)
- ✅ ObjectIdentifier
- ✅ BitString
- ✅ time.Time
- ✅ *big.Int
示例:
type Person struct {
Name string `asn1:"utf8string"`
Age int `asn1:"integer"`
}
person := Person{
Name: "张三",
Age: 30,
}
data, err := asn1.Marshal(person)
if err != nil {
log.Fatal(err)
}
fmt.Printf("编码数据:%x\n", data)
2. Unmarshal - 解码
func Unmarshal(data []byte, val interface{}) (rest []byte, err error)
功能:将 ASN.1 DER 数据解码到 Go 值。
返回值:
rest:未使用的剩余数据err:错误信息
示例:
type Person struct {
Name string `asn1:"utf8string"`
Age int `asn1:"integer"`
}
data := []byte{ /* ASN.1 DER 数据 */ }
var person Person
rest, err := asn1.Unmarshal(data, &person)
if err != nil {
log.Fatal(err)
}
fmt.Printf("姓名:%s, 年龄:%d\n", person.Name, person.Age)
fmt.Printf("剩余数据:%d 字节\n", len(rest))
3. MarshalWithParams - 带参数编码
func MarshalWithParams(val interface{}, params string) ([]byte, error)
功能:使用指定的标签参数编码值。
示例:
type Data struct {
Value int `asn1:"integer"`
}
data := Data{Value: 42}
// 显式指定为 context-specific 标签
encoded, err := asn1.MarshalWithParams(data, "context:1")
if err != nil {
log.Fatal(err)
}
4. UnmarshalWithParams - 带参数解码
func UnmarshalWithParams(data []byte, val interface{}, params string) ([]byte, error)
功能:使用指定的标签参数解码数据。
示例:
type Data struct {
Value int `asn1:"integer"`
}
var data Data
rest, err := asn1.UnmarshalWithParams(rawData, &data, "context:1")
if err != nil {
log.Fatal(err)
}
完整示例
示例 1:基本类型编解码
package main
import (
"encoding/asn1"
"fmt"
"log"
"math/big"
"time"
)
func main() {
// 1. 布尔值
boolData, err := asn1.Marshal(true)
if err != nil {
log.Fatal(err)
}
var boolVal bool
asn1.Unmarshal(boolData, &boolVal)
fmt.Printf("布尔值:%v\n", boolVal)
// 2. 整数
intData, err := asn1.Marshal(42)
if err != nil {
log.Fatal(err)
}
var intVal int
asn1.Unmarshal(intData, &intVal)
fmt.Printf("整数值:%d\n", intVal)
// 3. 大整数
bigInt := big.NewInt(12345678901234567890)
bigIntData, err := asn1.Marshal(bigInt)
if err != nil {
log.Fatal(err)
}
var decodedBigInt big.Int
asn1.Unmarshal(bigIntData, &decodedBigInt)
fmt.Printf("大整数:%s\n", decodedBigInt.String())
// 4. 字符串
stringData, err := asn1.Marshal("Hello, ASN.1!")
if err != nil {
log.Fatal(err)
}
var stringVal string
asn1.Unmarshal(stringData, &stringVal)
fmt.Printf("字符串:%s\n", stringVal)
// 5. 时间
now := time.Now().UTC()
timeData, err := asn1.Marshal(now)
if err != nil {
log.Fatal(err)
}
var timeVal time.Time
asn1.Unmarshal(timeData, &timeVal)
fmt.Printf("时间:%s\n", timeVal.Format(time.RFC3339))
// 6. OID
oid := asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
oidData, err := asn1.Marshal(oid)
if err != nil {
log.Fatal(err)
}
var oidVal asn1.ObjectIdentifier
asn1.Unmarshal(oidData, &oidVal)
fmt.Printf("OID: %s\n", oidVal.String())
}
示例 2:结构体编解码
package main
import (
"encoding/asn1"
"fmt"
"log"
)
// AlgorithmIdentifier 算法标识符
type AlgorithmIdentifier struct {
Algorithm asn1.ObjectIdentifier
Parameters asn1.RawValue `asn1:"optional"`
}
// RDNSequence 相对可分辨名称序列
type RDNSequence []RelativeDistinguishedNameSET
// RelativeDistinguishedNameSET 相对可分辨名称集合
type RelativeDistinguishedNameSET []AttributeTypeAndValue
// AttributeTypeAndValue 属性类型和值
type AttributeTypeAndValue struct {
Type asn1.ObjectIdentifier
Value interface{}
}
// Validity 有效期
type Validity struct {
NotBefore time.Time `asn1:"utctime"`
NotAfter time.Time `asn1:"utctime"`
}
// Certificate 简化的证书结构
type Certificate struct {
Version int `asn1:"tag:0,optional,default:0"`
SerialNumber int
Signature AlgorithmIdentifier
Issuer RDNSequence
Validity Validity
Subject RDNSequence
}
func main() {
// 创建证书
cert := Certificate{
Version: 2,
SerialNumber: 12345,
Signature: AlgorithmIdentifier{
Algorithm: asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}, // SHA-256 with RSA
},
Issuer: RDNSequence{
RelativeDistinguishedNameSET{
AttributeTypeAndValue{
Type: asn1.ObjectIdentifier{2, 5, 4, 6}, // Country
Value: "US",
},
},
},
Validity: Validity{
NotBefore: time.Now().UTC(),
NotAfter: time.Now().AddDate(1, 0, 0).UTC(),
},
Subject: RDNSequence{
RelativeDistinguishedNameSET{
AttributeTypeAndValue{
Type: asn1.ObjectIdentifier{2, 5, 4, 3}, // Common Name
Value: "example.com",
},
},
},
}
// 编码
data, err := asn1.Marshal(cert)
if err != nil {
log.Fatal(err)
}
fmt.Printf("编码大小:%d 字节\n", len(data))
fmt.Printf("编码数据(前 32 字节):%x\n", data[:32])
// 解码
var decodedCert Certificate
rest, err := asn1.Unmarshal(data, &decodedCert)
if err != nil {
log.Fatal(err)
}
fmt.Printf("\n解码结果:\n")
fmt.Printf("版本:%d\n", decodedCert.Version)
fmt.Printf("序列号:%d\n", decodedCert.SerialNumber)
fmt.Printf("颁发者 OID: %s\n", decodedCert.Issuer[0][0].Type.String())
fmt.Printf("主题: %s\n", decodedCert.Subject[0][0].Value)
fmt.Printf("剩余数据:%d 字节\n", len(rest))
}
示例 3:RSA 密钥编解码
package main
import (
"crypto/rsa"
"crypto/x509"
"encoding/asn1"
"encoding/pem"
"fmt"
"log"
"math/big"
)
// RSAPublicKey RSA 公钥结构
type RSAPublicKey struct {
N *big.Int `asn1:"integer"`
E int `asn1:"integer"`
}
// RSAPrivateKey RSA 私钥结构
type RSAPrivateKey struct {
Version int
Modulus *big.Int
PublicExponent int
PrivateExponent *big.Int
Prime1 *big.Int
Prime2 *big.Int
Exponent1 *big.Int
Exponent2 *big.Int
Coefficient *big.Int
}
func main() {
// 生成 RSA 密钥
privateKey, err := rsa.GenerateKey(nil, 2048)
if err != nil {
log.Fatal(err)
}
// 编码公钥
pubKey := RSAPublicKey{
N: privateKey.N,
E: privateKey.E,
}
pubData, err := asn1.Marshal(pubKey)
if err != nil {
log.Fatal(err)
}
// 使用标准库编码(PKIX 格式)
pubDER, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey)
if err != nil {
log.Fatal(err)
}
// PEM 编码
pubPEM := pem.EncodeToMemory(&pem.Block{
Type: "RSA PUBLIC KEY",
Bytes: pubDER,
})
fmt.Printf("公钥 PEM:\n%s\n", string(pubPEM))
// 编码私钥
privDER := x509.MarshalPKCS1PrivateKey(privateKey)
privPEM := pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: privDER,
})
fmt.Printf("私钥 PEM:\n%s\n", string(privPEM))
// 解码公钥
var decodedPub RSAPublicKey
asn1.Unmarshal(pubData, &decodedPub)
fmt.Printf("解码公钥 N: %s\n", decodedPub.N.String())
fmt.Printf("解码公钥 E: %d\n", decodedPub.E)
// 解码私钥
var decodedPriv RSAPrivateKey
asn1.Unmarshal(privDER, &decodedPriv)
fmt.Printf("解码私钥模数:%s\n", decodedPriv.Modulus.String())
}
示例 4:解析 X.509 证书
package main
import (
"crypto/x509"
"encoding/asn1"
"encoding/pem"
"fmt"
"io/ioutil"
"log"
)
// Certificate 简化的 X.509 证书结构
type Certificate struct {
TBSCertificate TBSCertificate
SignatureAlgorithm AlgorithmIdentifier
SignatureValue asn1.BitString
}
// TBSCertificate TBS 证书部分
type TBSCertificate struct {
Version int `asn1:"tag:0,default:0"`
SerialNumber asn1.RawValue
Signature AlgorithmIdentifier
Issuer asn1.RawValue
Validity Validity
Subject asn1.RawValue
SubjectPKI SubjectPublicKeyInfo
IssuerUniqueID asn1.RawValue `asn1:"tag:1,optional"`
SubjectUniqueID asn1.RawValue `asn1:"tag:2,optional"`
Extensions []Extension `asn1:"tag:3,optional"`
}
// Validity 有效期
type Validity struct {
NotBefore asn1.RawTime
NotAfter asn1.RawTime
}
// SubjectPublicKeyInfo 公钥信息
type SubjectPublicKeyInfo struct {
Algorithm AlgorithmIdentifier
SubjectPublicKey asn1.BitString
}
// Extension 证书扩展
type Extension struct {
Id asn1.ObjectIdentifier
Critical bool `asn1:"optional"`
Value []byte
}
// AlgorithmIdentifier 算法标识符
type AlgorithmIdentifier struct {
Algorithm asn1.ObjectIdentifier
Parameters asn1.RawValue `asn1:"optional"`
}
func main() {
// 读取证书文件
certData, err := ioutil.ReadFile("certificate.pem")
if err != nil {
log.Fatal(err)
}
// 解析 PEM
block, _ := pem.Decode(certData)
if block == nil {
log.Fatal("无效的 PEM 数据")
}
// 使用标准库解析
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
log.Fatal(err)
}
fmt.Printf("证书信息:\n")
fmt.Printf(" 序列号:%s\n", cert.SerialNumber.String())
fmt.Printf(" 颁发者:%s\n", cert.Issuer.String())
fmt.Printf(" 主题:%s\n", cert.Subject.String())
fmt.Printf(" 有效期:%s - %s\n", cert.NotBefore, cert.NotAfter)
// 手动 ASN.1 解析
var asn1Cert Certificate
rest, err := asn1.Unmarshal(block.Bytes, &asn1Cert)
if err != nil {
log.Fatal(err)
}
fmt.Printf("\nASN.1 解析:\n")
fmt.Printf(" 签名算法 OID: %s\n", asn1Cert.SignatureAlgorithm.Algorithm.String())
fmt.Printf(" 签名长度:%d 位\n", asn1Cert.SignatureValue.BitLength)
fmt.Printf(" 剩余数据:%d 字节\n", len(rest))
// 解析扩展
fmt.Printf("\n证书扩展:\n")
for _, ext := range asn1Cert.TBSCertificate.Extensions {
fmt.Printf(" OID: %s\n", ext.Id.String())
fmt.Printf(" 关键:%v\n", ext.Critical)
fmt.Printf(" 值大小:%d 字节\n", len(ext.Value))
}
}
示例 5:自定义 ASN.1 结构
package main
import (
"encoding/asn1"
"fmt"
"log"
"math/big"
)
// 定义自定义 OID
var (
oidMyApplication = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 99999, 1}
oidUserName = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 99999, 1, 1}
oidUserEmail = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 99999, 1, 2}
oidUserAge = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 99999, 1, 3}
)
// UserData 用户数据
type UserData struct {
Name string `asn1:"utf8string,tag:1"`
Email string `asn1:"ia5string,tag:2,optional"`
Age int `asn1:"integer,tag:3,optional"`
}
// UserRecord 用户记录
type UserRecord struct {
Version int `asn1:"integer,tag:0,default:1"`
UserID *big.Int `asn1:"integer"`
Data UserData
Attributes []Attribute
}
// Attribute 自定义属性
type Attribute struct {
Type asn1.ObjectIdentifier
Value asn1.RawValue
}
func main() {
// 创建用户记录
userID := big.NewInt(12345)
record := UserRecord{
Version: 1,
UserID: userID,
Data: UserData{
Name: "张三",
Email: "zhangsan@example.com",
Age: 30,
},
Attributes: []Attribute{
{
Type: oidUserName,
Value: asn1.RawValue{
Tag: asn1.TagUTF8String,
Bytes: []byte("张三"),
},
},
},
}
// 编码
data, err := asn1.Marshal(record)
if err != nil {
log.Fatal(err)
}
fmt.Printf("编码大小:%d 字节\n", len(data))
fmt.Printf("编码数据:%x\n", data)
// 解码
var decodedRecord UserRecord
rest, err := asn1.Unmarshal(data, &decodedRecord)
if err != nil {
log.Fatal(err)
}
fmt.Printf("\n解码结果:\n")
fmt.Printf(" 版本:%d\n", decodedRecord.Version)
fmt.Printf(" 用户 ID: %s\n", decodedRecord.UserID.String())
fmt.Printf(" 姓名:%s\n", decodedRecord.Data.Name)
fmt.Printf(" 邮箱:%s\n", decodedRecord.Data.Email)
fmt.Printf(" 年龄:%d\n", decodedRecord.Data.Age)
fmt.Printf(" 属性数量:%d\n", len(decodedRecord.Attributes))
fmt.Printf(" 剩余数据:%d 字节\n", len(rest))
}
示例 6:处理可选字段和默认值
package main
import (
"encoding/asn1"
"fmt"
"log"
)
// OptionalData 包含可选字段的数据
type OptionalData struct {
Required int `asn1:"integer"`
Optional1 string `asn1:"utf8string,optional"`
Optional2 int `asn1:"integer,optional"`
DefaultVal int `asn1:"integer,optional,default:42"`
}
func main() {
// 1. 只有必填字段
data1 := OptionalData{
Required: 100,
}
encoded1, err := asn1.Marshal(data1)
if err != nil {
log.Fatal(err)
}
var decoded1 OptionalData
asn1.Unmarshal(encoded1, &decoded1)
fmt.Printf("示例 1(只有必填字段):\n")
fmt.Printf(" Required: %d\n", decoded1.Required)
fmt.Printf(" Optional1: '%s' (空)\n", decoded1.Optional1)
fmt.Printf(" Optional2: %d (0)\n", decoded1.Optional2)
fmt.Printf(" DefaultVal: %d (默认值)\n", decoded1.DefaultVal)
// 2. 包含所有字段
data2 := OptionalData{
Required: 200,
Optional1: "Hello",
Optional2: 99,
DefaultVal: 100, // 覆盖默认值
}
encoded2, err := asn1.Marshal(data2)
if err != nil {
log.Fatal(err)
}
var decoded2 OptionalData
asn1.Unmarshal(encoded2, &decoded2)
fmt.Printf("\n示例 2(所有字段):\n")
fmt.Printf(" Required: %d\n", decoded2.Required)
fmt.Printf(" Optional1: '%s'\n", decoded2.Optional1)
fmt.Printf(" Optional2: %d\n", decoded2.Optional2)
fmt.Printf(" DefaultVal: %d\n", decoded2.DefaultVal)
// 3. 编码大小对比
fmt.Printf("\n编码大小对比:\n")
fmt.Printf(" 示例 1: %d 字节\n", len(encoded1))
fmt.Printf(" 示例 2: %d 字节\n", len(encoded2))
}
常见错误和注意事项
⚠️ 时间处理
// ✅ 正确:使用 UTC 时间
type Valid struct {
NotBefore time.Time `asn1:"utctime"`
NotAfter time.Time `asn1:"utctime"`
}
// ⚠️ 注意:UTCTime 只能表示 1950-2049 年
// 2050 年以后的时间需要使用 GeneralizedTime
type ValidLong struct {
NotBefore time.Time `asn1:"generalizedtime"`
NotAfter time.Time `asn1:"generalizedtime"`
}
⚠️ 大整数处理
// ✅ 正确:使用 *big.Int
type LargeNumber struct {
Value *big.Int `asn1:"integer"`
}
// ❌ 错误:int64 可能溢出
type WrongNumber struct {
Value int64 `asn1:"integer"` // 可能溢出
}
⚠️ 可选字段
// ✅ 正确:可选字段应该有零值
type Data struct {
Required string `asn1:"utf8string"`
Optional string `asn1:"utf8string,optional"`
}
// 解码后检查可选字段
if data.Optional == "" {
// 字段不存在
}
⚠️ 标签号冲突
// ✅ 正确:明确指定标签号
type Message struct {
Field1 string `asn1:"tag:1,utf8string"`
Field2 int `asn1:"tag:2,integer"`
Field3 []byte `asn1:"tag:3,octetstring"`
}
// ❌ 错误:标签号重复
type WrongMessage struct {
Field1 string `asn1:"tag:1,utf8string"`
Field2 int `asn1:"tag:1,integer"` // 标签号冲突
}
总结
核心类型
| 类型 | 用途 | 示例 |
|---|---|---|
| ObjectIdentifier | OID | 1.2.840.113549.1.1.1 |
| BitString | 位字符串 | 公钥、签名 |
| RawValue | 原始值 | 未知类型、扩展 |
| Enumerated | 枚举 | 算法类型 |
核心函数
| 函数 | 用途 | 说明 |
|---|---|---|
| Marshal | 编码 | Go 值 → DER |
| Unmarshal | 解码 | DER → Go 值 |
| MarshalWithParams | 带参数编码 | 指定标签参数 |
| UnmarshalWithParams | 带参数解码 | 指定标签参数 |
常用标签
| 标签 | ASN.1 类型 | Go 类型 |
|---|---|---|
asn1:"boolean" | BOOLEAN | bool |
asn1:"integer" | INTEGER | int, *big.Int |
asn1:"bitstring" | BIT STRING | BitString |
asn1:"octetstring" | OCTET STRING | []byte |
asn1:"utf8string" | UTF8String | string |
asn1:"oid" | OBJECT IDENTIFIER | ObjectIdentifier |
asn1:"sequence" | SEQUENCE | struct |
asn1:"utctime" | UTCTime | time.Time |
使用场景
| 场景 | 说明 |
|---|---|
| X.509 证书 | 证书结构解析和生成 |
| 加密密钥 | RSA、EC 密钥编码 |
| 数字签名 | 签名值编码 |
| LDAP | 目录服务协议 |
| TLS/SSL | 握手消息编码 |
参考资料
最后更新:2026-04-03
Go 版本:Go 1.23+