mirror of
https://github.com/golang/go
synced 2024-09-29 22:14:29 -06:00
crypto/x509: generate SubjectKeyId for CAs
Fixes #26676 Change-Id: I5bc91d4a8161bc6ff25effcf93f551f735fef115 Reviewed-on: https://go-review.googlesource.com/c/go/+/227098 Run-TryBot: Katie Hockman <katie@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Filippo Valsorda <filippo@golang.org>
This commit is contained in:
parent
7b5303d08a
commit
6f3a9515b6
@ -17,6 +17,7 @@ import (
|
||||
"crypto/ed25519"
|
||||
"crypto/elliptic"
|
||||
"crypto/rsa"
|
||||
"crypto/sha1"
|
||||
_ "crypto/sha1"
|
||||
_ "crypto/sha256"
|
||||
_ "crypto/sha512"
|
||||
@ -1686,7 +1687,7 @@ func isIA5String(s string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildExtensions(template *Certificate, subjectIsEmpty bool, authorityKeyId []byte) (ret []pkix.Extension, err error) {
|
||||
func buildExtensions(template *Certificate, subjectIsEmpty bool, authorityKeyId []byte, subjectKeyId []byte) (ret []pkix.Extension, err error) {
|
||||
ret = make([]pkix.Extension, 10 /* maximum number of elements. */)
|
||||
n := 0
|
||||
|
||||
@ -1751,9 +1752,9 @@ func buildExtensions(template *Certificate, subjectIsEmpty bool, authorityKeyId
|
||||
n++
|
||||
}
|
||||
|
||||
if len(template.SubjectKeyId) > 0 && !oidInExtensions(oidExtensionSubjectKeyId, template.ExtraExtensions) {
|
||||
if len(subjectKeyId) > 0 && !oidInExtensions(oidExtensionSubjectKeyId, template.ExtraExtensions) {
|
||||
ret[n].Id = oidExtensionSubjectKeyId
|
||||
ret[n].Value, err = asn1.Marshal(template.SubjectKeyId)
|
||||
ret[n].Value, err = asn1.Marshal(subjectKeyId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -2082,6 +2083,9 @@ var emptyASN1Subject = []byte{0x30, 0}
|
||||
// The AuthorityKeyId will be taken from the SubjectKeyId of parent, if any,
|
||||
// unless the resulting certificate is self-signed. Otherwise the value from
|
||||
// template will be used.
|
||||
//
|
||||
// If SubjectKeyId from template is empty and the template is a CA, SubjectKeyId
|
||||
// will be generated from the hash of the public key.
|
||||
func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv interface{}) (cert []byte, err error) {
|
||||
key, ok := priv.(crypto.Signer)
|
||||
if !ok {
|
||||
@ -2117,12 +2121,24 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
|
||||
authorityKeyId = parent.SubjectKeyId
|
||||
}
|
||||
|
||||
extensions, err := buildExtensions(template, bytes.Equal(asn1Subject, emptyASN1Subject), authorityKeyId)
|
||||
encodedPublicKey := asn1.BitString{BitLength: len(publicKeyBytes) * 8, Bytes: publicKeyBytes}
|
||||
pki := publicKeyInfo{nil, publicKeyAlgorithm, encodedPublicKey}
|
||||
subjectKeyId := template.SubjectKeyId
|
||||
if len(subjectKeyId) == 0 && template.IsCA {
|
||||
// SubjectKeyId generated using method 1 in RFC 5280, Section 4.2.1.2
|
||||
b, err := asn1.Marshal(pki)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h := sha1.Sum(b)
|
||||
subjectKeyId = h[:]
|
||||
}
|
||||
|
||||
extensions, err := buildExtensions(template, bytes.Equal(asn1Subject, emptyASN1Subject), authorityKeyId, subjectKeyId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
encodedPublicKey := asn1.BitString{BitLength: len(publicKeyBytes) * 8, Bytes: publicKeyBytes}
|
||||
c := tbsCertificate{
|
||||
Version: 2,
|
||||
SerialNumber: template.SerialNumber,
|
||||
@ -2130,7 +2146,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
|
||||
Issuer: asn1.RawValue{FullBytes: asn1Issuer},
|
||||
Validity: validity{template.NotBefore.UTC(), template.NotAfter.UTC()},
|
||||
Subject: asn1.RawValue{FullBytes: asn1Subject},
|
||||
PublicKey: publicKeyInfo{nil, publicKeyAlgorithm, encodedPublicKey},
|
||||
PublicKey: pki,
|
||||
Extensions: extensions,
|
||||
}
|
||||
|
||||
|
@ -1710,6 +1710,33 @@ func TestNoAuthorityKeyIdInSelfSignedCert(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoSubjectKeyIdInCert(t *testing.T) {
|
||||
template := &Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
Subject: pkix.Name{
|
||||
CommonName: "Σ Acme Co",
|
||||
},
|
||||
NotBefore: time.Unix(1000, 0),
|
||||
NotAfter: time.Unix(100000, 0),
|
||||
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: true,
|
||||
}
|
||||
if cert := serialiseAndParse(t, template); len(cert.SubjectKeyId) == 0 {
|
||||
t.Fatalf("self-signed certificate did not generate subject key id using the public key")
|
||||
}
|
||||
|
||||
template.IsCA = false
|
||||
if cert := serialiseAndParse(t, template); len(cert.SubjectKeyId) != 0 {
|
||||
t.Fatalf("self-signed certificate generated subject key id when it isn't a CA")
|
||||
}
|
||||
|
||||
template.SubjectKeyId = []byte{1, 2, 3, 4}
|
||||
if cert := serialiseAndParse(t, template); len(cert.SubjectKeyId) == 0 {
|
||||
t.Fatalf("self-signed certificate erased explicit subject key id")
|
||||
}
|
||||
}
|
||||
|
||||
func TestASN1BitLength(t *testing.T) {
|
||||
tests := []struct {
|
||||
bytes []byte
|
||||
|
Loading…
Reference in New Issue
Block a user