📄 pgpsecsh.c
字号:
/*____________________________________________________________________________
Copyright (C) 2002 PGP Corporation
All rights reserved.
Platform independent implementation of SECSH v 1.5
$Id: pgpSECSH.c,v 1.7 2002/08/06 20:11:13 dallen Exp $
____________________________________________________________________________*/
#include "pgpSECSHPriv.h"
#include "pgpErrors.h"
#include "pgpContext.h"
#include "pgpMem.h"
#include "pgpEndianConversion.h"
#include "pgpHash.h"
#include "pgpHMAC.h"
#include "pgpPublicKey.h"
#include "pgpSymmetricCipher.h"
#include "pgpCBC.h"
#include "pgpCFB.h"
#include "pgpKeys.h"
#include "pgpFeatures.h"
#include "pgpPFLPriv.h"
#include "pgpKeyPriv.h"
#include "pgpBigNum.h"
#include "pgpOptionListPriv.h"
#include <string.h>
#define CKERR if( err ) goto done
#define CKNULL(p) if( IsNull(p) ) { \
err = kPGPError_OutOfMemory; \
goto done; }
#define FATALSECSH( x ) { \
err = x; \
session->state = kPGPsecsh_FatalErrorState; \
goto done; }
#define CRC32_POLY 0xedb88320L
#define SECSHIDPREFIX "SSH-"
#define SECSHID "SSH-1.4-PGPTest1.0\n"
#define SECSHNUMCLIENTSTATES 5
#define SECSHNUMEVENTS 5
/* -1 is ignored, -2 is an error */
static PGPInt8 kPGPsecsh_ClientStateTable[SECSHNUMCLIENTSTATES][SECSHNUMEVENTS] =
{
/* S F PK CH D */
{ /* 0 */ -2, -2, 1, -2, 0, }, /* Waiting for Server PK */
{ /* 1 */ 2, -2, -2, -2, 1, }, /* Sent session key */
{ /* 2 */ 5, 3, -2, -2, 2, }, /* Sent user name */
{ /* 3 */ -2, -2, -2, 4, 3, }, /* Requested RSA challenge */
{ /* 4 */ 5, -2, -2, -2, 4, } /* Sent RSA response */
};
PGPInt8
pgpSECSHNextState(
PGPsecshSessionPriv * session,
PGPByte event )
{
PGPInt8 newState;
pgpAssert( session->isClientSide );
newState = kPGPsecsh_ClientStateTable[session->intState][event];
if( newState == -2 )
session->state = kPGPsecsh_FatalErrorState;
else if( newState >= 0 )
session->intState = newState;
return newState;
}
static void
sCalculateCRC(
PGPByte const * inBuffer,
PGPSize inLength,
PGPByte * outCRC )
{
PGPUInt32 crc = 0;
PGPUInt32 b;
PGPUInt32 i;
while( inLength-- )
{
crc ^= *inBuffer++;
for( i = 0; i < 8; i++ )
{
b = (crc & 1);
crc >>= 1;
if( b )
crc ^= CRC32_POLY;
}
}
PGPUInt32ToEndian( crc, kPGPBigEndian, outCRC );
}
/* Return the size in bits of the bignum stored in bigendian form in
* inBuffer. Return outOffset as the offset to the first nonzero
* byte.
*/
static PGPUInt16
sCountBits(
const PGPByte * inBuffer,
PGPSize inLength,
PGPSize * outOffset )
{
PGPSize off;
PGPUInt16 cnt;
for( off=0; off<inLength; ++off )
if( inBuffer[off] != 0 )
break;
*outOffset = off;
if( off == inLength )
return 0;
for( cnt=7; (inBuffer[off] & (1<<cnt))==0; --cnt )
;
return cnt + 8*(inLength - off - 1);
}
/*
* Starting with RSA key data in SECSH format (exponent then modulus),
* create a PGP key with that data and return the keydb and key.
*/
static PGPError
sDataToPGPKey (
PGPsecshSessionPriv * session,
PGPByte * inBuffer,
PGPUInt32 inLength,
PGPUInt32 *outDataUsed,
PGPKeyDBRef * outKDB,
PGPKeyDBObjRef * outKey)
{
PGPUInt32 expbytes,
modbytes;
PGPUInt32 keybufLength;
PGPUInt32 len = inLength;
PGPByte * p = inBuffer;
PGPByte *bp,
*exponent,
*modulus;
PGPKeyIterRef kiter;
PGPKeyDBRef kdb;
PGPKeyDBObjRef key;
PGPByte * pgpBuffer = NULL;
PGPSize bufLength = 0;
PGPError err = kPGPError_NoErr;
*outDataUsed = 0;
*outKDB = kInvalidPGPKeyDBRef;
*outKey = kInvalidPGPKeyDBObjRef;
expbytes = (((p[0]<<8) | p[1]) + 7) / 8;
if( len < expbytes + 2 )
{
(void)pgpSECSHAlert( session, kPGPsecsh_AL_FatalAlert,
kPGPsecsh_AT_DecodeError );
FATALSECSH( kPGPError_SECSHProtocolViolation );
}
exponent = p;
p += expbytes + 2;
len -= expbytes + 2;
modbytes = (((p[0]<<8) | p[1]) + 7) / 8;
if( len < modbytes + 2 )
{
(void)pgpSECSHAlert( session, kPGPsecsh_AL_FatalAlert,
kPGPsecsh_AT_DecodeError );
FATALSECSH( kPGPError_SECSHProtocolViolation );
}
modulus = p;
p += modbytes + 2;
len -= modbytes + 2;
keybufLength = 1 + 2 + 1 + 4 + 2 + 1 + 2 + modbytes + 2 + expbytes;
bufLength = keybufLength + 2 + strlen( session->hostName );
pgpBuffer = (PGPByte *) PGPNewData(session->memMgr, bufLength, 0 );
CKNULL( pgpBuffer );
bp = pgpBuffer;
*bp++ = 0x99; /* RSA key buffer */
*bp++ = ((keybufLength-3)>>8) & 0xff;
*bp++ = (keybufLength-3) & 0xff;
*bp++ = 0x03; /* key version */
*bp++ = 0x00; /* creation date */
*bp++ = 0x00;
*bp++ = 0x00;
*bp++ = 0x00;
*bp++ = 0x00; /* expiration interval */
*bp++ = 0x00;
*bp++ = 0x01; /* key type (1 = RSA) */
pgpCopyMemory( modulus, bp, modbytes+2 );
bp += modbytes+2;
pgpCopyMemory( exponent, bp, expbytes+2 );
bp += expbytes+2;
*bp++ = 0xb4; /* userid */
*bp++ = strlen( session->hostName );
pgpCopyMemory( session->hostName, bp, strlen( session->hostName ) );
bp += strlen( session->hostName );
PGPImport( session->pgpContext, &kdb,
PGPOInputBuffer( session->pgpContext, pgpBuffer, bufLength ),
PGPOLastOption( session->pgpContext ) );
if( !PGPKeyDBRefIsValid( kdb ) )
{
(void)pgpSECSHAlert( session, kPGPsecsh_AL_FatalAlert,
kPGPsecsh_AT_DecodeError );
FATALSECSH( kPGPError_SECSHProtocolViolation );
}
PGPNewKeyIterFromKeyDB( kdb, &kiter );
PGPKeyIterNextKeyDBObj( kiter, kPGPKeyDBObjType_Key, &key );
PGPFreeKeyIter( kiter );
*outDataUsed = p - inBuffer;
*outKDB = kdb;
*outKey = key;
done:
if( IsntNull( pgpBuffer ) )
{
(void)PGPFreeData( pgpBuffer );
}
return err;
}
/* Print a bignum to a buffer, return length of string. If buffer is
* null just return the length. */
static PGPInt32
sPrint10(PGPContextRef context, char *outbuf, PGPBigNumRef bn)
{
PGPBigNumRef pbig, pbig1;
PGPBigNumRef ten, zero, rem;
char buf[3000]; /* up to 9000 bits */
PGPInt32 bufi = sizeof(buf)-1;
PGPInt32 n;
buf[bufi] = '\0';
PGPNewBigNum( context, FALSE, &pbig );
PGPNewBigNum( context, FALSE, &pbig1 );
PGPNewBigNum( context, FALSE, &rem );
PGPNewBigNum( context, FALSE, &zero );
PGPNewBigNum( context, FALSE, &ten );
PGPBigNumSetQ( ten, 10 );
PGPAssignBigNum (bn, pbig);
while (PGPBigNumCompare (pbig, zero) != 0) {
PGPBigNumDivide( pbig, ten, pbig1, rem );
PGPAssignBigNum( pbig1, pbig );
n = PGPBigNumGetLSWord (rem);
buf[--bufi] = n + '0';
}
PGPFreeBigNum (zero);
PGPFreeBigNum (ten);
PGPFreeBigNum (pbig);
PGPFreeBigNum (pbig1);
PGPFreeBigNum (rem);
if( outbuf != NULL )
memcpy( outbuf, buf+bufi, sizeof(buf)-bufi );
return sizeof(buf) - bufi - 1;
}
PGPError
pgpSECSHClientChooseAlgorithm(
PGPsecshSessionPriv * session,
PGPCipherAlgorithm * outCipher )
{
PGPError err = kPGPError_NoErr;
if( ! ( session->cipherMask & (1 << kPGPsecsh_CT_IDEA) ) )
{
(void)pgpSECSHAlert( session, kPGPsecsh_AL_FatalAlert,
kPGPsecsh_AT_InsufficientSecurity );
FATALSECSH( kPGPError_SECSHNoCommonCipher );
}
*outCipher = kPGPCipherAlgorithm_IDEA;
done:
return err;
}
PGPError
pgpSECSHBufferRawData(
PGPsecshSessionPriv * session,
const PGPByte * rawData,
PGPSize rawDataSize )
{
PGPError err = kPGPError_NoErr;
err = PGPReallocData( session->memMgr,
(void **) &session->rcvdRawData,
session->rawDataSize + rawDataSize, 0 ); CKERR;
pgpCopyMemory( rawData, session->rcvdRawData + session->rawDataSize,
rawDataSize );
session->rawDataSize += rawDataSize;
done:
return err;
}
PGPError
pgpSECSHExtractRawData(
PGPsecshSessionPriv * session,
PGPByte * rawData,
PGPSize * rawDataSize )
{
PGPError err = kPGPError_NoErr;
PGPSize maxSize = *rawDataSize;
*rawDataSize = 0;
if( ( maxSize > 0 ) && ( session->rawDataSize > 0 ) )
{
if( maxSize > session->rawDataSize )
maxSize = session->rawDataSize;
pgpCopyMemory( session->rcvdRawData, rawData, maxSize );
*rawDataSize = maxSize;
pgpCopyMemory( session->rcvdRawData + maxSize,
session->rcvdRawData, session->rawDataSize - maxSize );
session->rawDataSize -= maxSize;
err = PGPReallocData( session->memMgr,
(void **) &session->rcvdRawData,
session->rawDataSize, 0 ); CKERR;
}
done:
return err;
}
PGPError
pgpSECSHBufferSendData(
PGPsecshSessionPriv * session,
const PGPByte * sendData,
PGPSize sendDataSize )
{
PGPError err = kPGPError_NoErr;
err = PGPReallocData( session->memMgr,
(void **) &session->queuedSendData,
session->queuedSendSize + sendDataSize, 0 ); CKERR;
pgpCopyMemory( sendData, session->queuedSendData + session->queuedSendSize,
sendDataSize );
session->queuedSendSize += sendDataSize;
done:
return err;
}
PGPError
pgpSECSHReceivePacket(
PGPsecshSessionPriv * session,
PGPByte * outType,
PGPByte ** outBuffer,
PGPSize * outLength )
{
PGPError err = kPGPError_NoErr;
PGPError rerr = kPGPError_NoErr;
PGPByte header[kPGPsecsh_RecordLengthSize];
PGPByte * buffer = NULL;
PGPSize rcvd;
PGPUInt16 length;
PGPUInt16 bufLength;
PGPUInt8 padLength;
PGPInt32 bytesRead;
PGPByte crcCheck[kPGPsecsh_CRCSize];
*outType = 0;
*outBuffer = NULL;
*outLength = 0;
rcvd = kPGPsecsh_RecordLengthSize;
err = pgpSECSHExtractRawData( session, header, &rcvd ); CKERR;
for(; rcvd < kPGPsecsh_RecordLengthSize; rcvd += bytesRead)
{
bytesRead = (session->secshReceiveProc)( session->secshReceiveUserData,
header + rcvd,
(PGPInt32)( kPGPsecsh_RecordLengthSize - rcvd ) );
if( bytesRead < 0 )
{
if( bytesRead != kPGPError_SECSHWouldBlock )
{
FATALSECSH( kPGPError_SECSHUnexpectedClose );
}
else
{
rerr = kPGPError_SECSHWouldBlock;
bytesRead = 0;
}
}
if( bytesRead == 0 )
{
if( session->blocking )
{
FATALSECSH( kPGPError_SECSHUnexpectedClose );
}
else
{
if( rcvd )
{
err = pgpSECSHBufferRawData( session, header, rcvd ); CKERR;
if(rerr == kPGPError_SECSHWouldBlock)
/* check to see if receive call returned a blocking error */
{
err = kPGPError_SECSHWouldBlock;
}
}
else if(rerr == kPGPError_SECSHWouldBlock)
/* check for blocking error */
{
err = kPGPError_SECSHWouldBlock;
}
goto done;
}
}
}
pgpAssert( rcvd == kPGPsecsh_RecordLengthSize );
length = PGPEndianToUInt32( kPGPBigEndian, &header[0] );
if( length <= 0 || length > kPGPsecsh_MaximumPacketSize )
{
(void)pgpSECSHAlert( session, kPGPsecsh_AL_FatalAlert,
kPGPsecsh_AT_DecodeError );
FATALSECSH( kPGPError_SECSHProtocolViolation );
}
padLength = 8 - (length & 7);
bufLength = length + padLength;
buffer = (PGPByte *) PGPNewData(session->memMgr, bufLength, 0 );
CKNULL( buffer );
rcvd = bufLength;
err = pgpSECSHExtractRawData( session, buffer, &rcvd ); CKERR;
for(; rcvd < bufLength; rcvd += bytesRead)
{
bytesRead = (session->secshReceiveProc)( session->secshReceiveUserData,
buffer + rcvd, (PGPInt32)( bufLength - rcvd ) );
if( bytesRead < 0 )
{
if( bytesRead != kPGPError_SECSHWouldBlock )
{
(void)PGPFreeData( buffer );
buffer = NULL;
FATALSECSH( kPGPError_SECSHUnexpectedClose );
}
else
{
bytesRead = 0;
rerr = kPGPError_SECSHWouldBlock;
}
}
if( bytesRead == 0 )
{
if( session->blocking )
{
FATALSECSH( kPGPError_SECSHUnexpectedClose );
}
else
{
if( rcvd )
{
err = pgpSECSHBufferRawData( session, header,
kPGPsecsh_RecordLengthSize );CKERR;
err = pgpSECSHBufferRawData( session, buffer, rcvd ); CKERR;
}
if(rerr == kPGPError_SECSHWouldBlock)
err = kPGPError_SECSHWouldBlock;
(void)PGPFreeData( buffer );
buffer = NULL;
goto done;
}
}
}
pgpAssert( rcvd == bufLength );
/* Decrypt data if appropriate */
if( session->encrypting )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -