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

📄 ssl_rw.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 3 页
字号:
		}

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

	/* If it's TLS 1.1 or newer and we're using a block cipher, adjust for 
	   the explicit IV that precedes the data */
	if( sslInfo->ivSize > 0 )
		{
		assert( sessionInfoPtr->sendBufStartOfs >= \
				SSL_HEADER_SIZE + sslInfo->ivSize ); 

		bufPtr -= sslInfo->ivSize;
		length += sslInfo->ivSize;
		}

	/* Encrypt the payload */
	length = encryptData( sessionInfoPtr, bufPtr, length );
	if( cryptStatusError( length ) )
		return( length );

	/* Insert the final packet payload length into the packet header.  We do
	   this both for convenience and because the stream may have been opened
	   in read-only mode if we're using it to write pre-assembled packet
	   data that's been passed in by the caller */
	headerPtr += ID_SIZE + VERSIONINFO_SIZE;
	mputWord( headerPtr, length );

	/* Sync the stream info to match the new payload size */
	return( sSkip( stream, length - ( sslInfo->ivSize + payloadLength ) ) );
	}

/* Wrap up and send an SSL packet */

int sendPacketSSL( SESSION_INFO *sessionInfoPtr, STREAM *stream,
				   const BOOLEAN sendOnly )
	{
	int status;

	assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( sStatusOK( stream ) );
	assert( stell( stream ) >= SSL_HEADER_SIZE );

	/* Safety check to make sure that the stream is OK */
	if( !sStatusOK( stream ) )
		{
		assert( NOTREACHED );
		return( sGetStatus( stream ) );
		}

	/* Update the length field at the start of the packet if necessary */
	if( !sendOnly )
		completePacketStreamSSL( stream, 0 );

	/* Send the packet to the peer */
	status = swrite( &sessionInfoPtr->stream, 
					 sMemBufPtr( stream ) - stell( stream ), 
					 stell( stream ) );
	if( cryptStatusError( status ) )
		{
		sNetGetErrorInfo( &sessionInfoPtr->stream,
						  sessionInfoPtr->errorMessage,
						  &sessionInfoPtr->errorCode );
		return( status );
		}
	return( CRYPT_OK );	/* swrite() returns a byte count */
	}

/****************************************************************************
*																			*
*							Send/Receive SSL Alerts							*
*																			*
****************************************************************************/

/* Process an alert packet.  IIS often just drops the connection rather than 
   sending an alert when it encounters a problem (although we try and work
   around some of the known problems, e.g. by sending a canary in the client
   hello to force IIS to at least send back something rather than just 
   dropping the connection, see ssl_cli.c), so when communicating with IIS 
   the only error indication we sometimes get will be a "Connection closed 
   by remote host" rather than an SSL-level error message.  In addition when 
   it encounters an unknown cert, MSIE will complete the handshake and then 
   close the connection (via a proper close alert in this case rather than 
   just closing the connection), wait while the user clicks OK several 
   times, and then restart the connection via an SSL resume.  Netscape in 
   contrast just hopes that the session won't time out while waiting for the 
   user to click OK.  As a result, cryptlib sees a closed connection and 
   aborts the session setup process, requiring a second call to the session 
   setup to continue with the resumed session */

