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

📄 ssl.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 5 页
字号:
		return( status );
		}
	sMemConnect( &stream, sessionInfoPtr->receiveBuffer, length );
	status = checkHSPacketHeader( sessionInfoPtr, &stream, &length,
								  SSL_HAND_FINISHED, macValueLength );
	if( !cryptStatusError( status ) )
		{
		if( length != macValueLength )
			{
			/* A length mis-match can only be an overflow, since an
			   underflow would be caught by checkHSPacketHeader() */
			status = CRYPT_ERROR_OVERFLOW;
			}
		else
			status = sread( &stream, macBuffer, macValueLength );
		}
	sMemDisconnect( &stream );
	if( cryptStatusError( status ) )
		{
		if( status == CRYPT_ERROR_BADDATA )
			{
			retExt( CRYPT_ERROR_WRONGKEY,
					( CRYPT_ERROR_WRONGKEY, SESSION_ERRINFO, 
					  "Invalid handshake finished packet, probably due to "
					  "incorrect encryption keys being negotiated during "
					  "the handshake" ) );
			}
		return( status );
		}

	/* Make sure that the dual MAC/hashed MAC of all preceding messages is
	   valid */
	if( memcmp( hashValues, macBuffer, macValueLength ) )
		{
		retExt( CRYPT_ERROR_SIGNATURE,
				( CRYPT_ERROR_SIGNATURE, SESSION_ERRINFO, 
				  "Bad MAC for handshake messages, handshake messages were "
				  "corrupted/modified" ) );
		}

	return( CRYPT_OK );
	}

static int writeHandshakeCompletionData( INOUT SESSION_INFO *sessionInfoPtr,
										 INOUT SSL_HANDSHAKE_INFO *handshakeInfo,
										 IN_BUFFER( hashValueLen ) \
										 const BYTE *hashValues, 
										 const int hashValuesLen,
										 const BOOLEAN continuedStream )
	{
	STREAM *stream = &handshakeInfo->stream;
	int offset = 0, ccsEndPos, status;

	/* Build the change cipher spec packet:

		byte		type = SSL_MSG_CHANGE_CIPHER_SPEC
		byte[2]		version = { 0x03, 0x0n }
		uint16		len = 1
		byte		1

	   Since change cipher spec is its own protocol, we use SSL-level packet
	   encoding rather than handshake protocol-level encoding */
	if( continuedStream )
		offset = continuePacketStreamSSL( stream, sessionInfoPtr,
										  SSL_MSG_CHANGE_CIPHER_SPEC );
	else
		{
		status = openPacketStreamSSL( stream, sessionInfoPtr, 
									  CRYPT_USE_DEFAULT,
									  SSL_MSG_CHANGE_CIPHER_SPEC );
		if( cryptStatusError( status ) )
			return( status );
		}
	sputc( stream, 1 );
	status = completePacketStreamSSL( stream, offset );
	if( cryptStatusError( status ) )
		{
		sMemDisconnect( stream );
		return( status );
		}

	/* Change cipher spec was the last message not subject to security
	   encapsulation so we turn on security for the write channel after
	   seeing it.  In addition if we're using TLS 1.1 explicit IVs the
	   effective header size changes because of the extra IV data, so we
	   record the size of the additional IV data and update the receive
	   buffer start offset to accomodate it */
	sessionInfoPtr->flags |= SESSION_ISSECURE_WRITE;
	if( sessionInfoPtr->version >= SSL_MINOR_VERSION_TLS11 && \
		sessionInfoPtr->cryptBlocksize > 1 )
		{
		sessionInfoPtr->sessionSSL->ivSize = sessionInfoPtr->cryptBlocksize;
		sessionInfoPtr->sendBufStartOfs += sessionInfoPtr->cryptBlocksize;
		}

	/* Build the finished packet.  The initiator sends the MAC of the
	   contents of every handshake packet before the finished packet, the
	   responder sends the MAC of the contents of every packet before its own
	   finished packet but including the MAC of the initiator's packet
	   contents:

		byte		ID = SSL_HAND_FINISHED
		uint24		len
			SSLv3						TLS
		byte[16]	MD5 MAC			byte[12]	hashedMAC
		byte[20]	SHA-1 MAC */
	ccsEndPos = continuePacketStreamSSL( stream, sessionInfoPtr,
										 SSL_MSG_HANDSHAKE );
	offset = continueHSPacketStream( stream, SSL_HAND_FINISHED );
	swrite( stream, hashValues, hashValuesLen );
	status = completeHSPacketStream( stream, offset );
	if( cryptStatusOK( status ) )
		status = wrapPacketSSL( sessionInfoPtr, stream, ccsEndPos );
	if( cryptStatusOK( status ) )
		status = sendPacketSSL( sessionInfoPtr, stream,
								TRUE );
	sMemDisconnect( stream );

	return( status );
	}

