コード例 #1
0
ファイル: obj_qry.c プロジェクト: TellarHK/wwiv
int getPgpPacketInfo( INOUT STREAM *stream, 
					  OUT QUERY_INFO *queryInfo )
	{
	const long startPos = stell( stream );
	long offset, length;
	int ctb, status;

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

	/* Clear return value */
	memset( queryInfo, 0, sizeof( QUERY_INFO ) );

	/* Read the packet header and extract information from the CTB.  Note
	   that the assignment of version numbers is speculative only because
	   it's possible to use PGP 2.x packet headers to wrap up OpenPGP
	   packets */
	status = pgpReadPacketHeader( stream, &ctb, &length, 8 );
	if( cryptStatusError( status ) )
		return( status );
	queryInfo->formatType = CRYPT_FORMAT_PGP;
	queryInfo->version = pgpGetPacketVersion( ctb );
	offset = stell( stream );
	if( cryptStatusError( offset ) )
		return( offset );
	queryInfo->size = ( offset - startPos ) + length;
	switch( pgpGetPacketType( ctb ) )
		{
		case PGP_PACKET_SKE:
			queryInfo->type = CRYPT_OBJECT_ENCRYPTED_KEY;
			break;

		case PGP_PACKET_PKE:
			queryInfo->type = CRYPT_OBJECT_PKCENCRYPTED_KEY;
			break;

		case PGP_PACKET_SIGNATURE:
			queryInfo->type = CRYPT_OBJECT_SIGNATURE;
			break;

		case PGP_PACKET_SIGNATURE_ONEPASS:
			/* First half of a one-pass signature, this is given a special
			   type of 'none' since it's not a normal packet */
			queryInfo->type = CRYPT_OBJECT_NONE;
			break;

		default:
			DEBUG_DIAG(( "Found unrecognised ctb %X", ctb ));
			assert( DEBUG_WARN );
			return( CRYPT_ERROR_BADDATA );
		}

	/* Make sure that all of the data is present without resetting the 
	   stream */
	return( ( sMemDataLeft( stream ) < length ) ? \
			CRYPT_ERROR_UNDERFLOW : CRYPT_OK );
	}
コード例 #2
0
ファイル: int_err.c プロジェクト: TellarHK/wwiv
CHECK_RETVAL_ERROR \
static int convertErrorStatus( IN_ERROR const int status )
	{
	REQUIRES( cryptStatusError( status ) );

	if( cryptArgError( status ) )
		{
		DEBUG_DIAG(( "Error exit was passed argError status" ));
		assert( DEBUG_WARN );
		return( CRYPT_ERROR_FAILED );
		}

	return( status );
	}
コード例 #3
0
ファイル: int_err.c プロジェクト: TellarHK/wwiv
static BOOLEAN formatErrorString( OUT ERROR_INFO *errorInfoPtr, 
								  IN_STRING const char *format, 
								  IN va_list argPtr )
	{
	assert( isWritePtr( errorInfoPtr, sizeof( ERROR_INFO ) ) );
	assert( isReadPtr( format, 4 ) );

	REQUIRES_B( verifyVAList( argPtr ) );

	/* Clear return value */
	memset( errorInfoPtr, 0, sizeof( ERROR_INFO ) );

	/* This function is a bit tricky to deal with because of the 
	   braindamaged behaviour of some of the underlying functions that it 
	   may be mapped to.  Specifically, (v)snprintf() returns the number of 
	   bytes it *could* have written had it felt like it rather than how 
	   many it actually wrote on non-Windows systems and an error indicator 
	   with no guarantee of null-termination on Windows systems.  The latter 
	   isn't a problem because we both catch the error and don't require 
	   null termination, the former is more problematic because it can lead 
	   to a length indication that's larger than the actual buffer.  To 
	   handle this we explicitly check for an overflow as well as an 
	   error/underflow */
	errorInfoPtr->errorStringLength = \
				vsprintf_s( errorInfoPtr->errorString, MAX_ERRMSG_SIZE, 
							format, argPtr ); 
	if( errorInfoPtr->errorStringLength <= 0 || \
		errorInfoPtr->errorStringLength > MAX_ERRMSG_SIZE )
		{
		DEBUG_DIAG(( "Invalid error string data" ));
		assert( DEBUG_WARN );
		setErrorString( errorInfoPtr, 
						"(Couldn't record error information)", 35 );

		return( FALSE );
		}

	return( TRUE );
	}
コード例 #4
0
int initCertMgmtACL( INOUT KERNEL_DATA *krnlDataPtr )
	{
	int i;

	assert( isWritePtr( krnlDataPtr, sizeof( KERNEL_DATA ) ) );

	/* Perform a consistency check on the cert management ACLs */
	for( i = 0; certMgmtACLTbl[ i ].action != MECHANISM_NONE && \
				i < FAILSAFE_ARRAYSIZE( certMgmtACLTbl, CERTMGMT_ACL ); i++ )
		{
		const CERTMGMT_ACL *certMgmtACL = &certMgmtACLTbl[ i ];

		/* Actions and permissions are consistent */
		ENSURES( certMgmtACL->action > CRYPT_CERTACTION_NONE && \
				 certMgmtACL->action < CRYPT_CERTACTION_LAST );
		ENSURES( certMgmtACL->access == ACTION_PERM_NONE || \
				 certMgmtACL->access == ACTION_PERM_NONE_EXTERNAL || \
				 certMgmtACL->access == ACTION_PERM_ALL );

		/* If it's a no-access ACL, all mechanisms should be blocked */
		if( certMgmtACL->access == ACTION_PERM_NONE )
			{
			ENSURES( paramInfo( certMgmtACL, 0 ).valueType == PARAM_VALUE_NONE );
			continue;
			}

		/* If it's an internal-only ACL, it always needs a request
		   parameter */
		if( certMgmtACL->access == ACTION_PERM_NONE_EXTERNAL )
			{
			if( paramInfo( certMgmtACL, 1 ).valueType != PARAM_VALUE_OBJECT || \
				( paramInfo( certMgmtACL, 1 ).subTypeA & \
					~( ST_CERT_CERTREQ | ST_CERT_REQ_CERT | \
					   ST_CERT_REQ_REV | ST_CERT_CERT ) ) || \
				paramInfo( certMgmtACL, 1 ).subTypeB != ST_NONE )
				{
				DEBUG_DIAG(( "Certificate management ACLs inconsistent" ));
				retIntError();
				}
			}

		/* If it requires a CA key parameter, it must be a private-key
		   context with the key loaded and an attached CA certificate */
		if( paramInfo( certMgmtACL, 0 ).valueType == PARAM_VALUE_OBJECT )
			{
			ENSURES( paramInfo( certMgmtACL, 0 ).subTypeA == ST_CTX_PKC && \
					 paramInfo( certMgmtACL, 0 ).subTypeB == ST_NONE && \
					 paramInfo( certMgmtACL, 0 ).flags == ACL_FLAG_HIGH_STATE );
			if( ( secParamInfo( certMgmtACL, 0 ).subTypeA & \
					~( ST_CERT_CERT | ST_CERT_CERTCHAIN ) ) || \
				secParamInfo( certMgmtACL, 0 ).subTypeB != ST_NONE || \
				secParamInfo( certMgmtACL, 0 ).flags != ACL_FLAG_HIGH_STATE )
				{
				DEBUG_DIAG(( "Certificate management ACLs inconsistent" ));
				retIntError();
				}
			continue;
			}
		ENSURES( paramInfo( certMgmtACL, 0 ).valueType == PARAM_VALUE_UNUSED );
		}
	ENSURES( i < FAILSAFE_ARRAYSIZE( certMgmtACLTbl, CERTMGMT_ACL ) );

	/* Set up the reference to the kernel data block */
	krnlData = krnlDataPtr;

	return( CRYPT_OK );
	}
コード例 #5
0
ファイル: pkcs11_init.c プロジェクト: ryankurte/cryptlib
static int loadPKCS11driver( PKCS11_DRIVER_INFO *pkcs11Info,
							 const char *driverName )
	{
	CK_C_GetFunctionList pC_GetFunctionList;
	CK_INFO info DUMMY_INIT_STRUCT;
	CK_RV status;
#ifdef __WIN16__
	UINT errorMode;
#endif /* __WIN16__ */
	BOOLEAN isInitialised = FALSE;
	int i = 32;

	assert( isWritePtr( pkcs11Info, sizeof( PKCS11_DRIVER_INFO ) ) );
	assert( isReadPtr( driverName, 4 ) );

	/* Obtain a handle to the device driver module */
#ifdef __WIN16__
	errorMode = SetErrorMode( SEM_NOOPENFILEERRORBOX );
	pkcs11Info->hPKCS11 = LoadLibrary( driverName );
	SetErrorMode( errorMode );
	if( pkcs11Info->hPKCS11 < HINSTANCE_ERROR )
		{
		pkcs11Info->hPKCS11 = NULL_HINSTANCE;
		return( CRYPT_ERROR );
		}
#else
	if( ( pkcs11Info->hPKCS11 = DynamicLoad( driverName ) ) == NULL_INSTANCE )
		return( CRYPT_ERROR );
#endif /* OS-specific dynamic load */

	/* Get the access information for the PKCS #11 library, initialise it, 
	   and get information on the device.  There are four types of PKCS #11 
	   driver around: v1, v1-like claiming to be v2, v2-like claiming to be 
	   v1, and v2.  cryptlib can in theory handle all of these, however 
	   there are some problem areas with v1 (for example v1 uses 16-bit 
	   values while v2 uses 32-bit ones, this is usually OK because data is 
	   passed around as 32-bit values with the high bits zeroed but some 
	   implementations may leave garbage in the high 16 bits that leads to 
	   all sorts of confusion).  Because of this we explicitly fail if 
	   something claims to be v1 even though it might work in practice */
	pC_GetFunctionList = ( CK_C_GetFunctionList ) \
				DynamicBind( pkcs11Info->hPKCS11, "C_GetFunctionList" );
	if( pC_GetFunctionList == NULL )
		status = CKR_GENERAL_ERROR;
	else
		{
		CK_FUNCTION_LIST_PTR functionListPtr;

		/* The following two-step initialisation is needed because PKCS #11 
		   uses a 1-byte alignment on structs, which means that if we pass
		   in the pkcs11Info member address directly we run into alignment
		   problems with 64-bit architectures */
		status = pC_GetFunctionList( &functionListPtr ) & 0xFFFF;
		if( status == CKR_OK )
			pkcs11Info->functionListPtr = functionListPtr;
		}
	if( status != CKR_OK )
		{
		/* Free the library reference and clear the information */
		DynamicUnload( pkcs11Info->hPKCS11 );
		memset( pkcs11Info, 0, sizeof( PKCS11_DRIVER_INFO ) );
		return( CRYPT_ERROR );
		}
	status = C_Initialize( NULL_PTR ) & 0xFFFF;
	if( status == CKR_ARGUMENTS_BAD && \
		strFindStr( driverName, strlen( driverName ), "softokn3.", 9 ) >= 0 )
		{
		typedef struct CK_C_INITIALIZE_ARGS {
			CK_CREATEMUTEX CreateMutex;
			CK_DESTROYMUTEX DestroyMutex;
			CK_LOCKMUTEX LockMutex;
			CK_UNLOCKMUTEX UnlockMutex;
			CK_FLAGS flags;
			CK_VOID_PTR LibraryParameters;
			CK_VOID_PTR pReserved;
			} Netscape_CK_C_INITIALIZE_ARGS;
		Netscape_CK_C_INITIALIZE_ARGS initArgs;

		/* Netscape invented their own extension to CK_C_INITIALIZE_ARGS, 
		   adding a 'LibraryParameters' string to allow the specification of 
		   free-form parameters.  If the Netscape library's C_Initialize()
		   is called then it'll return CKR_ARGUMENTS_BAD (rather than 
		   assuming sensible default values), so that we have to call it 
		   again with explicitly-specified parameters.

		   Even this doesn't work properly though, according to the Netscape 
		   docs we can set LibraryParameters to NULL, but this still results 
		   in C_Initialize() returning CKR_ARGUMENTS_BAD.  Later in the docs
		   is a requirement that the softokn3 library be passed a 
		   "parameters=" string, but it's unclear what parameters need to be 
		   set, to what values, and what effect these values may have on the
		   behaviour of existing configs for applications like Firefox.  The
		   following config lets the C_Initialize() call succeed but causes
		   odd failures later in other PKCS #11 functions */
		DEBUG_DIAG(( "Driver is the buggy Netscape/NSS one that requires "
					 "nonstandard initialisation, see the code comment for "
					 "details" ));
		assert( DEBUG_WARN );
		memset( &initArgs, 0, sizeof( Netscape_CK_C_INITIALIZE_ARGS ) );
		initArgs.LibraryParameters = \
			"configdir='.' certPrefix='' keyPrefix='' secmod='secmod.db' "
			"flags=noModDB,noCertDB,noKeyDB,optimizeSpace,readOnly";
		status = C_Initialize( &initArgs );
		}
	if( status == CKR_OK || status == CKR_CRYPTOKI_ALREADY_INITIALIZED )
		{
		isInitialised = TRUE;
		status = C_GetInfo( &info ) & 0xFFFF;
		if( status == CKR_OK && info.cryptokiVersion.major <= 1 )
			{
			/* It's v1, we can't work with it */
			status = CKR_FUNCTION_NOT_SUPPORTED;
			}
		}
	if( status != CKR_OK )
		{
		if( isInitialised )
			C_Finalize( NULL_PTR );
		DynamicUnload( pkcs11Info->hPKCS11 );
		memset( pkcs11Info, 0, sizeof( PKCS11_DRIVER_INFO ) );
		return( CRYPT_ERROR );
		}

	/* Copy out the device driver's name so that the user can access it by 
	   name.  Some vendors erroneously null-terminate the string so we check 
	   for nulls as well */
	memcpy( pkcs11Info->name, info.libraryDescription, 32 );
	while( i > 0 && ( pkcs11Info->name[ i - 1 ] == ' ' || \
					  !pkcs11Info->name[ i - 1 ] ) )
		i--;
	pkcs11Info->name[ i ] = '\0';

	return( CRYPT_OK );
	}
