⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ssl.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 5 页
字号:

	[ hdr | IV | data | MAC | pad ]	|
			   +------------------+	| Unwrap, removes MAC, pad, 
			   |		|			| returns data length
			 buffer	 length 

   Processing of the header and IV during unwrapping have already been 
   performed during the packet header read, so the two functions aren't
   quite isometric */

static int wrapData( SESSION_INFO *sessionInfoPtr, BYTE *buffer, 
					 const int length, const int type )
	{
	BYTE *bufPtr = buffer;
	const int ivSize = \
				( sessionInfoPtr->protocolFlags & SSL_PFLAG_EXPLICITIV ) ? \
				sessionInfoPtr->cryptBlocksize : 0;
	int startOffset = sessionInfoPtr->sendBufStartOfs, dataLength;

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( length >= 0 && length <= MAX_PACKET_SIZE );
	assert( isWritePtr( buffer, length ) );
	assert( startOffset >= SSL_HEADER_SIZE ); 

	/* MAC the payload */
	if( sessionInfoPtr->version == SSL_MINOR_VERSION_SSL )
		dataLength = macDataSSL( sessionInfoPtr, bufPtr + startOffset, 
								 length, type, FALSE );
	else
		dataLength = macDataTLS( sessionInfoPtr, bufPtr + startOffset, 
								 length, type, FALSE );
	if( cryptStatusError( dataLength ) )
		return( dataLength );

	/* If it's TLS 1.1 or newer and we're using a block cipher, prepend
	   the IV to the data */
	if( ivSize > 0 )
		{
		RESOURCE_DATA msgData;

		assert( startOffset >= SSL_HEADER_SIZE + ivSize ); 

		startOffset -= ivSize;
		setMessageData( &msgData, bufPtr + startOffset, ivSize );
		krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S, 
						 &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
		}

	/* Encrypt the payload */
	dataLength = encryptData( sessionInfoPtr, bufPtr + startOffset,
							  dataLength + ivSize );
	if( cryptStatusError( dataLength ) )
		return( dataLength );

	/* Add the packet wrapper */
	*bufPtr++ = type;
	*bufPtr++ = SSL_MAJOR_VERSION;
	*bufPtr++ = sessionInfoPtr->version;
	mputWord( bufPtr, dataLength );

	return( startOffset + dataLength );
	}

static int unwrapData( SESSION_INFO *sessionInfoPtr, BYTE *buffer,
					   const int length, const int type )
	{
	BOOLEAN badDecrypt = FALSE;
	int dataLength, status;

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( length >= 0 && length <= MAX_PACKET_SIZE + 20 + \
									 sessionInfoPtr->cryptBlocksize );
	assert( isWritePtr( buffer, length ) );

	/* Make sure that the length is a multiple of the block cipher size */
	if( sessionInfoPtr->cryptBlocksize > 1 && \
		( length % sessionInfoPtr->cryptBlocksize ) )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid packet length %d relative to cipher block size %d", 
				length, sessionInfoPtr->cryptBlocksize );

	/* Decrypt the packet in the buffer.  We allow zero-length blocks (once
	   the padding is stripped) because some versions of OpenSSL send these 
	   as a kludge to work around chosen-IV attacks */
	dataLength = decryptData( sessionInfoPtr, buffer, length );
	if( cryptStatusError( dataLength ) )
		{
		/* If there's a padding error, don't exit immediately but record 
		   that there was a problem for after we've done the MAC'ing.  
		   Delaying the error reporting until then helps prevent timing 
		   attacks of the kind described by Brice Canvel, Alain Hiltgen,
		   Serge Vaudenay, and Martin Vuagnoux in "Password Interception 
		   in a SSL/TLS Channel", Crypto'03, LNCS No.2729, p.583.  These 
		   are close to impossible in most cases because we delay sending 
		   the close notify over a much longer period than the MAC vs.non-
		   MAC time difference and because it requires repeatedly connecting
		   with a fixed-format secret such as a password at the same location
		   in the packet (which MS Outlook manages to do, however), but we 
		   take this step anyway just to be safe */
		if( dataLength == CRYPT_ERROR_BADDATA )
			{
			badDecrypt = TRUE;
			dataLength = length;
			}
		else
			return( dataLength );
		}
	dataLength -= sessionInfoPtr->authBlocksize;
	if( dataLength < 0 )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid data payload length %d", dataLength );

	/* MAC the decrypted data */
	if( sessionInfoPtr->version == SSL_MINOR_VERSION_SSL )
		status = macDataSSL( sessionInfoPtr, buffer, dataLength, type, TRUE );
	else
		status = macDataTLS( sessionInfoPtr, buffer, dataLength, type, TRUE );
	if( badDecrypt )
		/* Report the delayed decrypt error, held to this point to make 
		   timing attacks more difficult.  The extended error info will have
		   been overwritten by the error info from the MAC'ing code, but
		   either message is appropriate */
		return( CRYPT_ERROR_BADDATA );
	if( cryptStatusError( status ) )
		return( status );

	return( dataLength );
	}

