Esempio n. 1
0
CHECK_RETVAL \
int checkDHdata( void )
	{
	HASHFUNCTION_ATOMIC hashFunctionAtomic;
	BYTE hashValue[ 20 + 8 ];

	getHashAtomicParameters( CRYPT_ALGO_SHA1, 0, &hashFunctionAtomic, NULL );

	/* Generate/check the SHA-1 values for the primes.  This doesn't cover 
	   all of the data, but is needed to bootstrap the full check because 
	   only the hashes of the primes have been published */
#if 0
	hashFunctionAtomic( hashValue, 20, dh1024SSL + 2, sizeof( dh1024SSL ) - 5 );
	hashFunctionAtomic( hashValue, 20, dh1536SSL + 2, sizeof( dh1536SSL ) - 5 );
	hashFunctionAtomic( hashValue, 20, dh2048SSL + 2, sizeof( dh2048SSL ) - 5 );
	hashFunctionAtomic( hashValue, 20, dh3072SSL + 2, sizeof( dh3072SSL ) - 5 );
#endif /* 0 */

	/* Check the SHA-1 values for the DH data */
	hashFunctionAtomic( hashValue, 20, dh1024SSL, sizeof( dh1024SSL ) );
	if( memcmp( hashValue, \
				"\x46\xF4\x47\xC3\x69\x00\x6F\x22\x91\x0E\x24\xF5\x73\x68\xE6\xF7", 16 ) )
		retIntError();
	hashFunctionAtomic( hashValue, 20, dh1536SSL, sizeof( dh1536SSL ) );
	if( memcmp( hashValue, \
				"\xA3\xEC\x2F\x85\xC7\xD3\x74\xD2\x56\x53\x22\xED\x53\x87\x6F\xDC", 16 ) )
		retIntError();
	hashFunctionAtomic( hashValue, 20, dh2048SSL, sizeof( dh2048SSL ) );
	if( memcmp( hashValue, \
				"\x0E\x8E\x49\x9F\xD9\x18\x02\xCB\x5D\x42\x03\xA5\xE1\x67\x51\xDB", 16 ) )
		retIntError();
	hashFunctionAtomic( hashValue, 20, dh3072SSL, sizeof( dh3072SSL ) );
	if( memcmp( hashValue, \
				"\x8F\x4A\x19\xEF\x85\x1D\x91\xEA\x18\xE8\xB8\xB9\x9F\xF0\xFD\xF8", 16 ) )
		retIntError();

	/* Now that we've verified that the DH data is valid, calculate a 
	   checksum for each value to allow it to be quickly checked before it's
	   loaded into a context */
	dh1024checksum = checksumData( dh1024SSL, sizeof( dh1024SSL ) );
	dh1536checksum = checksumData( dh1536SSL, sizeof( dh1536SSL ) );
	dh2048checksum = checksumData( dh2048SSL, sizeof( dh2048SSL ) );
	dh3072checksum = checksumData( dh3072SSL, sizeof( dh3072SSL ) );

	return( CRYPT_OK );
	}
Esempio n. 2
0
CHECK_RETVAL \
static int selfTest( void )
	{
	CONTEXT_INFO contextInfo;
	PKC_INFO contextData, *pkcInfo = &contextData;
	int status;

	/* Initialise the key components */
	status = staticInitContext( &contextInfo, CONTEXT_PKC, 
								getDHCapability(), &contextData, 
								sizeof( PKC_INFO ), NULL );
	if( cryptStatusError( status ) )
		return( CRYPT_ERROR_FAILED );
	status = importBignum( &pkcInfo->dlpParam_p, dlpTestKey.p, 
						   dlpTestKey.pLen, DLPPARAM_MIN_P, 
						   DLPPARAM_MAX_P, NULL, KEYSIZE_CHECK_PKC );
	if( cryptStatusOK( status ) )
		status = importBignum( &pkcInfo->dlpParam_g, dlpTestKey.g, 
							   dlpTestKey.gLen, DLPPARAM_MIN_G, 
							   DLPPARAM_MAX_G, &pkcInfo->dlpParam_p,
							   KEYSIZE_CHECK_NONE );
	if( cryptStatusOK( status ) )
		status = importBignum( &pkcInfo->dlpParam_q, dlpTestKey.q, 
							   dlpTestKey.qLen, DLPPARAM_MIN_Q, 
							   DLPPARAM_MAX_Q, &pkcInfo->dlpParam_p,
							   KEYSIZE_CHECK_NONE );
	if( cryptStatusOK( status ) )
		status = importBignum( &pkcInfo->dlpParam_y, dlpTestKey.y, 
							   dlpTestKey.yLen, DLPPARAM_MIN_Y, 
							   DLPPARAM_MAX_Y, &pkcInfo->dlpParam_p,
							   KEYSIZE_CHECK_NONE );
	if( cryptStatusOK( status ) )
		status = importBignum( &pkcInfo->dlpParam_x, dlpTestKey.x, 
							   dlpTestKey.xLen, DLPPARAM_MIN_X, 
							   DLPPARAM_MAX_X, &pkcInfo->dlpParam_p,
							   KEYSIZE_CHECK_NONE );
	if( cryptStatusError( status ) )
		{
		staticDestroyContext( &contextInfo );
		retIntError();
		}

	ENSURES( sanityCheckPKCInfo( pkcInfo ) );

	/* Perform the test key exchange on a block of data */
	status = contextInfo.capabilityInfo->initKeyFunction( &contextInfo, NULL, 0 );
	if( cryptStatusOK( status ) && \
		!pairwiseConsistencyTest( &contextInfo ) )
		status = CRYPT_ERROR_FAILED;

	/* Clean up */
	staticDestroyContext( &contextInfo );

	return( status );
	}
