1
0
mirror of https://github.com/golang/go synced 2024-11-18 07:04:52 -07:00

crypto/x509/pkix: Parse and add additional elements in a DN

Additional elements in a DN can be added in via ExtraNames. This
option can also be used for sorting DN elements in a custom order.

Change-Id: Ie408d332de913dc2a33bdd86433be38abb7b55be
Reviewed-on: https://go-review.googlesource.com/2257
Reviewed-by: Adam Langley <agl@golang.org>
This commit is contained in:
Paul van Brouwershaven 2015-01-05 11:15:18 +00:00 committed by Adam Langley
parent 027e47b7b1
commit f7e78aa586
2 changed files with 57 additions and 13 deletions

View File

@ -46,7 +46,9 @@ type Extension struct {
}
// Name represents an X.509 distinguished name. This only includes the common
// elements of a DN. Additional elements in the name are ignored.
// elements of a DN. When parsing, all elements are stored in Names and
// non-standard elements can be extracted from there. When marshaling, elements
// in ExtraNames are appended and override other values with the same OID.
type Name struct {
Country, Organization, OrganizationalUnit []string
Locality, Province []string
@ -54,6 +56,7 @@ type Name struct {
SerialNumber, CommonName string
Names []AttributeTypeAndValue
ExtraNames []AttributeTypeAndValue
}
func (n *Name) FillFromRDNSequence(rdns *RDNSequence) {
@ -110,8 +113,8 @@ var (
// and returns the new value. The relativeDistinguishedNameSET contains an
// attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and
// search for AttributeTypeAndValue.
func appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNSequence {
if len(values) == 0 {
func (n Name) appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNSequence {
if len(values) == 0 || oidInAttributeTypeAndValue(oid, n.ExtraNames) {
return in
}
@ -125,23 +128,37 @@ func appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNS
}
func (n Name) ToRDNSequence() (ret RDNSequence) {
ret = appendRDNs(ret, n.Country, oidCountry)
ret = appendRDNs(ret, n.Organization, oidOrganization)
ret = appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit)
ret = appendRDNs(ret, n.Locality, oidLocality)
ret = appendRDNs(ret, n.Province, oidProvince)
ret = appendRDNs(ret, n.StreetAddress, oidStreetAddress)
ret = appendRDNs(ret, n.PostalCode, oidPostalCode)
ret = n.appendRDNs(ret, n.Country, oidCountry)
ret = n.appendRDNs(ret, n.Organization, oidOrganization)
ret = n.appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit)
ret = n.appendRDNs(ret, n.Locality, oidLocality)
ret = n.appendRDNs(ret, n.Province, oidProvince)
ret = n.appendRDNs(ret, n.StreetAddress, oidStreetAddress)
ret = n.appendRDNs(ret, n.PostalCode, oidPostalCode)
if len(n.CommonName) > 0 {
ret = appendRDNs(ret, []string{n.CommonName}, oidCommonName)
ret = n.appendRDNs(ret, []string{n.CommonName}, oidCommonName)
}
if len(n.SerialNumber) > 0 {
ret = appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber)
ret = n.appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber)
}
for _, atv := range n.ExtraNames {
ret = append(ret, []AttributeTypeAndValue{atv})
}
return ret
}
// oidInAttributeTypeAndValue returns whether a type with the given OID exists
// in atv.
func oidInAttributeTypeAndValue(oid asn1.ObjectIdentifier, atv []AttributeTypeAndValue) bool {
for _, a := range atv {
if a.Type.Equal(oid) {
return true
}
}
return false
}
// CertificateList represents the ASN.1 structure of the same name. See RFC
// 5280, section 5.1. Use Certificate.CheckCRLSignature to verify the
// signature.

View File

@ -326,6 +326,18 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
Subject: pkix.Name{
CommonName: commonName,
Organization: []string{"Σ Acme Co"},
Country: []string{"US"},
ExtraNames: []pkix.AttributeTypeAndValue{
{
Type: []int{2, 5, 4, 42},
Value: "Gopher",
},
// This should override the Country, above.
{
Type: []int{2, 5, 4, 6},
Value: "NL",
},
},
},
NotBefore: time.Unix(1000, 0),
NotAfter: time.Unix(100000, 0),
@ -391,6 +403,21 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
t.Errorf("%s: subject wasn't correctly copied from the template. Got %s, want %s", test.name, cert.Subject.CommonName, commonName)
}
if len(cert.Subject.Country) != 1 || cert.Subject.Country[0] != "NL" {
t.Errorf("%s: ExtraNames didn't override Country", test.name)
}
found := false
for _, atv := range cert.Subject.Names {
if atv.Type.Equal([]int{2, 5, 4, 42}) {
found = true
break
}
}
if !found {
t.Errorf("%s: Names didn't contain oid 2.5.4.42 from ExtraNames", test.name)
}
if cert.Issuer.CommonName != commonName {
t.Errorf("%s: issuer wasn't correctly copied from the template. Got %s, want %s", test.name, cert.Issuer.CommonName, commonName)
}