0

We are upgrading the connection between ourselves and a partner, they require that we upgrade to MTLS. I've been debugging low level java,

javax.net.debug=all and I can see that the handshake is successful. However the partner, does a full string match against the Subject and Issuer field and compares with something fields in their database.

I've used the following,

   if (cert instanceof X509Certificate) {
        X509Certificate x509cert = (X509Certificate) cert;

        // Get subject
        Principal principal = x509cert.getSubjectDN();
        String subjectDn = principal.getName();
        logger.error(subjectDn);
        // Get issuer
        principal = x509cert.getIssuerDN();
        String issuerDn = principal.getName();
        logger.error(issuerDn);
    }

to dump a the values java has. An interesting note, openssl, reports them in a completely different order than java reports.

I've now been digging around in Wireshark and I can see the handshake from that level, however, it seems to translate the names to id-at-commonName, pkcs-9-at-emailAddress as nearly as I can tell.

Is there any way to know what is actually being sent?

dstarh
  • 4,586
  • 3
  • 27
  • 66
  • Possible duplicate of [How do I efficiently iterate over each entry in a Java Map?](https://stackoverflow.com/questions/46898/how-do-i-efficiently-iterate-over-each-entry-in-a-java-map) – Henry Henrinson Oct 03 '19 at 23:47

1 Answers1

2

There is no protocol MTLS, but it sounds like you are concerned with client authentication, also called mutual authentication, in TLS, which like server authentication normally uses X.509-type (more exactly, PKIX) certificates.

Background: X.509/PKIX certificates identify the Subject and Issuer (and sometimes other things/entities in some extensions) using the X.500/501 Distinguished Name structure also called X500Name, X501Name, or simply Name. This structure is defined in ASN.1 as a SEQUENCE (ordered) of RelativeDistinguishedName items, each of which is officially a SET (unordered) of pairs (SEQUENCE) of attribute type and value, although in practice the RDN SETs are almost always singletons, so Name is effectively a sequence of attribute type and value. This name format was designed to be used in a global, distributed, hierarchical network of 'directories', rather like DNS except (since CCITT-now-ITU-T is an organization of government agencies) rooted primarily in country-based national directories rather than functional or 'generic' ones like .com .org .edu .gov .mil .net, and X.509 certificates were designed as basically an export of data from that network of directories usable offline. In practice real X.500 directories aren't used at all, and even the prototcols for them like LDAP (Lightweight Directory Access Protocol) aren't used much except for Microsoft Windows 'domains' (Active Directory), but X.509 certs including the name format used in them are widely used in SSL-now-TLS, S/MIME, and many other applications.

The conventional textual or external form of a DN is a series of attr=value items, where the attr is commonly abbreviated, e.g. C for Country, ST for StateOrProvince, CN for CommonName, etc. Java uses the standardized form defined (with small changes/improvements) by RFCs 1485, 1779, 2253 and 4514 where the items are separated by commas and given in reverse order i.e. from last (lowest level) to first (highest level usually root), similar to DNS. For example Java displays the Subject of the cert currently used by www.duckduckgo.com as

CN=*.duckduckgo.com, O="Duck Duck Go, Inc.", L=Paoli, ST=Pennsylvania, C=US

OpenSSL traditionally used by default a format with slashes preceding each item (instead of commas separating them), and also going in forward order

/C=US/ST=Pennsylvania/L=Paoli/O=Duck Duck Go, Inc./CN=*.duckduckgo.com

but 1.1.0 up changed the default to use comma separators with forward order

C = US, ST = Pennsylvania, L = Paoli, O = "Duck Duck Go, Inc.", CN = *.duckduckgo.com 

Some OpenSSL commandline operations, like x509, support other display formats; see the man page under "Name Options". In particular x509 -nameopt oneline,dn_rev gives almost the same format as Java:

CN = *.duckduckgo.com, O = "Duck Duck Go, Inc.", L = Paoli, ST = Pennsylvania, C = US

Wireshark if you only look at the summary for a transmitted certificate (in TLS) displays the attribute=value pairs with full names instead of abbreviations for the attributes, in reverse order like the RFCs and Java:

Wireshark unexpanded display

but if you click on the plus-sign boxes to expand a few levels you can see the structure with each attribute item separately, in forward order:

Wireshark expanded display

Precisely because there are and have been numerous variations on the display format, it is not a good idea to compare DNs as strings. If you need to store it as a string in e.g. a database, the better way to is to rebuild the structured form from the string -- using consistent conventions as to order, abbreviations, etc. -- and compare the structured objects. This is made a little easier if you read the javadoc and see that X509Certificate.getIssuerDN() and similarly .getSubjectDN() are 'denigrated' (apparently intended to be 'deprecated') and superseded since Java 1.4 by .getIssuerX500Principal() and .getSubjectX500Principal() which use a documented API class (instead of an opaque internal class) javax.security.auth.x500.X500Principal with a documented .equals() operation.

dave_thompson_085
  • 24,048
  • 4
  • 34
  • 52
  • This is such a wonderfully thorough answer. As it turns out, we just got the issue solved because the remote system we were connecting to was terminating the tls connection at the load balancer, which then rewrote the subject and sent it to their back end system, which is where the order got changed. It's a wildly fragile system that we're not happy with but not much we can do about that. – dstarh Oct 04 '19 at 16:51