예제 #1
0
파일: obj_qry.c 프로젝트: TellarHK/wwiv
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 );
	}
예제 #2
0
static int checkPkiUserInfo( INOUT SESSION_INFO *sessionInfoPtr,
							 INOUT SCEP_PROTOCOL_INFO *protocolInfo )
	{
	const ATTRIBUTE_LIST *userNamePtr = \
				findSessionInfo( sessionInfoPtr->attributeList,
								 CRYPT_SESSINFO_USERNAME );
	MESSAGE_KEYMGMT_INFO getkeyInfo;
	MESSAGE_DATA msgData;
	BYTE keyID[ 64 + 8 ];
	BYTE requestPassword[ CRYPT_MAX_TEXTSIZE + 8 ];
	BYTE userPassword[ CRYPT_MAX_TEXTSIZE + 8 ];
	int requestPasswordSize, userPasswordSize = DUMMY_INIT;
	int keyIDsize, status;

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

	REQUIRES( userNamePtr != NULL );
	
	/* Get the password from the PKCS #10 request */
	setMessageData( &msgData, requestPassword, CRYPT_MAX_TEXTSIZE );
	status = krnlSendMessage( sessionInfoPtr->iCertRequest, 
							  IMESSAGE_GETATTRIBUTE_S, &msgData, 
							  CRYPT_CERTINFO_CHALLENGEPASSWORD );
	if( cryptStatusError( status ) )
		{
		retExt( status,
				( status, SESSION_ERRINFO, 
				  "Couldn't get challenge password from PKCS #10 request" ) );
		}
	requestPasswordSize = msgData.length;

	/* Since it's a cryptlib encoded user ID we need to decode it before we 
	   can look up a PKI user with it */
	REQUIRES( userNamePtr->flags & ATTR_FLAG_ENCODEDVALUE );
	status = decodePKIUserValue( keyID, 64, &keyIDsize,
								 userNamePtr->value, 
								 userNamePtr->valueLength );
	ENSURES( cryptStatusOK( status ) );

	/* Get the user information for the request from the certificate 
	   store */
	setMessageKeymgmtInfo( &getkeyInfo, CRYPT_IKEYID_KEYID, keyID, 
						   keyIDsize, NULL, 0, KEYMGMT_FLAG_NONE );
	status = krnlSendMessage( sessionInfoPtr->cryptKeyset,
							  IMESSAGE_KEY_GETKEY, &getkeyInfo, 
							  KEYMGMT_ITEM_PKIUSER );
	if( cryptStatusError( status ) )
		{
		char userID[ CRYPT_MAX_TEXTSIZE + 8 ];
		int userIDlen;

		zeroise( requestPassword, CRYPT_MAX_TEXTSIZE );
		userIDlen = min( userNamePtr->valueLength, CRYPT_MAX_TEXTSIZE );
		memcpy( userID, userNamePtr->value, userIDlen );
		retExtObj( status, 
				   ( status, SESSION_ERRINFO, sessionInfoPtr->cryptKeyset,
					 "Couldn't find PKI user information for %s",
					 sanitiseString( userID, CRYPT_MAX_TEXTSIZE, 
									 userIDlen ) ) );
		}

	/* Get the password from the PKI user object */
	setMessageData( &msgData, userPassword, CRYPT_MAX_TEXTSIZE );
	status = krnlSendMessage( getkeyInfo.cryptHandle, 
							  IMESSAGE_GETATTRIBUTE_S, &msgData,
							  CRYPT_CERTINFO_PKIUSER_ISSUEPASSWORD );
	if( cryptStatusOK( status ) )
		{
		userPasswordSize = msgData.length;
		status = updateSessionInfo( &sessionInfoPtr->attributeList, 
									CRYPT_SESSINFO_PASSWORD, 
									userPassword, userPasswordSize, 
									CRYPT_MAX_TEXTSIZE, 
									ATTR_FLAG_ENCODEDVALUE );
		}
	if( cryptStatusError( status ) )
		{
		zeroise( requestPassword, CRYPT_MAX_TEXTSIZE );
		zeroise( userPassword, CRYPT_MAX_TEXTSIZE );
		krnlSendNotifier( getkeyInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
		retExt( status, 
				( status, SESSION_ERRINFO, 
				  "Couldn't copy read PKI user data from PKI user object "
				  "into session object" ) );
		}

	/* Make sure that the password matches the one in the request */
	if( userPasswordSize != requestPasswordSize || \
		!compareDataConstTime( userPassword, requestPassword, 
							   userPasswordSize ) )
		{
		zeroise( requestPassword, CRYPT_MAX_TEXTSIZE );
		zeroise( userPassword, CRYPT_MAX_TEXTSIZE );
		krnlSendNotifier( getkeyInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
		retExt( status, 
				( status, SESSION_ERRINFO, 
				  "Password in PKCS #10 request doesn't match PKI user "
				  "password" ) );
		}
	zeroise( userPassword, CRYPT_MAX_TEXTSIZE );

	/* If the subject only knows their CN, they may send a CN-only subject DN 
	   in the hope that we can fill it in for them.  In addition there may be 
	   other constraints that the CA wants to apply, these are handled by
	   applying the PKI user information to the request */
	status = krnlSendMessage( sessionInfoPtr->iCertRequest,
							  IMESSAGE_SETATTRIBUTE, &getkeyInfo.cryptHandle,
							  CRYPT_IATTRIBUTE_PKIUSERINFO );
	krnlSendNotifier( getkeyInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
	if( cryptStatusError( status ) )
		{
		retExt( CRYPT_ERROR_INVALID, 
				( CRYPT_ERROR_INVALID, SESSION_ERRINFO, 
				  "User information in PKCS #10 request can't be "
				  "reconciled with stored information for the user" ) );
		}

	return( CRYPT_OK );
	}
예제 #3
0
static int checkScepRequest( INOUT SESSION_INFO *sessionInfoPtr,
							 INOUT SCEP_PROTOCOL_INFO *protocolInfo, 
							 OUT BOOLEAN *requestDataAvailable )
	{
	CRYPT_CERTIFICATE iCmsAttributes;
	MESSAGE_CREATEOBJECT_INFO createInfo;
	MESSAGE_DATA msgData;
	int dataLength, sigResult, value, status;

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( isWritePtr( protocolInfo, sizeof( SCEP_PROTOCOL_INFO ) ) );
	assert( isWritePtr( requestDataAvailable, sizeof( BOOLEAN ) ) );

	/* Clear return value */
	*requestDataAvailable = FALSE;

	/* Phase 1: Sig-check the self-signed data */
	DEBUG_DUMP_FILE( "scep_sreq2", sessionInfoPtr->receiveBuffer, 
					 sessionInfoPtr->receiveBufEnd );
	status = envelopeSigCheck( sessionInfoPtr->receiveBuffer, 
							   sessionInfoPtr->receiveBufEnd,
							   sessionInfoPtr->receiveBuffer, 
							   sessionInfoPtr->receiveBufSize, &dataLength, 
							   CRYPT_UNUSED, &sigResult, 
							   &protocolInfo->iScepCert, &iCmsAttributes );
	if( cryptStatusError( status ) )
		{
		retExt( status, 
				( status, SESSION_ERRINFO, 
				  "Invalid CMS signed data in client request" ) );
		}
	DEBUG_DUMP_FILE( "scep_sreq1", sessionInfoPtr->receiveBuffer, 
					 dataLength );
	if( cryptStatusError( sigResult ) )
		{
		/* The signed data was valid but the signature on it wasn't, this is
		   a different style of error than the previous one */
		krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
		retExt( sigResult, 
				( sigResult, SESSION_ERRINFO, 
				  "Bad signature on client request data" ) );
		}

	/* Make sure that the client certificate is valid for signing and 
	   decryption.  In effect the signing capability has already been 
	   checked by the fact that the certificate signed the request but we do 
	   an explicit check here just to be thorough */
	status = krnlSendMessage( protocolInfo->iScepCert, IMESSAGE_CHECK, 
							  NULL, MESSAGE_CHECK_PKC_SIGCHECK );
	if( cryptStatusOK( status ) )
		status = krnlSendMessage( protocolInfo->iScepCert, IMESSAGE_CHECK, 
								  NULL, MESSAGE_CHECK_PKC_ENCRYPT );
	if( cryptStatusError( status ) )
		{
		krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
		retExt( CRYPT_ERROR_INVALID, 
				( CRYPT_ERROR_INVALID, SESSION_ERRINFO, 
				  "Ephemeral SCEP client certificate isn't valid for "
				  "signing/encryption" ) );
		}

	/* Get the nonce and transaction ID and save it for the reply */
	setMessageData( &msgData, protocolInfo->nonce, CRYPT_MAX_HASHSIZE );
	status = krnlSendMessage( iCmsAttributes, IMESSAGE_GETATTRIBUTE_S,
							  &msgData, CRYPT_CERTINFO_SCEP_SENDERNONCE );
	if( cryptStatusOK( status ) )
		{
		protocolInfo->nonceSize = msgData.length;
		setMessageData( &msgData, protocolInfo->transID, CRYPT_MAX_HASHSIZE );
		status = krnlSendMessage( iCmsAttributes, IMESSAGE_GETATTRIBUTE_S,
								  &msgData,
								  CRYPT_CERTINFO_SCEP_TRANSACTIONID );
		}
	if( cryptStatusError( status ) )
		{
		krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
		retExt( CRYPT_ERROR_BADDATA,
				( CRYPT_ERROR_BADDATA, SESSION_ERRINFO, 
				  "Request is missing a nonce/transaction ID" ) );
		}
	protocolInfo->transIDsize = msgData.length;

	/* We've now got enough request data available to construct a SCEP-level 
	   response to an error instead of an HTTP-level one, let the caller 
	   know.  Note that this lets an attacker know that they've made it this
	   far in the checking, but it's not obvious that this is a security
	   problem, especially since they can get a good idea of how far they 
	   got from the different error conditions that will be returned */
	*requestDataAvailable = TRUE;

	/* Since the request is for a cryptlib server it'll have a transaction 
	   ID that's a cryptlib-encoded PKI user ID.  If we don't get this then 
	   we reject the request */
	if( protocolInfo->transIDsize != 17 || \
		!isPKIUserValue( protocolInfo->transID, protocolInfo->transIDsize ) )
		{
		krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
		retExt( CRYPT_ERROR_BADDATA,
				( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
				  "Request has an invalid transaction ID '%s'",
				  sanitiseString( protocolInfo->transID, 
								  protocolInfo->transIDsize,
				  				  protocolInfo->transIDsize ) ) );
		}
	status = updateSessionInfo( &sessionInfoPtr->attributeList,
								CRYPT_SESSINFO_USERNAME, 
								protocolInfo->transID, 
								protocolInfo->transIDsize, 
								CRYPT_MAX_TEXTSIZE, ATTR_FLAG_ENCODEDVALUE );
	if( cryptStatusError( status ) )
		{
		krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
		return( status );
		}

	/* Check that we've been sent the correct type of message */
	status = getScepStatusValue( iCmsAttributes,
								 CRYPT_CERTINFO_SCEP_MESSAGETYPE, &value );
	if( cryptStatusOK( status ) && value != MESSAGETYPE_PKCSREQ_VALUE )
		status = CRYPT_ERROR_BADDATA;
	krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
	if( cryptStatusError( status ) )
		{
		retExt( status, 
				( status, SESSION_ERRINFO, 
				  "Incorrect SCEP message type %d", value ) );
		}

	/* Phase 2: Decrypt the data using our CA key */
	status = envelopeUnwrap( sessionInfoPtr->receiveBuffer, dataLength,
							 sessionInfoPtr->receiveBuffer, 
							 sessionInfoPtr->receiveBufSize, &dataLength, 
							 sessionInfoPtr->privateKey );
	if( cryptStatusError( status ) )
		{
		retExt( status, 
				( status, SESSION_ERRINFO, 
				  "Couldn't decrypt CMS enveloped data in client request" ) );
		}

	/* Finally, import the request as a PKCS #10 request */
	setMessageCreateObjectIndirectInfo( &createInfo,
								sessionInfoPtr->receiveBuffer, dataLength,
								CRYPT_CERTTYPE_CERTREQUEST );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
							  IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
							  &createInfo, OBJECT_TYPE_CERTIFICATE );
	if( cryptStatusError( status ) )
		{
		retExt( status, 
				( status, SESSION_ERRINFO, 
				  "Invalid PKCS #10 request in client request" ) );
		}
	sessionInfoPtr->iCertRequest = createInfo.cryptHandle;

	return( CRYPT_OK );
	}
예제 #4
0
static int selfTest( void )
	{
#if 0
	/* ECB */
	static const BYTE FAR_BSS mctECBKey[] = \
		{ 0x8D, 0x2E, 0x60, 0x36, 0x5F, 0x17, 0xC7, 0xDF, 0x10, 0x40, 0xD7, 0x50, 0x1B, 0x4A, 0x7B, 0x5A };
	static const BYTE FAR_BSS mctECBPT[] = \
		{ 0x59, 0xB5, 0x08, 0x8E, 0x6D, 0xAD, 0xC3, 0xAD, 0x5F, 0x27, 0xA4, 0x60, 0x87, 0x2D, 0x59, 0x29 };
	/* CBC */
	static const BYTE FAR_BSS mctCBCKey[] = \
		{ 0x9D, 0xC2, 0xC8, 0x4A, 0x37, 0x85, 0x0C, 0x11, 0x69, 0x98, 0x18, 0x60, 0x5F, 0x47, 0x95, 0x8C };
	static const BYTE FAR_BSS mctCBCIV[] = \
		{ 0x25, 0x69, 0x53, 0xB2, 0xFE, 0xAB, 0x2A, 0x04, 0xAE, 0x01, 0x80, 0xD8, 0x33, 0x5B, 0xBE, 0xD6 };
	static const BYTE FAR_BSS mctCBCPT[] = \
		{ 0x2E, 0x58, 0x66, 0x92, 0xE6, 0x47, 0xF5, 0x02, 0x8E, 0xC6, 0xFA, 0x47, 0xA5, 0x5A, 0x2A, 0xAB };
	/* OFB */
	static const BYTE FAR_BSS mctOFBKey[] = \
		{ 0xB1, 0x1E, 0x4E, 0xCA, 0xE2, 0xE7, 0x1E, 0x14, 0x14, 0x5D, 0xD7, 0xDB, 0x26, 0x35, 0x65, 0x2F };
	static const BYTE FAR_BSS mctOFBIV[] = \
		{ 0xAD, 0xD3, 0x2B, 0xF8, 0x20, 0x4C, 0x33, 0x33, 0x9C, 0x54, 0xCD, 0x58, 0x58, 0xEE, 0x0D, 0x13 };
	static const BYTE FAR_BSS mctOFBPT[] = \
		{ 0x73, 0x20, 0x49, 0xE8, 0x9D, 0x74, 0xFC, 0xE7, 0xC5, 0xA4, 0x96, 0x64, 0x04, 0x86, 0x8F, 0xA6 };
	/* CFB-128 */
	static const BYTE FAR_BSS mctCFBKey[] = \
		{ 0x71, 0x15, 0x11, 0x93, 0x1A, 0x15, 0x62, 0xEA, 0x73, 0x29, 0x0A, 0x8B, 0x0A, 0x37, 0xA3, 0xB4 };
	static const BYTE FAR_BSS mctCFBIV[] = \
		{ 0x9D, 0xCE, 0x23, 0xFD, 0x2D, 0xF5, 0x36, 0x0F, 0x79, 0x9C, 0xF1, 0x79, 0x84, 0xE4, 0x7C, 0x8D };
	static const BYTE FAR_BSS mctCFBPT[] = \
		{ 0xF0, 0x66, 0xBE, 0x4B, 0xD6, 0x71, 0xEB, 0xC1, 0xC4, 0xCF, 0x3C, 0x00, 0x8E, 0xF2, 0xCF, 0x18 };
#endif /* 0 */
	const CAPABILITY_INFO *capabilityInfo = getAESCapability();
	BYTE keyData[ AES_EXPANDED_KEYSIZE + 8 ];
	int i, status;

	/* The AES code requires 16-byte alignment for data structures, before 
	   we try anything else we make sure that the compiler voodoo required
	   to handle this has worked */
	if( aes_test_alignment_detection( 16 ) != EXIT_SUCCESS  )
		return( CRYPT_ERROR_FAILED );

	for( i = 0; i < sizeof( testAES ) / sizeof( AES_TEST ); i++ )
		{
		status = testCipher( capabilityInfo, keyData, testAES[ i ].key, 
							 testAES[ i ].keySize, testAES[ i ].plaintext,
							 testAES[ i ].ciphertext );
		if( cryptStatusError( status ) )
			return( status );
		}

#if 0	/* OK */
	staticInitContext( &contextInfo, CONTEXT_CONV, capabilityInfo,
					   &contextData, sizeof( CONV_INFO ), keyData );
	status = mct( &contextInfo, capabilityInfo, mctECBKey, 16, 
				  NULL, mctECBPT );
	staticDestroyContext( &contextInfo );
	if( cryptStatusError( status ) )
		return( CRYPT_ERROR_FAILED );
#endif
#if 0	/* OK */
	staticInitContext( &contextInfo, CONTEXT_CONV, capabilityInfo,
					   &contextData, sizeof( CONV_INFO ), keyData );
	status = mct( &contextInfo, capabilityInfo, mctCBCKey, 16, 
				  mctCBCIV, mctCBCPT );
	staticDestroyContext( &contextInfo );
	if( cryptStatusError( status ) )
		return( CRYPT_ERROR_FAILED );
#endif

	return( CRYPT_OK );
	}
예제 #5
0
파일: keyex_rw.c 프로젝트: TellarHK/wwiv
static int readKeyDerivationInfo( INOUT STREAM *stream, 
								  OUT QUERY_INFO *queryInfo )
	{
	long endPos, value;
	int length, status;

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

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

	/* Read the outer wrapper and key derivation algorithm OID */
	readConstructed( stream, NULL, CTAG_KK_DA );
	status = readFixedOID( stream, OID_PBKDF2, sizeofOID( OID_PBKDF2 ) );
	if( cryptStatusError( status ) )
		return( status );

	/* Read the PBKDF2 parameters, limiting the salt and iteration count to
	   sane values */
	status = readSequence( stream, &length );
	if( cryptStatusError( status ) )
		return( status );
	endPos = stell( stream ) + length;
	readOctetString( stream, queryInfo->salt, &queryInfo->saltLength, 
					 2, CRYPT_MAX_HASHSIZE );
	status = readShortInteger( stream, &value );
	if( cryptStatusError( status ) )
		return( status );
	if( value < 1 || value > MAX_KEYSETUP_ITERATIONS )
		return( CRYPT_ERROR_BADDATA );
	queryInfo->keySetupIterations = ( int ) value;
	queryInfo->keySetupAlgo = CRYPT_ALGO_HMAC_SHA1;
	if( stell( stream ) < endPos && \
		sPeek( stream ) == BER_INTEGER )
		{
		/* There's an optional key length that may override the default 
		   key size present, read it.  Note that we compare the upper
		   bound to MAX_WORKING_KEYSIZE rather than CRYPT_MAX_KEYSIZE,
		   since this is a key used directly with an encryption algorithm
		   rather than a generic keying value that may be hashed down to 
		   size */
		status = readShortInteger( stream, &value );
		if( cryptStatusError( status ) )
			return( status );
		if( value < MIN_KEYSIZE || value > MAX_WORKING_KEYSIZE )
			return( CRYPT_ERROR_BADDATA );
		queryInfo->keySize = ( int ) value;
		}
	if( stell( stream ) < endPos )
		{
		CRYPT_ALGO_TYPE prfAlgo;
	
		/* There's a non-default hash algorithm ID present, read it */
		status = readAlgoID( stream, &prfAlgo, ALGOID_CLASS_HASH );
		if( cryptStatusError( status ) )
			return( status );
		queryInfo->keySetupAlgo = prfAlgo;
		}

	return( CRYPT_OK );
	}
예제 #6
0
static int addStandardExtensions( INOUT CERT_INFO *certInfoPtr )
	{
	BOOLEAN isCA = FALSE;
	int keyUsage, extKeyUsage, value, status;

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

	/* Get the implicit keyUsage flags (based on any extended key usage 
	   extensions present) and explicit key usage flags, which we use to 
	   extend the basic keyUsage flags if required */
 	status = getKeyUsageFromExtKeyUsage( certInfoPtr, &extKeyUsage,
						&certInfoPtr->errorLocus, &certInfoPtr->errorType );
	if( cryptStatusError( status ) )
		return( status );
	status = getAttributeFieldValue( certInfoPtr->attributes,
									 CRYPT_CERTINFO_KEYUSAGE,
									 CRYPT_ATTRIBUTE_NONE, &keyUsage );
	if( cryptStatusError( status ) )
		{
		if( status != CRYPT_ERROR_NOTFOUND )
			return( status );

		/* There's no keyUsage attribute present, mark the value as being 
		   not set so that we explicitly set it later */
		keyUsage = CRYPT_ERROR;
		}

	/* If there's an explicit key usage present, make sure that it's
	   consistent with the implicit key usage flags derived from the 
	   extended key usage.  We mask out the nonRepudiation bit for reasons 
	   given in chk_cert.c.

	   This check is also performed by checkCert(), however we need to
	   explicitly perform it here as well since we need to add a key usage 
	   to match the extKeyUsage before calling checkCert() if one wasn't
	   explicitly set or checkCert() will reject the certificate because of 
	   the inconsistent keyUsage */
	if( keyUsage > 0 )
		{
		const int effectiveKeyUsage = \
						extKeyUsage & ~CRYPT_KEYUSAGE_NONREPUDIATION;

		if( ( keyUsage & effectiveKeyUsage ) != effectiveKeyUsage )
			{
			setErrorInfo( certInfoPtr, CRYPT_CERTINFO_KEYUSAGE,
						  CRYPT_ERRTYPE_CONSTRAINT );
			return( CRYPT_ERROR_INVALID );
			}
		}

	/* Check whether this is a CA certificate.  If there's no 
	   basicConstraints attribute present, add one and make it a non-CA 
	   certificate */
	status = getAttributeFieldValue( certInfoPtr->attributes,
									 CRYPT_CERTINFO_CA, CRYPT_ATTRIBUTE_NONE,
									 &value );
	if( cryptStatusOK( status ) )
		isCA = ( value > 0 ) ? TRUE : FALSE;
	else
		{
		status = addCertComponent( certInfoPtr, CRYPT_CERTINFO_CA, FALSE );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* If there's no explicit keyUsage information present add it based on
	   various implicit information.  We also add key feature information
	   which is used to help automate key management, for example to inhibit
	   speculative reads of keys held in removable tokens, which can result
	   in spurious insert-token dialogs being presented to the user outside
	   the control of cryptlib if the token isn't present */
	if( keyUsage <= 0 )
		{
		/* If there's no implicit key usage present and it's not a CA (for 
		   which we don't want to set things like encryption flags for the
		   CA certificate), set the key usage flags based on the 
		   capabilities of the associated context.  Because no-one can 
		   figure out what the nonRepudiation flag signifies we don't set 
		   this, if the user wants it they have to specify it explicitly.  
		   Similarly we don't try and set the keyAgreement encipher/decipher-
		   only flags, which were tacked on as variants of keyAgreement long 
		   after the basic keyAgreement flag was defined */
		if( extKeyUsage <= 0 && !isCA )
			{
			keyUsage = 0;	/* Reset key usage */
			if( certInfoPtr->iPubkeyContext != CRYPT_ERROR )
				{
				/* There's a context present, check its capabilities.  This
				   has the advantage that it takes into account any ACLs
				   that may exist for the key */
				if( cryptStatusOK( \
						krnlSendMessage( certInfoPtr->iPubkeyContext, 
										 IMESSAGE_CHECK, NULL, 
										 MESSAGE_CHECK_PKC_SIGCHECK ) ) )
					keyUsage = CRYPT_KEYUSAGE_DIGITALSIGNATURE;
				if( cryptStatusOK( \
						krnlSendMessage( certInfoPtr->iPubkeyContext, 
										 IMESSAGE_CHECK, NULL, 
										 MESSAGE_CHECK_PKC_ENCRYPT ) ) )
					keyUsage |= CRYPT_KEYUSAGE_KEYENCIPHERMENT;
				if( cryptStatusOK( \
						krnlSendMessage( certInfoPtr->iPubkeyContext, 
										 IMESSAGE_CHECK, NULL, 
										 MESSAGE_CHECK_PKC_KA_EXPORT ) ) || \
					cryptStatusOK( \
						krnlSendMessage( certInfoPtr->iPubkeyContext, 
										 IMESSAGE_CHECK, NULL, 
										 MESSAGE_CHECK_PKC_KA_IMPORT ) ) )
					keyUsage |= CRYPT_KEYUSAGE_KEYAGREEMENT;
				}
			else
				{
				/* There's no context present (the key is present as encoded
				   data), assume we can do whatever the algorithm allows */
				if( isSigAlgo( certInfoPtr->publicKeyAlgo ) )
					keyUsage = CRYPT_KEYUSAGE_DIGITALSIGNATURE;
				if( isCryptAlgo( certInfoPtr->publicKeyAlgo ) )
					keyUsage |= CRYPT_KEYUSAGE_KEYENCIPHERMENT;
				if( isKeyxAlgo( certInfoPtr->publicKeyAlgo ) )
					keyUsage |= CRYPT_KEYUSAGE_KEYAGREEMENT;
				}
			}
		else
			{
			/* There's an extended key usage set but no basic keyUsage, make 
			   the keyUsage consistent with the usage flags derived from the 
			   extended usage */
			keyUsage = extKeyUsage;

			/* If it's a CA key, make sure that it's a signing key and
			   enable its use for certification-related purposes*/
			if( isCA )
				{
				BOOLEAN usageOK;

				if( certInfoPtr->iPubkeyContext != CRYPT_ERROR )
					{
					usageOK = cryptStatusOK( \
								krnlSendMessage( certInfoPtr->iPubkeyContext, 
												 IMESSAGE_CHECK, NULL, 
												 MESSAGE_CHECK_PKC_SIGCHECK ) );
					}
				else
					usageOK = isSigAlgo( certInfoPtr->publicKeyAlgo );
				if( !usageOK )
					{
					setErrorInfo( certInfoPtr, CRYPT_CERTINFO_CA,
								  CRYPT_ERRTYPE_CONSTRAINT );
					return( CRYPT_ERROR_INVALID );
					}
				keyUsage |= KEYUSAGE_CA;
				}
			}
		ENSURES( keyUsage > CRYPT_KEYUSAGE_NONE && \
				 keyUsage < CRYPT_KEYUSAGE_LAST );
		status = addCertComponent( certInfoPtr, CRYPT_CERTINFO_KEYUSAGE,
								   keyUsage );
		if( cryptStatusError( status ) )
			return( status );
		}
	if( certInfoPtr->publicKeyFeatures > 0 )
		{
		/* This is a bitstring so we only add it if there are feature flags
		   present to avoid writing zero-length values */
		status = addCertComponent( certInfoPtr, CRYPT_CERTINFO_KEYFEATURES,
								   certInfoPtr->publicKeyFeatures );
		if( cryptStatusError( status ) && status != CRYPT_ERROR_INITED )
			return( status );
		}

	/* Add the subjectKeyIdentifier */
	return( addCertComponentString( certInfoPtr, 
									CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER,
									certInfoPtr->publicKeyID, KEYID_SIZE ) );
	}
예제 #7
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 );
	}
예제 #8
0
static int preEncodeDN( INOUT DN_COMPONENT *dnComponentPtr, 
						OUT_LENGTH_SHORT_Z int *length )
	{
	int size = 0, iterationCount;

	assert( isWritePtr( dnComponentPtr, sizeof( DN_COMPONENT ) ) );
	assert( isWritePtr( length, sizeof( int ) ) );

	/* Clear return value */
	*length = 0;

	assert( isReadPtr( dnComponentPtr, sizeof( DN_COMPONENT ) ) );

#if 0	/* 18/7/08 Should never happen */
	/* If we're being fed an entry in the middle of a DN, move back to the
	   start */
	for( iterationCount = 0;
		 dnComponentPtr->prev != NULL && \
			iterationCount < FAILSAFE_ITERATIONS_MED;
		 dnComponentPtr = dnComponentPtr->prev, iterationCount++ );
	ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
#endif /* 0 */
	ENSURES( dnComponentPtr->prev == NULL );

	/* Walk down the DN pre-encoding each AVA */
	for( iterationCount = 0;
		 dnComponentPtr != NULL && iterationCount < FAILSAFE_ITERATIONS_MED; 
		 dnComponentPtr = dnComponentPtr->next, iterationCount++ )
		{
		DN_COMPONENT *rdnStartPtr = dnComponentPtr;
		int innerIterationCount;

		/* Calculate the size of every AVA in this RDN */
		for( innerIterationCount = 0;
			 dnComponentPtr != NULL && \
				innerIterationCount < FAILSAFE_ITERATIONS_MED;
			 dnComponentPtr = dnComponentPtr->next, innerIterationCount++ )
			{
			const DN_COMPONENT_INFO *dnComponentInfo = dnComponentPtr->typeInfo;
			int dnStringLength, status;

			status = getAsn1StringInfo( dnComponentPtr->value, 
										dnComponentPtr->valueLength,
										&dnComponentPtr->valueStringType, 
										&dnComponentPtr->asn1EncodedStringType,
										&dnStringLength );
			if( cryptStatusError( status ) )
				return( status );
			dnComponentPtr->encodedAVAdataSize = ( int ) \
										sizeofOID( dnComponentInfo->oid ) + \
										sizeofObject( dnStringLength );
			dnComponentPtr->encodedRDNdataSize = 0;
			rdnStartPtr->encodedRDNdataSize += ( int ) \
						sizeofObject( dnComponentPtr->encodedAVAdataSize );
			if( !( dnComponentPtr->flags & DN_FLAG_CONTINUED ) )
				break;
			}
		ENSURES( innerIterationCount < FAILSAFE_ITERATIONS_MED );

		/* Calculate the overall size of the RDN */
		size += ( int ) sizeofObject( rdnStartPtr->encodedRDNdataSize );

		/* If the inner loop terminated because it reached the end of the DN 
		   then we need to explicitly exit the outer loop as well before it
		   tries to follow the 'next' link in the dnComponentPtr */
		if( dnComponentPtr == NULL )
			break;
		}
	ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
	*length = size;

	return( CRYPT_OK );
	}
예제 #9
0
int writeDN( INOUT STREAM *stream, 
			 IN_OPT const DN_PTR *dnComponentList,
			 IN_TAG const int tag )
	{
	DN_COMPONENT *dnComponentPtr;
	int size, iterationCount, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( dnComponentList == NULL || \
			isReadPtr( dnComponentList, sizeof( DN_COMPONENT ) ) );

	REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );

	/* Special case for empty DNs */
	if( dnComponentList == NULL )
		return( writeConstructed( stream, 0, tag ) );

	status = preEncodeDN( ( DN_COMPONENT * ) dnComponentList, &size );
	if( cryptStatusError( status ) )
		return( status );

	/* Write the DN */
	writeConstructed( stream, size, tag );
	for( dnComponentPtr = ( DN_COMPONENT * ) dnComponentList, \
			iterationCount = 0;
		 dnComponentPtr != NULL && \
			iterationCount < FAILSAFE_ITERATIONS_MED;
		 dnComponentPtr = dnComponentPtr->next, iterationCount++ )
		{
		const DN_COMPONENT_INFO *dnComponentInfo = dnComponentPtr->typeInfo;
		BYTE dnString[ MAX_ATTRIBUTE_SIZE + 8 ];
		int dnStringLength;

		/* Write the RDN wrapper */
		if( dnComponentPtr->encodedRDNdataSize > 0 )
			{
			/* If it's the start of an RDN, write the RDN header */
			writeSet( stream, dnComponentPtr->encodedRDNdataSize );
			}
		writeSequence( stream, dnComponentPtr->encodedAVAdataSize );
		status = swrite( stream, dnComponentInfo->oid, 
						 sizeofOID( dnComponentInfo->oid ) );
		if( cryptStatusError( status ) )
			return( status );

		/* Convert the string to an ASN.1-compatible format and write it
		   out */
		status = copyToAsn1String( dnString, MAX_ATTRIBUTE_SIZE, 
								   &dnStringLength, dnComponentPtr->value,
								   dnComponentPtr->valueLength,
								   dnComponentPtr->valueStringType );
		if( cryptStatusError( status ) )
			return( status );
		if( dnComponentPtr->asn1EncodedStringType == BER_STRING_IA5 && \
			!dnComponentInfo->ia5OK )
			{
			/* If an IA5String isn't allowed in this instance, use a
			   T61String instead */
			dnComponentPtr->asn1EncodedStringType = BER_STRING_T61;
			}
		status = writeCharacterString( stream, dnString, dnStringLength,
									   dnComponentPtr->asn1EncodedStringType );
		if( cryptStatusError( status ) )
			return( status );
		}
	ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );

	return( CRYPT_OK );
	}
예제 #10
0
CHECK_RETVAL \
int deviceInitPKCS11( void )
	{
	int tblIndex = 0, optionIndex, status;

	/* If we've previously tried to initialise the drivers, don't try it 
	   again */
	if( pkcs11Initialised )
		return( CRYPT_OK );
	memset( pkcs11InfoTbl, 0, sizeof( pkcs11InfoTbl ) );

	/* Try and link in each driver specified in the config options.  Since
	   this is a general systemwide config option, we always query the built-
	   in default user object */
	for( optionIndex = 0; optionIndex < MAX_PKCS11_DRIVERS; optionIndex++ )
		{
		MESSAGE_DATA msgData;
		char deviceDriverName[ MAX_PATH_LENGTH + 1 + 8 ];

		setMessageData( &msgData, deviceDriverName, MAX_PATH_LENGTH );
		status = krnlSendMessage( DEFAULTUSER_OBJECT_HANDLE, 
						IMESSAGE_GETATTRIBUTE_S, &msgData, 
						optionIndex + CRYPT_OPTION_DEVICE_PKCS11_DVR01 );
		if( cryptStatusError( status ) )
			continue;
		deviceDriverName[ msgData.length ] = '\0';
		status = loadPKCS11driver( &pkcs11InfoTbl[ tblIndex ], 
								   deviceDriverName );
		if( cryptStatusOK( status ) )
			{
			tblIndex++;
			pkcs11Initialised = TRUE;
			}
		}

	/* If it's a Unix system and there were no drivers explicitly specified,
	   try with the default driver name "libpkcs11.so".  Unlike Windows,
	   where there are large numbers of PKCS #11 vendors and we have to use
	   vendor-specific names, under Unix there are very few vendors and 
	   there's usually only one device/driver in use which inevitably 
	   co-opts /usr/lib for its own use, so we can always try for a standard
	   name and location.  As a backup measure we also try for the nCipher 
	   PKCS #11 driver, which is by far the most commonly used one on Unix 
	   systems (this may sometimes be found as /usr/lib/libcknfast.so).

	   An unfortunate side-effect of this handling is that if there's more
	   than one PKCS #11 driver present and the user forgets to explicitly
	   specify it then this may load the wrong one, however the chances of
	   there being multiple drivers present on a Unix system is close to 
	   zero so it's probably better to take the more user-friendly option
	   of trying to load a default driver */
#ifdef __UNIX__
	if( !pkcs11Initialised )
		{
		status = loadPKCS11driver( &pkcs11InfoTbl[ tblIndex ], 
								   "libpkcs11.so" );
		if( cryptStatusOK( status ) )
			pkcs11Initialised = TRUE;
		}
	if( !pkcs11Initialised )
		{
		status = loadPKCS11driver( &pkcs11InfoTbl[ tblIndex ], 
								   "/opt/nfast/toolkits/pkcs11/libcknfast.so" );
		if( cryptStatusOK( status ) )
			pkcs11Initialised = TRUE;
		}
#endif /* __UNIX__ */
	
	return( pkcs11Initialised ? CRYPT_OK : CRYPT_ERROR );
	}
