Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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"`  // 标签号冲突
}

总结

核心类型

类型用途示例
ObjectIdentifierOID1.2.840.113549.1.1.1
BitString位字符串公钥、签名
RawValue原始值未知类型、扩展
Enumerated枚举算法类型

核心函数

函数用途说明
Marshal编码Go 值 → DER
Unmarshal解码DER → Go 值
MarshalWithParams带参数编码指定标签参数
UnmarshalWithParams带参数解码指定标签参数

常用标签

标签ASN.1 类型Go 类型
asn1:"boolean"BOOLEANbool
asn1:"integer"INTEGERint, *big.Int
asn1:"bitstring"BIT STRINGBitString
asn1:"octetstring"OCTET STRING[]byte
asn1:"utf8string"UTF8Stringstring
asn1:"oid"OBJECT IDENTIFIERObjectIdentifier
asn1:"sequence"SEQUENCEstruct
asn1:"utctime"UTCTimetime.Time

使用场景

场景说明
X.509 证书证书结构解析和生成
加密密钥RSA、EC 密钥编码
数字签名签名值编码
LDAP目录服务协议
TLS/SSL握手消息编码

参考资料


最后更新:2026-04-03
Go 版本:Go 1.23+