📄 pgpike.c
字号:
/*____________________________________________________________________________
Copyright (C) 2002 PGP Corporation
All rights reserved.
Platform independent state machine based implementation of
IETF RFC 2409: Internet Key Exchange protocol
Also implements XAuth V6+, Config Mode, and NAT Traversal.
$Id: pgpIKE.c,v 1.129 2002/08/06 20:11:10 dallen Exp $
____________________________________________________________________________*/
#include "pgpIKEPriv.h"
#include "pgpErrors.h"
#include "pgpContext.h"
#include "pgpMem.h"
#include "pgpEndianConversion.h"
#include "pgpHash.h"
#include "pgpHMAC.h"
#include "pgpPFLPriv.h"
#include "pgpPublicKey.h"
#include "pgpSymmetricCipher.h"
#include "pgpCBC.h"
#include "pgpKeys.h"
#include "pgpFeatures.h"
#include "pgpMilliseconds.h"
#include <string.h>
#include <stdio.h>
#if PGP_DEBUG
#define PGPIKE_DEBUG 1
#define PGPIKE_VERBOSE 1
#else
#define PGPIKE_DEBUG 1
#define PGPIKE_VERBOSE 0
#endif
const PGPikeTransform kPGPike_DefaultIKETransforms[] =
{
{
kPGPike_AM_PreSharedKey,
kPGPike_HA_SHA1,
kPGPike_SC_CAST_CBC, 0,
kPGPike_GR_MODPFive
},
{
kPGPike_AM_PreSharedKey,
kPGPike_HA_MD5,
kPGPike_SC_3DES_CBC, 0,
kPGPike_GR_MODPTwo
},
/*{
kPGPike_AM_PreSharedKey,
kPGPike_HA_SHA1,
kPGPike_SC_CAST_CBC, 0,
kPGPike_GR_ECEight
},*/
{
kPGPike_AM_DSS_Sig,
kPGPike_HA_SHA1,
kPGPike_SC_CAST_CBC, 0,
kPGPike_GR_MODPFive
},
{
kPGPike_AM_DSS_Sig,
kPGPike_HA_SHA1,
kPGPike_SC_3DES_CBC, 0,
kPGPike_GR_MODPTwo
},
{
kPGPike_AM_RSA_Sig,
kPGPike_HA_SHA1,
kPGPike_SC_CAST_CBC, 0,
kPGPike_GR_MODPFive
},
{
kPGPike_AM_RSA_Sig,
kPGPike_HA_MD5,
kPGPike_SC_3DES_CBC, 0,
kPGPike_GR_MODPTwo
},
/*{
kPGPike_AM_RSA_Sig,
kPGPike_HA_SHA1,
kPGPike_SC_CAST_CBC, 0,
kPGPike_EC2NGroupType, kPGPike_GR_ECEight
},*/
};
const PGPipsecTransform kPGPike_DefaultIPSECTransforms[] =
{
{ /* ESP, CAST, SHA1 */
TRUE, { kPGPike_ET_CAST, 0, kPGPike_AA_HMAC_SHA, kPGPike_PM_None },
FALSE, { kPGPike_AH_None, kPGPike_AA_None, kPGPike_PM_None },
FALSE, { kPGPike_IC_None },
kPGPike_GR_None
},
{ /* ESP, 3DES, MD5 */
TRUE, { kPGPike_ET_3DES, 0, kPGPike_AA_HMAC_MD5, kPGPike_PM_None },
FALSE, { kPGPike_AH_None, kPGPike_AA_None, kPGPike_PM_None },
FALSE, { kPGPike_IC_None },
kPGPike_GR_None
},
};
const char kPGPike_PGPVendorString1[] = "OpenPGP1";
const char kPGPike_PGPVendorString2[] = "0171"; /* last v change is SDK 171 */
const PGPByte kPGPike_XAuth6VendorID[8] =
{ 0x09, 0x00, 0x26, 0x89, 0xDF, 0xD6, 0xB7, 0x12 };
/* This is the MD5 hash of "draft-ietf-ipsec-nat-t-ike-00" */
const PGPByte kPGPike_NATTraversalVendorID[16] =
{ 0x44, 0x85, 0x15, 0x2d, 0x18, 0xb6, 0xbb, 0xcd,
0x0b, 0xe8, 0xa8, 0x46, 0x95, 0x79, 0xdd, 0xcc };
enum pgpIKEDHComponent_
{
kPGPike_dhP,
kPGPike_dhYi,
kPGPike_dhYr,
PGP_ENUM_FORCE( pgpIKEDHComponent_ )
};
PGPENUM_TYPEDEF( pgpIKEDHComponent_, pgpIKEDHComponent );
/* Insert Big Endian bytes into data structures for prime group or EC.
Those are public "Y" values, received from the peer
*/
static PGPError
sInsertDH(
PGPikeExchange *exchange,
pgpIKEDHComponent compType,
const PGPByte *p,
PGPSize size )
{
PGPError err = kPGPError_NoErr;
#if PGPIKE_VERBOSE
char dbg_msg[80];
pgpCopyMemory( "Insert ", dbg_msg, 8 );
#endif
if( compType == kPGPike_dhYi )
{
#if PGPIKE_VERBOSE
strcat( dbg_msg, "dhYi" );
#endif
pgpAssert( exchange->dhYi == NULL );
exchange->dhYi = pgpContextMemAlloc( exchange->ike->pgpContext, size, 0 );
if( IsNull(exchange->dhYi) )
err = kPGPError_OutOfMemory;
else
{
pgpCopyMemory( p, exchange->dhYi, size );
exchange->dhYi_size = size;
}
}
else if( compType == kPGPike_dhYr )
{
#if PGPIKE_VERBOSE
strcat( dbg_msg, "dhYr" );
#endif
pgpAssert( exchange->dhYr == NULL );
exchange->dhYr = pgpContextMemAlloc( exchange->ike->pgpContext, size, 0 );
if( IsNull(exchange->dhYr) )
err = kPGPError_OutOfMemory;
else
{
pgpCopyMemory( p, exchange->dhYr, size );
exchange->dhYr_size = size;
}
}
else if( compType == kPGPike_dhP ) /* for prime field only */
{
#if PGPIKE_VERBOSE
strcat( dbg_msg, "dhP" );
#endif
pgpAssert( exchange->isPrimeDH );
err = PGPNewBigNum( exchange->ike->pgpContext, TRUE, &exchange->primeDH.dhP );
if( IsntPGPError(err) )
err = PGPBigNumInsertBigEndianBytes( exchange->primeDH.dhP, p, 0, size );
}
#if PGP_DEBUG
else
{
pgpAssert(0);
}
#endif
#if PGPIKE_VERBOSE
pgpIKEDebugData( exchange->ike, dbg_msg, (void*)p, size );
#endif
return err;
}
/* Perform DH step 1 with internal structures,
i.e. G (op) dhX,
where (op) is either exponentiation or scalar multiplication .
*/
static PGPError
sGenerateDH_1( PGPikeExchange *exchange, PGPByte *secretX, PGPSize secretXsize )
{
PGPError err = kPGPError_NoErr;
PGPByte *out1 = NULL;
PGPSize out1_size;
/* allocate buffers */
if( exchange->initiator ) /* store initiator Y value */
{
pgpAssert( exchange->dhYi == NULL );
/* I always transmit compressed */
out1_size = exchange->dhYi_size = exchange->ySizeInTransitMyDH;
exchange->dhYi = pgpContextMemAlloc( exchange->ike->pgpContext,
exchange->dhYi_size, 0 );
if( exchange->dhYi == NULL )
err = kPGPError_OutOfMemory;
else
out1 = exchange->dhYi;
}
else /* store responder Y value */
{
pgpAssert( exchange->dhYr == NULL );
/* always transmit compressed */
out1_size = exchange->dhYr_size = exchange->ySizeInTransitMyDH;
exchange->dhYr = pgpContextMemAlloc( exchange->ike->pgpContext,
exchange->dhYr_size, 0 );
if( exchange->dhYr == NULL )
err = kPGPError_OutOfMemory;
else
out1 = exchange->dhYr;
}
if( IsPGPError(err) )
return err;
pgpAssert( out1_size );
if( exchange->isPrimeDH )
{
PGPBigNumRef dhY = NULL; /* public value, "my" or "his" */
pgpAssert( exchange->primeDH.xSecretDH == NULL );
err = PGPNewBigNum( exchange->ike->pgpContext, TRUE, &exchange->primeDH.xSecretDH );
if( IsntPGPError(err) )
err = PGPBigNumInsertBigEndianBytes(
exchange->primeDH.xSecretDH, secretX, 0, secretXsize );
err = PGPNewBigNum( exchange->ike->pgpContext, TRUE, &dhY );
if( IsntPGPError(err) )
err = PGPBigNumExpMod( exchange->ike->dhPrimeG, exchange->primeDH.xSecretDH, exchange->primeDH.dhP, dhY );
if( IsntPGPError(err) )
err = PGPBigNumExtractBigEndianBytes( dhY, out1, 0, out1_size );
if( dhY != kPGPInvalidBigNumRef )
(void)PGPFreeBigNum( dhY );
}
else
{
err = pgpECIKE_DH1( exchange->ecDH.c, secretX, out1 );
}
return err;
}
static PGPError
sGenerateDH_2(
PGPikeExchange *exchange )
{
PGPError err = kPGPError_NoErr;
pgpAssert( exchange->gXYLen == 0 && exchange->gXY == NULL );
exchange->gXYLen = exchange->xySizeDH;
exchange->gXY = PGPNewSecureData( exchange->ike->memMgr, exchange->gXYLen, 0 );
if( IsNull( exchange->gXY ) )
{
exchange->gXYLen = 0;
return kPGPError_OutOfMemory;
}
if( exchange->isPrimeDH )
{
PGPBigNumRef dhSecret = kPGPInvalidBigNumRef;
PGPBigNumRef dhY = kPGPInvalidBigNumRef;
err = PGPNewBigNum( exchange->ike->pgpContext, TRUE, &dhSecret );
if( IsntPGPError( err) )
err = PGPNewBigNum( exchange->ike->pgpContext, TRUE, &dhY );
if( exchange->initiator )
err = PGPBigNumInsertBigEndianBytes( dhY, exchange->dhYr,
0, exchange->dhYr_size );
else
err = PGPBigNumInsertBigEndianBytes( dhY, exchange->dhYi,
0, exchange->dhYi_size );
if( IsntPGPError(err) )
err = PGPBigNumExpMod( dhY, exchange->primeDH.xSecretDH, exchange->primeDH.dhP, dhSecret );
/* Load gXY with the shared secret */
if( IsntPGPError(err) )
err = PGPBigNumExtractBigEndianBytes( dhSecret,
exchange->gXY, 0, exchange->gXYLen );
if( dhSecret != kPGPInvalidBigNumRef )
(void)PGPFreeBigNum( dhSecret );
if( dhY != kPGPInvalidBigNumRef )
(void)PGPFreeBigNum( dhY );
}
else
{
if( exchange->initiator )
err = pgpECIKE_import_Y( exchange->ecDH.c, exchange->dhYr );
else
err = pgpECIKE_import_Y( exchange->ecDH.c, exchange->dhYi );
if( IsntPGPError(err) )
err = pgpECIKE_DH2( exchange->ecDH.c, exchange->gXY );
}
return err;
}
/* This function makes assumptions about values of group IDs for performance */
const static PGPByte id2type[] =
{
0,
kPGPike_MODPGroupType, /* kPGPike_GR_MODPOne */
kPGPike_MODPGroupType, /* kPGPike_GR_MODPTwo */
0, /* don't support EC 2^composite */
0,
kPGPike_MODPGroupType, /* kPGPike_GR_MODPFive */
kPGPike_EC2NGroupType, /* kPGPike_GR_ECSix */
kPGPike_EC2NGroupType, /* kPGPike_GR_ECSeven */
kPGPike_EC2NGroupType, /* kPGPike_GR_ECEight */
kPGPike_EC2NGroupType /* kPGPike_GR_ECNine */
};
static PGPByte
sGroupTypeFromGroupID(
PGPikeGroupID groupID )
{
if( groupID >= sizeof(id2type) )
{
/* TODO: when IANA number is assigned, use id2type instead of switch */
switch( groupID )
{
case kPGPike_GR_MODP2048:
case kPGPike_GR_MODP3072:
case kPGPike_GR_MODP4096:
case kPGPike_GR_MODP6144:
case kPGPike_GR_MODP8192:
return kPGPike_MODPGroupType;
default:
break;
}
return 0;
}
return id2type[groupID];
}
PGPError
PGPNewIKEContext(
PGPContextRef context,
PGPikeMessageProcPtr ikeMessageProc,
void * inUserData,
PGPikeContextRef * outRef )
{
PGPError err = kPGPError_NoErr;
PGPikeContextPriv * pContext;
*outRef = NULL;
PGPValidatePtr( context );
if( IsNull( ikeMessageProc ) )
return kPGPError_BadParams;
pContext = (PGPikeContextPriv *) pgpContextMemAlloc( context,
sizeof(PGPikeContextPriv),
kPGPMemoryMgrFlags_Clear );
if( IsntNull( pContext ) )
{
pContext->pgpContext = context;
pContext->memMgr = PGPPeekContextMemoryMgr( context );
pContext->msgProc = ikeMessageProc;
pContext->userData = inUserData;
pContext->pending = NULL;
pContext->cookieDough = FALSE;
err = PGPContextGetRandomBytes( context, &pContext->cookieSecret,
kPGPike_CookieSize );
if( IsntPGPError( err ) )
pContext->cookieDough = TRUE;
err = kPGPError_NoErr; /* no entropy error here will be retried later */
pContext->secLifeTimeIKE = kPGPike_DefaultSecLife;
pContext->kbLifeTimeIKE = kPGPike_DefaultKBLife;
pContext->secLifeTimeIPSEC = kPGPike_DefaultSecLife;
pContext->kbLifeTimeIPSEC = kPGPike_DefaultKBLife;
pContext->defaultIKEProps = (PGPikeTransform *) pgpContextMemAlloc(
context, sizeof(kPGPike_DefaultIKETransforms),
kPGPMemoryMgrFlags_Clear );
if( IsNull( pContext->defaultIKEProps ) )
{
err = kPGPError_OutOfMemory;
goto done;
}
pContext->numIKEProps = sizeof(kPGPike_DefaultIKETransforms) /
sizeof(PGPikeTransform);
pgpCopyMemory( &kPGPike_DefaultIKETransforms[0], pContext->defaultIKEProps,
sizeof(kPGPike_DefaultIKETransforms) );
pContext->defaultIPSECProps = (PGPipsecTransform *) pgpContextMemAlloc(
context, sizeof(kPGPike_DefaultIPSECTransforms),
kPGPMemoryMgrFlags_Clear );
if( IsNull( pContext->defaultIPSECProps ) )
{
err = kPGPError_OutOfMemory;
goto done;
}
pContext->numIPSECProps = sizeof(kPGPike_DefaultIPSECTransforms) /
sizeof(PGPipsecTransform);
pgpCopyMemory( &kPGPike_DefaultIPSECTransforms[0],
pContext->defaultIPSECProps,
sizeof(kPGPike_DefaultIPSECTransforms) );
pContext->allowedAlgorithms.cast5 = TRUE;
pContext->allowedAlgorithms.aes = kPGPike_AESKeyLengthAll;
pContext->allowedAlgorithms.tripleDES = TRUE;
pContext->allowedAlgorithms.singleDES = FALSE;
pContext->allowedAlgorithms.espNULL = FALSE;
pContext->allowedAlgorithms.sha1 = TRUE;
pContext->allowedAlgorithms.sha2_256 = TRUE;
pContext->allowedAlgorithms.sha2_384 = TRUE;
pContext->allowedAlgorithms.sha2_512 = TRUE;
pContext->allowedAlgorithms.md5 = TRUE;
pContext->allowedAlgorithms.noAuth = FALSE;
pContext->allowedAlgorithms.lzs = TRUE;
pContext->allowedAlgorithms.deflate = TRUE;
pContext->allowedAlgorithms.modpOne768 = TRUE;
pContext->allowedAlgorithms.modpTwo1024 = TRUE;
pContext->allowedAlgorithms.modpFive1536 = TRUE;
pContext->allowedAlgorithms.ec2n163 = FALSE;
pContext->allowedAlgorithms.ec2n283 = FALSE;
pContext->allowedAlgorithms.modp2048 = FALSE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -