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

📄 lib_dbms.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 5 页
字号:
						const int maxLength )
	{
	int inPos = 0, outPos = 0, status = CRYPT_OK;

	while( inPos < inputLength )
		{
		if( input[ inPos ] == '$' )
			{
			const char *fieldName = &input[ inPos + 1 ];
			const char *outputFieldName;
			const int fieldPos = inPos + 1;
			int length;

			inPos++;	/* Skip '$' */

			/* Extract the field name and translate it into the table
			   column name */
			while( isalpha( input[ inPos ] ) )
				inPos++;
			length = inPos - fieldPos;
			if( length <= 0 )
				{
				status = CRYPT_ERROR_BADDATA;
				break;
				}
			if( !strnicmp( fieldName, "C", length ) )
				outputFieldName = "C";
			else
			if( !strnicmp( fieldName, "SP", length ) )
				outputFieldName = "SP";
			else
			if( !strnicmp( fieldName, "L", length ) )
				outputFieldName = "L";
			else
			if( !strnicmp( fieldName, "O", length ) )
				outputFieldName = "O";
			else
			if( !strnicmp( fieldName, "OU", length ) )
				outputFieldName = "OU";
			else
			if( !strnicmp( fieldName, "CN", length ) )
				outputFieldName = "CN";
			else
			if( !strnicmp( fieldName, "email", length ) )
				outputFieldName = "email";
			else
			if( !strnicmp( fieldName, "date", length ) )
				outputFieldName = "validTo";
			else
				{
				status = CRYPT_ERROR_BADDATA;
				break;
				}
			length = strlen( outputFieldName );

			/* Copy the translated name to the output buffer */
			if( outPos + length >= maxLength - 1 )
				{
				status = CRYPT_ERROR_OVERFLOW;
				break;
				}
			strcpy( output + outPos, outputFieldName );
			outPos += length;
			}
		else
			{
			const char ch = input[ inPos++ ];

			/* Just copy the char over, with a length check */
			if( outPos > maxLength - 1 )
				{
				outPos = 0;
				break;
				}
#ifdef __WINDOWS__
			/* Bypass the ODBC security problem mentioned above */
			if( ch != '|' )
#endif /* __WINDOWS__ */
			output[ outPos++ ] = ch;
			}
		}
	if( cryptStatusError( status ) )
		outPos = 0;
	output[ outPos++ ] = '\0';	/* Add der terminador */

	return( status );
	}

/* Set up key ID information for a query.  There are two variations of
   this, makeKeyID() encodes an existing keyID value and getKeyID() reads an 
   attribute from an object and encodes it */

static void makeKeyID( char *keyIDbuffer, const CRYPT_KEYID_TYPE keyIDtype,
					   const void *keyID, const int keyIDlength )
	{
	const int idLength = min( keyIDlength, ( CRYPT_MAX_TEXTSIZE * 2 ) - 1 );

	assert( ( keyIDtype == CRYPT_KEYID_NAME || \
			  keyIDtype == CRYPT_KEYID_EMAIL ) || \
			( keyIDtype == CRYPT_IKEYID_KEYID || \
			  keyIDtype == CRYPT_IKEYID_ISSUERID || \
			  keyIDtype == CRYPT_IKEYID_CERTID ) );

	/* Name and email address are used as is */
	if( keyIDtype == CRYPT_KEYID_NAME || \
		keyIDtype == CRYPT_KEYID_EMAIL )
		{
		memcpy( keyIDbuffer, keyID, idLength );
		keyIDbuffer[ idLength ] = '\0';
		}

	/* A keyID is just a subjectKeyIdentifier, which is supposed to be an 
	   SHA-1 hash anyway but which in practice can be almost anything so we
	   always hash it to a fixed-length value */
	if( keyIDtype == CRYPT_IKEYID_KEYID )
		{
		HASHFUNCTION hashFunction;
		BYTE hashBuffer[ CRYPT_MAX_HASHSIZE ];
		int hashSize;

		/* Get the hash algorithm information and hash the keyID to get
		   the fixed-length keyID */
		getHashParameters( CRYPT_ALGO_SHA, &hashFunction, &hashSize );
		hashFunction( NULL, hashBuffer, ( void * ) keyID, keyIDlength,
					  HASH_ALL );
		base64encode( keyIDbuffer, hashBuffer, DBXKEYID_SIZE,
					  CRYPT_CERTTYPE_NONE );
		keyIDbuffer[ MAX_ENCODED_DBXKEYID_SIZE ] = '\0';
		return;
		}
	if( keyIDtype == CRYPT_IKEYID_ISSUERID || \
		keyIDtype == CRYPT_IKEYID_CERTID )
		{
		assert( ( keyIDtype == CRYPT_IKEYID_CERTID && \
				  keyIDlength == DBXKEYID_SIZE ) || \
				( keyIDtype != CRYPT_IKEYID_CERTID ) );

		/* base64-encode the key ID so we can use it with database queries.
		   Since we only store 128 bits of a (usually 160 bit) ID to save
		   space (particularly where it's used in indices) and speed lookups,
		   this encoding step has a side-effect of truncating the ID down to
		   the correct size */
		base64encode( keyIDbuffer, keyID, DBXKEYID_SIZE, CRYPT_CERTTYPE_NONE );
		keyIDbuffer[ MAX_ENCODED_DBXKEYID_SIZE ] = '\0';
		return;
		}
	}

