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

📄 ssl_cli.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 2 页
字号:
			retExt( sessionInfoPtr, status, 
					"Server provided a broken/invalid certificate, try again "
					"with a reduced level of certificate compliance "
					"checking" );
		}
	else
		status = krnlSendMessage( createInfo.cryptHandle, 
								  IMESSAGE_GETATTRIBUTE, &algorithm,
								  CRYPT_CTXINFO_ALGO );
	if( cryptStatusOK( status ) )
		{
		setMessageData( &msgData, certFingerprint, CRYPT_MAX_HASHSIZE );
		status = krnlSendMessage( createInfo.cryptHandle, 
							IMESSAGE_GETATTRIBUTE_S, &msgData, 
							( sessionInfoPtr->keyFingerprintSize == 16 ) ? \
							CRYPT_CERTINFO_FINGERPRINT_MD5 : \
							CRYPT_CERTINFO_FINGERPRINT_SHA );
		}
	if( cryptStatusError( status ) )
		return( status );
	bufPtr += chainLength;
	sessionInfoPtr->iKeyexCryptContext = createInfo.cryptHandle;

	/* Either compare the cert fingerprint to a supplied one or save it for 
	   the caller to examine */
	if( sessionInfoPtr->keyFingerprintSize > 0 )
		{
		/* The caller has supplied a cert fingerprint, compare it to the
		   received cert's fingerprint to make sure that we're talking to 
		   the right server */
		if( sessionInfoPtr->keyFingerprintSize != msgData.length || \
			memcmp( sessionInfoPtr->keyFingerprint, certFingerprint,
					msgData.length ) )
			retExt( sessionInfoPtr, CRYPT_ERROR_WRONGKEY,
					"Server key didn't match fingerprint" );
		}
	else
		{
		/* Remember the cert fingerprint in case the caller wants to check 
		   it */
		memcpy( sessionInfoPtr->keyFingerprint, certFingerprint, 
				msgData.length );
		sessionInfoPtr->keyFingerprintSize = msgData.length;
		}

	/* Make sure that we can perform the required operation using the key 
	   we've been given.  This performs a variety of checks alongside the 
	   obvious one, so it's a good general health check before we go any 
	   further.  If this fails, we convert the result to a wrong key error 
	   rather than a check failure */
	status = krnlSendMessage( createInfo.cryptHandle, 
							  IMESSAGE_CHECK, NULL,
							  isKeyxAlgo( algorithm ) ? \
								MESSAGE_CHECK_PKC_KA_IMPORT : \
								MESSAGE_CHECK_PKC_ENCRYPT );
	if( cryptStatusError( status ) )
		retExt( sessionInfoPtr, CRYPT_ERROR_WRONGKEY,
				"Server returned a key incapable of being used for %s",
				isKeyxAlgo( algorithm ) ? "key agreement" : "key transport" );

	/* Process optional server cert request and server hello done:

		byte		ID = 0x0E
		uint24		len = 0 */
	if( sessionInfoPtr->receiveBufPos >= sessionInfoPtr->receiveBufEnd )
		{
		status = readPacketSSL( sessionInfoPtr, handshakeInfo,  
								SSL_MSG_HANDSHAKE );
		if( cryptStatusError( status ) )
			return( status );
		bufPtr = sessionInfoPtr->receiveBuffer;
		}		
	if( *bufPtr == SSL_HAND_SERVER_CERTREQUEST )
		{
		int certInfoLen;

		/* The server wants a client cert:

			byte	ID = 0x0D
			uint24	len
			byte	certTypeLen
			byte[]	certType
			uint16	caNameListLen
				uint16	caNameLen
				byte[]	caName

		   We don't really care what's in the cert request packet since the 
		   contents are irrelevant, and in many cases servers send out
		   superfluous cert requests without the admins even knowning that
		   they're doing it.  All we do here is perform a basic sanity check 
		   and remember that we may need to submit a cert later on.

		   Although the spec says that at least one CA name entry must be 
		   present, some implementations send a zero-length list, so we allow 
		   this as well.  The spec was changed in late TLS 1.1 drafts to
		   reflect this practice */
		length = checkPacketHeader( sessionInfoPtr, &bufPtr, 
									SSL_HAND_SERVER_CERTREQUEST, 4, 
									CRYPT_UNUSED );
		if( cryptStatusError( length ) )
			return( length );
		certInfoLen = *bufPtr++;	/* certTypeLen */
		if( certInfoLen < 1 || certInfoLen > length - 1 )
			retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
					"Invalid cert request cert type length %d", 
					certInfoLen );
		bufPtr += certInfoLen;		/* Skip cert types */
		length -= 1 + certInfoLen;
		certInfoLen = mgetWord( bufPtr );
		if( certInfoLen < 0 || certInfoLen != length - UINT16_SIZE )
			retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
					"Invalid cert request CA name list length %d", 
					certInfoLen );
		bufPtr += certInfoLen;
		needClientCert = TRUE;
		if( sessionInfoPtr->receiveBufPos >= sessionInfoPtr->receiveBufEnd )
			{
			status = readPacketSSL( sessionInfoPtr, handshakeInfo,  
									SSL_MSG_HANDSHAKE );
			if( cryptStatusError( status ) )
				return( status );
			bufPtr = sessionInfoPtr->receiveBuffer;
			}
		}
	if( sessionInfoPtr->receiveBufPos + SERVERHELLODONE_TEMPLATE_SIZE > \
			sessionInfoPtr->receiveBufEnd || \
		memcmp( bufPtr, serverHelloDoneTemplate, 
				SERVERHELLODONE_TEMPLATE_SIZE ) )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid server hello packet" );
	sessionInfoPtr->receiveBufPos += SERVERHELLODONE_TEMPLATE_SIZE;

	/* If we need a client cert, build the client cert packet */
	bufPtr = sessionInfoPtr->sendBuffer + sessionInfoPtr->sendBufStartOfs;
	if( needClientCert )
		{
		/* If we haven't got a cert available, tell the server.  SSL and TLS
		   differ here, SSL sends a no-certificate alert while TLS sends an
		   empty client cert packet */
		if( sessionInfoPtr->privateKey == CRYPT_ERROR )
			{
			setErrorInfo( sessionInfoPtr, CRYPT_SESSINFO_PRIVATEKEY, 
						  CRYPT_ERRTYPE_ATTR_ABSENT );
			if( sessionInfoPtr->version == SSL_MINOR_VERSION_SSL )
				swrite( &sessionInfoPtr->stream, noCertAlertSSLTemplate, 
						NOCERTALERT_TEMPLATE_SIZE );
			else
				{
				memcpy( bufPtr, noCertTLSTemplate, NOCERT_TEMPLATE_SIZE );
				length = NOCERT_TEMPLATE_SIZE;
				bufPtr += NOCERT_TEMPLATE_SIZE;
				}

			/* The reaction to the lack of a cert is up to the server (some 
			   just request one anyway even though they can't do anything
			   with it), so from here on we just continue as if nothing had
			   happened */
			needClientCert = FALSE;
			}
		else
			{
			/* Write the client cert chain */
			status = length = writeSSLCertChain( sessionInfoPtr, bufPtr );
			if( cryptStatusError( status ) )
				return( status );
			bufPtr += status;
			}
		}
	else
		/* No client cert packet */
		length = 0;

	/* Build 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 */
	*bufPtr++ = SSL_HAND_CLIENT_KEYEXCHANGE;
	*bufPtr++ = 0;
	lengthPtr = bufPtr;
	bufPtr += UINT16_SIZE;
	if( !isKeyxAlgo( algorithm ) )
		{
		if( sessionInfoPtr->version >= SSL_MINOR_VERSION_TLS )
			bufPtr += UINT16_SIZE;	/* See comment below */

		/* Create the premaster secret and wrap it using the server's public 
		   key.  Note that the version that we advertise 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 */
		handshakeInfo->premasterSecret[ 0 ] = SSL_MAJOR_VERSION;
		handshakeInfo->premasterSecret[ 1 ] = handshakeInfo->clientOfferedVersion;
		setMessageData( &msgData, 
						handshakeInfo->premasterSecret + VERSIONINFO_SIZE, 
						SSL_SECRET_SIZE - VERSIONINFO_SIZE );
		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
								  IMESSAGE_GETATTRIBUTE_S, &msgData,
								  CRYPT_IATTRIBUTE_RANDOM );
		if( cryptStatusError( status ) )
			return( status );
		setMechanismWrapInfo( &mechanismInfo, bufPtr, CRYPT_MAX_PKCSIZE, 
							  handshakeInfo->premasterSecret, SSL_SECRET_SIZE, 
							  CRYPT_UNUSED, sessionInfoPtr->iKeyexCryptContext, 
							  CRYPT_UNUSED );
		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_EXPORT, 
								  &mechanismInfo, MECHANISM_PKCS1_RAW );
		if( cryptStatusError( status ) )
			return( status );
		bufPtr += mechanismInfo.wrappedDataLength;
		length += ID_SIZE + LENGTH_SIZE + mechanismInfo.wrappedDataLength;
		if( sessionInfoPtr->version >= SSL_MINOR_VERSION_TLS )
			{
			/* 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 ambiguous) so the encoding 
			   differs slightly between SSL and TLS */
			mputWord( lengthPtr, UINT16_SIZE + mechanismInfo.wrappedDataLength );
			length += UINT16_SIZE;
			}
		mputWord( lengthPtr, mechanismInfo.wrappedDataLength );
		}
	else
		{
		KEYAGREE_PARAMS keyAgreeParams;

		/* Perform phase 2 of the DH key agreement.  This is in fact extra-
		   ordinarily complex since SSL allows for DH parameters to be 
		   exchanged in every imaginable manner, including raw DH parameters, 
		   a DH key signed by the server, a DH server cert, and just to top 
		   it all off as DH client info.  Since nothing actively uses DH, 
		   it's not even possible to determine which of the various options 
		   are likely to occur.  Because of this we go through the motions of
		   handling DH up to this point but leave the public value zeroed, if
		   anyone ever reports a live deployment that uses DH we can fetch
		   the data from the appropriate location and complete the key
		   agreement process */
		memset( &keyAgreeParams, 0, sizeof( KEYAGREE_PARAMS ) );
#if 0
		memcpy( keyAgreeParams.publicValue, y, yLength );
		keyAgreeParams.publicValueLen = yLength;
#endif /* 0 */
		status = krnlSendMessage( sessionInfoPtr->iKeyexCryptContext,
								  IMESSAGE_CTX_DECRYPT, &keyAgreeParams, 
								  sizeof( KEYAGREE_PARAMS ) );
		if( cryptStatusError( status ) )
			{
			zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) );
			return( status );
			}
		memcpy( handshakeInfo->premasterSecret, keyAgreeParams.wrappedKey,
				SSL_SECRET_SIZE );
		zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) );
		}

	/* If we need to supply a client cert, send the signature generated with 
	   the cert to prove possession of the private key */
	if( needClientCert )
		{
		int verifyInfoLength;

		/* Write the packet header and drop in the signature data */
		*bufPtr++ = SSL_HAND_CLIENT_CERTVERIFY;
		status = verifyInfoLength = \
			processCertVerify( sessionInfoPtr, handshakeInfo, 
							   bufPtr + LENGTH_SIZE, 0, 
							   min( sessionInfoPtr->sendBufSize - ( length + 256 ),
									MAX_PACKET_SIZE ) );
		if( cryptStatusError( status ) )
			return( status );
		*bufPtr++ = 0;
		mputWord( bufPtr, verifyInfoLength );
		length += ID_SIZE + LENGTH_SIZE + verifyInfoLength;
		}

	/* Send the client information to the server */
	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( CRYPT_OK );
	}

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

void initSSLclientProcessing( SSL_HANDSHAKE_INFO *handshakeInfo )
	{
	handshakeInfo->beginHandshake = beginClientHandshake;
	handshakeInfo->exchangeKeys = exchangeClientKeys;
	}
#endif /* USE_SSL */

⌨️ 快捷键说明

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