예제 #11
0
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 );
	}
예제 #12
0
파일: sign_x509.c 프로젝트: TellarHK/wwiv
						 IN_LENGTH const int objectLength,
						 IN_HANDLE const CRYPT_CONTEXT iSignContext,
						 IN_ALGO const CRYPT_ALGO_TYPE hashAlgo,
						 IN_OPT const X509SIG_FORMATINFO *formatInfo )
	{
	CRYPT_CONTEXT iHashContext;
	MESSAGE_CREATEOBJECT_INFO createInfo;
	STREAM stream;
	BYTE dataSignature[ CRYPT_MAX_PKCSIZE + 128 + 8 ];
	int signatureLength, totalSigLength, status;

	assert( signedObject == NULL || \
			isWritePtr( signedObject, signedObjectMaxLength ) );
	assert( isWritePtr( signedObjectLength, sizeof( int ) ) );
	assert( isReadPtr( object, objectLength ) && \
			!cryptStatusError( checkObjectEncoding( object, \
													objectLength ) ) );
	assert( formatInfo == NULL || \
			isReadPtr( formatInfo, sizeof( X509SIG_FORMATINFO ) ) );

	REQUIRES( ( signedObject == NULL && signedObjectMaxLength == 0 ) || \
			  ( signedObject != NULL && \
				signedObjectMaxLength > MIN_CRYPT_OBJECTSIZE && \
				signedObjectMaxLength < MAX_INTLENGTH ) );
	REQUIRES( objectLength > 0 && objectLength < MAX_INTLENGTH );
	REQUIRES( isHandleRangeValid( iSignContext ) );
	REQUIRES( isHashAlgo( hashAlgo ) );
	REQUIRES( formatInfo == NULL || \
			  ( ( formatInfo->tag >= 0 && \
				  formatInfo->tag < MAX_CTAG_VALUE ) && \
				( formatInfo->extraLength >= 0 && \
				  formatInfo->extraLength < MAX_INTLENGTH_SHORT ) ) );
예제 #13
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 );
	}
예제 #14
0
파일: obj_qry.c 프로젝트: TellarHK/wwiv
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 );
	}
예제 #15
0
파일: comp_pkiu.c 프로젝트: TRI0N/wwiv
static int copyPkiUserAttributes( INOUT CERT_INFO *certInfoPtr,
								  INOUT ATTRIBUTE_PTR *pkiUserAttributes )
	{
	ATTRIBUTE_PTR *requestAttrPtr, *pkiUserAttrPtr;
	int value, status;

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

	REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTREQUEST || \
			  certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT );

	/* If there are altNames present in both the PKI user data and the 
	   request, make sure that they match */
	requestAttrPtr = findAttribute( certInfoPtr->attributes,
									CRYPT_CERTINFO_SUBJECTALTNAME, FALSE );
	pkiUserAttrPtr = findAttribute( pkiUserAttributes,
									CRYPT_CERTINFO_SUBJECTALTNAME, FALSE );
	if( requestAttrPtr != NULL && pkiUserAttrPtr != NULL )
		{
		/* Both the certificate request and the PKI user have altNames,
		   make sure that they're identical */
		if( !compareAttribute( requestAttrPtr, pkiUserAttrPtr ) )
			{
			setErrorInfo( certInfoPtr, CRYPT_CERTINFO_SUBJECTALTNAME,
						  CRYPT_ERRTYPE_ISSUERCONSTRAINT );
			return( CRYPT_ERROR_INVALID );
			}

		/* The two altNames are identical, delete the one in the request in 
		   order to allow the one from the PKI user data to be copied across 
		   when we call copyAttributes() */
		status = deleteAttribute( &certInfoPtr->attributes,
								  &certInfoPtr->attributeCursor, 
								  requestAttrPtr,
								  certInfoPtr->currentSelection.dnPtr );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* There's one rather ugly special-case situation that we have to handle 
	   which is when the user has submitted a PnP PKI request for a generic 
	   signing certificate but their PKI user information indicates that 
	   they're intended to be a CA user.  The processing flow for this is:

			Read request data from an external source into certificate 
				request object, creating a state=high object;

			Add PKI user information to state=high request;

	   When augmenting the request with the PKI user information the 
	   incoming request will contain a keyUsage of digitalSignature while 
	   the PKI user information will contain a keyUsage of keyCertSign 
	   and/or crlSign.  We can't fix this up at the PnP processing level 
	   because the request object will be in the high state once it's
	   instantiated and no changes to the attributes can be made (the PKI 
	   user information is a special case that can be added to an object in 
	   the high state but which modifies attributes in it as if it were 
	   still in the low state).

	   To avoid the attribute conflict, if we find this situation in the 
	   request/pkiUser combination we delete the keyUsage in the request to 
	   allow it to be replaced by the pkiUser keyUsage.  Hardcoding in this 
	   special case isn't very elegant but it's the only way to make the PnP 
	   PKI issue work without requiring that the user explicitly specify 
	   that they want to be a CA in the request's keyUsage, which makes it 
	   rather non-PnP and would also lead to slightly strange requests since
	   basicConstraints can't be specified in requests while the CA keyUsage
	   can */
	status = getAttributeFieldValue( certInfoPtr->attributes,
									 CRYPT_CERTINFO_KEYUSAGE, 
									 CRYPT_ATTRIBUTE_NONE, &value );
	if( cryptStatusOK( status ) && value == CRYPT_KEYUSAGE_DIGITALSIGNATURE )
		{
		status = getAttributeFieldValue( pkiUserAttributes, 
										 CRYPT_CERTINFO_KEYUSAGE,
										 CRYPT_ATTRIBUTE_NONE, &value );
		if( cryptStatusOK( status ) && ( value & KEYUSAGE_CA ) )
			{
			/* The certificate contains a digitalSignature keyUsage and the 
			   PKI user information contains a CA usage, delete the 
			   certificate's keyUsage to make way for the PKI user's CA 
			   keyUsage */
			status = deleteCompleteAttribute( &certInfoPtr->attributes,
											  &certInfoPtr->attributeCursor, 
											  CRYPT_CERTINFO_KEYUSAGE, 
											  certInfoPtr->currentSelection.dnPtr );
			if( cryptStatusError( status ) )
				return( status );
			}
		}

	/* Copy the attributes from the PKI user information into the 
	   certificate */
	status = copyAttributes( &certInfoPtr->attributes, pkiUserAttributes,
							 &certInfoPtr->errorLocus,
							 &certInfoPtr->errorType );
	if( cryptStatusError( status ) )
		return( status );

	/* Perform any special-case adjustments on attributes that may be 
	   required after they've been copied from the PKI user to the 
	   certificate request */
	return( adjustPkiUserAttributes( certInfoPtr ) );
	}