Esempio n. 3
0
CHECK_RETVAL \
static int selfTest( void )
	{
	CONTEXT_INFO contextInfo;
	PKC_INFO contextData, *pkcInfo = &contextData;
	const CAPABILITY_INFO *capabilityInfoPtr;
	int status;

	/* Initialise the key components */
	status = staticInitContext( &contextInfo, CONTEXT_PKC, 
								getECDHCapability(), &contextData, 
								sizeof( PKC_INFO ), NULL );
	if( cryptStatusError( status ) )
		return( CRYPT_ERROR_FAILED );
	pkcInfo->curveType = CRYPT_ECCCURVE_P256;
	status = importBignum( &pkcInfo->eccParam_qx, ecdhTestKey.qx, 
						   ecdhTestKey.qxLen, ECCPARAM_MIN_QX, 
						   ECCPARAM_MAX_QX, NULL, KEYSIZE_CHECK_ECC );
	if( cryptStatusOK( status ) ) 
		status = importBignum( &pkcInfo->eccParam_qy, ecdhTestKey.qy, 
							   ecdhTestKey.qyLen, ECCPARAM_MIN_QY, 
							   ECCPARAM_MAX_QY, NULL, KEYSIZE_CHECK_NONE );
	if( cryptStatusOK( status ) ) 
		status = importBignum( &pkcInfo->eccParam_d, ecdhTestKey.d, 
							   ecdhTestKey.dLen, ECCPARAM_MIN_D, 
							   ECCPARAM_MAX_D, NULL, KEYSIZE_CHECK_NONE );
	if( cryptStatusError( status ) ) 
		{
		staticDestroyContext( &contextInfo );
		retIntError();
		}
	capabilityInfoPtr = contextInfo.capabilityInfo;

	/* Perform the test key exchange on a block of data */
	status = capabilityInfoPtr->initKeyFunction( &contextInfo,  NULL, 0 );
	if( cryptStatusError( status ) || \
		!pairwiseConsistencyTest( &contextInfo ) )
		{
		staticDestroyContext( &contextInfo );
		return( CRYPT_ERROR_FAILED );
		}

	/* Clean up */
	staticDestroyContext( &contextInfo );

	return( CRYPT_OK );
	}
Esempio n. 4
0
static int initMemoryStream( OUT STREAM *stream, 
							 const BOOLEAN isNullStream )
	{
	/* We don't use a REQUIRES() predicate here for the reasons given in the 
	   comments above */
	assert( isWritePtr( stream, sizeof( STREAM ) ) );

	/* Check that the input parameters are in order */
	if( !isWritePtrConst( stream, sizeof( STREAM ) ) )
		retIntError();

	/* Clear the stream data and initialise the stream structure.  Further 
	   initialisation of stream buffer parameters will be done by the 
	   caller */
	memset( stream, 0, sizeof( STREAM ) );
	stream->type = ( isNullStream ) ? STREAM_TYPE_NULL : STREAM_TYPE_MEMORY;

	return( CRYPT_OK );
	}
Esempio n. 5
0
static int shutdownMemoryStream( INOUT STREAM *stream,
								 const BOOLEAN clearStreamBuffer )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );

	/* Check that the input parameters are in order */
	if( !isWritePtrConst( stream, sizeof( STREAM ) ) )
		retIntError();

	REQUIRES( stream->type == STREAM_TYPE_NULL || \
			  stream->type == STREAM_TYPE_MEMORY );

	/* Clear the stream structure */
	if( clearStreamBuffer && stream->buffer != NULL && stream->bufEnd > 0 )
		zeroise( stream->buffer, stream->bufEnd );
	zeroise( stream, sizeof( STREAM ) );

	return( CRYPT_OK );
	}
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 );
	}
Esempio n. 7
0
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();
	}
Esempio n. 8
0
int deleteCertComponent( INOUT CERT_INFO *certInfoPtr,
						 IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE certInfoType )
	{
	int status;

	assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );

	REQUIRES( isAttribute( certInfoType ) || \
			  isInternalAttribute( certInfoType ) );

	/* If it's a GeneralName or DN component, delete it.  These are 
	   special-case attribute values so they have to come before the 
	   general attribute-handling code */
	if( isGeneralNameSelectionComponent( certInfoType ) )
		{
		/* Check whether this GeneralName is present */
		status = selectGeneralName( certInfoPtr, certInfoType,
									MUST_BE_PRESENT );
		if( cryptStatusError( status ) )
			return( status );

		/* Delete each field in the GeneralName */
		if( deleteCompositeAttributeField( &certInfoPtr->attributes,
					&certInfoPtr->attributeCursor, certInfoPtr->attributeCursor,
					certInfoPtr->currentSelection.dnPtr ) == OK_SPECIAL )
			{
			/* We've deleted the attribute containing the currently selected 
			   DN, deselect it */
			certInfoPtr->currentSelection.dnPtr = NULL;
			}

		return( CRYPT_OK );
		}
	if( isGeneralNameComponent( certInfoType ) )
		{
		SELECTION_STATE selectionState;
		ATTRIBUTE_PTR *attributePtr = DUMMY_INIT_PTR;

		/* Find the requested GeneralName component.  Since 
		   selectGeneralNameComponent() changes the current selection within 
		   the GeneralName, we save the selection state around the call */
		saveSelectionState( selectionState, certInfoPtr );
		status = selectGeneralNameComponent( certInfoPtr, certInfoType );
		if( cryptStatusOK( status ) )
			attributePtr = certInfoPtr->attributeCursor;
		restoreSelectionState( selectionState, certInfoPtr );
		if( cryptStatusError( status ))
			return( status );
		ENSURES( attributePtr != NULL );

		/* Delete the field within the GeneralName */
		if( deleteAttributeField( &certInfoPtr->attributes,
						&certInfoPtr->attributeCursor, attributePtr,
						certInfoPtr->currentSelection.dnPtr ) == OK_SPECIAL )
			{
			/* We've deleted the attribute containing the currently selected
			   DN, deselect it */
			certInfoPtr->currentSelection.dnPtr = NULL;
			}
		return( CRYPT_OK );
		}
	if( isDNComponent( certInfoType ) )
		{
		status = selectDN( certInfoPtr, CRYPT_ATTRIBUTE_NONE,
						   MUST_BE_PRESENT );
		if( cryptStatusOK( status ) )
			status = deleteDNComponent( certInfoPtr->currentSelection.dnPtr,
										certInfoType, NULL, 0 );
		return( status );
		}

	/* If it's standard certificate or CMS attribute, delete it */
	if( ( certInfoType >= CRYPT_CERTINFO_FIRST_EXTENSION && \
		  certInfoType <= CRYPT_CERTINFO_LAST_EXTENSION ) || \
		( certInfoType >= CRYPT_CERTINFO_FIRST_CMS && \
		  certInfoType <= CRYPT_CERTINFO_LAST_CMS ) )
		return( deleteCertAttribute( certInfoPtr, certInfoType ) );

	/* If it's anything else, handle it specially */
	switch( certInfoType )
		{
		case CRYPT_CERTINFO_SELFSIGNED:
			if( !( certInfoPtr->flags & CERT_FLAG_SELFSIGNED ) )
				return( CRYPT_ERROR_NOTFOUND );
			certInfoPtr->flags &= ~CERT_FLAG_SELFSIGNED;
			return( CRYPT_OK );

		case CRYPT_CERTINFO_CURRENT_CERTIFICATE:
		case CRYPT_ATTRIBUTE_CURRENT_GROUP:
		case CRYPT_ATTRIBUTE_CURRENT:
		case CRYPT_ATTRIBUTE_CURRENT_INSTANCE:
			if( certInfoPtr->attributeCursor == NULL )
				return( CRYPT_ERROR_NOTFOUND );
			if( certInfoType == CRYPT_ATTRIBUTE_CURRENT_GROUP )
				{
				status = deleteAttribute( &certInfoPtr->attributes,
									&certInfoPtr->attributeCursor,
									certInfoPtr->attributeCursor,
									certInfoPtr->currentSelection.dnPtr );
				}
			else
				{
				/* The current component and field are essentially the
				   same thing since a component is one of a set of
				   entries in a multivalued field, thus they're handled
				   identically */
				status = deleteAttributeField( &certInfoPtr->attributes,
									&certInfoPtr->attributeCursor,
									certInfoPtr->attributeCursor,
									certInfoPtr->currentSelection.dnPtr );
				}
			if( status == OK_SPECIAL )
				{
				/* We've deleted the attribute containing the currently 
				   selected DN, deselect it */
				certInfoPtr->currentSelection.dnPtr = NULL;
				}
			return( CRYPT_OK );

		case CRYPT_CERTINFO_TRUSTED_USAGE:
			if( certInfoPtr->cCertCert->trustedUsage == CRYPT_ERROR )
				return( CRYPT_ERROR_NOTFOUND );
			certInfoPtr->cCertCert->trustedUsage = CRYPT_ERROR;
			return( CRYPT_OK );

		case CRYPT_CERTINFO_TRUSTED_IMPLICIT:
			return( krnlSendMessage( certInfoPtr->ownerHandle,
									 IMESSAGE_USER_TRUSTMGMT,
									 &certInfoPtr->objectHandle,
									 MESSAGE_TRUSTMGMT_DELETE ) );

		case CRYPT_CERTINFO_VALIDFROM:
		case CRYPT_CERTINFO_THISUPDATE:
			if( certInfoPtr->startTime <= 0 )
				return( CRYPT_ERROR_NOTFOUND );
			certInfoPtr->startTime = 0;
			return( CRYPT_OK );

		case CRYPT_CERTINFO_VALIDTO:
		case CRYPT_CERTINFO_NEXTUPDATE:
			if( certInfoPtr->endTime <= 0 )
				return( CRYPT_ERROR_NOTFOUND );
			certInfoPtr->endTime = 0;
			return( CRYPT_OK );

		case CRYPT_CERTINFO_SUBJECTNAME:
			if( certInfoPtr->currentSelection.dnPtr == &certInfoPtr->subjectName )
				{
				/* This is the currently selected DN, deselect it before 
				   deleting it */
				certInfoPtr->currentSelection.dnPtr = NULL;
				}
			deleteDN( &certInfoPtr->subjectName );
			return( CRYPT_OK );

#ifdef USE_CERTREV
		case CRYPT_CERTINFO_REVOCATIONDATE:
			{
			time_t *revocationTimePtr = ( time_t * ) \
							getRevocationTimePtr( certInfoPtr );

			if( revocationTimePtr == NULL )
				return( CRYPT_ERROR_NOTFOUND );
			*revocationTimePtr = 0;
			return( CRYPT_OK );
			}
#endif /* USE_CERTREV */

#ifdef USE_PKIUSER
		case CRYPT_CERTINFO_PKIUSER_RA:
			if( !certInfoPtr->cCertUser->isRA )
				return( CRYPT_ERROR_NOTFOUND );
			certInfoPtr->cCertUser->isRA = FALSE;
			return( CRYPT_OK );
#endif /* USE_PKIUSER */
		}

	retIntError();
	}
