Beispiel #1
0
int connectViaSocksProxy( INOUT STREAM *stream )
	{
	MESSAGE_DATA msgData;
	BYTE socksBuffer[ 64 + CRYPT_MAX_TEXTSIZE + 8 ], *bufPtr = socksBuffer;
	char userName[ CRYPT_MAX_TEXTSIZE + 8 ];
	int length, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );

	REQUIRES_S( stream->type == STREAM_TYPE_NETWORK );

	/* Get the SOCKS user name, defaulting to "cryptlib" if there's none
	   set */
	setMessageData( &msgData, userName, CRYPT_MAX_TEXTSIZE );
	status = krnlSendMessage( DEFAULTUSER_OBJECT_HANDLE,
							  IMESSAGE_GETATTRIBUTE_S, &msgData,
							  CRYPT_OPTION_NET_SOCKS_USERNAME );
	if( cryptStatusOK( status ) )
		userName[ msgData.length ] = '\0';
	else
		strlcpy_s( userName, CRYPT_MAX_TEXTSIZE, "cryptlib" );

	/* Build up the SOCKSv4 request string:

		BYTE: version = 4
		BYTE: command = 1 (connect)
		WORD: port
		LONG: IP address
		STRING: userName + '\0'

	   Note that this has a potential problem in that it requires a DNS 
	   lookup by the client, which can lead to problems if the client
	   can't get DNS requests out because only SOCKSified access is allowed.
	   A related problem occurs when SOCKS is being used as a tunnelling
	   interface because the DNS lookup will communicate data about the 
	   client to an observer outside the tunnel.

	   To work around this there's a so-called SOCKSv4a protocol that has 
	   the SOCKS proxy perform the lookup:

		BYTE: version = 4
		BYTE: command = 1 (connect)
		WORD: port
		LONG: IP address = 0x00 0x00 0x00 0xFF
		STRING: userName + '\0'
		STRING: FQDN + '\0'

	   Unfortunately there's no way to tell whether a SOCKS server supports
	   4a or only 4, but in any case since SOCKS support is currently 
	   disabled we leave the poke-and-hope 4a detection until such time as
	   someone actually requests it */
	*bufPtr++ = 4; *bufPtr++ = 1;
	mputWord( bufPtr, netStream->port );
	status = getIPAddress( stream, bufPtr, netStream->host );
	strlcpy_s( bufPtr + 4, CRYPT_MAX_TEXTSIZE, userName );
	length = 1 + 1 + 2 + 4 + strlen( userName ) + 1;
	if( cryptStatusError( status ) )
		{
		netStream->transportDisconnectFunction( stream, TRUE );
		return( status );
		}

	/* Send the data to the server and read back the reply */
	status = netStream->transportWriteFunction( stream, socksBuffer, length,
												TRANSPORT_FLAG_FLUSH );
	if( cryptStatusOK( status ) )
		status = netStream->transportReadFunction( stream, socksBuffer, 8,
												   TRANSPORT_FLAG_BLOCKING );
	if( cryptStatusError( status ) )
		{
		/* The involvement of a proxy complicates matters somewhat because
		   we can usually connect to the proxy OK but may run into problems
		   going from the proxy to the remote server, so if we get an error
		   at this stage (which will typically show up as a read error from
		   the proxy) we report it as an open error instead */
		if( status == CRYPT_ERROR_READ || status == CRYPT_ERROR_COMPLETE )
			status = CRYPT_ERROR_OPEN;
		netStream->transportDisconnectFunction( stream, TRUE );
		return( status );
		}

	/* Make sure that everything is OK:

		BYTE: null = 0
		BYTE: status = 90 (OK)
		WORD: port
		LONG: IP address */
	if( socksBuffer[ 1 ] != 90 )
		{
		int i;

		netStream->transportDisconnectFunction( stream, TRUE );
		strlcpy_s( netStream->errorInfo->errorString, MAX_ERRMSG_SIZE, 
				   "Socks proxy returned" );
		for( i = 0; i < 8; i++ )
			{
			sprintf_s( netStream->errorInfo->errorString + 20 + ( i * 3 ),
					   MAX_ERRMSG_SIZE - ( 20 + ( i * 3 ) ), " %02X", 
					   socksBuffer[ i ] );
			}
		strlcat_s( netStream->errorInfo->errorString, MAX_ERRMSG_SIZE, "." );
		netStream->errorCode = socksBuffer[ 1 ];
		return( CRYPT_ERROR_OPEN );
		}

	return( CRYPT_OK );
	}
