Diffie-Hellman parameters

From OpenSSLWiki
Revision as of 20:55, 12 May 2021 by Jwalton (talk | contribs) (Spelling.)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

TLS key agreement algorithms use Diffie-Hellman groups and provide perfect forward secrecy (PFS). To use Diffie-Hellman groups and cipher suites with perfect forward secrecy, you must set up Diffie-Hellman parameters at the server or the PFS cipher suites will be silently ignored.

Your Diffie-Hellman group parameters should match the key size used in the server's certificate. If you use a 2048-bit RSA prime in the server's certificate, then use a 2048-bit Diffie-Hellman group for key agreement.

Due to Logjam vulnerabilities you should use a group with 2048-bits or higher.

Diffie-Hellman[edit]

SSL_CTX_set_tmp_dh is used to set the Diffie-Hellman parameters for a context. One of the easiest ways to get Diffie-Hellman parameters to use with this function is to generate random Diffie-Hellman parameters with the dhparam command-line program with the -C option, and embed the resulting code fragment in your program. For example, openssl dhparam -C 2236 might result in:

#ifndef HEADER_DH_H
#include <openssl/dh.h>
#endif
DH *get_dh2236()
	{
	static unsigned char dh2236_p[]={
		0x0F,0x52,0xE5,0x24,0xF5,0xFA,0x9D,0xDC,0xC6,0xAB,0xE6,0x04,
		0xE4,0x20,0x89,0x8A,0xB4,0xBF,0x27,0xB5,0x4A,0x95,0x57,0xA1,
		0x06,0xE7,0x30,0x73,0x83,0x5E,0xC9,0x23,0x11,0xED,0x42,0x45,
		0xAC,0x49,0xD3,0xE3,0xF3,0x34,0x73,0xC5,0x7D,0x00,0x3C,0x86,
		0x63,0x74,0xE0,0x75,0x97,0x84,0x1D,0x0B,0x11,0xDA,0x04,0xD0,
		0xFE,0x4F,0xB0,0x37,0xDF,0x57,0x22,0x2E,0x96,0x42,0xE0,0x7C,
		0xD7,0x5E,0x46,0x29,0xAF,0xB1,0xF4,0x81,0xAF,0xFC,0x9A,0xEF,
		0xFA,0x89,0x9E,0x0A,0xFB,0x16,0xE3,0x8F,0x01,0xA2,0xC8,0xDD,
		0xB4,0x47,0x12,0xF8,0x29,0x09,0x13,0x6E,0x9D,0xA8,0xF9,0x5D,
		0x08,0x00,0x3A,0x8C,0xA7,0xFF,0x6C,0xCF,0xE3,0x7C,0x3B,0x6B,
		0xB4,0x26,0xCC,0xDA,0x89,0x93,0x01,0x73,0xA8,0x55,0x3E,0x5B,
		0x77,0x25,0x8F,0x27,0xA3,0xF1,0xBF,0x7A,0x73,0x1F,0x85,0x96,
		0x0C,0x45,0x14,0xC1,0x06,0xB7,0x1C,0x75,0xAA,0x10,0xBC,0x86,
		0x98,0x75,0x44,0x70,0xD1,0x0F,0x20,0xF4,0xAC,0x4C,0xB3,0x88,
		0x16,0x1C,0x7E,0xA3,0x27,0xE4,0xAD,0xE1,0xA1,0x85,0x4F,0x1A,
		0x22,0x0D,0x05,0x42,0x73,0x69,0x45,0xC9,0x2F,0xF7,0xC2,0x48,
		0xE3,0xCE,0x9D,0x74,0x58,0x53,0xE7,0xA7,0x82,0x18,0xD9,0x3D,
		0xAF,0xAB,0x40,0x9F,0xAA,0x4C,0x78,0x0A,0xC3,0x24,0x2D,0xDB,
		0x12,0xA9,0x54,0xE5,0x47,0x87,0xAC,0x52,0xFE,0xE8,0x3D,0x0B,
		0x56,0xED,0x9C,0x9F,0xFF,0x39,0xE5,0xE5,0xBF,0x62,0x32,0x42,
		0x08,0xAE,0x6A,0xED,0x88,0x0E,0xB3,0x1A,0x4C,0xD3,0x08,0xE4,
		0xC4,0xAA,0x2C,0xCC,0xB1,0x37,0xA5,0xC1,0xA9,0x64,0x7E,0xEB,
		0xF9,0xD3,0xF5,0x15,0x28,0xFE,0x2E,0xE2,0x7F,0xFE,0xD9,0xB9,
		0x38,0x42,0x57,0x03,
		};
	static unsigned char dh2236_g[]={
		0x02,
		};
	DH *dh;

	if ((dh=DH_new()) == NULL) return(NULL);
	dh->p=BN_bin2bn(dh2236_p,sizeof(dh2236_p),NULL);
	dh->g=BN_bin2bn(dh2236_g,sizeof(dh2236_g),NULL);
	if ((dh->p == NULL) || (dh->g == NULL))
		{ DH_free(dh); return(NULL); }
	return(dh);
	}

