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- PeteWhiteEmployeeThat’s correct, regsub - - all should modify both of those. I’ll test it out later
- Stan_PIRON_F5Employee
: The regsub try to match the largest pattern...
The first match string is:
London, City of", L=Bar, O=Foo, OU=TEST, CN="F5lab
The second is
local"
So you have to force stoping at the first "... replace the .* with [^"]*
The problem with this expression is it will also match this string:
f", L=Bar, O=Foo, OU=TEST, CN="
This expression seems to work with your example:
% set subject [regsub -all {([a-zA-Z]+ ?= ?"[^"]+),([^"]+")} $subject "\\1--COMMA--\\2"]
C=GB, ST="London--COMMA-- City of", L=Bar, O=Foo, OU=TEST, CN="F5lab--COMMA-- local"
- uniqngAltostratus
OK I understand now, the regsub -all is greedy so it matches as much as it can.
Thanks again both of you for your help with that. All is good now
- PeteWhiteEmployee
Updated to work better with commas and made less greedy with the use of ? in the regsub regex
- Stanislas_Piro2Cumulonimbus
Hi , I had the same requirement and it seems the change is the following:
<= TMOS v12 is CN=LASTNAME\, FIRSTNAME,OU=CONTRACTOR,OU=PKI,OU=DEPT,O=COMPANY,C=US
>= TMOS v13 is C=US, O=COMPANY, OU=DEPT, OU=PKI, OU=CONTRACTOR, CN="LASTNAME, FIRSTNAME"
So differences are:
- Reverse Ordered elements (full reverse may be better than defining the order in the irule)
- space after comma separator
- double quotes around fields with special characters (like comma)
- unescaped special character between double quotes
I wrote following procs to manage conversion from v12 to v13 and from v13 to v12 :
proc subject_v13_to_v12 {subject_openssl} { # Create the empty subject set new_subject "" # For each subject element, do the following actions: # - remove double quotes arround the value # - escape the comma character # - remove space around comma separator # Insert the value at the begining of the subject (to reverse order) foreach {type value} [ split [regsub -all {(".*?),(.*?")} $subject_openssl "\\1--COMMA--\\2"] ",=" ] { set new_subject "{[string trim $type]=[string trim [string map {"--COMMA--" "\\," "+" "\\+" "\\" "\\\\" "<" "\\<" ">" "\\>" ";" "\\;" } [string trim $value {"}]]]} $new_subject" } # Return the joined values with comma return [join $new_subject ","] }
proc subject_v12_to_v13 {subject_rfc2253} { # Create the empty subject set new_subject "" # For each subject element, do the following actions: # - add double quotes arround the value # - unescape the comma character # - Add space around comma separator # Insert the value at the begining of the subject (to reverse order) foreach {type value} [ split [string map {"\\," "--COMMA--"} $subject_rfc2253] ",=" ] { set new_subject "{[string trim $type]=[expr {[string match "*--COMMA--*" $value] ? "\"[string trim [string map {"--COMMA--" ","} $value]]\"" : [string trim $value] }]} $new_subject" } # Return the joined values with comma and space return [join $new_subject ", "] }
I got the following results:
subject_v12_to_v13 {CN=F5lab\, local,OU=TEST,O=Foo,L=Bar,ST=London\, City of,C=GB} C=GB, ST="London, City of", L=Bar, O=Foo, OU=TEST, CN="F5lab, local" % subject_v13_to_v12 {C=GB, ST="London, City of", L=Bar, O=Foo, OU=TEST, CN="F5lab, local"} CN=F5lab\, local,OU=TEST,O=Foo,L=Bar,ST=London\, City of,C=GB