Beispiel #2
0
static int getItemFunction( DEVICE_INFO *deviceInfo,
							CRYPT_CONTEXT *iCryptContext,
							const KEYMGMT_ITEM_TYPE itemType,
							const CRYPT_KEYID_TYPE keyIDtype,
							const void *keyID, const int keyIDlength,
							void *auxInfo, int *auxInfoLength, 
							const int flags )
	{
#if 0
	const CRYPT_DEVICE cryptDevice = deviceInfo->objectHandle;
	CRYPT_CERTIFICATE iCryptCert = CRYPT_UNUSED;
	const CAPABILITY_INFO *capabilityInfoPtr;
	HW_KEYINFO keyInfo;
	MESSAGE_DATA msgData;
	const int extraFlags = ( itemType == KEYMGMT_ITEM_PRIVATEKEY ) ? \
						   KEYMGMT_FLAG_DATAONLY_CERT : 0;
	int keyHandle, p15status, status;
#endif
	CRYPT_CONTEXT iLocalContext;
	HARDWARE_INFO *hardwareInfo = deviceInfo->deviceHardware;
	MESSAGE_KEYMGMT_INFO getkeyInfo;
	int keyHandle, status;

	assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) );
	assert( isWritePtr( iCryptContext, sizeof( CRYPT_CONTEXT ) ) );
	assert( isReadPtr( keyID, keyIDlength ) );

	REQUIRES( itemType == KEYMGMT_ITEM_PUBLICKEY || \
			  itemType == KEYMGMT_ITEM_PRIVATEKEY );
	REQUIRES( keyIDtype == CRYPT_KEYID_NAME || \
			  keyIDtype == CRYPT_KEYID_URI || \
			  keyIDtype == CRYPT_IKEYID_KEYID || \
			  keyIDtype == CRYPT_IKEYID_PGPKEYID || \
			  keyIDtype == CRYPT_IKEYID_ISSUERANDSERIALNUMBER );
	REQUIRES( auxInfo == NULL && *auxInfoLength == 0 );
	REQUIRES( flags >= KEYMGMT_FLAG_NONE && flags < KEYMGMT_FLAG_MAX );

#if 1
	/* Redirect the fetch down to the PKCS #15 storage object, which will
	   create either a dummy context that we have to connect to the actual
	   hardware for a private-key object or a native public-key/certificate 
	   object if it's a non-private-key item */
	if( hardwareInfo->iCryptKeyset == CRYPT_ERROR )
		return( CRYPT_ERROR_NOTINITED );
	setMessageKeymgmtInfo( &getkeyInfo, keyIDtype, keyID, keyIDlength,
						   NULL, 0, flags );
	status = krnlSendMessage( hardwareInfo->iCryptKeyset,
							  IMESSAGE_KEY_GETKEY, &getkeyInfo,
							  itemType );
	if( cryptStatusError( status ) )
		return( status );
	iLocalContext = getkeyInfo.cryptHandle;

	/* If it's a public-key fetch, we've created a native object and we're
	   done */
	if( itemType != KEYMGMT_ITEM_PRIVATEKEY )
		{
		*iCryptContext = iLocalContext;
		return( CRYPT_OK );
		}

	/* It was a private-key fetch, we need to connect the dummy context that
	   was created with the underlying hardware.  When this final step
	   has been completed we can move the context to the initialised state */
	status = getHardwareReference( iLocalContext, &keyHandle );
	if( cryptStatusError( status ) )
		{
		krnlSendNotifier( iLocalContext, IMESSAGE_DECREFCOUNT );
		return( status );
		}
	status = krnlSendMessage( iLocalContext, IMESSAGE_SETATTRIBUTE,
							  &keyHandle, CRYPT_IATTRIBUTE_DEVICEOBJECT );
	if( cryptStatusOK( status ) )
		{
		status = krnlSendMessage( iLocalContext, IMESSAGE_SETATTRIBUTE, 
								  MESSAGE_VALUE_UNUSED, 
								  CRYPT_IATTRIBUTE_INITIALISED );
		}
	if( cryptStatusError( status ) )
		{
		krnlSendNotifier( iLocalContext, IMESSAGE_DECREFCOUNT );
		return( status );
		}
