F5 SIRT
70 TopicsWAF evasion techniques for Command Injection
Let’s talk about Command Injection; I’m going to talk about this specifically from the perspective of Web Application Firewalls (like BIG-IP Advanced WAF, BIG-IP Next WAF, F5 Distributed Cloud WAF and so on) but these concepts are generally applicable anywhere user-input is used to construct commands run on the system, directly or indirectly. So, what is Command Injection? To quote OWASP, who put it very nicely: Command injection is an attack in which the goal is execution of arbitrary commands on the host operating system via a vulnerable application. Command injection attacks are possible when an application passes unsafe user supplied data (forms, cookies, HTTP headers etc.) to a system shell. In this attack, the attacker-supplied operating system commands are usually executed with the privileges of the vulnerable application. Command injection attacks are possible largely due to insufficient input validation. This attack differs from Code Injection, in that code injection allows the attacker to add their own code that is then executed by the application. In Command Injection, the attacker extends the default functionality of the application, which execute system commands, without the necessity of injecting code. Like I say, in this case I’m going to talk about command injection to web applications, but they can happen in almost any piece of software that works on untrusted user input. Perhaps the most famous example of a command injection vulnerability is Shellshock, a suite of vulnerabilities in the Unix Bash shell and if you needed any proof that they can be hard things to find as a defender, Shellshock lived, undiscovered (or at least undisclosed, we’ve no way of proving that no malicious entities knew of the bug!) for 25 years from 1989 to 2014, in one of the most widely used pieces of software in the world. The original Shellshock vulnerability involved a maliciously crafted environment variable containing (malicious) commands after a function definition, e.g. env x=’() { :;}; echo vulnerable’ bash -c “echo test” On a vulnerable system, running the above commands would display “vulnerable” because of Bash continuing to execute the (injected) commands following the function definition. Injecting a command here requires the"| use of two specific characters plus the command, the semi-colon and space characters. If you imagine a web application passing commands to bash on a vulnerable system, you’ll see that it would be possible to block this attack simply by blocking requests containing semi-colon or space (or indeed having a signature for the full function definition and trailing semi-colon of “{ :;};”) Bypassing protections Any time there is a WAF in front of a vulnerable system – and sometimes even when there isn’t – an attacker must try to evade the rules preventing them from simply injecting their chosen command. You’ll often see this when attackers or scanners are looking for SQL injection vulnerabilities in web applications, replacing characters like ‘ with %27 or the space with %20 (and many other tricks), or using chunks of existing text with the SUBSTRING() function to construct queries without having to use the actual text. Many of the same tricks work for command injection vulnerabilities, and I’d like to talk about a specific example here because it’s one I hadn’t considered until it turned up in some real life traffic.. Bypassing WAF signatures using Environment Variables Remember I just said you could construct SQL queries using sub-strings of existing text? Well, if your target system is Windows-based and you know there’s a command injection vulnerability but you’re unable to exploit it due to character blocks or similar restrictions, then good news! Windows environment variables might be what you’re looking for.. Environment variables exist in most operating systems, and Microsoft ones are no exception – they date back to DOS and were one of the enhancements Microsoft brought to the table over and above CP/M (unlike the 8.3 filenames, which came right from CP/M!); their behaviour has been pretty much the same throughout, and there have always been a number of ‘default’ environment variables like the PATH, TMP & TEMP. Current versions of Windows add a number of additional default environment variables like PROGRAMDATA, PROGRAMFILES etc. Windows also allows the shell to return just a part of the environment variable value using the following syntax: %VARIABLE:~start_pos,end_pos% How is this useful to us, you ask? Let’s say you know you can inject a command, but you need a space in your command line; you want to inject “ping 127.0.0.1” but the space is dropped or the request is blocked by a WAF looking for “ping <IP>”, well then you just need an environment variable you know will have a space in it! %PROGRAMFILES%, by default, is going to be set to C:\Program Files on most systems, which has a space right there in the middle! All we need to do to get to it is use it as %PROGRAMFILES:~10,1%, for example: ping%PROGRAMFILES:~10,1%127.0.0.1 Go ahead, fire up a command prompt, and try it out! You could even construct the whole command that way: %PROGRAMFILES:~3,1%%SYSTEMROOT:~4,2%%PROGRAMFILES:~6,1%%PROGRAMFILES:~10,1%127.0.0.1 Again, fire up a command prompt and give that a try! Protect against bypasses with BIG-IP Advanced WAF Now here’s the good news: ASM includes signatures, by default, for all of those useful Windows environment variables (and the same for many other systems, too), so if you were to try the above on a vulnerable system with the right signatures in the policy, you’d still be blocked – like this: All these signatures are part of the Predictable Resource Location Signatures signature set, so you’ll want to make sure you either have all signatures of Medium or above, or at least this set assigned to your policy: Summary Command Injection is a huge topic, much bigger than I can talk about in one blog post here, but hopefully this shows you one way an attacker might try to evade protection in front of a vulnerable Windows system, and some ways in which you can protect it — BIG-IP Advanced WAF or F5 Distributed Cloud WAF both have signatures for this kind of evasion.284Views2likes0CommentsEnhancing Software Security with Rust: A Solution to Common Vulnerabilities
Introduction The digital landscape is continually evolving, with cybersecurity threats growing both in sophistication and number. Among these threats, memory safety vulnerabilities stand out, contributing to a significant portion of software security issues today. Supported by guidance from CISA, NSA, and many other security minded individuals, there is an urgent need for programming practices that inherently mitigate memory safety risks. Addressing Memory Safety with Rust Rust is an open-source programming language renowned for its dedication to safety and performance. It effectively addresses common challenges related to memory safety and concurrency without sacrificing execution speed. In this article, we will explore the top three Common Weakness Enumerations (CWEs) from the 2023 Known Exploited Vulnerabilities list: Use After Free, Heap-based Buffer Overflow, and Out-of-bounds Write. All these CWEs directly relate to memory safety problems. Throughout this article, we will demonstrate how Rust’s unique capabilities serve as effective safeguards against these widespread concerns. Note: While Rust also mitigates other critical issues such as double-free, dangling pointers, and concurrency issues like race conditions, deadlocks, and improper synchronization, these will not be covered in detail in this article. CWE-416: Use After Free This vulnerability occurs when a program continues to use a memory location after it has been freed, potentially leading to application crashes or in more severe scenarios, arbitrary code execution. Languages that require manual memory management, such as C and C++, are typically vulnerable to this issue, as developers must explicitly manage memory allocation and deallocation. Rust uniquely addresses CWE-416 through itsownership, borrowing, and lifetimes systems, catching potential vulnerabilities at compile time. Ownership rules enforce that each piece of data is owned by a single entity. When this owner or piece of data goes out of scope, Rust automatically deallocates the memory associated with it, thereby eliminating the risk of accessing freed memory. Borrowingallows functions to access data via references without taking ownership, a process carefully scrutinized by the borrow checker. This component of the compiler ensures that all borrowed references adhere strictly to lifetime rules, preventing them from outliving the data they reference, thereby avoiding use-after-free vulnerabilities. Lifetimes specify the scope for which a reference is valid, enabling the compiler to track and manage the lifespan of data throughout the program. By requiring explicit lifetime annotations where necessary, Rust enforces a clear contract for how long data can be safely borrowed, further strengthening its memory safety by preventing dangling references that could lead to vulnerabilities. CWE-122: Heap-based Buffer Overflow Heap-based buffer overflows occur when data exceeds its allocated memory in the heap, potentially allowing attackers to read or write memory they shouldn't have access to. This can result in crashing the application or enabling arbitrary code execution. Such vulnerabilities are particularly prevalent in languages like C and C++, which do not automatically enforce bounds checking. Rust effectively addresses CWE-122 through multiple security measures, including a type system, the principle of immutability by default, and robust memory safety abstractions. Type systems are critical for security, and Rust's system exemplifies this by being both statically and strongly typed. Static typing ensures all data types are defined before runtime, allowing the compiler to catch type errors early and mitigate related vulnerabilities. Strong typing in Rust requires explicit type conversions, guarding against unsafe coercions that could lead to issues like buffer overflows. Additionally, Rust enforces runtime bounds checking, which actively prevents heap-based buffer overflows and out-of-bounds writes by causing errors to panic rather than fail silently or behave unpredictably. Together, these features not only enhance security by enforcing strict type safety and data integrity but also by ensuring reliable and predictable error handling. Immutability by Default ensures that all data is immutable unless explicitly declared mutable. This design significantly reduces the risk of unintended data modifications that could lead to buffer overflows. By default, this immutability prevents many common programming errors associated with memory corruption. Memory Safety Abstractions provide high-level abstractions such as Vec<T> for managing dynamic arrays and Box<T> for smart pointers. These abstractions come with built-in bounds checking, which are enforced at runtime. When data operations exceed their allocated bounds, Rust's approach ensures that these operations result in controlled runtime panics, thus preventing unsafe memory access and preserving application integrity. Additionally, Rust promotes using iterators when working with collections. Iterators are both safe and efficient because they abstract away the need for manual bounds checking. This not only simplifies the code but also eliminates a common source of errors associated with direct index access, further enhancing safety and performance. CWE-787: Out-of-bounds Write This vulnerability involves writing data past the bounds of allocated memory, which can corrupt data, crash the application, or lead to code execution. It predominantly affects languages like C and C++ where bounds checking is not enforced automatically by the language, requiring manual oversight by developers. Rust addresses CWE-787: Out-of-bounds Write through its robust memory safety protocols, including automatic bounds checking for all memory write operations. This ensures that data stays within safe operational limits at both compilation and runtime stages, preventing potential security breaches. Additionally, features like the Option enum and fearless concurrency further safeguard against out-of-bounds writes by enforcing strict data handling and thread-safe access. Automatic bounds checking for all memory write operations, effectively preventing data from being written outside allocated segments. This safety measure operates during both compilation and runtime, where Rust ensures safe failure modes through structured error handling and panics rather than allowing undefined behavior. Option enum is special in Rust and its use ensures proper management of data safely, helping developers avoid The Billion Dollar Mistake. Unlike many other languages, Rust does not have null values for any data types and using the Option enum requires developers to explicitly handle cases of Some (data present) and None (data absent), promoting deliberate and safe data access patterns. This forces developers to handle cases which may otherwise go undefined in other languages. Fearless Concurrencyis another defining feature of Rust that guarantees thread-safe data access, effectively eliminating the risk of data races that could lead to out-of-bounds writes. This is achieved through Rust’s ownership and borrowing rules (described earlier), which ensure that data is accessed by only one thread at a time unless explicitly shared in a thread-safe manner. By leveraging these strict concurrency controls, Rust allows developers to build highly concurrent applications without the typical safety compromises seen in other languages, enhancing both performance and security and avoiding difficult to detect and reproduce defects. Conclusion The future of programming, particularly in systems and kernel development, is trending towards languages that provide strong memory safety guarantees. Rust's integration into system programming and even parts of the Linux kernel highlights a significant shift in software development paradigms. While Rust represents the future of secure programming, it's crucial to recognize the enduring legacy of languages like C. The Linux kernel and widely-used software such as OpenSSL and NGINX are predominantly written in C, illustrating that an immediate wholesale transition to Rust across all development sectors isn't practical. However, as we move forward, Rust's role in fostering more secure software is poised to expand with its focus on memory safety becoming a cornerstone of modern system software. The adoption of memory-safe languages like Rust isn't just about addressing current vulnerabilities; it's about reshaping software development practices to prioritize security from the ground up. This evolution marks a future where software inherently withstands a wide range of cybersecurity threats, greatly enhancing the resilience of our digital infrastructure against new challenges.157Views1like0CommentsCoordinated Vulnerability Disclosure: A Balanced Approach
The world of vulnerability disclosure encompasses, and affects, many different parties – security researchers, vendors, customers, consumers, and even random bystanders who may be caught in the blast radius of a given issue. The security professionals who manage disclosures must weigh many factors when considering when and what to disclose. There are risks to disclosing an issue when there is no fix yet available, possibly making more malicious actors aware of the issue when those affected have limited options. Conversely, there are also risks to not disclosing an issue for an extended period when malicious actors may already know of it, yet those affected remain blissfully unaware of their risk. This is but one factor to be considered. Researchers and Vendors The relationship between security researchers and product vendors is sometimes perceived as contentious. I’d argue that’s largely due to the exceptions that make headlines – because they’re exceptions. When some vendor tries to silence a researcher through legal action, blocking a talk at a conference, stopping a disclosure, etc., those moves make for sensational stories simply because they are unusual and extreme. And those vendors are clearly not familiar with the Streisand Effect. The reality is that security researchers and vendors work together every day, with mutual respect and professionalism. We’re all part of the security ecosystem, and, in the end, we all have the same goal – to make our digital world a safer, more secure place for everyone. As a security engineer working for a vendor, you never want to have someone point out a flaw in your product, but you’d much rather be approached by a researcher and have the opportunity to fix the vulnerability before it is exploited than to become aware of it because it was exploited. Sure, this is where someone will say that vendors should be catching the issues before the product ships, etc. In a perfect world that would be the case, but we don’t live in a perfect world. In the real world, resources are finite. Every complex product will have flaws because humans are involved. Especially products that have changed and evolved over time. No matter how much testing you do, for any product of sufficient complexity, you can never be certain that every possibility has been covered. Furthermore, many products developed 10 or 20 years ago are now being used in scenarios that could not be conceived of at the time of their design. For example, the disintegration of the corporate perimeter and the explosion of remote work has exposed security shortcomings in a wide range of enterprise technologies. As they say, hindsight is 20/20. Defects often appear obvious after they’ve been discovered but may have slipped by any number of tests and reviews previously. That is, until a security researcher brings a new way of thinking to the task and uncovers the issue. For any vendor who takes security seriously, that’s still a good thing in the end. It helps improve the product, protects customers, and improves the overall security of the Internet. Non sequitur. Your facts are uncoordinated. When researchers discover a new vulnerability, they are faced with a choice of what to do with that discovery. One option is to act unilaterally, disclosing the vulnerability directly. From a purely mercenary point of view, they might make the highest return by taking the discovery to the dark web and selling it to anyone willing to pay, with no regard to their intentions. Of course, this option brings with it both moral and legal complications. It arguably does more to harm the security of our digital world overall than any other option, and there is no telling when, or indeed if, the vendor will become aware of the issue for it to be fixed. Another drastic, if less mercenary, option is Full Disclosure - aka the ‘Zero-Day’ or ‘0-day’ approach. Dumping the details of the vulnerability on a public forum makes them freely available to all, both defenders and attackers, but leaves no time for advance preparation of a fix, or even mitigation. This creates a race between attackers and defenders which, more often than not, is won by the attackers. It is nearly always easier, and faster, to create an exploit for a vulnerability and begin distributing it than it is to analyze a vulnerability, develop and test a fix, distribute it, and then patch devices in the field. Both approaches may, in the long term, improve Internet security as the vulnerabilities are eventually fixed. But in the short- and medium-terms they can do a great deal of harm to many environments and individual users as attackers have the advantage and defenders are racing to catch up. These disclosure methods tend to be driven primarily by monetary reward, in the first case, or by some personal or political agenda, in the second case. Dropping a 0-day to embarrass a vendor, government, etc. Now, Full Disclosure does have an important role to play, which we’ll get to shortly. Mutual Benefit As an alternative to unilateral action, there is Coordinated Disclosure: working with the affected vendor(s) to coordinate the disclosure, including providing time to develop and distribute fixes, etc. Coordinated Disclosure can take a few different forms, but before I get into that, a slight detour. Coordinated Disclosure is the current term of art for what was once called ‘Responsible Disclosure’, a term which has generally fallen out of favor. The word ‘responsible’ is, by its nature, judgmental. Who decides what is responsible? For whom? To whom? The reality is it was often a way to shame researchers – anyone who didn’t work with vendors in a specified way was ‘irresponsible’. There were many arguments in the security community over what it meant to be ‘responsible’, for both researchers and vendors, and in time the industry moved to the more neutrally descriptive term of ‘Coordinated Disclosure’. Coordinated Disclosure, in its simplest form means working with the vendor to agree upon a disclosure timeline and to, well, coordinate the process of disclosure. The industry standard is for researchers to give vendors a 90-day period in which to prepare and release a fix, before the disclosure is made. Though this may vary with different programs and may be as short as 60-days or as long as 120-days, and often include modifiers for different conditions such as active exploitation, Critical Severity (CVSS) issues, etc. There is also the option of private disclosure, wherein the vendor notifies only customers directly. This may happen as a prelude to Coordinated Disclosure. There are tradeoffs to this approach – on the one hand it gives end users time to update their systems before the issues become public knowledge, but on the other hand it can be hard to notify all users simultaneously without missing anyone, which would put those unaware at increased risk. The more people who know about an issue, the greater the risk of the information finding its way to the wrong people, or premature disclosure. Private disclosure without subsequent Coordinated Disclosure has several downsides. As already stated, there is a risk that not all affected users will receive the notification. Future customers will have a harder time being aware of the issues, and often scanners and other security tools will also fail to detect the issues, as they’re not in the public record. The lack of CVE IDs also means there is no universal way to identify the issues. There’s also a misguided belief that private disclosure will keep the knowledge out of the wrong hands, which is just an example of ‘security by obscurity’, and rarely effective. It’s more likely to instill a false sense of security which is counter-productive. Some vendors may have bug bounty programs which include detailed reporting procedures, disclosure guidelines, etc. Researchers who choose to work within the bug bounty program are bound by those rules, at least if they wish to receive the bounty payout from the program. Other vendors may not have a bug bounty program but still have ways for researchers to official report vulnerabilities. If you can’t find a way to contact a given vendor, or aren’t comfortable doing so for any reason, there are also third-party reporting programs such as Vulnerability Information and Coordination Environment (VINCE) or reporting directly to the Cybersecurity & Infrastructure Security Agency (CISA). I won’t go into detail on these programs here, as that could be an article of its own – perhaps I will tackle that in the future. As an aside, at the time of writing, F5 does not have a bug bounty program, but the F5 SIRT does regularly work with researchers for coordinated disclosure of vulnerabilities. Guidelines for reporting vulnerabilities to F5 are detailed in K4602: Overview of the F5 security vulnerability response policy. We do provide an acknowledgement for researchers in any resulting Security Advisory. Carrot and Stick Coordinated disclosure is not all about the researcher, the vendor has responsibilities as well. The vendor is being given an opportunity to address the issue before it is disclosed. They should not see this as a burden or an imposition, the researcher is under no obligation to give them this opportunity. This is the ‘carrot’ being offered by the researcher. The vendor needs to act with some urgency to address the issue in a timely fashion, to deliver a fix to their customers before disclosure. The researcher is not to blame if the vendor is given a reasonable time to prepare a fix and fails to do so. The ’90-day’ guideline should be considered just that, a guideline. The intention is to ensure that vendors take vulnerability reports seriously and make a real effort to address them. Researchers should use their judgment, and if they feel that the vendor is making a good faith effort to address the issue but needs more time to do so, especially for a complex issue or one that requires fixing multiple products, etc., it is not unreasonable to extend the disclosure deadline. If the end goal is truly improving security and protecting users, and all parties involved are making a good faith effort, reasonable people can agree to adjust deadlines on a case-by-case basis. But there should still be some reasonable deadline, remember that it is an undisclosed vulnerability which could be independently discovered and exploited at any time – if not already – so a little firmness is justified. Even good intentions can use a little encouragement. That said, the researcher also has a stick for the vendors who don’t bite the carrot – Full Disclosure. For vendors who are unresponsive to vulnerability reports, who respond poorly to such (threats, etc.), who do not make a good faith effort to fix issues in a timely manner, etc., this is alternative of last resort. If the researcher has made a good faith effort at Coordinated Disclosure but has been unable to do so because of the vendor, then the best way to get the word out about the issue is Full Disclosure. You can’t coordinate unless both parties are willing to do so in good faith. Vendors who don’t understand it is in their best interest to work with researchers may eventually learn that it is after dealing with Full Disclosure a few times. Full Disclosure is rarely, if ever, a good first option, but if Coordinated Disclosure fails, and the choice becomes No Disclosure vs. Full Disclosure, then Full Disclosure is the best remaining option. In All Things, Balance Coordinated disclosure seeks to balance the needs of the parties mentioned at the start of this article – security researchers, vendors, customers, consumers, and even random bystanders. Customers cannot make informed decisions about their networks unless vendors inform them, and that’s why we need vulnerability disclosures. You can’t mitigate what you don’t know about. And the reality is no one has the resources to keep all their equipment running the latest software release all the time, so updates get prioritized based on need. Coordinated disclosure gives the vendor time to develop a fix, or at least a mitigation, and make it available to customers before the disclosure. Thus, allowing customers to rapidly respond to the disclosure and patch their networks before exploits are widely developed and deployed, keeping more users safe. The coordination is about more than just the timing, vendors and researchers will work together on the messaging of the disclosure, often withholding details in the initial publication to provide time for patching before disclosing information which make exploitation easier. Crafting a disclosure is always a balancing act between disclosing enough information for customers to understand the scope and severity of the issue and not disclosing information which is more useful to attackers than to defenders. The Needs of the Many Coordinated disclosure gets researchers the credit for their work, allows vendors time to develop fixes and/or mitigations, gives customers those resources to apply when the issue is disclosed to them, protects customers by enabling patching faster than other disclosure methods, and ultimately results in a safer, more secure, Internet for all. In the end, that’s what we’re all working for, isn’t it? I encourage vendors and researchers alike to view each other as allies and not adversaries. And to give each other the benefit of the doubt, rather than presume some nefarious intent. Most vendors and researchers are working toward the same goals of improved security. We’re all in this together. If you’re looking for more information on handling coordinated disclosure, you might check out The CERT Guide to Coordinated Vulnerability Disclosure.188Views4likes0Comments- 114Views2likes0Comments
Cipher Suite Practices and Pitfalls
Cipher Suite Practices and Pitfalls It seems like every time you turn around there is a new vulnerability to deal with, and some of them, such as Sweet32, have required altering cipher configurations for mitigation. Still other users may tweak their cipher suite settings to meet requirements for PCI compliance, regulatory issues, local compatibility needs, etc. However, once you start modifying your cipher suite settings you must take great care, as it is very easy to shoot yourself in the foot. Many misconfigurations will silently fail – seeming to achieve the intended result while opening up new, even worse, vulnerabilities. Let's take a look at cipher configuration on the F5 BIG-IP products to try stay on the safe path. What is a Cipher Suite? Before we talk about how they're configured, let's define exactly what we mean by 'cipher suite', how it differs from just a 'cipher', and the components of the suite. Wikipedia had a good summary, so rather than reinvent the wheel: A cipher suite is a named combination of authentication, encryption, message authentication code (MAC) and key exchange algorithms used to negotiate the security settings for a network connection using the Transport Layer Security (TLS) / Secure Sockets Layer (SSL) network protocol. When we talk about configuring ciphers on BIG-IP we're really talking about configuring cipher suites. More specifically the configured list of cipher suites is a menu of options available to be negotiated. Each cipher suite specifies the key exchange algorithm, authentication algorithm, cipher, cipher mode, and MAC that will be used. I recommend reading K15194: Overview of the BIG-IP SSL/TLS cipher suite for more information. But as a quick overview, let's look at a couple of example cipher suites. The cipher suite is in the format: Key Exchange-Authentication-Cipher-Cipher Mode-MAC Note that not all of these components may be explicitly present in the cipher suite, but they are still implicitly part of the suite. Let's consider this cipher suite: ECDHE-RSA-AES256-GCM-SHA384 This breaks down as follows: Key Exchange Algorithm: ECDHE (Elliptic Curve Diffie-Hellman Ephemeral) Authentication Algorithm: RSA Cipher: AES256 (aka AES with a 256-bit key) Cipher Mode: GCM (Galois/Counter Mode) MAC: SHA384 (aka SHA-2 (Secure Hash Algorithm 2) with 384-bit hash) This is arguably the strongest cipher suite we have on BIG-IP at this time. Let's compare that to a simpler cipher suite: AES128-SHA Key Exchange Algorithm: RSA (Implied) – When it isn't specified, presume RSA. Authentication Algorithm: RSA (Implied) – When it isn't specified, presume RSA. Cipher: AES128 (aka AES with a 128-bit key) Cipher Mode: CBC (Cipher Block Chaining) (Implied) – When it isn't specified, presume CBC. MAC: SHA1 (Secure Hash Algorithm 1; SHA-1 always produces a 160-bit hash.) This example illustrates that the cipher suite may not always explicitly specify every parameter, but they're still there. There are 'default' values that are fairly safe to presume when not otherwise specified. If an algorithm isn't specified, it is RSA. That's a safe bet. And if a cipher mode isn't specified it is CBC. Always CBC. Note that all ciphers currently supported on BIG-IP are CBC mode except for AES-GCM and RC4. ALL. I stress this as it has been a recurring source of confusion amongst customers. It isn't only the cipher suites which explicitly state 'CBC' in their name. Let's examine each of these components. This article is primarily about cipher suite configuration and ciphers, and not the SSL/TLS protocol, so I won't dive too deeply here, but I think it helps to have a basic understanding. Forgive me if I simplify a bit. Key Exchange Algorithms As a quick review of the difference between asymmetric key (aka public key) cryptography and symmetric key cryptography: With the asymmetric key you have two keys – K public and K private –which have a mathematical relationship. Since you can openly share the public key there is no need to pre-share keys with anyone. The downside is that these algorithms are computationally expensive. Key lengths for a common algorithm such as RSA are at least 1024-bit, and 2048-bit is really the minimally acceptable these days. Symmetric key has only K private . Both ends use the same key, which poses the problem of key distribution. The advantage is higher computational performance and common key sizes are 128-bit or 256-bit. SSL/TLS, of course, uses both public and private key systems – the Key Exchange Algorithm is the public key system used to exchange the symmetric key. Examples you'll see in cipher suites include ECDHE, DHE, RSA, ECDH, and ADH. Authentication Algorithms The Authentication Algorithm is sometimes grouped in with the Key Exchange Algorithm for configuration purposes; 'ECDHE_RSA' for example. But we'll consider it as a separate component. This is the algorithm used in the SSL/TLS handshake for the server to sign (using the server's private key) elements sent to the client in the negotiation. The client can authenticate them using the server's public key. Examples include: RSA, ECDSA, DSS (aka DSA), and Anonymous. Anonymous means no authentication; this is generally bad. The most common way users run into this is by accidentally enabling an 'ADH' cipher suite. More on this later when we talk about pitfalls. Note that when RSA is used for the key exchange, authentication is inherent to the scheme so there really isn't a separate authentication step. However, most tools will list it out for completeness. Cipher To borrow once again from Wikipedia: In cryptography, a cipher (or cypher) is an algorithm for performing encryption or decryption—a series of well-defined steps that can be followed as a procedure. An alternative, less common term is encipherment. To encipher or encode is to convert information into cipher or code. In common parlance, 'cipher' is synonymous with 'code', as they are both a set of steps that encrypt a message; however, the concepts are distinct in cryptography, especially classical cryptography. This is what most of us mean when we refer to 'configuring ciphers'. We're primarily interested in controlling the cipher used to protect our information through encryption. There are many, many examples of ciphers which you may be familiar with: DES (Data Encryption Standard), 3DES (Triple DES), AES (Advanced Encryption Standard), RC4 (Rivest Cipher 4), Camellia, RC6, RC2, Blowfish, Twofish, IDEA, SEED, GOST, Rijndael, Serpent, MARS, etc. For a little cipher humor, I recommend RFC2410: The NULL Encryption Algorithm and Its Use With IPsec. Roughly speaking, ciphers come in two types – block ciphers and stream ciphers. Block Ciphers Block ciphers operate on fixed-length chunks of data, or blocks. For example, DES operates on 64-bit blocks while AES operates on 128-bit blocks. Most of the ciphers you'll encounter are block ciphers. Examples: DES, 3DES, AES, Blowfish, Twofish, etc. Stream Ciphers Stream ciphers mathematically operate on each bit in the data flow individually. The most commonly encountered stream cipher is RC4, and that's deprecated. So we're generally focused on block ciphers, not that it really changes anything for the purposes of this article. All of the secrecy in encryption comes from the key that is used, not the cipher itself. Obtain the key and you can unlock the ciphertext. The cipher itself – the algorithm, source code, etc. – not only can be, but should be, openly available. History is full of examples of private cryptosystems failing due to weaknesses missed by their creators, while the most trusted ciphers were created via open processes (AES for example). Keys are of varying lengths and, generally speaking, the longer the key the more secure the encryption. DES only had 56-bits of key data, and thus is considered insecure. We label 3DES as 168-bit, but it is really only equivalent to 112-bit strength. (More on this later.) Newer ciphers, such as AES, often offer options – 128-bits, 192-bits, or 256-bits of key. Remember, a 256-bit key is far more than twice as strong as a 128-bit key. It is 2 128 vs. 2 256 - 3.4028237e+38 vs. 1.1579209e+77 Cipher Mode Cipher mode is the mode of operation used by the cipher when encrypting plaintext into ciphertext, or decrypting ciphertext into plaintext. The most common mode is CBC – Cipher Block Chaining. In cipher block chaining the ciphertext from block n feeds into the process for block n+1 – the blocks are chained together. To steal borrow an image from Wikipedia: As I mentioned previously, all ciphers on BIG-IP are CBC mode except for RC4 (the lone stream cipher, disabled by default starting in 11.6.0) and AES-GCM. AES-GCM was first introduced in 11.5.0, and it is only available for TLSv1.2 connections. GCM stands for Galois/Counter Mode, a more advanced mode of operation than CBC. In GCM the blocks are not chained together. GCM runs in an Authenticated Encryption with Associated Data (AEAD) mode which eliminates the separate per-message hashing step, therefore it can achieve higher performance than CBC mode on a given HW platform. It is also immune to classes of attack that have harried CBC, such as the numerous padding attacks (BEAST, Lucky 13, etc.) Via Wikipedia: The main drawback to AES-GCM is that it was only added in TLSv1.2, so any older clients which don't support TLSv1.2 cannot use it. There are other cipher suites officially supported in TLS which have other modes, but F5 does not currently support those ciphers so we won't get too deep into that. Other ciphers include AES-CCM (CTR mode with a CBC MAC; CTR is Counter Mode), CAMELLIA-GCM (CAMELLIA as introduced in 12.0.0 is CBC), and GOST CNT (aka CTR). We may see these in the future. MAC aka Hash Function What did we ever do before Wikipedia? A hash function is any function that can be used to map data of arbitrary size to data of fixed size. The values returned by a hash function are called hash values, hash codes, digests, or simply hashes. One use is a data structure called a hash table, widely used in computer software for rapid data lookup. Hash functions accelerate table or database lookup by detecting duplicated records in a large file. An example is finding similar stretches in DNA sequences. They are also useful in cryptography. A cryptographic hash function allows one to easily verify that some input data maps to a given hash value, but if the input data is unknown, it is deliberately difficult to reconstruct it (or equivalent alternatives) by knowing the stored hash value. This is used for assuring integrity of transmitted data, and is the building block for HMACs, which provide message authentication. In short, the MAC provides message integrity. Hash functions include MD5, SHA-1 (aka SHA), SHA-2 (aka SHA128, SHA256, & SHA384), and AEAD (Authenticated Encryption with Associated Data). MD5 has long since been rendered completely insecure and is deprecated. SHA-1 is now being 'shamed', if not blocked, by browsers as it is falling victim to advances in cryptographic attacks. While some may need to continue to support SHA-1 cipher suites for legacy clients, it is encouraged to migrate to SHA-2 as soon as possible – especially for digital certificates. Configuring Cipher Suites on BIG-IP Now that we've covered what cipher suites are, let's look at where we use them. There are two distinct and separate areas where cipher suites are used – the host, or control plane, and TMM, or the data plane. On the host side SSL/TLS is handled by OpenSSL and the configuration follows the standard OpenSSL configuration options. Control Plane The primary use of SSL/TLS on the control plane is for httpd. To see the currently configured cipher suite, use ' tmsh list sys http ssl-ciphersuite '. The defaults may vary depending on the version of TMOS. For example, these were the defaults in 12.0.0: tmsh list sys http ssl-ciphersuite sys httpd { ssl-ciphersuite DEFAULT:!aNULL:!eNULL:!LOW:!RC4:!MD5:!EXP } As of 12.1.2 these have been updated to a more explicit list: tmsh list sys http ssl-ciphersuite sys httpd { ssl-ciphersuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA384:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA:AES256-SHA:AES128-SHA256:AES256-SHA256:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:DES-CBC3-SHA } You can change this configuration via ' tmsh modify sys http ssl-ciphersuite <value> '. One important thing to note is that the default is not just 'DEFAULT' as it is on the data plane. This is one thing that users have been caught by; thinking that setting the keyword to 'DEFAULT' will reset the configuration. As OpenSSL provides SSL/TLS support for the control plane, if you want to see which ciphers will actually be supported you can use ' openssl ciphers -v <cipherstring> '. For example: openssl ciphers -v 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA384:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA:AES256-SHA:AES128-SHA256:AES256-SHA256:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:DES-CBC3-SHA' ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD ECDHE-RSA-AES128-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA1 ECDHE-RSA-AES256-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA1 ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA256 ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA384 ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD ECDHE-ECDSA-AES128-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA1 ECDHE-ECDSA-AES256-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA1 ECDHE-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA256 ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA384 AES128-GCM-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AESGCM(128) Mac=AEAD AES256-GCM-SHA384 TLSv1.2 Kx=RSA Au=RSA Enc=AESGCM(256) Mac=AEAD AES128-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA1 AES256-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA1 AES128-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA256 AES256-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA256 ECDHE-RSA-DES-CBC3-SHA SSLv3 Kx=ECDH Au=RSA Enc=3DES(168) Mac=SHA1 ECDHE-ECDSA-DES-CBC3-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=3DES(168) Mac=SHA1 DES-CBC3-SHA SSLv3 Kx=RSA Au=RSA Enc=3DES(168) Mac=SHA1 Now let's see what happens if you use 'DEFAULT': openssl ciphers -v 'DEFAULT' ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA384 ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA384 ECDHE-RSA-AES256-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA1 ECDHE-ECDSA-AES256-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA1 DHE-DSS-AES256-GCM-SHA384 TLSv1.2 Kx=DH Au=DSS Enc=AESGCM(256) Mac=AEAD DHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=DH Au=RSA Enc=AESGCM(256) Mac=AEAD DHE-RSA-AES256-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AES(256) Mac=SHA256 DHE-DSS-AES256-SHA256 TLSv1.2 Kx=DH Au=DSS Enc=AES(256) Mac=SHA256 DHE-RSA-AES256-SHA SSLv3 Kx=DH Au=RSA Enc=AES(256) Mac=SHA1 DHE-DSS-AES256-SHA SSLv3 Kx=DH Au=DSS Enc=AES(256) Mac=SHA1 DHE-RSA-CAMELLIA256-SHA SSLv3 Kx=DH Au=RSA Enc=Camellia(256) Mac=SHA1 DHE-DSS-CAMELLIA256-SHA SSLv3 Kx=DH Au=DSS Enc=Camellia(256) Mac=SHA1 ECDH-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH/RSA Au=ECDH Enc=AESGCM(256) Mac=AEAD ECDH-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH/ECDSA Au=ECDH Enc=AESGCM(256) Mac=AEAD ECDH-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH/RSA Au=ECDH Enc=AES(256) Mac=SHA384 ECDH-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH/ECDSA Au=ECDH Enc=AES(256) Mac=SHA384 ECDH-RSA-AES256-SHA SSLv3 Kx=ECDH/RSA Au=ECDH Enc=AES(256) Mac=SHA1 ECDH-ECDSA-AES256-SHA SSLv3 Kx=ECDH/ECDSA Au=ECDH Enc=AES(256) Mac=SHA1 AES256-GCM-SHA384 TLSv1.2 Kx=RSA Au=RSA Enc=AESGCM(256) Mac=AEAD AES256-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA256 AES256-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA1 CAMELLIA256-SHA SSLv3 Kx=RSA Au=RSA Enc=Camellia(256) Mac=SHA1 PSK-AES256-CBC-SHA SSLv3 Kx=PSK Au=PSK Enc=AES(256) Mac=SHA1 ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA256 ECDHE-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA256 ECDHE-RSA-AES128-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA1 ECDHE-ECDSA-AES128-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA1 DHE-DSS-AES128-GCM-SHA256 TLSv1.2 Kx=DH Au=DSS Enc=AESGCM(128) Mac=AEAD DHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AESGCM(128) Mac=AEAD DHE-RSA-AES128-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AES(128) Mac=SHA256 DHE-DSS-AES128-SHA256 TLSv1.2 Kx=DH Au=DSS Enc=AES(128) Mac=SHA256 DHE-RSA-AES128-SHA SSLv3 Kx=DH Au=RSA Enc=AES(128) Mac=SHA1 DHE-DSS-AES128-SHA SSLv3 Kx=DH Au=DSS Enc=AES(128) Mac=SHA1 DHE-RSA-SEED-SHA SSLv3 Kx=DH Au=RSA Enc=SEED(128) Mac=SHA1 DHE-DSS-SEED-SHA SSLv3 Kx=DH Au=DSS Enc=SEED(128) Mac=SHA1 DHE-RSA-CAMELLIA128-SHA SSLv3 Kx=DH Au=RSA Enc=Camellia(128) Mac=SHA1 DHE-DSS-CAMELLIA128-SHA SSLv3 Kx=DH Au=DSS Enc=Camellia(128) Mac=SHA1 ECDH-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH/RSA Au=ECDH Enc=AESGCM(128) Mac=AEAD ECDH-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH/ECDSA Au=ECDH Enc=AESGCM(128) Mac=AEAD ECDH-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH/RSA Au=ECDH Enc=AES(128) Mac=SHA256 ECDH-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH/ECDSA Au=ECDH Enc=AES(128) Mac=SHA256 ECDH-RSA-AES128-SHA SSLv3 Kx=ECDH/RSA Au=ECDH Enc=AES(128) Mac=SHA1 ECDH-ECDSA-AES128-SHA SSLv3 Kx=ECDH/ECDSA Au=ECDH Enc=AES(128) Mac=SHA1 AES128-GCM-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AESGCM(128) Mac=AEAD AES128-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA256 AES128-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA1 SEED-SHA SSLv3 Kx=RSA Au=RSA Enc=SEED(128) Mac=SHA1 CAMELLIA128-SHA SSLv3 Kx=RSA Au=RSA Enc=Camellia(128) Mac=SHA1 PSK-AES128-CBC-SHA SSLv3 Kx=PSK Au=PSK Enc=AES(128) Mac=SHA1 ECDHE-RSA-RC4-SHA SSLv3 Kx=ECDH Au=RSA Enc=RC4(128) Mac=SHA1 ECDHE-ECDSA-RC4-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=RC4(128) Mac=SHA1 ECDH-RSA-RC4-SHA SSLv3 Kx=ECDH/RSA Au=ECDH Enc=RC4(128) Mac=SHA1 ECDH-ECDSA-RC4-SHA SSLv3 Kx=ECDH/ECDSA Au=ECDH Enc=RC4(128) Mac=SHA1 RC4-SHA SSLv3 Kx=RSA Au=RSA Enc=RC4(128) Mac=SHA1 RC4-MD5 SSLv3 Kx=RSA Au=RSA Enc=RC4(128) Mac=MD5 PSK-RC4-SHA SSLv3 Kx=PSK Au=PSK Enc=RC4(128) Mac=SHA1 ECDHE-RSA-DES-CBC3-SHA SSLv3 Kx=ECDH Au=RSA Enc=3DES(168) Mac=SHA1 ECDHE-ECDSA-DES-CBC3-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=3DES(168) Mac=SHA1 EDH-RSA-DES-CBC3-SHA SSLv3 Kx=DH Au=RSA Enc=3DES(168) Mac=SHA1 EDH-DSS-DES-CBC3-SHA SSLv3 Kx=DH Au=DSS Enc=3DES(168) Mac=SHA1 ECDH-RSA-DES-CBC3-SHA SSLv3 Kx=ECDH/RSA Au=ECDH Enc=3DES(168) Mac=SHA1 ECDH-ECDSA-DES-CBC3-SHA SSLv3 Kx=ECDH/ECDSA Au=ECDH Enc=3DES(168) Mac=SHA1 DES-CBC3-SHA SSLv3 Kx=RSA Au=RSA Enc=3DES(168) Mac=SHA1 PSK-3DES-EDE-CBC-SHA SSLv3 Kx=PSK Au=PSK Enc=3DES(168) Mac=SHA1 EDH-RSA-DES-CBC-SHA SSLv3 Kx=DH Au=RSA Enc=DES(56) Mac=SHA1 EDH-DSS-DES-CBC-SHA SSLv3 Kx=DH Au=DSS Enc=DES(56) Mac=SHA1 DES-CBC-SHA SSLv3 Kx=RSA Au=RSA Enc=DES(56) Mac=SHA1 EXP-EDH-RSA-DES-CBC-SHA SSLv3 Kx=DH(512) Au=RSA Enc=DES(40) Mac=SHA1 export EXP-EDH-DSS-DES-CBC-SHA SSLv3 Kx=DH(512) Au=DSS Enc=DES(40) Mac=SHA1 export EXP-DES-CBC-SHA SSLv3 Kx=RSA(512) Au=RSA Enc=DES(40) Mac=SHA1 export EXP-RC2-CBC-MD5 SSLv3 Kx=RSA(512) Au=RSA Enc=RC2(40) Mac=MD5 export EXP-RC4-MD5 SSLv3 Kx=RSA(512) Au=RSA Enc=RC4(40) Mac=MD5 export As you can see that enables far, far more ciphers, including a number of unsafe ciphers – export, MD5, DES, etc. This is a good example of why you always want to confirm your cipher settings and check exactly what is being enabled before placing new settings into production. Many security disasters could be avoided if everyone doublechecked their settings first. Let’s take a closer look at how OpenSSL represents one of the cipher suites: ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD The columns are: Cipher Suite: ECDHE-RSA-AES256-GCM-SHA384 Protocol: TLSv1.2 Key Exchange Algorithm (Kx): ECDH Authentication Algorithm (Au): RSA Cipher/Encryption Algorithm (Enc): AESGCM(256) MAC (Mac): AEAD Since the control plane uses OpenSSL you can use the standard OpenSSL documentation, so I won't spend a lot of time on that. Data Plane In TMM the cipher suites are configured in the Ciphers field of the Client SSL or Server SSL profiles. See K14783: Overview of the Client SSL profile (11.x - 12.x) & K14806: Overview of the Server SSL profile (11.x - 12.x), respectively for more details. It is important to keep in mind that these are two different worlds with their own requirements and quirks. As most of the configuration activity, and security concerns, occur on the public facing side of the system, we'll focus on the Client SSL Profile. Most of the things we'll cover here will also apply to the Server SSL profile. In the GUI it appears as an editable field: Presuming the profile was created with the name 'Test': tmsh list ltm profile client-ssl Test ltm profile client-ssl Test { app-service none cert default.crt cert-key-chain { default { cert default.crt key default.key } } chain none ciphers DEFAULT defaults-from clientssl inherit-certkeychain true key default.key passphrase none } Modifying the cipher configuration from the command line is simple. tmsh list ltm profile client-ssl Test ciphers ltm profile client-ssl Test { ciphers DEFAULT } tmsh modify ltm profile client-ssl Test ciphers 'DEFAULT:!3DES' tmsh list ltm profile client-ssl Test ciphers ltm profile client-ssl Test { ciphers DEFAULT:!3DES } Just remember the ' tmsh save sys config ' when you're happy with the configuration. Note here the default is just 'DEFAULT'. What that expands to will vary depending on the version of TMOS. K13156: SSL ciphers used in the default SSL profiles (11.x - 12.x) defines the default values for each version of TMOS. Or you can check it locally from the command line: tmm --clientciphers 'DEFAULT' On 12.1.2 that would be: tmm --clientciphers 'DEFAULT' ID SUITE BITS PROT METHOD CIPHER MAC KEYX 0: 159 DHE-RSA-AES256-GCM-SHA384 256 TLS1.2 Native AES-GCM SHA384 EDH/RSA 1: 158 DHE-RSA-AES128-GCM-SHA256 128 TLS1.2 Native AES-GCM SHA256 EDH/RSA 2: 107 DHE-RSA-AES256-SHA256 256 TLS1.2 Native AES SHA256 EDH/RSA 3: 57 DHE-RSA-AES256-SHA 256 TLS1 Native AES SHA EDH/RSA 4: 57 DHE-RSA-AES256-SHA 256 TLS1.1 Native AES SHA EDH/RSA 5: 57 DHE-RSA-AES256-SHA 256 TLS1.2 Native AES SHA EDH/RSA 6: 57 DHE-RSA-AES256-SHA 256 DTLS1 Native AES SHA EDH/RSA 7: 103 DHE-RSA-AES128-SHA256 128 TLS1.2 Native AES SHA256 EDH/RSA 8: 51 DHE-RSA-AES128-SHA 128 TLS1 Native AES SHA EDH/RSA 9: 51 DHE-RSA-AES128-SHA 128 TLS1.1 Native AES SHA EDH/RSA 10: 51 DHE-RSA-AES128-SHA 128 TLS1.2 Native AES SHA EDH/RSA 11: 51 DHE-RSA-AES128-SHA 128 DTLS1 Native AES SHA EDH/RSA 12: 22 DHE-RSA-DES-CBC3-SHA 168 TLS1 Native DES SHA EDH/RSA 13: 22 DHE-RSA-DES-CBC3-SHA 168 TLS1.1 Native DES SHA EDH/RSA 14: 22 DHE-RSA-DES-CBC3-SHA 168 TLS1.2 Native DES SHA EDH/RSA 15: 22 DHE-RSA-DES-CBC3-SHA 168 DTLS1 Native DES SHA EDH/RSA 16: 157 AES256-GCM-SHA384 256 TLS1.2 Native AES-GCM SHA384 RSA 17: 156 AES128-GCM-SHA256 128 TLS1.2 Native AES-GCM SHA256 RSA 18: 61 AES256-SHA256 256 TLS1.2 Native AES SHA256 RSA 19: 53 AES256-SHA 256 TLS1 Native AES SHA RSA 20: 53 AES256-SHA 256 TLS1.1 Native AES SHA RSA 21: 53 AES256-SHA 256 TLS1.2 Native AES SHA RSA 22: 53 AES256-SHA 256 DTLS1 Native AES SHA RSA 23: 60 AES128-SHA256 128 TLS1.2 Native AES SHA256 RSA 24: 47 AES128-SHA 128 TLS1 Native AES SHA RSA 25: 47 AES128-SHA 128 TLS1.1 Native AES SHA RSA 26: 47 AES128-SHA 128 TLS1.2 Native AES SHA RSA 27: 47 AES128-SHA 128 DTLS1 Native AES SHA RSA 28: 10 DES-CBC3-SHA 168 TLS1 Native DES SHA RSA 29: 10 DES-CBC3-SHA 168 TLS1.1 Native DES SHA RSA 30: 10 DES-CBC3-SHA 168 TLS1.2 Native DES SHA RSA 31: 10 DES-CBC3-SHA 168 DTLS1 Native DES SHA RSA 32: 49200 ECDHE-RSA-AES256-GCM-SHA384 256 TLS1.2 Native AES-GCM SHA384 ECDHE_RSA 33: 49199 ECDHE-RSA-AES128-GCM-SHA256 128 TLS1.2 Native AES-GCM SHA256 ECDHE_RSA 34: 49192 ECDHE-RSA-AES256-SHA384 256 TLS1.2 Native AES SHA384 ECDHE_RSA 35: 49172 ECDHE-RSA-AES256-CBC-SHA 256 TLS1 Native AES SHA ECDHE_RSA 36: 49172 ECDHE-RSA-AES256-CBC-SHA 256 TLS1.1 Native AES SHA ECDHE_RSA 37: 49172 ECDHE-RSA-AES256-CBC-SHA 256 TLS1.2 Native AES SHA ECDHE_RSA 38: 49191 ECDHE-RSA-AES128-SHA256 128 TLS1.2 Native AES SHA256 ECDHE_RSA 39: 49171 ECDHE-RSA-AES128-CBC-SHA 128 TLS1 Native AES SHA ECDHE_RSA 40: 49171 ECDHE-RSA-AES128-CBC-SHA 128 TLS1.1 Native AES SHA ECDHE_RSA 41: 49171 ECDHE-RSA-AES128-CBC-SHA 128 TLS1.2 Native AES SHA ECDHE_RSA 42: 49170 ECDHE-RSA-DES-CBC3-SHA 168 TLS1 Native DES SHA ECDHE_RSA 43: 49170 ECDHE-RSA-DES-CBC3-SHA 168 TLS1.1 Native DES SHA ECDHE_RSA 44: 49170 ECDHE-RSA-DES-CBC3-SHA 168 TLS1.2 Native DES SHA ECDHE_RSA Some differences when compared to OpenSSL are readily apparent. For starters, TMM kindly includes a column label header, and actually aligns the columns. The first column is simply a 0-ordinal numeric index, the rest are as follows: ID: The official SSL/TLS ID assigned to that cipher suite. SUITE: The cipher suite. BITS: The size of the key in bits. PROT: The protocol supported. METHOD: NATIVE (in TMM) vs. COMPAT (using OpenSSL code). CIPHER: The cipher. MAC: The hash function. KEYX: The Key Exchange and Authentication Algorithms Note that the MAC is a little misleading for AES-GCM cipher suites. There is no separate MAC as they're AEAD. But the hashing algorithm is used in the Pseudo-Random Function (PRF) and a few other handshake related places. Selecting the Cipher Suites Now we know how to look at the current configuration, modify it, and list the actual ciphers that will be enabled by the listed suites. But what do we put into the configuration? Most users won't have to touch this. The default values are carefully selected by F5 to meet the needs of the majority of our customers. That's the good news. The bad news is that some customers will need to get in there and change the configuration – be it for regulatory compliance, internal policies, legacy client support, etc. Once you begin modifying them, the configuration is truly custom for each customer. Every customer who modifies the configuration, and uses a custom cipher configuration, needs to determine what the proper list is for their needs. Let's say we have determined that we need to support only AES & AES-GCM, 128-bit or 256-bit, and only ECDHE key exchange. Any MAC or Authentication is fine. OK, let's proceed from there. On 12.1.2 there are six cipher suites that fit those criteria. We could list them all explicitly: tmm --clientciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-CBC-SHA:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-CBC-SHA' That will work, but it gets unwieldy fast. Not only that, but in versions up to 11.5.0 the ciphers configuration string was truncated at 256bytes. Starting in 11.5.0 that was increased to 768bytes, but that can still truncate long configurations. We'll revisit this when we get to the pitfalls section. Fortunately, there is an alternative – keywords! This will result in the same list of cipher suites: tmm --clientciphers 'ECDHE+AES-GCM:ECDHE+AES' That specifies the ECDHE key exchange with AES-GCM ciphers, and ECDHE with AES ciphers. Let's take a closer look to help understand what is happening here. Keywords Keywords are extremely important when working with cipher suite configuration, so we'll spend a little time on those. Most of these apply to both the control plane (OpenSSL) and the data plane (TMM), unless otherwise noted, but we're focused on the data plane as that's F5 specific. Keywords organize into different categories. F5 specific: NATIVE: cipher suites implemented natively in TMM COMPAT: cipher suites using OpenSSL code; removed as of 12.0.0 @SPEED: Re-orders the list to put 'faster' (based on TMOS implementation performance) ciphers first. Sorting: @SPEED: Re-orders the list to put 'faster' (based on TMOS implementation performance) ciphers first. (F5 Specific) @STRENGTH: Re-orders the list to put 'stronger' (larger keys) ciphers first. Protocol: TLSv1_2: cipher suites available under TLSv1.2 TLSv1_1: cipher suites available under TLSv1.1 TLSv1: cipher suites available under TLSv1.0 SSLv3: cipher suites available under SSLv3 Note the 'Protocol' keywords in the cipher configuration control the ciphers associated with that protocol, and not the protocol itself! More on this in pitfalls. Key Exchange Algorithms (sometimes with Authentication specified): ECDHE or ECDHA_RSA: Elliptic Curve Diffie-Hellman Ephemeral (with RSA) ECDHE_ECDSA: ECDHE with Elliptic Curve Digital Signature Algorithm DHE or EDH: Diffie-Hellman Ephemeral (aka Ephemeral Diffie-Hellman) (with RSA) DHE_DSS: DHE with Digital Signature Standard (aka DSA – Digital Signature Algorithm) ECDH_RSA: Elliptic Curve Diffie-Hellman with RSA ECDH_ECDSA: ECDH with ECDSA RSA: RSA, obviously ADH: Anonymous Diffie-Hellman. Note the Authentication Algorithms don't work as standalone keywords in TMM. You can't use 'ECDSA' or 'DSS' for example. And you might think ECDHE or DHE includes all such cipher suites – note that they don't if you read carefully. General cipher groupings: DEFAULT: The default cipher suite for that version; see K13156 ALL: All NATIVE cipher suites; does not include COMPAT in current versions HIGH: 'High' security cipher suites; >128-bit MEDIUM: 'Medium' security cipher suites; effectively 128-bit suites LOW: 'Low' security cipher suites; <128-bit excluding export grade ciphers EXP or EXPORT: Export grade ciphers; 40-bit or 56-bit EXPORT56: 56-bit export ciphers EXPORT40: 40-bit export ciphers Note that DEFAULT does change periodically as F5 updates the configuration to follow the latest best practices. K13156: SSL ciphers used in the default SSL profiles (11.x - 12.x) documents these changes. Cipher families: AES-GCM: AES in GCM mode; 128-bit or 256-bit AES: AES in CBC mode; 128-bit or 256-bit CAMELLIA: Camellia in CBC mode; 128-bit or 256-bit 3DES: Triple DES in CBC mode; 168-bit (well, 112-bit really) DES: Single DES in CBC mode, includes EXPORTciphers;40-bit & 56-bit. RC4: RC4 stream cipher NULL: NULL cipher; just what it sounds like, it does nothing – no encryption MAC aka Hash Function: SHA384: SHA-2 384-bit hash SHA256: SHA-2 256-bit hash SHA1 or SHA: SHA-1 160-bit hash MD5: MD5 128-bit hash Other: On older TMOS versions when using the COMPAT keyword it also enables two additional keywords: SSLv2: Ciphers supported on the SSLv2 protocol RC2: RC2 ciphers. So, let's go back to our example: tmm --clientciphers 'ECDHE+AES-GCM:ECDHE+AES' Note that you can combine keywords using '+' (plus sign). And multiple entries in the ciphers configuration line are separated with ':' (colon). You may also need to wrap the string in single quotes on the command line – I find it is a good habit to just always do so. We can also exclude suites or keywords. There are two ways to do that: '!' (exclamation point) is a hard exclusion. Anything excluded this way cannot be implicitly or explicitly re-enabled. It is disabled, period. '-' (minus sign or dash) is a soft exclusion. Anything excluded this way can be explicitly re-enabled later in the configuration string. (Note: The dash is also usedinthe names of many cipher suites, such as ECDHE-RSA-AES256-GCM-SHA384 or AES128-SHA. Do not confuse the dashes that are part of the cipher suite names with a soft exclusion, which alwaysprecedes, or prefixes,the value being excluded. 'AES128-SHA': AES128-SHA cipher suite. '-SHA': SHA is soft excluded. '-AES128-SHA': the AES128-SHA cipher suite is soft excluded. Position matters.) Let's look at the difference in hard and soft exclusions. We'll start with our base example: tmm --clientciphers 'ECDHE+AES-GCM:DHE+AES-GCM' ID SUITE BITS PROT METHOD CIPHER MAC KEYX 0: 49200 ECDHE-RSA-AES256-GCM-SHA384 256 TLS1.2 Native AES-GCM SHA384 ECDHE_RSA 1: 49199 ECDHE-RSA-AES128-GCM-SHA256 128 TLS1.2 Native AES-GCM SHA256 ECDHE_RSA 2: 159 DHE-RSA-AES256-GCM-SHA384 256 TLS1.2 Native AES-GCM SHA384 EDH/RSA 3: 158 DHE-RSA-AES128-GCM-SHA256 128 TLS1.2 Native AES-GCM SHA256 EDH/RSA Now let's look at a hard exclusion: tmm --clientciphers 'ECDHE+AES-GCM:!DHE:DHE+AES-GCM' ID SUITE BITS PROT METHOD CIPHER MAC KEYX 0: 49200 ECDHE-RSA-AES256-GCM-SHA384 256 TLS1.2 Native AES-GCM SHA384 ECDHE_RSA 1: 49199 ECDHE-RSA-AES128-GCM-SHA256 128 TLS1.2 Native AES-GCM SHA256 ECDHE_RSA And lastly a soft exclusion: tmm --clientciphers 'ECDHE+AES-GCM:-DHE:DHE+AES-GCM' ID SUITE BITS PROT METHOD CIPHER MAC KEYX 0: 49200 ECDHE-RSA-AES256-GCM-SHA384 256 TLS1.2 Native AES-GCM SHA384 ECDHE_RSA 1: 49199 ECDHE-RSA-AES128-GCM-SHA256 128 TLS1.2 Native AES-GCM SHA256 ECDHE_RSA 2: 159 DHE-RSA-AES256-GCM-SHA384 256 TLS1.2 Native AES-GCM SHA384 EDH/RSA 3: 158 DHE-RSA-AES128-GCM-SHA256 128 TLS1.2 Native AES-GCM SHA256 EDH/RSA Note that in the second example, the hard exclusion, we used '!DHE' and even though we then explicitly added 'DHE+AES-GCM' those ciphers were not enabled. This is because, once excluded with a hard exclusion, ciphers cannot be re-enabled. In the third example, the soft exclusion, we used '-DHE' and then 'DHE+AES-GCM'. This time it did enable those ciphers, which is possible with a soft exclusion. You might be wondering what soft disabling is useful for; why would you ever want to remove ciphers only to add them again? Reordering the ciphers is a common use case. As an example, DEFAULT orders ciphers differently in different versions, but mainly based on strength – bit size. Let's say we know 3DES is really 112-bit equivalent strength and not 168-bit as it is usually labeled. For some reason, maybe legacy clients, we can't disable them, but we want them to be last on the list. One way to do this is to first configure the DEFAULT list, then remove all of the 3DES ciphers. But then add the 3DES ciphers back explicitly – at the end of the list. Let's try it – compare the following: tmm --clientciphers 'DEFAULT' ID SUITE BITS PROT METHOD CIPHER MAC KEYX 0: 159 DHE-RSA-AES256-GCM-SHA384 256 TLS1.2 Native AES-GCM SHA384 EDH/RSA 1: 158 DHE-RSA-AES128-GCM-SHA256 128 TLS1.2 Native AES-GCM SHA256 EDH/RSA 2: 107 DHE-RSA-AES256-SHA256 256 TLS1.2 Native AES SHA256 EDH/RSA 3: 57 DHE-RSA-AES256-SHA 256 TLS1 Native AES SHA EDH/RSA 4: 57 DHE-RSA-AES256-SHA 256 TLS1.1 Native AES SHA EDH/RSA 5: 57 DHE-RSA-AES256-SHA 256 TLS1.2 Native AES SHA EDH/RSA 6: 57 DHE-RSA-AES256-SHA 256 DTLS1 Native AES SHA EDH/RSA 7: 103 DHE-RSA-AES128-SHA256 128 TLS1.2 Native AES SHA256 EDH/RSA 8: 51 DHE-RSA-AES128-SHA 128 TLS1 Native AES SHA EDH/RSA 9: 51 DHE-RSA-AES128-SHA 128 TLS1.1 Native AES SHA EDH/RSA 10: 51 DHE-RSA-AES128-SHA 128 TLS1.2 Native AES SHA EDH/RSA 11: 51 DHE-RSA-AES128-SHA 128 DTLS1 Native AES SHA EDH/RSA 12: 22 DHE-RSA-DES-CBC3-SHA 168 TLS1 Native DES SHA EDH/RSA 13: 22 DHE-RSA-DES-CBC3-SHA 168 TLS1.1 Native DES SHA EDH/RSA 14: 22 DHE-RSA-DES-CBC3-SHA 168 TLS1.2 Native DES SHA EDH/RSA 15: 22 DHE-RSA-DES-CBC3-SHA 168 DTLS1 Native DES SHA EDH/RSA 16: 157 AES256-GCM-SHA384 256 TLS1.2 Native AES-GCM SHA384 RSA 17: 156 AES128-GCM-SHA256 128 TLS1.2 Native AES-GCM SHA256 RSA 18: 61 AES256-SHA256 256 TLS1.2 Native AES SHA256 RSA 19: 53 AES256-SHA 256 TLS1 Native AES SHA RSA 20: 53 AES256-SHA 256 TLS1.1 Native AES SHA RSA 21: 53 AES256-SHA 256 TLS1.2 Native AES SHA RSA 22: 53 AES256-SHA 256 DTLS1 Native AES SHA RSA 23: 60 AES128-SHA256 128 TLS1.2 Native AES SHA256 RSA 24: 47 AES128-SHA 128 TLS1 Native AES SHA RSA 25: 47 AES128-SHA 128 TLS1.1 Native AES SHA RSA 26: 47 AES128-SHA 128 TLS1.2 Native AES SHA RSA 27: 47 AES128-SHA 128 DTLS1 Native AES SHA RSA 28: 10 DES-CBC3-SHA 168 TLS1 Native DES SHA RSA 29: 10 DES-CBC3-SHA 168 TLS1.1 Native DES SHA RSA 30: 10 DES-CBC3-SHA 168 TLS1.2 Native DES SHA RSA 31: 10 DES-CBC3-SHA 168 DTLS1 Native DES SHA RSA 32: 49200 ECDHE-RSA-AES256-GCM-SHA384 256 TLS1.2 Native AES-GCM SHA384 ECDHE_RSA 33: 49199 ECDHE-RSA-AES128-GCM-SHA256 128 TLS1.2 Native AES-GCM SHA256 ECDHE_RSA 34: 49192 ECDHE-RSA-AES256-SHA384 256 TLS1.2 Native AES SHA384 ECDHE_RSA 35: 49172 ECDHE-RSA-AES256-CBC-SHA 256 TLS1 Native AES SHA ECDHE_RSA 36: 49172 ECDHE-RSA-AES256-CBC-SHA 256 TLS1.1 Native AES SHA ECDHE_RSA 37: 49172 ECDHE-RSA-AES256-CBC-SHA 256 TLS1.2 Native AES SHA ECDHE_RSA 38: 49191 ECDHE-RSA-AES128-SHA256 128 TLS1.2 Native AES SHA256 ECDHE_RSA 39: 49171 ECDHE-RSA-AES128-CBC-SHA 128 TLS1 Native AES SHA ECDHE_RSA 40: 49171 ECDHE-RSA-AES128-CBC-SHA 128 TLS1.1 Native AES SHA ECDHE_RSA 41: 49171 ECDHE-RSA-AES128-CBC-SHA 128 TLS1.2 Native AES SHA ECDHE_RSA 42: 49170 ECDHE-RSA-DES-CBC3-SHA 168 TLS1 Native DES SHA ECDHE_RSA 43: 49170 ECDHE-RSA-DES-CBC3-SHA 168 TLS1.1 Native DES SHA ECDHE_RSA 44: 49170 ECDHE-RSA-DES-CBC3-SHA 168 TLS1.2 Native DES SHA ECDHE_RSA tmm --clientciphers 'DEFAULT:-3DES:!SSLv3:3DES+ECDHE:3DES+DHE:3DES+RSA' ID SUITE BITS PROT METHOD CIPHER MAC KEYX 0: 159 DHE-RSA-AES256-GCM-SHA384 256 TLS1.2 Native AES-GCM SHA384 EDH/RSA 1: 158 DHE-RSA-AES128-GCM-SHA256 128 TLS1.2 Native AES-GCM SHA256 EDH/RSA 2: 107 DHE-RSA-AES256-SHA256 256 TLS1.2 Native AES SHA256 EDH/RSA 3: 57 DHE-RSA-AES256-SHA 256 TLS1 Native AES SHA EDH/RSA 4: 57 DHE-RSA-AES256-SHA 256 TLS1.1 Native AES SHA EDH/RSA 5: 57 DHE-RSA-AES256-SHA 256 TLS1.2 Native AES SHA EDH/RSA 6: 57 DHE-RSA-AES256-SHA 256 DTLS1 Native AES SHA EDH/RSA 7: 103 DHE-RSA-AES128-SHA256 128 TLS1.2 Native AES SHA256 EDH/RSA 8: 51 DHE-RSA-AES128-SHA 128 TLS1 Native AES SHA EDH/RSA 9: 51 DHE-RSA-AES128-SHA 128 TLS1.1 Native AES SHA EDH/RSA 10: 51 DHE-RSA-AES128-SHA 128 TLS1.2 Native AES SHA EDH/RSA 11: 51 DHE-RSA-AES128-SHA 128 DTLS1 Native AES SHA EDH/RSA 12: 157 AES256-GCM-SHA384 256 TLS1.2 Native AES-GCM SHA384 RSA 13: 156 AES128-GCM-SHA256 128 TLS1.2 Native AES-GCM SHA256 RSA 14: 61 AES256-SHA256 256 TLS1.2 Native AES SHA256 RSA 15: 53 AES256-SHA 256 TLS1 Native AES SHA RSA 16: 53 AES256-SHA 256 TLS1.1 Native AES SHA RSA 17: 53 AES256-SHA 256 TLS1.2 Native AES SHA RSA 18: 53 AES256-SHA 256 DTLS1 Native AES SHA RSA 19: 60 AES128-SHA256 128 TLS1.2 Native AES SHA256 RSA 20: 47 AES128-SHA 128 TLS1 Native AES SHA RSA 21: 47 AES128-SHA 128 TLS1.1 Native AES SHA RSA 22: 47 AES128-SHA 128 TLS1.2 Native AES SHA RSA 23: 47 AES128-SHA 128 DTLS1 Native AES SHA RSA 24: 49200 ECDHE-RSA-AES256-GCM-SHA384 256 TLS1.2 Native AES-GCM SHA384 ECDHE_RSA 25: 49199 ECDHE-RSA-AES128-GCM-SHA256 128 TLS1.2 Native AES-GCM SHA256 ECDHE_RSA 26: 49192 ECDHE-RSA-AES256-SHA384 256 TLS1.2 Native AES SHA384 ECDHE_RSA 27: 49172 ECDHE-RSA-AES256-CBC-SHA 256 TLS1 Native AES SHA ECDHE_RSA 28: 49172 ECDHE-RSA-AES256-CBC-SHA 256 TLS1.1 Native AES SHA ECDHE_RSA 29: 49172 ECDHE-RSA-AES256-CBC-SHA 256 TLS1.2 Native AES SHA ECDHE_RSA 30: 49191 ECDHE-RSA-AES128-SHA256 128 TLS1.2 Native AES SHA256 ECDHE_RSA 31: 49171 ECDHE-RSA-AES128-CBC-SHA 128 TLS1 Native AES SHA ECDHE_RSA 32: 49171 ECDHE-RSA-AES128-CBC-SHA 128 TLS1.1 Native AES SHA ECDHE_RSA 33: 49171 ECDHE-RSA-AES128-CBC-SHA 128 TLS1.2 Native AES SHA ECDHE_RSA 34: 49170 ECDHE-RSA-DES-CBC3-SHA 168 TLS1 Native DES SHA ECDHE_RSA 35: 49170 ECDHE-RSA-DES-CBC3-SHA 168 TLS1.1 Native DES SHA ECDHE_RSA 36: 49170 ECDHE-RSA-DES-CBC3-SHA 168 TLS1.2 Native DES SHA ECDHE_RSA 37: 22 DHE-RSA-DES-CBC3-SHA 168 TLS1 Native DES SHA EDH/RSA 38: 22 DHE-RSA-DES-CBC3-SHA 168 TLS1.1 Native DES SHA EDH/RSA 39: 22 DHE-RSA-DES-CBC3-SHA 168 TLS1.2 Native DES SHA EDH/RSA 40: 22 DHE-RSA-DES-CBC3-SHA 168 DTLS1 Native DES SHA EDH/RSA 41: 10 DES-CBC3-SHA 168 TLS1 Native DES SHA RSA 42: 10 DES-CBC3-SHA 168 TLS1.1 Native DES SHA RSA 43: 10 DES-CBC3-SHA 168 TLS1.2 Native DES SHA RSA 44: 10 DES-CBC3-SHA 168 DTLS1 Native DES SHA RSA I added something else in there which I'll come back to later. Pitfalls As should be clear by now cipher configuration is a powerful tool, but as the song says, every tool is a weapon if you hold it right. And weapons are dangerous. With a little careless handling it is easy to lose a toe – or a leg. Whenever you are working with cipher suite configuration the old rule of 'measure twice, cut once' applies – and then double-check the work to be certain. There are several common pitfalls which await you. Misuse Perhaps the most common pitfall is simply misuse – using cipher suite configuration for that which it is not intended. And the single most common example of this comes from using cipher configuration to manipulate protocols. Given the keywords, as described above, it seems common for users to presume that if they want to disable a protocol, such as TLSv1.0, then the way to do that is to use a cipher suite keyword, such as !TLSv1. And, indeed, this may seem to work – but it isn't doing what is desired. The protocol is not disabled, only the ciphers that are supported for that protocol are. The protocol is configured on the VIP independently of the ciphers. !TLSv1 would disable all ciphers supported under the TLSv1.0 protocol, but not the protocol itself. Note that the protocol negotiation and the cipher negotiation in the SSL/TLS handshake are independent. What happens if the VIP only supports TLSv1.0/v1.1/v1.2 and the client only supports SSLv3 & TLSv1.0? Well, they'd agree on TLSv1.0 as the common protocol. The cipher list the client sends in the Client Hello is independent of the protocol that is eventually negotiated. Say the client sends AES128-SHA and the server has that in its list, so it is selected. OK, we've agreed on a protocol and a cipher suite – only the server won't do any ciphers on TLSv1.0 because of '!TLSv1' in the ciphers configuration, and the connection will fail. That may seem like splitting hairs, but it makes a difference. If a scanner is looking for protocols that are enabled, and not the full handshake, it may still flag a system which has been configured this way. The protocol is negotiated during the SSL/TLS handshake before the cipher is selected. This also means the system is doing more work, as the handshake continues further before failing, and the log messages may be misleading. Instead of logging a protocol incompatibility the logs will reflect the failure to find a viable cipher, which can be a red herring when it comes time to debug the configuration. The right way to do this is to actually disable the protocol, which doesn't involve the cipher suite configuration at all. For the control plane this is done through the ssl-protocol directive: tmsh list sys http ssl-protocol sys httpd { ssl-protocol "all -SSLv2 -SSLv3" } For example, if we wanted to disable TLSv1.0: tmsh modify sys http ssl-protocol 'all -SSLv2 -SSLv3 -TLSv1' tmsh list sys http ssl-protocol sys httpd { ssl-protocol "all -SSLv2 -SSLv3 -TLSv1" } For the data plane this can be done via the Options List in the SSL Profile GUI, via the No SSL, No TLSv1.1, etc. directives: Or via the command line: tmsh list ltm profile client-ssl Test options ltm profile client-ssl Test { options { dont-insert-empty-fragments } } tmsh modify ltm profile client-ssl Test options {dont-insert-empty-fragments no-tlsv1} tmsh list /ltm profile client-ssl Test options ltm profile client-ssl Test { options { dont-insert-empty-fragments no-tlsv1 } } The values are slightly different on the command line, use this command to see them all: tmsh modify ltm profile client-ssl <profile-name> options ? Use the right tool for the job and you'll be more likely to succeed. Truncation As I previously mentioned, in versions up to 11.5.0 the ciphers configuration string was truncated at 256 bytes. Starting in 11.5.0 that was increased to 768 bytes (see K11481: The SSL profile cipher lists have a 256 character limitation for more information), but that can still silently truncate long configurations. This is not a theoretical issue, we've seen users run into this in the real world. For example, little over a year ago I worked with a customer who was then using 11.4.1 HF8. They were trying to very precisely control which ciphers were enabled, and their order. In order to do this they'd decided to enumerate every individual cipher in their configuration – resulting in this cipher suite configuration string: TLSv1_2+ECDHE-RSA-AES256-CBC-SHA:TLSv1_1+ECDHE-RSA-AES256-CBC-SHA:TLSv1_2+ECDHE-RSA-AES128-CBC-SHA:TLSv1_1+ECDHE-RSA-AES128-CBC-SHA:TLSv1_2+DHE-RSA-AES256-SHA:TLSv1_1+DHE-RSA-AES256-SHA:TLSv1_2+DHE-RSA-AES128-SHA:TLSv1_1+DHE-RSA-AES128-SHA:TLSv1_2+AES256-SHA256:TLSv1_1+AES256-SHA:TLSv1_2+AES128-SHA256:TLSv1_1+AES128-SHA:TLSv1+ECDHE-RSA-AES256-CBC-SHA:TLSv1+ECDHE-RSA-AES128-CBC-SHA:TLSv1+DHE-RSA-AES256-SHA:TLSv1+DHE-RSA-AES128-SHA:TLSv1+AES256-SHA:TLSv1+AES128-SHA:TLSv1+DES-CBC3-SHA That string would save in the configuration and it was there if you looked at the bigip.conf file, but it was silently truncated when the configuration was loaded. Since this was 11.4.1, only the first 256 bytes were loaded successfully, which made the running configuration: TLSv1_2+ECDHE-RSA-AES256-CBC-SHA:TLSv1_1+ECDHE-RSA-AES256-CBC-SHA:TLSv1_2+ECDHE-RSA-AES128-CBC-SHA:TLSv1_1+ECDHE-RSA-AES128-CBC-SHA:TLSv1_2+DHE-RSA-AES256-SHA:TLSv1_1+DHE-RSA-AES256-SHA:TLSv1_2+DHE-RSA-AES128-SHA:TLSv1_1+DHE-RSA-AES128-SHA:TLSv1_2+AES256-S Note the last suite is truncated itself, which means it was invalid and therefore ignored. If their configuration had worked they would've had nineteen protocol+suite combinations – instead they had eight. Needless to say, this caused some problems. This customer was missing ciphers that they expected to have working. That is bad enough – but it could be worse. Let's imagine a customer who wants to specify several specific ciphers first, then generally enable a number of other TLSv1.2 & TLSv1.1 ciphers. And, of course, they are careful to disable dangerous ciphers! TLSv1_2+ECDHE-RSA-AES256-CBC-SHA:TLSv1_1+ECDHE-RSA-AES256-CBC-SHA:TLSv1_2+ECDHE-RSA-AES128-CBC-SHA:TLSv1_1+ECDHE-RSA-AES128-CBC-SHA:TLSv1_2+DHE-RSA-AES256-SHA:TLSv1_1+DHE-RSA-AES256-SHA:TLSv1_2+DHE-RSA-AES128-SHA:TLSv1_1+DHE-RSA-AES128-SHA:TLSv1_2:TLSv1_1:!RC4:!MD5:!ADH:!DES:!EXPORT OK, that looks fairly solid, right? What do you suppose the problem with this is? This is the problem; in 11.4.1 and earlier it would truncate to this: TLSv1_2+ECDHE-RSA-AES256-CBC-SHA:TLSv1_1+ECDHE-RSA-AES256-CBC-SHA:TLSv1_2+ECDHE-RSA-AES128-CBC-SHA:TLSv1_1+ECDHE-RSA-AES128-CBC-SHA:TLSv1_2+DHE-RSA-AES256-SHA:TLSv1_1+DHE-RSA-AES256-SHA:TLSv1_2+DHE-RSA-AES128-SHA:TLSv1_1+DHE-RSA-AES128-SHA:TLSv1_2:TLSv1_1: All of the exclusions were truncated off! Now we have the opposite problem – there are a number of ciphers enabled which the customer expects to be disabled! And they're BAD ciphers – ADH, DES, MD5, RC4. So this customer would be at high risk without realizing it. Be aware of this; it is very sneaky. The configuration will look fine; the truncation happens in the code when it loads the configuration. This is also one reason why I always recommend listing your exclusions first in the configuration string. Then you can never accidentally enable something. Unintended Consequences Let's say a new CVE is announced which exposes a very serious vulnerability in SSLv3 & TLSv1.0. There is no way to mitigate it, and the only solution is to limit connections to only TLSv1.1 & TLSv1.2. You want a cipher configuration to accomplish this. It seems straight-forward – just configure it to use only ciphers on TLSv1.1 & TLSv1.2: tmsh modify ltm profile client-ssl <profile> ciphers 'TLSv1_2:TLSv1_1' Congratulations, you've solved the problem. You are no longer vulnerable to this CVE. You know there is a but coming, right? What's wrong? Well, you just enabled all TLSv1.2 & TLSv1.1 ciphers. That includes such gems as RC4-MD5, RC4-SHA, DES, and a few ADH (Anonymous Diffie-Hellman) suites which have no authentication. As recently as 11.3.0 you'd even be enabling some 40-bit EXPORT ciphers. (We pulled them out of NATIVE in 11.4.0.) So you just leapt out of the frying pan and into the fire. Always, always, always check the configuration before using it. Running that through tmm --clientciphers 'TLSv1_2:TLSv1_1' would've raised red flags. Instead, this configuration would work without causing those problems: tmsh modify ltm profile client-ssl <profile> ciphers 'DEFAULT:!TLSv1:!SSLv3' Another option, and probably the better one, is to disable the SSLv3 and TLSv1.0 protocols on the VIP. As I discussed above. Of course, you can do both – belt and suspenders. And just to show you how easy it is to make such a mistake, F5 did this! In K13400: SSL 3.0/TLS 1.0 BEAST vulnerability CVE-2011-3389 and TLS protocol vulnerability CVE-2012-1870 we originally had the following in the mitigation section: Note: Alternatively, to configure an SSL profile to use only TLS 1.1-compatible, TLS 1.2-compatible, AES-GCM, or RC4-SHA ciphers using the tmsh utility, use the following syntax: tmsh create /ltm profile client-ssl <name> ciphers TLSv1_1:TLSv1_2:AES-GCM:RC4-SHA Yes, I had this fixed long ago. Remember back in the section on keywords I had this comparison example: tmm --clientciphers 'DEFAULT' tmm --clientciphers 'DEFAULT:-3DES:!SSLv3:3DES+ECDHE:3DES+DHE:3DES+RSA' Who caught the '!SSLv3' in the second line? Why do you think I added that? Did I need to? Hint: What do you think the side effect of blanket enabling all of those 3DES ciphers would be if I didn't explicitly disable SSLv3? Cipher Ordering In SSL/TLS there are two main models to the cipher suite negotiation – Server Cipher Preference or Client Cipher Preference. What does this mean? In SSL/TLS the client sends the list of cipher suites it is willing and able to support in the Client Hello. The server also has its list of cipher suites that it is willing and able to support. In Client Cipher Preference the server will select the first cipher on the client's list that is also in the server's list. Effectively this gives the client influence over which cipher is selected based on the order of the list it sends. In Server Cipher Preference the server will select the first server on its own list that is also on the client's list. So the server gives the order of its list precedence. BIG-IP always operates in Server Cipher Preference, so be very careful in how you order your cipher suites. Preferred suites should go at the top of the list. How you order your cipher suites will directly affect which ciphers are used. It doesn't matter if a stronger cipher is available if a weak cipher is matched first. HTTP/2 How is HTTP/2 a pitfall? The HTTP/2 RFC7540 includes a blacklist of ciphers that are valid in TLS, but should not be used in HTTP/2. This can cause a problem on a server where the TLS negotiation is decoupled from the ALPN exchange for the higher level protocol. The server might select a cipher which is on the blacklist, and then when the connection attempts to step up to HTTP/2 via ALPN the client may terminate the connection with extreme prejudice. It is well known enough to be called out in the RFC – Section 9.2.2. F5 added support for HTTP/2 in 12.0.0 – and we fell into this trap. Our DEFAULT ciphers list was ordered such that it was almost certain a blacklisted cipher would be selected.; This was fixed in 12.0.0 HF3 and 12.1.0, but serves as an example. On 12.0.0 FINAL through 12.0.0 HF2 a simple fix was to configure the ciphers to be 'ECDHE+AES-GCM:DEFAULT'. ECDHE+AES-GCM is guaranteed to be supported by any client compliant with RFC7540 (HTTP/2). Putting it first ensures it is selected before any blacklisted cipher. 3DES Back in the section on ciphers I mentioned that we label 3DES as being 168-bit, but that it only provides the equivalent of 112-bit strength. So, what did I mean by that? DES operates on 64-bit data blocks, using 56-bits of key. So it has a strength of 2 56 . 3DES, aka Triple DES, was a stop-gap designed to stretch the life of DES once 56-bits was too weak to be safe, until AES became available. 3DES use the exact same DES cipher, it just uses it three times – hence the name. So you might think 3x56-bits = 168-bits. 2 168 strong. Right? No, not really. The standard implementation of 3DES is known as EDE – for Encrypt, Decrypt, Encrypt. (For reasons we don't need to get into here.) You take the 64-bit data block, run it through DES once to encrypt it with K 1 , then run it through again to decrypt it using K 2 , then encrypt it once again using K 3 . Three keys, that's still 168-bits, right? Well, you'd think so. But the devil is in the (implementation) details. First of all there are three keying options for 3DES: - Keying option 1: K1, K2, K3 – 168 unique bits (but only 112-bit strength!) - Keying option 2: K1, K2, K1 – 112 unique bits (but only 80-bit strength!) - Keying option 3: K1, K1, K1 – 56 unique bits, 56-bit strength (Equivalent to DES due to EDE!) F5 uses keying option one, so we have 168-bits of unique key. However, 3DES with keying option one is subject to a meet-in-the-middle cryptographic attack which only has a cost of 2 112 . It has even been reduced as low as 2 108 , as described in this paper. So it does not provide the expected 168-bits of security, and is in fact weaker than AES128. To add some confusion, due to an old issue we used to describe 3DES as being 192-bit. See: K17296: The BIG-IP system incorrectly reports a 192-bit key length for cipher suites using 3DES (DES-CBC3) for more details. Of course, with the appearance of the Sweet32 attack last fall I would encourage everyone to disable 3DES completely whenever possible. We're also seeing a growing number of scanners and audit tools recategorizing 3DES as a 'Medium' strength cipher, down from 'High', and correspondingly lowering the grade for any site still supporting it. If you don't need it, turn it off. See K13167034: OpenSSL vulnerability CVE-2016-2183 for more information. Conclusion Believe it or not, that's the quick overview of cipher suite configuration on BIG-IP. There are many areas where we could dig in further and spend some time in the weeds, but I hope that this article helps at least one person understand cipher suite configuration better, and to avoid the pitfalls that commonly claim those who work with them. Additional Resources This article is by no means comprehensive, and for those interested I'd encourage additional reading: BIG-IP SSL Cipher History by David Holmes, here on DevCentral Cipher Rules And Groups in BIG-IP v13 by Chase Abbott, also on DevCentral OpenSSL Cipher Documentation K8802: Using SSL ciphers with BIG-IP Client SSL and Server SSL profiles K15194: Overview of the BIG-IP SSL/TLS cipher suite K13163: SSL ciphers supported on BIG-IP platforms (11.x - 12.x) K13156: SSL ciphers used in the default SSL profiles (11.x - 12.x) K17370: Configuring the cipher strength for SSL profiles (12.x) K13171: Configuring the cipher strength for SSL profiles (11.x) K14783: Overview of the Client SSL profile (11.x - 12.x) K14806: Overview of the Server SSL profile (11.x - 12.x)21KViews9likes17Comments