-
Notifications
You must be signed in to change notification settings - Fork 211
Description
[WIP] Issue
Summary
This issue is intended to serve as a point of discussion related to the effort to standardize our handling of the distinguished name values found in x.509 certificate subject
and issuer
fields. The intent is to arrive at a field ordering that is
- portable across programming languages (at least Java, Python, and Go)
- deterministic even when processing unknown fields
Commentary from HD about handling in Go:
Lines 4 to 38 in 94c2576
This fingerprint set matches the Subject field of x509 certificates. These x509 | |
certificates may be sourced from any SSL or TLS service. If a particular system | |
has identical subject and issuer fields, the subject field should be preferred. | |
The format of the Subject field is built from the x509 distinguished names using | |
a specific order. This order matches the Go implementation at the URL: | |
https://golang.org/src/crypto/x509/pkix/pkix.go#203 | |
The ToRDNSequence() function builds the string in reverse order: | |
func (n Name) ToRDNSequence() (ret RDNSequence) { | |
ret = n.appendRDNs(ret, n.Country, oidCountry) | |
ret = n.appendRDNs(ret, n.Province, oidProvince) | |
ret = n.appendRDNs(ret, n.Locality, oidLocality) | |
ret = n.appendRDNs(ret, n.StreetAddress, oidStreetAddress) | |
ret = n.appendRDNs(ret, n.PostalCode, oidPostalCode) | |
ret = n.appendRDNs(ret, n.Organization, oidOrganization) | |
ret = n.appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit) | |
if len(n.CommonName) > 0 { | |
ret = n.appendRDNs(ret, []string{n.CommonName}, oidCommonName) | |
} | |
if len(n.SerialNumber) > 0 { | |
ret = n.appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber) | |
} | |
for _, atv := range n.ExtraNames { | |
ret = append(ret, []AttributeTypeAndValue{atv}) | |
} | |
return ret | |
} | |
All names are separated by commas and any commas inside a name are escaped with a | |
single backslash character. See RFC 2253 for additional details on formatting. | |
Practically, most Subjects start with the Common Name (CN=) and then step through | |
Organization Unit (OU), Organization (O), and then some level of location, but | |
typically Locality (L) and Country (C). Names are guaranteed to be listed in | |
the order described above, but may start at any point in the list. For example, | |
Subjects may start with a Serial Number (SERIALNUMBER=) or even Extra Names, but | |
these are somewhat rare. Keep this name order in mind when working on these | |
fingerprints. |
Commentary and example from HD on handling of extra fields in Go:
The relevant Go code for extra name handling:
oidString := tv.Type.String() typeName, ok := attributeTypeNames[oidString] if !ok { derBytes, err := asn1.Marshal(tv.Value) if err == nil { s += oidString + "=#" + hex.EncodeToString(derBytes) continue // No value escaping necessary. } typeName = oidString }
In practice this looks like:
CN=device.corp.com,OU=VMware Engineering,O=VMware,L=Palo Alto,ST=California,C=US,1.2.840.113549.1.9.1=#0c0f766d636140766d776172652e636f6d
1.2.840.113549.1.9.1 is the OID of the EMAILADDRESS attribute. The value includes the DER bytes, including the Type and Length before the value ([email protected]).
TODO before requesting feedback from others:
- Build simple Python, Ruby, Go, and Rust tools that connect to an HTTP endpoint and emit the certificate with the least amount of processing
- Use the tools above to provide reference examples to show the differences
Examples
Some example subject values that haven't been accounted for in our prior discussions.
unstructuredName
{
"C": "US",
"CN": "foo.bar",
"L": "Palo Alto",
"O": "VMware, Inc",
"OU": "VMware ESX Server Default Certificate",
"ST": "California",
"emailAddress": "[email protected]",
"unstructuredName": "1617207215,564d7761726520496e632e"
}
businessCategory
, jurisdictionC
, jurisdictionL
, jurisdictionST
{
"C": "DE",
"CN": "foo.bar",
"L": "Hannover",
"O": "TUI AG",
"ST": "Niedersachsen",
"businessCategory": "Private Organization",
"jurisdictionC": "DE",
"jurisdictionL": "Charlottenburg",
"jurisdictionST": "Berlin",
"serialNumber": "HRB 000"
}
name
{
"name": "AR2220-Self-Signed-Certificate-2102352934DMGA000458"
}
description
{
"CN": "00:09:52:05:b9:73",
"O": "Auerswald",
"description": "Vendor=Auerswald;SN=0000000000;MAC=00:00:00:00:00:00;DevClass=PBX;DevTyp=COMpact5200"
}`
From Microsoft Active Directory, DC
{
"CN": "foo.bar.local",
"DC": "va",
"OU": "devices"
}