Esempio n. 9
0
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 );
	}
Esempio n. 10
0
CHECK_RETVAL \
static int selfTest( void )
	{
	CONTEXT_INFO contextInfo;
	PKC_INFO contextData, *pkcInfo = &contextData;
	const CAPABILITY_INFO *capabilityInfoPtr;
	DLP_PARAMS dlpParams;
	BYTE buffer[ ( CRYPT_MAX_PKCSIZE * 2 ) + 32 + 8 ];
	int status;

	/* Initialise the key components */
	status = staticInitContext( &contextInfo, CONTEXT_PKC, 
								getElgamalCapability(), &contextData, 
								sizeof( PKC_INFO ), NULL );
	if( cryptStatusError( status ) )
		return( status );
	status = importBignum( &pkcInfo->dlpParam_p, dlpTestKey.p, 
						   dlpTestKey.pLen, DLPPARAM_MIN_P, 
						   DLPPARAM_MAX_P, NULL, KEYSIZE_CHECK_PKC );
	if( cryptStatusOK( status ) )
		status = importBignum( &pkcInfo->dlpParam_g, dlpTestKey.g, 
							   dlpTestKey.gLen, DLPPARAM_MIN_G, 
							   DLPPARAM_MAX_G, &pkcInfo->dlpParam_p, 
							   KEYSIZE_CHECK_NONE );
	if( cryptStatusOK( status ) )
		status = importBignum( &pkcInfo->dlpParam_q, dlpTestKey.q, 
							   dlpTestKey.qLen, DLPPARAM_MIN_Q, 
							   DLPPARAM_MAX_Q, &pkcInfo->dlpParam_p,
							   KEYSIZE_CHECK_NONE );
	if( cryptStatusOK( status ) )
		status = importBignum( &pkcInfo->dlpParam_y, dlpTestKey.y, 
							   dlpTestKey.yLen, DLPPARAM_MIN_Y, 
							   DLPPARAM_MAX_Y, &pkcInfo->dlpParam_p,
							   KEYSIZE_CHECK_NONE );
	if( cryptStatusOK( status ) )
		status = importBignum( &pkcInfo->dlpParam_x, dlpTestKey.x, 
							   dlpTestKey.xLen, DLPPARAM_MIN_X, 
							   DLPPARAM_MAX_X, &pkcInfo->dlpParam_p,
							   KEYSIZE_CHECK_NONE );
	if( cryptStatusError( status ) )
		{
		staticDestroyContext( &contextInfo );
		retIntError();
		}
	capabilityInfoPtr = contextInfo.capabilityInfo;

	ENSURES( sanityCheckPKCInfo( pkcInfo ) );

	/* Perform a test a sig generation/check and test en/decryption */
#if 0	/* See comment in sig.code */
	memset( buffer, '*', 20 );
	status = capabilityInfoPtr->signFunction( &contextInfoPtr, buffer, -1 );
	if( !cryptStatusError( status ) )
		{
		memmove( buffer + 20, buffer, status );
		memset( buffer, '*', 20 );
		status = capabilityInfoPtr->sigCheckFunction( &contextInfoPtr,
													  buffer, 20 + status );
		}
	if( status != CRYPT_OK )
		status = CRYPT_ERROR_FAILED;
#endif /* 0 */
	status = capabilityInfoPtr->initKeyFunction( &contextInfo, NULL, 0 );
	if( cryptStatusError( status ) || \
		!pairwiseConsistencyTest( &contextInfo, FALSE ) )
		{
		staticDestroyContext( &contextInfo );
		return( CRYPT_ERROR_FAILED );
		}

	/* Finally, make sure that the memory fault-detection is working */
	pkcInfo->dlpParam_p.d[ 8 ] ^= 0x0011;
	memset( buffer, 0, CRYPT_MAX_PKCSIZE );
	memcpy( buffer + 1, "abcde", 5 );
	setDLPParams( &dlpParams, buffer,
				  bitsToBytes( contextInfo.ctxPKC->keySizeBits ),
				  buffer, ( CRYPT_MAX_PKCSIZE * 2 ) + 32 );
	status = capabilityInfoPtr->encryptFunction( &contextInfo,
							( BYTE * ) &dlpParams, sizeof( DLP_PARAMS ) );
	if( cryptStatusOK( status ) )
		{
		/* The fault-detection couldn't detect a bit-flip, there's a 
		   problem */
		staticDestroyContext( &contextInfo );
		return( CRYPT_ERROR_FAILED );
		}

	/* Clean up */
	staticDestroyContext( &contextInfo );

	return( CRYPT_OK );
	}