which can then be used like this:

DH *dh = get_dh2236 ();
if (1 != SSL_CTX_set_tmp_dh (ctx, dh))
  error ();
DH_free (dh);

Be sure to choose a bit length appropriate to the security level you want to achieve, although keep in mind that Diffie-Hellman parameters longer than 2236 bits may be incompatible with older versions of NSS. Even worse, it appears that versions of Java prior to 1.7 don't support Diffie-Hellman parameters longer than 1024 bits!

Validating Parameters[edit]

The Diffie-Hellman parameters should be validated after loading. To perform paramter validation, you call DH_check. DH_check returns 0 or a bitmask values of the following:

  • DH_CHECK_P_NOT_PRIME (0x01)
  • DH_CHECK_P_NOT_SAFE_PRIME (0x02)
  • DH_UNABLE_TO_CHECK_GENERATOR (0x04)
  • DH_NOT_SUITABLE_GENERATOR (0x08)

The validation code might look as follows (error checking omitted for clarity):

BIO* bio = ...;
DH* dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);

int rc, codes = 0;
rc = DH_check(dh, &codes);
assert(rc == 1);

if(BN_is_word(dh->g, DH_GENERATOR_2))
{
    long residue = BN_mod_word(dh->p, 24);
    if(residue == 11 || residue == 23) {
        codes &= ~DH_NOT_SUITABLE_GENERATOR;
    }
}

if (codes & DH_UNABLE_TO_CHECK_GENERATOR)
    printf("DH_check: failed to test generator\n");

if (codes & DH_NOT_SUITABLE_GENERATOR)
    printf("DH_check: g is not a suitable generator\n");

if (codes & DH_CHECK_P_NOT_PRIME)
    printf("DH_check: p is not prime\n");

if (codes & DH_CHECK_P_NOT_SAFE_PRIME)
    printf("DH_check: p is not a safe prime\n");

The additional call to BN_mod_word(dh->p, 24) (and unmasking of DH_NOT_SUITABLE_GENERATOR) is performed to ensure your program accepts IETF group parameters. OpenSSL checks the prime is congruent to 11 when g = 2; while the IETF's primes are congruent to 23 when g = 2. Without the test, the IETF parameters would fail validation. For details, see Diffie-Hellman Parameter Check (when g = 2, must p mod 24 == 11?).

Elliptic curve Diffie-Hellman[edit]

For elliptic curve Diffie-Hellman, you can do something like this:

EC_KEY *ecdh = EC_KEY_new_by_curve_name (NID_X9_62_prime256v1);
if (! ecdh)
  error ();
if (1 != SSL_CTX_set_tmp_ecdh (ctx, ecdh))
  error ();
EC_KEY_free (ecdh);

Or, in OpenSSL 1.0.2 (not yet released, as of Feb 2013) and higher, you should be able to do:

SSL_CTX_set_ecdh_auto (ctx, 1)

For more information, see Elliptic Curve Diffie Hellman and Elliptic Curve Cryptography.

Diffie-Hellman Groups[edit]

Ephemeral Diffie-Hellman key agreement needs to happen over a group. The client and server will each pick a random value in the group and perform key agreement with the random parameters. For each run of the protocol, the random parameters will change but the group will remain the same. When you need a group you can either calculate one; or you can use a standard group published by a standards body like the IETF.

Calculating a group is an expensive operation because the safe primes used for the group are harder to find. As the group size gets larger it takes more time to find them. A 3072-bit group can take minutes to find, and a 8192-bit group can take hours to find in the worst case.

To avoid the runtime costs associated with finding a group, you typically you use a standard group, like those published in RFC 3526 or RFC 7919. The declarations for the IETF groups are provided below.

RFC 3526 Groups[edit]

Below are five Diffie-Hellman MODP groups specified in RFC 3526, More Modular Exponential (MODP) Diffie-Hellman groups for Internet Key Exchange (IKE) (the 1024-bit parameter is from RFC 2409). They can be used with PEM_read_bio_DHparams and a memory BIO. RFC 3526 also offers 1536-bit, 6144-bit and 8192-bit primes.

static const char g_dh1024_sz[] =
    "-----BEGIN DH PARAMETERS-----\n"
    "MIGHAoGBAP//////////yQ/aoiFowjTExmKLgNwc0SkCTgiKZ8x0Agu+pjsTmyJR\n"
    "Sgh5jjQE3e+VGbPNOkMbMCsKbfJfFDdP4TVtbVHCReSFtXZiXn7G9ExC6aY37WsL\n"
    "/1y29Aa37e44a/taiZ+lrp8kEXxLH+ZJKGZR7OZTgf//////////AgEC\n"
    "-----END DH PARAMETERS-----\n";

