This article dissects the recent Logjam paper from a pentesting viewpoint to reveal a number of different factors that affect the impact of the vulnerability. One of those factors includes the use of common primes and I’ve included a small change to OpenSSL that you can use to look out for this.
Two for the price of one
For me, the penny dropped when I realised that the Logjam paper sets out two strategies. The first is a cryptanalytic attack that uses pre-computation to speed up the process of cracking a Diffie-Hellman (DH) key exchange. The second is a protocol attack that allows weaker export-grade versions of DH-based cipher suites to be selected, so long as they are supported by the server. A man-in-the-middle attacker who can make use of the second technique can downgrade vulnerable connections, which helps the first attack by forcing the use of weaker cryptography. But an attacker doesn’t have to rely on the downgrade trick for an attack on the security of the connection to succeed. It all depends on what the attacker wants to achieve and what position they are in.
Attack scenarios
If the attacker wants to modify the data in transit then the attack must be performed in real time. The attacker must be a man-in-the-middle and have access to sufficient computing resources to perform the necessary cryptanalysis in a short space of time. To ease the cryptanalysis, if the attacker can downgrade the connection to using a 512-bit prime, then so much the better. That’s only possible if the server supports export-grade DH cipher suites. In the opinion of the Logjam authors, any 512-bit prime should be considered vulnerable but a 768-bit, and certainly a 1024-bit, DH prime would require a serious amount of effort to attack.
In contrast, decrypting (but not modifying) the secure traffic from a connection that begins with a DH key exchange can be done passively in slower time: the attacker can capture the traffic and run the cryptanalysis offline. In this case, the attacker must contend with whatever strength of DH prime was selected during the TLS negotiation, which is unlikely to be 512-bit. For passive attacks, cipher suite preference is therefore more important: if the server prefers a common cipher suite that isn’t based on the standard DH key exchange (e.g. AES256-SHA) then a passive attack is very unlikely to succeed.
Client-side fixes
As with a number of previous TLS bugs, browsers have applied plasters to the sores to try to mitigate the impact. Although the downgrade attack exploited a weakness in the TLS protocol rather than an implementation flaw, refusing to accept 512-bit DH primes is a quick and effective solution. But taking that strategy all the way up to 1024-bit primes is dangerous in terms of user experience – users could start complaining that sites are suddenly inaccessible. So the success of client-side “patching” will depend on the vendors, the minimum size of DH prime their browser accepts and the user’s update regime.
Common primes
Another factor to consider is the prime itself. The Logjam paper noted that servers tend to re-use it – and, not only that, but the same primes are in circulation across different implementations. The pre-computation work for the cryptanalysis is based on a single DH prime so it’s in the attacker’s interest to do the number crunching for primes that are most widely used. A server that uses a common prime is thus more of a target. But what are these common primes? The Logjam paper itself makes explicit reference to two 512-bit primes. A number of larger primes can be found by inspecting the JavaScript behind the server test page on the Logjam site. You can test for a dozen common primes by adding a bit of code to the file apps/s_cb.c
before compiling OpenSSL. Since version 1.0.2 the default output includes a line, when appropriate, beginning “Server Temp Key”, e.g.
Insert the following lines after the line that outputs the bit length, which is BIO_printf(out, "DH, %d bits\n", EVP_PKEY_bits(key));
(line 519 for the current version 1.0.2d):
if (EVP_PKEY_bits(key) > 1024) break; const char *common[12]; // common primes from https://weakdh.org/imperfect-forward-secrecy.pdf, https://weakdh.org/docheck.js common[0] = "9FDB8B8A004544F0045F1737D0BA2E0B274CDF1A9F588218FB435316A16E374171FD19D8D8F37C39BF863FD60E3E300680A3030C6E4C3757D08F70E6AA871033"; common[1] = "D4BCD52406F69B35994B88DE5DB89682C8157F62D8F33633EE5772F11F05AB22D6B5145B9F241E5ACC31FF090A4BC71148976F76795094E71E7903529F5A824B"; common[2] = "E9E642599D355F37C97FFD3567120B8E25C9CD43E927B3A9670FBEC5D890141922D2C3B3AD2480093799869D1E846AAB49FAB0AD26D2CE6A22219D470BCE7D777D4A21FBE9C270B57F607002F3CEF8393694CF45EE3688C11A8C56AB127A3DAF"; common[3] = "D67DE440CBBBDC1936D693D34AFD0AD50C84D239A45F520BB88174CB98BCE951849F912E639C72FB13B4B4D7177E16D55AC179BA420B2A29FE324A467A635E81FF5901377BEDDCFD33168A461AAD3B72DAE8860078045B07A7DBCA7874087D1510EA9FCC9DDD330507DD62DB88AEAA747DE0F4D6E2BD68B0E7393E0F24218EB3"; common[4] = "BBBC2DCAD84674907C43FCF580E9CFDBD958A3F568B42D4B08EED4EB0FB3504C6C030276E710800C5CCBBAA8922614C5BEECA565A5FDF1D287A2BC049BE6778060E91A92A757E3048F68B076F7D36CC8F29BA5DF81DC2CA725ECE66270CC9A5035D8CECEEF9EA0274A63AB1E58FAFD4988D0F65D146757DA071DF045CFE16B9B"; common[5] = "E6969D3D495BE32C7CF180C3BDD4798E91B7818251BB055E2A2064904A79A770FA15A259CBD523A6A6EF09C43048D5A22F971F3C20129B48000E6EDD061CBC053E371D794E5327DF611EBBBE1BAC9B5C6044CF023D76E05EEA9BAD991B13A63C974E9EF1839EB5DB125136F7262E56A8871538DFD823C6505085E21F0DD5C86B"; common[6] = "C9BBF5F774A8297B0F97CDDA3A3468C7117B6BF799A13D9F1F5DAC487B2241FE95EFB13C2855DFD2F898B3F99188E24EDF326DD68C76CC85537283512D46F1953129C693364D8C71202EABB3EBC85C1DF53907FBD0B7EB490AD0BC99289686800C46AB04BF7CDD9AD425E6FB25592EB6258A0655D75E93B2671746AE349E721B"; common[7] = "CD5C22FAEA0C53C39E602242C088FA0EA31586F472E9B04606AEDFB35F56C4948095F687B388575FA1700DB3D02253025A523AC76E9646F755A12338653AE071CB64F185591C34C6673FAC9B78DC4D71E53F3A5CCA6326F89C5400FBF8272A76367C630E234A905E4E558CDA968A46A136AD3088DD295F934EC36ADB5F69C3F3"; common[8] = "92402435C3A12E44D3730D8E78CADFA78E2F5B51A956BFF4DB8E56523E9695E63E32506CFEB912F2A77D22E71BB54C8680893B82AD1BCF337F7F7796D3FB968181D9BA1F7034ABFB1F97B3104CF3203F663E81990B7E090F6C4C5EE1A0E57EC174D3E84AD9E72E6AC7DA6AEA12DF297C131854FBF21AC4E879C23BBC60B4F753"; common[9] = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF"; common[10] = "D6C094AD57F5374F68D58C7B096872D945CEE1F82664E0594421E1D5E3C8E98BC3F0A6AF8F92F19E3FEF9337B99B9C93A055D55A96E425734005A68ED47040FDF00A55936EBA4B93F64CBA1A004E4513611C9B217438A703A2060C2038D0CFAAFFBBA48FB9DAC4B2450DC58CB0320A0317E2A31B44A02787C657FB0C0CBEC11D"; common[11] = "B10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C69A6A9DCA52D23B616073E28675A23D189838EF1E2EE652C013ECB4AEA906112324975C3CD49B83BFACCBDD7D90C4BD7098488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0A151AF5F0DC8B4BD45BF37DF365C1A65E68CFDA76D4DA708DF1FB2BC2E4A4371"; char *prime; prime = BN_bn2hex(key->pkey.dh->p); BIO_printf(out, "---> DH prime: %s\n", prime); int i; for (i = 0; i < 12; i++) { if (!strcmp(prime, common[i])) { BIO_puts(out, "---> Warning - common prime!\n"); break; } }
So you should have something like:
Now you’ll get output such as:
Remember that you may need to employ the -cipher DH
parameter to force OpenSSL to use a DH-based cipher suite. If export-grade as well as stronger DH suites are supported then you’ll also have to use something like -cipher EXP
on a second connection to ensure you test the commonality of both primes.