static int getKeyID( char *keyIDbuffer, const CRYPT_HANDLE cryptHandle,
					 const CRYPT_ATTRIBUTE_TYPE keyIDtype )
	{
	RESOURCE_DATA msgData;
	BYTE hashBuffer[ CRYPT_MAX_HASHSIZE ];
	int status;

	assert( ( keyIDtype == CRYPT_IATTRIBUTE_CERTID || \
			  keyIDtype == CRYPT_IATTRIBUTE_AUTHCERTID ) || \
			( keyIDtype == CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER || \
			  keyIDtype == CRYPT_IATTRIBUTE_ISSUER || \
			  keyIDtype == CRYPT_IATTRIBUTE_SUBJECT || \
			  keyIDtype == CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER || \
			  keyIDtype == CRYPT_IATTRIBUTE_SPKI ) );

	/* Get the attribute from the cert and hash it unless it's already a
	   hash */
	if( keyIDtype != CRYPT_IATTRIBUTE_CERTID && \
		keyIDtype == CRYPT_IATTRIBUTE_AUTHCERTID )
		{
		setResourceData( &msgData, hashBuffer, CRYPT_MAX_HASHSIZE );
		status = krnlSendMessage( cryptHandle, 
								  RESOURCE_IMESSAGE_GETATTRIBUTE_S,
								  &msgData, keyIDtype );
		assert( msgData.length == KEYID_SIZE );
		if( cryptStatusError( status ) )
			return( status );
		}
	else
		{
		BYTE buffer[ 1024 ], *bufPtr = buffer;
		HASHFUNCTION hashFunction;
		int hashSize;

		/* Get the attribute data */
		setResourceData( &msgData, NULL, 0 );
		status = krnlSendMessage( cryptHandle, 
								  RESOURCE_IMESSAGE_GETATTRIBUTE_S,
								  &msgData, keyIDtype );
		if( cryptStatusError( status ) )
			return( status );
		if( msgData.length > 1024 && \
			( bufPtr = malloc( msgData.length ) ) == NULL )
			return( CRYPT_ERROR_MEMORY );
		msgData.data = bufPtr;
		status = krnlSendMessage( cryptHandle, 
								  RESOURCE_IMESSAGE_GETATTRIBUTE_S,
								  &msgData, keyIDtype );
		if( cryptStatusError( status ) )
			{
			if( bufPtr != buffer )
				free( bufPtr );
			return( status );
			}

		/* Get the hash algorithm information and hash the attribute to get
		   the ID */
		getHashParameters( CRYPT_ALGO_SHA, &hashFunction, &hashSize );
		hashFunction( NULL, hashBuffer, bufPtr, msgData.length, HASH_ALL );
		assert( hashSize == KEYID_SIZE );
		if( bufPtr != buffer )
			free( bufPtr );
		}

	/* base64-encode the key ID so we can use it with database queries.  
	   Since we only store 128 bits of a (usually 160 bit) ID to save space 
	   (particularly where it's used in indices) and speed lookups, this 
	   encoding step has a side-effect of truncating the ID down to the 
	   correct size */
	base64encode( keyIDbuffer, hashBuffer, DBXKEYID_SIZE,
				  CRYPT_CERTTYPE_NONE );
	keyIDbuffer[ MAX_ENCODED_DBXKEYID_SIZE ] = '\0';
	return( CRYPT_OK );
	}