예제 #16
0
int checkServerCertValid( const CRYPT_CERTIFICATE iServerKey,
						  INOUT ERROR_INFO *errorInfo )
	{
	CRYPT_CERTIFICATE iServerCert;
	CRYPT_ERRTYPE_TYPE errorType DUMMY_INIT;
	CRYPT_ATTRIBUTE_TYPE errorLocus DUMMY_INIT;
	static const int complianceLevelStandard = CRYPT_COMPLIANCELEVEL_STANDARD;
	int complianceLevel, status;

	assert( isWritePtr( errorInfo, sizeof( ERROR_INFO ) ) );

	REQUIRES( isHandleRangeValid( iServerKey ) );

	status = krnlSendMessage( iServerKey, IMESSAGE_GETATTRIBUTE, 
							  &complianceLevel, 
							  CRYPT_OPTION_CERT_COMPLIANCELEVEL );
	if( cryptStatusError( status ) )
		{
		/* We can't do much more if we can't even get the initial compliance 
		   level */
		return( CRYPT_ERROR_INVALID );
		}

	/* Check whether the certificate is valid at a standard level of 
	   compliance, which catches expired certificates and other obvious
	   problems */
	krnlSendMessage( iServerKey, IMESSAGE_SETATTRIBUTE, 
					 ( MESSAGE_CAST ) &complianceLevelStandard, 
					 CRYPT_OPTION_CERT_COMPLIANCELEVEL );
	status = krnlSendMessage( iServerKey, IMESSAGE_CHECK, NULL, 
							  MESSAGE_CHECK_CERT );
	krnlSendMessage( iServerKey, IMESSAGE_SETATTRIBUTE, 
					 ( MESSAGE_CAST ) &complianceLevel, 
					 CRYPT_OPTION_CERT_COMPLIANCELEVEL );
	if( cryptStatusOK( status ) )
		return( CRYPT_OK );

	/* The certificate associated with the key isn't valid, get the 
	   certificate (since otherwise we'd be querying the key rather than the
	   certificate) and fetch the extended error information */
	status = krnlSendMessage( iServerKey, IMESSAGE_GETDEPENDENT, 
							  &iServerCert, OBJECT_TYPE_CERTIFICATE );
	if( cryptStatusOK( status ) )
		{
		int value;

		status = krnlSendMessage( iServerCert, IMESSAGE_GETATTRIBUTE, 
								  &value, CRYPT_ATTRIBUTE_ERRORLOCUS );
		if( cryptStatusOK( status ) )
			{
			errorLocus = value;	/* int to enum */
			status = krnlSendMessage( iServerCert, IMESSAGE_GETATTRIBUTE, 
									  &value, CRYPT_ATTRIBUTE_ERRORTYPE );
			}
		if( cryptStatusOK( status ) )
			errorType = value;	/* int to enum */
		}
	if( cryptStatusError( status ) )
		{
		/* If we can't get extended error information then there's not much 
		   more that we can do */
		retExt( CRYPT_ERROR_INVALID,
				( CRYPT_ERROR_INVALID, errorInfo,
				  "Server certificate is invalid" ) );
		}

	/* Try and get more	information on common errors and report them to the
	   caller */
	if( errorType == CRYPT_ERRTYPE_CONSTRAINT )
		{
		switch( errorLocus )
			{
			case CRYPT_CERTINFO_VALIDFROM:
				retExt( CRYPT_ERROR_INVALID,
						( CRYPT_ERROR_INVALID, errorInfo,
						  "Server certificate is not valid yet" ) );

			case CRYPT_CERTINFO_VALIDTO:
				retExt( CRYPT_ERROR_INVALID,
						( CRYPT_ERROR_INVALID, errorInfo,
						  "Server certificate has expired" ) );

			case CRYPT_CERTINFO_KEYUSAGE:
				retExt( CRYPT_ERROR_INVALID,
						( CRYPT_ERROR_INVALID, errorInfo,
						  "Server certificate's keyUsage doesn't allow it "
						  "to be used" ) );
			}
		}

	retExt( CRYPT_ERROR_INVALID,
			( CRYPT_ERROR_INVALID, errorInfo,
			  "Server certificate is invalid, error type %d, error "
			  "locus %d", errorType, errorLocus ) );
	}
예제 #17
0
파일: net_proxy.c 프로젝트: TellarHK/wwiv
int connectViaSocksProxy( INOUT STREAM *stream )
	{
	MESSAGE_DATA msgData;
	BYTE socksBuffer[ 64 + CRYPT_MAX_TEXTSIZE + 8 ], *bufPtr = socksBuffer;
	char userName[ CRYPT_MAX_TEXTSIZE + 8 ];
	int length, status;

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

	REQUIRES_S( stream->type == STREAM_TYPE_NETWORK );

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

	/* Build up the SOCKSv4 request string:

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

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

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

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

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

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

	/* Make sure that everything is OK:

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

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

	return( CRYPT_OK );
	}
예제 #18
0
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 );
	}
예제 #19
0
파일: user_rw.c 프로젝트: deflomu/cryptlib
static int readConfigOption( INOUT STREAM *stream, 
							 IN_HANDLE CRYPT_USER iCryptUser )
	{
	CRYPT_ATTRIBUTE_TYPE attributeType;
	const BUILTIN_OPTION_INFO *builtinOptionInfoPtr;
	MESSAGE_DATA msgData;
	void *dataPtr DUMMY_INIT_PTR;
	long optionCode;
	int value, tag, length, status;

	/* Read the wrapper and option index and map it to the actual option.  
	   If we find an unknown index or one that shouldn't be writeable to 
	   persistent storage, we skip it and continue.  This is done to handle 
	   new options that may have been added after this version of cryptlib 
	   was built (for unknown indices) and because the stored configuration 
	   options are an untrusted source so we have to check for attempts to 
	   feed in bogus values (for non-writeable options) */
	readSequence( stream, NULL );
	status = readShortInteger( stream, &optionCode );
	if( cryptStatusError( status ) )
		return( status );
	if( optionCode < 0 || optionCode > LAST_OPTION_INDEX )
		{
		/* Unknown option, ignore it */
		return( readUniversal( stream ) );
		}
	builtinOptionInfoPtr = getBuiltinOptionInfoByCode( optionCode );
	if( builtinOptionInfoPtr == NULL || \
		builtinOptionInfoPtr->index < 0 || \
		builtinOptionInfoPtr->index > LAST_OPTION_INDEX || \
		builtinOptionInfoPtr->index == CRYPT_UNUSED )
		{
		/* Unknown option, ignore it */
		return( readUniversal( stream ) );
		}
	attributeType = builtinOptionInfoPtr->option;

	/* Read the option value and set the option.  We don't treat a failure 
	   to set the option as a problem since the user probably doesn't want 
	   the entire system to fail because of a bad configuration option, and 
	   in any case we'll fall back to a safe default value */
	status = tag = peekTag( stream );
	if( cryptStatusError( status ) )
		return( status );
	if( tag == BER_BOOLEAN || tag == BER_INTEGER )
		{
		/* It's a numeric value, read the appropriate type and try and set 
		   the option */
		if( tag == BER_BOOLEAN )
			status = readBoolean( stream, &value );
		else
			{
			long integer;

			status = readShortInteger( stream, &integer );
			if( cryptStatusOK( status ) )
				value = ( int ) integer;
			}
		if( cryptStatusError( status ) )
			return( status );
		( void ) krnlSendMessage( iCryptUser, IMESSAGE_SETATTRIBUTE, 
								  &value, attributeType );
		return( CRYPT_OK );
		}

	/* It's a string value, set the option straight from the encoded data */
	status = readGenericHole( stream, &length, 1, BER_STRING_UTF8 );
	if( cryptStatusOK( status ) )
		status = sMemGetDataBlock( stream, &dataPtr, length );
	if( cryptStatusOK( status ) )
		status = sSkip( stream, length, SSKIP_MAX );
	if( cryptStatusError( status ) )
		return( status );
	setMessageData( &msgData, dataPtr, length );
	( void ) krnlSendMessage( iCryptUser, IMESSAGE_SETATTRIBUTE_S, 
							  &msgData, attributeType );

	return( CRYPT_OK );
	}
예제 #20
0
파일: keydbx.c 프로젝트: ryankurte/cryptlib
static int testKeysetRead( const CRYPT_KEYSET_TYPE keysetType,
						   const C_STR keysetName,
						   const CRYPT_KEYID_TYPE keyType,
						   const C_STR keyName,
						   const CRYPT_CERTTYPE_TYPE type,
						   const int option )
	{
	CRYPT_KEYSET cryptKeyset;
	CRYPT_CERTIFICATE cryptCert;
	BOOLEAN isCertChain = FALSE;
	int value, status;

	/* Open the keyset with a check to make sure this access method exists
	   so we can return an appropriate error message */
	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, keysetType,
							  keysetName, CRYPT_KEYOPT_READONLY );
	if( status == CRYPT_ERROR_PARAM3 )
		{
		/* This type of keyset access not available */
		return( CRYPT_ERROR_NOTAVAIL );
		}
	if( cryptStatusError( status ) )
		{
		printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
				status, __LINE__ );
		return( CRYPT_ERROR_FAILED );
		}

	/* Read the certificate from the keyset */
	status = cryptGetPublicKey( cryptKeyset, &cryptCert, keyType, keyName );
	if( cryptStatusError( status ) )
		{
		/* The access to network-accessible keysets can be rather
		   temperamental and can fail at this point even though it's not a
		   fatal error.  The calling code knows this and will continue the
		   self-test with an appropriate warning, so we explicitly clean up
		   after ourselves to make sure we don't get a CRYPT_ORPHAN on
		   shutdown */
		if( keysetType == CRYPT_KEYSET_HTTP && \
			status == CRYPT_ERROR_NOTFOUND )
			{
			/* 404's are relatively common, and non-fatal */
			extErrorExit( cryptKeyset, "cryptGetPublicKey()", status, __LINE__ );
			puts( "  (404 is a common HTTP error, and non-fatal)." );
			return( TRUE );
			}

		return( extErrorExit( cryptKeyset, "cryptGetPublicKey()", status,
							  __LINE__ ) );
		}

	/* Make sure that we got what we were expecting */
	status = cryptGetAttribute( cryptCert, CRYPT_CERTINFO_CERTTYPE, 
								&value );
	if( cryptStatusError( status ) || ( value != type ) )
		{
		printf( "Expecting certificate object type %d, got %d, line %d.", 
				type, value, __LINE__ );
		return( FALSE );
		}
	if( value == CRYPT_CERTTYPE_CERTCHAIN )
		isCertChain = TRUE;
	if( value == CRYPT_CERTTYPE_CERTCHAIN || value == CRYPT_CERTTYPE_CRL )
		{
		value = 0;
		cryptSetAttribute( cryptCert, CRYPT_CERTINFO_CURRENT_CERTIFICATE,
						   CRYPT_CURSOR_FIRST );
		do
			value++;
		while( cryptSetAttribute( cryptCert,
								  CRYPT_CERTINFO_CURRENT_CERTIFICATE,
								  CRYPT_CURSOR_NEXT ) == CRYPT_OK );
		printf( isCertChain ? "Certificate chain length = %d.\n" : \
							  "CRL has %d entries.\n", value );
		}

	/* Check the certificate against the CRL.  Any kind of error is a 
	   failure since the certificate isn't in the CRL */
	if( keysetType != CRYPT_KEYSET_LDAP && \
		keysetType != CRYPT_KEYSET_HTTP )
		{
		if( !checkKeysetCRL( cryptKeyset, cryptCert, isCertChain ) )
			return( FALSE );
		}
	cryptDestroyCert( cryptCert );

	/* If we're reading multiple certs using the same (cached) query type,
	   try re-reading the certificate.  This can't be easily tested from the
	   outside because it's database back-end specific, so it'll require
	   attaching a debugger to the read code to make sure that the cacheing
	   is working as required */
	if( option == READ_OPTION_MULTIPLE )
		{
		int i;

		for( i = 0; i < 3; i++ )
			{
			status = cryptGetPublicKey( cryptKeyset, &cryptCert, keyType,
										keyName );
			if( cryptStatusError( status ) )
				{
				printf( "cryptGetPublicKey() with cached query failed with "
						"error code %d, line %d.\n", status, __LINE__ );
				return( FALSE );
				}
			cryptDestroyCert( cryptCert );
			}
		}

	/* Close the keyset */
	status = cryptKeysetClose( cryptKeyset );
	if( cryptStatusError( status ) )
		{
		printf( "cryptKeysetClose() failed with error code %d, line %d.\n",
				status, __LINE__ );
		return( FALSE );
		}

	return( TRUE );
	}