static const char g_dh1536_sz[] = "-----BEGIN DH PARAMETERS-----\n"
    "MIHHAoHBAP//////////yQ/aoiFowjTExmKLgNwc0SkCTgiKZ8x0Agu+pjsTmyJR\n"
    "Sgh5jjQE3e+VGbPNOkMbMCsKbfJfFDdP4TVtbVHCReSFtXZiXn7G9ExC6aY37WsL\n"
    "/1y29Aa37e44a/taiZ+lrp8kEXxLH+ZJKGZR7ORbPcIAfLihY78FmNpINhxV05pp\n"
    "Fj+o/STPX4NlXSPco62WHGLzViCFUrue1SkHcJaWbWcMNU5KvJgE8XRsCMojcyf/\n"
    "/////////wIBAg==\n"
    "-----END DH PARAMETERS-----\n";

static const char g_dh2048_sz[] =
    "-----BEGIN DH PARAMETERS-----\n"
    "MIIBCAKCAQEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb\n"
    "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft\n"
    "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT\n"
    "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh\n"
    "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq\n"
    "5RXSJhiY+gUQFXKOWoqsqmj//////////wIBAg==\n"
    "-----END DH PARAMETERS-----\n";

static const char g_dh3072_sz[] =
    "-----BEGIN DH PARAMETERS-----\n"
    "MIIBiAKCAYEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb\n"
    "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft\n"
    "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT\n"
    "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh\n"
    "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq\n"
    "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM\n"
    "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq\n"
    "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqTrS\n"
    "yv//////////AgEC\n"
    "-----END DH PARAMETERS-----\n";

static const char g_dh4096_sz[] =
    "-----BEGIN DH PARAMETERS-----\n"
    "MIICCAKCAgEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb\n"
    "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft\n"
    "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT\n"
    "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh\n"
    "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq\n"
    "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM\n"
    "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq\n"
    "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI\n"
    "ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O\n"
    "+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI\n"
    "HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0BjGZ//////////8CAQI=\n"
    "-----END DH PARAMETERS-----\n";

RFC 7919 Groups[edit]

Below are three additional Diffie-Hellman groups specified in RFC 7919, Negotiated Finite Field Diffie-Hellman Ephemeral Parameters for Transport Layer Security (TLS). They can be used with PEM_read_bio_DHparams and a memory BIO.

static const char g_ffdhe2048_sz[] =
    "-----BEGIN DH PARAMETERS-----\n"
    "MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz\n"
    "+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a\n"
    "87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7\n"
    "YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi\n"
    "7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD\n"
    "ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==\n"
    "-----END DH PARAMETERS-----\n";

static const char g_ffdhe3072_sz[] =
    "-----BEGIN DH PARAMETERS-----\n"
    "MIIBiAKCAYEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz\n"
    "+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a\n"
    "87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7\n"
    "YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi\n"
    "7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD\n"
    "ssbzSibBsu/6iGtCOGEfz9zeNVs7ZRkDW7w09N75nAI4YbRvydbmyQd62R0mkff3\n"
    "7lmMsPrBhtkcrv4TCYUTknC0EwyTvEN5RPT9RFLi103TZPLiHnH1S/9croKrnJ32\n"
    "nuhtK8UiNjoNq8Uhl5sN6todv5pC1cRITgq80Gv6U93vPBsg7j/VnXwl5B0rZsYu\n"
    "N///////////AgEC\n"
    "-----END DH PARAMETERS-----\n";

static const char g_ffdhe4096_sz[] =
    "-----BEGIN DH PARAMETERS-----\n"
    "MIICCAKCAgEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz\n"
    "+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a\n"
    "87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7\n"
    "YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi\n"
    "7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD\n"
    "ssbzSibBsu/6iGtCOGEfz9zeNVs7ZRkDW7w09N75nAI4YbRvydbmyQd62R0mkff3\n"
    "7lmMsPrBhtkcrv4TCYUTknC0EwyTvEN5RPT9RFLi103TZPLiHnH1S/9croKrnJ32\n"
    "nuhtK8UiNjoNq8Uhl5sN6todv5pC1cRITgq80Gv6U93vPBsg7j/VnXwl5B0rZp4e\n"
    "8W5vUsMWTfT7eTDp5OWIV7asfV9C1p9tGHdjzx1VA0AEh/VbpX4xzHpxNciG77Qx\n"
    "iu1qHgEtnmgyqQdgCpGBMMRtx3j5ca0AOAkpmaMzy4t6Gh25PXFAADwqTs6p+Y0K\n"
    "zAqCkc3OyX3Pjsm1Wn+IpGtNtahR9EGC4caKAH5eZV9q//////////8CAQI=\n"
    "-----END DH PARAMETERS-----\n";