⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dbxdbx.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 4 页
字号:
			if( keyUsage & 0x20 )
				return( TRUE );
			}
		else
			if( keyUsage & 0x80 )
				return( TRUE );

		/* The requested usage isn't permitted by this cert */
		return( FALSE );
		}

	/* No key usage found, assume that any usage is OK */
	return( TRUE );
	}

/* Create a new key database */

static int createDatabase( DBMS_INFO *dbmsInfo )
	{
	int updateProgress = 0, status;

	/* Create tables for certs, CRLs, cert requests, PKI users, and CA logs.
	   We use CHAR rather than VARCHAR for the ID fields since these always
	   have a fixed length and CHAR is faster than VARCHAR.  In addition we
	   make as many columns as possible NOT NULL since these fields should
	   always be present, and because this is faster for most databases.  The
	   BLOB type is nonstandard, this is rewritten by the database interface
	   layer to the type which is appropriate for the database */
	status = dbmsStaticUpdate(
			"CREATE TABLE certificates ("
				"C CHAR(2), "
				"SP VARCHAR(64), "
				"L VARCHAR(64), "
				"O VARCHAR(64), "
				"OU VARCHAR(64), "
				"CN VARCHAR(64), "
				"email VARCHAR(64), "
				"validTo DATETIME NOT NULL, "
				"nameID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL, "
				"issuerID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL, "
				"keyID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL, "
				"certID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL, "
				"certData BLOB NOT NULL)" );
	if( cryptStatusError( status ) )
		return( status );
	if( isCertStore( dbmsInfo ) )
		/* The cert store contains in addition to the other CRL fields the
		   certificate expiry time which is used to remove the entry from
		   the CRL table once the certificate has expired anyway, the nameID
		   which is used to force clustering of entries for each CA, and the
		   ID of the cert being revoked, which isn't available if we're
		   creating it from a raw CRL */
		status = dbmsStaticUpdate(
			"CREATE TABLE CRLs ("
				"expiryDate DATETIME NOT NULL, "
				"nameID CHAR(" TEXT_DBXKEYID_SIZE ") PRIMARY KEY NOT NULL, "
				"issuerID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL,"
				"certID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL, "
				"certData BLOB NOT NULL)" );
	else
		status = dbmsStaticUpdate(
			"CREATE TABLE CRLs ("
				"issuerID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL,"
				"certData BLOB NOT NULL)" );
	if( cryptStatusOK( status ) && isCertStore( dbmsInfo ) )
		{
		updateProgress++;
		status = dbmsStaticUpdate(
			"CREATE TABLE pkiUsers ("
				"C CHAR(2), "
				"SP VARCHAR(64), "
				"L VARCHAR(64), "
				"O VARCHAR(64), "
				"OU VARCHAR(64), "
				"CN VARCHAR(64), "
				"nameID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL, "
				"keyID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL, "
				"certID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL, "
				"certData BLOB NOT NULL)" );
		}
	if( cryptStatusOK( status ) && isCertStore( dbmsInfo ) )
		{
		updateProgress++;
		status = dbmsStaticUpdate(
			"CREATE TABLE certRequests ("
				"type SMALLINT NOT NULL, "
				"C CHAR(2), "
				"SP VARCHAR(64), "
				"L VARCHAR(64), "
				"O VARCHAR(64), "
				"OU VARCHAR(64), "
				"CN VARCHAR(64), "
				"email VARCHAR(64), "
				"certID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL, "
				"certData BLOB NOT NULL)" );
		}
	if( cryptStatusOK( status ) && isCertStore( dbmsInfo ) )
		{
		updateProgress++;
		status = dbmsStaticUpdate(
			"CREATE TABLE certLog ("
				"action SMALLINT NOT NULL, "
				"actionTime DATETIME NOT NULL, "
				"certID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL, "
				"reqCertID CHAR(" TEXT_DBXKEYID_SIZE "), "
				"subjCertID CHAR(" TEXT_DBXKEYID_SIZE "), "
				"certData BLOB)" );
		}
	if( cryptStatusError( status ) )
		{
		/* Undo the previous table creations */
		dbmsStaticUpdate( "DROP TABLE certificates" );
		if( updateProgress > 0 )
			dbmsStaticUpdate( "DROP TABLE CRLs" );
		if( updateProgress > 1 )
			dbmsStaticUpdate( "DROP TABLE pkiUsers" );
		if( updateProgress > 2 )
			dbmsStaticUpdate( "DROP TABLE certRequests" );
		return( status );
		}

	/* Create an index for the email address, nameID, issuerID, keyID, and
	   certID in the certificates table, the issuerID and certID in the CRLs
	   table (the CRL nameID isn't indexed since we only use it for linear
	   scans, however it's designated the primary key to ensure that rows are
	   clustered around it), the nameID and keyID in the PKI users table (the
	   former isn't used but is made a UNIQUE INDEX to ensure that the same 
	   entry can't be added more than once) and the certID in the cert log 
	   (this also isn't used but is made a UNIQUE INDEX to ensure that the 
	   same entry can't be added more than once).  We have to give these 
	   unique names since some databases don't allow two indexes to have the 
	   same name, even if they're in a different table.  Since most of the 
	   fields in the tables are supposed to be unique, we can specify this 
	   for the indexes we're creating, however we can't do it for the email 
	   address or the nameID in the certs table since there could be multiple 
	   certs present that differ only in key usage.  We don't index the other 
	   tables since indexes consume space and we don't expect to access any 
	   of these much */
	status = dbmsStaticUpdate(
			"CREATE INDEX emailIdx ON certificates(email)" );
	if( cryptStatusOK( status ) )
		status = dbmsStaticUpdate(
			"CREATE INDEX nameIDIdx ON certificates(nameID)" );
	if( cryptStatusOK( status ) )
		status = dbmsStaticUpdate(
			"CREATE UNIQUE INDEX issuerIDIdx ON certificates(issuerID)" );
	if( cryptStatusOK( status ) )
		status = dbmsStaticUpdate(
			"CREATE UNIQUE INDEX keyIDIdx ON certificates(keyID)" );
	if( cryptStatusOK( status ) )
		status = dbmsStaticUpdate(
			"CREATE UNIQUE INDEX certIDIdx ON certificates(certID)" );
	if( cryptStatusOK( status ) )
		status = dbmsStaticUpdate(
			"CREATE UNIQUE INDEX crlIssuerIDIdx ON CRLs (issuerID)" );
	if( cryptStatusOK( status ) && isCertStore( dbmsInfo ) )
		status = dbmsStaticUpdate(
			"CREATE UNIQUE INDEX crlCertIDIdx ON CRLs (certID)" );
	if( cryptStatusOK( status ) && isCertStore( dbmsInfo ) )
		status = dbmsStaticUpdate(
			"CREATE UNIQUE INDEX userKeyIDIdx ON pkiUsers (keyID)" );
	if( cryptStatusOK( status ) && isCertStore( dbmsInfo ) )
		status = dbmsStaticUpdate(
			"CREATE UNIQUE INDEX userNameIDIdx ON pkiUsers (nameID)" );
	if( cryptStatusOK( status ) && isCertStore( dbmsInfo ) )
		status = dbmsStaticUpdate(
			"CREATE UNIQUE INDEX logCertIDIdx ON certLog (certID)" );
	if( cryptStatusOK( status ) && isCertStore( dbmsInfo ) )
		{
		char dummyCertID[ DBXKEYID_BUFFER_SIZE ];

		/* Create a special dummy certID with an out-of-band value to mark
		   the first entry in the log */
		memset( dummyCertID, '-', MAX_ENCODED_DBXKEYID_SIZE );
		dummyCertID[ MAX_ENCODED_DBXKEYID_SIZE - 1 ] = '\0';

		/* Add the initial log entry recording the creation of the log */
		status = updateCertLog( dbmsInfo, CRYPT_CERTACTION_CREATE,
								dummyCertID, NULL, NULL, NULL, 0,
								DBMS_UPDATE_NORMAL );
		}
	if( cryptStatusError( status ) )
		{
		/* Undo the creation of the various tables */
		dbmsStaticUpdate( "DROP TABLE certificates" );
		dbmsStaticUpdate( "DROP TABLE CRLs" );
		if( isCertStore( dbmsInfo ) )
			{
			dbmsStaticUpdate( "DROP TABLE pkiUsers" );
			dbmsStaticUpdate( "DROP TABLE certRequests" );
			dbmsStaticUpdate( "DROP TABLE certLog" );
			}
		return( CRYPT_ERROR_WRITE );
		}

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							Database Access Functions						*
*																			*
****************************************************************************/

/* Fetch a sequence of certs from a data source.  This is called in one of
   two ways, either indirectly by the certificate code to fetch the first and
   subsequent certs in a chain or directly by the user after submitting a
   query to the keyset (which doesn't return any data) to read the results of
   the query */

int getItemData( DBMS_INFO *dbmsInfo, CRYPT_CERTIFICATE *iCertificate,
				 int *stateInfo, const char *keyName, const char *keyValue,
				 const KEYMGMT_ITEM_TYPE itemType, const int options )
	{
	MESSAGE_CREATEOBJECT_INFO createInfo;
	const BOOLEAN multiCertQuery = ( options & KEYMGMT_MASK_USAGEOPTIONS ) ? \
								   TRUE : FALSE;
	const DBMS_QUERY_TYPE queryType = \
					( stateInfo == NULL || multiCertQuery ) ? \
					DBMS_QUERY_CONTINUE : DBMS_QUERY_NORMAL;
	BYTE certificate[ MAX_CERT_SIZE ];
	BOOLEAN continueFetch;
	char keyBuffer[ MAX_QUERY_RESULT_SIZE ], *keyPtr = keyBuffer;
	char sqlBuffer[ MAX_SQL_QUERY_SIZE ], *sqlBufPtr = NULL;
	int keyLength, status;

	assert( itemType == KEYMGMT_ITEM_NONE || \
			itemType == KEYMGMT_ITEM_PUBLICKEY || \
			itemType == KEYMGMT_ITEM_REQUEST || \
			itemType == KEYMGMT_ITEM_PKIUSER || \
			itemType == KEYMGMT_ITEM_REVOCATIONINFO );

	/* Make sure that we can never explicitly fetch anything with an ID that
	   indicates that it's physically but not logically present, for example
	   certificates that have been created but not fully issued yet, cert
	   items that are on hold, and similar items */
	if( keyValue != NULL && \
		( !memcmp( keyValue, "--", 2 ) || !memcmp( keyValue, "++", 2 ) ) )
		/* Eheu, litteras istas reperire non possum */
		return( CRYPT_ERROR_NOTFOUND );

	/* If we have binary blob support, fetch the data directly into the
	   certificate buffer */
	if( hasBinaryBlobs( dbmsInfo ) )
		keyPtr = ( char * ) certificate;

	/* If this isn't an ongoing fetch from a query submitted earlier, prepare
	   and submit the query to fetch the data */
	if( stateInfo != NULL )
		{
		dbmsFormatSQL( sqlBuffer,
			"SELECT certData FROM $ WHERE $ = '$'",
					   getTableName( itemType ), keyName, keyValue );
		if( multiCertQuery )
			{
			/* We're fetching a collection of certs in order to pick out the
			   one that we want, submit the query to start the fetch */
			status = dbmsQuery( sqlBuffer, NULL, NULL, 0, DBMS_QUERY_START );
			if( cryptStatusError( status ) )
				return( status );
			}
		else
			/* It's a point query, submit it as we do the fetch */
			sqlBufPtr = sqlBuffer;
		}

	do
		{
		/* Retrieve the record and base64-decode the binary cert data if
		   necessary */
		status = dbmsQuery( sqlBufPtr, keyPtr, &keyLength, 0, queryType );
		if( cryptStatusOK( status ) && !hasBinaryBlobs( dbmsInfo ) )
			{
			keyLength = base64decode( certificate, keyBuffer, keyLength,
									  CRYPT_CERTFORMAT_NONE );
			if( !keyLength )
				status = CRYPT_ERROR_BADDATA;
			}
		if( cryptStatusError( status ) )
			/* Convert the error code to a more appropriate value if
			   appropriate */
			return( ( multiCertQuery && ( status == CRYPT_ERROR_COMPLETE ) ) ? \
					CRYPT_ERROR_NOTFOUND : status );

		/* If the first byte of the cert data is 0xFF, this is an item which
		   is physically but not logically present (see the comment above in
		   the check for the keyValue), which means we can't explicitly fetch
		   it.  If it's a point query this means we didn't find anything,
		   otherwise we try again with the next result */
		if( certificate[ 0 ] == 0xFF )
			{
			if( sqlBufPtr == sqlBuffer )
				/* Point query, we found something but it isn't there.
				   "Can't you understand English you arse, we're not at home"
				   -- Jeremy Black, "The Boys from Brazil" */
				return( CRYPT_ERROR_NOTFOUND );
			continueFetch = TRUE;
			}
		else
			/* If more than one cert is present and the requested key usage
			   doesn't match the one indicated in the cert, try again */
			if( multiCertQuery && \
				!checkCertUsage( certificate, keyLength, options ) )
				continueFetch = TRUE;
			else
				/* We got what we wanted, exit */
				continueFetch = FALSE;
		}
	while( continueFetch );

	/* If we've been looking through multiple certs, cancel the outstanding
	   query, which is still in progress */
	if( multiCertQuery )
		dbmsStaticQuery( NULL, DBMS_QUERY_CANCEL );

	/* Create a certificate object from the encoded cert.  If we're reading 
	   revocation information the data is a single CRL entry so we have to 
	   tell the cert import code to treat it as a special case of a CRL.  If
	   we're reading a request, it could be one of several types so we have
	   to use autodetection rather than specifying an exact format */
	setMessageCreateObjectIndirectInfo( &createInfo, certificate, keyLength,
		( itemType == KEYMGMT_ITEM_PUBLICKEY || \
		  itemType == KEYMGMT_ITEM_NONE ) ? CRYPT_CERTTYPE_CERTIFICATE : \
		( itemType == KEYMGMT_ITEM_REQUEST ) ? CRYPT_CERTTYPE_NONE : \
		( itemType == KEYMGMT_ITEM_PKIUSER ) ? CRYPT_CERTTYPE_PKIUSER : \
		( itemType == KEYMGMT_ITEM_REVOCATIONINFO ) ? CERTFORMAT_REVINFO : \
		CRYPT_CERTTYPE_NONE );
	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
							  IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
							  &createInfo, OBJECT_TYPE_CERTIFICATE );
	if( cryptStatusError( status ) )
		return( status );
	*iCertificate = createInfo.cryptHandle;

	/* If this was a read with state held externally, remember where we got
	   to so we can fetch the next cert in the sequence */
	if( stateInfo != NULL )
		*stateInfo = *iCertificate;
	return( CRYPT_OK );
	}