#else
	/* As a first step we redirect the fetch down to the PKCS #15 storage 
	   object to get any certificate that may be associated with the item.
	   We always do this because if we're fetching a public key then this
	   is all that we need and if we're fetching a private key then we'll
	   associate the certificate with it if it's present */
	if( hardwareInfo->iCryptKeyset == CRYPT_ERROR )
		return( CRYPT_ERROR_NOTINITED );
	setMessageKeymgmtInfo( &getkeyInfo, keyIDtype, keyID, keyIDlength,
						   NULL, 0, flags | extraFlags );
	p15status = krnlSendMessage( hardwareInfo->iCryptKeyset,
								 IMESSAGE_KEY_GETKEY, &getkeyInfo,
								 KEYMGMT_ITEM_PUBLICKEY );
	if( cryptStatusOK( p15status ) )
		{
		iCryptCert = getkeyInfo.cryptHandle;

		/* If we were after a public key, we're done */
		if( itemType == KEYMGMT_ITEM_PUBLICKEY )
			{
			*iCryptContext = iCryptCert;
			return( CRYPT_OK );
			}

		/* If we were after a private key and the keyID is one that isn't
		   stored locally, extract it from the returned private key */
		// This won't work, there's no CRYPT_IKEYID_KEYID or 
		// CRYPT_IKEYID_PGPKEYID with the cert, only an 
		// CRYPT_IKEYID_ISSUERANDSERIALNUMBER
		}

	/* Look up the private key, which we may use directly or simply extract
	   the public-key components from.  If there's an error then we 
	   preferentially return the error code from the storage object, which 
	   is likely to be more informative than a generic CRYPT_ERROR_NOTFOUND 
	   from the hardware lookup */
	status = hwLookupItemInfo( keyIDtype, keyID, keyIDlength, &keyHandle, 
							   &keyInfo );
	if( cryptStatusError( status ) )
		return( cryptStatusError( p15status ) ? p15status : status );
	if( itemType == KEYMGMT_ITEM_PUBLICKEY )
		{
		MESSAGE_CREATEOBJECT_INFO createInfo;

		/* There's no certificate present but we do have private-key 
		   components from which we can extract the public-key portion to
		   create a native context instead of a device one.  This solves a 
		   variety of problems including the fact that performing public-key 
		   operations natively is often much faster than the time it takes
		   to marshall the data and get it to the crypto hardware, and that 
		   if we do it ourselves we can defend against a variety of RSA 
		   padding and timing attacks that have come up since the device 
		   firmware was done */
		setMessageCreateObjectInfo( &createInfo, keyInfo.cryptAlgo );
		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, 
								  IMESSAGE_DEV_CREATEOBJECT, &createInfo, 
								  OBJECT_TYPE_CONTEXT );
		if( cryptStatusError( status ) )
			return( status );
		iLocalContext = createInfo.cryptHandle;

		/* Send the keying information to the context.  We don't set the 
		   action flags because there are none recorded at the hardware 
		   level */
		status = setPublicComponents( createInfo.cryptHandle, 
									  keyInfo.cryptAlgo, 
									  &keyInfo.publicKeyInfo );
		if( cryptStatusError( status ) )
			{
			krnlSendNotifier( iLocalContext, IMESSAGE_DECREFCOUNT );
			return( status );
			}
		*iCryptContext = iLocalContext;
		return( CRYPT_OK );
		}

	/* It's a private key, create a dummy context for the device object, 
	   remember the device that it's contained in, and record the handle for 
	   the device-internal key */
	capabilityInfoPtr = findCapabilityInfo( deviceInfo->capabilityInfoList, 
											keyInfo.cryptAlgo );
	if( capabilityInfoPtr == NULL )
		return( CRYPT_ERROR_NOTAVAIL );
	status = createContextFromCapability( &iLocalContext, cryptDevice, 
										  capabilityInfoPtr, 
										  CREATEOBJECT_FLAG_DUMMY | \
										  CREATEOBJECT_FLAG_PERSISTENT );
	if( cryptStatusError( status ) )
		{
		if( iCryptCert != CRYPT_UNUSED )
			krnlSendNotifier( iCryptCert, IMESSAGE_DECREFCOUNT );
		return( status );
		}
	status = krnlSendMessage( iLocalContext, IMESSAGE_SETDEPENDENT,
							  ( MESSAGE_CAST ) &cryptDevice, 
							  SETDEP_OPTION_INCREF );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( iLocalContext, IMESSAGE_SETATTRIBUTE, 
								  ( MESSAGE_CAST ) &keyHandle, 
								  CRYPT_IATTRIBUTE_DEVICEOBJECT );
	if( cryptStatusError( status ) )
		{
		krnlSendNotifier( iLocalContext, IMESSAGE_DECREFCOUNT );
		if( iCryptCert != CRYPT_UNUSED )
			krnlSendNotifier( iCryptCert, IMESSAGE_DECREFCOUNT );
		return( status );
		}

	/* Set the object's label, send the keying information to the context, 
	   and mark it as initialised (i.e. with a key loaded).  Setting the 
	   label requires special care because the label that we're setting 
	   matches that of an existing object, so trying to set it as a standard 
	   CRYPT_CTXINFO_LABEL will return a CRYPT_ERROR_DUPLICATE error when 
	   the context code checks for the existence of an existing label.  To 
	   handle this, we use the attribute CRYPT_IATTRIBUTE_EXISTINGLABEL to 
	   indicate that we're setting a label that matches an existing object 
	   in the device */
	if( keyInfo.labelLength <= 0 )
		{
		/* If there's no label present, use a dummy value */
		strlcpy_s( keyInfo.label, CRYPT_MAX_TEXTSIZE, "Label-less private key" );
		keyInfo.labelLength = 22;
		}
	setMessageData( &msgData, keyInfo.label, keyInfo.labelLength );
	status = krnlSendMessage( iLocalContext, IMESSAGE_SETATTRIBUTE_S,
							  &msgData, CRYPT_IATTRIBUTE_EXISTINGLABEL );
	if( cryptStatusOK( status ) )
		status = setPublicComponents( iLocalContext, keyInfo.cryptAlgo, 
									  &keyInfo.publicKeyInfo );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( iLocalContext, IMESSAGE_SETATTRIBUTE,
								  MESSAGE_VALUE_UNUSED, 
								  CRYPT_IATTRIBUTE_INITIALISED );
	if( cryptStatusOK( status ) && ( iCryptCert != CRYPT_UNUSED ) )
		{
		/* If there's a certificate present, attach it to the context.  The 
		   certificate is an internal object used only by the context so we 
		   tell the kernel to mark it as owned by the context only */
		status = krnlSendMessage( iLocalContext, IMESSAGE_SETDEPENDENT, 
								  ( MESSAGE_CAST ) &iCryptCert, 
								  SETDEP_OPTION_NOINCREF );
		}
	if( cryptStatusError( status ) )
		{
		krnlSendNotifier( iLocalContext, IMESSAGE_DECREFCOUNT );
		if( iCryptCert != CRYPT_UNUSED )
			krnlSendNotifier( iCryptCert, IMESSAGE_DECREFCOUNT );
		}
#endif /* 1 */

	*iCryptContext = iLocalContext;
	return( CRYPT_OK );
	}