Some notes on edge cases to HSTS I have seen in the wild, and appropriate mitigations.
Not Invoking Parent Domain Frequently Enough
Problem: If your website is on www.example.com and the search engines indexes it there. Even if you have HSTS in the HTTP headers on https://example.com/ the user may never visit that domain, and never see the dynamic strict-transport-security header. This may be a problem if you have cookies scoped to that domain, especially if they lack the secure flag.
Fixes:
Serve a commonly retrieved item such as Logo from the parent domain https://example.com/logo.png
Included the “preload” attribute on the HSTS header on the parent domain.
Ensure all cookies have the secure flag.
Redirecting Around Parent Domain
Problem: You have a redirect at http://example.com to https://www.example.com
This is a special case of “Not Invoking Parent Domain Frequently Enough”. Where you type example.com most browsers default to HTTP, but HSTS headers need to be set over HTTPS.
Fixes:
Redirect HTTP to HTTPS before you redirect to “www”. http://example.com/ to https://example.com/ to https://www.example.com/
Serve a logo or other item in the parent domain.
Include the “preload” attribute on HSTS headers on the parent page.
Ensure all cookies have the secure flag.
Subdomains Can Remove the Include Subdomain Option
Problem: Your parent domain “https://example.com” includes the HSTS IncludeSubDomains, but your subdomain “https://status.example.com” doesn’t include IncludeSubDomains. Google Chrome gives precedence to the child domain so a MITM can create “http://nonsuch.status.example.com/” and any cookies scoped to “.example.com” without the secure flag will be delivered in the clear. Note the behaviour may vary depending which websites have been visited and when, and which browser is used.
Partial fixes or other techniques to consider include:
Domain owners consider DNSSEC, domain users consider DNS over HTTPS, to defeat the Man in the Middle DNS modification.
Avoid situations where you delegate subdomains to different organisations or managerial regimes where you can’t ensure consistent application of controls.
Use “host” cookies where appropriate but accept this will fail in some browsers.
No doubt the latest critical vulnerability on OpenSSL will reopen old debates. Should we use open source software? David Wheeler suggests closed source code is about as bad on average but you can’t test it as easily and it often uses open source code anyway (sometimes outside of permitted license arrangements). Should we write application code, especially network or cryptographic code in C? Cryptographic code has its own challenges in optimisation and avoiding timing attacks where not being too far from the metal has some advantages. I doubt C is still the best language for all aspects of OpenSSL but despite being experienced in lots of IT and IT Security I will leave that debate to cryptographers and specialists. I have views, they are probably wrong.
One person on Twitter suggested OpenSSL and other TLS libraries implemented in C are much of a muchness. Presumably OpenSSL and LibreSSL. Now this is something I think I can make a stab at assessing. LibreSSL is a fork from 2014, a fair amount has changed in TLS since then so these tools are not identical, but any C programmer tasked with implementing TLS in an application likely has this choice available.
OpenSSL
LibreSSL
Version
3.0.5
3.5.3
Download integrity available
SHA256, PGP sig
SHA256, PGP sig
Size
15MB
3.9MB
CVE (2015-2022 OpenSSL)
116
6 (+one in 2014)
Avg CVSS Score
5.9
5
Configure and build time
16m34s
9m17s
Test time
17m2s
2m32s
Tests
3299
102
libcrypto.so size (*inc debug)
5MB
9.4MB*
SHA256 benchmark 8192 bytes (bigger is better)
121268
86906
Ciphers
146
121
libssl/libtls lines of code (*.c)
55254
45269
Flawfinder findings per 1000 lines
ssl 7.25 (no tls) crypto 7.74
ssl 5.10 tls 9.35 crypto 7.64
Comparison of OpenSSL and LibreSSL
First thing to note on unpacking is the size difference, and whilst much of LibreSSL is smaller than the corresponding OpenSSL equivalent the bulk of that difference is that the OpenSSL tarball ships a lot of test data, including scripts to fuzz a lot of the implementation. OpenSSL also ship manual pages for all the various C calls in the tarball. So the difference is not bloat but purpose.
CVE counting is notoriously tricky as it reflects both attention to, processes, and vulnerability of the product. Both products clearly having CVE reported, no high scoring issues in LibreSSL yet. OpenSSL loses out on history, since version 3 is a major piece of work it might arguably be fairer to compare since September 2021, and bugs only in 3, when it still does badly in the comparison. Clearly OpenSSL is more widely used than LibreSSL, although with Apple and OpenBSD (and thus OpenSSH) LibreSSL is used in plenty of high profile situations.
LibreSSL builds faster, ships and runs with fewer tests, includes debugging information by default. I noted a small number of warnings compiling LibreSSL (none for OpenSSL), some from DJB’s ChaCha20 code which has a slightly different coding convention utilising GCC attributes.
Diving into ChaCha20 is instructive, LibreSSL has taken the author’s C code and stuck it in “chacha-merged.c” largely unchanged. OpenSSL has a re-implementation in “chacha_enc.c”, plus a sub-folder with various (presumably) hand coded or hand optimised assembler versions and bench-marking tools to show on which CPUs they outperform the C version compiled with GCC 4.8 dated 2015. So here we have a real difference between the two libraries, a trade-off between greater complexity and maintenance versus performance. Quick web search shows only a handful of complaints where some had noticed that LibreSSL migration had slowed down VPNs or digital checksums.
Ciphers were crudely counted from the command line list, OpenSSL offers ARIA and SEED, both South Korean originated ciphers. A figment of old export controls on stronger cryptography, but this might sway the opinion of people choosing a library if South Korean interoperability is key.
Flawfinder was just the first C static analysis tool to hand that didn’t require setup. Flawfinder results are quoted as raw numbers. David Wheeler says “an idiot with a tool is still an idiot”. So I tried to look closer and not be too big an idiot.
A lot of these flawfinder results are clearly false positives where the tool has misunderstood the code. This is of course what you would expect if both teams are using any sort of static source code analysis tools (including GCC warnings). All the high level issues in LibreSSL tls were immediately recognisable as false positives, so the high score for “libtls” isn’t meaningful in my view. The high risk issues in OpenSSL libraries included a bunch of C string functions which are subject of much secure coding debate. So this approach does reveal some of the secure coding practices that OpenBSD have applied to harden the code base.
At this point I was minded that LibreSSL is smaller and simpler, and has had some C safe coding practices applied, but slower and less featured. In my own C code not following these safe coding practices has generated security issues so I see the value. But it still isn’t quite clear to me why it has so many fewer CVEs. So I figured visit bugs which were found to be present at the fork (1.0.1g) and in v3 of OpenSSL and see why they aren’t a problem in LibreSSL. This seemed a simple idea but for the recent CVE the OpenSSL report doesn’t analyse if it was present before 1.0.2. So I assumed any present at 1.0.2 may be present in 1.0.1.g unless there is a specific statement to the contrary.
Selected commentary
CVE-2022-2068 OpenSSL Commit ce60b13707add7e6b54c5817376234c4043506ed File not present in LibreSSL
CVE-2022-1292 OpenSSL commit 7c33270707b568c524a8ef125fe611a8872cb5e8 File not present in LibreSSL
CVE-2022-0778 OpenSSL commit 9eafb53614bf65797db25f467946e735e1b43dc9 The vulnerable code appears to be present in LibreSSL unaltered.
CVE-2021-23841 OpenSSL commit 122a19ab48091c657f7cb1fb3af9fc07bd557bbf The added check is missing in LibreSSL The notes say it isn’t called directly, so it affected 3rd party apps calling relevant function. The CVE report documents another OpenSSL commit, not found in logs.
CVE-2021-23840 OpenSSL commit c9fb704cf3af5524eb8e79961e31b60eee8c3c47 Code is too diverse to immediately see if the issue was present.
CVE-2020-1971 OpenSSL commit b33c48b75aaf33c93aeda42d7138616b9e6a64cb File not present in LibreSSL
CVE-2020-1968 Raccoon Attack a protocol bug, fixed by disabling the method used. I believe these methods weren’t implemented in LibreSSL
Of the most recent CVEs ~75% appear in code that was added to OpenSSL or removed from LibreSSL since the fork. Of the remaining issues several were unfixed in LibreSSL although they were relatively minor issues or in code that isn’t called directly by LibreSSL. This suggests that counting CVEs may be giving a slightly rosy view of LibreSSL but not so rosy it isn’t clearly better from a security perspective. Some caution is required as recent CVEs will by the nature of forks have fewer issues in common than earlier ones (someone else can look at the 2015-2018 CVEs).
Conclusions
Some were critiquing the code because it is C, my brief inspection suggests that OpenBSD security folk know how to audit and fix C code, and they have addressed many of the obvious C related risk areas. Likely some of those changes weren’t strictly needed but it is easier to change than to rely on code staying safe in future. I’m not getting further into should we write network apps in C debate here.
LibreSSL clearly shuns performance and features for security and maintainability.
Compared to many large C code projects both appear to be developed with disciplined processes, but OpenSSL is consistently adding security vulnerabilities in a manner that LibreSSL isn’t. I note in passing that OpenBSD are not secretive about what they do to audit C code, or precious about people taking their improvements into their own code, and the licensing doesn’t forbid that either.
If you are grabbing libcrypto for cryptography in C, then OpenSSL may occasionally be preferable as the differences between them in the security arena are less stark and the performance edge or features may matter. However that presumes a cryptography use case where security aspects aren’t as crucial as performance, those exist, such as some types of storage encryption or ransomware.
If you after implementing TLS in C, or binding to a C library for TLS, than LibreSSL is likely to be slower but more secure, and for most network bound TLS that is probably fine, especially in client applications. Also the security benefits of LibreSSL may justify cross-porting any missing features you need.
It looks like at least one known cryptographic issue with the forked code base remains unfixed in LibreSSL, and likely more. A keen contributor could review all the OpenSSL CVEs that might apply and address them. But these are large libraries and there will always be issues, pragmatically you can limit exposure further by limiting the optional features at configuration and runtime to reduce further the amount of exposed code. For example a VPN product might only need to permit a small choice, or no runtime choice of ciphers and protocols.
Given the rapid progress in CPU technology, and the limited complaints about LibreSSL performance, one has to wonder for how many people is it worth trading security for performance.