mirror of
https://github.com/golang/go
synced 2024-11-18 01:34:44 -07:00
crypto/x509: follow OpenSSL and emit Extension structures directly in CSRs.
I don't know if I got lost in the old PKCS documents, or whether this is
a case where reality diverges from the spec, but OpenSSL clearly stuffs
PKIX Extension objects in CSR attributues directly[1].
In either case, doing what OpenSSL does seems valid here and allows the
critical flag in extensions to be serialised.
Fixes #13739.
[1] e3713c365c/crypto/x509/x509_req.c (L173)
Change-Id: Ic1e73ba9bd383a357a2aa8fc4f6bd76811bbefcc
Reviewed-on: https://go-review.googlesource.com/70851
Run-TryBot: Adam Langley <agl@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
This commit is contained in:
parent
c529141d72
commit
0b37f05d8d
@ -2317,7 +2317,7 @@ func newRawAttributes(attributes []pkix.AttributeTypeAndValueSET) ([]asn1.RawVal
|
|||||||
return rawAttributes, nil
|
return rawAttributes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseRawAttributes Unmarshals RawAttributes intos AttributeTypeAndValueSETs.
|
// parseRawAttributes Unmarshals RawAttributes into AttributeTypeAndValueSETs.
|
||||||
func parseRawAttributes(rawAttributes []asn1.RawValue) []pkix.AttributeTypeAndValueSET {
|
func parseRawAttributes(rawAttributes []asn1.RawValue) []pkix.AttributeTypeAndValueSET {
|
||||||
var attributes []pkix.AttributeTypeAndValueSET
|
var attributes []pkix.AttributeTypeAndValueSET
|
||||||
for _, rawAttr := range rawAttributes {
|
for _, rawAttr := range rawAttributes {
|
||||||
@ -2410,70 +2410,57 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv
|
|||||||
|
|
||||||
extensions = append(extensions, template.ExtraExtensions...)
|
extensions = append(extensions, template.ExtraExtensions...)
|
||||||
|
|
||||||
var attributes []pkix.AttributeTypeAndValueSET
|
// Make a copy of template.Attributes because we may alter it below.
|
||||||
attributes = append(attributes, template.Attributes...)
|
attributes := make([]pkix.AttributeTypeAndValueSET, 0, len(template.Attributes))
|
||||||
|
for _, attr := range template.Attributes {
|
||||||
|
values := make([][]pkix.AttributeTypeAndValue, len(attr.Value))
|
||||||
|
copy(values, attr.Value)
|
||||||
|
attributes = append(attributes, pkix.AttributeTypeAndValueSET{
|
||||||
|
Type: attr.Type,
|
||||||
|
Value: values,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
extensionsAppended := false
|
||||||
if len(extensions) > 0 {
|
if len(extensions) > 0 {
|
||||||
// specifiedExtensions contains all the extensions that we
|
// Append the extensions to an existing attribute if possible.
|
||||||
// found specified via template.Attributes.
|
for _, atvSet := range attributes {
|
||||||
specifiedExtensions := make(map[string]bool)
|
if !atvSet.Type.Equal(oidExtensionRequest) || len(atvSet.Value) == 0 {
|
||||||
|
|
||||||
for _, atvSet := range template.Attributes {
|
|
||||||
if !atvSet.Type.Equal(oidExtensionRequest) {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// specifiedExtensions contains all the extensions that we
|
||||||
|
// found specified via template.Attributes.
|
||||||
|
specifiedExtensions := make(map[string]bool)
|
||||||
|
|
||||||
for _, atvs := range atvSet.Value {
|
for _, atvs := range atvSet.Value {
|
||||||
for _, atv := range atvs {
|
for _, atv := range atvs {
|
||||||
specifiedExtensions[atv.Type.String()] = true
|
specifiedExtensions[atv.Type.String()] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
atvs := make([]pkix.AttributeTypeAndValue, 0, len(extensions))
|
newValue := make([]pkix.AttributeTypeAndValue, 0, len(atvSet.Value[0])+len(extensions))
|
||||||
for _, e := range extensions {
|
newValue = append(newValue, atvSet.Value[0]...)
|
||||||
if specifiedExtensions[e.Id.String()] {
|
|
||||||
// Attributes already contained a value for
|
for _, e := range extensions {
|
||||||
// this extension and it takes priority.
|
if specifiedExtensions[e.Id.String()] {
|
||||||
continue
|
// Attributes already contained a value for
|
||||||
|
// this extension and it takes priority.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
newValue = append(newValue, pkix.AttributeTypeAndValue{
|
||||||
|
// There is no place for the critical
|
||||||
|
// flag in an AttributeTypeAndValue.
|
||||||
|
Type: e.Id,
|
||||||
|
Value: e.Value,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
atvs = append(atvs, pkix.AttributeTypeAndValue{
|
atvSet.Value[0] = newValue
|
||||||
// There is no place for the critical flag in a CSR.
|
extensionsAppended = true
|
||||||
Type: e.Id,
|
|
||||||
Value: e.Value,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append the extensions to an existing attribute if possible.
|
|
||||||
appended := false
|
|
||||||
for _, atvSet := range attributes {
|
|
||||||
if !atvSet.Type.Equal(oidExtensionRequest) || len(atvSet.Value) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
atvSet.Value[0] = append(atvSet.Value[0], atvs...)
|
|
||||||
appended = true
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, add a new attribute for the extensions.
|
|
||||||
if !appended {
|
|
||||||
attributes = append(attributes, pkix.AttributeTypeAndValueSET{
|
|
||||||
Type: oidExtensionRequest,
|
|
||||||
Value: [][]pkix.AttributeTypeAndValue{
|
|
||||||
atvs,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
asn1Subject := template.RawSubject
|
|
||||||
if len(asn1Subject) == 0 {
|
|
||||||
asn1Subject, err = asn1.Marshal(template.Subject.ToRDNSequence())
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rawAttributes, err := newRawAttributes(attributes)
|
rawAttributes, err := newRawAttributes(attributes)
|
||||||
@ -2481,6 +2468,38 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If not included in attributes, add a new attribute for the
|
||||||
|
// extensions.
|
||||||
|
if len(extensions) > 0 && !extensionsAppended {
|
||||||
|
attr := struct {
|
||||||
|
Type asn1.ObjectIdentifier
|
||||||
|
Value [][]pkix.Extension `asn1:"set"`
|
||||||
|
}{
|
||||||
|
Type: oidExtensionRequest,
|
||||||
|
Value: [][]pkix.Extension{extensions},
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := asn1.Marshal(attr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("x509: failed to serialise extensions attribute: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
var rawValue asn1.RawValue
|
||||||
|
if _, err := asn1.Unmarshal(b, &rawValue); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
rawAttributes = append(rawAttributes, rawValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
asn1Subject := template.RawSubject
|
||||||
|
if len(asn1Subject) == 0 {
|
||||||
|
asn1Subject, err = asn1.Marshal(template.Subject.ToRDNSequence())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tbsCSR := tbsCertificateRequest{
|
tbsCSR := tbsCertificateRequest{
|
||||||
Version: 0, // PKCS #10, RFC 2986
|
Version: 0, // PKCS #10, RFC 2986
|
||||||
Subject: asn1.RawValue{FullBytes: asn1Subject},
|
Subject: asn1.RawValue{FullBytes: asn1Subject},
|
||||||
|
@ -1240,8 +1240,9 @@ func TestCertificateRequestOverrides(t *testing.T) {
|
|||||||
// template.
|
// template.
|
||||||
ExtraExtensions: []pkix.Extension{
|
ExtraExtensions: []pkix.Extension{
|
||||||
{
|
{
|
||||||
Id: oidExtensionSubjectAltName,
|
Id: oidExtensionSubjectAltName,
|
||||||
Value: sanContents,
|
Value: sanContents,
|
||||||
|
Critical: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -1252,6 +1253,10 @@ func TestCertificateRequestOverrides(t *testing.T) {
|
|||||||
t.Errorf("Extension did not override template. Got %v\n", csr.DNSNames)
|
t.Errorf("Extension did not override template. Got %v\n", csr.DNSNames)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(csr.Extensions) != 1 || !csr.Extensions[0].Id.Equal(oidExtensionSubjectAltName) || !csr.Extensions[0].Critical {
|
||||||
|
t.Errorf("SAN extension was not faithfully copied, got %#v", csr.Extensions)
|
||||||
|
}
|
||||||
|
|
||||||
// If there is already an attribute with X.509 extensions then the
|
// If there is already an attribute with X.509 extensions then the
|
||||||
// extra extensions should be added to it rather than creating a CSR
|
// extra extensions should be added to it rather than creating a CSR
|
||||||
// with two extension attributes.
|
// with two extension attributes.
|
||||||
|
Loading…
Reference in New Issue
Block a user