如何用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.comOU以
+分隔似乎是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
相关产品推荐
相关产品推荐