예제 #21
0
static int mct( CONTEXT_INFO *contextInfo, 
			    const CAPABILITY_INFO *capabilityInfo,
				const BYTE *initialKey, const int keySize,
				const BYTE *initialIV, const BYTE *initialPT )
	{
	BYTE key[ AES_KEYSIZE + 8 ], iv[ AES_KEYSIZE + 8 ];
	BYTE temp[ AES_BLOCKSIZE + 8 ];
	int i;

	memcpy( key, initialKey, keySize );
	if( iv != NULL )
		memcpy( iv, initialIV, AES_BLOCKSIZE );
	memcpy( temp, initialPT, AES_BLOCKSIZE );
	for( i = 0; i < 100; i++ )
		{
		BYTE prevTemp[ AES_BLOCKSIZE + 8 ];
		int j, status;

		status = capabilityInfo->initKeyFunction( contextInfo, key, 
												  keySize );
		if( cryptStatusError( status ) )
			return( status );
		printVector( "Key", key, keySize );
		if( iv != NULL )
			printVector( "IV", iv, AES_BLOCKSIZE );
		printVector( "Plaintext", temp, AES_BLOCKSIZE );
		if( iv != NULL )
			memcpy( contextInfo->ctxConv->currentIV, iv, AES_BLOCKSIZE );
		for( j = 0; j < 1000; j++ )
			{
/*			memcpy( prevTemp, temp, AES_BLOCKSIZE ); */
			if( iv != NULL && j == 0 )
				{
				status = capabilityInfo->encryptCBCFunction( contextInfo, temp, 
															 AES_BLOCKSIZE );
				memcpy( prevTemp, temp, AES_BLOCKSIZE );
				memcpy( temp, iv, AES_BLOCKSIZE );
				}
			else
				{
				status = capabilityInfo->encryptFunction( contextInfo, temp, 
														  AES_BLOCKSIZE );
				if( iv != NULL )
					{
					BYTE tmpTemp[ AES_BLOCKSIZE + 8 ];

					memcpy( tmpTemp, temp, AES_BLOCKSIZE );
					memcpy( temp, prevTemp, AES_BLOCKSIZE );
					memcpy( prevTemp, tmpTemp, AES_BLOCKSIZE );
					}
				}
			if( cryptStatusError( status ) )
				return( status );
			}
		printVector( "Ciphertext", temp, AES_BLOCKSIZE );
		putchar( '\n' );
		status = updateKey( key, keySize, contextInfo, capabilityInfo, 
							prevTemp, temp );
		if( cryptStatusError( status ) )
			return( status );
		}
	
	return( CRYPT_OK );
	}
예제 #22
0
파일: keydbx.c 프로젝트: ryankurte/cryptlib
static int testKeysetWrite( const CRYPT_KEYSET_TYPE keysetType,
							const C_STR keysetName )
	{
	CRYPT_KEYSET cryptKeyset;
	CRYPT_CERTIFICATE cryptCert;
	CRYPT_CONTEXT pubKeyContext, privKeyContext;
	C_CHR filenameBuffer[ FILENAME_BUFFER_SIZE ];
	C_CHR name[ CRYPT_MAX_TEXTSIZE + 1 ];
	int length, status;

	/* Import the certificate from a file - this is easier than creating one
	   from scratch.  We use one of the later certs in the test set, since
	   this contains an email address, which the earlier ones don't */
	status = importCertFromTemplate( &cryptCert, CERT_FILE_TEMPLATE, 
									 EMAILADDR_CERT_NO );
	if( cryptStatusError( status ) )
		{
		printf( "Couldn't read certificate from file, status %d, line %d.\n",
				status, __LINE__ );
		return( FALSE );
		}

	/* Make sure that the certificate does actually contain an email 
	   address */
	status = cryptGetAttributeString( cryptCert, CRYPT_CERTINFO_EMAIL,
									  name, &length );
	if( cryptStatusError( status ) )
		{
		printf( "Certificate doesn't contain an email address and can't be "
				"used for testing,\n  line %d.\n", __LINE__ );
		return( FALSE );
		}

	/* Create the database keyset with a check to make sure this access
	   method exists so we can return an appropriate error message.  If the
	   database table already exists, this will return a duplicate data
	   error so we retry the open with no flags to open the existing database
	   keyset for write access */
	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, keysetType,
							  keysetName, CRYPT_KEYOPT_CREATE );
	if( cryptStatusOK( status ) )
		printf( "Created new certificate database '%s'.\n", keysetName );
	if( status == CRYPT_ERROR_PARAM3 )
		{
		/* This type of keyset access isn't available, return a special error
		   code to indicate that the test wasn't performed, but that this
		   isn't a reason to abort processing */
		cryptDestroyCert( cryptCert );
		return( CRYPT_ERROR_NOTAVAIL );
		}
	if( status == CRYPT_ERROR_DUPLICATE )
		status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, keysetType,
								  keysetName, 0 );
	if( cryptStatusError( status ) )
		{
		cryptDestroyCert( cryptCert );
		printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
				status, __LINE__ );
		if( status == CRYPT_ERROR_OPEN )
			return( CRYPT_ERROR_FAILED );
		return( FALSE );
		}

	/* Write the key to the database */
	puts( "Adding certificate." );
	status = cryptAddPublicKey( cryptKeyset, cryptCert );
	if( status == CRYPT_ERROR_DUPLICATE )
		{
		/* The key is already present, delete it and retry the write */
		status = cryptGetAttributeString( cryptCert,
								CRYPT_CERTINFO_COMMONNAME, name, &length );
		if( cryptStatusOK( status ) )
			{
#ifdef UNICODE_STRINGS
			length /= sizeof( wchar_t );
#endif /* UNICODE_STRINGS */
			name[ length ] = TEXT( '\0' );
			status = cryptDeleteKey( cryptKeyset, CRYPT_KEYID_NAME, name );
			}
		if( cryptStatusError( status ) )
			return( extErrorExit( cryptKeyset, "cryptDeleteKey()", status,
								  __LINE__ ) );
		status = cryptAddPublicKey( cryptKeyset, cryptCert );
		}
	if( cryptStatusError( status ) )
		{
		printExtError( cryptKeyset, "cryptAddPublicKey()", status, __LINE__ );

		/* LDAP writes can fail due to the chosen directory not supporting the
		   schema du jour, so we're a bit more careful about cleaning up since
		   we'll skip the error and continue processing */
		cryptDestroyCert( cryptCert );
		cryptKeysetClose( cryptKeyset );
		return( FALSE );
		}
	cryptDestroyCert( cryptCert );

	/* Add a second certificate with C=US so that we've got enough certs to 
	   properly exercise the query code.  This certificate is highly unusual 
	   in that it doesn't have a DN, so we have to move up the DN looking 
	   for higher-up values, in this case the OU */
	if( keysetType != CRYPT_KEYSET_LDAP )
		{
		status = importCertFromTemplate( &cryptCert, CERT_FILE_TEMPLATE, 2 );
		if( cryptStatusError( status ) )
			{
			printf( "Couldn't read certificate from file, status %d, "
					"line %d.\n", status, __LINE__ );
			return( FALSE );
			}
		status = cryptAddPublicKey( cryptKeyset, cryptCert );
		if( status == CRYPT_ERROR_DUPLICATE )
			{
			status = cryptGetAttributeString( cryptCert,
							CRYPT_CERTINFO_COMMONNAME, name, &length );
			if( cryptStatusError( status ) )
				status = cryptGetAttributeString( cryptCert,
							CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, name, &length );
			if( cryptStatusOK( status ) )
				{
#ifdef UNICODE_STRINGS
				length /= sizeof( wchar_t );
#endif /* UNICODE_STRINGS */
				name[ length ] = TEXT( '\0' );
				status = cryptDeleteKey( cryptKeyset, CRYPT_KEYID_NAME, name );
				}
			if( cryptStatusOK( status ) )
				status = cryptAddPublicKey( cryptKeyset, cryptCert );
			}
		if( cryptStatusError( status ) )
			return( extErrorExit( cryptKeyset, "cryptAddPublicKey()",
								  status, __LINE__ ) );
		cryptDestroyCert( cryptCert );
		}

	/* Add a third certificate with a DN that'll cause problems for some 
	   storage technologies */
	if( !loadRSAContexts( CRYPT_UNUSED, &pubKeyContext, &privKeyContext ) )
		return( FALSE );
	status = cryptCreateCert( &cryptCert, CRYPT_UNUSED,
							  CRYPT_CERTTYPE_CERTIFICATE );
	if( cryptStatusError( status ) )
		{
		printf( "cryptCreateCert() failed with error code %d, line %d.\n",
				status, __LINE__ );
		return( FALSE );
		}
	status = cryptSetAttribute( cryptCert,
					CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, pubKeyContext );
	if( cryptStatusError( status ) )
		return( attrErrorExit( cryptCert, "cryptSetAttribute()", status,
							   __LINE__ ) );
	if( !addCertFields( cryptCert, sqlCertData, __LINE__ ) )
		return( FALSE );
	status = cryptSignCert( cryptCert, privKeyContext );
	if( cryptStatusError( status ) )
		return( attrErrorExit( cryptCert, "cryptSignCert()", status,
							   __LINE__ ) );
	destroyContexts( CRYPT_UNUSED, pubKeyContext, privKeyContext );
	status = cryptAddPublicKey( cryptKeyset, cryptCert );
	if( cryptStatusError( status ) )
		{
		/* The key is already present, delete it and retry the write */
		status = cryptGetAttributeString( cryptCert,
								CRYPT_CERTINFO_COMMONNAME, name, &length );
		if( cryptStatusOK( status ) )
			{
#ifdef UNICODE_STRINGS
			length /= sizeof( wchar_t );
#endif /* UNICODE_STRINGS */
			name[ length ] = TEXT( '\0' );
			status = cryptDeleteKey( cryptKeyset, CRYPT_KEYID_NAME, name );
			}
		if( cryptStatusError( status ) )
			return( extErrorExit( cryptKeyset, "cryptDeleteKey()", status,
								  __LINE__ ) );
		status = cryptAddPublicKey( cryptKeyset, cryptCert );
		}
	if( cryptStatusError( status ) )
		{
		return( extErrorExit( cryptKeyset, "cryptAddPublicKey()",
							  status, __LINE__ ) );
		}
	cryptDestroyCert( cryptCert );

	/* Now try the same thing with a CRL.  This code also tests the
	   duplicate-detection mechanism, if we don't get a duplicate error
	   there's a problem */
	puts( "Adding CRL." );
	status = importCertFromTemplate( &cryptCert, CRL_FILE_TEMPLATE, 1 );
	if( cryptStatusError( status ) )
		{
		printf( "Couldn't read CRL from file, status %d, line %d.\n", 
				status, __LINE__ );
		return( TRUE );
		}
	status = cryptAddPublicKey( cryptKeyset, cryptCert );
	if( cryptStatusError( status ) && status != CRYPT_ERROR_DUPLICATE )
		return( extErrorExit( cryptKeyset, "cryptAddPublicKey()", status,
							  __LINE__ ) );
	status = cryptAddPublicKey( cryptKeyset, cryptCert );
	if( status != CRYPT_ERROR_DUPLICATE )
		{
		printf( "Addition of duplicate item to keyset failed to produce "
			    "CRYPT_ERROR_DUPLICATE, status %d, line %d.\n", status,
				__LINE__ );
		return( FALSE );
		}
	cryptDestroyCert( cryptCert );

	/* Finally, try it with a certificate chain */
	puts( "Adding certificate chain." );
	filenameParamFromTemplate( filenameBuffer, CERTCHAIN_FILE_TEMPLATE, 
							   CERT_CHAIN_NO );
	status = importCertFile( &cryptCert, filenameBuffer );
	if( cryptStatusError( status ) )
		{
		printf( "Couldn't read certificate chain from file, status %d, "
				"line %d.\n", status, __LINE__ );
		return( FALSE );
		}
	status = cryptAddPublicKey( cryptKeyset, cryptCert );
	if( cryptStatusError( status ) && status != CRYPT_ERROR_DUPLICATE )
		return( extErrorExit( cryptKeyset, "cryptAddPublicKey()", status,
							  __LINE__ ) );
	cryptDestroyCert( cryptCert );

	/* In addition to the other certs we also add the generic user 
	   certificate, which is used later in other tests.  Since it may have 
	   been added earlier we try and delete it first (we can't use the 
	   existing version since the issuerAndSerialNumber won't match the one 
	   in the private-key keyset) */
	status = getPublicKey( &cryptCert, USER_PRIVKEY_FILE,
						   USER_PRIVKEY_LABEL );
	if( cryptStatusError( status ) )
		{
		printf( "Couldn't read user certificate from file, status %d, line "
				"%d.\n", status, __LINE__ );
		return( FALSE );
		}
	status = cryptGetAttributeString( cryptCert, CRYPT_CERTINFO_COMMONNAME,
									  name, &length );
	if( cryptStatusError( status ) )
		return( FALSE );
#ifdef UNICODE_STRINGS
	length /= sizeof( wchar_t );