コード例 #6
0
ファイル: pkcs11_init.c プロジェクト: ryankurte/cryptlib
static int initFunction( DEVICE_INFO *deviceInfo, const char *name,
						 const int nameLength )
	{
	CK_SESSION_HANDLE hSession;
	CK_SLOT_ID slotList[ MAX_PKCS11_SLOTS + 8 ];
	CK_ULONG slotCount = MAX_PKCS11_SLOTS;
	CK_SLOT_INFO slotInfo;
	CK_TOKEN_INFO tokenInfo;
	CK_RV status;
	PKCS11_INFO *pkcs11Info = deviceInfo->devicePKCS11;
	const PKCS11_MECHANISM_INFO *mechanismInfoPtr;
	char *labelPtr;
	int tokenSlot = DEFAULT_SLOT, i, labelLength, mechanismInfoSize;
	int cryptStatus, cryptStatus2;

	assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) );
	assert( isReadPtr( name, nameLength ) );

	/* Get information on all available slots */
	memset( slotList, 0, sizeof( slotList ) );
	status = C_GetSlotList( TRUE, slotList, &slotCount );
	if( status != CKR_OK )
		return( pkcs11MapError( status, CRYPT_ERROR_OPEN ) );
	if( slotCount <= 0 )
		{
		/* There are token slots present but no tokens in the slots */
		return( CRYPT_ERROR_OPEN );
		}

	/* Check whether a token name (used to select the slot) has been 
	   specified */
	for( i = 1; i < nameLength - 1; i++ )
		{
		if( name[ i ] == ':' && name[ i + 1 ] == ':' )
			break;
		}
	if( i < nameLength - 1 )
		{
		const char *tokenName = name + i + 2;	/* Skip '::' */
		const int tokenNameLength = nameLength - ( i + 2 );

		if( tokenNameLength <= 0 )
			return( CRYPT_ARGERROR_STR1 );

		/* Some tokens don't implement named slots, so we also allow them to 
		   be specified using slot counts */
		if( tokenNameLength == 1 && isDigit( *tokenName ) )
			{
			tokenSlot = *tokenName - '0';
			if( tokenSlot < 0 || tokenSlot > 9 )
				return( CRYPT_ARGERROR_STR1 );
			if( tokenSlot > slotCount - 1 )	/* Slots numbered from zero */
				return( CRYPT_ERROR_NOTFOUND );
			status = C_GetTokenInfo( slotList[ tokenSlot ], &tokenInfo );
			if( status != CKR_OK )
				return( CRYPT_ERROR_NOTFOUND );
			}
		else
			{
			/* Check each (named) slot for a token matching the given name */
			for( tokenSlot = 0; tokenSlot < slotCount && \
								tokenSlot < FAILSAFE_ITERATIONS_MED; 
				 tokenSlot++ )
				{
				status = C_GetTokenInfo( slotList[ tokenSlot ], &tokenInfo );
				if( status == CKR_OK && \
					!strCompare( tokenName, tokenInfo.label, tokenNameLength ) )
					break;
				}
			ENSURES( tokenSlot < FAILSAFE_ITERATIONS_MED );
			if( tokenSlot >= slotCount )
				return( CRYPT_ERROR_NOTFOUND );
			}
		}
	pkcs11Info->slotID = slotList[ tokenSlot ];

	/* Get information on device-specific capabilities */
	status = C_GetSlotInfo( pkcs11Info->slotID, &slotInfo );
	if( status != CKR_OK )
		{
		shutdownFunction( deviceInfo );
		return( pkcs11MapError( status, CRYPT_ERROR_OPEN ) );
		}
	if( slotInfo.flags & CKF_REMOVABLE_DEVICE )
		{
		/* The device is removable */
		deviceInfo->flags |= DEVICE_REMOVABLE;
		}
	status = C_GetTokenInfo( pkcs11Info->slotID, &tokenInfo );
	if( status != CKR_OK )
		{
		shutdownFunction( deviceInfo );
		return( pkcs11MapError( status, CRYPT_ERROR_OPEN ) );
		}
	if( tokenInfo.flags & CKF_RNG )
		{
		/* The device has an onboard RNG that we can use */
		deviceInfo->getRandomFunction = getRandomFunction;
		}
#if 0	/* The Spyrus driver for pre-Lynks-II cards returns the local system 
		   time (with a GMT/localtime offset), ignoring the fact that the 
		   token has an onboard clock, so having the CKF_CLOCK_ON_TOKEN not 
		   set is accurate, although having it ignore the presence of the 
		   clock isn't very valid */
	if( !( tokenInfo.flags & CKF_CLOCK_ON_TOKEN ) && \
		( !strCompare( tokenInfo.label, "Lynks Token", 11 ) || \
		  !strCompare( tokenInfo.model, "Rosetta", 7 ) ) )
		{
		/* Fix buggy Spyrus PKCS #11 drivers which claim that the token
		   doesn't have a RTC even though it does (the Rosetta (smart card) 
		   form of the token is even worse, it returns garbage in the label 
		   and manufacturer fields, but the model field is OK).  There is a 
		   chance that there's a genuine problem with the clock (there are 
		   batches of tokens with bad clocks) but the time check that  
		   follows below will catch those */
		tokenInfo.flags |= CKF_CLOCK_ON_TOKEN;
		}
#endif /* 0 */
	if( tokenInfo.flags & CKF_CLOCK_ON_TOKEN )
		{
		const time_t theTime = getTokenTime( &tokenInfo );
		const time_t currentTime = getTime();

		/* The token claims to have an onboard clock that we can use.  Since
		   this could be arbitrarily inaccurate we compare it with the 
		   system time and only rely on it if it's within +/- 1 day of the
		   system time.
		   
		   There is a second check that we should make to catch drivers that
		   claim to read the time from the token but actually use the local
		   computer's time, but this isn't easy to do.  The most obvious way
		   is to set the system time to a bogus value and check whether this
		   matches the returned time, but this is somewhat drastic and 
		   requires superuser privs on most systems.  An alternative is to 
		   check whether the claimed token time exactly matches the system 
		   time, but this will produce false positives if (for example) the
		   token has been recently synchronised to the system time.  For now
		   all we can do is throw an exception if it appears that the token
		   time is faked */
		if( theTime > MIN_TIME_VALUE && \
			theTime >= currentTime - 86400 && \
			theTime <= currentTime + 86400 )
			deviceInfo->flags |= DEVICE_TIME;

		/* If this check is triggered then the token time may be faked since 
		   it's identical to the host system time, see the comment above for 
		   details.  We make an exception for soft-tokens (if we can detect 
		   them), which will (by definition) have the same time as the 
		   system time */
		if( !( pkcs11InfoTbl[ pkcs11Info->deviceNo ].name[ 0 ] && \
			   !strCompare( pkcs11InfoTbl[ pkcs11Info->deviceNo ].name, 
							"Software", 8 ) ) && \
			theTime == currentTime )
			{
			DEBUG_DIAG(( "PKCS #11 token time is the same as the host "
						 "system time, token time may be faked by the "
						 "driver." ));
			assert( DEBUG_WARN );
			}
		}
	if( tokenInfo.flags & CKF_WRITE_PROTECTED )
		{
		/* The device can't have data on it changed */
		deviceInfo->flags |= DEVICE_READONLY;
		}
	if( ( tokenInfo.flags & CKF_LOGIN_REQUIRED ) || \
		!( tokenInfo.flags & CKF_USER_PIN_INITIALIZED ) )
		{
		/* The user needs to log in before using various device functions.
		   We check for the absence of CKF_USER_PIN_INITIALIZED as well as 
		   the more obvious CKF_LOGIN_REQUIRED because if we've got an 
		   uninitialised device there's no PIN set so some devices will 
		   report that there's no login required (or at least none is 
		   possible).  We need to introduce some sort of pipeline stall if 
		   this is the case because otherwise the user could successfully 
		   perform some functions that don't require a login (where the 
		   exact details of what's allowed without a login are device-
		   specific) before running into mysterious failures when they get 
		   to functions that do require a login.  To avoid this, we make an 
		   uninitialised device look like a login-required device, so the 
		   user gets an invalid-PIN error if they try and proceed */
		deviceInfo->flags |= DEVICE_NEEDSLOGIN;
		}
	if( ( pkcs11Info->minPinSize = ( int ) tokenInfo.ulMinPinLen ) < 4 )
		{
		/* Some devices report silly PIN sizes */
		DEBUG_DIAG(( "Driver reports suspicious minimum PIN size %lu, "
					 "using 4", tokenInfo.ulMinPinLen ));
		pkcs11Info->minPinSize = 4;
		}
	if( ( pkcs11Info->maxPinSize = ( int ) tokenInfo.ulMaxPinLen ) < 4 )
		{
		/* Some devices report silly PIN sizes (setting this to ULONG_MAX or
		   4GB, which becomes -1 as an int, counts as silly).  Since we can't
		   differentiate between 0xFFFFFFFF = bogus value and 0xFFFFFFFF = 
		   ULONG_MAX we play it safe and set the limit to 8 bytes, which most
		   devices should be able to handle */
		DEBUG_DIAG(( "Driver reports suspicious maximum PIN size %lu, "
					 "using 8", tokenInfo.ulMinPinLen ));
		pkcs11Info->maxPinSize = 8;
		}
	labelPtr = ( char * ) tokenInfo.label;
	for( labelLength = 32;
		 labelLength > 0 && \
		 ( labelPtr[ labelLength - 1 ] == ' ' || \
		   !labelPtr[ labelLength - 1 ] ); 
		  labelLength-- );	/* Strip trailing blanks/nulls */
	while( labelLength > 0 && *labelPtr == ' ' )
		{
		/* Strip leading blanks */
		labelPtr++;
		labelLength--;
		}
	if( labelLength > 0 )
		{
		memcpy( pkcs11Info->label, labelPtr, labelLength );
		pkcs11Info->labelLen = labelLength;
		sanitiseString( pkcs11Info->label, CRYPT_MAX_TEXTSIZE, 
						labelLength );
		}
	else
		{
		/* There's no label for the token, use the device label instead */
		if( pkcs11InfoTbl[ pkcs11Info->deviceNo ].name[ 0 ] )
			{
			labelLength = \
				min( strlen( pkcs11InfoTbl[ pkcs11Info->deviceNo ].name ),
					 CRYPT_MAX_TEXTSIZE );
			memcpy( pkcs11Info->label, 
					pkcs11InfoTbl[ pkcs11Info->deviceNo ].name, labelLength );
			}
		}
	pkcs11Info->hActiveSignObject = CK_OBJECT_NONE;
	deviceInfo->label = pkcs11Info->label;
	deviceInfo->labelLen = pkcs11Info->labelLen;

	/* Open a session with the device.  This gets a bit awkward because we 
	   can't tell whether a R/W session is OK without opening a session, but 
	   we can't open a session unless we know whether a R/W session is OK, 
	   so we first try for a RW session and if that fails we go for a read-
	   only session */
	status = C_OpenSession( pkcs11Info->slotID, 
							CKF_RW_SESSION | CKF_SERIAL_SESSION, NULL_PTR, 
							NULL_PTR, &hSession );
	if( status == CKR_TOKEN_WRITE_PROTECTED )
		{
		status = C_OpenSession( pkcs11Info->slotID, 
								CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, 
								&hSession );
		}
	if( status != CKR_OK )
		{
		cryptStatus = pkcs11MapError( status, CRYPT_ERROR_OPEN );
		if( cryptStatus == CRYPT_ERROR_OPEN && \
			!( tokenInfo.flags & CKF_USER_PIN_INITIALIZED ) )
			{
			/* We couldn't do much with the error code, it could be that the
			   token hasn't been initialised yet but unfortunately PKCS #11 
			   doesn't define an error code for this condition.  In addition
			   many tokens will allow a session to be opened and then fail 
			   with a "PIN not set" error at a later point (which allows for
			   more accurate error reporting), however a small number won't
			   allow a session to be opened and return some odd-looking error
			   because there's nothing useful available.  The best way to
			   report this in a meaningful manner to the caller is to check
			   whether the user PIN has been initialised, if it hasn't then 
			   it's likely that the token as a whole hasn't been initialised 
			   so we return a not initialised error */
			cryptStatus = CRYPT_ERROR_NOTINITED;
			}
		return( cryptStatus );
		}
	ENSURES( hSession != CK_OBJECT_NONE );
	pkcs11Info->hSession = hSession;
	deviceInfo->flags |= DEVICE_ACTIVE;

	/* Set up the capability information for this device.  Since there can 
	   be devices that have one set of capabilities but not the other (e.g.
	   a smart card that only performs RSA ops), we allow one of the two
	   sets of mechanism information setups to fail, but not both */
	mechanismInfoPtr = getMechanismInfoPKC( &mechanismInfoSize );
	cryptStatus = getCapabilities( deviceInfo, mechanismInfoPtr, 
								   mechanismInfoSize );
	mechanismInfoPtr = getMechanismInfoConv( &mechanismInfoSize );
	cryptStatus2 = getCapabilities( deviceInfo, mechanismInfoPtr, 
									mechanismInfoSize );
	if( cryptStatusError( cryptStatus ) && cryptStatusError( cryptStatus2 ) )
		{
		shutdownFunction( deviceInfo );
		return( ( cryptStatus == CRYPT_ERROR ) ? \
				CRYPT_ERROR_OPEN : ( int ) cryptStatus );
		}

	return( CRYPT_OK );
	}
