I tried to generate a CSR using "crypto/x509" package and didn't find the way to add a "emailAddress" field into its Subject.
According to the documentation CertificateRequest structure has a "EmailAddresses []string" field but it's serialized into SAN extension. Here is a test code i used: http://play.golang.org/p/OtObaTyuTM
Also I created a CSR using "openssl req" program and compared results:
% openssl req -in openssl.csr -noout -text
Certificate Request:
Data:
Version: 0 (0x0)
Subject: C=AU, ST=Some-State, L=MyCity, O=Company Ltd, OU=IT, CN=domain.com/[email protected]
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 -text
Certificate 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:[email protected]
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
To my mind I should build RawSubject field myself with emainAddress oid but I didn't find any code samples. UPD: I've found the solution. As I mentioned above, the RawSubject field must be prepared manually:
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,
}
where:
Thus the private key is needed to produce, but it is not part of, the CSR. CSR for personal ID certificates and signing certificates must have the email address of the ID holder or name of organisation in case of business ID.
In the Server Manager dashboard, in the top right corner, choose Tools, Certification Authority. In the Certification Authority window, choose your computer name. From the Action menu, choose All Tasks, Submit new request. Select your CSR file, and then choose Open.
This is a variation on Jeremy's answer which takes advantage of some new additions in Go since his answer, and also fixes what I believe to be a bug. (For more info on that, see my comments on his post.)
Here's a runnable playground link for the code below.
package main
import (
"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 := "[email protected]"
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})
}
The main differences are:
RawSubject
field, add the email address field to the pkix.Name ExtraNames
slice (added in Go 1.5).IA5String
, not as a PrintableString
or UTF8String
. This is why we need to use asn1.RawValue
.CertificateRequest
EmailAddresses
field, which sets a SubjectAltName (SAN). Those are designed more for things like signed emails. In the context of TLS certificates, SANs should be used for alternatively valid hostnames and IP addresses.(Update 2018-06-14: The Value
has been changed from a string
to an asn1.RawValue
. OpenSSL rejects CSRs generated otherwise because the ASN.1 serialized encoding of emailAddress
needs to be IA5String
rather than PrintableString
or UTF8String
.)
I know mephist answered his own question, but he left a few things to piece together. So, for the sake of completeness (and because I've landed here twice in the past 2 years...) Here's a complete working example: https://play.golang.org/p/YL_qfPe4Zz
package main
import (
"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 := "[email protected]"
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})
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With