#endif /* UNICODE_STRINGS */
	name[ length ] = TEXT( '\0' );
	do
		status = cryptDeleteKey( cryptKeyset, CRYPT_KEYID_NAME, name );
	while( cryptStatusOK( status ) );
	status = cryptAddPublicKey( cryptKeyset, cryptCert );
	if( status == CRYPT_ERROR_NOTFOUND )
		{
		/* This can occur if a database keyset is defined but hasn't been
		   initialised yet so the necessary tables don't exist, it can be
		   opened but an attempt to add a key will return a not found error
		   since it's the table itself rather than any item within it that
		   isn't being found */
		status = CRYPT_OK;
		}
	if( cryptStatusError( status ) )
		return( extErrorExit( cryptKeyset, "cryptAddPublicKey()", status,
							  __LINE__ ) );
	cryptDestroyCert( cryptCert );

	/* Finally, if ECC is enabled we also add ECC certificates that are used
	   later in other tests */
	if( cryptStatusOK( cryptQueryCapability( CRYPT_ALGO_ECDSA, NULL ) ) )
		{
#ifdef UNICODE_STRINGS
		wchar_t wcBuffer[ FILENAME_BUFFER_SIZE ];
#endif /* UNICODE_STRINGS */
		void *fileNamePtr = filenameBuffer;

		/* Add the P256 certificate */
		filenameFromTemplate( filenameBuffer, 
							  SERVER_ECPRIVKEY_FILE_TEMPLATE, 256 );
#ifdef UNICODE_STRINGS
		mbstowcs( wcBuffer, filenameBuffer, strlen( filenameBuffer ) + 1 );
		fileNamePtr = wcBuffer;
#endif /* UNICODE_STRINGS */
		status = getPublicKey( &cryptCert, fileNamePtr,
							   USER_PRIVKEY_LABEL );
		if( cryptStatusError( status ) )
			{
			printf( "Couldn't read user certificate from file, status %d, "
					"line %d.\n", status, __LINE__ );
			return( FALSE );
			}
		status = cryptAddPublicKey( cryptKeyset, cryptCert );
		if( cryptStatusError( status ) && status != CRYPT_ERROR_DUPLICATE )
			return( extErrorExit( cryptKeyset, "cryptAddPublicKey()", status,
								  __LINE__ ) );
		cryptDestroyCert( cryptCert );

		/* Add the P384 certificate */
		filenameFromTemplate( filenameBuffer, 
							  SERVER_ECPRIVKEY_FILE_TEMPLATE, 384 );
#ifdef UNICODE_STRINGS
		mbstowcs( wcBuffer, filenameBuffer, strlen( filenameBuffer ) + 1 );
		fileNamePtr = wcBuffer;
#endif /* UNICODE_STRINGS */
		status = getPublicKey( &cryptCert, fileNamePtr,
							   USER_PRIVKEY_LABEL );
		if( cryptStatusError( status ) )
			{
			printf( "Couldn't read user certificate from file, status %d, "
					"line %d.\n", status, __LINE__ );
			return( FALSE );
			}
		status = cryptAddPublicKey( cryptKeyset, cryptCert );
		if( cryptStatusError( status ) && status != CRYPT_ERROR_DUPLICATE )
			return( extErrorExit( cryptKeyset, "cryptAddPublicKey()", status,
								  __LINE__ ) );
		cryptDestroyCert( cryptCert );
		}

	/* Make sure the deletion code works properly.  This is an artifact of
	   the way RDBMS' work, the delete query can execute successfully but
	   not delete anything so we make sure the glue code correctly
	   translates this into a CRYPT_DATA_NOTFOUND */
	status = cryptDeleteKey( cryptKeyset, CRYPT_KEYID_NAME,
							 TEXT( "Mr.Not Appearing in this Keyset" ) );
	if( status != CRYPT_ERROR_NOTFOUND )
		{
		puts( "Attempt to delete a nonexistant key reports success, the "
			  "database backend glue\ncode needs to be fixed to handle this "
			  "correctly." );
		return( FALSE );
		}

	/* Close the keyset */
	status = cryptKeysetClose( cryptKeyset );
	if( cryptStatusError( status ) )
		{
		printf( "cryptKeysetClose() failed with error code %d, line %d.\n",
				status, __LINE__ );
		}

	return( TRUE );
	}
예제 #23
0
static int processAdditionalScepRequest( INOUT SESSION_INFO *sessionInfoPtr,
										 const HTTP_URI_INFO *httpReqInfo )
	{
	HTTP_URI_INFO rewrittenHttpReqInfo;
	MESSAGE_DATA msgData;
	int operationType, status;

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( isReadPtr( httpReqInfo, sizeof( HTTP_URI_INFO ) ) );

	/* If the client has fed us an HTTP GET request, find out what they  
	   want.  SCEP's handling of HTTP requests is a bit different from the 
	   "attribute '=' value" lookup that's normally used for HTTP data 
	   retrieval.  Instead, it uses the format 
	   "'operation =' value '&' extraData", with the search key buried in 
	   the 'extraData' value.  In addition the content of the 'extraData' 
	   value isn't defined outside of "any string which is understood by the 
	   CA".  However since 'value' defines what we want, we can determine 
	   what to return based on this and ignore the 'extraData' portion.

	   In order to fix up the query information into a format that works 
	   with standard HTTP queries, we rewrite the query data from the 
	   "'operation =' value '&' extraData" form into "attribute '=' value" 
	   before we process the query */
	memset( &rewrittenHttpReqInfo, 0, sizeof( HTTP_URI_INFO ) );
	memcpy( rewrittenHttpReqInfo.attribute, httpReqInfo->value, 
			httpReqInfo->valueLen );
	rewrittenHttpReqInfo.attributeLen = httpReqInfo->valueLen;
	if( httpReqInfo->extraDataLen > 0 )
		{
		memcpy( rewrittenHttpReqInfo.value, httpReqInfo->extraData, 
				httpReqInfo->extraDataLen );
		rewrittenHttpReqInfo.valueLen = httpReqInfo->extraDataLen;
		}
	status = processCertQuery( sessionInfoPtr, &rewrittenHttpReqInfo,
							   certstoreReadInfo, 
							   FAILSAFE_ARRAYSIZE( certstoreReadInfo, \
												   CERTSTORE_READ_INFO ),
							   &operationType, NULL, 0, NULL );
	if( cryptStatusError( status ) )
		{
		sendCertErrorResponse( sessionInfoPtr, status );
		return( status );
		}
	ENSURES( operationType == SCEP_OPERATION_GETCACAPS || \
			 operationType == SCEP_OPERATION_GETCACERT || \
			 operationType == SCEP_OPERATION_GETCACERTCHAIN );

	/* If it's a CA capabilities query, return the information as raw text
	   over HTTP */
	if( operationType == SCEP_OPERATION_GETCACAPS )
		{
		STREAM stream;

		sMemOpen( &stream, sessionInfoPtr->receiveBuffer, 1024 );
		swrite( &stream, "POSTPKIOperation\n", 17 );
#if 0	/* 14/6/14 Too risky to implement given its current state in the 
				   spec, see the discussion on the JSCEP mailing list for
				   details */
		status = swrite( &stream, "Renewal\n", 8 );
#endif /* 0 */
		if( algoAvailable( CRYPT_ALGO_SHA1 ) )
			status = swrite( &stream, "SHA-1\n", 6 );
		if( algoAvailable( CRYPT_ALGO_SHA2 ) )
			status = swrite( &stream, "SHA-256\n", 8 );
		if( algoAvailable( CRYPT_ALGO_SHAng ) )
			status = swrite( &stream, "SHAng\n", 6 );
		if( algoAvailable( CRYPT_ALGO_3DES ) )
			status = swrite( &stream, "DES3\n", 5 );
		if( algoAvailable( CRYPT_ALGO_AES ) )
			status = swrite( &stream, "AES\n", 4 );
		if( cryptStatusOK( status ) )
			sessionInfoPtr->receiveBufEnd = stell( &stream );
		sMemDisconnect( &stream );
		ENSURES( cryptStatusOK( status ) );
		return( writePkiDatagram( sessionInfoPtr, SCEP_CONTENT_TYPE, 
								  SCEP_CONTENT_TYPE_LEN ) );
		}
예제 #24
0
파일: keydbx.c 프로젝트: ryankurte/cryptlib
int testReadCert( void )
	{
	CRYPT_CERTIFICATE cryptCert;
	C_CHR name[ CRYPT_MAX_TEXTSIZE + 1 ], email[ CRYPT_MAX_TEXTSIZE + 1 ];
	C_CHR filenameBuffer[ FILENAME_BUFFER_SIZE ];
	int length, status;

	/* Get the DN from one of the test certs (the one that we wrote to the
	   keyset earlier with testKeysetWrite() */
	status = importCertFromTemplate( &cryptCert, CERT_FILE_TEMPLATE, 
									 EMAILADDR_CERT_NO );
	if( cryptStatusError( status ) )
		{
		printf( "Couldn't read certificate from file, status %d, line %d.\n",
				status, __LINE__ );
		return( FALSE );
		}
	status = cryptGetAttributeString( cryptCert, CRYPT_CERTINFO_COMMONNAME,
									  name, &length );
	if( cryptStatusOK( status ) )
		{
#ifdef UNICODE_STRINGS
		length /= sizeof( wchar_t );
#endif /* UNICODE_STRINGS */
		name[ length ] = TEXT( '\0' );
		status = cryptGetAttributeString( cryptCert, CRYPT_CERTINFO_EMAIL,
										  email, &length );
		}
	if( cryptStatusOK( status ) )
		{
		int i;

#ifdef UNICODE_STRINGS
		length /= sizeof( wchar_t );
#endif /* UNICODE_STRINGS */
		email[ length ] = TEXT( '\0' );

		/* Mess up the case to make sure that case-insensitive matching is
		   working */
		for( i = 0; i < length; i++ )
			{
			if( i & 1 )
				email[ i ] = toupper( email[ i ] );
			else
				email[ i ] = tolower( email[ i ] );
			}
		}
	else
		{
		return( extErrorExit( cryptCert, "cryptGetAttributeString()", status,
							  __LINE__ ) );
		}
	cryptDestroyCert( cryptCert );

	puts( "Testing certificate database read..." );
	status = testKeysetRead( DATABASE_KEYSET_TYPE, DATABASE_KEYSET_NAME,
	 						 CRYPT_KEYID_NAME, name,
							 CRYPT_CERTTYPE_CERTIFICATE,
							 READ_OPTION_NORMAL );
	if( status == CRYPT_ERROR_NOTAVAIL )
		{
		/* Database keyset access not available */
		return( CRYPT_ERROR_NOTAVAIL );
		}
	if( status == CRYPT_ERROR_FAILED )
		{
		puts( "This is probably because you haven't set up a database or "
			  "data source for use\nas a key database.  For this test to "
			  "work, you need to set up a database/data\nsource with the "
			  "name '" DATABASE_KEYSET_NAME_ASCII "'.\n" );
		return( TRUE );
		}
	if( !status )
		return( FALSE );
	puts( "Reading certs using cached query." );
	status = testKeysetRead( DATABASE_KEYSET_TYPE, DATABASE_KEYSET_NAME,
	 						 CRYPT_KEYID_EMAIL, email,
							 CRYPT_CERTTYPE_CERTIFICATE,
							 READ_OPTION_MULTIPLE );
	if( !status )
		return( FALSE );

	/* Get the DN from one of the test certificate chains */
	filenameParamFromTemplate( filenameBuffer, CERTCHAIN_FILE_TEMPLATE, 
							   CERT_CHAIN_NO );
	status = importCertFile( &cryptCert, filenameBuffer );
	if( cryptStatusError( status ) )
		{
		printf( "Couldn't read certificate chain from file, status %d, "
				"line %d.\n", status, __LINE__ );
		return( FALSE );
		}
	status = cryptGetAttributeString( cryptCert, CRYPT_CERTINFO_COMMONNAME,
									  name, &length );
	if( cryptStatusOK( status ) )
		{
#ifdef UNICODE_STRINGS
		length /= sizeof( wchar_t );
#endif /* UNICODE_STRINGS */
		name[ length ] = TEXT( '\0' );
		}
	cryptDestroyCert( cryptCert );

	/* Now read the complete certificate chain */
	puts( "Reading complete certificate chain." );
	status = testKeysetRead( DATABASE_KEYSET_TYPE, DATABASE_KEYSET_NAME,
	 						 CRYPT_KEYID_NAME, name,
							 CRYPT_CERTTYPE_CERTCHAIN, READ_OPTION_NORMAL );
	if( !status )
		return( FALSE );
	puts( "Certificate database read succeeded.\n" );
	return( TRUE );
	}
예제 #25
0
static BOOLEAN pairwiseConsistencyTest( INOUT CONTEXT_INFO *contextInfoPtr )
	{
	CONTEXT_INFO checkContextInfo;
	PKC_INFO *sourcePkcInfo = contextInfoPtr->ctxPKC;
	PKC_INFO contextData, *pkcInfo = &contextData;
	KEYAGREE_PARAMS keyAgreeParams1, keyAgreeParams2;
	const CAPABILITY_INFO *capabilityInfoPtr;
	int bnStatus = BN_STATUS, status;

	assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );

	REQUIRES( sanityCheckPKCInfo( sourcePkcInfo ) );

	/* The DH pairwise check is a bit more complex than the one for the
	   other algorithms because there's no matched public/private key pair,
	   so we have to load a second DH key to use for key agreement with
	   the first one */
	status = staticInitContext( &checkContextInfo, CONTEXT_PKC, 
								getDHCapability(), &contextData, 
								sizeof( PKC_INFO ), NULL );
	if( cryptStatusError( status ) )
		return( FALSE );
	CKPTR( BN_copy( &pkcInfo->dlpParam_p, &sourcePkcInfo->dlpParam_p ) );
	CKPTR( BN_copy( &pkcInfo->dlpParam_g, &sourcePkcInfo->dlpParam_g ) );
	CKPTR( BN_copy( &pkcInfo->dlpParam_q, &sourcePkcInfo->dlpParam_q ) );
	CKPTR( BN_copy( &pkcInfo->dlpParam_y, &sourcePkcInfo->dlpParam_y ) );
	CKPTR( BN_copy( &pkcInfo->dlpParam_x, &sourcePkcInfo->dlpParam_x ) );
	if( bnStatusError( bnStatus ) )
		{
		staticDestroyContext( &checkContextInfo );
		return( getBnStatusBool( bnStatus ) );
		}

	/* Perform the pairwise test using the check key */
	capabilityInfoPtr = checkContextInfo.capabilityInfo;
	memset( &keyAgreeParams1, 0, sizeof( KEYAGREE_PARAMS ) );
	memset( &keyAgreeParams2, 0, sizeof( KEYAGREE_PARAMS ) );
	status = capabilityInfoPtr->initKeyFunction( &checkContextInfo, NULL, 0 );
	if( cryptStatusOK( status ) )
		status = capabilityInfoPtr->encryptFunction( contextInfoPtr,
					( BYTE * ) &keyAgreeParams1, sizeof( KEYAGREE_PARAMS ) );
	if( cryptStatusOK( status ) )
		status = capabilityInfoPtr->encryptFunction( &checkContextInfo,
					( BYTE * ) &keyAgreeParams2, sizeof( KEYAGREE_PARAMS ) );
	if( cryptStatusOK( status ) )
		status = capabilityInfoPtr->decryptFunction( contextInfoPtr,
					( BYTE * ) &keyAgreeParams2, sizeof( KEYAGREE_PARAMS ) );
	if( cryptStatusOK( status ) )
		status = capabilityInfoPtr->decryptFunction( &checkContextInfo,
					( BYTE * ) &keyAgreeParams1, sizeof( KEYAGREE_PARAMS ) );
	if( cryptStatusError( status ) || \
		keyAgreeParams1.wrappedKeyLen != keyAgreeParams2.wrappedKeyLen || \
		memcmp( keyAgreeParams1.wrappedKey, keyAgreeParams2.wrappedKey, 
				keyAgreeParams1.wrappedKeyLen ) )
		status = CRYPT_ERROR_FAILED;

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

	return( cryptStatusOK( status ) ? TRUE : FALSE );
	}
