}
// 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
StreetAddress, PostalCode []string
SerialNumber, CommonName string
- Names []AttributeTypeAndValue
+ Names []AttributeTypeAndValue
+ ExtraNames []AttributeTypeAndValue
}
func (n *Name) FillFromRDNSequence(rdns *RDNSequence) {
// 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
}
}
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.
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),
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)
}