问答:使用Go中的电子邮件地址创建证书签名请求(CSR)
我尝试使用”crypto/x509″软件包生成CSR,但没有找到在其Subject中添加”emailAddress”字段的方法.
根据文档,CertificateRequest结构有一个”EmailAddresses [] string”字段,但它被序列化为SAN扩展.这是我使用的测试代码:http: //play.golang.org/p/OtObaTyuTM
我还使用”openssl req”程序创建了一个CSR并比较了结果:
% openssl req -in openssl.csr -noout -textCertificate Request: Data: Version: 0 (0x0) Subject: C=AU, ST=Some-State, L=MyCity, O=Company Ltd, OU=IT, CN=domain.com/emailAddress=test@email.com Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (512 bit) Modulus: 00:a3:05:e3:37:63:f9:8b:d0:37:46:2d:a8:d9:26: 4e:be:83:1d:b9:30:88:2b:80:4b:53:cc:7c:01:86: b0:9b:1d:3b:0a:05:c4:56:47:4e:5d:90:f9:5a:29: 8b:9a:7f:fa:4b:5e:e4:5d:dd:c6:8b:87:33:c4:b4: fa:6b:b4:67:bd Exponent: 65537 (0x10001) Attributes: a0:00 Signature Algorithm: sha1WithRSAEncryption 0b:24:6e:0a:f9:bf:23:d7:41:5f:96:da:78:d1:99:18:fb:d6: 71:7e:79:f0:02:e9:8a:50:a9:00:32:df:26:14:2f:f4:3e:c4: 22:c9:5c:4e:79:c1:c2:22:1b:2a:da:79:6f:51:ba:8a:12:63: 27:02:4a:b3:22:97:59:f7:6e:d6=============================================================== % openssl req -in golang.csr -noout -textCertificate Request: Data: Version: 0 (0x0) Subject: C=AU, O=Company Ltd, OU=IT, L=MyCity, ST=Some-State, CN=domain.com Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (512 bit) Modulus: 00:ac:b6:51:5b:53:44:44:20:91:da:01:45:72:49: 95:83:78:74:7c:05:f9:a7:77:88:02:3a:23:5f:04: c3:69:45:b9:5a:bb:fd:e7:d3:24:5f:46:14:b8:7d: 30:ce:a0:c6:ea:e3:3b:ec:4c:75:24:cc:ce:60:1d: e9:33:57:ae:21 Exponent: 65537 (0x10001) Attributes: Requested Extensions: X509v3 Subject Alternative Name: email:test@email.com Signature Algorithm: sha256WithRSAEncryption a1:c1:b7:80:a0:f0:c3:b6:44:06:f4:ad:12:3a:67:19:fa:84: 34:22:2a:d9:56:d9:8b:c9:a4:d0:cf:8d:a1:36:87:fa:75:b7: 05:40:0a:15:1f:72:61:85:a8:09:bc:f4:13:e6:24:5e:2e:b7: 99:e3:93:53:4e:2d:d5:0c:22:fc
在我看来,我应该自己使用emainAddress oid构建RawSubject字段,但我没有找到任何代码示例.UPD: 我找到了解决方案.如上所述,必须手动准备RawSubject字段:
subj := pkix.Name{ CommonName: cn, Country: []string{c}, Organization: []string{o}, OrganizationalUnit: []string{ou}, Locality: []string{l}, Province: []string{s},}rawSubj := subj.ToRDNSequence()rawSubj = appendRDNs(rawSubj, []string{e}, oidEmailAddress)asn1Subj, err := asn1.Marshal(rawSubj)template := x509.CertificateRequest{ RawSubject: asn1Subj, SignatureAlgorithm: x509.SHA1WithRSA,}
哪里:
var oidEmailAddress = asn1.ObjectIdentifier {1,2,840,113549,1,9,1}
appendRDNs()在crypto/x509/pkix中定义(因为它的名称不是以大写字母开头,默认情况下不会导出.你可以再次将它定义为你自己的复制和粘贴功能).
Jeremy Jay.. 14
我知道mephist回答了他自己的问题,但他留下了一些东西要拼凑起来.所以,为了完整起见(因为我在过去的两年里已经两次登陆……)这是一个完整的工作示例:https://play.golang.org/p/YL_qfPe4Zz
package mainimport ( “crypto/rand” “crypto/rsa” “crypto/x509” “crypto/x509/pkix” “encoding/asn1” “encoding/pem” “os”)var oidEmailAddress = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}func main() { keyBytes, _ := rsa.GenerateKey(rand.Reader, 1024) emailAddress := “test@example.com” subj := pkix.Name{ CommonName: “example.com”, Country: []string{“AU”}, Province: []string{“Some-State”}, Locality: []string{“MyCity”}, Organization: []string{“Company Ltd”}, OrganizationalUnit: []string{“IT”}, } rawSubj := subj.ToRDNSequence() rawSubj = append(rawSubj, []pkix.AttributeTypeAndValue{ {Type: oidEmailAddress, Value: emailAddress}, }) asn1Subj, _ := asn1.Marshal(rawSubj) template := x509.CertificateRequest{ RawSubject: asn1Subj, EmailAddresses: []string{emailAddress}, SignatureAlgorithm: x509.SHA256WithRSA, } csrBytes, _ := x509.CreateCertificateRequest(rand.Reader, &template, keyBytes) pem.Encode(os.Stdout, &pem.Block{Type: “CERTIFICATE REQUEST”, Bytes: csrBytes})}
Joe Shaw.. 10
这是Jeremy的答案的一个变种,它回答了Go中的一些新增功能,并修复了我认为是一个bug.(有关更多信息,请参阅我对他的帖子的评论.)
这是下面代码的可运行的游乐场链接.
package mainimport ( “crypto/rand” “crypto/rsa” “crypto/x509” “crypto/x509/pkix” “encoding/asn1” “encoding/pem” “os”)var oidEmailAddress = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}func main() { keyBytes, _ := rsa.GenerateKey(rand.Reader, 1024) emailAddress := “test@example.com” subj := pkix.Name{ CommonName: “example.com”, Country: []string{“AU”}, Province: []string{“Some-State”}, Locality: []string{“MyCity”}, Organization: []string{“Company Ltd”}, OrganizationalUnit: []string{“IT”}, ExtraNames: []pkix.AttributeTypeAndValue{ { Type: oidEmailAddress, Value: asn1.RawValue{ Tag: asn1.TagIA5String, Bytes: []byte(emailAddress), }, }, }, } template := x509.CertificateRequest{ Subject: subj, SignatureAlgorithm: x509.SHA256WithRSA, } csrBytes, _ := x509.CreateCertificateRequest(rand.Reader, &template, keyBytes) pem.Encode(os.Stdout, &pem.Block{Type: “CERTIFICATE REQUEST”, Bytes: csrBytes})}
主要区别是:
不是序列化主题并使用RawSubject字段,而是将电子邮件地址字段添加到pkix.Name ExtraNames切片中(在Go 1.5中添加).
电子邮件地址需要编码为ASN.1 IA5String,而不是作为PrintableString或UTF8String.这就是我们需要使用的原因asn1.RawValue.
不要在CertificateRequest EmailAddresses字段中添加电子邮件地址,该字段设置SubjectAltName(SAN).这些更适用于签名电子邮件等内容.在TLS证书的上下文中,SAN应该用于备用有效的主机名和IP地址.
(更新2018年6月14日:将Value已经从一个改变string到asn1.RawValueOpenSSL的拒绝以其它方式生成的CSR因为ASN.1序列编码.emailAddress需要是IA5String,而不是PrintableString或UTF8String.)