You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Go生成OU以逗号分隔的CSR?

关于Go crypto库生成CSR时OU字段分隔符的问题

我尝试使用Go语言的crypto库生成Certificate Signing Request(CSR),但遇到问题:生成的CSR中Organizational Unit(OU)字段默认以+分隔,示例如下:

Subject: O = Example Org, OU = OU1 + OU = OU2, CN = example.com

我希望生成的CSR中OU字段以逗号分隔,格式如下:

Subject: O = Example Org, OU = OU1, OU = OU2, CN = example.com

OU以+分隔似乎是crypto库的默认行为,请问能否通过crypto库实现需求?如果不能,有没有其他库可以生成OU以逗号分隔的CSR?
使用的代码如下:

package main

import (
    "crypto/rand"
    "crypto/rsa"
    "crypto/x509"
    "crypto/x509/pkix"
    "encoding/pem"
    "fmt"
    "os"
)

func main() {
    privKey, err := rsa.GenerateKey(rand.Reader, 2048)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    csrTemplate := x509.CertificateRequest{
        Subject: pkix.Name{
            CommonName:         "example.com",
            Organization:       []string{"Example Org"},
            OrganizationalUnit: []string{"OU1", "OU2"},
        },
        EmailAddresses: []string{"test@example.com"},
    }

    csrBytes, err := x509.CreateCertificateRequest(rand.Reader, &csrTemplate, privKey)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    csrPem := pem.EncodeToMemory(&pem.Block{
        Type:  "CERTIFICATE REQUEST",
        Bytes: csrBytes,
    })

    fmt.Println(string(csrPem))
}

问题分析与解决方案

1. 标准库的限制

Go标准库crypto/x509处理pkix.Name中的多值字段(如OrganizationalUnit)时,遵循X.500 DN规范,默认用+分隔同类型属性值。这是因为ASN.1编码中,多个同类型属性会被合并为一个条目,值之间用加号分隔,而非生成多个独立属性条目。因此仅通过标准库API无法直接生成逗号分隔的多OU格式。

2. 手动构造DN的ASN.1结构

要生成多个独立的OU属性,可绕过pkix.Name的默认处理,手动构造X.500 DN的ASN.1序列,将其赋值给x509.CertificateRequest的RawSubject字段替代Subject字段:

package main

import (
    "crypto/rand"
    "crypto/rsa"
    "crypto/x509"
    "crypto/x509/pkix"
    "encoding/asn1"
    "encoding/pem"
    "fmt"
    "os"
)

func main() {
    privKey, err := rsa.GenerateKey(rand.Reader, 2048)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    // 手动构造RDN序列,每个OU作为独立条目
    rdnSequence := pkix.RDNSequence{
        { // O属性
            {Type: asn1.ObjectIdentifier{2, 5, 4, 10}, Value: "Example Org"},
        },
        { // 第一个OU属性
            {Type: asn1.ObjectIdentifier{2, 5, 4, 11}, Value: "OU1"},
        },
        { // 第二个OU属性
            {Type: asn1.ObjectIdentifier{2, 5, 4, 11}, Value: "OU2"},
        },
        { // CN属性
            {Type: asn1.ObjectIdentifier{2, 5, 4, 3}, Value: "example.com"},
        },
    }

    // 将RDN序列编码为ASN.1字节
    rawSubject, err := asn1.Marshal(rdnSequence)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    csrTemplate := x509.CertificateRequest{
        RawSubject:     rawSubject,
        EmailAddresses: []string{"test@example.com"},
    }

    csrBytes, err := x509.CreateCertificateRequest(rand.Reader, &csrTemplate, privKey)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    csrPem := pem.EncodeToMemory(&pem.Block{
        Type:  "CERTIFICATE REQUEST",
        Bytes: csrBytes,
    })

    fmt.Println(string(csrPem))
}

3. 第三方库选项

若不想手动处理ASN.1编码,可使用第三方库(如github.com/cloudflare/cfssl),它提供了更灵活的DN构造方式,支持生成多个独立OU属性,能简化代码逻辑,但会增加项目依赖。


内容的提问来源于stack exchange,提问作者Shailendra Kirtikar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 00:22:37