コード例 #7
0
ファイル: pkcs11_init.c プロジェクト: ryankurte/cryptlib
static CAPABILITY_INFO *getCapability( const DEVICE_INFO *deviceInfo,
									   const PKCS11_MECHANISM_INFO *mechanismInfoPtr,
									   const int maxMechanisms )
	{
	VARIABLE_CAPABILITY_INFO *capabilityInfo;
	CK_MECHANISM_INFO pMechanism;
	CK_RV status;
	const CRYPT_ALGO_TYPE cryptAlgo = mechanismInfoPtr->cryptAlgo;
	const BOOLEAN isPKC = isPkcAlgo( cryptAlgo ) ? TRUE : FALSE;
	const CK_FLAGS keyGenFlag = isPKC ? CKF_GENERATE_KEY_PAIR : CKF_GENERATE;
	PKCS11_INFO *pkcs11Info = deviceInfo->devicePKCS11;
	int hardwareOnly, i, iterationCount;

	assert( isReadPtr( deviceInfo, sizeof( DEVICE_INFO ) ) );
	assert( isReadPtr( mechanismInfoPtr, \
					   maxMechanisms * sizeof( PKCS11_MECHANISM_INFO ) ) );

	/* Set up canary values for the mechanism information in case the driver
	   blindly reports success for every mechanism that we ask for */
	memset( &pMechanism, 0, sizeof( CK_MECHANISM_INFO ) );
	pMechanism.ulMinKeySize = 0xA5A5;
	pMechanism.ulMaxKeySize = 0x5A5A;

	/* Get the information for this mechanism.  Since many PKCS #11 drivers
	   implement some of their capabilities using God knows what sort of 
	   software implementation, we provide the option to skip emulated 
	   mechanisms if required */
	status = C_GetMechanismInfo( pkcs11Info->slotID, 
								 mechanismInfoPtr->mechanism,
								 &pMechanism );
	if( status != CKR_OK )
		return( NULL );
	if( pMechanism.ulMinKeySize == 0xA5A5 && \
		pMechanism.ulMaxKeySize == 0x5A5A )
		{
		/* The driver reported that this mechanism is available but didn't
		   update the mechanism information, it's lying */
		DEBUG_DIAG(( "Driver reports that mechanism %X is available even "
					 "though it isn't", mechanismInfoPtr->mechanism ));
		assert( DEBUG_WARN );
		return( NULL );
		}
	status = krnlSendMessage( deviceInfo->ownerHandle, IMESSAGE_GETATTRIBUTE, 
							  &hardwareOnly, 
							  CRYPT_OPTION_DEVICE_PKCS11_HARDWAREONLY );
	if( cryptStatusOK( status ) && hardwareOnly && \
		!( pMechanism.flags & CKF_HW ) )
		{
		DEBUG_DIAG(( "Skipping mechanism %X, which is only available in "
					 "software emulation", mechanismInfoPtr->mechanism ));
		return( NULL );
		}
	if( mechanismInfoPtr->requiredFlags != CKF_NONE )
		{
		/* Make sure that the driver flags indicate support for the specific 
		   functionality that we require */
		if( ( mechanismInfoPtr->requiredFlags & \
			  pMechanism.flags ) != mechanismInfoPtr->requiredFlags )
			{
			DEBUG_DIAG(( "Driver reports that mechanism %X only has "
						 "capabilities %lX when we require %lX", 
						 mechanismInfoPtr->mechanism, 
						 mechanismInfoPtr->requiredFlags & pMechanism.flags,
						 mechanismInfoPtr->requiredFlags ));
//////////////////////////////////
// Kludge to allow it to be used
//////////////////////////////////
//			assert( DEBUG_WARN );
//			return( NULL );
			}
		}

	/* Copy across the template for this capability */
	if( ( capabilityInfo = clAlloc( "getCapability", \
									sizeof( CAPABILITY_INFO ) ) ) == NULL )
		return( NULL );
	for( i = 0; capabilityTemplates[ i ].cryptAlgo != cryptAlgo && \
				capabilityTemplates[ i ].cryptAlgo != CRYPT_ERROR && \
				i < FAILSAFE_ARRAYSIZE( capabilityTemplates, CAPABILITY_INFO ); 
		 i++ );
	ENSURES_N( i < FAILSAFE_ARRAYSIZE( capabilityTemplates, CAPABILITY_INFO ) );
	ENSURES_N( capabilityTemplates[ i ].cryptAlgo != CRYPT_ERROR );
	memcpy( capabilityInfo, &capabilityTemplates[ i ],
			sizeof( CAPABILITY_INFO ) );

	/* Set up the keysize information if there's anything useful available */
	if( keysizeValid( cryptAlgo ) )
		{
		int minKeySize = ( int ) pMechanism.ulMinKeySize;
		int maxKeySize = ( int ) pMechanism.ulMaxKeySize;

		/* Adjust the key size to bytes and make sure that all values are 
		   consistent.  Some implementations report silly bounds (e.g. 1-bit 
		   RSA, "You naughty minKey" or alternatively 4Gbit RSA) so we 
		   adjust them to a sane value if necessary.  We also limit the 
		   maximum key size to match the cryptlib native maximum key size, 
		   both for consistency and because cryptlib performs buffer 
		   allocation based on the maximum native buffer size */
		if( pMechanism.ulMinKeySize < 0 || \
			pMechanism.ulMinKeySize >= 10000L )
			{
			DEBUG_DIAG(( "Driver reports invalid minimum key size %lu for "
						 "%s algorithm", pMechanism.ulMinKeySize,
						 capabilityInfo->algoName ));
			assert( DEBUG_WARN );
			minKeySize = 0;
			}
		if( pMechanism.ulMaxKeySize < 0 || \
			pMechanism.ulMaxKeySize >= 100000L )
			{
			DEBUG_DIAG(( "Driver reports invalid maximum key size %lu for "
						 "%s algorithm", pMechanism.ulMaxKeySize,
						 capabilityInfo->algoName ));
			assert( DEBUG_WARN );
			maxKeySize = 0;
			}
		if( !keysizeInBytes( cryptAlgo ) )
			{
			minKeySize = bitsToBytes( minKeySize );
			maxKeySize = bitsToBytes( maxKeySize );
			}
		if( minKeySize > capabilityInfo->minKeySize )
			capabilityInfo->minKeySize = minKeySize;
		if( capabilityInfo->keySize < capabilityInfo->minKeySize )
			capabilityInfo->keySize = capabilityInfo->minKeySize;
		capabilityInfo->maxKeySize = min( maxKeySize, 
										  capabilityInfo->maxKeySize );
		if( capabilityInfo->maxKeySize < capabilityInfo->minKeySize )
			{
			/* Serious braindamage in the driver, we'll just have to make
			   a sensible guess */
			DEBUG_DIAG(( "Driver reports maximum key size %d < minimum key "
						 "size %d for %s algorithm", 
						 capabilityInfo->maxKeySize, 
						 capabilityInfo->minKeySize, 
						 capabilityInfo->algoName ));
			assert( DEBUG_WARN );
			if( isPKC )
				{
				capabilityInfo->maxKeySize = \
					max( capabilityInfo->minKeySize, bitsToBytes( 2048 ) );
				}
			else
				capabilityInfo->maxKeySize = 16;
			}
		if( capabilityInfo->keySize > capabilityInfo->maxKeySize )
			capabilityInfo->keySize = capabilityInfo->maxKeySize;
		capabilityInfo->endFunction = genericEndFunction;
		}

	/* Set up the device-specific handlers */
	capabilityInfo->selfTestFunction = selfTestFunction;
	capabilityInfo->getInfoFunction = getDefaultInfo;
	if( !isPKC )
		capabilityInfo->initParamsFunction = initGenericParams;
	capabilityInfo->endFunction = mechanismInfoPtr->endFunction;
	capabilityInfo->initKeyFunction = mechanismInfoPtr->initKeyFunction;
	if( pMechanism.flags & keyGenFlag )
		capabilityInfo->generateKeyFunction = \
									mechanismInfoPtr->generateKeyFunction;
	if( pMechanism.flags & CKF_SIGN )
		{
		/* cryptlib treats hashing as an encrypt/decrypt operation while 
		   PKCS #11 treats it as a sign/verify operation, so we have to
		   juggle the function pointers based on the underlying algorithm
		   type */
		if( isPKC )
			capabilityInfo->signFunction = mechanismInfoPtr->signFunction;
		else
			capabilityInfo->encryptFunction = mechanismInfoPtr->encryptFunction;
		}
	if( pMechanism.flags & CKF_VERIFY )
		{
		/* See comment above */
		if( isPKC )
			capabilityInfo->sigCheckFunction = mechanismInfoPtr->sigCheckFunction;
		else
			capabilityInfo->decryptFunction = mechanismInfoPtr->decryptFunction;
		}
	if( pMechanism.flags & CKF_ENCRYPT )
		{
		/* Not all devices implement all modes, so we have to be careful to 
		   set up the pointer for the exact mode that's supported */
		switch( mechanismInfoPtr->cryptMode )
			{
			case CRYPT_MODE_CBC:
				capabilityInfo->encryptCBCFunction = mechanismInfoPtr->encryptFunction;
				break;

			case CRYPT_MODE_CFB:
				capabilityInfo->encryptCFBFunction = mechanismInfoPtr->encryptFunction;
				break;

			case CRYPT_MODE_GCM:
				capabilityInfo->encryptGCMFunction = mechanismInfoPtr->encryptFunction;
				break;

			default:	/* ECB or a PKC */
				capabilityInfo->encryptFunction = mechanismInfoPtr->encryptFunction;
				break;
			}
		}
	if( pMechanism.flags & CKF_DECRYPT )
		{
		/* Not all devices implement all modes, so we have to be careful to 
		   set up the pointer for the exact mode that's supported */
		switch( mechanismInfoPtr->cryptMode )
			{
			case CRYPT_MODE_CBC:
				capabilityInfo->decryptCBCFunction = mechanismInfoPtr->decryptFunction;
				break;

			case CRYPT_MODE_CFB:
				capabilityInfo->decryptCFBFunction = mechanismInfoPtr->decryptFunction;
				break;

			case CRYPT_MODE_GCM:
				capabilityInfo->decryptGCMFunction = mechanismInfoPtr->decryptFunction;
				break;

			default:	/* ECB or a PKC */
				capabilityInfo->decryptFunction = mechanismInfoPtr->decryptFunction;
				break;
			}
		}
	if( cryptAlgo == CRYPT_ALGO_DH && pMechanism.flags & CKF_DERIVE )
		{
		/* DH is a special-case that doesn't really have an encrypt function 
		   and where "decryption" is actually a derivation */
		capabilityInfo->encryptFunction = mechanismInfoPtr->encryptFunction;
		capabilityInfo->decryptFunction = mechanismInfoPtr->decryptFunction;
		}

	/* Keygen capabilities are generally present as separate mechanisms,
	   sometimes CKF_GENERATE/CKF_GENERATE_KEY_PAIR is set for the main 
	   mechanism and sometimes it's set for the separate one so if it isn't 
	   present in the main one we check the alternative one */
	if( !( pMechanism.flags & keyGenFlag ) && \
		( mechanismInfoPtr->keygenMechanism != CKM_NONE ) )
		{
		status = C_GetMechanismInfo( pkcs11Info->slotID, 
									 mechanismInfoPtr->keygenMechanism,
									 &pMechanism );
		if( status == CKR_OK && ( pMechanism.flags & keyGenFlag ) && \
			( !hardwareOnly || ( pMechanism.flags & CKF_HW ) ) )
			{
			/* Some tinkertoy tokens don't implement key generation in 
			   hardware but instead do it on the host PC (!!!) and load the
			   key into the token afterwards, so we have to perform another 
			   check here to make sure that they're doing things right */
			capabilityInfo->generateKeyFunction = \
									mechanismInfoPtr->generateKeyFunction;
			}
		}

	/* Record mechanism-specific parameters if required */
	if( isConvAlgo( cryptAlgo ) || isMacAlgo( cryptAlgo ) )
		{
		capabilityInfo->paramKeyType = mechanismInfoPtr->keyType;
		capabilityInfo->paramKeyGen = mechanismInfoPtr->keygenMechanism;
		capabilityInfo->paramDefaultMech = mechanismInfoPtr->defaultMechanism;
		}

	/* Some drivers report bizarre combinations of capabilities like (for 
	   RSA) sign, verify, and decrypt but not encrypt, which will fail later 
	   sanity checks.  If we run into one of these we force the capabilities 
	   to be consistent by disabling any for which only partial capabilities
	   are supported */
	if( isPkcAlgo( cryptAlgo ) )
		{
		if( capabilityInfo->decryptFunction != NULL && \
			capabilityInfo->encryptFunction == NULL )
			{
			DEBUG_DIAG(( "Driver reports decryption but not encryption "
						 "capability for %s algorithm, disabling "
						 "encryption", capabilityInfo->algoName ));
			capabilityInfo->decryptFunction = NULL;
			}
		if( capabilityInfo->signFunction != NULL && \
			capabilityInfo->sigCheckFunction == NULL )
			{
			DEBUG_DIAG(( "Driver reports signature-generation but not "
						 "signature-verification capability for %s "
						 "algorithm, disabling signing", 
						 capabilityInfo->algoName ));
//////////////////////////////////
// Kludge to allow it to be used
//////////////////////////////////
if( cryptAlgo == CRYPT_ALGO_ECDSA )
capabilityInfo->sigCheckFunction = capabilityInfo->signFunction;
else
			capabilityInfo->signFunction = NULL;
			}

		/* If we've now disabled all capabilities, we can't use this 
		   algorithm */
		if( capabilityInfo->decryptFunction == NULL && \
			capabilityInfo->signFunction == NULL )
			{
			DEBUG_DIAG(( "Use of algorithm %s disabled since no consistent "
						 "set of capabilities is available", 
						 capabilityInfo->algoName ));
			clFree( "getCapability", capabilityInfo );
			assert( DEBUG_WARN );
			return( NULL );
			}
		}

	/* If it's not a conventional encryption algo, we're done */
	if( !isConvAlgo( cryptAlgo ) )
		return( ( CAPABILITY_INFO * ) capabilityInfo );

	/* PKCS #11 handles encryption modes by defining a separate mechanism for
	   each one.  In order to enumerate all the modes available for a 
	   particular algorithm we check for each mechanism in turn and set up 
	   the appropriate function pointers if it's available */
	for( mechanismInfoPtr++, iterationCount = 0; 
		 mechanismInfoPtr->cryptAlgo == cryptAlgo && \
			iterationCount < maxMechanisms; 
		 mechanismInfoPtr++, iterationCount++ )
		{
		/* There's a different form of the existing mechanism available,
		   check whether the driver implements it */
		status = C_GetMechanismInfo( pkcs11Info->slotID, 
									 mechanismInfoPtr->mechanism,
									 &pMechanism );
		if( status != CKR_OK )
			continue;

		/* Set up the pointer for the appropriate encryption mode */
		switch( mechanismInfoPtr->cryptMode )
			{
			case CRYPT_MODE_CBC:
				if( pMechanism.flags & CKF_ENCRYPT )
					capabilityInfo->encryptCBCFunction = \
										mechanismInfoPtr->encryptFunction;
				if( pMechanism.flags & CKF_DECRYPT )
					capabilityInfo->decryptCBCFunction = \
										mechanismInfoPtr->decryptFunction;
				break;
			case CRYPT_MODE_CFB:
				if( pMechanism.flags & CKF_ENCRYPT )
					capabilityInfo->encryptCFBFunction = \
										mechanismInfoPtr->encryptFunction;
				if( pMechanism.flags & CKF_DECRYPT )
					capabilityInfo->decryptCFBFunction = \
										mechanismInfoPtr->decryptFunction;
				break;
			case CRYPT_MODE_GCM:
				if( pMechanism.flags & CKF_ENCRYPT )
					capabilityInfo->encryptGCMFunction = \
										mechanismInfoPtr->encryptFunction;
				if( pMechanism.flags & CKF_DECRYPT )
					capabilityInfo->decryptGCMFunction = \
										mechanismInfoPtr->decryptFunction;
				break;

			default:
				retIntError_Null();
			}
		}
	ENSURES_N( iterationCount < maxMechanisms );

	return( ( CAPABILITY_INFO * ) capabilityInfo );
	}