/* Write an SSL cert chain:

	byte		ID = 0x0B
	uint24		len
	uint24		certListLen
	uint24		certLen			| 1...n certs ordered
	byte[]		cert			|   leaf -> root */

int writeSSLCertChain( SESSION_INFO *sessionInfoPtr, BYTE *buffer )
	{
	CRYPT_CERTIFICATE iCryptCert;
	BYTE *bufPtr = buffer, *lengthPtr;
	int length = 0, status;

	/* Write the packet header and leave room for the packet length and
	   cert list length */
	*bufPtr++ = SSL_HAND_CERTIFICATE;
	lengthPtr = bufPtr;
	bufPtr += LENGTH_SIZE + LENGTH_SIZE;	/* len + certListLen */

	/* Lock the cert chain for our exclusive use and select the leaf cert,
	   export each cert in turn until we reach the root, and unlock it again 
	   to allow others access */
	krnlSendMessage( sessionInfoPtr->privateKey, IMESSAGE_GETDEPENDENT,
					 &iCryptCert, OBJECT_TYPE_CERTIFICATE );
	status = krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE,
							  MESSAGE_VALUE_TRUE, CRYPT_IATTRIBUTE_LOCKED );
	if( cryptStatusError( status ) )
		return( status );
	krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE, 
					 MESSAGE_VALUE_CURSORFIRST, 
					 CRYPT_CERTINFO_CURRENT_CERTIFICATE );
	do
		{
		RESOURCE_DATA msgData;

		setMessageData( &msgData, bufPtr + LENGTH_SIZE,
						sessionInfoPtr->sendBufSize - \
						( bufPtr + LENGTH_SIZE - sessionInfoPtr->sendBuffer ) );
		status = krnlSendMessage( sessionInfoPtr->privateKey,
								  IMESSAGE_CRT_EXPORT, &msgData, 
								  CRYPT_CERTFORMAT_CERTIFICATE );
		*bufPtr++ = 0;
		mputWord( bufPtr, msgData.length );
		bufPtr += msgData.length;
		length += msgData.length + LENGTH_SIZE;
		}
	while( cryptStatusOK( status ) && \
		   krnlSendMessage( sessionInfoPtr->privateKey,
							IMESSAGE_SETATTRIBUTE, MESSAGE_VALUE_CURSORNEXT,
							CRYPT_CERTINFO_CURRENT_CERTIFICATE ) == CRYPT_OK );
	krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE, MESSAGE_VALUE_FALSE, 
					 CRYPT_IATTRIBUTE_LOCKED );
	if( cryptStatusError( status ) )
		return( status );

	/* Go back and add the overall packet length and cert chain length at the
	   start of the packet */
	*lengthPtr++ = 0;		/* len */
	mputWord( lengthPtr, length + LENGTH_SIZE );
	*lengthPtr++ = 0;		/* certListLen */
	mputWord( lengthPtr, length );

	return( ID_SIZE + LENGTH_SIZE + LENGTH_SIZE + length );
	}

/* Read/write an SSL certificate verify message:

	byte		ID = 0x0F
	uint24		len
	byte[]		signature

   SSLv3/TLS use a weird signature format that dual-MACs (SSLv3) or hashes
   (TLS) all of the handshake messages exchanged to date (SSLv3 additionally 
   hashes in further data like the master secret), then signs them using raw,
   non-PKCS #1 RSA (that is, it uses the private key to encrypt the
   concatenated SHA-1 and MD5 MAC or hash of the handshake messages), unless
   we're using DSA in which case it drops the MD5 MAC/hash and uses only the
   SHA-1 one.  This is an incredible pain to support because it requires
   running a parallel hash of handshake messages that terminates before the
   main hashing does, further hashing/MAC'ing of additional data and the use 
   of weird nonstandard data formats and signature mechanisms that aren't 
   normally supported by anything.  For example if the signing is to be done 
   via a smart card then we can't use the standard PKCS #1 sig, we can't 
   even use raw RSA and kludge the format together ourselves because some 
   PKCS #11 implementations don't support the _X509 (raw) mechanism, what we 
   have to do is tunnel the nonstandard sig.format info down through several 
   cryptlib layers and then hope that the PKCS #11 implementation we're using 
   (a) supports this format and (b) gets it right.  Another problem (which 
   only occurs for SSLv3) is that the MAC requires the use of the master 
   secret, which isn't available for several hundred more lines of code, so 
   we have to delay producing any more data packets until the master secret 
   is available, which severely screws up the handshake processing flow.

   The chances of all of this working correctly are fairly low, and in any
   case there's no advantage to the weird mechanism and format used in
   SSL/TLS, all we actually need to do is sign the client and server nonces
   to ensure signature freshness.  Because of this what we actually do is
   just this, after which we create a standard PKCS #1 signature via the
   normal cryptlib mechanisms, which guarantees that it'll work with native
   cryptlib as well as any crypto hardware implementation.  Since client
   certs are hardly ever used and when they are it's in a closed environment,
   it's extremely unlikely that anyone will ever notice.  There'll be far
   more problems in trying to use the nonstandard SSL/TLS signature mechanism
   than there are with using a standard (but not-in-the-spec) one */

