For more information regarding the security incident at F5, the actions we are taking to address it, and our ongoing efforts to protect our customers, click here.

X509 Subject Formatting

Problem this snippet solves:

TMOS v12.1.4.1 and v13 have a change where the output of X509::subject is formatted to match OpenSSL output. See https://cdn.f5.com/product/bugtracker/ID607410.html


<= TMOS v12 is CN=USERNAME,OU=CONTRACTOR,OU=PKI,OU=DEPT,O=COMPANY,C=US

>= TMOS v13 is C=US,O=COMPANY,OU=DEPT,OU=PKI,OU=CONTRACTOR,CN=USERNAME

How to use this snippet:

This procedure will change the output format to either v12 or v13 ( or you can easily modify it to create your own output ). Default output is v12.


Use v13 output:

set serialNumber [ call formatSubject [ X509::subject [SSL::cert 0] ] 13 ]


Use v12 output:

set serialNumber [ call formatSubject [ X509::subject [SSL::cert 0] ] ]


Code :

proc formatSubject { subject { f 12 }} {
    # subject is the subject string eg CN=USERNAME,OU=CONTRACTOR,OU=PKI,OU=DEPT,O=COMPANY,C=US
    # f is format version and is either 12 or 13. Default 12
    # This procedure formats the subject field according to TMOS v12 or v13 format
    # v12 is CN=USERNAME,OU=CONTRACTOR,OU=PKI,OU=DEPT,O=COMPANY,C=US
    # v13 is C=US,O=COMPANY,OU=DEPT,OU=PKI,OU=CONTRACTOR,CN=USERNAME
    # See https://cdn.f5.com/product/bugtracker/ID607410.html
    # dn is an array with format [ CN O { OU } CN ]

    array set dn {
        OU {}
    } 
    set subject [regsub -all {(".*?),(.*?")} $subject "\\1--COMMA--\\2"]
    
    foreach i [ split $subject , ] {
        set j [ split [ string trim $i] = ]
        if { [lindex $j 0] == "OU" } {
            lappend dn(OU) [lindex $j 1]
        } else {
            array set dn [ list [lindex $j 0] [lindex $j 1] ]
        }
    }
    # Loop through OUs and create a string
    set ouString ""
    foreach ou $dn(OU) {
        append ouString "OU=$ou, "
    }
																		
    if { $f == 12 } {
        set order { CN OU O C }
    } else {
        set order { C O OU CN }
    }
							  
    set returnString ""
    foreach a $order {
        if { [info exists dn($a)] } {
            if { $a == "OU" } { 
                append returnString $ouString 
            } else {
                append returnString "$a=$dn($a), "
            }
        }
    }
    set returnString [string map {"--COMMA--" ","} $returnString]
    return [ string trimright $returnString ", " ]
}

Tested this on version:

13.0
Published Oct 18, 2019
Version 1.0

15 Comments

  •  to prevent this issue, you can replace lines 13 to 20 with:

    array set dn [list]
    foreach {key val} [ split [string map {"\\," "\\," "," "|" "\\=" "\\=" "=" "|"} $subject] "|"] {
        lappend dn([string trim $key]) [string trim $val]
    }
  • uniqng this splits the DN on the comma so if there is an unexpected comma then it will break. If you have complex, specific requirements then I suggest you decode the field using the ASN1 commands

  • How is this proc going to behave in case the ','character is part of the CN or any other sub-string?