"crypto/ed25519"
"crypto/elliptic"
"crypto/rsa"
+ "crypto/sha1"
_ "crypto/sha1"
_ "crypto/sha256"
_ "crypto/sha512"
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
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
}
// 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 {
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,
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,
}
}
}
+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