Esempio n. 11
0
int queryPgpObject( INOUT void *streamPtr, OUT QUERY_INFO *queryInfo )
	{
	QUERY_INFO basicQueryInfo;
	STREAM *stream = streamPtr;
	const long startPos = stell( stream );
	int status;

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

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

	/* Determine basic object information.  This also verifies that all of 
	   the object data is present in the stream */
	status = getPgpPacketInfo( stream, &basicQueryInfo );
	sseek( stream, startPos );
	if( cryptStatusError( status ) )
		return( status );

	/* Call the appropriate routine to find out more about the object */
	switch( basicQueryInfo.type )
		{
		case CRYPT_OBJECT_ENCRYPTED_KEY:
			{
			const READKEK_FUNCTION readKekFunction = \
									getReadKekFunction( KEYEX_PGP );

			if( readKekFunction == NULL )
				return( CRYPT_ERROR_NOTAVAIL );
			status = readKekFunction( stream, queryInfo );
			break;
			}

		case CRYPT_OBJECT_PKCENCRYPTED_KEY:
			{
			const READKEYTRANS_FUNCTION readKeytransFunction = \
									getReadKeytransFunction( KEYEX_PGP );

			if( readKeytransFunction == NULL )
				return( CRYPT_ERROR_NOTAVAIL );
			status = readKeytransFunction( stream, queryInfo );
			break;
			}

		case CRYPT_OBJECT_SIGNATURE:
			{
			const READSIG_FUNCTION readSigFunction = \
									getReadSigFunction( SIGNATURE_PGP );

			if( readSigFunction == NULL )
				return( CRYPT_ERROR_NOTAVAIL );
			status = readSigFunction( stream, queryInfo );
			break;
			}

		case CRYPT_OBJECT_NONE:
			/* First half of a one-pass signature */
			status = readPgpOnepassSigPacket( stream, queryInfo );
			break;

		default:
			retIntError();
		}
	sseek( stream, startPos );
	if( cryptStatusError( status ) )
		{
		zeroise( queryInfo, sizeof( QUERY_INFO ) );
		return( status );
		}

	/* Augment the per-object query information with the basic query 
	   information that we got earlier */
	queryInfo->formatType = basicQueryInfo.formatType;
	if( queryInfo->type == CRYPT_OBJECT_NONE )
		{
		/* The non-type CRYPT_OBJECT_NONE denotes the first half of a one-
		   pass signature packet, in which case the actual type is given in
		   the packet data */
		queryInfo->type = basicQueryInfo.type;
		}
	queryInfo->size = basicQueryInfo.size;
	if( queryInfo->version == 0 )
		{
		/* PGP has multiple packet version numbers sprayed all over the
		   place, and just because an outer version is X doesn't mean that
		   a subsequent inner version can't be Y.  The information is really
		   only used to control the formatting of what gets read, so we
		   just report the first version that we encounter */
		queryInfo->version = basicQueryInfo.version;
		}

	return( CRYPT_OK );
	}
