如何在 x509.Certificate 中添加扩展(subjectAltName)?

huangapple go评论109阅读模式
英文:

Go: How do I add an extension (subjectAltName) to a x509.Certificate?

问题

我正在创建一个CA证书,并且我想添加subjectAltName扩展,其中包含一些值,如电子邮件、crl或公共证书位置等。

你可以使用以下代码来添加这个扩展:

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}

将这段代码插入到你的main函数中的合适位置,然后重新运行程序,你应该会得到期望的结果。

希望对你有帮助!如果你还有其他问题,请随时问我。

英文:

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

答案1

得分: 7

extSubjectAltName := pkix.Extension{}
extSubjectAltName.Id = asn1.ObjectIdentifier{2, 5, 29, 17}
extSubjectAltName.Critical = false
extSubjectAltName.Value = []byte(email:my@mail.tld, URI:http://ca.dom.tld/)
template.ExtraExtensions = []pkix.Extension{extSubjectAltName}

注意:
template.ExtraExtensions 替代 template.Extensions

英文:
extSubjectAltName := pkix.Extension{}
extSubjectAltName.Id = asn1.ObjectIdentifier{2, 5, 29, 17}
extSubjectAltName.Critical = false
extSubjectAltName.Value = []byte(`email:my@mail.tld, URI:http://ca.dom.tld/`)
template.ExtraExtensions = []pkix.Extension{extSubjectAltName}

note:
template.ExtraExtensions instead of template.Extensions

答案2

得分: 5

X.509扩展是ASN.1 DER编码的。直接将SAN扩展的ASCII表示放入证书的二进制数据中是行不通的,并且会截断数据。这可能是OP问题的原因。

如果你想要添加任何Go支持的SAN,可以按照Cole Brumley指定的方式进行操作。这是因为Go处理ASN.1序列化,这样就避免了你需要编写额外代码的情况。查看"Subject Alternate Name values"部分,了解Go支持的SAN类型:https://godoc.org/crypto/x509#Certificate。

如果你想要添加一些Go不支持的SAN类型,比如URI,请参考如何使用原始值对dns、ip和email进行编组的方式,这可能会帮助你找到解决方法:https://github.com/golang/go/blob/2a26f5809e4e80e7d8d4e20b9965efb2eefe71c5/src/crypto/x509/x509.go#L1439-L1456。你可能需要找出对应的标签是什么。

英文:

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.

答案3

得分: 3

我知道这是一个晚回答,但是我在谷歌搜索golang x509 SubjectAltName时遇到了这个问题,所以我想为未来的谷歌用户提供一些建议:

根据x509.Certificate规范,SubjectAltNames应该放在x509.Certificate的DNSNameEmailAddressesIPAddresses属性中。

你的示例代码如下:

package main

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

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
	template.DNSNames = []string{"ca.my.domain", "ca"}

	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()
}

希望对你有帮助!

英文:

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, or IPAddresses properties.

Your example + happy SAN:

package main
import (
&quot;crypto/rand&quot;
&quot;crypto/rsa&quot;
&quot;crypto/x509&quot;
&quot;crypto/x509/pkix&quot;
&quot;encoding/pem&quot;
&quot;fmt&quot;
&quot;math/big&quot;
&quot;os&quot;
&quot;time&quot;
)
func main() {
template := x509.Certificate{}
template.Subject = pkix.Name{
Organization:  []string{&quot;domain.tld&quot;, &quot;My Name&quot;},
StreetAddress: []string{&quot;Whatever. 123&quot;},
PostalCode:    []string{&quot;12345&quot;},
Province:      []string{&quot;Redneckville&quot;},
Locality:      []string{&quot;Woods&quot;},
Country:       []string{&quot;US&quot;},
CommonName:    &quot;CA domain my name&quot;,
}
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
template.DNSNames = []string{&quot;ca.my.domain&quot;, &quot;ca&quot;}
priv, err := rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
fmt.Println(&quot;Failed to generate private key:&quot;, 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(&quot;Failed to generate serial number:&quot;, err)
os.Exit(1)
}
derBytes, err := x509.CreateCertificate(rand.Reader, &amp;template, &amp;template, &amp;priv.PublicKey, priv)
if err != nil {
fmt.Println(&quot;Failed to create certificate:&quot;, err)
os.Exit(1)
}
certOut, err := os.Create(&quot;ca.crt&quot;)
if err != nil {
fmt.Println(&quot;Failed to open ca.pem for writing:&quot;, err)
os.Exit(1)
}
pem.Encode(certOut, &amp;pem.Block{Type: &quot;CERTIFICATE&quot;, Bytes: derBytes})
certOut.Close()
keyOut, err := os.OpenFile(&quot;ca.key&quot;, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
fmt.Println(&quot;failed to open ca.key for writing:&quot;, err)
os.Exit(1)
}
pem.Encode(keyOut, &amp;pem.Block{Type: &quot;RSA PRIVATE KEY&quot;, Bytes: x509.MarshalPKCS1PrivateKey(priv)})
keyOut.Close()
}

huangapple
  • 本文由 发表于 2014年10月18日 23:43:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/26441547.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定