int processAlert( SESSION_INFO *sessionInfoPtr, const void *header, 
				  const int headerLength )
	{
	const static struct {
		const int type;
		const char *message;
		const int cryptlibError;
		} alertInfo[] = {
		{ SSL_ALERT_CLOSE_NOTIFY, "Close notify", CRYPT_ERROR_COMPLETE },
		{ SSL_ALERT_UNEXPECTED_MESSAGE, "Unexpected message", CRYPT_ERROR_FAILED },
		{ SSL_ALERT_BAD_RECORD_MAC, "Bad record MAC", CRYPT_ERROR_SIGNATURE },
		{ TLS_ALERT_DECRYPTION_FAILED, "Decryption failed", CRYPT_ERROR_WRONGKEY },
		{ TLS_ALERT_RECORD_OVERFLOW, "Record overflow", CRYPT_ERROR_OVERFLOW },
		{ SSL_ALERT_DECOMPRESSION_FAILURE, "Decompression failure", CRYPT_ERROR_FAILED },
		{ SSL_ALERT_HANDSHAKE_FAILURE, "Handshake failure", CRYPT_ERROR_FAILED },
		{ SSL_ALERT_NO_CERTIFICATE, "No certificate", CRYPT_ERROR_PERMISSION },
		{ SSL_ALERT_BAD_CERTIFICATE, "Bad certificate", CRYPT_ERROR_INVALID },
		{ SSL_ALERT_UNSUPPORTED_CERTIFICATE, "Unsupported certificate", CRYPT_ERROR_INVALID },
		{ SSL_ALERT_CERTIFICATE_REVOKED, "Certificate revoked", CRYPT_ERROR_INVALID },
		{ SSL_ALERT_CERTIFICATE_EXPIRED, "Certificate expired", CRYPT_ERROR_INVALID },
		{ SSL_ALERT_CERTIFICATE_UNKNOWN, "Certificate unknown", CRYPT_ERROR_INVALID },
		{ SSL_ALERT_ILLEGAL_PARAMETER, "Illegal parameter", CRYPT_ERROR_FAILED },
		{ TLS_ALERT_UNKNOWN_CA, "Unknown CA", CRYPT_ERROR_INVALID },
		{ TLS_ALERT_ACCESS_DENIED, "Access denied", CRYPT_ERROR_PERMISSION },
		{ TLS_ALERT_DECODE_ERROR, "Decode error", CRYPT_ERROR_FAILED },
		{ TLS_ALERT_DECRYPT_ERROR, "Decrypt error", CRYPT_ERROR_WRONGKEY },
		{ TLS_ALERT_EXPORT_RESTRICTION, "Export restriction", CRYPT_ERROR_FAILED },
		{ TLS_ALERT_PROTOCOL_VERSION, "Protocol version", CRYPT_ERROR_NOTAVAIL },
		{ TLS_ALERT_INSUFFICIENT_SECURITY, "Insufficient security", CRYPT_ERROR_NOSECURE },
		{ TLS_ALERT_INTERNAL_ERROR, "Internal error", CRYPT_ERROR_FAILED },
		{ TLS_ALERT_USER_CANCELLED, "User cancelled", CRYPT_ERROR_FAILED },
		{ TLS_ALERT_NO_RENEGOTIATION, "No renegotiation", CRYPT_ERROR_FAILED },
		{ TLS_ALERT_UNSUPPORTED_EXTENSION, "Unsupported extension", CRYPT_ERROR_NOTAVAIL },
		{ TLS_ALERT_CERTIFICATE_UNOBTAINABLE, "Certificate unobtainable", CRYPT_ERROR_NOTFOUND },
		{ TLS_ALERT_UNRECOGNIZED_NAME, "Unrecognized name", CRYPT_ERROR_FAILED },
		{ TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE, "Bad certificate status response", CRYPT_ERROR_FAILED },
		{ TLS_ALERT_BAD_CERTIFICATE_HASH_VALUE, "Bad certificate hash value", CRYPT_ERROR_FAILED },
		{ TLS_ALERT_UNKNOWN_PSK_IDENTITY, "Unknown PSK identity", CRYPT_ERROR_NOTFOUND },
 		{ CRYPT_ERROR, NULL }
		};
	STREAM stream;
	BYTE buffer[ 256 + 8 ];
	int length, type, i, status;

	/* Process the alert packet header */
	sMemConnect( &stream, header, headerLength );
	status = length = checkPacketHeader( sessionInfoPtr, &stream, 
										 SSL_MSG_ALERT, ALERTINFO_SIZE );
	if( cryptStatusError( status ) )
		{
		sMemDisconnect( &stream );
		return( status );
		}
	if( sessionInfoPtr->flags & SESSION_ISSECURE_READ )
		{
		if( length < ALERTINFO_SIZE || length > 256 )
			status = CRYPT_ERROR_BADDATA;
		}
	else
		if( length != ALERTINFO_SIZE )
			status = CRYPT_ERROR_BADDATA;
	sMemDisconnect( &stream );
	if( cryptStatusError( status ) )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid alert message" );

	/* Read and process the alert packet */
	status = sread( &sessionInfoPtr->stream, buffer, length );
	if( cryptStatusError( status ) )
		{
		sNetGetErrorInfo( &sessionInfoPtr->stream,
						  sessionInfoPtr->errorMessage,
						  &sessionInfoPtr->errorCode );
		return( status );
		}
	if( status < length )
		{
		/* If we timed out before we could get all of the alert data, bail
		   out without trying to perform any further processing.  We're 
		   about to shut down the session anyway so there's no point in 
		   potentially stalling for ages trying to find a lost byte */
		sendCloseAlert( sessionInfoPtr, TRUE );
		sessionInfoPtr->flags |= SESSION_SENDCLOSED;
		retExt( sessionInfoPtr, CRYPT_ERROR_TIMEOUT, 
				"Timed out reading alert message, only got %d of %d bytes", 
				status, length );
		}
	sessionInfoPtr->receiveBufEnd = length;
	if( ( sessionInfoPtr->flags & SESSION_ISSECURE_READ ) && \
		( length > ALERTINFO_SIZE || \
		  isStreamCipher( sessionInfoPtr->cryptAlgo ) ) )
		{
		/* We only try and decrypt if the alert info is big enough to be
		   encrypted, i.e. it contains the fixed-size data + padding.  This
		   situation can occur if there's an error moving from the non-
		   secure to the secure state.  However, if it's a stream cipher the 
		   ciphertext and plaintext are the same size so we always have to 
		   try the decryption */
		sMemConnect( &stream, buffer, length );
		status = unwrapPacketSSL( sessionInfoPtr, &stream, SSL_MSG_ALERT );
		sMemDisconnect( &stream );
		if( cryptStatusError( status ) )
			{
			sendCloseAlert( sessionInfoPtr, TRUE );
			sessionInfoPtr->flags |= SESSION_SENDCLOSED;
			return( status );
			}
		}

	/* Tell the other side that we're going away */
	sendCloseAlert( sessionInfoPtr, TRUE );
	sessionInfoPtr->flags |= SESSION_SENDCLOSED;

	/* Process the alert info.  In theory we should also make the session 
	   non-resumable if the other side goes away without sending a close 
	   alert, but this leads to too many problems with non-resumable 
	   sessions if we do it.  For example many protocols do their own end-of-
	   data indication (e.g. "Connection: close" in HTTP and BYE in SMTP) 
	   and so don't bother with a close alert.  In other cases 
	   implementations just drop the connection without sending a close 
	   alert, carried over from many early Unix protocols that used a 
	   connection close to signify end-of-data, which has caused problems 
	   ever since for newer protocols that want to keep the connection open.  
	   Other implementations still send their alert but then immediately 
	   close the connection.  Because of this haphazard approach to closing 
	   connections, many implementations allow a session to be resumed even 
	   if no close alert is sent.  In order to be compatible with this 
	   behaviour, we do the same (thus perpetuating the problem).  If 
	   necessary this can be fixed by calling deleteSessionCacheEntry() if 
	   the connection is closed without a close alert having been sent */
	if( buffer[ 0 ] != SSL_ALERTLEVEL_WARNING && \
		buffer[ 0 ] != SSL_ALERTLEVEL_FATAL )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Invalid alert message level %d", buffer[ 0 ] );
	sessionInfoPtr->errorCode = type = buffer[ 1 ];
	for( i = 0; alertInfo[ i ].type != CRYPT_ERROR && \
				alertInfo[ i ].type != type; i++ );
	if( alertInfo[ i ].type == CRYPT_ERROR )
		retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
				"Unknown alert message type %d at alert level %d", 
				type, buffer[ 0 ] );
	strcpy( sessionInfoPtr->errorMessage,
			( sessionInfoPtr->version == SSL_MINOR_VERSION_SSL ) ? \
				"Received SSL alert message: " : \
				"Received TLS alert message: " );
	strcat( sessionInfoPtr->errorMessage, alertInfo[ i ].message );
	return( alertInfo[ i ].cryptlibError );
	}