コード例 #8
0
ファイル: ssh2_msg.c プロジェクト: UhuruSoftware/bosh-dotnet
int processChannelControlMessage( INOUT SESSION_INFO *sessionInfoPtr,
								  INOUT STREAM *stream )
	{
	SSH_INFO *sshInfo = sessionInfoPtr->sessionSSH;
	const long prevChannelNo = \
				getCurrentChannelNo( sessionInfoPtr, CHANNEL_READ );
	long channelNo;
	int status;

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

	/* See what we've got.  SSH has a whole pile of no-op equivalents that 
	   we have to handle as well as the obvious no-ops.  We can also get 
	   global and channel requests for assorted reasons and a constant 
	   stream of window adjusts to implement the SSH performance handbrake */
	switch( sshInfo->packetType )
		{
		case SSH2_MSG_GLOBAL_REQUEST:
			status = processChannelRequest( sessionInfoPtr, stream,
											CRYPT_UNUSED );
			if( cryptStatusError( status ) && status != OK_SPECIAL )
				return( status );
			return( OK_SPECIAL );

		case SSH2_MSG_CHANNEL_OPEN:
			/* Process the channel-open request.  In theory we could 
			   immediately reject any attempts by the server to open a
			   channel to the client at this point, but unfortunately we
			   have to process a considerable portion of the channel-open
			   request in order to use the information in it to send a
			   request-denied response back to the server */
			status = processChannelOpen( sessionInfoPtr, stream );
			if( cryptStatusError( status ) )
				return( status );

			/* Tell the caller that they have to process the new channel
			   information before they can continue */
			return( CRYPT_ENVELOPE_RESOURCE );

		case SSH2_MSG_IGNORE:
		case SSH2_MSG_DEBUG:
			/* Nothing to see here, move along, move along:

				byte	SSH2_MSG_IGNORE
				string	data

				byte	SSH2_MSG_DEBUG
				boolean	always_display
				string	message
				string	language_tag */
			return( OK_SPECIAL );

		case SSH2_MSG_DISCONNECT:
			/* This only really seems to be used during the handshake phase,
			   once a channel is open it (and the session as a whole) is
			   disconnected with a channel EOF/close, but we handle it here
			   anyway just in case */
			return( getDisconnectInfo( sessionInfoPtr, stream ) );

#ifdef KPYM_HACK
		case SSH2_MSG_KEXDH_INIT/*SSH2_MSG_KEXDH_GEX_REQUEST_OLD*/:
		case SSH2_MSG_KEXDH_GEX_INIT:
		case SSH2_MSG_KEXDH_GEX_REQUEST_NEW:
		case SSH2_MSG_KEXINIT:
		case SSH2_MSG_NEWKEYS:
			{
				int status = ke_DH_ROUTER(sessionInfoPtr, stream, sshInfo->packetType);
				if( status == CRYPT_OK )return( OK_SPECIAL );
				else return status;
			}
#else
		case SSH2_MSG_KEXINIT:
#endif
			/* The SSH spec is extremely vague about the sequencing of
			   operations during a rehandshake.  Unlike SSL there's no real 
			   indication of what happens to the connection-layer transfers 
			   while a transport-layer rehandshake is in progress.  Also 
			   unlike SSL we can't refuse a rehandshake by ignoring the 
			   request, so once we've fallen we can't get up any more.  This 
			   is most obvious with ssh.com's server, which starting with 
			   version 2.3.0 would do a rehandshake every hour (for a basic 
			   encrypted telnet session, while a high-volume IPsec link can 
			   run for hours before it feels the need to do this).  To make 
			   things even messier, neither side can block for too long 
			   waiting for the rehandshake to complete before sending new 
			   data because the lack of WINDOW_ADJUSTs (in an implementation 
			   that sends these with almost every packet, as most do) will 
			   screw up flow control and lead to deadlock.  This problem got 
			   so bad that as of 2.4.0 the ssh.com implementation would 
			   detect OpenSSH (the other main implementation at the time) 
			   and disable the rehandshake when it was talking to it, but it 
			   may not do this for other implementations.

			   To avoid falling into this hole, or at least to fail
			   obviously when the two sides can't agree on how to handle the
			   layering mismatch problem, we report a rehandshake request as
			   an error.  Trying to handle it properly results in hard-to-
			   diagnose errors (it depends on what the layers are doing at
			   the time of the problem), typically some bad-packet error
			   when the other side tries to interpret a connection-layer
			   packet as part of the rehandshake, or when the two sides
			   disagree on when to switch keys and one of the two decrypts 
			   with the wrong keys and gets a garbled packet type */
			retExt( CRYPT_ERROR_BADDATA,
					( CRYPT_ERROR_BADDATA, SESSION_ERRINFO, 
					  "Unexpected KEXINIT request received" ) );

		case SSH2_MSG_CHANNEL_DATA:
		case SSH2_MSG_CHANNEL_EXTENDED_DATA:
		case SSH2_MSG_CHANNEL_REQUEST:
		case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
		case SSH2_MSG_CHANNEL_EOF:
		case SSH2_MSG_CHANNEL_CLOSE:
			/* All channel-specific messages end up here */
			channelNo = readUint32( stream );
			if( cryptStatusError( channelNo ) )
				{
				/* We can't send an error response to a channel request at
				   this point both because we haven't got to the response-
				   required flag yet and because SSH doesn't provide a
				   mechanism for returning an error response without an
				   accompanying channel number.  The best that we can do is
				   to quietly ignore the packet */
				retExt( CRYPT_ERROR_BADDATA,
						( CRYPT_ERROR_BADDATA, SESSION_ERRINFO, 
						  "Invalid channel number in channel-specific packet "
						  "type %d", sshInfo->packetType ) );
				}
			if( channelNo != getCurrentChannelNo( sessionInfoPtr, \
												  CHANNEL_READ ) )
				{
				/* It's a request on something other than the current
				   channel, try and select the new channel */
				status = selectChannel( sessionInfoPtr, channelNo,
										CHANNEL_READ );
				if( cryptStatusError( status ) )
					{
					/* As before for error handling */
					retExt( CRYPT_ERROR_BADDATA,
							( CRYPT_ERROR_BADDATA, SESSION_ERRINFO, 
							  "Invalid channel number %lX in "
							  "channel-specific packet type %d, current "
							  "channel is %lX", channelNo,
							  sshInfo->packetType, prevChannelNo ) );
					}
				}
			break;

		default:
			{
			BYTE buffer[ 16 + 8 ];
			int length;

			/* We got something unexpected, throw an exception in the debug
			   version and let the caller know the details */
			DEBUG_DIAG(( "Unexpected control packet %d", 
						 sshInfo->packetType ));
			assert( DEBUG_WARN );
			status = length = sread( stream, buffer, 8 );
			if( cryptStatusError( status ) || length < 8 )
				{
				/* There's not enough data present to dump the start of the
				   packet, provide a more generic response */
				retExt( CRYPT_ERROR_BADDATA,
						( CRYPT_ERROR_BADDATA, SESSION_ERRINFO, 
						  "Unexpected control packet type %d received",
						  sshInfo->packetType ) );
				}
			retExt( CRYPT_ERROR_BADDATA,
					( CRYPT_ERROR_BADDATA, SESSION_ERRINFO, 
					  "Unexpected control packet type %d received, "
					  "beginning %02X %02X %02X %02X %02X %02X %02X %02X",
					  sshInfo->packetType,
					  buffer[ 0 ], buffer[ 1 ], buffer[ 2 ], buffer[ 3 ],
					  buffer[ 4 ], buffer[ 5 ], buffer[ 6 ], buffer[ 7 ] ) );
			}
		}

	/* From here on we're processing a channel-specific message that applies
	   to the currently selected channel */
	switch( sshInfo->packetType )
		{
		case SSH2_MSG_CHANNEL_DATA:
		case SSH2_MSG_CHANNEL_EXTENDED_DATA:
			{
			int length;

			/* Get the payload length and make sure that it's
			   (approximately) valid, more exact checking has already been
			   done by the caller so we don't need to return extended error
			   information as this is just a backup check */
			status = length = readUint32( stream );
			if( cryptStatusError( status ) || \
				length < 0 || length > sessionInfoPtr->receiveBufSize )
				return( CRYPT_ERROR_BADDATA );

			/* These are messages that consume window space, adjust the data 
			   window and communicate changes to the other side if 
			   necessary */
			status = handleWindowAdjust( sessionInfoPtr, channelNo, length );
			if( cryptStatusError( status ) )
				return( status );

			/* If it's a standard data packet, we're done */
			if( sshInfo->packetType == SSH2_MSG_CHANNEL_DATA )
				return( CRYPT_OK );

			/* The extended data message is used for out-of-band data sent
			   over a channel, specifically output sent to stderr from a
			   shell command.  What to do with this is somewhat uncertain,
			   the only possible action that we could take apart from just
			   ignoring it is to convert it back to in-band data.  However,
			   something running a shell command may not expect to get
			   anything returned in this manner (see the comment for the
			   port-forwarding channel open in the client-side channel-open
			   code for more on this) so for now we just ignore it and 
			   assume that the user will rely on results sent as in-band
			   data.  This should be fairly safe since this message type
			   seems to be rarely (if ever) used, so apps will function
			   without it */
			return( OK_SPECIAL );
			}

		case SSH2_MSG_CHANNEL_REQUEST:
			status = processChannelRequest( sessionInfoPtr, stream,
											prevChannelNo );
			if( cryptStatusError( status ) && status != OK_SPECIAL )
				return( status );
			return( OK_SPECIAL );

		case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
			/* Another noop-equivalent (but a very performance-affecting
			   one) */
			return( OK_SPECIAL );

		case SSH2_MSG_CHANNEL_EOF:
			/* According to the SSH docs the EOF packet is mostly a courtesy
			   notification, however many implementations seem to use a
			   channel EOF in place of a close before sending a disconnect
			   message */
#ifdef KPYM_HACK
#else
			return( OK_SPECIAL );
#endif
		case SSH2_MSG_CHANNEL_CLOSE:
			/* The peer has closed their side of the channel, if our side
			   isn't already closed (in other words if this message isn't
			   a response to a close that we sent), close our side as well */
			if( getChannelStatusByChannelNo( sessionInfoPtr, 
											 channelNo ) == CHANNEL_BOTH )
				{
#ifdef KPYM_HACK
				status = sendChannelClose( sessionInfoPtr, channelNo,
										   CHANNEL_BOTH, TRUE );

				/* We've already closed our side of the channel, delete it */
				status = deleteChannel( sessionInfoPtr, channelNo,
										CHANNEL_BOTH, TRUE );
#else
				status = sendChannelClose( sessionInfoPtr, channelNo,
										   CHANNEL_BOTH, TRUE );
#endif
				}
			else
				{
				/* We've already closed our side of the channel, delete it */
				status = deleteChannel( sessionInfoPtr, channelNo,
										CHANNEL_BOTH, TRUE );
				}

			/* If this wasn't the last channel, we're done */
			if( status != OK_SPECIAL )
				return( OK_SPECIAL );

			/* We've closed the last channel, indicate that the overall
			   connection is now closed.  This behaviour isn't mentioned in
			   the spec but it seems to be the standard way of handling 
			   things, particularly for the most common case where
			   channel == session */
			sessionInfoPtr->flags |= SESSION_SENDCLOSED;
			retExt( CRYPT_ERROR_COMPLETE,
					( CRYPT_ERROR_COMPLETE, SESSION_ERRINFO, 
					  "Remote system closed last remaining SSH channel" ) );
		}

	retIntError();
	}