Esempio n. 12
0
int queryAsn1Object( INOUT void *streamPtr, OUT QUERY_INFO *queryInfo )
	{
	QUERY_INFO basicQueryInfo;
	STREAM *stream = streamPtr;
	const long startPos = stell( stream );
	int status;

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

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

	/* Determine basic object information.  This also verifies that all of 
	   the object data is present in the stream */
	status = getObjectInfo( stream, &basicQueryInfo );
	if( cryptStatusError( status ) )
		return( status );

	/* Call the appropriate routine to find out more about the object */
	switch( basicQueryInfo.type )
		{
		case CRYPT_OBJECT_ENCRYPTED_KEY:
			{
			const READKEK_FUNCTION readKekFunction = \
									getReadKekFunction( KEYEX_CMS );

			if( readKekFunction == NULL )
				return( CRYPT_ERROR_NOTAVAIL );
			status = readKekFunction( stream, queryInfo );
			break;
			}

		case CRYPT_OBJECT_PKCENCRYPTED_KEY:
			{
			const READKEYTRANS_FUNCTION readKeytransFunction = \
				getReadKeytransFunction( ( basicQueryInfo.formatType == CRYPT_FORMAT_CMS ) ? \
										 KEYEX_CMS : KEYEX_CRYPTLIB );

			if( readKeytransFunction == NULL )
				return( CRYPT_ERROR_NOTAVAIL );
			status = readKeytransFunction( stream, queryInfo );
			break;
			}

		case CRYPT_OBJECT_SIGNATURE:
			{
			const READSIG_FUNCTION readSigFunction = \
				getReadSigFunction( ( basicQueryInfo.formatType == CRYPT_FORMAT_CMS ) ? \
									SIGNATURE_CMS : SIGNATURE_CRYPTLIB );

			if( readSigFunction == NULL )
				return( CRYPT_ERROR_NOTAVAIL );
			status = readSigFunction( stream, queryInfo );
			break;
			}

		case CRYPT_OBJECT_NONE:
			/* New, unrecognised RecipientInfo type */
			status = readUniversal( stream );
			break;

		default:
			retIntError();
		}
	sseek( stream, startPos );
	if( cryptStatusError( status ) )
		{
		zeroise( queryInfo, sizeof( QUERY_INFO ) );
		return( status );
		}

	/* Augment the per-object query information with the basic query 
	   information that we got earlier */
	queryInfo->formatType = basicQueryInfo.formatType;
	queryInfo->type = basicQueryInfo.type;
	queryInfo->size = basicQueryInfo.size;
	queryInfo->version = basicQueryInfo.version;

	return( CRYPT_OK );
	}
Esempio n. 13
0
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 ) );
	}
Esempio n. 14
0
static int controlFunction( DEVICE_INFO *deviceInfo,
							const CRYPT_ATTRIBUTE_TYPE type,
							const void *data, const int dataLength,
							MESSAGE_FUNCTION_EXTINFO *messageExtInfo )
	{
	HARDWARE_INFO *hardwareInfo = deviceInfo->deviceHardware;
	int status;

	assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) );

	REQUIRES( isAttribute( type ) || isInternalAttribute( type ) );

	UNUSED_ARG( hardwareInfo );
	UNUSED_ARG( messageExtInfo );

	/* Handle user authorisation.  Since this is a built-in hardware device 
	   it's always available for use so these are just dummy routines, 
	   although they can be expanded to call down into the HAL for actual
	   authentication if any hardware with such a facility is ever used */
	if( type == CRYPT_DEVINFO_AUTHENT_USER || \
		type == CRYPT_DEVINFO_AUTHENT_SUPERVISOR )
		{
		/* Authenticate the user */
		/* ... */

		/* The device is now ready for use */
		deviceInfo->flags |= DEVICE_LOGGEDIN;		
		krnlSendMessage( deviceInfo->objectHandle, IMESSAGE_SETATTRIBUTE, 
						 MESSAGE_VALUE_UNUSED, CRYPT_IATTRIBUTE_INITIALISED );
		return( CRYPT_OK );
		}

	/* Handle authorisation value change */
	if( type == CRYPT_DEVINFO_SET_AUTHENT_SUPERVISOR )
		{
		/* Set SO PIN */
		/* ... */

		return( CRYPT_OK );
		}
	if( type == CRYPT_DEVINFO_SET_AUTHENT_USER )
		{
		/* Set user PIN */
		/* ... */

		return( CRYPT_OK );
		}

	/* Handle initialisation and zeroisation */
	if( type == CRYPT_DEVINFO_INITIALISE || \
		type == CRYPT_DEVINFO_ZEROISE )
		{
		CRYPT_KEYSET iCryptKeyset;

		/* Shut down any existing state if necessary in preparation for the 
		   zeroise/initialise.  Since this clears all state we manually 
		   reset the device-active flag since we're still active, just with
		   all information cleared */
		if( hardwareInfo->iCryptKeyset != CRYPT_ERROR )
			shutdownFunction( deviceInfo );
		hwInitialise();
		deviceInfo->flags |= DEVICE_ACTIVE;

		/* The only real difference between a zeroise and an initialise is
		   that the zeroise only clears existing state and exits while the 
		   initialise resets the state with the device ready to be used 
		   again */
		if( type == CRYPT_DEVINFO_ZEROISE )
			{
			char storageFilePath[ MAX_PATH_LENGTH + 1 + 8 ];
			int storageFilePathLen;

			/* Zeroise the device */
			status = fileBuildCryptlibPath( storageFilePath, MAX_PATH_LENGTH, 
											&storageFilePathLen, "CLKEYS", 6, 
											BUILDPATH_GETPATH );
			if( cryptStatusOK( status ) )
				{
				storageFilePath[ storageFilePathLen ] = '\0';
				fileErase( storageFilePath );
				}
			deviceInfo->flags &= ~DEVICE_LOGGEDIN;
			return( status );
			}

		/* Initialise the device.  In theory we're already in the logged-in
		   state but if the initialise was preceded by a zeroise then this
		   will have been cleared, so we explicitly re-set it */
		status = openStorageObject( &iCryptKeyset, CRYPT_KEYOPT_CREATE,
									deviceInfo->objectHandle );
		if( cryptStatusError( status ) )
			return( status );
		hardwareInfo->iCryptKeyset = iCryptKeyset;
		deviceInfo->flags |= DEVICE_LOGGEDIN;

		return( CRYPT_OK );
		}

	/* Handle high-reliability time */
	if( type == CRYPT_IATTRIBUTE_TIME )
		{
		time_t *timePtr = ( time_t * ) data;

		UNUSED_ARG( timePtr );

		return( CRYPT_ERROR_NOTAVAIL );
		}

	retIntError();
	}
Esempio n. 15
0
int setPKCinfo( CONTEXT_INFO *contextInfoPtr, 
				const CRYPT_ALGO_TYPE cryptAlgo, const void *keyInfo )
	{
	BYTE keyDataBuffer[ ( CRYPT_MAX_PKCSIZE * 4 ) + 8 ];
	MESSAGE_DATA msgData;
	int keyDataSize, status;

	assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
	assert( ( cryptAlgo == CRYPT_ALGO_RSA && \
			  isReadPtr( keyInfo, sizeof( CRYPT_PKCINFO_RSA ) ) ) || \
			( cryptAlgo != CRYPT_ALGO_RSA && \
			  isReadPtr( keyInfo, sizeof( CRYPT_PKCINFO_DLP ) ) ) );

	REQUIRES( cryptAlgo == CRYPT_ALGO_DH || \
			  cryptAlgo == CRYPT_ALGO_RSA || \
			  cryptAlgo == CRYPT_ALGO_DSA || \
			  cryptAlgo == CRYPT_ALGO_ELGAMAL );

	/* Send the public key data to the context.  We send the keying 
	   information as CRYPT_IATTRIBUTE_KEY_SPKI_PARTIAL rather than 
	   CRYPT_IATTRIBUTE_KEY_SPKI since the latter transitions the context 
	   into the high state.  We don't want to do this because we're already 
	   in the middle of processing a message that does this on completion, 
	   all that we're doing here is sending in encoded public key data for 
	   use by objects such as certificates */
	switch( cryptAlgo )
		{
		case CRYPT_ALGO_RSA:
			{
			const CRYPT_PKCINFO_RSA *rsaKeyInfo = \
						( CRYPT_PKCINFO_RSA * ) keyInfo;

			if( rsaKeyInfo->isPublicKey ) 
				contextInfoPtr->flags |= CONTEXT_FLAG_ISPUBLICKEY;
			else
				contextInfoPtr->flags |= CONTEXT_FLAG_PERSISTENT;
			status = writeFlatPublicKey( keyDataBuffer, 
							CRYPT_MAX_PKCSIZE * 4, &keyDataSize, 
							CRYPT_ALGO_RSA, 0, rsaKeyInfo->n, 
							bitsToBytes( rsaKeyInfo->nLen ), rsaKeyInfo->e, 
							bitsToBytes( rsaKeyInfo->eLen ), NULL, 0, 
							NULL, 0 );
			break;
			}

		case CRYPT_ALGO_DH:
		case CRYPT_ALGO_DSA:
		case CRYPT_ALGO_ELGAMAL:
			{
			const CRYPT_PKCINFO_DLP *dlpKeyInfo = \
						( CRYPT_PKCINFO_DLP * ) keyInfo;

			if( dlpKeyInfo->isPublicKey ) 
				contextInfoPtr->flags |= CONTEXT_FLAG_ISPUBLICKEY;
			else
				contextInfoPtr->flags |= CONTEXT_FLAG_PERSISTENT;
			status = writeFlatPublicKey( keyDataBuffer, 
						CRYPT_MAX_PKCSIZE * 4, &keyDataSize, cryptAlgo, 0,
						dlpKeyInfo->p, bitsToBytes( dlpKeyInfo->pLen ), 
						dlpKeyInfo->q, bitsToBytes( dlpKeyInfo->qLen ), 
						dlpKeyInfo->g, bitsToBytes( dlpKeyInfo->gLen ), 
						dlpKeyInfo->y, bitsToBytes( dlpKeyInfo->yLen ) );
			break;
			}

		default:
			retIntError();
		}
	if( cryptStatusError( status ) )
		return( status );
	setMessageData( &msgData, keyDataBuffer, keyDataSize );
	return( krnlSendMessage( contextInfoPtr->objectHandle, 
							 IMESSAGE_SETATTRIBUTE_S, &msgData, 
							 CRYPT_IATTRIBUTE_KEY_SPKI_PARTIAL ) );
	}
