SSL Profiles Part 8: Client Authentication
This is the eighth article in a series of Tech Tips that highlight SSL Profiles on the BIG-IP LTM. SSL Overview and Handshake SSL Certificates Certificate Chain Implementation Cipher Suites SSL Options SSL Renegotiation Server Name Indication Client Authentication Server Authentication All the "Little" Options This article will discuss the concept of Client Authentication, how it works, and how the BIG-IP system allows you to configure it for your environment. Client Authentication In a TLS handshake, the client and the server exchange several messages that ultimately result in an encrypted channel for secure communication. During this handshake, the client authenticates the server's identity by verifying the server certificate (for more on the TLS handshake, see SSL Overview and Handshake - Article 1in this series). Although the client always authenticates the server's identity, the server is not required to authenticate the client's identity. However, there are some situations that call for the server to authenticate the client. Client authentication is a feature that lets you authenticate users that are accessing a server. In client authentication, a certificate is passed from the client to the server and is verified by the server. Client authentication allow you to rest assured that the person represented by the certificate is the person you expect. Many companies want to ensure that only authorized users can gain access to the services and content they provide. As more personal and access-controlled information moves online, client authentication becomes more of a reality and a necessity. How Does Client Authentication Work? Before we jump into client authentication, let's make sure we understand server authentication. During the TLS handshake, the client authenticates the identity of the server by verifying the server's certificate and using the server's public key to encrypt data that will be used to compute the shared symmetric key. The server can only generate the symmetric key used in the TLS session if it can decrypt that data with its private key. The following diagram shows an abbreviated version of the TLS handshake that highlights some of these concepts. Ultimately, the client and server need to use a symmetric key to encrypt all communication during their TLS session. In order to calculate that key, the server shares its certificate with the client (the certificate includes the server's public key), and the client sends a random string of data to the server (encrypted with the server's public key). Now that the client and server each have the random string of data, they can each calculate (independently) the symmetric key that will be used to encrypt all remaining communication for the duration of that specific TLS session. In fact, the client and server both send a "Finished' message at the end of the handshake...and that message is encrypted with the symmetric key that they have both calculated on their own. So, if all that stuff works and they can both read each other's "Finished" message, then the server has been authenticated by the client and they proceed along with smiles on their collective faces (encrypted smiles, of course). You'll notice in the diagram above that the server sent its certificate to the client, but the client never sent its certificate to the server. When client authentication is used, the server still sends its certificate to the client, but it also sends a "Certificate Request" message to the client. This lets the client know that it needs to get its certificate ready because the next message from the client to the server (during the handshake) will need to include the client certificate. The following diagram shows the added steps needed during the TLS handshake for client authentication. So, you can see that when client authentication is enabled, the public and private keys are still used to encrypt and decrypt critical information that leads to the shared symmetric key. In addition to the public and private keys being used for authentication, the client and server both send certificates and each verifies the certificate of the other. This certificate verification is also part of the authentication process for both the client and the server. The certificate verification process includes four important checks. If any of these checks do not return a valid response, the certificate verification fails (which makes the TLS handshake fail) and the session will terminate. These checks are as follows: Check digital signature Check certificate chain Check expiration date and validity period Check certificate revocation status Here's how the client and server accomplish each of the checks for client authentication: Digital Signature: The client sends a "Certificate Verify" message that contains a digitally signed copy of the previous handshake message. This message is signed using the client certificate's private key. The server can validate the message digest of the digital signature by using the client's public key (which is found in the client certificate). Once the digital signature is validated, the server knows that public key belonging to the client matches the private key used to create the signature. Certificate Chain: The server maintains a list of trusted CAs, and this list determines which certificates the server will accept. The server will use the public key from the CA certificate (which it has in its list of trusted CAs) to validate the CA's digital signature on the certificate being presented. If the message digest has changed or if the public key doesn't correspond to the CA's private key used to sign the certificate, the verification fails and the handshake terminates. Expiration Date and Validity Period: The server compares the current date to the validity period listed in the certificate. If the expiration date has not passed and the current date is within the period, everything is good. If it's not, then the verification fails and the handshake terminates. Certificate Revocation Status: The server compares the client certificate to the list of revoked certificates on the system. If the client certificate is on the list, the verification fails and the handshake terminates. As you can see, a bunch of stuff has to happen in just the right way for the Client-Authenticated TLS handshake to finalize correctly. But, all this is in place for your own protection. After all, you want to make sure that no one else can steal your identity and impersonate you on a critically important website! BIG-IP Configuration Now that we've established the foundation for client authentication in a TLS handshake, let's figure out how the BIG-IP is set up to handle this feature. The following screenshot shows the user interface for configuring Client Authentication. To get here, navigate to Local Traffic > Profiles > SSL > Client. The Client Certificate drop down menu has three settings: Ignore (default), Require, and Request. The "Ignore" setting specifies that the system will ignore any certificate presented and will not authenticate the client before establishing the SSL session. This effectively turns off client authentication. The "Require" setting enforces client authentication. When this setting is enabled, the BIG-IP will request a client certificate and attempt to verify it. An SSL session is established only if a valid client certificate from a trusted CA is presented. Finally, the "Request" setting enables optional client authentication. When this setting is enabled, the BIG-IP will request a client certificate and attempt to verify it. However, an SSL session will be established regardless of whether or not a valid client certificate from a trusted CA is presented. The Request option is often used in conjunction with iRules in order to provide selective access depending on the certificate that is presented. For example: let's say you would like to allow clients who present a certificate from a trusted CA to gain access to the application while clients who do not provide the required certificate be redirected to a page detailing the access requirements. If you are not using iRules to enforce a different outcome based on the certificate details, there is no significant benefit to using the "Request" setting versus the default "Ignore" setting. In both cases, an SSL session will be established regardless of the certificate presented. Frequency specifies the frequency of client authentication for an SSL session. This menu offers two options: Once (default) and Always. The "Once" setting specifies that the system will authenticate the client only once for an SSL session. The "Always"setting specifies that the system will authenticate the client once when the SSL session is established as well as each time that session is reused. The Retain Certificate box is checked by default. When checked, the client certificate is retained for the SSL session. Certificate Chain Traversal Depth specifies the maximum number of certificates that can be traversed in a client certificate chain. The default for this setting is 9. Remember that "Certificate Chain" part of the verification checks? This setting is where you configure the depth that you allow the server to dig for a trusted CA. For more on certificate chains, see article 2 of this SSL series. Trusted Certificate Authorities setting is used to specify the BIG-IP's Trusted Certificate Authorities store. These are the CAs that the BIG-IP trusts when it verifies a client certificate that is presented during client authentication. The default value for the Trusted Certificate Authorities setting is None, indicating that no CAs are trusted. Don't forget...if the BIG-IP Client Certificate menu is set to Require but the Trusted Certificate Authorities is set to None, clients will not be able to establish SSL sessions with the virtual server. The drop down list in this setting includes the name of all the SSL certificates installed in the BIG-IP's /config/ssl/ssl.crt directory. A newly-installed BIG-IP system will include the following certificates: default certificate and ca-bundle certificate. The default certificate is a self-signed server certificate used when testing SSL profiles. This certificate is not appropriate for use as a Trusted Certificate Authorities certificate bundle. The ca-bundle certificate is a bundle of CA certificates from most of the well-known PKIs around the world. This certificate may be appropriate for use as a Trusted Certificate Authorities certificate bundle. However, if this bundle is specified as the Trusted Certificate Authorities certificate store, any valid client certificate that is signed by one of the popular Root CAs included in the default ca-bundle.crt will be authenticated. This provides some level of identification, but it provides very little access control since almost any valid client certificate could be authenticated. If you want to trust only certificates signed by a specific CA or set of CAs, you should create and install a bundle containing the certificates of the CAs whose certificates you trust. The bundle must also include the entire chain of CA certificates necessary to establish a chain of trust. Once you create this new certificate bundle, you can select it in the Trusted Certificate Authorities drop down menu. The Advertised Certificate Authorities setting is used to specify the CAs that the BIG-IP advertises as trusted when soliciting a client certificate for client authentication. The default value for the Advertised Certificate Authorities setting is None, indicating that no CAs are advertised. When set to None, no list of trusted CAs is sent to a client with the certificate request. If the Client Certificate menu is set to Require or Request, you can configure the Advertised Certificate Authorities setting to send clients a list of CAs that the server is likely to trust. Like the Trusted Certificate Authorities list, the Advertised Certificate Authorities drop down list includes the name of all the SSL certificates installed in the BIG-IP /config/ssl/ssl.crt directory. A newly-installed BIG-IP system includes the following certificates: default certificate and ca-bundle certificate. The default certificate is a self-signed server certificate used for testing SSL profiles. This certificate is not appropriate for use as an Advertised Certificate Authorities certificate bundle. The ca-bundle certificate is a bundle of CA certificates from most of the well-known PKIs around the world. This certificate may be appropriate for use as an Advertised Certificate Authorities certificate bundle. If you want to advertise only a specific CA or set of CAs, you should create and install a bundle containing the certificates of the CA to advertise. Once you create this new certificate bundle, you can select it in the Advertised Certificate Authorities setting drop down menu. You are allowed to configure the Advertised Certificate Authorities setting to send a different list of CAs than that specified for the Trusted Certificate Authorities. This allows greater control over the configuration information shared with unknown clients. You might not want to reveal the entire list of trusted CAs to a client that does not automatically present a valid client certificate from a trusted CA. Finally, you should avoid specifying a bundle that contains a large number of certificates when you configure the Advertised Certificate Authorities setting. This will cut down on the number of certificates exchanged during a client SSL handshake. The maximum size allowed by the BIG-IP for native SSL handshake messages is 14,304 bytes. Most handshakes don't result in large message lengths, but if the SSL handshake is negotiating a native cipher and the total length of all messages in the handshake exceeds the 14,304 byte threshold, the handshake will fail. The Certificate Revocation List (CRL) setting allows you to specify a CRL that the BIG-IP will use to check revocation status of a certificate prior to authenticating a client. If you want to use a CRL, you must upload it to the /config/ssl/ssl.crl directory on the BIG-IP. The name of the CRL file may then be entered in the CRL setting dialog box. Note that this box will offer no drop down menu options until you upload a CRL file to the BIG-IP. Since CRLs can quickly become outdated, you should use either OCSP or CRLDP profiles for more robust and current verification functionality. Conclusion Well, that wraps up our discussion on Client Authentication. I hope the information helped, and I hope you can use this to configure your BIG-IP to meet the needs of your specific network environment. Be sure to come back for our next article in the SSL series. As always, if you have any other questions, feel free to post a question here or Contact Us directly. See you next time!25KViews1like21CommentsSSL Profiles Part 7: Server Name Indication
This is the seventh article in a series of Tech Tips that highlight SSL Profiles on the BIG-IP LTM. The other articles are: SSL Overview and Handshake SSL Certificates Certificate Chain Implementation Cipher Suites SSL Options SSL Renegotiation Server Name Indication Client Authentication Server Authentication All the "Little" Options This article will discuss the concept of Server Name Indication (SNI) and how the BIG-IP system allows you to configure it for your environment. What is Server Name Indication? SNI (listed in RFC 4366) is an extension to the TLS protocol that allows the client to include the requested hostname in the first message of the SSL handshake (Client Hello). This allows the server to determine the correct named host for the request and setup the connection accordingly from the start. Prior to the introduction of SNI, the client could not establish secure connections to multiple virtual servers hosted on a single IP address. This happened because the destination server name can only be decoded from the HTTP request header after the SSL connection has been established. As you can see from the following diagram (taken from Jason Rahm's first articlein this series), the standard TLS handshake involves several messages between the client and the server. The server sends the certificate (step 3) to the client long before the handshake is complete. If a web server is used to host multiple DNS hostnames on a single IP address, the certificate passing between the server and the client could get problematic. Using the standard TLS protocol, the server might send the wrong certificate to the client because it does not yet know which certificate the client is looking for. Then, if the client receives a certificate with the wrong name, it will either abort the connection (assuming a Man-in-the-Middle attack) or at least display a warning page to the user stating that there is a problem with the certificate. This scenario is shown in the following figure. A client wants to visit https://www.securesite1.com, but the virtual web server doesn't know to pass the certificate for securesite1.com until it finishes the TLS handshake and reads the HTTP request header from the client. This is where SNI comes in really handy. With the introduction of SNI, the client can indicate the name of the server to which he is attempting to connect as part of the "Client Hello" message in the handshake process. The server then uses this information to select the appropriate certificate to return to the client when it sends back the "Server Hello" packet during the handshake. This allows a server to present multiple certificates on the same IP address and port number and thus allows multiple secure (HTTPS) sites to be served off the same IP address without requiring all the sites to use the same certificate. Having this extension available (per RFC 4366) is a great feature, but it does no good if a client is using a browser that doesn't send the correct SNI message to the server. So, to make SNI practical, the vast majority of your users must use web browsers that support it. Browsers that do not support SNI will be presented with the server's default certificate and are likely to receive a certificate warning. According to Wikipedia, the following browsers support SNI: Internet Explorer 7 or later, on Windows Vista or higher. Does not work on Windows XP, even Internet Explorer 8 (the support of this feature is not browser version dependent, it depends on SChannel system component which introduced the support of TLS SNI extension, starting from Windows Vista, not XP). Mozilla Firefox 2.0 or later Opera 8.0 (2005) or later (the TLS 1.1 protocol must be enabled) Opera Mobile at least version 10.1 beta on Android Google Chrome (Vista or higher. XP on Chrome 6 or newer. OS X 10.5.7 or higher on Chrome 5.0.342.1 or newer) Safari 3.0 or later (Mac OS X 10.5.6 or higher and Windows Vista or higher) Konqueror/KDE 4.7 or later MobileSafari in Apple iOS 4.0 or later Android default browser on Honeycomb (v3.x) or newer Windows Phone 7 MicroB on Maemo Odyssey on MorphOS Now that you know the background of SNI, let's dig into how the BIG-IP is set up for SNI configuration. BIG-IP Configuration Beginning in v11.1.0, the BIG-IP allows you to assign multiple SSL profiles to a virtual server for supporting the use of the TLS SNI feature. The TLS SNI feature is not available in previous BIG-IP versions, so you'll want to upgrade if you are not on v11.1.0 or higher! To support this feature, a virtual server must be assigned a default SSL profile for fallback as well as one SSL profile per HTTPS site. The fallback SSL profile is used when the server name does not match the client request or when the browser does not support the SNI extensions. Using the example from the figures above, suppose you need to host the three domains securesite1.com, securesite2.com, and securesite3.com on the same HTTPS virtual server. Each domain has its own server certificate to use, such as securesite1.crt, securesite2.crt, and securesite3.crt, and each has different security requirements. To ensure that the BIG-IP presents the correct certificate to the browser, you enable SNI, which sends the name of a domain as part of the TLS negotiation. To enable SNI, you configure the Server Name and other settings on an SSL profile, and then assign the profile to a virtual server. For SSL profiles (Client and Server), you type the name for the HTTPS site in the Server Name box. SNI configuration is found by navigating to Local Traffic > Profiles > SSL > Client | Server. The following screenshot shows the three settings used for SNI in the BIG-IP. Server Name specifies the fully qualified DNS hostname of the server that is used in SNI communications. Using the server name, the Local Traffic Manager can choose from multiple SSL profiles prior to the SSL Handshake. If no value is specified, the system uses the Common Name value from the default certificate. The default for this setting leaves the name blank. Default SSL Profile for SNI indicates that the system uses this profile as the default SSL profile when there is no match to the server name, or when the client provides no SNI extension support. Note that when assigning multiple SSL profiles to a single virtual server, you can enable this setting on one Client SSL profile only and on one Server SSL profile only. The default for this setting is unchecked. Require Peer SNI support requires that all network peers provide SNI support as well. If you enable both "Default SSL Profile for SNI" and "Require Peer SNI Support," the system terminates the connection when the client provides no SNI extension. The default for this setting is unchecked. Conclusion I hope this helps with setting up this great feature in your environment. SNI is a powerful tool, and it could go a long way in saving you precious IP addresses for your secure sites! As we noted before, this feature is only supported in BIG-IP version 11.1.0 and later. If you are using a version prior to 11.1.0, you can read this articleon DevCentral that shows how you can use an iRule to take advantage of SNI on previous versions. Finally, you can read more on our DevCentral Wiki about using iRules for SNI. Well, thanks for reading about SNI. Be sure to come back for the next article in the SSL series where I will talk about SSL Forward Proxy. See you then!24KViews1like10CommentsAutomate Let's Encrypt Certificates on BIG-IP
To quote the evil emperor Zurg: "We meet again, for the last time!" It's hard to believe it's been six years since my first rodeo with Let's Encrypt and BIG-IP, but (uncompromised) timestamps don't lie. And maybe this won't be my last look at Let's Encrypt, but it will likely be the last time I do so as a standalone effort, which I'll come back to at the end of this article. The first project was a compilation of shell scripts and python scripts and config files and well, this is no different. But it's all updated to meet the acme protocol version requirements for Let's Encrypt. Here's a quick table to connect all the dots: Description What's Out What's In acme client letsencrypt.sh dehydrated python library f5-common-python bigrest BIG-IP functionality creating the SSL profile utilizing an iRule for the HTTP challenge The f5-common-python library has not been maintained or enhanced for at least a year now, and I have an affinity for the good work Leo did with bigrest and I enjoy using it. I opted not to carry the SSL profile configuration forward because that functionality is more app-specific than the certificates themselves. And finally, whereas my initial project used the DNS challenge with the name.com API, in this proof of concept I chose to use an iRule on the BIG-IP to serve the challenge for Let's Encrypt to perform validation against. Whereas my solution is new, the way Let's Encrypt works has not changed, so I've carried forward the process from my previous article that I've now archived. I'll defer to their how it works page for details, but basically the steps are: Define a list of domains you want to secure Your client reaches out to the Let’s Encrypt servers to initiate a challenge for those domains. The servers will issue an http or dns challenge based on your request You need to place a file on your web server or a txt record in the dns zone file with that challenge information The servers will validate your challenge information and notify you You will clean up your challenge files or txt records The servers will issue the certificate and certificate chain to you You now have the key, cert, and chain, and can deploy to your web servers or in our case, to the BIG-IP Before kicking off a validation and generation event, the client registers your account based on your settings in the config file. The files in this project are as follows: /etc/dehydrated/config # Dehydrated configuration file /etc/dehydrated/domains.txt # Domains to sign and generate certs for /etc/dehydrated/dehydrated # acme client /etc/dehydrated/challenge.irule # iRule configured and deployed to BIG-IP by the hook script /etc/dehydrated/hook_script.py # Python script called by dehydrated for special steps in the cert generation process # Environment Variables export F5_HOST=x.x.x.x export F5_USER=admin export F5_PASS=admin You add your domains to the domains.txt file (more work likely if signing a lot of domains, I tested the one I have access to). The dehydrated client, of course is required, and then the hook script that dehydrated interacts with to deploy challenges and certificates. I aptly named that hook_script.py. For my hook, I'm deploying a challenge iRule to be applied only during the challenge; it is modified each time specific to the challenge supplied from the Let's Encrypt service and is cleaned up after the challenge is tested. And finally, there are a few environment variables I set so the information is not in text files. You could also move these into a credential vault. So to recap, you first register your client, then you can kick off a challenge to generate and deploy certificates. On the client side, it looks like this: ./dehydrated --register --accept-terms ./dehydrated -c Now, for testing, make sure you use the Let's Encrypt staging service instead of production. And since I want to force action every request while testing, I run the second command a little differently: ./dehydrated -c --force --force-validation Depicted graphically, here are the moving parts for the http challenge issued by Let's Encrypt at the request of the dehydrated client, deployed to the F5 BIG-IP, and validated by the Let's Encrypt servers. The Let's Encrypt servers then generate and return certs to the dehydrated client, which then, via the hook script, deploys the certs and keys to the F5 BIG-IP to complete the process. And here's the output of the dehydrated client and hook script in action from the CLI: # ./dehydrated -c --force --force-validation # INFO: Using main config file /etc/dehydrated/config Processing example.com + Checking expire date of existing cert... + Valid till Jun 20 02:03:26 2022 GMT (Longer than 30 days). Ignoring because renew was forced! + Signing domains... + Generating private key... + Generating signing request... + Requesting new certificate order from CA... + Received 1 authorizations URLs from the CA + Handling authorization for example.com + A valid authorization has been found but will be ignored + 1 pending challenge(s) + Deploying challenge tokens... + (hook) Deploying Challenge + (hook) Challenge rule added to virtual. + Responding to challenge for example.com authorization... + Challenge is valid! + Cleaning challenge tokens... + (hook) Cleaning Challenge + (hook) Challenge rule removed from virtual. + Requesting certificate... + Checking certificate... + Done! + Creating fullchain.pem... + (hook) Deploying Certs + (hook) Existing Cert/Key updated in transaction. + Done! This results in a deployed certificate/key pair on the F5 BIG-IP, and is modified in a transaction for future updates. This proof of concept is on github in the f5devcentral org if you'd like to take a look. Before closing, however, I'd like to mention a couple things: This is an update to an existing solution from years ago. It works, but probably isn't the best way to automate today if you're just getting started and have already started pursuing a more modern approach to automation. A better path would be something like Ansible. On that note, there are several solutions you can take a look at, posted below in resources. Resources https://github.com/EquateTechnologies/dehydrated-bigip-ansible https://github.com/f5devcentral/ansible-bigip-letsencrypt-http01 https://github.com/s-archer/acme-ansible-f5 https://github.com/s-archer/terraform-modular/tree/master/lets_encrypt_module(Terraform instead of Ansible) https://community.f5.com/t5/technical-forum/let-s-encrypt-with-cloudflare-dns-and-f5-rest-api/m-p/292943(Similar solution to mine, only slightly more robust with OCSP stapling, the DNS instead of HTTP challenge, and with bash instead of python)22KViews6likes18CommentsSSL Profiles Part 6: SSL Renegotiation
This is the sixth article in a series of Tech Tips that highlight SSL Profiles on the BIG-IP LTM. SSL Overview and Handshake SSL Certificates Certificate Chain Implementation Cipher Suites SSL Options SSL Renegotiation Server Name Indication Client Authentication Server Authentication All the "Little" Options This article will discuss SSL renegotiation, some OpenSSL features, some of the attack vectors against SSL renegotiation, and then how the BIG-IP is configured to handle this feature. What Is SSL Renegotiation? Before we get into the details of SSL renegotiation, let me start by outlining a quick scenario. Let's say a user visits an online shopping site that is SSL encrypted. Initially, the user shops around anonymously, but after some time on the site, the user decides to log in and make a purchase. The user will need to authenticate to the site before making the purchase, so the SSL connection will need to be adjusted to allow the authentication. Ideally, all the information the user collected as an anonymous visitor will be maintained and protected after the status change to an authenticated customer. This basic (yet frequent) scenario outlines the need for SSL renegotiation. The figure below shows a representation of this scenario and shows that a new SSL session must be established in order to authenticate the user. This new session completes the full handshake, but it does it using the security of the already-established SSL connection. SSL renegotiation messages (including types of ciphers and encryption keys) are encrypted and then sent over the existing SSL connection. This feature is nice because it can create a secure SSL session based on the fact that a secure connection is already established. SSL renegotiation is useful in several situations where an ordinary SSL session is already established. Here are a few examples: Client authentication is required A different set of encryption and decryption keys are needed A different set of encryption and hashing algorithms are used The client or the server can request renegotiation at any time. For the client to request renegotiation, the client sends a "Client Hello" message in the already-established encrypted channel and the server responds with a "Server Hello" and then the negotiation follows the normal handshake process. The server can initiate the renegotiation by sending the client a Hello Request message. When the client receives the request, the client sends the "Client Hello" message and the handshake process takes place. One quick note of clarification: the client and server can also complete a session resumption vice a session renegotiation. A session resumption basically resumes a previous session (using a previous session ID), and it saves the client and server the computing work of generating new encryption keys. Renegotiation is a process by which the full handshake process takes place over an already existing SSL connection. A Fly In The Ointment... Life would be much easier if the bad guys weren't out there doing their thing, but I guess it would also be less interesting. Nonetheless, some pretty smart guys were working with SSL renegotiation back in the old days (circa 2009) and found out that they could exploit a vulnerability in its design. The Common Vulnerabilities and Exposures (CVE) database outlines the details behind this SSL renegotiation vulnerability in CVE-2009-3555. You can read the details for yourself, but here's what the CVE basically says: TLS and SSLv3 do not properly associate renegotiation handshakes with an existing connection, and this allows attackers to insert data into existing sessions by sending an unauthenticated request that is processed retroactively by a server in a post-renegotiation context related to a "plaintext injection" attack. Essentially, this means that bad guys can hijack the SSL session and start using your "secure" communications on your behalf. Houston, we have a problem. Fortunately, the good folks at the Internet Engineering Task Force (IETF) found out about this problem, and they responded with a little magic of their own. It's outlined in Request for Comments (RFC) 5746. Here's what they had to say: "Secure Socket Layer (SSL) and Transport Layer Security (TLS) renegotiation are vulnerable to an attack in which the attacker forms a TLS connection with the target server, injects content of his choice, and then splices in a new TLS connection from a client. The server treats the client's initial TLS handshake as a renegotiation and thus believes that the initial data transmitted by the attacker is from the same entity as the subsequent client data. This specification defines a TLS extension to cryptographically tie renegotiations to the TLS connections they are being performed over, thus preventing this attack." Well, take that bad guys!! A Few Notes About OpenSSL Now that we have a basic understanding of RFC 5746, let's spend some time on OpenSSL and how it relates to F5's BIG-IP. After all, how can you have an article on SSL and not talk about OpenSSL? This stuff is free (Apache style) and it's awesome! The BIG-IP supports the popular OpenSSL toolkit, and it even has a built-in OpenSSL utility. It's important to understand how OpenSSL handles the behavior of clients and servers regarding the feature of SSL renegotiation. OpenSSL 0.9.8m and later always attempts to use secure renegotiation as described in RFC 5746. On the BIG-IP side of the house, versions prior to 10.2.3 do not support this RFC. However, beginning in version 10.2.3 and 11.x, the BIG-IP SSL profiles do support it. So, pause for a few minutes from reading this article and upgrade your BIG-IP! Patching When describing SSL implementations, systems that support secure renegotiation (per RFC 5746) are referred to as "patched" and systems that do not support secure renegotiation are referred to as "unpatched." If a client and server are both patched, connections and renegotiation are always permitted by OpenSSL implementations. If a server is patched but the client is unpatched, the initial connection will succeed but client renegotiation will be denied by the server with a no_renegotiation warning alert if TLS v1.0 is used or a fatal handshake_failure alert if SSL v3.0 is used. If the patched server attempts to renegotiate with the unpatched client, a fatal handshake_failure alert is sent. This is because the server code may be unaware of the unpatched nature of the client. Here's what happens if a client is patched but the server is unpatched. If the option "SSL_OP_LEGACY_SERVER_CONNECT" or "SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION" is set then initial connections as well as all renegotiations between patched clients and unpatched servers will succeed. However, if neither option is set then initial connections to unpatched servers will fail. (note: the option "SSL_OP_LEGACY_SERVER_CONNECT" is currently set by default, but as more servers become patched, this option will not be set by default in future versions of OpenSSL). Renegotiation Attacks Speaking of highly broken...let's spend a little time on SSL renegotiation attacks before we dive into the BIG-IP configurations. Here are two fairly well known attacks that are targeted at the SSL renegotiation feature. And, guess what? I'm starting with the..."Man in the Middle" (sung to Michael Jackson's hit song) Man In The Middle Since we discussed RFC 5746 earlier, why not go over the details of what it fixed? As we've discussed, SSL allows both servers and clients to initiate a complete renegotiation of the encryption parameters used for SSL connections. However, the design of the initial handshake and the renegotiation process had a gap that could allow an attacker to send a “Client Hello” and insert content into a client’s SSL session and then intercept secure communications between the server and the client. The following illustration shows how a bad guy could exploit the Man in the Middle vulnerability. In this example, the client sends a "Client Hello" to start an SSL session with his bank's server. The bad guy temporarily blocks the "Client Hello" and then creates an SSL connection of his own with the server. After the SSL session is created between the bad guy and the bank server, the bad guy asks for a money transfer. The bank server needs to authenticate the user, so it requests a renegotiation by sending a "Hello Request" to the bad guy...which is exactly what he wanted. This is where the bad guy sends the client's initial "Client Hello" to the server. The client thinks he is beginning a new SSL session, and the server thinks an SSL renegotiation has just taken place. But, nonetheless, all parties are happy with everything...especially the bad guy! See, now you know why you should be using a "patched" system! Denial of Service Last year, the IETF posted a paper that outlines a Denial of Service (DoS) attack against a server using the SSL renegotiation feature. The DoS attack is based on the fact that an SSL handshake requires up to 10 times more processing power on the server than on the client. Therein lies the problem...and the ability to exploit it! When SSL renegotiation is enabled on the server, a user is allowed to send a renegotiation request any time he wants...and this request initiates a new handshake. Since it takes much fewer resources for a client to perform a handshake than a server, the client can request multiple handshakes per second and cause a DoS on the server side SSL interface. Therefore, if a malicious user requests multiple renegotiation requests it will exhaust the server’s resources and not allow any other user to establish a connection. This attack is different than a Distributed Denial of Service (DDoS) as it does not require a large amounts of network volume to exhaust the network connection. Instead, it exhausts the server resources from a single host requiring only a single TCP/IP socket. A single server can perform between 150-300 handshakes per second while a single client can request up to 1,000 handshakes per second. By the way, Openssl doesn't consider this DoS exploit an actual vulnerability (which is why they haven't done anything about it in their latest releases). Their response is that this exploit is a way of DoS'ing a server by requesting lots of expensive crypto operations. Any app that allows an operation like SSL renegotiation to an untrusted host is subject to resource exhaustion. They would say the correct answer is to restrict hosts if this is an issue. Note also that if the OS firewall is not enabled, any OS is subject to a DoS through resource exhaustion, even if it's just TCP port exhaustion. For more information on a great SSL renegotiation DoS countermeasure, see this DevCentral article. David Holmes and Jason Rahm teamed up to talk about the DoS vulnerability, and then they wrote an iRule that elegantly defeats the attack...really cool and useful stuff!! In addition, here's a quick video clip that talks about the same issue...F5 knocks it out of the park with this iRule stuff! F5 Security Vignette: SSL Renegotiation BIG-IP Configuration Now that we've talked through this SSL renegotiation thing, let's finish up with the features of the BIG-IP and how it handles SSL renegotiation. The following screenshot shows the different options for SSL renegotiation on the BIG-IP. You can find this screen by navigating to Local Traffic > Profiles > SSL > Client | Server. Notice that you can either enable or disable SSL renegotiation altogether. By default, it is enabled. Renegotiation controls (on a per-connection basis) how the BIG-IP responds to mid-stream SSL reconnection requests. When enabled, the system processes mid-stream SSL renegotiation requests. When disabled, the system terminates the connection, or ignores the request, depending on system configuration. The Renegotiate Period setting specifies the number of seconds from the initial connect time that the system renegotiates an SSL session. The options are "Specify" (in seconds) and "Indefinite" with "Indefinite" being the default. The "Indefinite" setting means that you never want the system to force an SSL renegotiation. The system will renegotiate the session after the specified period of time...that's why the "Indefinite" setting never forces a renegotiation. For example, setting the renegotiate period to 3600 seconds triggers session renegotiation at least once an hour. The Renegotiate Size setting forces the BIG-IP to renegotiate an SSL session after a specified number of megabytes of application data have been transmitted over the secure channel. The values for this setting are "Indefinite" and "Specify" (in megabytes) with "Indefinite" being the default. This setting follows the same premise as the Renegotiate Period but it uses data size to determine when it will force a renegotiation vice a period of time. The Renegotiate Max Record Delay setting forces the BIG-IP to terminate an SSL session after receiving the specified maximum number of SSL records. The number of records are counted while the BIG-IP system waits for the client to initiate a renegotiation. If the BIG-IP system receives more than the maximum number of SSL records, it closes the connection. The values for this setting are "Indefinite" and "Specify" (number of records). The default setting is "Specify" 10 records. Secure Renegotiation is a fairly new feature in the BIG-IP (not available prior to v10.2.3). This setting handles the RFC 5746 problem, and it allows the user to specify the method of secure renegotiation for SSL connections. The values for this setting are "Request," "Require," and "Require Strict" with "Require" being the default value for the Client-side SSL profile. The default value for the Server-side SSL profile depends on the BIG-IP version: in v10.2.3 and v10.2.4, the default value for the Server-side SSL profile is "Require" and the default value in v11.x is "Require Strict." The "Request" value specifies that the system simply requests secure renegotiation of SSL connections. The "Require" value specifies that the system requires secure renegotiation of SSL connections. In this mode, the system permits initial SSL handshakes from clients, but terminates renegotiations from unpatched clients. The "Require Strict" value specifies that the system requires strict secure renegotiation of SSL connections. In this mode, the system does not accept new SSL connections from unpatched clients. Within the context of the Server-side SSL profile, there is no behavioral difference between "Require" and "Require Strict." In either mode, initial SSL connections from the BIG-IP to unpatched servers will fail. Conclusion Well, I think that about does it for SSL Renegotiation. Come back for more great SSL discussion in our next article that will feature Server Name Indication (SNI). As always, if you have any questions (about SSL, iRules, or any other F5 technology), feel free to comment here or contact the DevCentral team directly. See you soon!18KViews3likes7CommentsClient SSL Authentication on BIG-IP as in-depth as it can go
Quick Intro In this article, I'm going to explain how SSL client certificate authentication works on BIG-IP and explain what actually happens during client authentication as in-depth as I can, showing the TLS headers on Wireshark. This article is about the client side of BIG-IP (Client SL profile) authenticating a client connecting to BIG-IP. The Topology For reference so we can follow Wireshark output: How to Configure Client Certificate Authentication on Client SSL profile Essentially, what we're doing here is making BIG-IP verify client's credentials before allowing the TLS handshake to proceed. However, such credentials are in the form of a client certificate. The way to do this is to configure BIG-IP by: Adding a CA file to Trusted Certificate Authorities (ca-file in tmsh) to validate client certificate Optionally adding same CA that signed client certificate to Advertised Certificate Authorities Enforcing Client Certificate validation by setting Client Certificate option on BIG-IP to require Optionally setting the Frequency of such checks if we don't want to stick to the defaults. I'll go through each option now. Adding CA file to Trusted Certificate Authorities We should add to Trusted Certificate Authorities a single certificate file (*.crt) with one CA or concatenated file with 2 or more CAs with the purpose of validating client certificate, i.e. confirming client's identity. Upon receiving client certificate, BIG-IP will go through this list of CAs and confirm client's identity. It also has another purpose which is to authenticate BIG-IP to client but it's out of the scope of this article. Optionally add CA file to Advertised Certificate Authorities Trusted Certificate Authoritiesexplicitly tells BIG-IP the CA or chain of CAs it will use to validate client certificate whereasAdvertised Certificate Authorities tells client in advance what kind of CA BIG-IP trusts so that client can make the decision about which certificate to send to BIG-IP: Why would we use Advertised Certificate Authorities? Let's imagine a situation where Client's application has more than one Client Certificate configured. How is it going to figure out which certificate to send to BIG-IP? That's where Advertised Certificate Authorities comes to rescue us! When we add our CA bundle to Advertised Certificate Authorities, we're telling BIG-IP to add it to a header field named Distinguished Names within Certificate Request message. I dedicated the Appendix section to show you more in-depth how changing Advertised Certificate Authority affects Certificate Request header. Configuring BIG-IP to enforce Client Certificate validation To enable client certificate authentication on BIG-IP we change Local Traffic››Profiles : SSL : Client›› Client Certificate to request: The default is set to ignore where client certificate authentication is disabled. If we truly want to enable client certificate validation we need to select require. The reason why is because request makes BIG-IP request a client certificate from the client but BIG-IP will not perform the validation to confirm if the certificate sent is valid in this mode. The following subsections explain each option. Ignore Client Certificate Authentication is disabled (the default). BIG-IP never sends Certificate Request to client and therefore client does not need to send its certificate to BIG-IP. In this case, TLS handshake proceeds successfully without any client authentication: pcap:ssl-sample-peer-cert-mode-ignore.pcap Wireshark filter used:frame.number == 5 or frame.number == 6 Request BIG-IP requests Client Certificate by sending Certificate Request message but does not check whether client certificate is valid which is not really client authentication, is it? This means that ca-file(Trusted Certificate Authorities in the GUI) will not be used to validate client certificate and we will consider any certificate sent to us to be valid. For example, inssl-sample-peer-cert-mode-request-with-no-client-cert-sent.pcapwe now see that BIG-IP sends aCertificate Requestmessage and client responds with aCertificatemessage this time: Because I didn't add any client certificate to my browser, it sent a blank certificate to BIG-IP. Again, BIG-IP did not perform any validation whatsoever, so TLS handshake proceeded successfully. We can then conclude that this setting only makes BIG-IP request client certificate and that's it. Require It behaves just like Request but BIG-IP also performs client certificate validation, i.e. BIG-IP will use CA we hopefully added to ca-file (Trusted Certificate Authorities in the GUI) to confirm if client certificate is valid. This means that if we don't add a CA to Trusted Certificate Authorities (ca-file in tmsh) then validation will fail. Setting the Frequency of Client Certificate Requests This setting specifies the frequency BIG-IP authenticates client by enabling/disabling TLS session resumption. It has only 2 options: once BIG-IP requests client certificate during first handshake and no longer re-authenticates client as long as TLS session is reused and valid. The way BIG-IP does it is by using Session Resumption/Reuse. During first TLS handshake from client, BIG-IP sends a Session ID to Client within Server Hello header and in subsequent TLS connections, assuming session ID is still in BIG-IP's cache and client re-sends it back to BIG-IP, then session will be resumed every time client tries to establish a TLS session (respecting cache timeout). First time client sends Client Hello with blank session ID as it's cache is empty and then it is assigned a Session ID by BIG-IP (409f...): pcap:ssl-sample-clientcert-auth-once-enabled.pcap Wireshark filter used:filter:!ip.addr == 172.16.199.254 and frame.number > 1 and frame.number < 7 Certificate Requestconfirms BIG-IP is trying to authenticate client. Notice Session ID BIG-IP sent to client is 409f7... Then when Client tries to go through another TLS handshake and sends above session ID in Client Hello (packet #70 below). BIG-IP then confirms session is being resumed by sending samesession IDin Server Hello back to client: Wireshark filter used:!ip.addr == 172.16.199.254 and frame.number > 66 and frame.number < 73 This resumed TLS handshake just means we will not go through full handshake and will no longer need to exchange keys, select ciphers or re-authenticate client as we're reusing those already negotiated in the full TLS handshake where we first received Session ID 409f... always BIG-IP requests client certificate, i.e. re-authenticates client at every handshake. On BIG-IP, this is accomplished by disabling session reuse which makes BIG-IP not to sendSession IDback to Client in the beginning and forcing a full TLS handshake every time. pcap:ssl-sample-clientcert-auth-always-enabled.pcap Wireshark filter used: !ip.addr == 172.16.199.254 and ((frame.number > 1 and frame.number < 7) or (frame.number > 74 and frame.number < 80)) Appendix: Understanding how Advertised Certificate Authority field affects Certificate Request header For this test, I've got the following: myCAbundle.crt: concatenation of root_ca.crt and ltm2.crt (signed by root_ca.crt) client_cert.crt: added to Firefox and signed by ltm2.crt I've also added myCAbundle.crt to Trusted Certificate Authorities so BIG-IP is able to verify that client_cert.crt is valid. For each test, I will use change Advertised Certificate Authorities so we can see what happens. We'll go through 3 tests here: Setting Advertised Certificate Authority to None Setting Advertised Certificate Authority to a certificate that didn't sign client cert Setting Advertised Certificate Authority to a bundle that signed client cert Setting Advertised Certificate Authority to None Note that even though no CA was advertised in Certificate Request message, BIG-IP still advertises Certificate typesandSignature Hash Algorithmsso that client knows in advance what kind of certificate (RSA, DSS or ECDSA) and hash algorithms BIG-IP supports in advance. If client certificate had not been signed using any of the certificate types and hashing algorithms listed then handshake would have failed. However, in this case validation is successful as we can see on frame #8 that client certificate is RSA type and hashed with SHA1: pcap: ssl-sample-advcert-none.pcap filter used: !ip.addr == 172.16.199.254 and frame.number > 1 and frame.number < 16 It's worth noting that Distinguished Names is NOT populated and has length of zero because we didn't attach a bundle to Advertised Certificate Authorities. In this case, it worked fine because my client browser had only one certificate attached, so it shouldn't cause a problem anyway. Setting Advertised Certificate Authority to a certificate that didn't sign client cert pcap: ssl-sample-advcert-default-firefox.pcap Wireshark filter used: None I've set Advertised Certificate Authority to default.crt as this is NOT the CA that signed client's certificate: The difference here when compared to None is that now we can see that Distinguished Names is now populated with the certificate I added (default.crt): However, even though I added the correct certificate to my Firefox browser, it sent a blank certificate instead. Why? That's because BIG-IP signalled in Distinguished Names that default.crt is the CA that signed the certificate BIG-IP is looking for and as Firefox doesn't have any certificate signed by default.crt, it just sent a blank certificate back to BIG-IP. Also, because BIG-IP is now performing proper validation, i.e. comparing whatever client certificate is sent to it with the CA list added to Trusted Certificate Authorities, it knows a blank certificate is not valid and terminates the TLS handshake with a Fatal Alert. Setting Advertised Certificate Authority to a bundle that signed client cert pcap: ssl-sample-advcert-ltm2chainedwithrootca.pcap filter used: !ip.addr == 172.16.199.254 and frame.number > 1 Now I've set Advertised Certificate Authority to the correct bundle that signed my client certificate: And indeed handshake succeeds because: BIG-IP advertises myCAbundle.crt in Certificate Request >> Distinguished Names header, as per Advertised Certificate Authority configuration By reading Distinguished Names field, Client correctly sends the correct client certificate back to BIG-IP BIG-IP correctly validates client certificate using myCAbundle configured on Trusted Certificate Authorities Hope this article provides some clarification about these mysterious TLS headers.15KViews10likes8CommentsIncrease DH key exchange to 2048
I'm trying to move from cipher lists in the ssl profile to cipher rules and groups in order to support TLS1.3 I would like to only enable strong cipher suites. So far I've found this list TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 So far I've come up with this string to reproduce the list: ECDHE+AES-GCM:DHE+AES-GCM:CHACHA20-POLY1305 Each time I test it the DHE+AES-GCM gets flagged because it is only 1024 bits. Removing it means removing a lot of clients from the compatibility list. After days of reseach I can't find the place to increase my DH group strength. Only a 5 year old article which says that I can't increase it. Does anyone know if it is possible to increase DH group strength in either 13.1.1 or 14.1.2, and where to do it?Solved12KViews0likes16CommentsSSL Handshake failed for TCP
We are seeing a ton of these messages in our logs. Several per minute from legit client IPs. However, the clients are not reporting any issues. SSL Handshake failed for TCP x.x.x.x:11555 -> x.x.x.x:443 These particular messages are NOT followed up a connection error message about an unsupported version as you might expect (for example: Connection error: ssl_hs_rxhello:7699: unsupported version (40)). I am trying to understand what is occurring. I did a pcap but was not able to get much out of it since there was a lot of normal traffic in there as well since these are good source IPs. I did not find any fatal handshake errors. Anything else I could look for in a pcap to see what is occurring? What other instances would you see a message like this? The frequency of the messages increase/decrease with peak and off peak times. The application is a typical IIS web app where the client uses a browser to access.12KViews0likes3CommentsDecrypting TLS traffic on BIG-IP
1 Introduction As soon as I joined F5 Support, over 5 years ago, one of the first things I had to learn quickly was to decrypt TLS traffic becausemost of our customers useL7 applications protectedby TLS layer. In this article, I will show 4 ways to decrypt traffic on BIG-IP, including thenew one just release in v15.xthat is ideal for TLS1.3 where TLS handshake is also encrypted. If that's what you want to know just skip totcpdump --f5 ssl optionsection as this new approach is just a parameter added to tcpdump. As this article is very hands-on, I will show my lab topology for the tests I performed and then every possible way I used to decrypt customer's traffic working for Engineering Services at F5. 2 Lab Topology This is the lab topology I used for the lab test where all tests were performed: Also, for every capture I issued the followingcurlcommand: Update: the virtual server's IP address is actually 10.199.3.145/32 2 The 4 ways to decrypt BIG-IP's traffic RSA private key decryption There are 3 constraints here: Full TLS handshake has to be captured CheckAppendix 2to learn how to to disable BIG-IP's cache RSA key exchange has to be used, i.e. no (EC)DHE CheckAppendix1to understand how to check what's key exchange method used in your TLS connection CheckAppendix 2to understandhow to prioritise RSA as key exchange method Private key has to be copied to Wireshark machine (ssldump command solves this problem) Roughly, to accomplish that we can setCache Sizeto 0 on SSL profile and remove (EC)DHE fromCipher Suites(seeAppendix 1for details) I first took a packet capture using :pmodifier to capture only the client and server flows specific to my Client's IP address (10.199.3.1): Note: The0.0interface will capture any forwarding plane traffic (tmm) andnnnis the highest noise to capture as much flow information as possible to be displayed on the F5 dissector header.For more details about tcpdump syntax, please have a look atK13637: Capturing internal TMM information with tcpdumpandK411: Overview of packet tracing with the tcpdump utility. Also,we need to make sure we capture the full TLS handshake. It's perfectly fine to captureresumed TLS sessionsas long as full TLS handshake has been previously captured. Initially, our capture is unencrypted as seen below: On Mac, I clicked onWireshark→Preferences: ThenProtocols→TLS→RSA keys listwhere we see a window where we can reference BIG-IP's (or server if we want to decrypt server SSL side) private key: Once we get there, we need to add any IP address of the flow we want Wireshark to decrypt, the corresponding port and the private key file (default.crtfor Client SSL profile in this particular lab test): Note:For Client SSL profile, this would be the private key onCertificate Chainfield corresponding to the end entity Certificate being served to client machines through the Virtual Server. For Server SSL profile, the private key is located on the back-end server and the key would be the one corresponding to the end entity Certificate sent in the TLSCertificatemessage sent from back-end server to BIG-IP during TLS handshake. Once we clickOK, we can see the HTTP decrypted traffic (in green): In production environment, we would normally avoid copying private keys to different machines soanother option is usessldumpcommand directly on the server we're trying to capture. Again, if we're capturing Client SSL traffic,ssldumpis already installed on BIG-IP. We would follow the same steps as before but instead of copying private key to Wireshark machine, we would simply issue this command on the BIG-IP (or back-end server if it's Server SSL traffic): Syntax:ssldump-r<capture.pcap>-k<private key.key>-M<type a name for your ssldump file here.pms>. For more details, please have a look atK10209: Overview of packet tracing with the ssldump utility. Inssldump-generated.pms, we should find enough information for Wireshark to decrypt the capture: Syntax:ssldump-r<capture.pcap>-k<private key.key>-M<type a name for your ssldump file here.pms>. For more details, please have a look atK10209: Overview of packet tracing with the ssldump utility. Inssldump-generated.pms, we should find enough information for Wireshark to decrypt the capture: After I clickedOK, we indeed see the decrypted http traffic back again: We didn't have to copy BIG-IP's private key to Wireshark machine here. iRules The only constraint here is that we should apply the iRule to the virtual server in question. Sometimes that's not desirable, especially when we're troubleshooting an issue where we want the configuration to be unchanged. Note: there is abugthat affects versions 11.6.x and 12.x that was fixed on 13.x. It records the wrong TLS Session ID to LTM logs. The workaround would be to manually copy the Session ID from tcpdump capture or to use RSA decryption as in previous example. You can also combine bothSSL::clientrandomandSSL::sessionidwhich isthe ideal: Reference: K12783074: Decrypting SSL traffic using the SSL::sessionsecret iRules command (12.x and later) Again, I took a capture usingtcpdumpcommand: After applying above iRule to our HTTPS virtual server and taking tcpdump capture, I see this on /var/log/ltm: To copy this to a *.pms file wecanuseon Wireshark we can use sed command (reference:K12783074): Note:If you don't want to overwrite completely the PMS file make sure youuse >> instead of >. The endresult would be something like this: As both resumed and full TLS sessions have client random value, I only had to copy CLIENT_RANDOM + Master secret to our PMS file because all Wireshark needs is a session reference to apply master secret. To decrypt file on Wireshark just go toWireshark→Preferences→Protocols→TLS→Pre-Master Key logfile namelike we did inssldumpsection and add file we just created: As seen on LTM logs,CLIENTSSL_HANDSHAKEevent captured master secret from our client-side connection andSERVERSSL_HANDSHAKEfrom server side. In this case, we should have both client and server sides decrypted, even though we never had access to back-end server: Notice added anhttpfilter to show you both client and and server traffic were decrypted this time. tcpdump --f5 ssl option This was introduced in 15.x and we don't need to change virtual server configuration by adding iRules. The only thing we need to do is to enabletcpdump.sslproviderdb variable which is disabled by default: After that, when we take tcpdump capture, we just need to add --f5 ssl to the command like this: Notice that we've got a warning message because Master Secret will be copied to tcpdump capture itself, so we need to be careful with who we share such capture with. I had to update my Wireshark to v3.2.+ and clicked onAnalyze→Enabled Protocols: And enable F5 TLS dissector: Once we open the capture, we can find all the information you need to create our PMS file embedded in the capture: Very cool, isn't it? We can then copy the Master Secretand Client Random values by right clicking like this: And then paste it to a blank PMS file. I first pasted the Client Random value followed by Master Secret value like this: Note: I manually typedCLIENT_RANDOMand then pasted both values for both client and server sides directly from tcpdump capture. The last step was to go toWireshark→Preferences→Protocols→TLSand add it toPre-master-Secret log filenameand clickOK: Fair enough! Capture decrypted on both client and server sides: I usedhttpfilter to display only decrypted HTTP packets just like in iRule section. Appendix 1 How do we know which Key Exchange method is being used? RSA private key can only decrypt traffic on Wireshark if RSA is the key exchange method negotiated during TLS handshake. Client side will tell the Server side which ciphers it support and server side will reply with the chosen cipher onServer Hellomessage. With that in mind, on Wireshark, we'd click onServer Helloheader underCipher Suite: Key Exchange and Authentication both come before theWITHkeyword. In above example, because there's only RSA we can say that RSA is used for both Key Exchange and Authentication. In the following example, ECDHE is used for key exchange and RSAfor authentication: Appendix 2 Disabling Session Resumption and Prioritising RSA key exchange We can set Cache Size to 0 to disableTLS session resumptionand change the Cipher Suites to anything that makes BIG-IP pick RSA for Key Exchange:12KViews12likes10CommentsSSL Profiles Part 1: Handshakes
This is the first in a series of tech tips on the F5 BIG-IP LTM SSL profiles. SSL Overview and Handshake SSL Certificates Certificate Chain Implementation Cipher Suites SSL Options SSL Renegotiation Server Name Indication Client Authentication Server Authentication All the "Little" Options SSL, or the Secure Socket Layer, was developed by Netscape back in the ‘90s to secure the transport of web content. While adopted globally, the standards body defined the Transport Layer Security, or TLS 1.0, a few years later. Commonly interchanged in discussions, the final version of SSL (v3) and the initial version of TLS (v1) do not interoperate, though TLS includes the capabality to downgrade to SSLv3 if necessary. Before we dive into the options within the SSL profiles, we’ll start in this installment with a look at the SSL certificate exchanges and take a look at what makes a client versus a server ssl profile. Server-Only Authentication This is the basic TLS handshake, where the only certificate required is on the serverside of the connection. The exchange is shown in Figure 1 below. In the first step. the client sends a ClientHello message containing the cipher suites (I did a tech tip a while back on manipulating profiles that has a good breakdown of the fields in a ClientHello message), a random number, the TLS version it supports (highest), and compression methods. The ServerHello message is then sent by the server with the version, a random number, the ciphersuite, and a compression method from the clients list. The server then sends its Certificate and follows that with the ServerDone message. The client responds with key material (depending on cipher selected) and then begins computing the master secret, as does the server upon receipt of the clients key material. The client then sends the ChangeCipherSpec message informing the server that future messages will be authenticated and encrypted (encryption is optional and dependent on parameters in server certificate, but most implementations include encryption). The client finally sends its Finished message, which the server will decrypt and verify. The server then sends its ChangeCipherSpec and Finished messages, with the client performing the same decryption and verification. The application messages then start flowing and when complete (or there are SSL record errors) the session will be torn down. Question—Is it possible to host multiple domains on a single IP and still protect with SSL/TLS without certificate errors? This question is asked quite often in the forums. The answer is in the details we’ve already discussed, but perhaps this isn’t immediately obvious. Because the application messages—such as an HTTP GET—are not received until AFTER this handshake, there is no ability on the server side to switch profiles, so the default domain will work just fine, but the others will receive certificate errors. There is hope, however. In the TLSv1 standard, there is an option called Server Name Indication, or SNI, which will allow you to extract the server name and switch profiles accordingly. This could work today—if you control the client base. The problem is most browsers don’t default to TLS, but rather SSLv3. Also, TLS SNI is not natively supported in the profiles, so you’ll need to get your hands dirty with some serious iRule-fu (more on this later in the series). Anyway, I digress. Client-Authenticated Handshake The next handshake is the client-authenticated handshake, shown below in Figure 2. This handshake adds a few steps (in bold above), inserting the CertificateRequest by the server in between the Certificate and ServerHelloDone messages, and the client starting off with sending its Certificate and after sending its key material in the ClientKeyExchange message, sends the CertificateVerify message which contains a signature of the previous handshake messages using the client certificate’s private key. The server, upon receipt, verifies using the client’s public key and begins the heavy compute for the master key before both finish out the handshake in like fashion to the basic handshake. Resumed Handshake Figure 3 shows the abbreviated handshake that allows the performance gains of not requiring the recomputing of keys. The steps passed over from the full handshake are greyed out. It’s after step 5 that ordinarily both server and client would be working hard to compute the master key, and as this step is eliminated, bulk encryption of the application messages is far less costly than the full handshake. The resumed session works by the client submitting the existing session ID from previous connections in the ClientHello and the server responding with same session ID (if the ID is different, a full handshake is initiated) in the ServerHello and off they go. Profile Context As with many things, context is everything. There are two SSL profiles on the LTM, clientssl and serverssl. The clientssl profile is for acting as the SSL server, and the serverssl profile is for acting as the SSL client. Not sure why it worked out that way, but there you go. So if you will be offloading SSL for your applications, you’ll need a clientssl profile. If you will be offloading SSL to make decisions/optimizations/inspects, but still require secured transport to your servers, you’ll need a clientssl and a serverssl profile. Figure 4 details the context. Conclusion Hopefully this background on the handshake process and the profile context is beneficial to the profile options we’ll cover in this series. For a deeper dive into the handshakes (and more on TLS), you can check out RFC 2246 and this presentation on SSL and TLS cryptography. Next up, we’ll take a look at Certificates.11KViews6likes6CommentsTLS Fingerprinting - a method for identifying a TLS client without decrypting
Hello, Kevin Stewart here. A while back someone asked an interesting question in the DevCentral forum about selecting a client SSL profile based on the device (ex. iOS, Android, Windows Phone). Normally you'd use a browser User-Agent HTTP header to identify the client user agent, but in this case, and based on the OSI model, you wouldn't be able to select an SSL profile (OSI layer 6) based on a User-Agent HTTP header (OSI layer 7), because at this point in time you don't yet have the layer 7 data - it's still encrypted. You could, however, use layer 3 or 4 data (IPs and ports), but that's generally not useful for identifying the client user agent. But there might still be a way... Lee Brotherston has discovered that during an SSL handshake, most client user agents (different browsers, Dropbox, Skype, etc.) will initiate an SSL handshake request in an ever-so-unique way. The ordered combination of TLS version, record TLS version, ciphersuites, compression options, list of extensions, elliptic curves and signature algorithms are all specific enough that you can actually build a signature based on that data, and the collection of signatures into a database. From that discovery Lee created a project called "tls-fingerprinting". Please check it out. Now certainly, a client's ClientHello could be modified to support different ciphersuites and other features, the same way you could spoof a User-Agent HTTP header. However this modification will often lower security by re-introducing previously unsupported options, or in many cases modification to the user agent's SSL parameters isn't easy or isn't possible. So given that we now have a new way to identify a user agent based on the client's ClientHello (the first message in the SSL handshake), I decided to re-visit the original DC forum request by integrating Lee's database into an iRules-based solution. The code example in the aforementioned thread just used the client's ciphersuite list, however, so today I'm going to expand on that and use all of the paramaters from the tls-fingerprinting database. Before we get started, I should mention two things: This article is going to be long (sorry about that), and We're going to break it down into a few phases, specifically Defining the values in the tls-fingerprinting signature Exporting and converting the tls-fingerprinting database to a BIG-IP external data group Creating a fingerprintTLS PROC iRule (name this "Library-Rule") Creating the caller iRule So let's get started. Defining the values in the tls-fingerprinting signature Here's an example signature entry in Lee's tls-fingerprinting database (JSON version): {"id": 0, "desc": "ThunderBird (v38.0.1 OS X)", "record_tls_version": "0x0301", "tls_version": "0x0303", "ciphersuite_length": "0x0016", "ciphersuite": "0xC02B 0xC02F 0xC00A 0xC009 0xC013 0xC014 0x0033 0x0039 0x002F 0x0035 0x000A", "compression_length": "1", "compression": "0x00", "extensions": "0x0000 0xFF01 0x000A 0x000B 0x0023 0x0005 0x000D 0x0015" , "e_curves": "0x0017 0x0018 0x0019" , "sig_alg": "0x0401 0x0501 0x0201 0x0403 0x0503 0x0203 0x0402 0x0202" , "ec_point_fmt": "0x00" } Broken down it looks like this: { "id": 0, "desc": "ThunderBird (v38.0.1 OS X)", "record_tls_version": "0x0301", "tls_version": "0x0303", "ciphersuite_length": "0x0016", "ciphersuite": "0xC02B 0xC02F 0xC00A 0xC009 0xC013 0xC014 0x0033 0x0039 0x002F 0x0035 0x000A", "compression_length": "1", "compression": "0x00", "extensions": "0x0000 0xFF01 0x000A 0x000B 0x0023 0x0005 0x000D 0x0015" , "e_curves": "0x0017 0x0018 0x0019" , "sig_alg": "0x0401 0x0501 0x0201 0x0403 0x0503 0x0203 0x0402 0x0202" , "ec_point_fmt": "0x00" } This is a pretty straight forward set of JSON key-value pairs. And if you're curious about what any of these values mean, I urge you to fire up Wireshark, open a browser to some HTTPS site, and then find a ClientHello message in the capture. You'll see all of these values and more, except for the first two, in that message. Our job then is to a) export the set of signatures to a BIG-IP external data group, and b) create an iRule that extracts all of these values from the client's ClientHello and compares those to the set of signatures in the data group. Of course iRules don't natively support JSON parsing, and while yes I could use iRulesLX for this, I decided to simply reformat the signatures in the data group to something more condusive to TCL iRules. Exporting and converting the tls-fingerprinting database to a BIG-IP external data group I don't really care about the "id" value, so I'll leave that out. And the "desc" field will be the value in the data group. The key will be the concatenation of all of the remaining fields. "signature_data" := "ThunderBird (v38.0.1 OS X)", I'm also going to remove the "0x" from the hex values, remove whitespace, and delimit each field with the plus (+) sign, so the resulting key for the above signature will look like this: 0301+0303+0016+C02BC02FC00AC009C013C01400330039002F0035000A+1+00+0000FF01000A000B00230005000D0015+001700180019+04010501020104030503020304020202+00 If any of the values don't exist (ex. the signature doesn't have a sig_alg value), that value is replaced with "@@@@" in the resulting key. Okay, so to convert the tls-fingerprinting database to a BIG-IP external data group, you have to: 1. Download it - the current JSON-based database is here: https://github.com/LeeBrotherston/tls-fingerprinting/blob/master/fingerprints/fingerprints.json. Copy that JSON data in whole to a local text file. The conversion script uses BASH, so you need a Linux or Mac box. I named the file 'fingerprint.db'. 2. Convert it - use the following BASH script to extract each of the fields from each of the signatures. I should warn you now that my sed/awk/grep foo isn't strong, so I borrowed a BASH JSON parser from here: https://gist.github.com/cjus/1047794 #!/bin/bash function jsonval () { ## description desc=`echo $1 | sed 's/\\\\\//\//g' | sed 's/[{}]//g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | sed 's/\"\:\"/\|/g' | sed 's/[\,]/ /g' | sed 's/\"//g' | grep -w "desc" |awk -F": " '{print $2}'` ## record_tls_version rect=`echo $1 | sed 's/\\\\\//\//g' | sed 's/[{}]//g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | sed 's/\"\:\"/\|/g' | sed 's/[\,]/ /g' | sed 's/\"//g' | grep -w "record_tls_version" |awk -F": " '{print $2}' |sed 's/0x//g'` if [ -z "$rect" ]; then rect="@@@@"; fi ## tls_version tlsv=`echo $1 | sed 's/\\\\\//\//g' | sed 's/[{}]//g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | sed 's/\"\:\"/\|/g' | sed 's/[\,]/ /g' | sed 's/\"//g' | grep -w "tls_version" |awk -F": " '{print $2}' |sed 's/0x//g'` if [ -z "$tlsv" ]; then tlsv="@@@@"; fi ## ciphersuite_length cipl=`echo $1 | sed 's/\\\\\//\//g' | sed 's/[{}]//g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | sed 's/\"\:\"/\|/g' | sed 's/[\,]/ /g' | sed 's/\"//g' | grep -w "ciphersuite_length" |awk -F": " '{print $2}' |sed 's/0x//g' |sed 's/ //g'` if [ -z "$cipl" ]; then cipl="@@@@"; fi ## ciphersuite ciph=`echo $1 | sed 's/\\\\\//\//g' | sed 's/[{}]//g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | sed 's/\"\:\"/\|/g' | sed 's/[\,]/ /g' | sed 's/\"//g' | grep -w "ciphersuite" |awk -F": " '{print $2}' |sed 's/0x//g' |sed 's/ //g'` if [ -z "$ciph" ]; then tlsv="ciph"; fi ## compression_length coml=`echo $1 | sed 's/\\\\\//\//g' | sed 's/[{}]//g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | sed 's/\"\:\"/\|/g' | sed 's/[\,]/ /g' | sed 's/\"//g' | grep -w "compression_length" |awk -F": " '{print $2}'` if [ -z "$coml" ]; then coml="@@@@"; fi ## compression comp=`echo $1 | sed 's/\\\\\//\//g' | sed 's/[{}]//g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | sed 's/\"\:\"/\|/g' | sed 's/[\,]/ /g' | sed 's/\"//g' | grep -w "compression" |awk -F": " '{print $2}' |sed 's/0x//g' |sed 's/ //g'` if [ -z "$comp" ]; then comp="@@@@"; fi ## extensions exte=`echo $1 | sed 's/\\\\\//\//g' | sed 's/[{}]//g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | sed 's/\"\:\"/\|/g' | sed 's/[\,]/ /g' | sed 's/\"//g' | grep -w "extensions" |awk -F": " '{print $2}' |sed 's/0x//g' |sed 's/ //g'` if [ -z "$exte" ]; then exte="@@@@"; fi ## e_curves ecur=`echo $1 | sed 's/\\\\\//\//g' | sed 's/[{}]//g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | sed 's/\"\:\"/\|/g' | sed 's/[\,]/ /g' | sed 's/\"//g' | grep -w "e_curves" |awk -F": " '{print $2}' |sed 's/0x//g' |sed 's/ //g'` if [ -z "$ecur" ]; then ecur="@@@@"; fi ## sig_alg siga=`echo $1 | sed 's/\\\\\//\//g' | sed 's/[{}]//g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | sed 's/\"\:\"/\|/g' | sed 's/[\,]/ /g' | sed 's/\"//g' | grep -w "sig_alg" |awk -F": " '{print $2}' |sed 's/0x//g' |sed 's/ //g'` if [ -z "$siga" ]; then siga="@@@@"; fi ## ec_point_fmt ecfp=`echo $1 | sed 's/\\\\\//\//g' | sed 's/[{}]//g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | sed 's/\"\:\"/\|/g' | sed 's/[\,]/ /g' | sed 's/\"//g' | grep -w "ec_point_fmt" |awk -F": " '{print $2}' |sed 's/0x//g' |sed 's/ //g'` if [ -z "$ecfp" ]; then ecfp="@@@@"; fi echo "\"$rect+$tlsv+$cipl+$ciph+$coml+$comp+$exte+$ecur+$siga+$ecfp\" := \"$desc\"," } IFS=} for i in `cat fingerprint.db`; do jsonval $i done Create this BASH script however you like (VI, VIM, Joe, Nano, whatever), save it, chmod it so that it'll execute ('chmod 755 parser.sh'), and then run it ('./parser.sh'). It'll just echo the reformatted signatures to the screen, so you'll want to capture that as a file ('./parser.sh > fingerprint.dg'). It's also be a little slow, again due to my aggregious lack of sed/awk/grep (and regex) foo, but it should still finish in less than a minute. 3. Import it - now go to the BIG-IP management UI, and under System - File Management - Data Group File List, click Import. Choose your reformatted text file, give it a meaningful name (ex. fingerprint_db), select "String" as the File Contents type, and use the same name (ex. fingerprint_db) in the Data Group Name field. On a v12 BIG-IP this will auto-create the local data group. On earlier systems you'll need to go manually create the local data group object that points to this external data group. Creating a fingerprintTLS PROC iRule So now that we've reformatted and imported the fingerprintTLS database, let's build the iRule to parse out the data from the client's ClientHello. I should also warn you that this process requires a lot of binary manipulation, so please don't try to ingest it all at once if you're new to iRules. I'm building this iRule as a separate PROC that other data plane iRules can call. It won't be directly attached to a virtual server. ## Library-Rule ## TLS Fingerprint Procedure ################# ## ## Author: Kevin Stewart, 12/2016 ## Derived from Lee Brotherston's "tls-fingerprinting" project @ https://github.com/LeeBrotherston/tls-fingerprinting ## Purpose: to identify the user agent based on unique characteristics of the TLS ClientHello message ## Input: ## Full TCP payload collected in CLIENT_DATA event of a TLS handshake ClientHello message ## Record length (rlen) ## TLS outer version (outer) ## TLS inner version (inner) ## Client IP ## Server IP ############################################## proc fingerprintTLS { payload rlen outer inner clientip serverip } { ## The first 43 bytes of a ClientHello message are the record type, TLS versions, some length values and the ## handshake type. We should already know this stuff from the calling iRule. We're also going to be walking the ## packet, so the field_offset variable will be used to track where we are. set field_offset 43 ## The first value in the payload after the offset is the session ID, which may be empty. Grab the session ID length ## value and move the field_offset variable that many bytes forward to skip it. binary scan ${payload} @${field_offset}c sessID_len set field_offset [expr {${field_offset} + 1 + ${sessID_len}}] ## The next value in the payload is the ciphersuite list length (how big the ciphersuite list is. We need the binary ## and hex values of this data. binary scan ${payload} @${field_offset}S cipherList_len binary scan ${payload} @${field_offset}H4 cipherList_len_hex set cipherList_len_hex_text ${cipherList_len_hex} ## Now that we have the ciphersuite list length, let's offset the field_offset variable to skip over the length (2) bytes ## and go get the ciphersuite list. Multiple by 2 to get the number of appropriate hex characters. set field_offset [expr {${field_offset} + 2}] set cipherList_len_hex [expr {${cipherList_len} * 2}] binary scan ${payload} @${field_offset}H${cipherList_len_hex} cipherlist ## Next is the compression method length and compression method. First move field_offset to skip past the ciphersuite ## list, then grab the compression method length. Then move field_offset past the length (2) bytes and grab the ## compression method value. Finally, move field_offset past the compression method bytes. set field_offset [expr {${field_offset} + ${cipherList_len}}] binary scan ${payload} @${field_offset}c compression_len #set field_offset [expr {${field_offset} + ${compression_len}}] set field_offset [expr {${field_offset} + 1}] binary scan ${payload} @${field_offset}H[expr {${compression_len} * 2}] compression_type set field_offset [expr {${field_offset} + ${compression_len}}] ## We should be in the extensions section now, so we're going to just run through the remaining data and ## pick out the extensions as we go. But first let's make sure there's more record data left, based on ## the current field_offset vs. rlen. if { [expr {${field_offset} < ${rlen}}] } { ## There's extension data, so let's go get it. Skip the first 2 bytes that are the extensions length set field_offset [expr {${field_offset} + 2}] ## Make a variable to store the extension types we find set extensions_list "" ## Pad rlen by 1 byte set rlen [expr ${rlen} + 1] while { [expr {${field_offset} <= ${rlen}}] } { ## Grab the first 2 bytes to determine the extension type binary scan ${payload} @${field_offset}H4 ext ## Store the extension in the extensions_list variable append extensions_list ${ext} ## Increment field_offset past the 2 bytes of the extension type set field_offset [expr {${field_offset} + 2}] ## Grab the 2 bytes of extension lenth binary scan ${payload} @${field_offset}S ext_len ## Increment field_offset past the 2 bytes of the extension length set field_offset [expr {${field_offset} + 2}] ## Look for specific extension types in case these need to increment the field_offset (and because we need their values) switch $ext { "000b" { ## ec_point_format - there's another 1 byte after length ## Grab the extension data binary scan ${payload} @[expr {${field_offset} + 1}]H[expr {(${ext_len} - 1) * 2}] ext_data set ec_point_format ${ext_data} } "000a" { ## elliptic_curves - there's another 2 bytes after length ## Grab the extension data binary scan ${payload} @[expr {${field_offset} + 2}]H[expr {(${ext_len} - 2) * 2}] ext_data set elliptic_curves ${ext_data} } "000d" { ## sig_alg - there's another 2 bytes after length ## Grab the extension data binary scan ${payload} @[expr {${field_offset} + 2}]H[expr {(${ext_len} - 2) * 2}] ext_data set sig_alg ${ext_data} } default { ## Grab the otherwise unknown extension data binary scan ${payload} @${field_offset}H[expr {${ext_len} * 2}] ext_data } } ## Increment the field_offset past the extension data length. Repeat this loop until we reach rlen (the end of the payload) set field_offset [expr {${field_offset} + ${ext_len}}] } } ## Now let's compile all of that data. set cipl [string toupper ${cipherList_len_hex_text}] set ciph [string toupper ${cipherlist}] set coml ${compression_len} set comp [string toupper ${compression_type}] if { ( [info exists extensions_list] ) and ( ${extensions_list} ne "" ) } { set exte [string toupper ${extensions_list}] } else { set exte "@@@@" } if { ( [info exists elliptic_curves] ) and ( ${elliptic_curves} ne "" ) } { set ecur [string toupper ${elliptic_curves}] } else { set ecur "@@@@" } if { ( [info exists sig_alg] ) and ( ${sig_alg} ne "" ) } { set siga [string toupper ${sig_alg}] } else { set siga "@@@@" } if { ( [info exists ec_point_format] ) and ( ${ec_point_format} ne "" ) } { set ecfp [string toupper ${ec_point_format}] } else { set ecfp "@@@@" } ## Initialize the match variable set match "" ## Now let's build the fingerprint string and search the database set fingerprint_str "${outer}+${inner}+${cipl}+${ciph}+${coml}+${comp}+${exte}+${ecur}+${siga}+${ecfp}" ## Un-comment this line to display the fingerprint string in the LTM log for troubleshooting ## log local0. "${clientip}-${serverip}: fingerprint_str = ${fingerprint_str}" if { [class match ${fingerprint_str} equals fingerprint_db] } { ## Direct match set match [class match -value ${fingerprint_str} equals fingerprint_db] } elseif { not ( ${ciph} starts_with "C0" ) and not ( ${ciph} starts_with "00" ) } { ## Hmm.. there's no direct match, which could either mean a database entry doesn't exist, or Chrome (and Opera) are adding ## special values to the cipherlist, extensions list and elliptic curves list. ## ex. 9A9A, 5A5A, EAEA, BABA, etc. at the beginning of the cipherlist ## Let's strip out these anomalous values and try the match again. ## Substract 2 bytes from cipherlist length set cipl [format %04x [expr [expr 0x${cipl}] - 2]] ## Subtract 2 bytes from the front of the cipher list set ciph [string range ${ciph} 4 end] ## Subtract 2 bytes from the front of the extensions list set exte [string range ${exte} 4 end] ## There might be an additional random set in the string that needs to be removed (pattern is "(.)A\1A") regsub {(.)A\1A} ${exte} "" exte ## If the above regsub doesn't work, try the following: #regsub {(\wA)\1} ${exte} "" exte ## Subtract 2 bytes from the front of the elliptic curves list set ecur [string range ${ecur} 4 end] ## Rebuild the fingerprint string set fingerprint_str "${outer}+${inner}+${cipl}+${ciph}+${coml}+${comp}+${exte}+${ecur}+${siga}+${ecfp}" if { [class match ${fingerprint_str} equals fingerprint_db] } { ## Guess match set match [class match -value ${fingerprint_str} equals fingerprint_db] } else { ## No match set match "" } } ## Return the matching user agent string return ${match} } The PROC requires as input the full TCP payload (of the ClientHello message), the record length (extracted from the ClientHello message), the "outer" record TLS version and "inner" TLS version (also extracted form the ClientHello message). Using these values the PROC basically walks the payload looking for each of the required values (ciphersuite length, ciphersuite list, compression length, compression list, extensions list, elliptic curves, signature algorithms, and ec point formats). If any value doesn't exist in the payload (ex. the ClientHello doesn't contain a Sig_Alg field), that value is replaced with "@@@@". Once all of the values are found, the fingerprint string is created and used to search the data group. If there's a match, the user agent string (ex. ThunderBird (v38.0.1 OS X)) is returned to the caller. While testing this I noticed that newer versions of Chrome and Opera added what looked like "markers" to the ciphersuite list, extensions list, and elliptic curves list (ex. 9A9A, 5A5A, EAEA, BABA - always some alphanumeric value, followed by 'A', and repeated.). A cursory search didn't explain what these are, so maybe someone will know and report back. In the meantime, I added a "guess" function that removed these markers and tried the data group search again. All of the desktop browser testing (including Chrome and Opera) did get an accurate match with either the direct or guessed fingerprint, so I'll leave that in there until I find a better way to handle the markers. Creating the caller iRule The only thing left to do is to create the caller iRule. This iRule only needs to detect an SSL/TLS ClientHello, and then pass that to the fingerprint PROC. This is just a stub iRule to show the proper implementation. Once you've determined a TCP packet is an SSL/TLS handshake ClientHello, call the PROC and then do something useful with the resulting user agent string, like switch the client SSL profile. when CLIENT_ACCEPTED { ## Collect the TCP payload TCP::collect } when CLIENT_DATA { ## Get the TLS packet type and versions if { ! [info exists rlen] } { binary scan [TCP::payload] cH4ScH6H4 rtype outer_sslver rlen hs_type rilen inner_sslver if { ( ${rtype} == 22 ) and ( ${hs_type} == 1 ) } { ## This is a TLS ClientHello message (22 = TLS handshake, 1 = ClientHello) ## Call the fingerprintTLS proc set fingerprint [call Library-Rule::fingerprintTLS [TCP::payload] ${rlen} ${outer_sslver} ${inner_sslver} [IP::client_addr] [IP::local_addr]] ### Do Something here ### log local0. "match = ${fingerprint}" ### Do Something here ### } } # Collect the rest of the record if necessary if { [TCP::payload length] < $rlen } { TCP::collect $rlen } ## Release the paylaod TCP::release } What happens if there's no match? Yes, there are some caveats... It's safe to say that the tls-fingerprinting database isn't all inclusive. In fact it's FAR FROM COMPLETE and not always exact.I found, for example, that my version of Dropbox on a Win7 box (v16.4.30) doesn't make a match. It's nearly impossible to have the signature for every unique user agent every created, and all of the variations and versions of that agent. But what the database does have is the signatures for most browsers, so at the very least it makes for a nice way to whitelist browsers (vs. other agents). It also doesn't technically resolve the question in the original DC forum thread. The question was how to identify the device (ie. iOS, Android, Windows Phone), and for that you'd need some specific agent loaded on the device (not a browser) that could report that information. Mobile device management (MDM) solutions are particularly good at that sort of thing. The browser, Dropbox or other user agent on the mobile device may not specifically report the device (ex. "for iOS"). Some do, but I've found that most don't. At the end of this aticle I've included a few signatures that I found in my testing that aren't in the database. If your curious, uncomment thelog local0. "${clientip}-${serverip}: fingerprint_str = ${fingerprint_str}"line in the fingerprintTLS PROC and then tail the LTM log. The caller iRule is already logging the returned user agent string, so if that is empty, you'll see the empty match in the log (match =), preceded by the unmatched signature. Where this project may be most useful is in outbound traffic management, where you want to decrypt and inspect the Internet-bound traffic, but cannot decrypt some user agents becuase of things like cerificate pinning. Since the pinning decision happens at the client, the only other recourse is to bypass decryption and inspection based on the destination host name or IP address, which can be a tedious thing to manage. TLS fingerprinting might allow you to simply decrypt and inspect for the user agents that you know aren't affected by pinning, specifically browsers. You'll potentially miss some things that you could have decrypted, but you'll save yourself the burden of managing an ever-growing list of pinner exclusions. And on a final note, binary iRule manipulation is a very CPU-intensive thing to do. I could have very simply converted the raw payload to one long hex string (once) and walked that with string tools. I'll update the code when I have some time. Thanks. - Kevin Additional Signatures "0301+0303+0028+C02BC02F009ECC14CC13C00AC009C013C014C007C011003300320039009C002F0035000A00050004+1+00+0000FF01000A000B0023755000050012000D+001700180019+04010501020104030503020304020202+00" := "Dropbox", "0301+0303+0028+C02BC02F009ECC14CC13C00AC009C013C014C007C011003300320039009C002F0035000A00050004+1+00+0000FF01000A000B002300050012000D+001700180019+04010501020104030503020304020202+00" := "Dropbox", "0301+0303+001A+C030C028C014C02FC027C013009F006B0039009E0067003300FF+1+00+0000000B000A0023000D+00170019001C001B0018001A0016000E000D000B000C0009000A+060106020603050105020503040104020403030103020303020102020203+000102" := "Dropbox", "0301+0303+0094+C030C02CC032C02EC02FC02BC031C02D00A500A300A1009F00A400A200A0009EC028C024C014C00AC02AC026C00FC005006B006A006900680039003800370036C027C023C013C009C029C025C00EC00400670040003F003E0033003200310030C012C008C00DC00300880087008600850045004400430042001600130010000D009D009C003D0035003C002F00840041000A00FF+1+00+000B000A0023000D0015+00170019001C001B0018001A0016000E000D000B000C0009000A+060106020603050105020503040104020403030103020303020102020203+000102" := "Dropbox", "0301+0303+0028+C02BC02CC02FC030009E009FC009C00AC013C01400330039C007C011009C009D002F0035000500FF+1+00+0000000B000A0023000D+000E000D0019000B000C00180009000A00160017000800060007001400150004000500120013000100020003000F00100011+060106020603050105020503040104020403030103020303020102020203+000102" := "Android Google API Access", "0301+0303+001E+CC14CC13C02BC02F009EC00AC0140039C009C0130033009C0035002F000A+1+00+FF01000000170023000D0005337400120010000B000A+00170018+0601060305010503040104030301030302010203+00" := "Chrome 47.0.2526.83", "0301+0303+001E+CC14CC13C02BC02F009EC00AC0140039C009C0130033009C0035002F000A+1+00+FF01000000170023000D0005337400120010000B000A+00170018+0601060305010503040104030301030302010203+00" := "Chrome 48.0.2564.97", "0301+0303+001E+CC14CC13C02BC02F009EC00AC0140039C009C0130033009C0035002F000A+1+00+FF01000000170023000D00053374001200107550000B000A0015+00170018+0601060305010503040104030301030302010203+00" := "Chrome 48.0.2564.97", "0301+0303+0022+CCA9CCA8CC14CC13C02BC02FC02CC030C009C013C00AC014009C009D002F0035000A+1+00+FF01000000170023000D0005001200107550000B000A0018+001D00170018+06010603050105030401040302010203+00" := "Android Silk Browser", "0301+0303+0022+CCA9CCA8CC14CC13C02BC02FC02CC030C009C013C00AC014009C009D002F0035000A+1+00+FF01000000170023000D0005001200107550000B000A00180015+001D00170018+06010603050105030401040302010203+00" := "Android Silk Browser" "0303+0303+0038+C02CC02BC030C02F009F009EC024C023C028C027C00AC009C014C01300390033009D009C003D003C0035002F000A006A0040003800320013+1+00+0005000A000B000D0023001000175500FF01+001D00170018+040105010201040305030203020206010603+00" := "Internet Explorer 11.447.14393.0(Win 10)", "0301+0303+0022+C02BC02FC02CC030CCA9CCA8CC14CC13C009C013C00AC014009C009D002F0035000A+1+00+FF0100170023000D0005001200107550000B000A+001D00170018+06010603050105030401040302010203+00" := "Chrome 55.0.2883.87",10KViews3likes8Comments