コード例 #9
0
ファイル: key_acl.c プロジェクト: ryankurte/cryptlib
int initKeymgmtACL( INOUT KERNEL_DATA *krnlDataPtr )
	{
	int i;

	assert( isWritePtr( krnlDataPtr, sizeof( KERNEL_DATA ) ) );

	/* If we're running a fuzzing build, skip the lengthy self-checks */
#ifdef CONFIG_FUZZ
	krnlData = krnlDataPtr;
	return( CRYPT_OK );
#endif /* CONFIG_FUZZ */

	/* Perform a consistency check on the key management ACLs */
	for( i = 0; keyManagementACL[ i ].itemType != KEYMGMT_ITEM_NONE && \
				i < FAILSAFE_ARRAYSIZE( keyManagementACL, KEYMGMT_ACL ); 
		 i++ )
		{
		const KEYMGMT_ACL *keyMgmtACL = &keyManagementACL[ i ];
		int j;

		if( keyMgmtACL->keysetR_subTypeA != ST_NONE || \
			( keyMgmtACL->keysetR_subTypeB & ( SUBTYPE_CLASS_A | \
											   SUBTYPE_CLASS_C ) ) || \
			( keyMgmtACL->keysetR_subTypeB & \
				~( SUBTYPE_CLASS_B | ST_KEYSET_ANY | ST_DEV_P11 | \
									 ST_DEV_CAPI | ST_DEV_HW ) ) != 0 || \
			keyMgmtACL->keysetR_subTypeC != ST_NONE )
			{
			DEBUG_DIAG(( "Key management ACLs inconsistent" ));
			retIntError();
			}

		if( keyMgmtACL->keysetR_subTypeA != ST_NONE || \
			( keyMgmtACL->keysetW_subTypeB & ( SUBTYPE_CLASS_A | \
											   SUBTYPE_CLASS_C ) ) || \
			( keyMgmtACL->keysetW_subTypeB & \
				~( SUBTYPE_CLASS_B | ST_KEYSET_ANY | ST_DEV_P11 | \
									 ST_DEV_CAPI | ST_DEV_HW ) ) != 0 || \
			keyMgmtACL->keysetW_subTypeC != ST_NONE )
			{
			DEBUG_DIAG(( "Key management ACLs inconsistent" ));
			retIntError();
			}

		if( keyMgmtACL->keysetR_subTypeA != ST_NONE || \
			( keyMgmtACL->keysetD_subTypeB & ( SUBTYPE_CLASS_A | \
											   SUBTYPE_CLASS_C ) ) || \
			( keyMgmtACL->keysetD_subTypeB & \
				~( SUBTYPE_CLASS_B | ST_KEYSET_ANY | ST_DEV_P11 | \
									 ST_DEV_CAPI | ST_DEV_HW ) ) != 0 || \
			keyMgmtACL->keysetD_subTypeC != ST_NONE )
			{
			DEBUG_DIAG(( "Key management ACLs inconsistent" ));
			retIntError();
			}

		if( keyMgmtACL->keysetR_subTypeA != ST_NONE || \
			( keyMgmtACL->keysetFN_subTypeB & ( SUBTYPE_CLASS_A | \
											    SUBTYPE_CLASS_C ) ) || \
			( keyMgmtACL->keysetFN_subTypeB & \
				~( SUBTYPE_CLASS_B | ST_KEYSET_ANY | ST_DEV_P11 | \
									 ST_DEV_CAPI | ST_DEV_HW ) ) != 0 || \
			keyMgmtACL->keysetFN_subTypeC != ST_NONE )
			{
			DEBUG_DIAG(( "Key management ACLs inconsistent" ));
			retIntError();
			}

		if( keyMgmtACL->keysetR_subTypeA != ST_NONE || \
			( keyMgmtACL->keysetQ_subTypeB & ( SUBTYPE_CLASS_A | \
											   SUBTYPE_CLASS_C ) ) || \
			( keyMgmtACL->keysetQ_subTypeB & \
				~( SUBTYPE_CLASS_B | ST_KEYSET_ANY ) ) != 0 || \
			keyMgmtACL->keysetQ_subTypeC != ST_NONE )
			{
			DEBUG_DIAG(( "Key management ACLs inconsistent" ));
			retIntError();
			}

		if( ( keyMgmtACL->objSubTypeA & ( SUBTYPE_CLASS_B | \
										  SUBTYPE_CLASS_C ) ) || \
			( keyMgmtACL->objSubTypeA & \
				~( SUBTYPE_CLASS_A | ST_CERT_ANY | ST_CTX_PKC | \
									 ST_CTX_CONV ) ) != 0 || \
			keyMgmtACL->objSubTypeB != ST_NONE || \
			keyMgmtACL->objSubTypeC != ST_NONE )
			{
			DEBUG_DIAG(( "Key management ACLs inconsistent" ));
			retIntError();
			}

		ENSURES( keyMgmtACL->allowedKeyIDs != NULL );
		for( j = 0; keyMgmtACL->allowedKeyIDs[ j ] != CRYPT_KEYID_NONE && \
					j < FAILSAFE_ITERATIONS_SMALL; j++ )
			{
			ENSURES( keyMgmtACL->allowedKeyIDs[ j ] > CRYPT_KEYID_NONE && \
					 keyMgmtACL->allowedKeyIDs[ j ] < CRYPT_KEYID_LAST );
			}
		ENSURES( j < FAILSAFE_ITERATIONS_SMALL );

		ENSURES( keyMgmtACL->allowedFlags >= KEYMGMT_FLAG_NONE && \
				 keyMgmtACL->allowedFlags < KEYMGMT_FLAG_MAX );

		if( keyMgmtACL->specificKeysetSubTypeA != ST_NONE || \
			( keyMgmtACL->specificKeysetSubTypeB & ( SUBTYPE_CLASS_A | \
													 SUBTYPE_CLASS_C ) ) || \
			( keyMgmtACL->specificKeysetSubTypeB & \
				~( SUBTYPE_CLASS_B | ST_KEYSET_ANY | ST_DEV_P11 | \
									 ST_DEV_CAPI ) ) != 0 || \
			keyMgmtACL->specificKeysetSubTypeC != ST_NONE )
			{
			DEBUG_DIAG(( "Key management ACLs inconsistent" ));
			retIntError();
			}

		if( ( keyMgmtACL->specificObjSubTypeA & ( SUBTYPE_CLASS_B | \
												  SUBTYPE_CLASS_C ) ) || \
			( keyMgmtACL->specificObjSubTypeA & \
				~( SUBTYPE_CLASS_A | ST_CERT_ANY ) ) != 0 || \
			keyMgmtACL->specificObjSubTypeB != ST_NONE || \
			keyMgmtACL->specificObjSubTypeC != ST_NONE )
			{
			DEBUG_DIAG(( "Key management ACLs inconsistent" ));
			retIntError();
			}
		}
	ENSURES( i < FAILSAFE_ARRAYSIZE( keyManagementACL, KEYMGMT_ACL ) );

	/* Perform a consistency check on the supplementary ID ACLs */
	for( i = 0; idTypeACL[ i ].idType != CRYPT_KEYID_NONE && \
				i < FAILSAFE_ARRAYSIZE( idTypeACL, IDTYPE_ACL ); 
		 i++ )
		{
		const IDTYPE_ACL *idACL = &idTypeACL[ i ];

		ENSURES( idACL->idType > CRYPT_KEYID_NONE && \
				 idACL->idType < CRYPT_KEYID_LAST );

		if( ( idACL->keysetSubTypeB & \
				~( SUBTYPE_CLASS_B | ST_KEYSET_ANY | ST_DEV_P11 | \
									 ST_DEV_CAPI | ST_DEV_HW ) ) != 0 )
			{
			DEBUG_DIAG(( "Key management supplementary ACLs inconsistent" ));
			retIntError();
			}
		}
	ENSURES( i < FAILSAFE_ARRAYSIZE( idTypeACL, IDTYPE_ACL ) );

	/* Set up the reference to the kernel data block */
	krnlData = krnlDataPtr;

	return( CRYPT_OK );
	}
