Null Cipher
The radio amateur service does not allow encryption of communications. This is a fundamental rule meant to ensure that the amateur service is not used for unintended purposes, such as commercial ones.
As a consequence, we cannot transmit passwords securely over the amateur frequencies. But we can use cryptographic authentication. Just not anything that would be used to hide the contents of the communications.
Cryptographic authentication is something that HTTPS/TLS allows out-of-the-box. We just need to make sure that we are not using encryption. In this article, we’ll see how to do this with Mozilla Firefox.
Forking Firefox
The code base of Firefox is an unwieldy Mercurial repository. Maintaining a fork would be cumbersome.
Git has won. And learning Mercurial for a small project adds quite a bit of friction, and I could not host on GitHub or GitLab. Of course, I can use git-remote-hg
, but this adds another layer of abstraction, and another source of problems. I tried both, but it turned out it did not matter.
Since the official build process assumes that you are using the official repository with the official URLs and so forth, forking the repository itself would require also patching the build process. And I really did not want to touch that.
Another approach is to make a repository that just contains the patches to apply to the Firefox codebase, and a script that fetches the Firefox repository, applies the patches, and builds the project. This is gluon.
If you look into the HamFox repository, you will see that it contains just a few small files. The most important one is the null cipher patch itself.
The Patch
Grepping through the code for the TLS names of the cipher, we uncover an array sCipherPrefs
that lists the supported ciphers. Here is an extract:
static const CipherPref sCipherPrefs[] = {
{"security.ssl3.ecdhe_rsa_aes_128_gcm_sha256",
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
StaticPrefs::security_ssl3_ecdhe_rsa_aes_128_gcm_sha256},
{"security.ssl3.ecdhe_ecdsa_aes_128_gcm_sha256",
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
StaticPrefs::security_ssl3_ecdhe_ecdsa_aes_128_gcm_sha256},
//...
};
Each entry in the array is a CipherPref
. The definition is given right above the array:
// Table of pref names and SSL cipher ID
typedef struct {
const char* pref;
int32_t id;
bool (*prefGetter)();
} CipherPref;
The first field is the string used to toggle the cipher in the about:config
page. There is no point is creating a toggle for this cipher, so we’ll just leave it empty.
The second field is the identifier of the cipher; we find that the macros are defined in security/nss/lib/ssl/sslproto.h. When looking for the null ciphers, we find:
$ grep NULL security/nss/lib/ssl/sslproto.h
#define SSL_NULL_WITH_NULL_NULL TLS_NULL_WITH_NULL_NULL
#define SSL_RSA_WITH_NULL_MD5 TLS_RSA_WITH_NULL_MD5
#define SSL_RSA_WITH_NULL_SHA TLS_RSA_WITH_NULL_SHA
#define TLS_NULL_WITH_NULL_NULL 0x0000
#define TLS_RSA_WITH_NULL_MD5 0x0001
#define TLS_RSA_WITH_NULL_SHA 0x0002
#define TLS_RSA_WITH_NULL_SHA256 0x003B
#define TLS_ECDH_ECDSA_WITH_NULL_SHA 0xC001
#define TLS_ECDHE_ECDSA_WITH_NULL_SHA 0xC006
#define TLS_ECDH_RSA_WITH_NULL_SHA 0xC00B
#define TLS_ECDHE_RSA_WITH_NULL_SHA 0xC010
#define TLS_ECDH_anon_WITH_NULL_SHA 0xC015
#define SRTP_NULL_HMAC_SHA1_80 0x0005
#define SRTP_NULL_HMAC_SHA1_32 0x0006
#define SSL_FORTEZZA_DMS_WITH_NULL_SHA 0x001c
The SSL_*
ones are just aliases for the TLS_*
ones. We do want authentication. So, this eliminates TLS_NULL_WITH_NULL_NULL
. We then have the choice between MD5, SHA-1 and SHA-256, and I opted for the last one, so TLS_RSA_WITH_NULL_SHA256
.
The third one is a pointer to the function that tells us whether the toggle is enabled or not. There is no toggle. But we can just write a function that always returns true
.
We replace the contents of the array with a single entry containing these fields, and we’re good!
To minimize the risk of conflict when the upstream code changes, I have put the other ciphers in a block comment instead of removing them altogether from the code. With this, we get:
diff --git a/security/manager/ssl/nsNSSComponent.cpp b/security/manager/ssl/nsNSSComponent.cpp
index 5844ffecfd..e2da79480a 100644
--- a/security/manager/ssl/nsNSSComponent.cpp
+++ b/security/manager/ssl/nsNSSComponent.cpp
@@ -1054,9 +1054,15 @@ typedef struct {
bool (*prefGetter)();
} CipherPref;
+bool AlwaysTrue(void) {
+ return true;
+}
+
// Update the switch statement in AccumulateCipherSuite in nsNSSCallbacks.cpp
// when you add/remove cipher suites here.
static const CipherPref sCipherPrefs[] = {
+ {"", TLS_RSA_WITH_NULL_SHA256, AlwaysTrue},
+ /*
{"security.ssl3.ecdhe_rsa_aes_128_gcm_sha256",
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
StaticPrefs::security_ssl3_ecdhe_rsa_aes_128_gcm_sha256},
@@ -1103,6 +1109,7 @@ static const CipherPref sCipherPrefs[] = {
StaticPrefs::security_ssl3_rsa_aes_128_sha},
{"security.ssl3.rsa_aes_256_sha", TLS_RSA_WITH_AES_256_CBC_SHA,
StaticPrefs::security_ssl3_rsa_aes_256_sha},
+ */
};
// These ciphersuites can only be enabled if deprecated versions of TLS are