/****************************************************************************
*																			*
*					cryptlib SSHv2/SSL/TLS DH Public Parameters				*
*						Copyright Peter Gutmann 1998-2013					*
*																			*
****************************************************************************/

#if defined( INC_ALL )
  #include "crypt.h"
#else
  #include "crypt.h"
#endif /* Compiler-specific includes */

#if defined( USE_SSH ) || defined( USE_SSL )

/****************************************************************************
*																			*
*							Predefined DH Values							*
*																			*
****************************************************************************/

/* Predefined DH values from RFC 2409 and RFC 3526.  These have been 
   independently verified by Henrick Hellström <henrick@streamsec.se> to 
   check that:

	a: The numbers match the numbers in the RFCs.
	b: The numbers are safe primes (using both Miller-Rabin tests and Lucas 
	   tests on q = (p-1)/2, and then the Pocklington Criterion on p).
	c: The small constant k is indeed the least positive integer such that 
	   the number is a safe prime */

/* 1024-bit DH parameters from RFC 2409 */

static const BYTE FAR_BSS dh1024SSL[] = {
	0x00, 0x80,		/* p */
		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
		0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
		0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
		0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
		0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
		0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
		0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
		0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
		0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
		0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
		0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
		0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
		0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
		0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
		0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0x00, 0x01,		/* g */
		0x02
	};

/* 1536-, 2048- and 3072-bit parameters from RFC 3526.  There is also a 
   4096-bit value given in the RFC, but using that, and the even larger
   values of 6144 and 8192 bits, is just silly.  See also the comment on 
   defences against clients that request stupid key sizes in processDHE() 
   in ssh2_svr.c */

static const BYTE FAR_BSS dh1536SSL[] = {
	0x00, 0xC0,		/* p */
		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
		0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
		0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
		0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
		0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
		0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
		0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
		0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
		0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
		0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
		0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
		0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
		0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
		0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
		0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
		0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
		0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
		0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
		0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
		0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
		0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
		0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
		0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x23, 0x73, 0x27,
		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0x00, 0x01,		/* g */
		0x02
	};

static const BYTE FAR_BSS dh2048SSL[] = {
	0x01, 0x00,		/* p */
		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
		0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
		0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
		0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
		0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
		0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
		0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
		0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
		0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
		0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
		0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
		0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
		0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
		0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
		0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
		0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
		0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
		0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
		0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
		0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
		0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
		0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
		0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
		0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
		0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
		0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
		0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
		0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
		0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
		0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
		0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68,
		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0x00, 0x01,		/* g */
		0x02
	};

static const BYTE FAR_BSS dh3072SSL[] = {
	0x01, 0x80,		/* p */
		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
		0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
		0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
		0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
		0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
		0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
		0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
		0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
		0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
		0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
		0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
		0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
		0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
		0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
		0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
		0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
		0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
		0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
		0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
		0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
		0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
		0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
		0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
		0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
		0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
		0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
		0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
		0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
		0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
		0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
		0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
		0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
		0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
		0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
		0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
		0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
		0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
		0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
		0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
		0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
		0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
		0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
		0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
		0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
		0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
		0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
		0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x3A, 0xD2, 0xCA,
		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0x00, 0x01,		/* g */
		0x02
	};

/* Checksum values for the DH data */

static int dh1024checksum, dh1536checksum, dh2048checksum, dh3072checksum;

/****************************************************************************
*																			*
*								DH Access Functions							*
*																			*
****************************************************************************/

/* Load a fixed DH key of the appropriate size */