コード例 #10
0
ファイル: session.c プロジェクト: gitter-badger/OpenCKMS
static int activateConnection( INOUT SESSION_INFO *sessionInfoPtr )
	{
	CRYPT_ATTRIBUTE_TYPE errorAttribute;
	int status;

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );

	/* Make sure that everything is set up ready to go */
	errorAttribute = isServer( sessionInfoPtr ) ? \
					 checkServerParameters( sessionInfoPtr ) : \
					 checkClientParameters( sessionInfoPtr );
	if( errorAttribute != CRYPT_ATTRIBUTE_NONE )
		{
		setErrorInfo( sessionInfoPtr, errorAttribute, 
					  CRYPT_ERRTYPE_ATTR_ABSENT );
		return( CRYPT_ERROR_NOTINITED );
		}
	ENSURES( isServer( sessionInfoPtr ) || \
			 findSessionInfo( sessionInfoPtr->attributeList, 
							  CRYPT_SESSINFO_SERVER_NAME ) != NULL || \
			 sessionInfoPtr->networkSocket != CRYPT_ERROR );
	ENSURES( findSessionInfo( sessionInfoPtr->attributeList,
							  CRYPT_SESSINFO_SERVER_PORT ) != NULL || \
			 sessionInfoPtr->protocolInfo->port > 0 );

	/* Allocate the send and receive buffers if necessary.  The send buffer
	   isn't used for request-response session types that use the receive
	   buffer for both outgoing and incoming data so we only allocate it if
	   it's actually required */
	if( sessionInfoPtr->sendBuffer == NULL )
		{
		REQUIRES( sessionInfoPtr->receiveBufSize >= MIN_BUFFER_SIZE && \
				  sessionInfoPtr->receiveBufSize < MAX_BUFFER_SIZE );
		REQUIRES( ( sessionInfoPtr->sendBufSize >= MIN_BUFFER_SIZE && \
					sessionInfoPtr->sendBufSize < MAX_BUFFER_SIZE ) || \
				  sessionInfoPtr->sendBufSize == CRYPT_UNUSED );

		if( ( sessionInfoPtr->receiveBuffer = \
						clAlloc( "activateConnection", \
								 sessionInfoPtr->receiveBufSize + 8 ) ) == NULL )
			return( CRYPT_ERROR_MEMORY );
		if( sessionInfoPtr->sendBufSize != CRYPT_UNUSED )
			{
			/* When allocating the send buffer we use the size given for the
			   receive buffer since the user may have overridden the default
			   buffer size */
			if( ( sessionInfoPtr->sendBuffer = \
						clAlloc( "activateConnection", \
								 sessionInfoPtr->receiveBufSize + 8 ) ) == NULL )
				{
				clFree( "activateConnection", sessionInfoPtr->receiveBuffer );
				sessionInfoPtr->receiveBuffer = NULL;
				return( CRYPT_ERROR_MEMORY );
				}
			sessionInfoPtr->sendBufSize = sessionInfoPtr->receiveBufSize;
			}
		}
	ENSURES( sessionInfoPtr->receiveBuffer != NULL && \
			 sessionInfoPtr->receiveBufSize >= MIN_BUFFER_SIZE && \
			 sessionInfoPtr->receiveBufSize < MAX_BUFFER_SIZE );
	ENSURES( sessionInfoPtr->sendBufSize == CRYPT_UNUSED || \
			 sessionInfoPtr->sendBuffer != NULL );

	/* Set timeouts if they're not set yet.  If there's an error then we use
	   the default value rather than aborting the entire session because of 
	   a minor difference in timeout values, although we also warn the 
	   caller in debug mode */
	if( sessionInfoPtr->connectTimeout == CRYPT_ERROR )
		{
		int timeout;

		status = krnlSendMessage( sessionInfoPtr->ownerHandle,
								  IMESSAGE_GETATTRIBUTE, &timeout,
								  CRYPT_OPTION_NET_CONNECTTIMEOUT );
		if( cryptStatusOK( status ) )
			sessionInfoPtr->connectTimeout = timeout;
		else
			{
			DEBUG_DIAG(( "Couldn't get connect timeout config value" ));
			assert( DEBUG_WARN );
			sessionInfoPtr->connectTimeout = 30;
			}
		}
	if( sessionInfoPtr->readTimeout == CRYPT_ERROR )
		{
		int timeout;

		status = krnlSendMessage( sessionInfoPtr->ownerHandle,
								  IMESSAGE_GETATTRIBUTE, &timeout,
								  CRYPT_OPTION_NET_READTIMEOUT );
		if( cryptStatusOK( status ) )
			sessionInfoPtr->readTimeout = timeout;
		else
			{
			DEBUG_DIAG(( "Couldn't get read timeout config value" ));
			assert( DEBUG_WARN );
			sessionInfoPtr->readTimeout = 30;
			}
		}
	if( sessionInfoPtr->writeTimeout == CRYPT_ERROR )
		{
		int timeout;

		status = krnlSendMessage( sessionInfoPtr->ownerHandle,
								  IMESSAGE_GETATTRIBUTE, &timeout,
								  CRYPT_OPTION_NET_WRITETIMEOUT );
		if( cryptStatusOK( status ) )
			sessionInfoPtr->writeTimeout = timeout;
		else
			{
			DEBUG_DIAG(( "Couldn't get write timeout config value" ));
			assert( DEBUG_WARN );
			sessionInfoPtr->writeTimeout = 30;
			}
		}

	/* Wait for any async driver binding to complete.  We can delay this
	   until this very late stage because no networking functionality is
	   used until this point */
	if( !krnlWaitSemaphore( SEMAPHORE_DRIVERBIND ) )
		{
		/* The kernel is shutting down, bail out */
		return( CRYPT_ERROR_PERMISSION );
		}

	/* If this is the first time that we've got here, activate the session */
	if( !( sessionInfoPtr->flags & SESSION_PARTIALOPEN ) )
		{
		REQUIRES( !( sessionInfoPtr->flags & SESSION_ISOPEN ) )

		status = sessionInfoPtr->connectFunction( sessionInfoPtr );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* If it's a secure data transport session, complete the session state
	   setup.  Note that some sessions dynamically change the protocol 
	   information during the handshake to accommodate parameters negotiated 
	   during the handshake so we can only access the protocol information 
	   after the handshake has completed */
	if( !sessionInfoPtr->protocolInfo->isReqResp )
		{
		/* Complete the session handshake to set up the secure state */
		status = sessionInfoPtr->transactFunction( sessionInfoPtr );
		if( cryptStatusError( status ) )
			{
			/* If we need feedback from the user before we can complete the 
			   handshake (for example checking a user name and password or 
			   certificate supplied by the other side) we remain in the 
			   handshake state so that the user can re-activate the session 
			   after confirming (or denying) the check */
			if( status == CRYPT_ENVELOPE_RESOURCE )
				sessionInfoPtr->flags |= SESSION_PARTIALOPEN;

			return( status );
			}

		/* Notify the kernel that the session key context is attached to the
		   session object.  Note that we increment its reference count even
		   though it's an internal object used only by the session because
		   otherwise it'll be automatically destroyed by the kernel as a
		   zero-reference dependent object when the session object is
		   destroyed (but before the session object itself since the context 
		   is just a dependent object).  This automatic cleanup could cause 
		   problems for lower-level session management code that tries to 
		   work with the (apparently still-valid) handle, for example 
		   protocols that need to encrypt a close-channel message on session 
		   shutdown */
		krnlSendMessage( sessionInfoPtr->objectHandle, IMESSAGE_SETDEPENDENT,
						 &sessionInfoPtr->iCryptInContext,
						 SETDEP_OPTION_INCREF );

		/* Set up the buffer management variables */
		sessionInfoPtr->receiveBufPos = sessionInfoPtr->receiveBufEnd = 0;
		sessionInfoPtr->sendBufPos = sessionInfoPtr->sendBufStartOfs;

		/* For data transport sessions, partial reads and writes (that is,
		   sending and receiving partial packets in the presence of 
		   timeouts) are permitted */
		sioctlSet( &sessionInfoPtr->stream, STREAM_IOCTL_PARTIALREAD, TRUE );
		sioctlSet( &sessionInfoPtr->stream, STREAM_IOCTL_PARTIALWRITE, TRUE );
		}

	/* The handshake has been completed, switch from the handshake timeout
	   to the data transfer timeout and remember that the session has been
	   successfully established */
	sioctlSet( &sessionInfoPtr->stream, STREAM_IOCTL_HANDSHAKECOMPLETE, TRUE );
	sessionInfoPtr->flags &= ~SESSION_PARTIALOPEN;
	sessionInfoPtr->flags |= SESSION_ISOPEN;

	return( CRYPT_OK );
	}