int processCertVerify( const SESSION_INFO *sessionInfoPtr,
					   const SSL_HANDSHAKE_INFO *handshakeInfo,
					   void *signature, const int signatureLength,
					   const int signatureMaxLength )
	{
	MESSAGE_CREATEOBJECT_INFO createInfo;
	BYTE nonceBuffer[ 64 + SSL_NONCE_SIZE + SSL_NONCE_SIZE ];
	int length, status;

	/* Hash the client and server nonces */
	setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_SHA );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
							  IMESSAGE_DEV_CREATEOBJECT, &createInfo, 
							  OBJECT_TYPE_CONTEXT );
	if( cryptStatusError( status ) )
		return( status );
	memcpy( nonceBuffer, "certificate verify", 18 );
	memcpy( nonceBuffer + 18, handshakeInfo->clientNonce, SSL_NONCE_SIZE );
	memcpy( nonceBuffer + 18 + SSL_NONCE_SIZE, handshakeInfo->serverNonce,
			SSL_NONCE_SIZE );
	krnlSendMessage( createInfo.cryptHandle, IMESSAGE_CTX_HASH,
					 nonceBuffer, 18 + SSL_NONCE_SIZE + SSL_NONCE_SIZE );
	krnlSendMessage( createInfo.cryptHandle, IMESSAGE_CTX_HASH,
					 nonceBuffer, 0 );

	/* Create or verify the signature as appropriate */
	if( signatureLength )
		status = iCryptCheckSignatureEx( signature, signatureLength,
										 CRYPT_FORMAT_CRYPTLIB,
										 sessionInfoPtr->iKeyexAuthContext,
										 createInfo.cryptHandle, NULL );
	else
		status = iCryptCreateSignatureEx( signature, &length, 
										  signatureMaxLength,
										  CRYPT_FORMAT_CRYPTLIB,
										  sessionInfoPtr->privateKey,
										  createInfo.cryptHandle,
										  CRYPT_UNUSED, CRYPT_UNUSED );
	krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
	return( ( cryptStatusOK( status ) && !signatureLength ) ? \
			length : status );
	}

/* Process version information from a peer */

int processVersionInfo( SESSION_INFO *sessionInfoPtr, const int version )
	{
	switch( version )
		{
		case SSL_MINOR_VERSION_SSL:
			/* If the other side can't do TLS, fall back to SSL */
			if( sessionInfoPtr->version >= SSL_MINOR_VERSION_TLS )
				sessionInfoPtr->version = SSL_MINOR_VERSION_SSL;
			break;

		case SSL_MINOR_VERSION_TLS:
			/* If the other side can't do TLS 1.1, fall back to TLS 1.0 */
			if( sessionInfoPtr->version >= SSL_MINOR_VERSION_TLS11 )
				sessionInfoPtr->version = SSL_MINOR_VERSION_TLS;
			break;

		case SSL_MINOR_VERSION_TLS11:
			break;

		default:
			/* If we're the server and the client has offered a vaguely 
			   sensible version, fall back to the highest version we
			   support */
			if( ( sessionInfoPtr->flags && SESSION_ISSERVER ) && \
				version <= 5 )
				{
				sessionInfoPtr->version = SSL_MINOR_VERSION_TLS11;
				break;
				}

			/* It's nothing we can handle */
			retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
					"Invalid protocol version %d", version );
		}

	return( CRYPT_OK );
	}

/* Wrap a handshake packet, taking as input a data packet with a 5-byte gap
   at the start for the header and wrapping it up as appropriate in the
   SSL/TLS packet encapsulation

	byte		type = 22 (handshake)
	byte[2]		version = { 0x03, 0x0n }
	uint16		len */

void wrapHandshakePacket( void *data, const int length,
						  const int protocolVersion )
	{
	BYTE *dataPtr = data;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -