ssl
12 TopicsGenerate private key w/ CSR via iControl REST
Problem this snippet solves: Generate a private key w/ CSR How to use this snippet: To create a private key with a CSR via iControl REST: POST URL:https://10.1.1.165/mgmt/tm/sys/crypto/key Use the data below as your payload. For the name field, it must end in .key or you will get a false 404! Code : { "name":"www.testing.com.key", "commonName":"www.testing.com", "keySize":"4096", "keyType":"rsa-private", "options":[{"gen-csr":"www.testing.com"}], "organization":"Let It Snow Corp.", "ou":"Ice Engineering", "city":"Calhoun", "state":"AZ", "admin-email-address":"jerry@letit.snow", "email-address":"beth@letit.snow", "subject-alternative-name":"DNS:www.testing.com", "challenge-password":"myP4ssword" } Tested this on version: 13.01.9KViews3likes11CommentsTLS server_name extension based routing without clientssl profile
Problem this snippet solves: Some configuration requires to not decrypt SSL traffic on F5 appliances to select pool based on HTTP Host header. I found a useful irule and this code keeps the structure and most of binary commands of it. I'm not sure if the first author was Kevin Stewart or Colin Walker. thanks both of them to have provided such code. I worked to understand it reading TLS 1.2 RFC 5246 and TLS 1.3 draft-23 and provided some enhancements and following description with irule variables references. According to TLS 1.3 draft-23, this code will still be valid with next TLS version. the following network diagram shows one use cases where this code will help. This diagram show how this code works based on the tls_servername_routing_dg Datagroup values and detected server name and TLS versions detected in the CLIENT_HELLO packet. For performances reasons, only the first TCP data packet is analyzed. Versions : 1.1 : Updated to support TLS version detection and SSL offload feature. (05/03/2018) 1.2 : Updated to support TLS Handshake Failure Messages instead of reject. (09/03/2018) 1.3 : Updated to support node forwarding, logs only for debug (disabled with static variable), and changed the Datagroup name to tls_servername_routing_dg . (16/03/2018) 1.4 : Added 16K handshake length limit defined in RFC 1.2 in variable payload. (13/04/2018) 1.5 : Added supported version extension recursion, to bypass unknown TLS version if a known and allowed version is in the list. This correct an issue with Google chrome which include not documented TLS version on top of the list. (30/04/2018) How to use this snippet: create a virtual server with following configuration: type : Standard SSL Profile (client) : Only if you want to enable SSL offload for some pools irule : code bellow create all objects used in following datagroup (virtual servers, pools) create a data-group named tls_servername_routing_dg. if you want to forward to pool, add the value pool NameOfPool if you want to forward to pool and enable SSL Offload (ClientSSL profile must be enabled on virtual server), add the value pool NameOfPool ssl_offload if you want to forward to virtual server, add the value virtual NameOfVirtual if you want to forward to an IP address, add the value node IPOfServer , backend server will not be translated if you want to reject the connection with RFC compliant handshake_failure message, add the value handshake_failure if you want to reject the connection, add the value reject if you want to drop the connection, add the value drop The default value keyword is search if there is no TLS server name extension or if TLS server name extension is not found in the data group. here is an example: ltm data-group internal tls_servername_routing_dg { records { app1.company.com { data "virtual vs_app1.company.com" } app2.company.com { data "pool p_app2" } app3.company.com { data "pool p_app3 ssl_offload" } app4.company.com { reject } default { data "handshake_failure" } } type string } Code : when RULE_INIT { set static::sni_routing_debug 0 } when CLIENT_ACCEPTED { if { [PROFILE::exists clientssl] } { # We have a clientssl profile attached to this VIP but we need # to find an SNI record in the client handshake. To do so, we'll # disable SSL processing and collect the initial TCP payload. set ssldisable "SSL::disable" set sslenable "SSL::enable" eval $ssldisable } TCP::collect set default_pool [LB::server pool] set tls_servername "" set tls_handshake_prefered_version "0000" } when CLIENT_DATA { # Store TCP Payload up to 2^14 + 5 bytes (Handshake length is up to 2^14) set payload [TCP::payload 16389] set payloadlen [TCP::payload length] # - Record layer content-type (1 byte) --> variable tls_record_content_type # Handshake value is 22 (required for CLIENT_HELLO packet) # - SSLv3 / TLS version. (2 byte) --> variable tls_version # SSLv3 value is 0x0300 (doesn't support SNI, not valid in first condition) # TLS_1.0 value is 0x0301 # TLS_1.1 value is 0x0302, 0x0301 in CLIENT_HELLO handskake packet for backward compatibility (not specified in RFC, that's why the value 0x0302 is allowed in condition) # TLS_1.2 value is 0x0303, 0x0301 in CLIENT_HELLO handskake packet for backward compatibility (not specified in RFC, that's why the value 0x0303 is allowed in condition) # TLS_1.3 value is 0x0304, 0x0301 in CLIENT_HELLO handskake packet for backward compatibility (explicitly specified in RFC) # TLS_1.3 drafts values are 0x7FXX (XX is the hexadecimal encoded draft version), 0x0301 in CLIENT_HELLO handskake packet for backward compatibility (explicitly specified in RFC) # - Record layer content length (2 bytes) : must match payload length --> variable tls_recordlen # - TLS Hanshake protocol (length defined by Record layer content length value) # - Handshake action (1 byte) : CLIENT_HELLO = 1 --> variable tls_handshake_action # - handshake length (3 bytes) # - SSL / TLS handshake version (2 byte) # In TLS 1.3 CLIENT_HELLO handskake packet, TLS hanshake version is sent whith 0303 (TLS 1.2) version for backward compatibility. a new TLS extension add version negociation. # - hanshake random (32 bytes) # - handshake sessionID length (1 byte) --> variable tls_handshake_sessidlen # - handshake sessionID (length defined by sessionID length value, max 32-bit) # - CipherSuites length (2 bytes) --> variable tls_ciphlen # - CipherSuites (length defined by CipherSuites length value) # - Compression length (2 bytes) --> variable tls_complen # - Compression methods (length defined by Compression length value) # - Extensions # - Extension length (2 bytes) --> variable tls_extension_length # - list of Extensions records (length defined by extension length value) # - extension record type (2 bytes) : server_name = 0, supported_versions = 43--> variable tls_extension_type # - extension record length (2 bytes) --> variable tls_extension_record_length # - extension data (length defined by extension record length value) # # TLS server_name extension data format: # - SNI record length (2 bytes) # - SNI record data (length defined by SNI record length value) # - SNI record type (1 byte) # - SNI record value length (2 bytes) # - SNI record value (length defined by SNI record value length value) --> variable tls_servername # # TLS supported_version extension data format (added in TLS 1.3): # - supported version length (1 bytes) --> variable tls_supported_versions_length # - List of supported versions (2 bytes per version) --> variable tls_supported_versions # If valid TLS 1.X CLIENT_HELLO handshake packet if { [binary scan $payload cH4Scx3H4x32c tls_record_content_type tls_version tls_recordlen tls_handshake_action tls_handshake_version tls_handshake_sessidlen] == 6 && \ ($tls_record_content_type == 22) && \ ([string match {030[1-3]} $tls_version]) && \ ($tls_handshake_action == 1) && \ ($payloadlen == $tls_recordlen+5)} { # store in a variable the handshake version set tls_handshake_prefered_version $tls_handshake_version # skip past the session id set record_offset [expr {44 + $tls_handshake_sessidlen}] # skip past the cipher list binary scan $payload @${record_offset}S tls_ciphlen set record_offset [expr {$record_offset + 2 + $tls_ciphlen}] # skip past the compression list binary scan $payload @${record_offset}c tls_complen set record_offset [expr {$record_offset + 1 + $tls_complen}] # check for the existence of ssl extensions if { ($payloadlen > $record_offset) } { # skip to the start of the first extension binary scan $payload @${record_offset}S tls_extension_length set record_offset [expr {$record_offset + 2}] # Check if extension length + offset equals payload length if {$record_offset + $tls_extension_length == $payloadlen} { # for each extension while { $record_offset < $payloadlen } { binary scan $payload @${record_offset}SS tls_extension_type tls_extension_record_length if { $tls_extension_type == 0 } { # if it's a servername extension read the servername # SNI record value start after extension type (2 bytes), extension record length (2 bytes), record type (2 bytes), record type (1 byte), record value length (2 bytes) = 9 bytes binary scan $payload @[expr {$record_offset + 9}]A[expr {$tls_extension_record_length - 5}] tls_servername set record_offset [expr {$record_offset + $tls_extension_record_length + 4}] } elseif { $tls_extension_type == 43 } { # if it's a supported_version extension (starting with TLS 1.3), extract supported version in a list binary scan $payload @[expr {${record_offset} + 4}]cS[expr {($tls_extension_record_length -1)/2}] tls_supported_versions_length tls_supported_versions set tls_handshake_prefered_version [list] foreach version $tls_supported_versions { lappend tls_handshake_prefered_version [format %04X [expr { $version & 0xffff }] ] } if {$static::sni_routing_debug} {log local0. "[IP::remote_addr] : prefered version list : $tls_handshake_prefered_version"} set record_offset [expr {$record_offset + $tls_extension_record_length + 4}] } else { # skip over other extensions set record_offset [expr {$record_offset + $tls_extension_record_length + 4}] } } } } } elseif { [binary scan $payload cH4 ssl_record_content_type ssl_version] == 2 && \ ($tls_record_content_type == 22) && \ ($tls_version == 0300)} { # SSLv3 detected set tls_handshake_prefered_version "0300" } elseif { [binary scan $payload H2x1H2 ssl_version handshake_protocol_message] == 2 && \ ($ssl_version == 80) && \ ($handshake_protocol_message == 01)} { # SSLv2 detected set tls_handshake_prefered_version "0200" } unset -nocomplain payload payloadlen tls_record_content_type tls_recordlen tls_handshake_action tls_handshake_sessidlen record_offset tls_ciphlen tls_complen tls_extension_length tls_extension_type tls_extension_record_length tls_supported_versions_length tls_supported_versions foreach version $tls_handshake_prefered_version { switch -glob -- $version { "0200" { if {$static::sni_routing_debug} {log local0. "[IP::remote_addr] : SSLv2 ; connection is rejected"} reject return } "0300" - "0301" { if {$static::sni_routing_debug} {log local0. "[IP::remote_addr] : SSL/TLS ; connection is rejected (0x$version)"} # Handshake Failure packet format: # # - Record layer content-type (1 byte) --> variable tls_record_content_type # Alert value is 21 (required for Handshake Failure packet) # - SSLv3 / TLS version. (2 bytes) --> from variable tls_version # - Record layer content length (2 bytes) : value is 2 for Alert message # - TLS Message (length defined by Record layer content length value) # - Level (1 byte) : value is 2 (fatal) # - Description (1 bytes) : value is 40 (Handshake Failure) TCP::respond [binary format cH4Scc 21 $tls_version 2 2 40] after 10 TCP::close #drop #reject return } "030[2-9]" - "7F[0-9A-F][0-9A-F]" { # TLS version allowed, do nothing break } "0000" { if {$static::sni_routing_debug} {log local0. "[IP::remote_addr] : No SSL/TLS protocol detected ; connection is rejected (0x$version)"} reject return } default { if {$static::sni_routing_debug} {log local0. "[IP::remote_addr] : Unknown CLIENT_HELLO TLS handshake prefered version : 0x$version"} } } } if { $tls_servername equals "" || ([set sni_dg_value [class match -value [string tolower $tls_servername] equals tls_servername_routing_dg]] equals "")} { set sni_dg_value [class match -value "default" equals tls_servername_routing_dg] } switch [lindex $sni_dg_value 0] { "virtual" { if {[catch {virtual [lindex $sni_dg_value 1]}]} { if {$static::sni_routing_debug} {log local0. "[IP::remote_addr] : TLS server_name value = ${tls_servername} ; TLS prefered version = 0x${tls_handshake_prefered_version} ; Virtual server [lindex $sni_dg_value 1] doesn't exist"} } else { if {$static::sni_routing_debug} {log local0. "[IP::remote_addr] : TLS server_name value = ${tls_servername} ; TLS prefered version = 0x${tls_handshake_prefered_version} ; forwarded to Virtual server [lindex $sni_dg_value 1]"} } } "pool" { if {[catch {pool [lindex $sni_dg_value 1]}]} { if {$static::sni_routing_debug} {log local0. "[IP::remote_addr] : TLS server_name value = ${tls_servername} ; TLS prefered version = 0x${tls_handshake_prefered_version} ; Pool [lindex $sni_dg_value 1] doesn't exist"} } else { if {$static::sni_routing_debug} {log local0. "[IP::remote_addr] : TLS server_name value = ${tls_servername} ; TLS prefered version = 0x${tls_handshake_prefered_version} ; forwarded to Pool [lindex $sni_dg_value 1]"} } if {[lindex $sni_dg_value 2] equals "ssl_offload" && [info exists sslenable]} { eval $sslenable } } "node" { if {[catch {node [lindex $sni_dg_value 1]}]} { if {$static::sni_routing_debug} {log local0. "[IP::remote_addr] : TLS server_name value = ${tls_servername} ; TLS prefered version = 0x${tls_handshake_prefered_version} ; Invalid Node value [lindex $sni_dg_value 1]"} } else { if {$static::sni_routing_debug} {log local0. "[IP::remote_addr] : TLS server_name value = ${tls_servername} ; TLS prefered version = 0x${tls_handshake_prefered_version} ; forwarded to Node [lindex $sni_dg_value 1]"} } } "handshake_failure" { if {$static::sni_routing_debug} {log local0. "[IP::remote_addr] : TLS server_name value = ${tls_servername} ; TLS prefered version = 0x${tls_handshake_prefered_version} ; connection is rejected (with Handshake Failure message)"} TCP::respond [binary format cH4Scc 21 $tls_handshake_prefered_version 2 2 40] after 10 TCP::close return } "reject" { if {$static::sni_routing_debug} {log local0. "[IP::remote_addr] : TLS server_name value = ${tls_servername} ; TLS prefered version = 0x${tls_handshake_prefered_version} ; connection is rejected"} reject return } "drop" { if {$static::sni_routing_debug} {log local0. "[IP::remote_addr] : TLS server_name value = ${tls_servername} ; TLS prefered version = 0x${tls_handshake_prefered_version} ; connection is dropped"} drop return } } TCP::release }3.6KViews6likes10CommentsPowerShell - Get a list of Used and Unused SSL files (based on SSL profile usage)
Problem this snippet solves: There are many times where being able to determine which SSL files on the BIG-IP are or are not being used would be very beneficial (especially when trying to do some spring cleaning or old configurations). So this script aims to provide a simple way to use PowerShell and iControlRest to determine which SSL (cert and key) files are or are not being used in any SSL profiles (client or server). How to use this snippet: Prerequisites: You will need to be on BIG-IP v11.4 or newer, as that's when iControlRest was introduced. You will also need a Windows machine and PowerShell v3 or newer (v4 or v5). Paste this code into your PowerShell console and then run it with at least the hostname (or IP) of your BIG-IP, and it will prompt you for credentials and return the list of used and unused ssl cert and key files. Note: If you use an IP address, you should really include the -IgnoreCertErrors flag as well, since it won't work by default without a valid cert. Examples: Get-F5SslCertKeyFilesByStatus mybigip.example.com; Get-F5SslCertKeyFilesByStatus 10.10.10.10 -IgnoreCertErrors; Get-F5SslCertKeyFilesByStatus -f5HostIp mybigip.example.com; Get-F5SslCertKeyFilesByStatus -f5HostIp 10.10.10.10 -IgnoreCertErrors; $cred = (Get-Credentials); Get-F5SslCertKeyFilesByStatus -f5HostIp 10.10.10.10 -f5Cred $cred -IgnoreCertErrors; Code : function Get-F5SslCertKeyFilesByStatus { [CmdletBinding()] Param($f5HostIp, $f5Cred, [switch]$IgnoreCertErrors = $false) Begin { Write-Verbose "Get-F5SslCertKeyFilesByStatus"; if ($IgnoreCertErrors) { Write-Verbose " Ignoring certficate errors"; Add-Type @" using System.Net; using System.Security.Cryptography.X509Certificates; public class TrustAllCertsPolicy : ICertificatePolicy { public bool CheckValidationResult( ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) { return true; } } "@; [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy; } function Invoke-F5Rest ($path) { $url = "https://$($f5HostIp)/mgmt/tm$path"; Write-Verbose " GET: '$url'"; $ret = @($(Invoke-RESTMethod -Method GET -Uri $url -Credential $f5Cred -Verbose:$false).items); Write-Verbose " Returned $($ret.Count) items"; $ret; } } Process { # Grab all the stuff we'll need from the BIG-IP Write-Verbose " Grabbing data from BIG-IP"; $clientSslProfiles = Invoke-F5Rest '/ltm/profile/client-ssl?$select=name,fullPath,caFile,cert,chain,clientCertCa,key,proxyCaCert,proxyCaKey,certKeyChain'; $serverSslProfiles = Invoke-F5Rest '/ltm/profile/server-ssl?$select=name,fullPath,caFile,cert,chain,key'; $certFiles = Invoke-F5Rest '/sys/crypto/cert'; $keyFiles = Invoke-F5Rest '/sys/crypto/key'; $crlFiles = Invoke-F5Rest '/sys/crypto/crl'; # Process the data Write-Verbose " Processing the returned data"; $usedCerts = @(($clientSslProfiles | %{ @($_.caFile, $_.cert, $_.chain, $_.clientCertCa, $_.proxyCaCert) + $($_.certKeyChain | %{ $_.cert, $_.chain; }) }) ` + ($serverSslProfiles | %{ @($_.cert, $_.caFile, $_.chain) } ) ` | Select-Object -Unique); Write-Verbose " Used certs: $($usedCerts.Count)"; $usedKeys = @(($clientSslProfiles | %{ @($_.key, $_.proxyCaKey) + $($_.certKeyChain | %{ $_.key }) }) ` + ($serverSslProfiles | %{ $_.key }) ` | Select-Object -Unique); Write-Verbose " Used keys: $($usedCerts.Count)"; $usedCertFiles = $certFiles | ?{ $usedCerts -contains $_.fullPath } | Select-Object -ExpandProperty fullPath; $unusedCertFiles = $certFiles | ?{ $usedCerts -notcontains $_.fullPath } | Select-Object -ExpandProperty fullPath; $usedKeyFiles = $keyFiles | ?{ $usedKeys -contains $_.fullPath } | Select-Object -ExpandProperty fullPath; $unusedKeyFiles = $keyFiles | ?{ $usedKeys -notcontains $_.fullPath } | Select-Object -ExpandProperty fullPath; # Return lists [PSCustomObject]@{ Unused = [PSCustomObject]@{ CertFiles = $unusedCertFiles; KeyFiles = $unusedKeyFiles; }; Used = [PSCustomObject]@{ CertFiles = $usedCertFiles; KeyFiles = $usedKeyFiles; }; }; } } Tested this on version: 11.5848Views0likes7CommentsTourniquet iRule to detect, BLOCK, log, and count CVE-2016-9244 "Ticketbleed" attacks
Problem this snippet solves: This iApp installs the Tourniquet iRule ir-tourniquet which will detect, block, log, and count attempts to exploit CVE-2016-9244 "Ticketbleed". Attach the Tourniquet iRule to any TCP+TLS or UDP+DTLS virtual server with a Client SSL Profile. (The iRule works on BIG-IP TMOS v11.0 and above.) The Tourniquet iRule logs the source IP address and geolocation of each possible attack and counts attacks (per-virtual-server) using iStats. The Tourniquet iRule is for anyone (such as a honeypot operator) who wants to log the sources of Ticketbleed attacks and for BIG-IP users who want to utilize RFC-5077 TLS Session Tickets while still running vulnerable (older) versions of BIG-IP TMOS (by blocking Ticketbleed attacks, the Tourniquet iRule makes it safe to enable Session Tickets). NOTE: The best way to avoid the CVE-2016-9244 Ticketbleed vulnerability is to upgrade BIG-IP TMOS to a non-vulnerable version. See F5 Solution Note K05121675. The second-best way (imposing a modest performance cost) is to disable Session Tickets in your Client SSL Profile(s). The performance cost of the Tourniquet iRule is very small unless an attacker tries to flood your BIG-IP with Ticketbleed attacks. In that case, the Tourniquet iRule will at least help you track the attacker down. The Tourniquet iRule blocks Ticketbleed attacks on vulnerable versions of BIG-IP TMOS. It also has an option to log Ticketbleed attacks then allow them to proceed, if you really want to do that. How to use this snippet: Download the Tourniquet-iRule-v1.zip file (below). Extract (unzip) the Tourniquet-iRule-v1.tmpl file. In the BIG-IP Management GUI, navigate to iApps / Templates. Click Import, browse to select the template file, then click Upload. Navigate to iApps / Application Services. Click Create, then enter a unique name (for example, t ) and select the template Tourniquet_iRule . Click Finished. The Tourniquet iRule ir-tourniquet will be created (in an Application folder, for example as /Common/t.app/ir-tourniquet ). You may then navigate to Local Traffic / Virtual Servers, edit your virtual servers that have Client SSL Profiles, and add the Tourniquet iRule to each virtual server in the iRules section of the Resources tab. (If you really want to allow Ticketbleed attacks for some reason (making your BIG-IP insecure!), you can change the relevant setting in the iApp then click Finished to update the iRule.) Code : 73863277Views0likes0CommentsGet all certificates and their virtual servers and SSL profiles via API calls
Problem this snippet solves: Summary F5 will give you a decent report of all your certificates and their expiration dates. However I have not found a way to pull what Virtual Server or SSL Profile the certificates are applied to (or if they are used at all). What this code does is grabs all the virtual servers, all SSL profiles, and all certificates. Then it loops through them to find where a certificate is applied. Then it returns the certificate and virtual server info. I wrote this in C# but the logic can be used anywhere as the API calls are independent of language. How to use this snippet: You will need some way to compile C#. Easiest way is to use Visual Studio. Simply add your API credentials and IP addresses and run the code through a C# compiler. Code : https://github.com/matthewwedlow/F5_Scripts/blob/master/GetCerts.cs2.3KViews1like3CommentsDecrypting tcpdumps in Wireshark without key files (such as when FIPS is in use)
Problem this snippet solves: This procedure allows you to decrypt a tcpdump made on the F5 without requiring access to the key file. Despite multiple F5 pages that claim to document this procedure, none of them worked for me. This solution includes the one working iRule I found, trimmed down to the essentials. The bash command is my own, which generates a file with all the required elements from the LTM log lines generated by the iRule, needed to decrypt the tcpdump in Wireshark 3.x. How to use this snippet: Upgrade Wireshark to Version 3+. Apply this iRule to the virtual server targeted by the tcpdump: rule sessionsecret { when CLIENTSSL_HANDSHAKE { log local0.debug "CLIENT_RANDOM [SSL::clientrandom] [SSL::sessionsecret]" log local0.debug "RSA Session-ID:[SSL::sessionid] Master-Key:[SSL::sessionsecret]" } when SERVERSSL_HANDSHAKE { log local0.debug "CLIENT_RANDOM [SSL::clientrandom] [SSL::sessionsecret]" log local0.debug "RSA Session-ID:[SSL::sessionid] Master-Key:[SSL::sessionsecret]" } } Run tcpdump on the F5 using all required hooks to grab both client and server traffic. tcpdump -vvni 0.0:nnnp -s0 host <ip> -w /var/tmp/`date +%F-%H%M`.pcap Conduct tests to reproduce the problem, then stop the tcpdump (Control C)and remove the iRule from the virtual server. Collect the log lines into a file. cat /var/log/ltm | grep -oe "RSA Session.*$" -e "CLIENT_RANDOM.*$" > /var/tmp/pms Copy the .pcap and pms files to the computer running Wireshark 3+. Reference the "pms" file in "Wireshark > Preferences > Protocols > TLS > (Pre)-Master-Secret log filename" (hence the pms file name). Ensure that Wireshark > Analyze > Enabled Protocols > "F5 Ethernet trailer" and "f5ethtrailer" boxes are checked. Open the PCAP file in Wireshark; it will be decrypted. IMPORTANT TIP: Decrypting any large tcpdump brings a workstation to its knees, even to the point of running out of memory. A much better approach is to temporarily move the pms file, open the tcpdump in its default encrypted state, identify the problem areas using filters or F5 TCP conversation and export them to a much smaller file. Then you can move the pms file back to the expected location and decrypt the smaller file quickly and without significant impact on the CPU and memory. Code : Please refer to the "How to use this Code Snippet" section above. This procedure was successfully tested in 12.1.2 with a full-proxy virtual server. Tested this on version: 12.11.9KViews8likes8CommentsCategorize SSL traffic by version, display as graph
Problem this snippet solves: You want to know how much SSLv3 traffic is hitting your site. Example image when going to https://x.x.x.x/sslversions: How to use this snippet: Attach this iRule to your virtual server that is terminating SSL. It will collect statistics about which versions of SSL are being negotiated with clients. Use the 'istats dump' command to see the statistics. Or, connect to your virtual server and query for "/sslversions" to see a javascript graph. Code : when CLIENTSSL_HANDSHAKE { ISTATS::incr "ltm.virtual [virtual name] c [SSL::cipher version]" 1 } when HTTP_REQUEST { if { [string tolower [HTTP::uri]] equals "/sslversions" } { set v3 [ISTATS::get "ltm.virtual [virtual name] c SSLv3"] set t10 [ISTATS::get "ltm.virtual [virtual name] c TLSv1"] set t11 [ISTATS::get "ltm.virtual [virtual name] c TLSv1.1"] set t12 [ISTATS::get "ltm.virtual [virtual name] c TLSv1.2"] set hbody "\n \ \n \ \n \ \n \ \n \ \n \ // Load the Visualization API and the piechart package.\n \ google.load('visualization', '1.0', {'packages':\['corechart'\]});\n \ \n \ // Set a callback to run when the Google Visualization API is loaded.\n \ google.setOnLoadCallback(drawChart);\n \ \n \ // Callback that creates and populates a data table,\n \ // instantiates the pie chart, passes in the data and\n \ // draws it.\n \ function drawChart() {\n \ \n \ // Create the data table.\n \ var data = new google.visualization.DataTable();\n \ data.addColumn('string', 'SSL Types');\n \ data.addColumn('number', 'Versions');\n \ data.addRows(\[\n \ \['SSLv3', $v3],\n \ \['TLSv1', $t10],\n \ \['TLSv1.1', $t11],\n \ \['TLSv1.2', $t12]\n \ \]);\n \ \n \ // Set chart options\n \ var options = {'title':'SSL/TLS Versions on [virtual name]',\n \ 'width':800,\n \ 'height':600};\n \ \n \ // Instantiate and draw our chart, passing in some options.\n \ var chart = new google.visualization.PieChart(document.getElementById('chart_div'));\n \ chart.draw(data, options);\n \ }\n \ \n \ \n \ \n \ \n \ \n \ \n \ \n \ \n \ " HTTP::respond 200 content $hbody } }783Views2likes3CommentsScript for External Monitor to check server OCSP Stapling Status
Problem this snippet solves: Many BIG-IPs do not have DNS configured to ensure that traffic can continue flowing even during a DNS hiccup (you know they happen). But this lack of DNS makes name-based checking like OCSP stapling difficult. BIG-IP therefore doesn't try to check the OCSP Stapling status of the servers in a pool it is bridging SSL traffic to. One solution to this problem is to use a BIG-IP External Monitor to check the revocation status of servers in a server pool. How to use this snippet: Save this snippet to a file on your desktop. From the BIG-IP GUI, choose the System panel on the left. Then choose File Management. Then choose External Program File List. Upload the file that you saved to the desktop, and give it an appropriate name such as MyOCSPmonitor. From the GUI, select Local Traffic and then Monitors. Create a new monitor with type External. Ensure that the External Program field is set to the OCSP monitor object you just created (MyOCSPmonitor). Because OCSP status is not something that is likely to change often, use long intervals (on the order of minutes rather than seconds) and timeouts. Note that you can use 'revoked.grc.com:443' for testing :) If you don't have DNS configured on the BIG-IP,use the IP address of revoked.grc.com instead of the hostname. Code : #!/bin/sh # # OCSP stapling status monitor # # these arguments supplied automatically for all external pingers: # $1 = IP (::ffff:nnn.nnn.nnn.nnn notation or hostname) # $2 = port (decimal, host byte order) # $3 and higher = additional arguments # # $MONITOR_NAME = name of the monitor # # In this sample script, $3 is the regular expression # # Name of the pidfile pidfile="/var/run/$MONITOR_NAME.$1..$2.pid" # Send signal to the process group to kill our former self and any children # as external monitors are run with SIGHUP blocked if [ -f $pidfile ] then kill -9 -`cat $pidfile` > /dev/null 2>&1 fi echo "$$" > $pidfile # Remove the IPv6/IPv4 compatibility prefix node_ip=`echo $1 | sed 's/::ffff://'` # ================================================================= # OCSP Stapling # # it's better to check for 'Revoked' and use that as a trigger for # down rather than looking for success. There's ton of other # reasons that a node might be unavailable to report its status # (down for maintenance, network # hiccoughs, etc). # # Note that you can use 'revoked.grc.com:443' for testing :) # # Use the on-box openssl utility to query ocspstatus # ================================================================= cnt=`echo -e "GET /" | openssl s_client -status -connect ${node_ip}:$2 2> /dev/null | grep -A20 ^OCSP.Response.Data: | grep -c "Cert Status: revoked"` if [ $cnt -eq 0 ] then # Remove the pidfile before the script echoes anything to stdout and is killed by bigd rm -f $pidfile echo "up" fi # Remove the pidfile before the script ends rm -f $pidfile499Views0likes0CommentsSample Linux script to update CRL file from Certificate Authority
Problem this snippet solves: CRL files are signed lists of revoked serial numbers issued by a specific Certificate Authority (Verisign, Godaddy, GlobalSign, etc). There are several advanced methods of dealing with revoked certificates, the best of which is OCSP stapling. Other methods are OCSP responders or CRL Distribution Points. However, for small or internal projects, some administrators rely on simply using straight-up CRL files. After a time, the administrator will realize he or she needs to automate this process with a script. The administrator can automate this process on the BIG-IP itself with an iCall script. Here's a link to a great example of the iCall solution. However, some administrators many need to use a straight-up Linux device to pull and copy the CRL files around to many different devices, only one of which is the BIG-IP. How to use this snippet: This is a sample of a Linux script that pulls down a CRL file from GoDaddy, verifies it and then copies it to BIG-IP. Ensure that the Linux device can copy files directly to the BIG-IP via ssh-key authentication. Modify the 'f5' variable of the script to point to the BIG-IP. If not using GoDaddy, find the URL of the CRL file for the appropriate CA. If the 'ssl-crl' object hasn't been created on the BIG-IP yet, then it must be done manually the first time. Download the CRL, copy it to the BIG-IP's /var/tmp area. Then login to the BIG-IP and issue the following command: tmsh modify sys file ssl-crl gdcrl source-path file:/var/tmp/CRL After that, the script should work. Code : #!/bin/bash # # script to download a CRL from GoDaddy CA. # See this page for GoDaddy CRL information: # https://certs.godaddy.com/repository # Verify CRL # Convert CRL # Copy to BIG-IP # exit on error to prevent copying corrupt CRL to BIG-IP set -e f5=yourbigip.com f5port=22 crlurl=https://certs.godaddy.com/repository/mastergodaddy2issuing.crl gdcrturl=https://certs.godaddy.com/repository/gdig2.crt gdcrt=gdig2.crt echo "Automated CRL update Script" echo "Downloading from $crlurl" echo "Copying to ${f5}:${f5port}" echo "Last line should be SUCCESS" echo "---- GO ----" if [ ! -f $gdcrt ]; then echo "Fetching GoDaddy Certificate" curl $gdcrturl > $gdcrt fi cf=gdroot.crl last=last.crl if [ -f $cf ]; then if [ ! -s $cf ]; then echo "Found existing zero-length CRL file, deleting" rm -f $cf else echo "Found existing $cf - moving to backup" mv $cf $last fi fi echo "Downloading CRL file $cf" curl $crlurl > $cf echo "Testing $cf for readability" test -f $cf test -r $cf echo "Testing to see if $cf is zero length" test -s $cf if [ -f $last ]; then echo "Testing if $cf is newer than backup file $last" if [ ! $cf -nt $last ]; then echo "File not changed. SUCCESS" fi fi echo "Verifying CRL against certificate, converting to PEM format" openssl crl -inform DER -CAfile $gdcrt -in $cf -outform PEM -out ${cf}.pem echo "Testing PEM for zero length" test -s ${cf}.pem echo "Copying CRL file to bigip" scp -P ${f5port} ${cf}.pem root@${f5}:/var/tmp echo "Importing CRL into system" echo " this may fail if object was never created - replace 'modify' with 'create'" ssh root@${f5} -p ${f5port} "tmsh modify sys file ssl-crl gdcrl source-path file:/var/tmp/${cf}.pem" echo "SUCCESS"1.2KViews1like0CommentsSSL 3.0 Client Tracker
Problem this snippet solves: iRule to track and display information about traffic from SSL 3.0-only clients. Allows application administrators to assess the impact of disabling access to SSL 3.0-only clients using the BIG-IP. The iRule logs and displays Source Address, Host header, User-Agent, SSL Cipher and Geolocation (Continent, Country, State) How to use this snippet: Enable this iRule on BIG-IP Virtual Server and then access "Magic" URL of "/ssl3lookup/" to display data. Note that the iRule could be broken into parts so that accessing the data is only possible on an internal Virtual Server. Code : # iRule to maintain SSL3-only client information in memory # For performance purposes, it only "records" client information based on client IP address as a "key" into table # Rule also will not update information if request is from a client IP addresss that has used SSL3 within the timeout period # Chad Jenison c.jenison at f5.com when RULE_INIT { #set this value to value in seconds you want to keep ssl3clients in memory ; default is 3600 (1 hour) set static::ttl 3600 set static::honorXffIfExists 1 set static::xffHeaderName "X-Forwarded-For" } when HTTP_REQUEST { if {[SSL::cipher version] eq "SSLv3"}{ if {$static::honorXffIfExists && [HTTP::header exists $static::xffHeaderName]} { set requestorip [HTTP::header value $static::xffHeaderName] log local0. "SSL3 connection from Proxy: [IP::client_addr] on behalf of [HTTP::header value $static::xffHeaderName] **Notify Proxy Admin" } else { set requestorip [IP::client_addr] } if {[table incr -subtable ssl3sourceIPs $requestorip] eq 1}{ table timeout -subtable ssl3sourceIPs $requestorip $static::ttl table set "ssl3host$requestorip" [HTTP::header "Host"] $static::ttl table set "ssl3useragent$requestorip" [HTTP::header "User-Agent"] $static::ttl table set "sslcipher$requestorip" [SSL::cipher name] $static::ttl log local0. "SSL Cipher Used: [SSL::cipher name]" } else { table timeout -subtable ssl3sourceIPs $requestorip $static::ttl table timeout "ssl3host$requestorip" $static::ttl table timeout "ssl3useragent$requestorip" $static::ttl table timeout "sslcipher$requestorip" $static::ttl } } if {[HTTP::uri] starts_with "/ssl3lookup/"}{ set ssl3clienttable " Source IP Host Header User-Agent Geolocation SSL Cipher Used HTTP Requests " foreach clientip [table keys -subtable ssl3sourceIPs] { append ssl3clienttable " $clientip [table lookup "ssl3host$clientip"] [table lookup "ssl3useragent$clientip"] [table lookup "sslcipher$clientip"] [whereis $clientip continent]:[whereis $clientip country]:[whereis $clientip state] [table lookup -subtable ssl3sourceIPs $clientip] " } append ssl3clienttable " " HTTP::respond 200 content " SSL3 Client Table $ssl3clienttable" log local0. "Got Magic Request" } } Tested this on version: 11.6289Views0likes1Comment