static char *getKeyName( const CRYPT_KEYID_TYPE keyIDtype )
	{
	switch( keyIDtype )
		{
		case CRYPT_KEYID_NAME:
			return( "CN" );

		case CRYPT_KEYID_EMAIL:
			return( "email" );

		case CRYPT_IKEYID_KEYID:
			return( "keyID" );

		case CRYPT_IKEYID_ISSUERID:
			return( "issuerID" );

		case CRYPT_IKEYID_CERTID:
			return( "certID" );
		}

	assert( NOTREACHED );
	return( NULL );			/* Get rid of compiler warning */
	}

/* Get a keyID for a certificate */

static int getCertKeyID( char *keyID, const CRYPT_CERTIFICATE iCryptCert )
	{
	int status;

	/* Certificate keyID handling isn't quite as simple as just reading an
	   attribute from the certificate since the subjectKeyIdentifier (if
	   present) may not be the same as the keyID if the cert has come from
	   a CA which does strange things with the sKID.  To resolve this we try
	   and build the key ID from the sKID, if this isn't present we use the
	   keyID (the sKID may have a nonstandard length since it's possible to
	   stuff anything in there, getKeyID() will hash it to the standard size
	   if the length is wrong) */
	status = getKeyID( keyID, iCryptCert,
					   CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER );
	if( cryptStatusOK( status ) )
		return( CRYPT_OK );

	/* There's no subjectKeyIdentifier, use the keyID.  Note that we can't
	   just read the CRYPT_IATTRIBUTE_KEYID attribute directly since this
	   may be a data-only cert (either a standalone cert or one from the
	   middle of a chain), so we have to generate it indirectly by hashing
	   the SubjectPublicKeyInfo, which is equivalent to the keyID and is
	   always present in a cert */
	return( getKeyID( keyID, iCryptCert, CRYPT_IATTRIBUTE_SPKI ) );
	}

/* Create a new key database */

static int createDatabase( KEYSET_INFO *keysetInfo )
	{
	int status;

	/* Create tables for public keys, CRL's, revoked certs, and cert requests.
	   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.

	   If the one of the tables is deleted outside of cryptlib and others
	   left in place then creation will fail because one or more tables
	   already exist.  This is an anomalous situation (the users shouldn't
	   modify the tables outside cryptlib), but in the interests of luser-
	   friendliness we ignore a CRYPT_ERROR_DUPLICATE for the other tables if
	   the basic cert table creation succeeded */
	status = performStaticUpdate( &keysetInfo->keysetDBMS,
					"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( keysetInfo->keysetDBMS.isCertStore )
		/* 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 and the
		   nameID which is used to force clustering of entries for each CA */
		status = performStaticUpdate( &keysetInfo->keysetDBMS,
					"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 = performStaticUpdate( &keysetInfo->keysetDBMS,
					"CREATE TABLE CRLs ("
						"issuerID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL,"
						"certID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL, "
						"certData BLOB NOT NULL)" );
	if( cryptStatusError( status ) && status != CRYPT_ERROR_DUPLICATE )
		{
		/* Undo the certificate table creation */
		performStaticUpdate( &keysetInfo->keysetDBMS,
					"DROP TABLE certificates" );
		return( status );
		}
	if( keysetInfo->keysetDBMS.isCertStore )
		{
		status = performStaticUpdate( &keysetInfo->keysetDBMS,
					"CREATE TABLE pkiUsers ("
						"C CHAR(2), "
						"SP VARCHAR(64), "
						"L VARCHAR(64), "
						"O VARCHAR(64), "
						"OU VARCHAR(64), "
						"CN VARCHAR(64), "
						"keyID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL, "
						"certID CHAR(" TEXT_DBXKEYID_SIZE ") NOT NULL, "
						"certData BLOB NOT NULL)" );
		if( cryptStatusError( status ) && status != CRYPT_ERROR_DUPLICATE )
			{
			/* Undo the previous table creations */
			performStaticUpdate( &keysetInfo->keysetDBMS,
					"DROP TABLE certificates" );
			performStaticUpdate( &keysetInfo->keysetDBMS,
					"DROP TABLE CRLs" );

⌨️ 快捷键说明

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