CHECK_RETVAL \
int loadDHcontext( IN_HANDLE const CRYPT_CONTEXT iDHContext, 
				   IN_LENGTH_SHORT_OPT const int requestedKeySize )
	{
	MESSAGE_DATA msgData;
	const void *keyData;
	const int actualKeySize = \
				( requestedKeySize < 128 + 8 ) ? bitsToBytes( 1024 ) : \
				( requestedKeySize < 192 + 8 ) ? bitsToBytes( 1536 ) : \
				( requestedKeySize < 256 + 8 ) ? bitsToBytes( 2048 ) : \
				( requestedKeySize < 384 + 8 ) ? bitsToBytes( 3072 ) : \
				0;
	int keyDataLength, keyDataChecksum;

	REQUIRES( isHandleRangeValid( iDHContext ) );
	REQUIRES( requestedKeySize >= MIN_PKCSIZE && \
			  requestedKeySize <= CRYPT_MAX_PKCSIZE );

	/* Load the built-in DH key value that corresponds best to the client's 
	   requested key size.  We allow for a bit of slop to avoid having 
	   something like a 1025-bit requested key size lead to the use of a 
	   1536-bit key value.

	   In theory we should probably generate a new DH key each time:

		status = krnlSendMessage( iDHContext, IMESSAGE_SETATTRIBUTE,
								  ( MESSAGE_CAST ) &requestedKeySize,
								  CRYPT_CTXINFO_KEYSIZE );
		if( cryptStatusOK( status ) )
			status = krnlSendMessage( iDHContext, IMESSAGE_CTX_GENKEY, 
									  NULL, FALSE );

	   however because the handshake is set up so that the client (rather 
	   than the server) chooses the key size we can't actually perform the 
	   generation until we're in the middle of the handshake.  This means 
	   that the server will grind to a halt during each handshake as it 
	   generates a new key of whatever size takes the client's fancy (it 
	   also leads to a nice potential DoS attack on the server).  To avoid 
	   this problem we use fixed keys of various common sizes.
	   
	   As late as 2014 Java still can't handle DH keys over 1024 bits (it 
	   only allows keys ranging from 512-1024 bits):

		java.security.InvalidAlgorithmParameterException: Prime size must be 
		multiple of 64, and can only range from 512 to 1024 (inclusive)

	   so if you need to talk to a system built in Java you need to hardcode
	   the key size below to 1024 bits, the largest size that Java will 
	   allow */
	switch( actualKeySize )
		{
		case bitsToBytes( 1024 ):
			keyData = dh1024SSL;
			keyDataLength = sizeof( dh1024SSL );
			keyDataChecksum = dh1024checksum;
			break;

		case bitsToBytes( 1536 ):
			keyData = dh1536SSL;
			keyDataLength = sizeof( dh1536SSL );
			keyDataChecksum = dh1536checksum;
			break;

		case bitsToBytes( 2048 ):
			keyData = dh2048SSL;
			keyDataLength = sizeof( dh2048SSL );
			keyDataChecksum = dh2048checksum;
			break;

		case bitsToBytes( 3072 ):
		default:			/* Hier ist der mast zu ende */
			keyData = dh3072SSL;
			keyDataLength = sizeof( dh3072SSL );
			keyDataChecksum = dh3072checksum;
			break;
		}

	/* Make sure that the key data hasn't been corrupted */
	if( keyDataChecksum != checksumData( keyData, keyDataLength ) )
		{
		DEBUG_DIAG(( "Fixed DH value for %d-bit key has been corrupted",
					 bytesToBits( actualKeySize ) ));
		retIntError();
		}

	/* Load the fixed DH key into the context */
	setMessageData( &msgData, ( MESSAGE_CAST ) keyData, keyDataLength );
	return( krnlSendMessage( iDHContext, IMESSAGE_SETATTRIBUTE_S, &msgData, 
							 CRYPT_IATTRIBUTE_KEY_SSL ) );
	}

/* Check that the DH key data is valid */

CHECK_RETVAL \
int checkDHdata( void )
	{
	HASHFUNCTION_ATOMIC hashFunctionAtomic;
	BYTE hashValue[ 20 + 8 ];

	getHashAtomicParameters( CRYPT_ALGO_SHA1, 0, &hashFunctionAtomic, NULL );

	/* Generate/check the SHA-1 values for the primes.  This doesn't cover 
	   all of the data, but is needed to bootstrap the full check because 
	   only the hashes of the primes have been published */
#if 0
	hashFunctionAtomic( hashValue, 20, dh1024SSL + 2, sizeof( dh1024SSL ) - 5 );
	hashFunctionAtomic( hashValue, 20, dh1536SSL + 2, sizeof( dh1536SSL ) - 5 );
	hashFunctionAtomic( hashValue, 20, dh2048SSL + 2, sizeof( dh2048SSL ) - 5 );
	hashFunctionAtomic( hashValue, 20, dh3072SSL + 2, sizeof( dh3072SSL ) - 5 );
#endif /* 0 */

	/* Check the SHA-1 values for the DH data */
	hashFunctionAtomic( hashValue, 20, dh1024SSL, sizeof( dh1024SSL ) );
	if( memcmp( hashValue, \
				"\x46\xF4\x47\xC3\x69\x00\x6F\x22\x91\x0E\x24\xF5\x73\x68\xE6\xF7", 16 ) )
		retIntError();
	hashFunctionAtomic( hashValue, 20, dh1536SSL, sizeof( dh1536SSL ) );
	if( memcmp( hashValue, \
				"\xA3\xEC\x2F\x85\xC7\xD3\x74\xD2\x56\x53\x22\xED\x53\x87\x6F\xDC", 16 ) )
		retIntError();
	hashFunctionAtomic( hashValue, 20, dh2048SSL, sizeof( dh2048SSL ) );
	if( memcmp( hashValue, \
				"\x0E\x8E\x49\x9F\xD9\x18\x02\xCB\x5D\x42\x03\xA5\xE1\x67\x51\xDB", 16 ) )
		retIntError();
	hashFunctionAtomic( hashValue, 20, dh3072SSL, sizeof( dh3072SSL ) );
	if( memcmp( hashValue, \
				"\x8F\x4A\x19\xEF\x85\x1D\x91\xEA\x18\xE8\xB8\xB9\x9F\xF0\xFD\xF8", 16 ) )
		retIntError();

	/* Now that we've verified that the DH data is valid, calculate a 
	   checksum for each value to allow it to be quickly checked before it's
	   loaded into a context */
	dh1024checksum = checksumData( dh1024SSL, sizeof( dh1024SSL ) );
	dh1536checksum = checksumData( dh1536SSL, sizeof( dh1536SSL ) );
	dh2048checksum = checksumData( dh2048SSL, sizeof( dh2048SSL ) );
	dh3072checksum = checksumData( dh3072SSL, sizeof( dh3072SSL ) );

	return( CRYPT_OK );
	}
#endif /* USE_SSH || USE_SSL */
