I'm creating a CA cert. And I'd like to add the subjectAltName extension with some values like email or crl or public cert location and so on.
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/pem"
"fmt"
"math/big"
"os"
"time"
//"net"
//"strconv"
)
func main() {
template := x509.Certificate{}
template.Subject = pkix.Name{
Organization: []string{"domain.tld", "My Name"},
StreetAddress: []string{"Whatever. 123"},
PostalCode: []string{"12345"},
Province: []string{"Redneckville"},
Locality: []string{"Woods"},
Country: []string{"US"},
CommonName: "CA domain my name",
}
template.NotBefore = time.Now()
template.NotAfter = template.NotBefore.Add(87658 * time.Hour)
template.KeyUsage = x509.KeyUsageCertSign | x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCRLSign
template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}
template.IsCA = true
template.BasicConstraintsValid = true
extSubjectAltName := pkix.Extension{}
extSubjectAltName.Id = asn1.ObjectIdentifier{2, 5, 29, 17}
extSubjectAltName.Critical = false
var e error
extSubjectAltName.Value, e = asn1.Marshal([]string{`email:mail@domain.tld`, `URI:http://ca.domain.tld/`})
if e != nil {
fmt.Println(e.Error())
return
}
template.Extensions = []pkix.Extension{extSubjectAltName}
priv, err := rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
fmt.Println("Failed to generate private key:", err)
os.Exit(1)
}
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
template.SerialNumber, err = rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
fmt.Println("Failed to generate serial number:", err)
os.Exit(1)
}
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
if err != nil {
fmt.Println("Failed to create certificate:", err)
os.Exit(1)
}
certOut, err := os.Create("ca.crt")
if err != nil {
fmt.Println("Failed to open ca.pem for writing:", err)
os.Exit(1)
}
pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
certOut.Close()
keyOut, err := os.OpenFile("ca.key", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
fmt.Println("failed to open ca.key for writing:", err)
os.Exit(1)
}
pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
keyOut.Close()
}
When I do this, the result is
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Key Encipherment, Certificate Sign, CRL Sign
X509v3 Extended Key Usage:
TLS Web Client Authentication, TLS Web Server Authentication
X509v3 Basic Constraints: critical
CA:TRUE
So but I expect something like
X509v3 Subject Alternative Name:
email:caoperator@disig.sk, URI:http://www.disig.sk/ca
How do I add the extension with those values?
I also tried Value: []byte(``email:my@email.com, URI:http://some.tld/uri``)
< double "`" because formatting
X.509 extensions are ASN.1 DER encoded. Placing an ASCII representation of a SAN extension directly into the binary of the certificate won't work and will truncate the data. This is probably the reason behind the OP's problem.
If you are trying to add any SAN supported by Go, the way to do it is how Cole Brumley specified. This is because Go handles the ASN.1 serialization and this avoids you needing to write any extra code. Look at the section Subject Alternate Name values to see what Go supports as far as SANs: https://godoc.org/crypto/x509#Certificate.
If you are trying to add some SAN type not supported by Go, like a URI, take a look at how the marshalling is done for dns, ip and email using raw values and that's probably going to help you figure it out: https://github.com/golang/go/blob/2a26f5809e4e80e7d8d4e20b9965efb2eefe71c5/src/crypto/x509/x509.go#L1439-L1456. You'll probably need to find out what the corresponding tag is.
note:
template.ExtraExtensions
instead oftemplate.Extensions
I know this is a late answer, but this question came up for me in a Google search for golang x509 SubjectAltName, so I thought I'd throw in my 2 cents for future Googlers:
According to the x509.Certificate spec, SubjectAltNames should be put in the x509.Certificate's
DNSName
,EmailAddresses
, orIPAddresses
properties.Your example + happy SAN: