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

📄 ssl_svr.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 3 页
字号:
	/* Build the server hello, cert, optional cert request, and done packets:

		byte		ID = 2
		uint24		len
		byte[2]		version = { 0x03, 0x0n }
		uint32		time			| Server nonce
		byte[28]	nonce			|
		byte		sessIDlen
		byte[]		sessID
		uint16		suite
		byte		copr = 0
		... */
	setMessageData( &msgData, handshakeInfo->serverNonce, SSL_NONCE_SIZE );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S, 
							  &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
	if( cryptStatusError( status ) )
		return( status );
	bufPtr = sessionInfoPtr->sendBuffer + sessionInfoPtr->sendBufStartOfs;
	*bufPtr++ = SSL_HAND_SERVER_HELLO;
	*bufPtr++ = 0;
	lengthPtr = bufPtr;		/* Low 16 bits of length */
	bufPtr += LENGTH_SIZE - 1;
	*bufPtr++ = SSL_MAJOR_VERSION;
	*bufPtr++ = sessionInfoPtr->version;
	memcpy( bufPtr, handshakeInfo->serverNonce, SSL_NONCE_SIZE );
	bufPtr += SSL_NONCE_SIZE;
	*bufPtr++ = handshakeInfo->sessionIDlength;
	memcpy( bufPtr, handshakeInfo->sessionID, 
			handshakeInfo->sessionIDlength );
	bufPtr += handshakeInfo->sessionIDlength;
	mputWord( bufPtr, handshakeInfo->cipherSuite ); 
	*bufPtr++ = 0;			/* No compression */
	if( isExtendedHello )
		{
#if 0	/* TLS extension code.  Since no known clients/servers (except maybe 
		   some obscure bits of code embedded in cellphones) do this, we'll 
		   have to wait for something that implements it to come along so we 
		   can send back the appropriate response.  The RFC makes the rather 
		   optimistic assumption that implementations can handle the presence 
		   of unexpected data at the end of the hello packet, since  this is 
		   rarely the case we leave the following disabled by default so as 
		   not to confuse clients that leave some garbage at the end of their
		   client hello and suddenly get back an extension response from the
		   server */
		mputWord( bufPtr, ID_SIZE + UINT16_SIZE + 1 );
		*bufPtr++ = TLS_EXT_MAX_FRAGMENT_LENTH;
		mputWord( bufPtr, 1 );
		*bufPtr++ = 3;
#endif /* 0 */
		}
	length = bufPtr - \
			 ( sessionInfoPtr->sendBuffer + sessionInfoPtr->sendBufStartOfs );
	mputWord( lengthPtr, length - ( ID_SIZE + LENGTH_SIZE ) );

	/* If it's not a resumed session, write the server and optional client 
	   cert information and server hello done */
	if( !resumedSessionID )
		{
		/*	...
			(server cert chain)
			... */
		status = writeSSLCertChain( sessionInfoPtr, bufPtr );
		if( cryptStatusError( status ) )
			return( status );
		bufPtr += status;

		/*	...			( optional client cert request)
			byte		ID = 0x0D
			uint24		len = 7
			byte		certTypeLen = 2
			byte[2]		certType = { 0x01, 0x02 }
			uint16		caNameListLen = 4
			uint16		caNameLen = 2
			byte[]		caName = { 0x30, 0x00 }
			... */
		if( sessionInfoPtr->cryptKeyset != CRYPT_ERROR )
			{
			memcpy( bufPtr, serverCertRequestTemplate, 
					SERVERCERTREQUEST_TEMPLATE_SIZE );
			bufPtr += SERVERCERTREQUEST_TEMPLATE_SIZE;
			}

		/*	...
			byte		ID = 0x0E
			uint24		len = 0 */
		memcpy( bufPtr, serverHelloDoneTemplate, 
				SERVERHELLODONE_TEMPLATE_SIZE );
		bufPtr += SERVERHELLODONE_TEMPLATE_SIZE;
		}

	/* Send the combined server packets to the client.  We perform the dual 
	   MAC'ing of the client hello in between the network ops where it's 
	   effectively free */
	length = bufPtr - \
			 ( sessionInfoPtr->sendBuffer + sessionInfoPtr->sendBufStartOfs );
	wrapHandshakePacket( sessionInfoPtr->sendBuffer, length, 
						 sessionInfoPtr->version );
	status = swrite( &sessionInfoPtr->stream, sessionInfoPtr->sendBuffer, 
					 sessionInfoPtr->sendBufStartOfs + length );
	if( cryptStatusError( status ) )
		{
		sNetGetErrorInfo( &sessionInfoPtr->stream, 
						  sessionInfoPtr->errorMessage,
						  &sessionInfoPtr->errorCode );
		return( status );
		}
	dualMacData( handshakeInfo, sessionInfoPtr->sendBuffer + \
								sessionInfoPtr->sendBufStartOfs, length );

	return( resumedSessionID ? OK_SPECIAL : CRYPT_OK );
	}

/* Exchange keys with the client */

int exchangeServerKeys( SESSION_INFO *sessionInfoPtr, 
						SSL_HANDSHAKE_INFO *handshakeInfo )
	{
	MECHANISM_WRAP_INFO mechanismInfo;
	BYTE *bufPtr;
	int length, status;

	/* Read the response from the client and, if we're expecting a client 
	   cert, make sure that it's present */
	status = readPacketSSL( sessionInfoPtr, handshakeInfo, 
							SSL_MSG_HANDSHAKE );
	if( cryptStatusError( status ) )
		return( status );
	bufPtr = sessionInfoPtr->receiveBuffer;
	if( sessionInfoPtr->cryptKeyset != CRYPT_ERROR )
		{
		MESSAGE_CREATEOBJECT_INFO createInfo;
		MESSAGE_KEYMGMT_INFO getkeyInfo;
		RESOURCE_DATA msgData;
		BYTE certID[ KEYID_SIZE ];
		int chainLength;

		/* Make sure that the client has sent us a cert chain */
		length = checkPacketHeader( sessionInfoPtr, &bufPtr, 
									SSL_HAND_CERTIFICATE, 64, 0 );
		if( cryptStatusError( length ) )
			return( length );
		if( length == 0 || length == 3 )
			{
			/* SSLv3 sent an SSL_ALERT_NO_CERTIFICATE alert to indicate that 
			   the client doesn't have a cert, which is handled by the 
			   readPacketSSL() call.  TLS changed this to send an empty cert 
			   packet instead, supposedly because it lead to implementation
			   problems (presumably it's necessary to create a state machine-
			   based implementation to reproduce these problems, whatever 
			   they are).  The spec is ambiguous as to what constitutes an 
			   empty packet, it could be either a packet with a length of 
			   zero or a packet containing a zero-length cert list so we 
			   check for both.  We also fake the error indicators for 
			   consistency with the status obtained from an SSLv3 no-cert 
			   alert */
			sessionInfoPtr->errorCode = SSL_ALERT_NO_CERTIFICATE;
			retExt( sessionInfoPtr, CRYPT_ERROR_PERMISSION,
					( sessionInfoPtr->version == SSL_MINOR_VERSION_SSL ) ? \
						"Received SSL alert message: No certificate" : \
						"Received TLS alert message: No certificate" );
			}
		chainLength = mgetWord( bufPtr );
		if( chainLength < 64 || LENGTH_SIZE + chainLength != length )
			retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
					"Invalid client cert chain length %d", chainLength );

		/* Import the cert chain.  This isn't a true cert chain (in the sense 
		   of being degenerate PKCS #7 SignedData) but a special-case SSL-
		   encoded cert chain */
		setMessageCreateObjectIndirectInfo( &createInfo, bufPtr, chainLength,
											CRYPT_ICERTTYPE_SSL_CERTCHAIN );
		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
								  IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
								  &createInfo, OBJECT_TYPE_CERTIFICATE );
		if( cryptStatusError( status ) )
			return( status );
		bufPtr += chainLength;
		sessionInfoPtr->iKeyexAuthContext = createInfo.cryptHandle;

		/* Make sure that the cert is valid for signing data, which the 
		   client will need to do when it authenticates itself */
		status = krnlSendMessage( sessionInfoPtr->iKeyexAuthContext, 
								  IMESSAGE_CHECK, NULL, 
								  MESSAGE_CHECK_PKC_SIGCHECK );
		if( cryptStatusError( status ) )
			retExt( sessionInfoPtr, CRYPT_ERROR_INVALID,
					"Client supplied a certificate that can't be used for "
					"client authentication" );

		/* Make sure that the client cert is present in our cert store.  
		   Since we've already got a copy of the cert, we only do a presence 
		   check rather than actually fetching the cert */
		setMessageData( &msgData, certID, KEYID_SIZE );
		status = krnlSendMessage( sessionInfoPtr->iKeyexAuthContext, 
								  IMESSAGE_GETATTRIBUTE_S, &msgData, 
								  CRYPT_CERTINFO_FINGERPRINT_SHA );
		if( cryptStatusOK( status ) )
			{
			setMessageKeymgmtInfo( &getkeyInfo, CRYPT_IKEYID_CERTID, certID, 
								   KEYID_SIZE, NULL, 0, 
								   KEYMGMT_FLAG_CHECK_ONLY );
			status = krnlSendMessage( sessionInfoPtr->cryptKeyset, 
									  IMESSAGE_KEY_GETKEY, &getkeyInfo, 
									  KEYMGMT_ITEM_PUBLICKEY );
			}
		if( cryptStatusError( status ) )
			retExt( sessionInfoPtr, CRYPT_ERROR_INVALID,
					"Client certificate is not trusted for client "
					"authentication" );

		/* Read the next packet(s) if necessary */
		if( sessionInfoPtr->receiveBufPos >= sessionInfoPtr->receiveBufEnd )
			{
			status = readPacketSSL( sessionInfoPtr, handshakeInfo, 
									SSL_MSG_HANDSHAKE );
			if( cryptStatusError( status ) )
				return( status );
			bufPtr = sessionInfoPtr->receiveBuffer;
			}		
		}

	/* Process the client key exchange packet:

		byte		ID = 0x10
		uint24		len
	   RSA:
	  [ uint16		encKeyLen - TLS only ]
		byte[]		rsaPKCS1( byte[2] { 0x03, 0x0n } || byte[46] random )
	   DH:
		uint16		yLen
		byte[]		y */
	length = checkPacketHeader( sessionInfoPtr, &bufPtr, 
								SSL_HAND_CLIENT_KEYEXCHANGE, 64, 
								CRYPT_UNUSED );
	if( cryptStatusError( length ) )
		return( length );
	if( sessionInfoPtr->version >= SSL_MINOR_VERSION_TLS )
		{
		int innerLength;

		/* The original Netscape SSL implementation didn't provide a length
		   for the encrypted key and everyone copied that so it became the
		   de facto standard way to do it (Sic faciunt omnes.  The spec 
		   itself is ambiguous on the topic).  This was fixed in TLS 
		   (although the spec is still ambigous) so the encoding differs 
		   slightly between SSL and TLS */
		innerLength = mgetWord( bufPtr );
		if( UINT16_SIZE + innerLength != length )
			retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
					"Invalid encrypted key length %d vs.inner length %d",
					length, innerLength );
		length = innerLength;
		}
	if( length < bitsToBytes( MIN_PKCSIZE_BITS ) || \
		length > CRYPT_MAX_PKCSIZE )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid encrypted key length %d", length );

	/* Decrypt the encrypted premaster secret and make sure that it looks OK.  
	   Note that the version that we check for at this point is the version 
	   originally offered by the client in its hello message, not the version 
	   eventually negotiated for the connection.  This is designed to prevent 
	   rollback attacks.  In theory we could explicitly defend against 
	   Bleichenbacher-type attacks at this point by setting the premaster 
	   secret to a pseudorandom value if we get a bad data or incorrect 
	   version error and continuing as normal, however the attack depends on 
	   the server returning information required to pinpoint the cause of 
	   the failure and cryptlib just returns a generic "failed" response for 
	   any handshake failure, so this explicit defence isn't really 
	   necessary */
	setMechanismWrapInfo( &mechanismInfo, bufPtr, length, 
						  handshakeInfo->premasterSecret, SSL_SECRET_SIZE, 
						  CRYPT_UNUSED, sessionInfoPtr->privateKey, 
						  CRYPT_UNUSED );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_IMPORT, 
							  &mechanismInfo, MECHANISM_PKCS1_RAW );
	if( cryptStatusOK( status ) && \
		mechanismInfo.keyDataLength != SSL_SECRET_SIZE )
		status = CRYPT_ERROR_BADDATA;
	clearMechanismInfo( &mechanismInfo );
	if( cryptStatusError( status ) )
		return( status );
	if( handshakeInfo->premasterSecret[ 0 ] != SSL_MAJOR_VERSION || \
		handshakeInfo->premasterSecret[ 1 ] != handshakeInfo->clientOfferedVersion )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid premaster secret version data 0x%02X 0x%02X, "
				"expected 0x03 0x%02X",
				handshakeInfo->premasterSecret[ 0 ], 
				handshakeInfo->premasterSecret[ 1 ],
				handshakeInfo->clientOfferedVersion );
	bufPtr += length;

	/* If we're expecting a client cert, process the client cert verify */
	if( sessionInfoPtr->cryptKeyset != CRYPT_ERROR )
		{
		/* Read the next packet if necessary */
		if( sessionInfoPtr->receiveBufPos >= sessionInfoPtr->receiveBufEnd )
			{
			status = readPacketSSL( sessionInfoPtr, handshakeInfo, 
									SSL_MSG_HANDSHAKE );
			if( cryptStatusError( status ) )
				return( status );
			bufPtr = sessionInfoPtr->receiveBuffer;
			}		

		/* Process the client cert verify packet:

			byte		ID = 0x0F
			uint24		len
			byte[]		signature */
		length = checkPacketHeader( sessionInfoPtr, &bufPtr, 
									SSL_HAND_CLIENT_CERTVERIFY, 64, 
									CRYPT_UNUSED );
		if( cryptStatusError( length ) )
			return( length );
		status = processCertVerify( sessionInfoPtr, handshakeInfo, bufPtr,
									length, 0 );
		if( cryptStatusError( status ) )
			return( status );
		}

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							Session Access Routines							*
*																			*
****************************************************************************/

void initSSLserverProcessing( SSL_HANDSHAKE_INFO *handshakeInfo )
	{
	handshakeInfo->beginHandshake = beginServerHandshake;
	handshakeInfo->exchangeKeys = exchangeServerKeys;
	}
#endif /* USE_SSL */

⌨️ 快捷键说明

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