Esempio n. 16
0
static int dlpGenerateComponents( CRYPT_PKCINFO_DLP *dlpKeyInfo,
								  const int keySizeBits,
								  const CRYPT_ALGO_TYPE cryptAlgo )
	{
	CONTEXT_INFO staticContextInfo;
	PKC_INFO contextData, *pkcInfo = &contextData;
	int length, status;

	assert( isWritePtr( dlpKeyInfo, sizeof( CRYPT_PKCINFO_DLP ) ) );

	REQUIRES( keySizeBits >= bytesToBits( MIN_PKCSIZE ) && \
			  keySizeBits <= bytesToBits( CRYPT_MAX_PKCSIZE ) );
	REQUIRES( cryptAlgo == CRYPT_ALGO_DH || \
			  cryptAlgo == CRYPT_ALGO_DSA || \
			  cryptAlgo == CRYPT_ALGO_ELGAMAL );

	/* Clear return value */
	cryptInitComponents( dlpKeyInfo, FALSE );

	/* Generate the key components */
	switch( cryptAlgo )
		{
#ifdef USE_DH
		case CRYPT_ALGO_DH:
			status = generateKeyComponents( &staticContextInfo, &contextData, 
											getDHCapability(), keySizeBits );
			break;
#endif /* USE_DH */

#ifdef USE_DSA
		case CRYPT_ALGO_DSA:
			status = generateKeyComponents( &staticContextInfo, &contextData, 
											getDSACapability(), keySizeBits );
			break;
#endif /* USE_DSA */

#ifdef USE_ELGAMAL
		case CRYPT_ALGO_ELGAMAL:
			status = generateKeyComponents( &staticContextInfo, &contextData, 
											getElgamalCapability(), keySizeBits );
			break;
#endif /* USE_ELGAMAL */

		default:
			retIntError();
		}
	if( cryptStatusError( status ) )
		return( status );

	/* Extract the newly-generated key components for the caller to use */
	dlpKeyInfo->pLen = BN_num_bits( &pkcInfo->dlpParam_p );
	length = BN_bn2bin( &pkcInfo->dlpParam_p, dlpKeyInfo->p );
	ENSURES( length == bitsToBytes( dlpKeyInfo->pLen ) );
	dlpKeyInfo->gLen = BN_num_bits( &pkcInfo->dlpParam_g );
	length = BN_bn2bin( &pkcInfo->dlpParam_g, dlpKeyInfo->g );
	ENSURES( length == bitsToBytes( dlpKeyInfo->gLen ) );
	dlpKeyInfo->qLen = BN_num_bits( &pkcInfo->dlpParam_q );
	length = BN_bn2bin( &pkcInfo->dlpParam_q, dlpKeyInfo->q );
	ENSURES( length == bitsToBytes( dlpKeyInfo->qLen ) );
	dlpKeyInfo->yLen = BN_num_bits( &pkcInfo->dlpParam_y );
	length = BN_bn2bin( &pkcInfo->dlpParam_y, dlpKeyInfo->y );
	ENSURES( length == bitsToBytes( dlpKeyInfo->yLen ) );
	dlpKeyInfo->xLen = BN_num_bits( &pkcInfo->dlpParam_x );
	length = BN_bn2bin( &pkcInfo->dlpParam_x, dlpKeyInfo->x );
	ENSURES( length == bitsToBytes( dlpKeyInfo->xLen ) );
	staticDestroyContext( &staticContextInfo );

	return( status );
	}