Forum Discussion
William_Them_99
Nimbostratus
Jul 20, 2005Client Certificates at the Backend?
We have successfully configured the BIGIP device to require client certificates - it accepts the certs and passes the traffic through. Now, we need to be able to read and manipulate the client cert at the backend IIS web server via ASP/ASP.NET code.
I have configured IIS to require client certificates. If I visit the web server directly, it asks for the client cert, I choose the appropriate item, and the page loads and I am able to output (via ASP) the issuer and other attributes.
If I then go through the BIGIP to the backend web server, the BIGIP asks for the client cert, accepts it, and then I get a "Page cannot be displayed" error. If I then configure IIS to ignore client certificates, the error goes away and the page loads (albeit without displaying the issuer data on the page).
My guess is that the BIGIP is not pushing the client cert through to the backend. Is it possible to configure it to do so via iRules or some other method?
Thanks.
8 Replies
- drteeth_127330Historic F5 AccountPlease tell us something about your configuration. Since we are discussing client certificates, I assume that BIG-IP is performing SSL termination. Is this for offload purposes or is BIG-IP re-encrypting the traffic to the back-end servers? With SSL offload, the back-end traffic is unencrypted, so there really isn't a good way to offer a client cert to the back end. However, BIG-IP can be configured to perform the authorization itself. Additionally, the complete client certificate (or selected fields from it) can be included as custom HTTP headers. With re-encryption (also called SSL to server), the story changes somewhat. BIG-IP can offer a client certificate to the server. You can even choose which certificate to offer, but there is no good way to "push" the client's certificate through.
- William_Them_99
Nimbostratus
Oh ok, my mistake - so if we can put the whole cert in the header that could do the trick - do you have an example of that?
Also, to answer the config question - I have a client SSL profile and a server SSL profile set up and working... - rapmaster_c_127Historic F5 AccountTry this on a virtual server with an attached SSL and HTTP profile:
rule foo { when HTTP_REQUEST { if {[SSL::cert count] > 0} { HTTP::header replace SSLClientCert [b64encode [SSL::cert 0]] } } }
This BASE64-encodes the client certificate, if any, into an HTTP header called "SSLClientCert", replacing it if the client already has a header by that name. You'd need to BASE64-decode it on the back-end, and then you'd have the original certificate again.
Let us know if this works for you. - If there aren't builtin functions, I found this via Google.
http://www.freevbcode.com/ShowCode.asp?ID=5248 (Click here)' Functions to provide encoding/decoding of strings with Base64. ' ' Encoding: myEncodedString = base64_encode( inputString ) ' Decoding: myDecodedString = base64_decode( encodedInputString ) ' ' Programmed by Markus Hartsmar for ShameDesigns in 2002. ' Email me at: mark@shamedesigns.com ' Visit our website at: http://www.shamedesigns.com/ ' Dim Base64Chars Base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" & _ "abcdefghijklmnopqrstuvwxyz" & _ "0123456789" & _ "+/" ' Functions for encoding string to Base64 Public Function base64_encode( byVal strIn ) Dim c1, c2, c3, w1, w2, w3, w4, n, strOut For n = 1 To Len( strIn ) Step 3 c1 = Asc( Mid( strIn, n, 1 ) ) c2 = Asc( Mid( strIn, n + 1, 1 ) + Chr(0) ) c3 = Asc( Mid( strIn, n + 2, 1 ) + Chr(0) ) w1 = Int( c1 / 4 ) : w2 = ( c1 And 3 ) * 16 + Int( c2 / 16 ) If Len( strIn ) >= n + 1 Then w3 = ( c2 And 15 ) * 4 + Int( c3 / 64 ) Else w3 = -1 End If If Len( strIn ) >= n + 2 Then w4 = c3 And 63 Else w4 = -1 End If strOut = strOut + mimeencode( w1 ) + mimeencode( w2 ) + _ mimeencode( w3 ) + mimeencode( w4 ) Next base64_encode = strOut End Function Private Function mimeencode( byVal intIn ) If intIn >= 0 Then mimeencode = Mid( Base64Chars, intIn + 1, 1 ) Else mimeencode = "" End If End Function ' Function to decode string from Base64 Public Function base64_decode( byVal strIn ) Dim w1, w2, w3, w4, n, strOut For n = 1 To Len( strIn ) Step 4 w1 = mimedecode( Mid( strIn, n, 1 ) ) w2 = mimedecode( Mid( strIn, n + 1, 1 ) ) w3 = mimedecode( Mid( strIn, n + 2, 1 ) ) w4 = mimedecode( Mid( strIn, n + 3, 1 ) ) If w2 >= 0 Then _ strOut = strOut + _ Chr( ( ( w1 * 4 + Int( w2 / 16 ) ) And 255 ) ) If w3 >= 0 Then _ strOut = strOut + _ Chr( ( ( w2 * 16 + Int( w3 / 4 ) ) And 255 ) ) If w4 >= 0 Then _ strOut = strOut + _ Chr( ( ( w3 * 64 + w4 ) And 255 ) ) Next base64_decode = strOut End Function Private Function mimedecode( byVal strIn ) If Len( strIn ) = 0 Then mimedecode = -1 : Exit Function Else mimedecode = InStr( Base64Chars, strIn ) - 1 End If End Function
*Note, I haven't verified this works...
-Joe - KevinB_49644
Nimbostratus
This was a very helpful thread. My case is to do the same thing in java. I'm going to use the sun.misc.BASE64decoder to get the certificate. I do need to case the result to a X509Certificate[] object. The above just doesn't work. I get is as a byte[] but not a X509 object. I was thinking maybe X509::whole would work. How do I use that command. (ok, it's a newbie question).
HTTP::header replace SSLClientCert [b64encode [X509::whole $the_cert]]
Is this how it works? This creates an object in PEM format. My certs usually will have three levels. Would the PEM format load into the X509 java object. Maybe a sample java program would help me understand. - William_Them_99
Nimbostratus
I don't have an example in Java, as I wrote our code in ASP.NET, but I can show you what we did.
First, I used the iRule code mentioned in this post to put the cert in the header. Then I grabbed that value from the header with the code below:If Trim(Request.ServerVariables("HTTP_SSLCLIENTCERT")) <> "" Then CERTFROMHEADER.Value = Trim(Request.ServerVariables("HTTP_SSLCLIENTCERT")) ... End If
(Note that .NET prepends the "HTTP_" to all header variables)
As discussed in this post, the value in my CERTFROMHEADER variable is a base64 encoded string - otherwise known as PEM format for the certificate. The problem is that .NET only allows you to manipulate the cert in the DER format (at least with the version of the framework we are running). So, I had to use the Microsoft utility CERTUTIL.EXE to convert the PEM cert to a DER cert and then open it as a .NET object as shown below:'create a file name for the temporary storage of the certificate to disk and its converted form temp_file_name = "cert_PEM_" & Replace(Replace(DateTime.Now.TimeOfDay.ToString.Replace(".", "_"), ":", ""), " ", "") & ".cer" temp_output_file_name = "cert_DER_" & Replace(Replace(DateTime.Now.TimeOfDay.ToString.Replace(".", "_"), ":", ""), " ", "") & ".cer" file_save_result = SaveTextToFile(Trim(Request.Form.Item("CERTFROMHEADER")), temp_file_name) 'create a new process that runs the Cert utility to convert the cert to DER format CertConversion = System.Diagnostics.Process.Start(certConversionBatchPath, temp_file_name & " " & temp_output_file_name) 'wait until the process completes before continuing CertConversion.WaitForExit(1000) 'close the process CertConversion.Close() CertConversion.Dispose() CertConversion = Nothing 'using the created .cer file, load it as a certificate object cert = X509Certificates.X509Certificate.CreateFromCertFile(temp_output_file_name) 'delete the temporary .cer file and its converted form File.Delete(temp_file_name) File.Delete(temp_output_file_name)
------------------------------------------
Even in Java, you may be able to execute the Microsoft utility to get the proper certificate format. CERTUTIL.EXE is part of Windows 2003, but you can also just download the Windows Server 2003 Administration Tools Pack here:
http://www.microsoft.com/downloads/details.aspx?FamilyID=c16ae515-c8f4-47ef-a1e4-a8dcbacff8e3&DisplayLang=en
You can do many things with CERTUTIL. To convert from PEM to DER, as you can see in the code, all I did was run the executable with an input file (in PEM format), and an output file name, and that worked. For other possible uses, see:
http://technet2.microsoft.com/windowsserver/en/library/a3d5dbb9-1bf6-42da-a13b-2b220b11b6fe1033.mspx?mfr=true
I hope this helps.
-Bill - KevinB_49644
Nimbostratus
Here is the irule that I have working to get me the certificate information. It does pass it to Oracle in PEM format.
I will post my Java solution to dealing with this next
when CLIENTSSL_CLIENTCERT {
if { [SSL::verify_result] } {
log LOCAL0.warn "Client cert didn't verify, openssl code=[SSL::verify_result]"
reject
}
}
when HTTP_REQUEST {
if { [HTTP::header exists SSL_Client_Cert] } {
log LOCAL0.warn "removed inbound cert header - possible attack"
reject
}
if { [SSL::cert count] != 0 } {
set subject { }
lappend subject [X509::subject [SSL::cert 0]]
HTTP::header replace SSL_Client_Cert [X509::whole [SSL::cert 0]]
HTTP::header replace SSL_Client_Cert_Chain_1 [X509::whole [SSL::cert 1]]
}
} - tamins_90207Historic F5 AccountGreetings,
I need a rule to extract cert SN, issuer, and expiration date. when I enable this irule.
it's not only that nothing shows up in the header, but also I get page cannot be displayed after the client cert is presented.
when CLIENTSSL_CLIENTCERT {
set cert [SSL::cert 0]
set sn [X509::serial_number $cert]
set issuer [X509::issuer $cert]
set not_valid_before [X509::not_valid_before $cert]
}
when HTTP_REQUEST {
if { [matchclass [HTTP::uri] equals $::certURIs] } {
if { [SSL::cert count] < 1 } {
SSL::authenticate once
SSL::authenticate depth 9
SSL::cert mode request
SSL::renegotiate
} else {
HTTP::header insert ClientSSL_Serial_F5 $sn
HTTP::header insert ClientSSL_Issuer_F5 $issuer
HTTP::header insert ClientSSL_not_valid_before_F5 $not_valid_before
}
}
}
I have tried variations of the rule above, but with no luck.
any pointers would be greatly appreciated.
TIA
tsun
Recent Discussions
Related Content
DevCentral Quicklinks
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com
Discover DevCentral Connects
