Ejemplo n.º 1
0
static int readKeyIdentifiers( INOUT STREAM *stream, 
							   INOUT PKCS15_INFO *pkcs15infoPtr,
							   IN_LENGTH const int endPos )
	{
	int iterationCount, status;

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

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

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

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

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

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

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

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

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

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

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

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

	return( status );
	}
Ejemplo n.º 2
0
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 );
	}
Ejemplo n.º 3
0
static int processCertWrapper( INOUT STREAM *stream, 
							   OUT_LENGTH_SHORT_Z int *objectOffset, 
							   OUT_DATALENGTH_Z int *objectLength, 
							   IN_DATALENGTH_Z const int objectStartPos )
	{
	static const CMS_CONTENT_INFO FAR_BSS oidInfoSignedData = { 1, 3 };
	static const OID_INFO FAR_BSS signedDataOIDinfo[] = {
		{ OID_CMS_SIGNEDDATA, CRYPT_OK, &oidInfoSignedData },
		{ NULL, 0 }, { NULL, 0 }
		};
	static const OID_INFO FAR_BSS dataOIDinfo[] = {
		{ OID_CMS_DATA, CRYPT_OK, NULL },
		{ NULL, 0 }, { NULL, 0 }
		};
	long length;
	int setLength, localLength, offset DUMMY_INIT, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isWritePtr( objectOffset, sizeof( int ) ) );
	assert( isWritePtr( objectLength, sizeof( int ) ) );

	REQUIRES( objectStartPos >= 0 && objectStartPos < MAX_BUFFER_SIZE );

	/* Clear return values */
	*objectOffset = *objectLength = 0;

	/* Read the SignedData wrapper */
	sseek( stream, objectStartPos );
	status = readCMSheader( stream, signedDataOIDinfo, 
							FAILSAFE_ARRAYSIZE( signedDataOIDinfo, OID_INFO ), 
							&length, READCMS_FLAG_NONE );
	if( cryptStatusError( status ) )
		return( status );

	/* Read the SET OF DigestAlgorithmIdentifier, empty for a pure 
	   certificate chain, nonempty for signed data or buggy certificate 
	   chains */
	status = readSet( stream, &setLength );
	if( cryptStatusOK( status ) && setLength > 0 )
		status = sSkip( stream, setLength, MAX_INTLENGTH_SHORT );
	if( cryptStatusError( status ) )
		return( status );

	/* Read the ContentInfo information */
	status = readCMSheader( stream, dataOIDinfo, 
							FAILSAFE_ARRAYSIZE( dataOIDinfo, OID_INFO ), 
							&length, READCMS_FLAG_INNERHEADER );
	if( cryptStatusError( status ) )
		return( status );

	/* If we've been fed signed data (i.e. the ContentInfo has the content 
	   field present), skip the content to get to the certificate chain */
	if( length > 0 )
		{
		status = sSkip( stream, length, MAX_INTLENGTH_SHORT );
		if( cryptStatusError( status ) )
			return( status );
		}
	else
		{
		/* If we have an indefinite length then there could be up to three 
		   EOCs present (one for each of the SEQUENCE, [0], and OCTET 
		   STRING), which we have to skip.  In theory there could be content
		   present as well but at that point we're going to be replicating
		   large chunks of the de-enveloping code so we only try and process
		   zero-length content, created by some buggy browser's cert-export
		   code (possibly Firefox)  */
		if( length == CRYPT_UNUSED )
			{
			int i;

			for( i = 0; i < 3; i++ )
				{
				status = checkEOC( stream );
				if( cryptStatusError( status ) )
					return( status );
				if( !status )
					break;
				}
			}
		}

	/* We've reached the inner content encapsulation, find out how long the 
	   content (i.e. the chain of certificates) is */
	status = getStreamObjectLength( stream, &localLength );
	if( cryptStatusOK( status ) )
		{
		offset = stell( stream );
		status = readConstructedI( stream, NULL, 0 );
		}
	if( cryptStatusError( status ) )
		return( status );

	/* Adjust for the [0] { ... } wrapper that contains the list of 
	   certificate, returning a pointer to the collection of certificates
	   without any encapsulation */
	localLength -= stell( stream ) - offset;
	if( localLength < MIN_CERTSIZE || localLength >= MAX_INTLENGTH )
		return( CRYPT_ERROR_BADDATA );
	*objectOffset = stell( stream );
	*objectLength = localLength;
	
	return( CRYPT_OK );
	}