コード例 #11
0
ファイル: obj_qry.c プロジェクト: TellarHK/wwiv
static int getObjectInfo( INOUT STREAM *stream, 
						  OUT QUERY_INFO *queryInfo )
	{
	const long startPos = stell( stream );
	long value;
	int tag, length, status;

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

	/* Clear return value */
	memset( queryInfo, 0, sizeof( QUERY_INFO ) );

	/* We always need at least MIN_CRYPT_OBJECTSIZE more bytes to do
	   anything */
	if( sMemDataLeft( stream ) < MIN_CRYPT_OBJECTSIZE )
		return( CRYPT_ERROR_UNDERFLOW );

	/* Get the type, length, and version information */
	status = getStreamObjectLength( stream, &length );
	if( cryptStatusError( status ) )
		return( status );
	queryInfo->formatType = CRYPT_FORMAT_CRYPTLIB;
	queryInfo->size = length;
	tag = peekTag( stream );
	if( cryptStatusError( tag ) )
		return( tag );
	readGenericHole( stream, NULL, 16, tag );
	status = readShortInteger( stream, &value );
	if( cryptStatusError( status ) )
		return( status );
	queryInfo->version = value;
	switch( tag )
		{
		case BER_SEQUENCE:
			/* This could be a signature or a PKC-encrypted key, see what
			   follows */
			switch( value )
				{
				case KEYTRANS_VERSION:
				case KEYTRANS_EX_VERSION:
					queryInfo->type = CRYPT_OBJECT_PKCENCRYPTED_KEY;
					break;

				case SIGNATURE_VERSION:
				case SIGNATURE_EX_VERSION:
					queryInfo->type = CRYPT_OBJECT_SIGNATURE;
					break;

				default:
					return( CRYPT_ERROR_BADDATA );
				}
			if( value == KEYTRANS_VERSION || value == SIGNATURE_VERSION )
				queryInfo->formatType = CRYPT_FORMAT_CMS;
			break;

		case MAKE_CTAG( CTAG_RI_KEYAGREE ):
			/* It's CMS' wierd X9.42-inspired key agreement mechanism, we
			   can't do much with this (mind you neither can anyone else)
			   so we should probably really treat it as a 
			   CRYPT_ERROR_BADDATA if we encounter it rather than just 
			   ignoring it */
			queryInfo->type = CRYPT_OBJECT_NONE;
			DEBUG_DIAG(( "Found keyAgreeRecipientInfo" ));
			assert( DEBUG_WARN );
			break;

		case MAKE_CTAG( CTAG_RI_PWRI ):
			queryInfo->type = CRYPT_OBJECT_ENCRYPTED_KEY;
			break;

		default:
			queryInfo->type = CRYPT_OBJECT_NONE;
			if( tag > MAKE_CTAG( CTAG_RI_PWRI ) && \
				tag <= MAKE_CTAG( CTAG_RI_MAX ) )
				{
				/* This is probably a new RecipientInfo type, skip it */
				DEBUG_DIAG(( "Found unknown RecipientInfo %X", tag ));
				assert( DEBUG_WARN );
				break;
				}
			return( CRYPT_ERROR_BADDATA );
		}

	/* Reset the stream and make sure that all of the data is present */
	sseek( stream, startPos );
	return( sMemDataLeft( stream ) < queryInfo->size ? \
			CRYPT_ERROR_UNDERFLOW : CRYPT_OK );
	}
コード例 #12
0
static int readKeyIdentifiers( INOUT STREAM *stream, 
							   INOUT PKCS15_INFO *pkcs15infoPtr,
							   IN_LENGTH const int endPos )
	{
	int iterationCount, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
	
	REQUIRES( endPos > 0 && endPos > stell( stream ) && \
			  endPos < MAX_INTLENGTH );

	for( status = CRYPT_OK, iterationCount = 0;
		 cryptStatusOK( status ) && stell( stream ) < endPos && \
			iterationCount < FAILSAFE_ITERATIONS_MED; iterationCount++ )
		{
		long value;
		int payloadLength;

		/* Read each identifier type and copy the useful ones into the PKCS
		   #15 information */
		readSequence( stream, &payloadLength );
		status = readShortInteger( stream, &value );
		if( cryptStatusError( status ) )
			return( status );
		switch( value )
			{
			case PKCS15_KEYID_ISSUERANDSERIALNUMBER:
				{
				HASHFUNCTION_ATOMIC hashFunctionAtomic;
				void *iAndSPtr = DUMMY_INIT_PTR;
				int iAndSLength, hashSize;

				/* If we've already got the iAndSID, use that version 
				   instead */
				if( pkcs15infoPtr->iAndSIDlength > 0 )
					{
					status = readUniversal( stream );
					continue;
					}

				/* Hash the full issuerAndSerialNumber to get an iAndSID */
				getHashAtomicParameters( CRYPT_ALGO_SHA1, 0,
										 &hashFunctionAtomic, &hashSize );
				status = getStreamObjectLength( stream, &iAndSLength );
				if( cryptStatusOK( status ) )
					status = sMemGetDataBlock( stream, &iAndSPtr, 
											   iAndSLength );
				if( cryptStatusOK( status ) )
					status = sSkip( stream, iAndSLength );
				if( cryptStatusError( status ) )
					return( status );
				hashFunctionAtomic( pkcs15infoPtr->iAndSID, KEYID_SIZE, 
									iAndSPtr, iAndSLength );
				pkcs15infoPtr->iAndSIDlength = hashSize;
				break;
				}

			case PKCS15_KEYID_SUBJECTKEYIDENTIFIER:
				status = readOctetString( stream, pkcs15infoPtr->keyID,
										  &pkcs15infoPtr->keyIDlength, 
										  8, CRYPT_MAX_HASHSIZE );
				break;

			case PKCS15_KEYID_ISSUERANDSERIALNUMBERHASH:
				/* If we've already got the iAndSID by hashing the
				   issuerAndSerialNumber, use that version instead */
				if( pkcs15infoPtr->iAndSIDlength > 0 )
					{
					status = readUniversal( stream );
					continue;
					}
				status = readOctetString( stream, pkcs15infoPtr->iAndSID,
										  &pkcs15infoPtr->iAndSIDlength, 
										  KEYID_SIZE, KEYID_SIZE );
				break;

			case PKCS15_KEYID_ISSUERNAMEHASH:
				status = readOctetString( stream, pkcs15infoPtr->issuerNameID,
										  &pkcs15infoPtr->issuerNameIDlength, 
										  KEYID_SIZE, KEYID_SIZE );
				break;

			case PKCS15_KEYID_SUBJECTNAMEHASH:
				status = readOctetString( stream, pkcs15infoPtr->subjectNameID,
										  &pkcs15infoPtr->subjectNameIDlength, 
										  KEYID_SIZE, KEYID_SIZE );
				break;

			case PKCS15_KEYID_PGP2:
				status = readOctetString( stream, pkcs15infoPtr->pgp2KeyID,
										  &pkcs15infoPtr->pgp2KeyIDlength, 
										  PGP_KEYID_SIZE, PGP_KEYID_SIZE );
				break;

			case PKCS15_KEYID_OPENPGP:
				status = readOctetString( stream, pkcs15infoPtr->openPGPKeyID,
										  &pkcs15infoPtr->openPGPKeyIDlength, 
										  PGP_KEYID_SIZE, PGP_KEYID_SIZE );
				break;

			default:
				status = readUniversal( stream );
			}
		}
	if( iterationCount >= FAILSAFE_ITERATIONS_MED )
		{
		/* This could be either an internal error or some seriously 
		   malformed data, since we can't tell without human intervention
		   we throw a debug exception but otherwise treat it as bad data */
		DEBUG_DIAG(( "Encountered more than %d key IDs", 
					 FAILSAFE_ITERATIONS_MED ));
		assert( DEBUG_WARN );
		return( CRYPT_ERROR_BADDATA );
		}

	return( status );
	}
コード例 #13
0
ファイル: sshl_dh.c プロジェクト: klamonte/qodem
CHECK_RETVAL \
int loadDHcontext( IN_HANDLE const CRYPT_CONTEXT iDHContext, 
				   IN_LENGTH_SHORT_OPT const int requestedKeySize )
	{
	MESSAGE_DATA msgData;
	const void *keyData;
	const int actualKeySize = \
				( requestedKeySize < 128 + 8 ) ? bitsToBytes( 1024 ) : \
				( requestedKeySize < 192 + 8 ) ? bitsToBytes( 1536 ) : \
				( requestedKeySize < 256 + 8 ) ? bitsToBytes( 2048 ) : \
				( requestedKeySize < 384 + 8 ) ? bitsToBytes( 3072 ) : \
				0;
	int keyDataLength, keyDataChecksum;

	REQUIRES( isHandleRangeValid( iDHContext ) );
	REQUIRES( requestedKeySize >= MIN_PKCSIZE && \
			  requestedKeySize <= CRYPT_MAX_PKCSIZE );

	/* Load the built-in DH key value that corresponds best to the client's 
	   requested key size.  We allow for a bit of slop to avoid having 
	   something like a 1025-bit requested key size lead to the use of a 
	   1536-bit key value.

	   In theory we should probably generate a new DH key each time:

		status = krnlSendMessage( iDHContext, IMESSAGE_SETATTRIBUTE,
								  ( MESSAGE_CAST ) &requestedKeySize,
								  CRYPT_CTXINFO_KEYSIZE );
		if( cryptStatusOK( status ) )
			status = krnlSendMessage( iDHContext, IMESSAGE_CTX_GENKEY, 
									  NULL, FALSE );

	   however because the handshake is set up so that the client (rather 
	   than the server) chooses the key size we can't actually perform the 
	   generation until we're in the middle of the handshake.  This means 
	   that the server will grind to a halt during each handshake as it 
	   generates a new key of whatever size takes the client's fancy (it 
	   also leads to a nice potential DoS attack on the server).  To avoid 
	   this problem we use fixed keys of various common sizes.
	   
	   As late as 2014 Java still can't handle DH keys over 1024 bits (it 
	   only allows keys ranging from 512-1024 bits):

		java.security.InvalidAlgorithmParameterException: Prime size must be 
		multiple of 64, and can only range from 512 to 1024 (inclusive)

	   so if you need to talk to a system built in Java you need to hardcode
	   the key size below to 1024 bits, the largest size that Java will 
	   allow */
	switch( actualKeySize )
		{
		case bitsToBytes( 1024 ):
			keyData = dh1024SSL;
			keyDataLength = sizeof( dh1024SSL );
			keyDataChecksum = dh1024checksum;
			break;

		case bitsToBytes( 1536 ):
			keyData = dh1536SSL;
			keyDataLength = sizeof( dh1536SSL );
			keyDataChecksum = dh1536checksum;
			break;

		case bitsToBytes( 2048 ):
			keyData = dh2048SSL;
			keyDataLength = sizeof( dh2048SSL );
			keyDataChecksum = dh2048checksum;
			break;

		case bitsToBytes( 3072 ):
		default:			/* Hier ist der mast zu ende */
			keyData = dh3072SSL;
			keyDataLength = sizeof( dh3072SSL );
			keyDataChecksum = dh3072checksum;
			break;
		}

	/* Make sure that the key data hasn't been corrupted */
	if( keyDataChecksum != checksumData( keyData, keyDataLength ) )
		{
		DEBUG_DIAG(( "Fixed DH value for %d-bit key has been corrupted",
					 bytesToBits( actualKeySize ) ));
		retIntError();
		}

	/* Load the fixed DH key into the context */
	setMessageData( &msgData, ( MESSAGE_CAST ) keyData, keyDataLength );
	return( krnlSendMessage( iDHContext, IMESSAGE_SETATTRIBUTE_S, &msgData, 
							 CRYPT_IATTRIBUTE_KEY_SSL ) );
	}