/* Send a close alert, with appropriate protection if necessary */

static void sendAlert( SESSION_INFO *sessionInfoPtr, 
					   const int alertLevel, const int alertType,
					   const BOOLEAN alertReceived )
	{
	STREAM stream;
	int length, status = CRYPT_OK;

	/* Make sure that we only send a single alert.  Normally we do this 
	   automatically on shutdown, but we may have already sent it earlier 
	   as part of an error-handler */
	if( sessionInfoPtr->protocolFlags & SSL_PFLAG_ALERTSENT )
		return;
	sessionInfoPtr->protocolFlags |= SSL_PFLAG_ALERTSENT;

	/* Create the alert.  We can't really do much with errors at this point, 
	   although we can throw an exception in the debug version to draw 
	   attention to the fact that there's a problem.  The one error type 
	   that we don't complain about is an access permission problem, which 
	   can occur when cryptlib is shutting down, for example when the 
	   current thread is blocked waiting for network traffic and another 
	   thread shuts cryptlib down */
	openPacketStreamSSL( &stream, sessionInfoPtr, CRYPT_USE_DEFAULT, 
						 SSL_MSG_ALERT );
	sputc( &stream, alertLevel );
	sputc( &stream, alertType );
	if( sessionInfoPtr->flags & SESSION_ISSECURE_WRITE )
		{
		status = wrapPacketSSL( sessionInfoPtr, &stream, 0 );
		assert( status != CRYPT_ERROR_PERMISSION );
		}
	else
		completePacketStreamSSL( &stream, 0 );
	length = stell( &stream );
	sMemDisconnect( &stream );

	/* Send the alert */
	if( cryptStatusOK( status ) )
		status = sendCloseNotification( sessionInfoPtr, 
										sessionInfoPtr->sendBuffer, length );
	else
		status = sendCloseNotification( sessionInfoPtr, NULL, 0 );
	if( cryptStatusError( status ) || alertReceived )
		return;

	/* Read back the other side's close alert acknowledgement */
	readPacketSSL( sessionInfoPtr, NULL, SSL_MSG_ALERT );
	}

void sendCloseAlert( SESSION_INFO *sessionInfoPtr, 
					 const BOOLEAN alertReceived )
	{
	sendAlert( sessionInfoPtr, SSL_ALERTLEVEL_WARNING, 
			   SSL_ALERT_CLOSE_NOTIFY, alertReceived );
	}

void sendHandshakeFailAlert( SESSION_INFO *sessionInfoPtr )
	{
	/* We set the alertReceived flag to true when sending a handshake
	   failure alert to avoid waiting to get back an ack, since this 
	   alert type isn't acknowledged by the other side */
	sendAlert( sessionInfoPtr, SSL_ALERTLEVEL_FATAL, 
			   SSL_ALERT_HANDSHAKE_FAILURE, TRUE );
	}
#endif /* USE_SSL */

⌨️ 快捷键说明

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