예제 #26
0
파일: keydbx.c 프로젝트: ryankurte/cryptlib
int testReadCertLDAP( void )
	{
	CRYPT_KEYSET cryptKeyset;
	static const char FAR_BSS *ldapErrorString = \
		"LDAP directory read failed, probably because the standard being "
		"used by the\ndirectory server differs from the one used by the "
		"LDAP client software (pick\na standard, any standard).  If you "
		"know how the directory being used is\nconfigured, you can try "
		"changing the CRYPT_OPTION_KEYS_LDAP_xxx settings to\nmatch those "
		"used by the server.  Processing will continue without treating\n"
		"this as a fatal error.\n";
	const C_STR ldapKeysetName = ldapUrlInfo[ LDAP_SERVER_NO ].url;
	char ldapAttribute1[ CRYPT_MAX_TEXTSIZE + 1 ];
	char ldapAttribute2[ CRYPT_MAX_TEXTSIZE + 1 ];
	char certName[ CRYPT_MAX_TEXTSIZE ], caCertName[ CRYPT_MAX_TEXTSIZE ];
	char crlName[ CRYPT_MAX_TEXTSIZE ];
	int length, status;

	/* LDAP directories come and go, check to see which one is currently
	   around */
	puts( "Testing LDAP directory availability..." );
	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_LDAP,
							  ldapKeysetName, CRYPT_KEYOPT_READONLY );
	if( status == CRYPT_ERROR_PARAM3 )
		{
		/* LDAP keyset access not available */
		return( CRYPT_ERROR_NOTAVAIL );
		}
	if( status == CRYPT_ERROR_OPEN )
		{
		printf( "%s not available for some odd reason,\n  trying "
				"alternative directory instead...\n", 
				ldapUrlInfo[ LDAP_SERVER_NO ].asciiURL );
		ldapKeysetName = ldapUrlInfo[ LDAP_ALT_SERVER_NO ].url;
		status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED,
								  CRYPT_KEYSET_LDAP, ldapKeysetName,
								  CRYPT_KEYOPT_READONLY );
		}
	if( status == CRYPT_ERROR_OPEN )
		{
		printf( "%s not available either.\n",
				ldapUrlInfo[ LDAP_ALT_SERVER_NO ].asciiURL );
		puts( "None of the test LDAP directories are available.  If you need "
			  "to test the\nLDAP capabilities, you need to set up an LDAP "
			  "directory that can be used\nfor the certificate store.  You "
			  "can configure the LDAP directory using the\nLDAP_KEYSET_xxx "
			  "settings in test/test.h.  Alternatively, if this message\n"
			  "took a long time to appear you may be behind a firewall that "
			  "blocks LDAP\ntraffic.\n" );
		return( FALSE );
		}
	if( cryptStatusError( status ) )
		{
		printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
				status, __LINE__ );
		return( FALSE );
		}
	status = cryptGetAttributeString( CRYPT_UNUSED,
									  CRYPT_OPTION_KEYS_LDAP_OBJECTCLASS,
									  ldapAttribute1, &length );
	if( cryptStatusOK( status ) )
		{
#ifdef UNICODE_STRINGS
		length /= sizeof( wchar_t );
#endif /* UNICODE_STRINGS */
		ldapAttribute1[ length ] = TEXT( '\0' );
		status = cryptGetAttributeString( cryptKeyset,
										  CRYPT_OPTION_KEYS_LDAP_OBJECTCLASS,
										  ldapAttribute2, &length );
		}
	if( cryptStatusOK( status ) )
		{
#ifdef UNICODE_STRINGS
		length /= sizeof( wchar_t );
#endif /* UNICODE_STRINGS */
		ldapAttribute2[ length ] = TEXT( '\0' );
		}
	if( cryptStatusError( status ) || \
		strcmp( ldapAttribute1, ldapAttribute2 ) )
		{
		printf( "Failed to get/set keyset attribute via equivalent global "
				"attribute, error\ncode %d, value '%s', should be\n'%s', "
				"line %d.\n", status, ldapAttribute2, ldapAttribute1,
				__LINE__ );
		return( FALSE );
		}
	cryptKeysetClose( cryptKeyset );
	printf( "  LDAP directory %s seems to be up, using that for read test.\n",
			ldapKeysetName );

	/* Now it gets tricky, we have to jump through all sorts of hoops to
	   run the tests in an automated manner since the innate incompatibility
	   of LDAP directory setups means that even though cryptlib's LDAP access
	   code retries failed queries with various options, we still need to
	   manually override some settings here.  The simplest option is a direct
	   read with no special-case handling */
	if( !paramStrcmp( ldapKeysetName, ldapUrlInfo[ LDAP_SERVER_NO ].url ) )
		{
		puts( "Testing LDAP certificate read..." );
		status = testKeysetRead( CRYPT_KEYSET_LDAP, ldapKeysetName,
								 CRYPT_KEYID_NAME,
								 ldapUrlInfo[ LDAP_SERVER_NO ].certName,
								 CRYPT_CERTTYPE_CERTIFICATE,
								 READ_OPTION_NORMAL );
		if( !status )
			{
			/* Since we can never be sure about the LDAP schema du jour, we
			   don't treat a failure as a fatal error */
			puts( ldapErrorString );
			return( FALSE );
			}

		/* This directory doesn't contain CRLs (or at least not at any known
		   location) so we skip the CRL read test */
		puts( "LDAP certificate read succeeded (CRL read skipped).\n" );
		return( TRUE );
		}

	/* The secondary LDAP directory that we're using for these tests doesn't
	   recognise the ';binary' modifier which is required by LDAP servers in
	   order to get them to work properly, we have to change the attribute
	   name around the read calls to the format expected by the server.

	   In addition because the magic formula for fetching a CRL doesn't seem
	   to work for certificates, the CRL read is done first */
	puts( "Testing LDAP CRL read..." );
	status = cryptGetAttributeString( CRYPT_UNUSED, 
									  CRYPT_OPTION_KEYS_LDAP_CRLNAME,
									  crlName, &length );
	if( cryptStatusError( status ) )
		return( FALSE );
#ifdef UNICODE_STRINGS
	length /= sizeof( wchar_t );
#endif /* UNICODE_STRINGS */
	certName[ length ] = TEXT( '\0' );
	cryptSetAttributeString( CRYPT_UNUSED, CRYPT_OPTION_KEYS_LDAP_CRLNAME,
							 "certificateRevocationList", 25 );
	status = testKeysetRead( CRYPT_KEYSET_LDAP, ldapKeysetName,
							 CRYPT_KEYID_NAME,
							 ldapUrlInfo[ LDAP_ALT_SERVER_NO ].crlName,
							 CRYPT_CERTTYPE_CRL, READ_OPTION_NORMAL );
	cryptSetAttributeString( CRYPT_UNUSED, CRYPT_OPTION_KEYS_LDAP_CRLNAME,
							 crlName, strlen( crlName ) );
	if( !status )
		{
		/* Since we can never be sure about the LDAP schema du jour, we
		   don't treat a failure as a fatal error */
		puts( ldapErrorString );
		return( FALSE );
		}

	puts( "Testing LDAP certificate read..." );
	status = cryptGetAttributeString( CRYPT_UNUSED, 
									  CRYPT_OPTION_KEYS_LDAP_CERTNAME,
									  certName, &length );
	if( cryptStatusError( status ) )
		return( FALSE );
#ifdef UNICODE_STRINGS
	length /= sizeof( wchar_t );
#endif /* UNICODE_STRINGS */
	certName[ length ] = TEXT( '\0' );
	cryptSetAttributeString( CRYPT_UNUSED, CRYPT_OPTION_KEYS_LDAP_CERTNAME,
							 "userCertificate", 15 );
	status = cryptGetAttributeString( CRYPT_UNUSED, 
									  CRYPT_OPTION_KEYS_LDAP_CACERTNAME,
									  caCertName, &length );
	if( cryptStatusError( status ) )
		return( FALSE );
#ifdef UNICODE_STRINGS
	length /= sizeof( wchar_t );
#endif /* UNICODE_STRINGS */
	certName[ length ] = TEXT( '\0' );
	cryptSetAttributeString( CRYPT_UNUSED, CRYPT_OPTION_KEYS_LDAP_CACERTNAME,
							 "cACertificate", 13 );
	status = testKeysetRead( CRYPT_KEYSET_LDAP, ldapKeysetName,
							 CRYPT_KEYID_NAME,
							 ldapUrlInfo[ LDAP_ALT_SERVER_NO ].certName,
							 CRYPT_CERTTYPE_CERTIFICATE, READ_OPTION_NORMAL );
	cryptSetAttributeString( CRYPT_UNUSED, CRYPT_OPTION_KEYS_LDAP_CERTNAME,
							 certName, strlen( certName ) );
	cryptSetAttributeString( CRYPT_UNUSED, CRYPT_OPTION_KEYS_LDAP_CACERTNAME,
							 caCertName, strlen( caCertName ) );
	if( !status )
		{
		/* Since we can never be sure about the LDAP schema du jour, we
		   don't treat a failure as a fatal error */
		puts( "LDAP directory read failed, probably due to the magic "
			  "incantatation to fetch\na certificate from this server not "
			  "matching the one used to fetch a CRL.\nProcessing will "
			  "continue without treating this as a fatal error.\n" );
		return( FALSE );
		}
	puts( "LDAP certificate/CRL read succeeded.\n" );

	return( TRUE );
	}
예제 #27
0
static int processAdditionalScepRequest( INOUT SESSION_INFO *sessionInfoPtr,
										 const HTTP_URI_INFO *httpReqInfo )
	{
	HTTP_URI_INFO rewrittenHttpReqInfo;
	MESSAGE_DATA msgData;
	int operationType, status;

	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
	assert( isReadPtr( httpReqInfo, sizeof( HTTP_URI_INFO ) ) );

	/* If the client has fed us an HTTP GET request, find out what they  
	   want.  SCEP's handling of HTTP requests is a bit different from the 
	   "attribute '=' value" lookup that's normally used for HTTP data 
	   retrieval.  Instead, it uses the format 
	   "'operation =' value '&' extraData", with the search key buried in 
	   the 'extraData' value.  In addition the content of the 'extraData' 
	   value isn't defined outside of "any string which is understood by the 
	   CA".  However since 'value' defines what we want, we can determine 
	   what to return based on this and ignore the 'extraData' portion.

	   In order to fix up the query information into a format that works 
	   with standard HTTP queries, we rewrite the query data from the 
	   "'operation =' value '&' extraData" form into "attribute '=' value" 
	   before we process the query */
	memset( &rewrittenHttpReqInfo, 0, sizeof( HTTP_URI_INFO ) );
	memcpy( rewrittenHttpReqInfo.attribute, httpReqInfo->value, 
			httpReqInfo->valueLen );
	rewrittenHttpReqInfo.attributeLen = httpReqInfo->valueLen;
	if( httpReqInfo->extraDataLen > 0 )
		{
		memcpy( rewrittenHttpReqInfo.value, httpReqInfo->extraData, 
				httpReqInfo->extraDataLen );
		rewrittenHttpReqInfo.valueLen = httpReqInfo->extraDataLen;
		}
	status = processCertQuery( sessionInfoPtr, &rewrittenHttpReqInfo,
							   certstoreReadInfo, 
							   FAILSAFE_ARRAYSIZE( certstoreReadInfo, \
												   CERTSTORE_READ_INFO ),
							   &operationType, NULL, 0, NULL );
	if( cryptStatusError( status ) )
		{
		sendCertErrorResponse( sessionInfoPtr, status );
		return( status );
		}
	ENSURES( operationType == SCEP_OPERATION_GETCACAPS || \
			 operationType == SCEP_OPERATION_GETCACERT || \
			 operationType == SCEP_OPERATION_GETCACERTCHAIN );

	/* If it's a CA capabilities query, return the information as raw text
	   over HTTP */
	if( operationType == SCEP_OPERATION_GETCACAPS )
		{
		STREAM stream;

		sMemOpen( &stream, sessionInfoPtr->receiveBuffer, 1024 );
		status = swrite( &stream, "POSTPKIOperation\n", 17 );
		if( algoAvailable( CRYPT_ALGO_SHA1 ) )
			status = swrite( &stream, "SHA-1\n", 6 );
		if( algoAvailable( CRYPT_ALGO_SHA2 ) )
			status = swrite( &stream, "SHA-256\n", 8 );
		if( algoAvailable( CRYPT_ALGO_SHAng ) )
			status = swrite( &stream, "SHAng\n", 6 );
		if( algoAvailable( CRYPT_ALGO_3DES ) )
			status = swrite( &stream, "DES3\n", 5 );
		if( algoAvailable( CRYPT_ALGO_AES ) )
			status = swrite( &stream, "AES\n", 4 );
		if( cryptStatusOK( status ) )
			sessionInfoPtr->receiveBufEnd = stell( &stream );
		sMemDisconnect( &stream );
		ENSURES( cryptStatusOK( status ) );
		return( writePkiDatagram( sessionInfoPtr, SCEP_CONTENT_TYPE,
								  SCEP_CONTENT_TYPE_LEN ) );
		}

	/* Export the CA certificate and send it to the client */
	setMessageData( &msgData, sessionInfoPtr->receiveBuffer,
					sessionInfoPtr->receiveBufSize );
	status = krnlSendMessage( sessionInfoPtr->privateKey,
							  IMESSAGE_CRT_EXPORT, &msgData,
							  ( operationType == SCEP_OPERATION_GETCACERT ) ? \
								CRYPT_CERTFORMAT_CERTIFICATE : \
								CRYPT_CERTFORMAT_CERTCHAIN );
	if( cryptStatusError( status ) )
		{
		retExt( status,
				( status, SESSION_ERRINFO, 
				  "Couldn't export CA certificate%s for '%s' request", 
				  ( operationType == SCEP_OPERATION_GETCACERT ) ? \
					"" : " chain",
				  ( operationType == SCEP_OPERATION_GETCACERT ) ? \
					"GetCACert" : "GetCACertChain" ) );
		}
	sessionInfoPtr->receiveBufEnd = msgData.length;
	if( operationType == SCEP_OPERATION_GETCACERT )
		{
		return( writePkiDatagram( sessionInfoPtr, 
								  SCEP_CONTENT_TYPE_GETCACERT,
								  SCEP_CONTENT_TYPE_GETCACERT_LEN ) );
		}
	return( writePkiDatagram( sessionInfoPtr, 
							  SCEP_CONTENT_TYPE_GETCACERTCHAIN,
							  SCEP_CONTENT_TYPE_GETCACERTCHAIN_LEN ) );
	}
예제 #28
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();
	}
예제 #29
0
static int createScepResponse( INOUT SESSION_INFO *sessionInfoPtr,
							   INOUT SCEP_PROTOCOL_INFO *protocolInfo )
	{
	CRYPT_CERTIFICATE iCmsAttributes;
	MESSAGE_DATA msgData;
	int dataLength, status;

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

	/* Extract the response data into the session buffer */
	setMessageData( &msgData, sessionInfoPtr->receiveBuffer,
					sessionInfoPtr->receiveBufSize );
	status = krnlSendMessage( sessionInfoPtr->iCertResponse,
							  IMESSAGE_CRT_EXPORT, &msgData,
							  CRYPT_CERTFORMAT_CERTCHAIN );
	if( cryptStatusError( status ) )
		{
		retExt( status,
				( status, SESSION_ERRINFO, 
				  "Couldn't get PKCS #7 certificate chain from SCEP "
				  "response object" ) );
		}
	DEBUG_DUMP_FILE( "scep_sresp0", sessionInfoPtr->receiveBuffer, 
					 msgData.length );

	/* Phase 1: Encrypt the data using the client's key */
	status = envelopeWrap( sessionInfoPtr->receiveBuffer, msgData.length,
						   sessionInfoPtr->receiveBuffer, 
						   sessionInfoPtr->receiveBufSize, &dataLength, 
						   CRYPT_FORMAT_CMS, CRYPT_CONTENT_NONE, 
						   protocolInfo->iScepCert );
	if( cryptStatusError( status ) )
		{
		retExt( status,
				( status, SESSION_ERRINFO, 
				  "Couldn't encrypt response data with client key" ) );
		}
	DEBUG_DUMP_FILE( "scep_sresp1", sessionInfoPtr->receiveBuffer, 
					 dataLength );

	/* Create the SCEP signing attributes */
	status = createScepAttributes( sessionInfoPtr, protocolInfo,  
								   &iCmsAttributes, FALSE, CRYPT_OK );
	if( cryptStatusError( status ) )
		{
		retExt( status,
				( status, SESSION_ERRINFO, 
				  "Couldn't create SCEP response signing attributes" ) );
		}

	/* Phase 2: Sign the data using the CA key and SCEP attributes */
	status = envelopeSign( sessionInfoPtr->receiveBuffer, dataLength,
						   sessionInfoPtr->receiveBuffer, 
						   sessionInfoPtr->receiveBufSize, 
						   &sessionInfoPtr->receiveBufEnd, 
						   CRYPT_CONTENT_NONE, sessionInfoPtr->privateKey, 
						   iCmsAttributes );
	krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
	if( cryptStatusError( status ) )
		{
		retExt( status,
				( status, SESSION_ERRINFO, 
				  "Couldn't sign response data with CA key" ) );
		}
	DEBUG_DUMP_FILE( "scep_sresp2", sessionInfoPtr->receiveBuffer, 
					 sessionInfoPtr->receiveBufEnd );

	return( CRYPT_OK );
	}
예제 #30
0
파일: testlib.c 프로젝트: TellarHK/wwiv
int main( int argc, char **argv )
	{
	const char *zargPtr = NULL;
	BOOLEAN sessionTestError = FALSE, loopbackTestError = FALSE;
	int flags, status;
	void testSystemSpecific1( void );
	void testSystemSpecific2( void );

	/* If we're running in test mode, run the test code and exit */
#ifdef CONFIG_SUITEB_TESTS
	return( suiteBMain( argc, argv ) );
#endif /* CONFIG_SUITEB_TESTS */

	/* Print a general banner to let the user know what's going on */
	printf( "testlib - cryptlib %d-bit self-test framework.\n", 
			( int ) sizeof( long ) * 8 );	/* Cast for gcc */
	puts( "Copyright Peter Gutmann 1995 - 2012." );
	puts( "" );

	/* Skip the program name and process any command-line arguments */
	argv++; argc--;
	status = processArgs( argc, argv, &flags, &zargPtr );
	if( !status )
		exit( EXIT_FAILURE );

#ifdef USE_TCHECK
	THREAD_DEBUG_SUSPEND();
#endif /* USE_TCHECK */

	/* Make sure that various system-specific features are set right */
	testSystemSpecific1();

	/* VisualAge C++ doesn't set the TZ correctly.  The check for this isn't
	   as simple as it would seem since most IBM compilers define the same
	   preprocessor values even though it's not documented anywhere, so we
	   have to enable the tzset() call for (effectively) all IBM compilers
	   and then disable it for ones other than VisualAge C++ */
#if ( defined( __IBMC__ ) || defined( __IBMCPP__ ) ) && !defined( __VMCMS__ )
	tzset();
#endif /* VisualAge C++ */

	/* Initialise cryptlib */
	printf( "Initialising cryptlib..." );
	status = cryptInit();
	if( cryptStatusError( status ) )
		{
		printf( "\ncryptInit() failed with error code %d, line %d.\n", 
				status, __LINE__ );
		exit( EXIT_FAILURE );
		}
	puts( "done." );

#ifndef TEST_RANDOM
	/* In order to avoid having to do a randomness poll for every test run,
	   we bypass the randomness-handling by adding some junk.  This is only
	   enabled when cryptlib is built in debug mode so it won't work with 
	   any production systems */
  #if defined( __MVS__ ) || defined( __VMCMS__ )
	#pragma convlit( resume )
	cryptAddRandom( "xyzzy", 5 );
	#pragma convlit( suspend )
  #else
	cryptAddRandom( "xyzzy", 5 );
  #endif /* Special-case EBCDIC handling */
#endif /* TEST_RANDOM */

	/* Perform a general sanity check to make sure that the self-test is
	   being run the right way */
	if( !checkFileAccess() )
		{
		cryptEnd();
		exit( EXIT_FAILURE );
		}

	/* Make sure that further system-specific features that require cryptlib 
	   to be initialised to check are set right */
#ifndef _WIN32_WCE
	testSystemSpecific2();
#endif /* WinCE */

#ifdef USE_TCHECK
	THREAD_DEBUG_RESUME();
#endif /* USE_TCHECK */

	/* For general testing purposes we can insert test code at this point to
	   test special cases that aren't covered in the general tests below */
	testKludge( zargPtr );

#ifdef SMOKE_TEST
	/* Perform a general smoke test of the kernel */
	smokeTest();
#endif /* SMOKE_TEST */

	/* Test each block of cryptlib functionality */
	if( ( flags & DO_SELFTEST ) && !testSelfTest() )
		goto errorExit;
	if( ( flags & DO_LOWLEVEL ) && !testLowLevel() )
		goto errorExit;
	if( ( flags & DO_RANDOM ) && !testRandom() )
		goto errorExit;
	if( ( flags & DO_CONFIG ) && !testConfig() )
		goto errorExit;
	if( ( flags & DO_DEVICE ) && !testDevice() )
		goto errorExit;
	if( ( flags & DO_MIDLEVEL ) && !testMidLevel() )
		goto errorExit;
	if( ( flags & DO_CERT ) && !testCert() )
		goto errorExit;
	if( ( flags & DO_KEYSETFILE ) && !testKeysetFile() )
		goto errorExit;
	if( ( flags & DO_KEYSETDBX ) && !testKeysetDatabase() )
		goto errorExit;
	if( ( flags & DO_CERTPROCESS ) && !testCertMgmt() )
		goto errorExit;
	if( ( flags & DO_HIGHLEVEL ) && !testHighLevel() )
		goto errorExit;
	if( ( flags & DO_ENVELOPE ) && !testEnveloping() )
		goto errorExit;
	if( ( flags & DO_SESSION ) && !testSessions() )
		{
		sessionTestError = TRUE;
		goto errorExit;
		}
	if( ( flags & DO_SESSIONLOOPBACK ) && !testSessionsLoopback() )
		{
		loopbackTestError = TRUE;
		goto errorExit;
		}
	if( ( flags & DO_USER  ) && !testUsers() )
		goto errorExit;

	/* Shut down cryptlib */
	status = cryptEnd();
	if( cryptStatusError( status ) )
		{
		if( status == CRYPT_ERROR_INCOMPLETE )
			{
			puts( "cryptEnd() failed with error code CRYPT_ERROR_INCOMPLETE, "
				  "a code path in the\nself-test code resulted in an error "
				  "return without a full cleanup of objects.\nIf you were "
				  "running the multithreaded loopback tests this may be "
				  "because one\nor more threads lost sync with other threads "
				  "and exited without cleaning up\nits objects.  This "
				  "happens occasionally due to network timing issues or\n"
				  "thread scheduling differences." );
			}
		else
			{
			printf( "cryptEnd() failed with error code %d, line %d.\n", 
					status, __LINE__ );
			}
		goto errorExit1;
		}

	puts( "All tests concluded successfully." );
	return( EXIT_SUCCESS );

	/* All errors end up here */
errorExit:
	cryptEnd();
errorExit1:
	puts( "\nThe test was aborted due to an error being detected.  If you "
		  "want to report\nthis problem, please provide as much information "
		  "as possible to allow it to\nbe diagnosed, for example the call "
		  "stack, the location inside cryptlib where\nthe problem occurred, "
		  "and the values of any variables that might be\nrelevant." );
	if( sessionTestError )
		{
		puts( "\nThe error occurred during one of the network session tests, "
			  "if the error\nmessage indicates a network-level problem such "
			  "as ECONNREFUSED, ECONNRESET,\nor a timeout or read error then "
			  "this is either due to a transient\nnetworking problem or a "
			  "firewall interfering with network connections.  This\nisn't a "
			  "cryptlib error, and doesn't need to be reported." );
		}
	if( loopbackTestError )
		{
		puts( "\nThe error occurred during one of the multi-threaded network "
			  "loopback\ntests, this was probably due to the different threads "
			  "losing synchronisation.\nFor the secure sessions this usually "
			  "results in read/write, timeout, or\nconnection-closed errors "
			  "when one thread is pre-empted for too long.  For the\n"
			  "certificate-management sessions it usually results in an error "
			  "related to the\nserver being pre-empted for too long by database "
			  "updates.  Since the self-\ntest exists only to exercise "
			  "cryptlib's capabilities, it doesn't bother with\ncomplex thread "
			  "synchronisation during the multi-threaded loopback tests.\nThis "
			  "type of error is non-fatal, and should disappear if the test is "
			  "re-run." );
		}

	cleanExit( EXIT_FAILURE );
	return( EXIT_FAILURE );			/* Get rid of compiler warnings */
	}