コード例 #14
0
ファイル: pgp_rd.c プロジェクト: VlaBst6/cryptlib-history
static int readKey( INOUT STREAM *stream, 
					INOUT PGP_INFO *pgpInfo, 
					IN_INT_SHORT_Z const int keyGroupNo,
					INOUT ERROR_INFO *errorInfo )
	{
	PGP_KEYINFO *keyInfo = &pgpInfo->key;
	HASHFUNCTION hashFunction;
	HASHINFO hashInfo;
	BYTE hash[ CRYPT_MAX_HASHSIZE + 8 ], packetHeader[ 64 + 8 ];
	BOOLEAN isPublicKey = TRUE, isPrimaryKey = FALSE;
	void *pubKeyPayload;
	long packetLength;
	int pubKeyPos, pubKeyPayloadPos, endPos, pubKeyPayloadLen;
	int ctb, length, value, hashSize, iterationCount, status;

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

	REQUIRES( keyGroupNo >= 0 && keyGroupNo < MAX_INTLENGTH_SHORT );
	REQUIRES( errorInfo != NULL );

	/* Process the CTB and packet length */
	ctb = sPeek( stream );
	if( cryptStatusError( ctb ) )
		{
		/* If there was an error reading the CTB, which is the first byte of 
		   the packet group, it means that we've run out of data so we 
		   return the status as a not-found error rather than the actual
		   stream status */
		return( CRYPT_ERROR_NOTFOUND );
		}
	switch( pgpGetPacketType( ctb ) )
		{
		case PGP_PACKET_SECKEY_SUB:
			keyInfo = &pgpInfo->subKey;
			isPublicKey = FALSE;
			break;

		case PGP_PACKET_SECKEY:
			isPublicKey = FALSE;
			break;

		case PGP_PACKET_PUBKEY_SUB:
			keyInfo = &pgpInfo->subKey;
			break;

		case PGP_PACKET_PUBKEY:
			isPrimaryKey = TRUE;
			break;

		default:
			retExt( CRYPT_ERROR_BADDATA, 
					( CRYPT_ERROR_BADDATA, errorInfo, 
					  "Invalid PGP CTB %02X for key packet group %d", 
					  ctb, keyGroupNo ) );
		}
	status = pgpReadPacketHeader( stream, NULL, &packetLength, 64 );
	if( cryptStatusError( status ) )
		{
		retExt( status,
				( status, errorInfo, 
				  "Invalid PGP key packet header for key packet group %d", 
				  keyGroupNo ) );
		}
	if( packetLength < 64 || packetLength > sMemDataLeft( stream ) )
		{
		retExt( CRYPT_ERROR_BADDATA, 
				( CRYPT_ERROR_BADDATA, errorInfo, 
				  "Invalid PGP key packet length %ld for key packet group %d", 
				  packetLength, keyGroupNo ) );
		}

	/* Since there can (in theory) be arbitrary numbers of subkeys and other 
	   odds and ends attached to a key and the details of what to do with 
	   these things gets a bit vague, we just skip any further subkeys that 
	   may be present */
	if( keyInfo->pkcAlgo != CRYPT_ALGO_NONE )
		{
		status = sSkip( stream, packetLength );
		for( iterationCount = 0; 
			 cryptStatusOK( status ) && \
				iterationCount < FAILSAFE_ITERATIONS_MED; 
			 iterationCount++ )
			{
			status = readUserID( stream, pgpInfo, 
								 isPrimaryKey ? &hashInfo : NULL );
			}
		ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
		if( cryptStatusError( status ) && status != OK_SPECIAL )
			{
			retExt( status, 
					( status, errorInfo, 
					  "Invalid additional PGP subkey information for key "
					  "packet group %d", keyGroupNo ) );
			}

		/* We've skipped the current subkey, we're done */
		return( CRYPT_OK );
		}

	/* Determine which bits make up the public and the private key data.  The
	   public-key data starts at the version number and includes the date,
	   validity, and public-key components.  Since there's no length 
	   information included for this data block we have to record bookmarks
	   and then later retroactively calculate the length based on how much
	   data we've read in the meantime:

		  pubKey pubKeyPayload		 privKey			 endPos
			|		|					|					|
			v		v					v					v
		+---+---------------------------+-------------------+
		|hdr|		|	Public key		|	Private key		|
		+---+---------------------------+-------------------+
			|		|<pubKeyPayloadLen->|					|
			|<----- pubKeyDataLen ----->|<-- privKeyDLen -->| 
			|<--------------- packetLength ---------------->| */
	pubKeyPos = stell( stream );
	endPos = pubKeyPos + packetLength;
	ENSURES( endPos > pubKeyPos && endPos < MAX_BUFFER_SIZE );
	status = value = sgetc( stream );
	if( cryptStatusError( status ) )
		return( status );
	if( value != PGP_VERSION_2 && value != PGP_VERSION_3 && \
		value != PGP_VERSION_OPENPGP )
		{
		/* Unknown version number, skip this packet */
		return( OK_SPECIAL );
		}
	pgpInfo->isOpenPGP = ( value == PGP_VERSION_OPENPGP ) ? TRUE : FALSE;

	/* Build the packet header, which is hashed along with the key components
	   to get the OpenPGP keyID.  This is generated anyway when the context
	   is created but we need to generate it here as well in order to locate
	   the key in the first place:

		byte		ctb = 0x99
		byte[2]		length
		byte		version = 4
		byte[4]		key generation time
	  [	byte[2]		validity time - PGP 2.x only ]
		byte[]		key data

	   We can't add the length or key data yet since we have to parse the
	   key data to know how long it is, so we can only build the static part
	   of the header at this point */
	packetHeader[ 0 ] = 0x99;
	packetHeader[ 3 ] = PGP_VERSION_OPENPGP;

	/* Read the timestamp and validity period (for PGP 2.x keys) */
	status = sread( stream, packetHeader + 4, 4 );
	if( !cryptStatusError( status ) && !pgpInfo->isOpenPGP )
		status = sSkip( stream, 2 );
	if( cryptStatusError( status ) )
		return( status );

	/* Read the public key components */
	pubKeyPayloadPos = stell( stream );
	status = readPublicKeyComponents( stream, keyInfo, &length );
	if( cryptStatusError( status ) )
		{
		/* If the error status is OK_SPECIAL then the problem was an
		   unrecognised algorithm or something similar so we just skip the 
		   packet */
		if( status == OK_SPECIAL )
			{
			DEBUG_DIAG(( "Encountered unrecognised algorithm while "
						 "reading key" ));
			assert( DEBUG_WARN );
			return( OK_SPECIAL );
			}
		retExt( status, 
				( status, errorInfo, 
				  "Invalid PGP public-key components for key packet group %d",
				  keyGroupNo ) );
		}

	/* Now that we know where the public key data starts and finishes, we 
	   can set up references to it */
	keyInfo->pubKeyDataLen = stell( stream ) - pubKeyPos;
	status = sMemGetDataBlockAbs( stream, pubKeyPos, &keyInfo->pubKeyData, 
								  keyInfo->pubKeyDataLen );
	if( cryptStatusError( status ) )
		{
		DEBUG_DIAG(( "Couldn't set up reference to key data" ));
		assert( DEBUG_WARN );
		return( status );
		}
	pubKeyPayloadLen = stell( stream ) - pubKeyPayloadPos;
	status = sMemGetDataBlockAbs( stream, pubKeyPayloadPos, &pubKeyPayload, 
								  pubKeyPayloadLen );
	if( cryptStatusError( status ) )
		{
		DEBUG_DIAG(( "Couldn't set up reference to key data" ));
		assert( DEBUG_WARN );
		return( status );
		}

	/* Complete the packet header that we read earlier on by adding the
	   length information */
	packetHeader[ 1 ] = intToByte( ( ( 1 + 4 + length ) >> 8 ) & 0xFF );
	packetHeader[ 2 ] = intToByte( ( 1 + 4 + length ) & 0xFF );

	/* Hash the data needed to generate the OpenPGP keyID */
	getHashParameters( CRYPT_ALGO_SHA1, 0, &hashFunction, &hashSize );
	hashFunction( hashInfo, NULL, 0, packetHeader, 1 + 2 + 1 + 4, 
				  HASH_STATE_START );
	hashFunction( hashInfo, hash, CRYPT_MAX_HASHSIZE, 
				  pubKeyPayload, pubKeyPayloadLen, HASH_STATE_END );
	memcpy( keyInfo->openPGPkeyID, hash + hashSize - PGP_KEYID_SIZE,
			PGP_KEYID_SIZE );

	/* If it's a private keyring, process the private key components */
	if( !isPublicKey )
		{
		/* Handle decryption information for private-key components if 
		   necessary */
		status = readPrivateKeyDecryptionInfo( stream, keyInfo );
		if( cryptStatusError( status ) )
			{
			/* If the error status is OK_SPECIAL then the problem was an
			   unrecognised algorithm or something similar so we just skip
			   the packet */
			if( status == OK_SPECIAL )
				{
				DEBUG_DIAG(( "Encountered unrecognised algorithm while "
							 "reading key" ));
				assert( DEBUG_WARN );
				return( OK_SPECIAL );
				}
			retExt( status, 
					( status, errorInfo, 
					  "Invalid PGP private-key decryption information for "
					  "key packet group %d", keyGroupNo ) );
			}

		/* What's left is the private-key data */
		keyInfo->privKeyDataLen = endPos - stell( stream );
		status = sMemGetDataBlock( stream, &keyInfo->privKeyData, 
								   keyInfo->privKeyDataLen );
		if( cryptStatusOK( status ) )
			status = sSkip( stream, keyInfo->privKeyDataLen );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* If it's the primary key, start hashing it in preparation for 
	   performing signature checks on subpackets */
	if( isPrimaryKey )
		{
		packetHeader[ 0 ] = 0x99;
		packetHeader[ 1 ] = intToByte( ( keyInfo->pubKeyDataLen >> 8 ) & 0xFF );
		packetHeader[ 2 ] = intToByte( keyInfo->pubKeyDataLen & 0xFF );	
		hashFunction( hashInfo, NULL, 0, packetHeader, 1 + 2, 
					  HASH_STATE_START );
		hashFunction( hashInfo, NULL, 0, keyInfo->pubKeyData, 
					  keyInfo->pubKeyDataLen, HASH_STATE_CONTINUE );
		}

	/* Read any associated subpacket(s), of which the only ones of real 
	   interest are the userID packet(s) */
	for( iterationCount = 0; 
		 cryptStatusOK( status ) && \
			iterationCount < FAILSAFE_ITERATIONS_MED; 
		 iterationCount++ )
		{
		status = readUserID( stream, pgpInfo, 
							 isPrimaryKey ? &hashInfo : NULL );
		}
	ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
	if( cryptStatusError( status ) && status != OK_SPECIAL )
		{
		retExt( status, 
				( status, errorInfo, 
				  "Invalid PGP userID information for key packet group %d",
				  keyGroupNo ) );
		}

	/* If there's no user ID present, set a generic label */
	if( pgpInfo->lastUserID <= 0 )
		{
		pgpInfo->userID[ 0 ] = "PGP key (no user ID found)";
		pgpInfo->userIDlen[ 0 ] = 26;
		pgpInfo->lastUserID = 1;
		}

	return( CRYPT_OK );
	}