In this post, we’ll walk through an example of how to configure Red Hat Enterprise Linux (RHEL) 8 crypto-policy to remove Cipher block chaining (CBC), but let’s start with a little background on CBC and default crypto-policy on RHEL 8.
At an operational level, most of us have experienced situations where there is a complex configuration on a system, and there is either too much or too little information to understand everything.
For example, have you ever run into a statement like, "Your server supports CBC ciphers which are no longer recommended and vulnerable," and then asked whether you are protected from a new vulnerability, along with a request to report ASAP and remediate if some systems across your estate are impacted?
What tools are you going to use? What checks are you going to make? Have you configured the system properly? Are your servers free of known vulnerabilities?
These questions, thankfully, can be answered with technologies available in RHEL 8 to enhance operational efficiency and improve confidence and understanding of crypto-policy tools.
Let’s step back a bit and analyse the problem at hand, with the help of this Wikipedia entry.
It says that CBC is one of the many modes of using a block cipher, the one XORing the current ciphertext block with the previous one before encrypting it. It also names it "the most commonly used mode of operation" and "one of two block cipher modes recommended by Niels Ferguson and Bruce Schneier."
It also says that it was invented in 1976, which could indicate it’s out of date and insecure. However, being old doesn't automatically mean insecure. Diffie–Hellman key exchange is also from 1976, yet it is still widely used and isn't considered insecure.
All that information does not really help in understanding what the situation is about then. It is highly likely that this investigation started from an automated vulnerability scanner alert noticing that the OpenSSH server is willing to use CBC cipher modes, citing CVE-2008-5161 as the reason. Maybe another reference was made to this or some other equally cryptic document. Sentences like, "It is therefore very unlikely for an interactive session to be usefully attacked using this protocol weakness: an attacker would expect around 11356 connection-killing attempts before they are likely to succeed" might be soothing, but does that mean that this decade-old security issue wasn’t addressed in RHEL?
Thankfully Red Hat is working proactively to monitor and mitigate the vulnerabilities present in its products. In fact, the aforementioned NIST page for CVE-2008-5161 has Red Hat vendor statement displayed prominently, stating that the issue is fixed from RHEL 5. Red Hat also provided a workaround to disable CBC ciphers from sshd configuration.
That article also clarifies that the mitigation in question was applying upstream patches, further lowering the probability of successfully conducting the attack. A vulnerability scanner does not know such information; it checks for the presence of the specific packages versions, matches them with known impacted versions and reports the finding. Those tools are not perfect and cannot detect the presence of such mitigations.
If there are any doubts about the security of a particular algorithm, why not go the extra mile and disable it altogether? These changes should be balanced with compatibility concerns.
Those CBC ciphers might be the only common language to speak when it comes to interoperability with older SSH clients and servers, and balancing more secure defaults with compatibility falls on the shoulders of the distribution builders.
Fedora 33, for example, disables CBC ciphers for usage with SSH, as seen on this merge request upstream. RHEL 8, being an enterprise distribution released a year earlier, has decided to keep them enabled by default though, citing both the presence of mitigations and compatibility reasons, as seen in this bugzilla: 1818103 – SSH Server CBC Mode Ciphers Enabled in RHCOS.
Balanced defaults are important, but defaults are made to be changed. Each user’s situation is unique and it’s up to them to make their own decisions as they see fit. To fulfil that need, RHEL 8 has switched to a new, centralized mechanism of disabling/enabling cryptographic algorithm usage, crypto-policies. Let’s take that as an opportunity to see how to use crypto-policies to disable CBC ciphers.
RHEL 8 crypto-policy related features and configuration
Looking at the default policy on RHEL 8 gives more understanding of the situation:
sudo less /usr/share/crypto-policies/policies/DEFAULT.pol # A reasonable default for today's standards. It should provide # 112-bit security with the exception of SHA1 signatures needed for DNSSec # and other still prevalent legacy use of SHA1 signatures.
There are other policies that can be set in RHEL 8 to match additional security requirements in regards to crypto-policies:
FIPS.pol: a policy only using approved FIPS algorithm.
FUTURE.pol: A level that will provide security on a conservative level that is believed to withstand any near-term future attacks.
LEGACY.pol: Provides settings for ensuring maximum compatibility with legacy systems.
There is even the flexibility to modify these policies by creating sub-policies and also to create your own policy from scratch. We previously published a post on the Red Hat Blog presenting the update-crypto-policies tool, its features and an explanation on how to use it.
There is additional important documentation for RHEL 8 related to the topic here: "Using system-wide cryptographic policies Red Hat Enterprise Linux 8."
How to configure RHEL 8 crypto-policy to remove CBC
Coming back to our initial problem, the auditor comes with additional supporting facts, the vulnerability assessment tool reported the issue:
"Vulnerability Name: SSH CBC Mode Ciphers Enabled, Description: CBC Mode Ciphers are enabled on the SSH Server."
There is a distinction to be made, as seen from online comments, many are able to configure their system to allegedly remediate the issue after passing the vulnerability scan. In practice, they are configuring the sshd process not to use the CBC related ciphers, which is preventing sshd from using those ciphers. There are even some instructions on how to apply that type of workaround.
That is only for the sshd process and not for the entire server. That is acting on a process level as opposed to on a system level. In other words, while the check on SSH CBC mode would pass, some CBC ciphers would still be left on the server. It is good practice to make the change at the system level, which is exactly what the update-crypto-policies tool can do.
First, we can see the crypto-policy currently in use in the RHEL 8 server:
update-crypto-policies --show DEFAULT
Since we have established that RHEL 8 is using the DEFAULT crypto-policy, we can try to find the CBC related ciphers in
tls_cipher = ... AES-256-CBC ...AES-128-CBC cipher = ... AES-256-CBC CAMELLIA-256-CBC AES-128-CBC CAMELLIA-128-CBC
(The unrelated ciphers have been removed for clarity.)
There are six ciphers related to CBC in use in the DEFAULT policy.
That is when things get complicated. At the time of writing, there are no policy files showing examples of an additional crypto-policy setting ssh_cipher. It is mentioned in the man page: man crypto-policies (... ssh_cipher: Optional; list of allowed symmetric encryption algorithms (including the modes) for use with the SSH protocol. If absent, the value is derived from cipher...).
That ssh_cipher exists, and while it’s not explicitly visible in the DEFAULT policy, it has to be explicitly excluded in the sub-policy if we want to effectively remove all CBC related ciphers.
We can create a sub-policy that will modify the DEFAULT policy in use. In order to do that, a sub-policy file needs to be created
Note: the naming convention is important; it has to be all in uppercase for the sub-policy name, and .pmod in lowercase for the extension name).
That file needs to contain the modifications that we want to make in the DEFAULT policy.
To remove the CBC ciphers from the server, modifying the DEFAULT profile, we have to add this:
tls_cipher = -AES-256-CBC -AES-128-CBC cipher = -AES-128-CBC -AES-256-CBC -CAMELLIA-256-CBC -CAMELLIA-128-CBC ssh_cipher = -AES-128-CBC -AES-256-CBC
To remove the CBC algorithm from the server for sshd only:
ssh_cipher = -AES-128-CBC -AES-256-CBC
Note: about ssh_cipher, since there are no examples, one could assume that the value could be:
ssh_cipher = -AES-128-CBC -AES-256-CBC -CAMELLIA-256-CBC -CAMELLIA-128-CBC
Actually, we don't specify these -CAMELLIA since they don't appear to be actually advertised or used by sshd, as seen doing: man sshd_config | grep -i cbc
3des-cbc aes128-cbc aes192-cbc aes256-cbc )
3des-cbc is not advertised either from RHEL 8.2 server, as seen with ssh -vv and looking at "Their offer":
The sub-policy with its configuration removing CBC ciphers has to be set:
sudo update-crypto-policies --set DEFAULT:DISABLE-CBC
We can verify that it is properly set:
sudo update-crypto-policies --show DEFAULT:DISABLE-CBC
The server then has to be rebooted for the policy and sub-policy to be effective.
At this point, there should not be any CBC ciphers left in use by the server. One way to easily verify that would be to actually check with sshd by running this command from a RHEL 8 server
ssh -vv -oCiphers=aes128-cbc,aes256-cbc 127.0.0.1
It should show login information, and the user should be able to connect using valid credentials.
When the CBC cipher are not there for sshd, it should show
Unable to negotiate with 127.0.0.1 port 22: no matching cipher found.
The sshd process would then display what ciphers are offered by that server, like:
"Their offer: firstname.lastname@example.org,email@example.com,aes256-ctr,firstname.lastname@example.org,aes128-ctr"
In this blog, we walked through how to configure a RHEL 8 server for compliance with a given crypto-policies requirement. We showed how to remove CBC related ciphers from a server, after validating the security concern. We used tools like update-crypto-policies to reach some security compliance requirements, in a proper way, at server level instead of having to act on individual components level.