/* Complete the handshake with the client or server.  The logic gets a bit
   complex here because the roles of the client and server are reversed if
   we're resuming a session:

		Normal					Resumed
	Client		Server		Client		Server
	------		------		------		------
		   <--- ...			Hello  --->
	KeyEx  --->					   <---	Hello
	CCS	   --->					   <--- CCS
	Fin	   --->					   <--- Fin
		   <---	CCS			CCS	   --->
		   <---	Fin			Fin	   --->

   Because of this the handshake-completion step treats the two sides as
   initiator and responder rather than client and server.  The overall flow
   is then:

	dualMAC( initiator );
	if( !initiator )
		read initiator CCS + Fin;
	dualMAC( responder );
	send initiator/responder CCS + Fin;
	if( initiator )
		read responder CCS + Fin; */

static int completeHandshake( SESSION_INFO *sessionInfoPtr,
							  SSL_HANDSHAKE_INFO *handshakeInfo,
							  const BOOLEAN isClient,
							  const BOOLEAN isResumedSession )
	{
	CRYPT_CONTEXT initiatorMD5context, initiatorSHA1context;
	CRYPT_CONTEXT responderMD5context, responderSHA1context;
	BYTE masterSecret[ SSL_SECRET_SIZE + 8 ];
	BYTE keyBlock[ MAX_KEYBLOCK_SIZE + 8 ];
	BYTE initiatorHashes[ ( CRYPT_MAX_HASHSIZE * 2 ) + 8 ];
	BYTE responderHashes[ ( CRYPT_MAX_HASHSIZE * 2 ) + 8 ];
	const void *sslInitiatorString, *sslResponderString;
	const void *tlsInitiatorString, *tlsResponderString;
	const BOOLEAN isInitiator = isResumedSession ? !isClient : isClient;
	int initiatorHashLength, responderHashLength;
	int sslLabelLength, tlsLabelLength, status;

	assert( MAX_KEYBLOCK_SIZE >= ( sessionInfoPtr->authBlocksize + \
								   handshakeInfo->cryptKeysize +
								   sessionInfoPtr->cryptBlocksize ) * 2 );
	assert( handshakeInfo->authAlgo == CRYPT_ALGO_NONE || \
			handshakeInfo->premasterSecretSize >= SSL_SECRET_SIZE );

	/* Perform the necessary juggling of values for the reversed message
	   flow of resumed sessions */
	if( isResumedSession )
		{
		/* Resumed session, initiator = server, responder = client */
		initiatorMD5context = handshakeInfo->serverMD5context;
		initiatorSHA1context = handshakeInfo->serverSHA1context;
		responderMD5context = handshakeInfo->clientMD5context;
		responderSHA1context = handshakeInfo->clientSHA1context;
		sslInitiatorString = SSL_SENDER_SERVERLABEL;
		sslResponderString = SSL_SENDER_CLIENTLABEL;
		tlsInitiatorString = "server finished";
		tlsResponderString = "client finished";
		}
	else
		{
		/* Normal session, initiator = client, responder = server */
		initiatorMD5context = handshakeInfo->clientMD5context;
		initiatorSHA1context = handshakeInfo->clientSHA1context;
		responderMD5context = handshakeInfo->serverMD5context;
		responderSHA1context = handshakeInfo->serverSHA1context;
		sslInitiatorString = SSL_SENDER_CLIENTLABEL;
		sslResponderString = SSL_SENDER_SERVERLABEL;
		tlsInitiatorString = "client finished";
		tlsResponderString = "server finished";
		}
	sslLabelLength = SSL_SENDERLABEL_SIZE;
	tlsLabelLength = 15;

	/* Create the security contexts required for the session */
	status = initSecurityContextsSSL( sessionInfoPtr );
	if( cryptStatusError( status ) )
		return( status );

	/* Convert the premaster secret into the master secret */
	if( !isResumedSession )
		{
		status = premasterToMaster( sessionInfoPtr, handshakeInfo,
									masterSecret, SSL_SECRET_SIZE );
		if( cryptStatusError( status ) )
			return( status );

		/* Everything is OK so far, if we're the server and using session 
		   resumes (and the client's ID value is sufficient to be useful) 
		   add the master secret to the session cache */
		if( !isClient && handshakeInfo->sessionIDlength > 8 )
			{
			sessionInfoPtr->sessionSSL->sessionCacheID = \
					addScoreboardEntry( sessionInfoPtr->sessionSSL->scoreboardInfoPtr,
										handshakeInfo->sessionID,
										handshakeInfo->sessionIDlength,
										masterSecret, SSL_SECRET_SIZE );
			}
		}
	else
		{
		/* We've already got the master secret present from the session that
		   we're resuming from, reuse that */
		memcpy( masterSecret, handshakeInfo->premasterSecret,
				handshakeInfo->premasterSecretSize );
		}

	/* Convert the master secret into keying material.  Unfortunately we
	   can't delete it yet because it's still needed to calculate the MAC
	   for the handshake messages */
	status = masterToKeys( sessionInfoPtr, handshakeInfo, masterSecret,
						   SSL_SECRET_SIZE, keyBlock, MAX_KEYBLOCK_SIZE );
	if( cryptStatusError( status ) )
		{
		zeroise( masterSecret, SSL_SECRET_SIZE );
		return( status );
		}

	/* Load the keys and secrets */
	status = loadKeys( sessionInfoPtr, handshakeInfo, keyBlock, 
					   MAX_KEYBLOCK_SIZE, isClient );
	zeroise( keyBlock, MAX_KEYBLOCK_SIZE );
	if( cryptStatusError( status ) )
		{
		zeroise( masterSecret, SSL_SECRET_SIZE );
		return( status );
		}

	/* Complete the dual-MAC hashing of the initiator-side messages and, if
	   we're the responder, check that the MACs match the ones supplied by
	   the initiator */
	if( sessionInfoPtr->version == SSL_MINOR_VERSION_SSL )
		{
		status = completeSSLDualMAC( initiatorMD5context, initiatorSHA1context,
									 initiatorHashes, CRYPT_MAX_HASHSIZE * 2,
									 &initiatorHashLength, sslInitiatorString, 
									 sslLabelLength, masterSecret, 
									 SSL_SECRET_SIZE );
		}
	else
		{
		status = completeTLSHashedMAC( initiatorMD5context, initiatorSHA1context,
									   initiatorHashes, CRYPT_MAX_HASHSIZE * 2,
									   &initiatorHashLength, tlsInitiatorString, 
									   tlsLabelLength, masterSecret, 
									   SSL_SECRET_SIZE );
		}
	if( cryptStatusOK( status ) && !isInitiator )
		status = readHandshakeCompletionData( sessionInfoPtr, initiatorHashes );
	if( cryptStatusError( status ) )
		{
		zeroise( masterSecret, SSL_SECRET_SIZE );
		return( status );
		}

	/* Now that we have the initiator MACs, complete the dual-MAC hashing of
	   the responder-side messages and destroy the master secret.  We haven't
	   created the full message yet at this point so we manually hash the
	   individual pieces so that we can get rid of the master secret */
	krnlSendMessage( responderMD5context, IMESSAGE_CTX_HASH,
					 ( void * ) finishedTemplate[ sessionInfoPtr->version ],
					 FINISHED_TEMPLATE_SIZE );
	krnlSendMessage( responderSHA1context, IMESSAGE_CTX_HASH,
					 ( void * ) finishedTemplate[ sessionInfoPtr->version ],
					 FINISHED_TEMPLATE_SIZE );
	krnlSendMessage( responderMD5context, IMESSAGE_CTX_HASH, 
					 initiatorHashes, initiatorHashLength );
	krnlSendMessage( responderSHA1context, IMESSAGE_CTX_HASH,
					 initiatorHashes, initiatorHashLength );
	if( sessionInfoPtr->version == SSL_MINOR_VERSION_SSL )
		{
		status = completeSSLDualMAC( responderMD5context, responderSHA1context,
									 responderHashes, CRYPT_MAX_HASHSIZE * 2,
									 &responderHashLength, sslResponderString, 
									 sslLabelLength, masterSecret, 
									 SSL_SECRET_SIZE );
		}
	else
		{
		status = completeTLSHashedMAC( responderMD5context, responderSHA1context,
									   responderHashes, CRYPT_MAX_HASHSIZE * 2,
									   &responderHashLength, tlsResponderString, 
									   tlsLabelLength, masterSecret, 
									   SSL_SECRET_SIZE );
		}
	zeroise( masterSecret, SSL_SECRET_SIZE );
	if( cryptStatusError( status ) )
		return( status );

	/* Send our MACs to the other side and read back their response if
	   necessary */
	status = writeHandshakeCompletionData( sessionInfoPtr, handshakeInfo,
										   isInitiator ? initiatorHashes : \
														 responderHashes,
										   initiatorHashLength,	
										   /* Same as responderHashLength */
										   ( isClient && !isResumedSession ) || \
										   ( !isClient && isResumedSession ) );
	if( cryptStatusError( status ) || !isInitiator )
		return( status );
	return( readHandshakeCompletionData( sessionInfoPtr, responderHashes ) );
	}

/****************************************************************************
*																			*
*								Init/Shutdown Functions						*
*																			*
****************************************************************************/

/* Close a previously-opened SSL session */

static void shutdownFunction( SESSION_INFO *sessionInfoPtr )
	{
	sendCloseAlert( sessionInfoPtr, FALSE );
	sNetDisconnect( &sessionInfoPtr->stream );
	}

/* Connect to an SSL server/client */

static int abortStartup( SESSION_INFO *sessionInfoPtr,
						 SSL_HANDSHAKE_INFO *handshakeInfo,
						 const BOOLEAN cleanupSecurityContexts,
						 const int status )
	{
	sendHandshakeFailAlert( sessionInfoPtr );
	if( cleanupSecurityContexts )
		destroySecurityContextsSSL( sessionInfoPtr );
	if( handshakeInfo != NULL )
		destroyHandshakeInfo( handshakeInfo );
	sNetDisconnect( &sessionInfoPtr->stream );
	return( status );
	}

static int commonStartup( SESSION_INFO *sessionInfoPtr,
						  const BOOLEAN isServer )
	{
	SSL_HANDSHAKE_INFO handshakeInfo;
	BOOLEAN resumedSession = FALSE;
	int status;

⌨️ 快捷键说明

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