static int getFirstItemFunction( KEYSET_INFO *keysetInfo,
								 CRYPT_CERTIFICATE *iCertificate,
								 int *stateInfo,
								 const CRYPT_KEYID_TYPE keyIDtype,
								 const void *keyID, const int keyIDlength,
								 const KEYMGMT_ITEM_TYPE itemType,
								 const int options )
	{
	DBMS_INFO *dbmsInfo = keysetInfo->keysetDBMS;
	char keyIDbuffer[ CRYPT_MAX_TEXTSIZE * 2 ];
	int status;

	/* If it's a general query, submit the query to the database */
	if( stateInfo == NULL )
		{
		char sqlBuffer[ MAX_SQL_QUERY_SIZE ];
		int sqlLength;

		assert( itemType == KEYMGMT_ITEM_PUBLICKEY || \
				itemType == KEYMGMT_ITEM_REQUEST );
		assert( options == KEYMGMT_FLAG_NONE );

		if( keyIDlength > MAX_SQL_QUERY_SIZE - 64 )
			return( CRYPT_ARGERROR_STR1 );

		/* If we're cancelling an existing query, pass it on down */
		if( keyIDlength == 6 && !strCompare( keyID, "cancel", keyIDlength ) )
			{
			status = dbmsStaticQuery( NULL, DBMS_QUERY_CANCEL );
			return( status );
			}

		assert( !keysetInfo->isBusyFunction( keysetInfo ) );

		/* Rewrite the user-supplied portion of the query using the actual
		   column names and append it to the SELECT statement */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -