Skip to content

[WIP]Discussion: x.509 Certificates - deterministic handling and fingerprinting. #360

@tsellers-r7

Description

@tsellers-r7

[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:

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"
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions