/****************************************************************************
*																			*
*						cryptlib Internal API Header File 					*
*						Copyright Peter Gutmann 1992-2016					*
*																			*
****************************************************************************/

#ifndef _INTAPI_DEFINED

#define _INTAPI_DEFINED

/* Copy a string attribute to external storage, with various range checks
   to follow the cryptlib external API semantics.  There are two variants
   of this function depending on whether the result parameters are passed
   in as discrete values or packed into a MESSAGE_DATA struct */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int attributeCopy( INOUT MESSAGE_DATA *msgData, 
				   IN_BUFFER( attributeLength ) const void *attribute, 
				   IN_LENGTH_SHORT_Z const int attributeLength );
CHECK_RETVAL STDC_NONNULL_ARG( ( 3 ) ) \
int attributeCopyParams( OUT_BUFFER_OPT( destMaxLength, \
										 *destLength ) void *dest, 
						 IN_LENGTH_SHORT_Z const int destMaxLength, 
						 OUT_LENGTH_BOUNDED_SHORT_Z( destMaxLength ) \
							int *destLength, 
						 IN_BUFFER_OPT( sourceLength ) const void *source, 
						 IN_LENGTH_SHORT_Z const int sourceLength );

/* Check whether a password is valid or not.  Currently this just checks that
   it contains at least one character, but stronger checking can be
   substituted if required */

#ifdef UNICODE_CHARS
  #define isBadPassword( password ) \
		  ( !isReadPtr( password, sizeof( wchar_t ) ) || \
		    ( wcslen( password ) < 1 ) )
#else
  #define isBadPassword( password ) \
		  ( !isReadPtr( password, 1 ) || \
		    ( strlen( password ) < 1 ) )
#endif /* Unicode vs. ASCII environments */

/* Check whether a given algorithm is available for use.  This is performed
   frequently enough that we have a special krnlSendMessage() wrapper
   function for it rather than having to explicitly query the system
   object */

CHECK_RETVAL_BOOL \
BOOLEAN algoAvailable( IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo );

/* For a given algorithm pair, check whether the first is stronger than the
   second */

CHECK_RETVAL_BOOL \
BOOLEAN isStrongerHash( IN_ALGO const CRYPT_ALGO_TYPE algorithm1,
						IN_ALGO const CRYPT_ALGO_TYPE algorithm2 );

/* Check that a string has at least a minimal amount of entropy.  This is
   used as a sanity-check on (supposedly) random keys before we load them */

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
BOOLEAN checkEntropy( IN_BUFFER( dataLength ) const BYTE *data, 
					  IN_LENGTH_SHORT_MIN( MIN_KEYSIZE ) const int dataLength );

/* Check whether a block of 64 bits of data is all-zeroes, typically used 
   for sanity-check functions that check contexts for validity */

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
BOOLEAN isEmptyData( IN_BUFFER_C( 8 ) const BYTE data[ 8 ],
					 IN_LENGTH_SHORT_Z const int dataLengthValue );

/* Return a random small integer, used to perform lightweight randomisation 
   of various algorithms in order to make DoS attacks harder */

CHECK_RETVAL_RANGE_NOERROR( 0, 32767 ) \
int getRandomInteger( void );

/* Delay by a (relatively) large random amount of time, used to dither the 
   results of (failed) crypto operations to make timing attacks harder, 
   register a crypto failure (as well as inserting a random delay) in order 
   to catch possible crypto fault attacks, and insert a small random delay
   to mask the exact timing of crypto operations */

int delayRandom( void );
int registerCryptoFailure( void );
int insertCryptoDelay( void );

/* Map one value to another, used to map values from one representation 
   (e.g. PGP algorithms or HMAC algorithms) to another (cryptlib algorithms
   or the underlying hash used for the HMAC algorithm) */

typedef struct {
	int source, destination;
	} MAP_TABLE;

CHECK_RETVAL STDC_NONNULL_ARG( ( 2, 3 ) ) \
int mapValue( IN_INT_SHORT_Z const int srcValue,
			  OUT_INT_SHORT_Z int *destValue,
			  IN_ARRAY( mapTblSize ) const MAP_TABLE *mapTbl,
			  IN_RANGE( 1, 100 ) const int mapTblSize );

/* Read a line of text from a stream.  The caller passes in a character-read
   function callback that returns the next character from a supplied input
   stream, and readTextLine() uses it to fetch the next line of input up to
   an EOL.  The localError flag is set when the returned error code was
   generated by readTextLine() itself, rather than being passed up from the
   character-read function.  This allows the caller to report the errors
   differently, for example a data-formatting error vs. a network I/O error.
   
   It would be nice if we could declare READCHARFUNCTION as taking a 
   STREAM * but this header gets included long before the stream header does
   so the STREAM structure isn't visible at this point */

#if defined( USE_HTTP ) || defined( USE_BASE64 ) || defined( USE_SSH )

typedef CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
		int ( *READCHAR_FUNCTION )( INOUT void *streamPtr );

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 5 ) ) \
int readTextLine( READCHAR_FUNCTION readCharFunction, 
				  INOUT TYPECAST( STREAM * ) void *streamPtr,
				  OUT_BUFFER( lineBufferMaxLen, *lineBufferSize ) \
						char *lineBuffer,
				  IN_LENGTH_SHORT_MIN( 16 ) const int lineBufferMaxLen, 
				  OUT_RANGE( 0, lineBufferMaxLen ) int *lineBufferSize, 
				  OUT_OPT_BOOL BOOLEAN *localError,
				  const BOOLEAN allowContinuation );
#endif /* USE_HTTP || USE_BASE64 || USE_SSH */

/****************************************************************************
*																			*
*								OS-specific Functions						*
*																			*
****************************************************************************/

/* Get OS-specific values */

#if defined( __WIN32__ ) || defined( __WINCE__ )
typedef enum { 
	SYSVAR_NONE,			/* No system variable */
#if VC_LT_2005( _MSC_VER )
	SYSVAR_OSMAJOR,			/* OS major version number */
	SYSVAR_OSMINOR,			/* OS minor version number */
#endif /* VC++ < 2005 */
	SYSVAR_HWINTRINS,		/* Hardware crypto intrinsics */
	SYSVAR_PAGESIZE,		/* System page size */
	SYSVAR_LAST				/* Last valid system variable type */
	} SYSVAR_TYPE;
#elif defined( __UNIX__ )
typedef enum { 
	SYSVAR_NONE,			/* No system variable */
	SYSVAR_HWINTRINS,		/* Hardware crypto intrinsics */
	SYSVAR_HWCRYPT,			/* Hardware crypto drivers */
	SYSVAR_PAGESIZE,		/* System page size */
	SYSVAR_LAST				/* Last valid system variable type */
	} SYSVAR_TYPE;
#else
typedef enum { 
	SYSVAR_NONE,			/* No system variable */
	SYSVAR_HWINTRINS,		/* Hardware crypto intrinsics */
	SYSVAR_LAST				/* Last valid system variable type */
	} SYSVAR_TYPE;
#endif /* OS-specific system variable types */

CHECK_RETVAL \
int initSysVars( void );
CHECK_RETVAL \
int getSysVar( IN_ENUM( SYSVAR ) const SYSVAR_TYPE type );

/* Flags for SYSVAR_HWINTRINS capabilities */

#define HWINTRINS_FLAG_NONE			0x000	/* No special HW capabilities */
#define HWINTRINS_FLAG_RDTSC		0x001	/* x86 RDTSC instruction support */
#define HWINTRINS_FLAG_XSTORE		0x002	/* VIA XSTORE instruction support */
#define HWINTRINS_FLAG_XCRYPT		0x004	/* VIA XCRYPT instruction support */
#define HWINTRINS_FLAG_XSHA			0x008	/* VIA XSHA instruction support */
#define HWINTRINS_FLAG_MONTMUL		0x010	/* VIA bignum instruction support */
#define HWINTRINS_FLAG_TRNG			0x020	/* AMD Geode LX TRNG MSR support */
#define HWINTRINS_FLAG_AES			0x040	/* Intel AES instruction support */
#define HWINTRINS_FLAG_RDRAND		0x080	/* Intel RDRAND instruction support */
#define HWINTRINS_FLAG_RDSEED		0x100	/* Intel RDSEED instruction support */
#define HWINTRINS_FLAG_MAX			0x1FF	/* Maximum possible flag value */

/* Flags for SYSVAR_HWCRYPT capabilities */

#define HWCRYPT_FLAG_NONE			0x00	/* No hardware crypto capability */
#define HWCRYPT_FLAG_CRYPTDEV_3DES	0x01	/* BSD/Linux CryptoDev 3DES-CBC */
#define HWCRYPT_FLAG_CRYPTDEV_AES	0x02	/* BSD/Linux CryptoDev AES-CBC */
#define HWCRYPT_FLAG_CRYPTDEV_SHA1	0x04	/* BSD/Linux CryptoDev SHA-1 */
#define HWCRYPT_FLAG_CRYPTDEV_SHA2	0x08	/* BSD/Linux CryptoDev SHA-2 */
#define HWCRYPT_FLAG_LAST			0x0F	/* Maximum possible flag value */

/* cryptlib-specific feature flags used in the keyFeatures extension in
   certificates */

#define KEYFEATURE_FLAG_NONE		0x00	/* No special key features */
#define KEYFEATURE_FLAG_RESERVED	0x01	/* Reserved for backwards-compat.*/
#define KEYFEATURE_FLAG_RAISSUED	0x02	/* Cert.was issued via an RA */
#define KEYFEATURE_FLAG_MAX			0x03	/* Maximum possible flag value */

/* Windows helper functions */

#ifdef __WINDOWS__
  /* Most versions of Windows support ACL-based access control mechanisms 
     for system objects, so when we create objects such as files and threads 
	 we give them an ACL that allows only the creator access.  The following 
	 functions return the security info needed when creating objects */
  #ifdef __WIN32__
	CHECK_RETVAL_PTR \
	void *initACLInfo( const int access );
	void *getACLInfo( INOUT_OPT void *securityInfoPtr );
	STDC_NONNULL_ARG( ( 1 ) ) \
	void freeACLInfo( IN void *securityInfoPtr );
  #else
	#define initACLInfo( x )	NULL
	#define getACLInfo( x )		NULL
	#define freeACLInfo( x )
  #endif /* __WIN32__ */

  /* Safely load a DLL while avoid, if possible, malicious path-specific 
     trickery */
  HMODULE WINAPI SafeLoadLibrary( IN_STRING LPCTSTR lpFileName );
#endif /* __WINDOWS__ */

/****************************************************************************
*																			*
*								String Functions							*
*																			*
****************************************************************************/

/* Check whether a value is a valid text character or not.  In almost all 
   cases for standard ASCII the isprint() restricts the input range to
   0x20 ... 0x7E, we perform the explicit range check beforehand mostly to 
   ensure that the input range to isprint() isn't exceeded in cases where
   it's implemented as a straight unchecked table lookup */

#define isValidTextChar( value )	( value >= 0x08 && value <= 0x7E && \
									  isPrint( value ) )

/* Compare two strings in a case-insensitive manner for those systems that
   don't have this function.  These are then mapped to the abstract 
   functions strCompare() (with length) and strCompareZ() (zero-
   terminated) */

#if defined( __UNIX__ ) && !( defined( __CYGWIN__ ) )
  #include <strings.h>
  #define strnicmp	strncasecmp
  #define stricmp	strcasecmp
#elif defined( __WINCE__ )
  #define strnicmp	_strnicmp
  #define stricmp	_stricmp
#elif defined( _MSC_VER ) 
  /* VC++ 8 and up warn about these being deprecated Posix functions and
     require the ANSI/ISO-conformant _strXcmp */
  #if _MSC_VER >= 1300 
	#define strnicmp _strnicmp
	#define stricmp	_stricmp
  #endif /* VC++ >= 8 */
#elif defined( __ECOS__ ) || defined( __iOS__ )
  #define strnicmp	strncasecmp
  #define stricmp	strcasecmp
#elif defined __PALMOS__
  /* PalmOS has strcasecmp()/strncasecmp() but these aren't i18n-aware so we
     have to use a system function instead */
  #include <StringMgr.h>

  #define strnicmp	StrNCaselessCompare
  #define stricmp	StrCaselessCompare
#elif defined( __TI_COMPILER_VERSION__ )
  #include <strings.h>
  #define strnicmp	strncasecmp
  #define stricmp	strcasecmp
#elif defined( __BEOS__ ) || defined( __IAR_SYSTEMS_ICC__ ) || \
	  defined( __SMX__ ) || defined( __SYMBIAN32__ ) || \
	  defined( __VxWorks___ )
  int strnicmp( const char *src, const char *dest, const int length );
  int stricmp( const char *src, const char *dest );

  /* Make sure that we provide our own versions of the functions */
  #define NO_NATIVE_STRICMP
#endif /* OS-specific case-insensitive string compares */

/* Sanitise a string before passing it back to the user.  This is used to
   clear potential problem characters (for example control characters)
   from strings passed back from untrusted sources.  The function returns a 
   pointer to the string to allow it to be used in the form 
   printf( "..%s..", sanitiseString( string, strLen ) ).  In addition it
   formats the data to fit a fixed-length buffer.  If the string is longer 
   than the indicated buffer size it appends a '[...]' at the end of the 
   buffer to indicate that further data was truncated.
   
   To avoid lots of problems with compilers and static analysers, the input
   argument is specified as a 'void *' rather than a 'BYTE *' because the
   fact that it converts a 'BYTE *' into a 'char *' gives these tools
   headaches */
					
STDC_NONNULL_ARG( ( 1 ) ) \
char *sanitiseString( INOUT_BUFFER( strMaxLen, strLen ) void *string, 
					  IN_LENGTH_SHORT const int strMaxLen, 
					  IN_LENGTH_SHORT const int strLen );

/* Perform various string-processing operations */

CHECK_RETVAL_STRINGOP STDC_NONNULL_ARG( ( 1 ) ) \
int strFindCh( IN_BUFFER( strLen ) const char *str, 
			   IN_LENGTH_SHORT const int strLen, 
			   IN_CHAR const int findCh );
CHECK_RETVAL_STRINGOP STDC_NONNULL_ARG( ( 1, 3 ) ) \
int strFindStr( IN_BUFFER( strLen ) const char *str, 
				IN_LENGTH_SHORT const int strLen, 
				IN_BUFFER( findStrLen ) const char *findStr, 
				IN_LENGTH_SHORT const int findStrLen );
CHECK_RETVAL_STRINGOP STDC_NONNULL_ARG( ( 1 ) ) \
int strSkipWhitespace( IN_BUFFER( strLen ) const char *str, 
					   IN_LENGTH_SHORT const int strLen );
CHECK_RETVAL_STRINGOP STDC_NONNULL_ARG( ( 1 ) ) \
int strSkipNonWhitespace( IN_BUFFER( strLen ) const char *str, 
						  IN_LENGTH_SHORT const int strLen );
CHECK_RETVAL_STRINGOP STDC_NONNULL_ARG( ( 1, 2 ) ) \
int strStripWhitespace( OUT_PTR_COND const char **newStringPtr, 
						IN_BUFFER( strLen ) const char *string, 
						IN_LENGTH_SHORT const int strLen );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int strExtract( OUT_PTR_COND const char **newStringPtr, 
				IN_BUFFER( strLen ) const char *string, 
				IN_LENGTH_SHORT_Z const int startOffset,
				IN_LENGTH_SHORT const int strLen );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int strGetNumeric( IN_BUFFER( strLen ) const char *str, 
				   IN_LENGTH_SHORT const int strLen, 
				   OUT_INT_Z int *numericValue, 
				   IN_RANGE( 0, 100 ) const int minValue, 
				   IN_RANGE( minValue, MAX_INTLENGTH ) const int maxValue );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int strGetHex( IN_BUFFER( strLen ) const char *str, 
			   IN_LENGTH_SHORT const int strLen, 
			   OUT_INT_Z int *numericValue, 
			   IN_RANGE( 0, 100 ) const int minValue, 
			   IN_RANGE( minValue, MAX_INTLENGTH ) const int maxValue );
CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
BOOLEAN strIsPrintable( IN_BUFFER( strLen ) const void *str, 
						IN_LENGTH_SHORT const int strLen );

/****************************************************************************
*																			*
*							Error-handling Functions						*
*																			*
****************************************************************************/

/* Handle internal errors.  These follow a fixed pattern of "throw an 
   exception, return an internal-error code" (with a few exceptions for
   functions that return a pointer or void).  There's also a 
   retExt_IntError() define in int_api.h for handling extended error 
   returns */

#define INTERNAL_ERROR	0	/* Symbolic define for assertion failure */
#define retIntError() \
		{ \
		DEBUG_DUMP_STACKTRACE(); \
		assert( INTERNAL_ERROR ); \
		return( CRYPT_ERROR_INTERNAL ); \
		}
#define retIntError_Null() \
		{ \
		DEBUG_DUMP_STACKTRACE(); \
		assert( INTERNAL_ERROR ); \
		return( NULL ); \
		}
#define retIntError_Boolean() \
		{ \
		DEBUG_DUMP_STACKTRACE(); \
		assert( INTERNAL_ERROR ); \
		return( FALSE ); \
		}
#define retIntError_Void() \
		{ \
		DEBUG_DUMP_STACKTRACE(); \
		assert( INTERNAL_ERROR ); \
		return; \
		}
#define retIntError_Ext( value ) \
		{ \
		DEBUG_DUMP_STACKTRACE(); \
		assert( INTERNAL_ERROR ); \
		return( value ); \
		}
#define retIntError_Dataptr() \
		{ \
		DEBUG_DUMP_STACKTRACE(); \
		assert( INTERNAL_ERROR ); \
		return( DATAPTR_NULL ); \
		}
#define retIntError_Stream( stream ) \
		{ \
		DEBUG_DUMP_STACKTRACE(); \
		assert( INTERNAL_ERROR ); \
		return( sSetError( stream, CRYPT_ERROR_INTERNAL ) ); \
		}

/* Check for an internal error.  This is required in situations where 
   supplementary information is returned as a by-reference parameter but
   we can't rely on the value of the by-reference parameter because it
   isn't reset to its default value until the internal-error checks have
   been performed.  For example if we have a function:

	CHECK_RETVAL int foo( IN_HANDLE const CRYPT_HANDLE cryptHandle,
						  OUT_INT_OPT int *errorInfo )
		{
		REQUIRES( isValidHandle( cryptHandle ) );

		// Clear return value
		*errorInfo = CRYPT_OK;

		//...
		}

   which is called as:

	status = foo( cryptHandle, &errorInfo );
	if( cryptStatusError( status ) )
		{
		switch( errorInfo )
			{
			// ...
			}
		}

   then we can't act on errorInfo if the returned status is 
   CRYPT_ERROR_INTERNAL because the exception may have been triggered 
   before the return value was cleared.

   An alternative option to this explicit check would be to switch the order 
   of the exception-throwing checks and the clearing of return values, but 
   this both doesn't work in the case of wrapper functions where the check 
   is performed in the wrapper but the return value isn't cleared until the 
   actual function, and creates nasty catch-22's where we can't check the 
   validity of the by-reference parameter until it's already been written 
   to:

	// Clear return value
	*errorInfo = CRYPT_OK;

	REQUIRES( errorInfo != NULL );

   Both options are ugly and error-prone, but having a requirement for the 
   caller to check for isInternalError() is relatively rare so it's the
   one that we use here */

#define isInternalError( status )	( ( status ) == CRYPT_ERROR_INTERNAL )

/* A struct to store extended error information.  This provides error info
   above and beyond that provided by cryptlib error codes.  Since this 
   consumes a fair amount of memory, we make it conditional on USE_ERRMSGS
   being defined and provide an alternative errorcode-only version if this
   isn't enabled */

#ifdef USE_ERRMSGS

typedef struct {
	BUFFER( MAX_ERRMSG_SIZE, errorStringLength ) \
	char errorString[ MAX_ERRMSG_SIZE + 8 ];
	int errorStringLength;			/* Error message */
	} ERROR_INFO;

/* When we're printing diagnostic messages we try and display a textual 
   description of an object rather than a numeric ID.  The following 
   function maps an ID to its name for display:

	getObjectName( objectNameInfo,
				   FAILSAFE_ARRAYSIZE( objectNameInfo, OBJECT_NAME_INFO ),
				   objectID ); */

typedef struct {
	const int objectType;
	const char *objectName;
	} OBJECT_NAME_INFO;

CHECK_RETVAL_PTR_NONNULL STDC_NONNULL_ARG( ( 1 ) ) \
const char *getObjectName( IN_ARRAY( objectNameInfoSize ) \
								const OBJECT_NAME_INFO *objectNameInfo,
						   IN_LENGTH_SHORT const int objectNameInfoSize,
						   const int objectType );
#else

typedef struct {
	int errorCode;					/* Low-level error code */
	} ERROR_INFO;

#endif /* USE_ERRMSGS */

/* Prototypes for various extended error-handling functions.  retExt() 
   returns after setting extended error information for the object.  
   
   In addition to the standard retExt() we also have several extended-form 
   versions of the function that take additional error info parameters:

	retExtArgFn() is identical to ertExtFn() but passes through 
		CRYPT_ARGERROR_xxx values, which are normally only present as leaked
		status codes from lower-level calls (and even then they should only
		ever occur in 'can't-occur' error situations).

	retExtObj() takes a handle to an object that may provide additional 
		error information, used when (for example) an operation references 
		a keyset, where the keyset also contains extended error information.

	retExtStr() takes an additional error string pointer and is used in the
		same way as retExtErr().

	retExtErr() takes a pointer to existing error info, used when (for
		example) a lower-level function has provided very low-level error 
		information but the higher-level function that calls it needs to 
		provide its own more general error information on top of it.  This 
		function is typically used when the caller wants to convert 
		something like "Low-level error string" into "High-level error 
		string: Low-level error string".  errorInfoPtr and 
		existingErrorInfoPtr can point to the same location.
	retExtErrAlt() is a variation of the above that appends the additional
		error information rather than prepending it */

#ifdef USE_ERRMSGS

STDC_NONNULL_ARG( ( 1, 3 ) ) \
void formatFingerprint( OUT_BUFFER_FIXED( fingerprintTextMaxLen ) \
							char *fingerprintText, 
						IN_LENGTH_SHORT_MIN( 32 ) const int fingerprintTextMaxLen,
						IN_BUFFER( fingerprintLen ) const BYTE *fingerprint,
						IN_LENGTH_SHORT_MIN( 8 ) const int fingerprintLen );
STDC_NONNULL_ARG( ( 1 ) ) \
void clearErrorString( OUT ERROR_INFO *errorInfoPtr );
STDC_NONNULL_ARG( ( 1 ) ) \
int readErrorInfo( OUT ERROR_INFO *errorInfo, 
				   IN_HANDLE const CRYPT_HANDLE objectHandle );
STDC_NONNULL_ARG( ( 1, 2 ) ) \
void setErrorString( OUT ERROR_INFO *errorInfoPtr, 
					 IN_BUFFER( stringLength ) const char *string, 
					 IN_LENGTH_ERRORMESSAGE const int stringLength );
CHECK_RETVAL STDC_NONNULL_ARG( ( 2, 3 ) ) STDC_PRINTF_FN( 3, 4 ) \
int retExtFn( IN_ERROR const int status, 
			  OUT ERROR_INFO *errorInfoPtr, 
			  FORMAT_STRING const char *format, ... );
CHECK_RETVAL STDC_NONNULL_ARG( ( 2, 3 ) ) STDC_PRINTF_FN( 3, 4 ) \
int retExtArgFn( IN_ERROR const int status, 
				 OUT ERROR_INFO *errorInfoPtr, 
				 FORMAT_STRING const char *format, ... );
CHECK_RETVAL STDC_NONNULL_ARG( ( 2, 4 ) ) STDC_PRINTF_FN( 4, 5 ) \
int retExtObjFn( IN_ERROR const int status, 
				 OUT ERROR_INFO *errorInfoPtr, 
				 IN_HANDLE const CRYPT_HANDLE extErrorObject, 
				 FORMAT_STRING const char *format, ... );
CHECK_RETVAL STDC_NONNULL_ARG( ( 2, 3, 5 ) ) STDC_PRINTF_FN( 5, 6 ) \
int retExtStrFn( IN_ERROR const int status, 
				 OUT ERROR_INFO *errorInfoPtr, 
				 IN_BUFFER( extErrorStringLength ) const char *extErrorString, 
				 IN_LENGTH_ERRORMESSAGE const int extErrorStringLength,
				 FORMAT_STRING const char *format, ... );
CHECK_RETVAL STDC_NONNULL_ARG( ( 2, 3, 4 ) ) STDC_PRINTF_FN( 4, 5 ) \
int retExtErrFn( IN_ERROR const int status, 
				 OUT ERROR_INFO *errorInfoPtr, 
				 const ERROR_INFO *existingErrorInfoPtr, 
				 FORMAT_STRING const char *format, ... );
CHECK_RETVAL STDC_NONNULL_ARG( ( 2, 3 ) ) STDC_PRINTF_FN( 3, 4 ) \
int retExtErrAltFn( IN_ERROR const int status, 
					INOUT ERROR_INFO *errorInfoPtr, 
					FORMAT_STRING const char *format, ... );
#else
  #define formatFingerprint( fingerprintText, fingerprintTextMaxLen, \
							 fingerprint, fingerprintLen );
  #define clearErrorString( errorInfoPtr )
  #define readErrorInfo( errorInfoPtr, objectHandle )
  #define setErrorString( errorInfoPtr, string, stringLength );
#endif /* USE_ERRMSGS */
STDC_NONNULL_ARG( ( 1, 2 ) ) \
void copyErrorInfo( OUT ERROR_INFO *destErrorInfoPtr, 
					const ERROR_INFO *srcErrorInfoPtr );

#ifdef USE_ERRMSGS
  #define retExt( status, extStatus )		return retExtFn extStatus
  #define retExtArg( status, extStatus )	return retExtArgFn extStatus
  #define retExtObj( status, extStatus )	return retExtObjFn extStatus
  #define retExtStr( status, extStatus )	return retExtStrFn extStatus 
  #define retExtErr( status, extStatus )	return retExtErrFn extStatus 
  #define retExtErrAlt( status, extStatus )	return retExtErrAltFn extStatus 
  #define retExt_IntError( status, extStatus ) \
		{ \
		assert( INTERNAL_ERROR ); \
		return retExtFn extStatus; \
		}
#else
  /* We're not using extended error information, just return the basic 
     status code */
  #define retExt( status, extStatus )		return status
  #define retExtArg( status, extStatus )	return status
  #define retExtObj( status, extStatus )	return status
  #define retExtStr( status, extStatus )	return status
  #define retExtErr( status, extStatus )	return status
  #define retExtErrAlt( status, extStatus )	return status
  #define retExt_IntError( status, extStatus ) \
		{ \
		assert( INTERNAL_ERROR ); \
		return( status ); \
		}
#endif /* USE_ERRMSGS */

/* Since this function works for all object types, we have to extract the
   error info pointer from the object-specific data.  The following defines
   do this for each object type */

#define ENVELOPE_ERRINFO	&envelopeInfoPtr->errorInfo
#define KEYSET_ERRINFO		&keysetInfoPtr->errorInfo
#define SESSION_ERRINFO		&sessionInfoPtr->errorInfo
#define STREAM_ERRINFO		stream->errorInfo
#define NETSTREAM_ERRINFO	&netStream->errorInfo

/* Additional helper functions used to provide extended information for
   error messages.  These are used both for long-form error messages and
   debug diagnostics, so we need to enable them for both */

#if defined( USE_ERRMSGS )
CHECK_RETVAL \
const char *getStatusName( IN_STATUS const int errorStatus );
CHECK_RETVAL \
const char *getAlgoName( IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo );
CHECK_RETVAL \
const char *getKeyIDName( IN_KEYID const CRYPT_KEYID_TYPE keyID );
#endif /* USE_ERRMSGS || debug mode */

/****************************************************************************
*																			*
*							Data Encode/Decode Functions					*
*																			*
****************************************************************************/

/* Special-case certificate function that works somewhat like the import 
   cert messages but reads certs by sending get_next_cert messages to the 
   message source and provides extended control over the format of the 
   imported object.  This isn't strictly speaking a certificate function but 
   the best (meaning least inappropriate) place to put it is with the cert-
   management code */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
int iCryptImportCertIndirect( OUT_HANDLE_OPT CRYPT_CERTIFICATE *iCertificate,
							  IN_HANDLE const CRYPT_HANDLE iCertSource, 
							  IN_ENUM( CRYPT_KEYID ) \
								const CRYPT_KEYID_TYPE keyIDtype,
							  IN_BUFFER( keyIDlength ) const void *keyID, 
							  IN_LENGTH_SHORT const int keyIDlength,
							  IN_FLAGS_Z( KEYMGMT ) const int options );

/* Read a public key from an X.509 SubjectPublicKeyInfo record, creating the
   context necessary to contain it in the process.  This is used by a variety
   of modules including certificate-management, keyset, and crypto device. 

   The use of the void * instead of STREAM * is necessary because the STREAM
   type isn't visible at the global level */

#ifdef USE_INT_ASN1
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int iCryptReadSubjectPublicKey( INOUT TYPECAST( STREAM * ) void *streamPtr, 
								OUT_HANDLE_OPT CRYPT_CONTEXT *iPubkeyContext,
								IN_HANDLE const CRYPT_DEVICE iCreatorHandle, 
								const BOOLEAN deferredLoad );
#endif /* USE_INT_ASN1 */

/* Get information on encoded object data.  The first parameter for this
   function is actually a STREAM *, but we can't use this here since
   STREAM * hasn't been defined yet */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int queryAsn1Object( INOUT void *streamPtr, OUT QUERY_INFO *queryInfo );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int queryPgpObject( INOUT void *streamPtr, OUT QUERY_INFO *queryInfo );

/* Export/import data to/from a stream without the overhead of going via a
   dynbuf.  The first parameter for these functions is actually a STREAM *,
   but we can't use this here since STREAM * hasn't been defined yet */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int exportAttributeToStream( INOUT void *streamPtr, 
							 IN_HANDLE const CRYPT_HANDLE cryptHandle,
							 IN_ATTRIBUTE \
								const CRYPT_ATTRIBUTE_TYPE attributeType );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int exportVarsizeAttributeToStream( INOUT void *streamPtr,
									IN_HANDLE const CRYPT_HANDLE cryptHandle,
									IN_LENGTH_FIXED( CRYPT_IATTRIBUTE_RANDOM_NONCE ) \
									const CRYPT_ATTRIBUTE_TYPE attributeType,
									IN_RANGE( 8, 1024 ) \
										const int attributeDataLength );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int exportCertToStream( INOUT void *streamPtr,
						IN_HANDLE const CRYPT_CERTIFICATE cryptCertificate,
						IN_ENUM( CRYPT_CERTFORMAT ) \
							const CRYPT_CERTFORMAT_TYPE certFormatType );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int importCertFromStream( INOUT TYPECAST( STREAM * ) void *streamPtr,
						  OUT_HANDLE_OPT CRYPT_CERTIFICATE *cryptCertificate,
						  IN_HANDLE const CRYPT_USER iCryptOwner,
						  IN_ENUM( CRYPT_CERTTYPE ) \
							const CRYPT_CERTTYPE_TYPE certType, 
						  IN_LENGTH_SHORT_MIN( MIN_CRYPT_OBJECTSIZE ) \
							const int certDataLength,
						  IN_FLAGS_Z( KEYMGMT ) const int options );

/* base64/SMIME-en/decode routines */

#ifdef USE_BASE64

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
int base64checkHeader( IN_BUFFER( dataLength ) const BYTE *data, 
					   IN_DATALENGTH_MIN( MIN_CERTSIZE ) \
							const int dataLength,
					   OUT_ENUM_OPT( CRYPT_CERTFORMAT ) \
							CRYPT_CERTFORMAT_TYPE *format,
					   OUT_DATALENGTH_Z int *startPos );
CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
int base64encodeLen( IN_DATALENGTH_MIN( 10 ) const int dataLength,
					 OUT_DATALENGTH_Z int *encodedLength,
					 IN_ENUM_OPT( CRYPT_CERTTYPE ) \
						const CRYPT_CERTTYPE_TYPE certType );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
int base64encode( OUT_BUFFER( destMaxLen, *destLen ) char *dest, 
				  IN_DATALENGTH_MIN( 10 ) const int destMaxLen,
				  OUT_LENGTH_BOUNDED_Z( destMaxLen ) int *destLen,
				  IN_BUFFER( srcLen ) const void *src, 
				  IN_DATALENGTH_MIN( 10 ) const int srcLen,
				  IN_ENUM_OPT( CRYPT_CERTTYPE ) \
					const CRYPT_CERTTYPE_TYPE certType );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int base64decodeLen( IN_BUFFER( dataLength ) const BYTE *data, 
					 IN_DATALENGTH_MIN( 10 ) const int dataLength,
					 OUT_DATALENGTH_Z int *decodedLength );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
int base64decode( OUT_BUFFER( destMaxLen, *destLen ) void *dest, 
				  IN_DATALENGTH_MIN( 10 ) const int destMaxLen,
				  OUT_DATALENGTH_Z int *destLen,
				  IN_BUFFER( srcLen ) const BYTE *src, 
				  IN_DATALENGTH_MIN( 10 ) const int srcLen,
				  IN_ENUM_OPT( CRYPT_CERTFORMAT ) \
					const CRYPT_CERTFORMAT_TYPE format );
#endif /* USE_BASE64 */

/* User data en/decode routines */

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
BOOLEAN isPKIUserValue( IN_BUFFER( encValLength ) const char *encVal, 
						IN_LENGTH_SHORT_MIN( 10 ) const int encValLength );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
int encodePKIUserValue( OUT_BUFFER( encValMaxLen, *encValLen ) char *encVal, 
						IN_LENGTH_SHORT_MIN( 10 ) const int encValMaxLen, 
						OUT_LENGTH_BOUNDED_Z( encValMaxLen ) int *encValLen,
						IN_BUFFER( valueLen ) const BYTE *value, 
						IN_LENGTH_SHORT_MIN( 8 ) const int valueLen, 
						IN_RANGE( 3, 4 ) const int noCodeGroups );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
int decodePKIUserValue( OUT_BUFFER( valueMaxLen, *valueLen ) BYTE *value, 
						IN_LENGTH_SHORT_MIN( 10 ) const int valueMaxLen, 
						OUT_LENGTH_BOUNDED_Z( valueMaxLen ) int *valueLen,
						IN_BUFFER( encValLength ) const char *encVal, 
						IN_LENGTH_SHORT const int encValLength );

/****************************************************************************
*																			*
*						Attribute List Manipulation Functions				*
*																			*
****************************************************************************/

/* In order to work with attribute lists of different types, we need a
   means of accessing the type-specific previous and next pointers and the
   attribute ID information.  The following callback function is passed to
   all attribute-list manipulation functions and provides external access
   to the required internal fields */

typedef enum {
	ATTR_NONE,			/* No attribute get type */
	ATTR_CURRENT,		/* Get details for current attribute */
	ATTR_PREV,			/* Get details for previous attribute */
	ATTR_NEXT,			/* Get details for next attribute */
	ATTR_LAST			/* Last valid attribute get type */
	} ATTR_TYPE;

typedef CHECK_RETVAL_PTR \
		const void * ( *GETATTR_FUNCTION ) \
							( IN_OPT const void *attributePtr,
							  OUT_OPT_ATTRIBUTE_Z CRYPT_ATTRIBUTE_TYPE *groupID,
							  OUT_OPT_ATTRIBUTE_Z CRYPT_ATTRIBUTE_TYPE *attributeID,
							  OUT_OPT_ATTRIBUTE_Z CRYPT_ATTRIBUTE_TYPE *instanceID,
							  IN_ENUM( ATTR ) const ATTR_TYPE attrGetType );
typedef CHECK_RETVAL \
		CONST_RETURN DATAPTR ( *DATAPTR_GETATTR_FUNCTION ) \
							( IN_OPT const DATAPTR attributePtr,
							  OUT_OPT_ATTRIBUTE_Z CRYPT_ATTRIBUTE_TYPE *groupID,
							  OUT_OPT_ATTRIBUTE_Z CRYPT_ATTRIBUTE_TYPE *attributeID,
							  OUT_OPT_ATTRIBUTE_Z CRYPT_ATTRIBUTE_TYPE *instanceID,
							  IN_ENUM( ATTR ) const ATTR_TYPE attrGetType );

CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 2 ) ) \
void *attributeFindStart( IN_OPT const void *attributePtr,
						  IN GETATTR_FUNCTION getAttrFunction );
CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 2 ) ) \
void *attributeFindEnd( IN_OPT const void *attributePtr,
						IN GETATTR_FUNCTION getAttrFunction );
CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 2 ) ) \
void *attributeFind( IN_OPT const void *attributePtr,
					 IN GETATTR_FUNCTION getAttrFunction,
					 IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attributeID );
CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 2 ) ) \
void *attributeFindEx( IN_OPT const void *attributePtr,
					   IN GETATTR_FUNCTION getAttrFunction,
					   IN_ENUM_OPT( CRYPT_ATTRIBUTE ) \
							const CRYPT_ATTRIBUTE_TYPE groupID,
					   IN_ENUM_OPT( CRYPT_ATTRIBUTE ) \
							const CRYPT_ATTRIBUTE_TYPE attributeID,
					   IN_ENUM_OPT( CRYPT_ATTRIBUTE ) \
							const CRYPT_ATTRIBUTE_TYPE instanceID );
CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 2 ) ) \
void *attributeFindNextInstance( IN_OPT const void *attributePtr,
								 IN GETATTR_FUNCTION getAttrFunction );
CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 2 ) ) \
const void *attributeMoveCursor( IN_OPT const void *currentCursor,
								 IN GETATTR_FUNCTION getAttrFunction,
								 IN_ATTRIBUTE \
									const CRYPT_ATTRIBUTE_TYPE attributeMoveType,
								 IN_RANGE( CRYPT_CURSOR_LAST, \
										   CRYPT_CURSOR_FIRST ) /* Values are -ve */
									const int cursorMoveType );

CHECK_RETVAL_DATAPTR STDC_NONNULL_ARG( ( 2 ) ) \
DATAPTR dataptrAttributeFind( IN_OPT const DATAPTR attributePtr,
							  IN GETATTR_FUNCTION getAttrFunction,
							  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attributeID );
CHECK_RETVAL_DATAPTR STDC_NONNULL_ARG( ( 2 ) ) \
DATAPTR dataptrAttributeFindEx( IN_OPT const DATAPTR attributePtr,
								IN GETATTR_FUNCTION getAttrFunction,
								IN_ENUM_OPT( CRYPT_ATTRIBUTE ) \
									const CRYPT_ATTRIBUTE_TYPE groupID,
								IN_ENUM_OPT( CRYPT_ATTRIBUTE ) \
									const CRYPT_ATTRIBUTE_TYPE attributeID,
								IN_ENUM_OPT( CRYPT_ATTRIBUTE ) \
									const CRYPT_ATTRIBUTE_TYPE instanceID );
CHECK_RETVAL_DATAPTR STDC_NONNULL_ARG( ( 2 ) ) \
DATAPTR dataptrAttributeFindNextInstance( IN_OPT DATAPTR attributePtr,
										  IN GETATTR_FUNCTION getAttrFunction );
CHECK_RETVAL_DATAPTR STDC_NONNULL_ARG( ( 2 ) ) \
CONST_RETURN DATAPTR dataptrAttributeMoveCursor( IN_OPT const DATAPTR currentCursor,
												 IN GETATTR_FUNCTION getAttrFunction,
												 IN_ATTRIBUTE \
													const CRYPT_ATTRIBUTE_TYPE attributeMoveType,
												 IN_RANGE( CRYPT_CURSOR_LAST, \
														   CRYPT_CURSOR_FIRST ) /* Values are -ve */
													const int cursorMoveType );

/****************************************************************************
*																			*
*								Time Functions								*
*																			*
****************************************************************************/

/* In exceptional circumstances an attempt to read the time can fail,
   returning either a garbage value (unsigned time_t) or -1 (signed time_t).
   This can be problematic because many crypto protocols and operations use
   the time at some point.  In order to protect against this, we provide a
   safe time-read function that returns either a sane time value or zero,
   and for situations where the absolute time isn't critical an approximate
   current-time function that returns either a sane time value or an
   approximate value hardcoded in at compile time.  Finally, we provide a
   reliable time function used for operations such as signing certs and
   timestamping that tries to get the time from a hardware time source if
   one is available */

#include <time.h>

time_t getTime( void );
time_t getApproxTime( void );
time_t getReliableTime( IN_HANDLE const CRYPT_HANDLE cryptHandle );

/* Monotonic timer interface that protect against the system clock being 
   changed during a timing operation.  Even without deliberate fiddling
   with the system clock, a timeout during a DST switch can cause something
   like a 5s wait to turn into a 1hr 5s wait, so we have to abstract the
   standard time API into a monotonic time API.  Since these functions are
   purely peripheral to other operations (for example handling timeouts for
   network I/O), they never fail but simply return good-enough results if
   there's a problem (although they assert in debug mode).  This is because 
   we don't want to abort a network session just because we've detected 
   some trivial clock irregularity */

typedef struct {
	time_t endTime, origTimeout, timeRemaining;
	} MONOTIMER_INFO;

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int setMonoTimer( OUT MONOTIMER_INFO *timerInfo, 
				  IN_INT_Z const int duration );
STDC_NONNULL_ARG( ( 1 ) ) \
void extendMonoTimer( INOUT MONOTIMER_INFO *timerInfo, 
					  IN_INT const int duration );
CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
BOOLEAN checkMonoTimerExpired( INOUT MONOTIMER_INFO *timerInfo );
CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
BOOLEAN checkMonoTimerExpiryImminent( INOUT MONOTIMER_INFO *timerInfo,
									  IN_INT_Z const int timeLeft );

/* Hardware timer read routine used for performance evaluation */

CHECK_RETVAL_RANGE( 0, INT_MAX ) \
long getTickCount( long startTime );

/****************************************************************************
*																			*
*						Dynamic Memory Management Functions					*
*																			*
****************************************************************************/

/* Dynamic buffer management functions.  When reading variable-length
   object data we can usually fit the data into a small fixed-length buffer, 
   but occasionally we have to cope with larger data amounts that require a 
   dynamically-allocated buffer.  The following routines manage this 
   process, dynamically allocating and freeing a larger buffer if required */

#define DYNBUF_SIZE		1024

typedef struct {
	BUFFER_FIXED( length ) \
	void *data;						/* Pointer to data */
	int length;
	BUFFER( DYNBUF_SIZE, length ) \
	BYTE dataBuffer[ DYNBUF_SIZE + 8 ];	/* Data buf.if size <= DYNBUF_SIZE */
	} DYNBUF;

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int dynCreate( OUT DYNBUF *dynBuf, 
			   IN_HANDLE const CRYPT_HANDLE cryptHandle,
			   IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attributeType );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int dynCreateCert( OUT DYNBUF *dynBuf, 
				   IN_HANDLE const CRYPT_HANDLE cryptHandle,
				   IN_ENUM( CRYPT_CERTFORMAT ) \
					const CRYPT_CERTFORMAT_TYPE formatType );
STDC_NONNULL_ARG( ( 1 ) ) \
void dynDestroy( INOUT DYNBUF *dynBuf );

#define dynLength( dynBuf )		( dynBuf ).length
#define dynData( dynBuf )		( dynBuf ).data

/* When allocating many little blocks of memory, especially in resource-
   constrained systems, it's better if we pre-allocate a small memory pool
   ourselves and grab chunks of it as required, falling back to dynamically
   allocating memory later on if we exhaust the pool.  To use a custom
   memory pool, the caller declares a state variable of type MEMPOOL_STATE,
   calls initMemPool() to initialise the pool, and then calls getMemPool()
   and freeMemPool() to allocate and free memory blocks.  The state pointer
   is declared as a void * because to the caller it's an opaque memory block
   while to the memPool routines it's structured storage */

typedef BYTE MEMPOOL_STATE[ 32 ];

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int initMemPool( OUT void *statePtr, 
				 IN_BUFFER( memPoolSize ) void *memPool, 
				 IN_LENGTH_SHORT_MIN( 64 ) const int memPoolSize );
CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 1 ) ) \
void *getMemPool( INOUT void *statePtr, IN_LENGTH_SHORT const int size );
STDC_NONNULL_ARG( ( 1, 2 ) ) \
void freeMemPool( INOUT void *statePtr, IN void *memblock );

/* Almost all objects require object-subtype-specific amounts of memory to
   store object information.  In addition some objects such as certificates
   contain arbitrary numbers of arbitrary-sized bits and pieces, most of
   which are quite small.  To avoid having to allocate worst-case sized
   blocks of memory for objects (a problem in embedded environments) or 
   large numbers of tiny little blocks of memory for certificate attributes, 
   we use variable-length structures in which the payload is stored after 
   the structure, with a pointer 'valueName' inside the structure pointing 
   into the payload storage (a convenient side-effect of this is that it 
   provides good spatial coherence when processing long lists of attributes).  
   To make this easier to handle, we use macros to set up and tear down the 
   necessary variables.
   
   The use of 'storage[ 1 ]' means that the only element that's guaranteed 
   to be valid is 'storage[ 0 ]' under strict C99 definitions, however 
   declaring it as an unsized array leads to warnings of use of a zero-sized 
   array from many compilers so we leave it as 'storage[ 1 ]'.
   
   We have to insert an additional dummy value before the storage 
   declaration to ensure the correct alignment for the storage itself, in
   particular on 64-bit platforms with the LLP64/LP64 memory model (which 
   means most current systems) the storage block may end up 32-bit aligned 
   if the compiler aligns to, at most, the nearest 32-bit integer value.  We 
   can't declare the storage as a long since under LLP64 it's only 32 bits 
   while a pointer is still 64 bits */

#define DECLARE_VARSTRUCT_VARS \
		int storageSize; \
		void *_align_value; \
		BUFFER_FIXED( storageSize ) \
		BYTE storage[ 1 ]

#define initVarStruct( structure, structureType, size, valueName ) \
		memset( structure, 0, sizeof( structureType ) ); \
		structure->valueName = structure->storage; \
		structure->storageSize = size

#define copyVarStruct( destStructure, srcStructure, structureType, valueName ) \
		memcpy( destStructure, srcStructure, \
				sizeof( structureType ) + srcStructure->storageSize ); \
		if( destStructure->storageSize > 0 ) \
			destStructure->valueName = destStructure->storage;

#define endVarStruct( structure, structureType ) \
		zeroise( structure, sizeof( structureType ) + structure->storageSize )

#define sizeofVarStruct( structure, structureType ) \
		( sizeof( structureType ) + structure->storageSize )

/****************************************************************************
*																			*
*							Checksum/Hash Functions							*
*																			*
****************************************************************************/

/* Hash state information.  We can call the hash function with HASH_START,
   HASH_CONTINUE, or HASH_END as required to process the input in parts */

typedef enum {
	HASH_STATE_NONE,				/* No hash state */
	HASH_STATE_START,				/* Begin hashing */
	HASH_STATE_CONTINUE,			/* Continue existing hashing */
	HASH_STATE_END,					/* Complete existing hashing */
	HASH_STATE_LAST					/* Last valid hash option */
	} HASH_STATE_TYPE;

/* The hash functions are used quite a bit so we provide an internal API for
   them to avoid the overhead of having to set up an encryption context
   every time they're needed.  These take a block of input data and hash it,
   leaving the result in the output buffer.
   
   In addition to the hash-step operation, we provide a one-step atomic hash
   function that processes a single data quantity and returns its hash.
   
   The data block is defined in terms of a long[] rather than a BYTE[] in
   order to deal with alignment issues */

#if defined( USE_SHA2_EXT ) 
  /* SHA2-384/512: ( 2 + 8 + 16 + 1 ) * sizeof( long long ) = 27 * 8 */
  typedef long HASHINFO[ ( 27 * 2 ) + 2 ];	/* ( 27 * 8 ) + 8 */
#else
  /* SHA-256: ( 2 + 8 + 16 + 1 ) * sizeof( long ) = 27 * 4 */
  typedef long HASHINFO[ 27 + 2 ];			/* ( 27 * 4 ) + 8 */
#endif /* SYSTEM_64BIT */

typedef void ( *HASH_FUNCTION )( OUT_WHEN( hashState == HASH_STATE_START ) \
								 INOUT_WHEN( hashState != HASH_STATE_START ) \
									HASHINFO hashInfo, 
								 OUT_BUFFER_OPT_FIXED( outBufMaxLength ) \
									BYTE *outBuffer, 
								 IN_LENGTH_HASH_Z const int outBufMaxLength,
								 IN_BUFFER_OPT( inLength ) const void *inBuffer, 
								 IN_LENGTH_Z const int inLength,
								 IN_ENUM( HASH_STATE ) \
									const HASH_STATE_TYPE hashState );
typedef STDC_NONNULL_ARG( ( 1, 3 ) ) \
		void ( *HASH_FUNCTION_ATOMIC )( OUT_BUFFER_FIXED( outBufMaxLength ) \
											BYTE *outBuffer, 
										IN_LENGTH_HASH const int outBufMaxLength,
										IN_BUFFER( inLength ) const void *inBuffer, 
										IN_LENGTH const int inLength );

STDC_NONNULL_ARG( ( 3 ) ) \
void getHashParameters( IN_ALGO const CRYPT_ALGO_TYPE hashAlgorithm,
						IN_INT_SHORT_Z const int hashParams,
						OUT_PTR HASH_FUNCTION *hashFunction, 
						OUT_OPT_LENGTH_SHORT_Z int *hashOutputSize );
STDC_NONNULL_ARG( ( 3 ) ) \
void getHashAtomicParameters( IN_ALGO const CRYPT_ALGO_TYPE hashAlgorithm,
							  IN_INT_SHORT_Z const int hashParams,
							  OUT_PTR HASH_FUNCTION_ATOMIC *hashFunctionAtomic, 
							  OUT_OPT_LENGTH_SHORT_Z int *hashOutputSize );

/* Sometimes all that we need is a quick-reject check, usually performed to 
   lighten the load before we do a full hash check.  The following function 
   returns an integer checksum that can be used to weed out non-matches.  If 
   the checksum matches, we use the more heavyweight full hash of the data */

#define HASH_DATA_SIZE	16

RETVAL_RANGE( MAX_ERROR, 0x7FFFFFFF ) STDC_NONNULL_ARG( ( 1 ) ) \
int checksumData( IN_BUFFER( dataLength ) const void *data, 
				  IN_DATALENGTH const int dataLength );
STDC_NONNULL_ARG( ( 1, 3 ) ) \
void hashData( OUT_BUFFER_FIXED( hashMaxLength ) BYTE *hash, 
			   IN_LENGTH_HASH const int hashMaxLength, 
			   IN_BUFFER( dataLength ) const void *data, 
			   IN_DATALENGTH const int dataLength );

/* When we're comparing two cryptographic values, for example two MAC 
   values, and the developer's been careful to implement things really 
   badly, it may be possible to use a timing attack to guess a MAC value a
   byte at a time by using a high-resolution timer to check at which byte
   the memcmp() exits, thus guessing the MAC value a byte at a time in the
   same way that the old TENEX password-guessing bug worked.  This seems
   highly unlikely given that cryptlib implementations of protocols won't
   allow themselves to be used as an oracle in this manner and for someone
   using cryptlib to implement their own protocol the overhead of a trip
   through the kernel will mask out a few clock cycles of difference in
   the memcmp() at the end, but we defend against it anyway because no doubt
   someone will eventually publish a CERT advisory on it being a problem in
   some app somewhere */

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1, 2 ) ) \
BOOLEAN compareDataConstTime( IN_BUFFER( length ) const void *src,
							  IN_BUFFER( length ) const void *dest,
							  IN_LENGTH_SHORT const int length );

/****************************************************************************
*																			*
*							Signing/Key Wrap Functions						*
*																			*
****************************************************************************/

/* Signatures can have all manner of additional odds and ends associated 
   with them, the following structure contains these additional optional
   values */

typedef struct {
	/* CMS additional signature information */
	BOOLEAN useDefaultAuthAttr;		/* Use built-in default auth.attr */
	CRYPT_CERTIFICATE iAuthAttr;	/* User-supplied auth.attributes */
	CRYPT_SESSION iTspSession;		/* TSP session for timestamping */

	/* PGP additional signature information */
	int sigType;					/* Signature type */
	BUFFER_OPT_FIXED( sigAttributeSize ) \
	const void *sigAttributes;		/* Additional signature attributes */
	int sigAttributeSize;

	/* SSL/TLS additional signature information */
	CRYPT_CONTEXT iSecondHash;		/* Second hash for dual sig.*/
	} SIGPARAMS;

#define initSigParams( sigParams ) \
	{ \
	memset( ( sigParams ), 0, sizeof( SIGPARAMS ) ); \
	( sigParams )->iAuthAttr = ( sigParams )->iTspSession = \
		( sigParams )->iSecondHash = CRYPT_ERROR; \
	}

#define initSigParamsPGP( sigParams, pgpSigType, pgpAttrs, pgpAttrSize ) \
	{ \
	memset( ( sigParams ), 0, sizeof( SIGPARAMS ) ); \
	( sigParams )->iAuthAttr = ( sigParams )->iTspSession = \
	( sigParams )->iSecondHash = CRYPT_ERROR; \
	( sigParams )->sigType = pgpSigType; \
	( sigParams )->sigAttributes = pgpAttrs; \
	( sigParams )->sigAttributeSize = pgpAttrSize; \
	}

/* Internal forms of various external functions.  These work with internal
   resources that are marked as being inaccessible to the corresponding
   external functions, and don't perform all the checking that their
   external equivalents perform, since the parameters have already been
   checked by cryptlib */

CHECK_RETVAL STDC_NONNULL_ARG( ( 3 ) ) \
int iCryptCreateSignature( OUT_BUFFER_OPT( signatureMaxLength, *signatureLength ) \
							void *signature, 
						   IN_DATALENGTH_Z const int signatureMaxLength,
						   OUT_DATALENGTH_Z int *signatureLength,
						   IN_ENUM( CRYPT_FORMAT ) \
							const CRYPT_FORMAT_TYPE formatType,
						   IN_HANDLE const CRYPT_CONTEXT iSignContext,
						   IN_HANDLE const CRYPT_CONTEXT iHashContext,
						   IN_OPT const SIGPARAMS *sigParams );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int iCryptCheckSignature( IN_BUFFER( signatureLength ) const void *signature, 
						  IN_LENGTH_SHORT const int signatureLength,
						  IN_ENUM( CRYPT_FORMAT ) \
							const CRYPT_FORMAT_TYPE formatType,
						  IN_HANDLE const CRYPT_HANDLE iSigCheckKey,
						  IN_HANDLE const CRYPT_CONTEXT iHashContext,
						  IN_HANDLE_OPT const CRYPT_CONTEXT iHash2Context,
						  OUT_OPT_HANDLE_OPT CRYPT_HANDLE *extraData );
#ifdef USE_INT_CMS
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int iCryptImportKey( IN_BUFFER( encryptedKeyLength ) const void *encryptedKey, 
					 IN_LENGTH_SHORT const int encryptedKeyLength,
					 IN_ENUM( CRYPT_FORMAT ) \
						const CRYPT_FORMAT_TYPE formatType,
					 IN_HANDLE const CRYPT_CONTEXT iImportKey,
					 IN_HANDLE_OPT const CRYPT_CONTEXT iSessionKeyContext,
					 OUT_OPT_HANDLE_OPT CRYPT_CONTEXT *iReturnedContext );
CHECK_RETVAL STDC_NONNULL_ARG( ( 3 ) ) \
int iCryptExportKey( OUT_BUFFER_OPT( encryptedKeyMaxLength, *encryptedKeyLength ) \
						void *encryptedKey, 
					 IN_DATALENGTH_Z const int encryptedKeyMaxLength,
					 OUT_DATALENGTH_Z int *encryptedKeyLength,
					 IN_ENUM( CRYPT_FORMAT ) \
						const CRYPT_FORMAT_TYPE formatType,
					 IN_HANDLE_OPT const CRYPT_CONTEXT iSessionKeyContext,
					 IN_HANDLE const CRYPT_CONTEXT iExportKey );
#endif /* USE_INT_CMS */

/****************************************************************************
*																			*
*							Envelope Management Functions					*
*																			*
****************************************************************************/

#ifdef USE_ENVELOPES

/* General-purpose enveloping functions, used by various high-level
   protocols */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5, 11 ) ) \
int envelopeWrap( IN_BUFFER( inDataLength ) const void *inData, 
				  IN_DATALENGTH_MIN( 16 ) const int inDataLength, 
				  OUT_BUFFER( outDataMaxLength, *outDataLength ) void *outData, 
				  IN_DATALENGTH_MIN( 16 ) const int outDataMaxLength, 
				  OUT_DATALENGTH_Z int *outDataLength, 
				  IN_ENUM( CRYPT_FORMAT ) const CRYPT_FORMAT_TYPE formatType,
				  IN_ENUM_OPT( CRYPT_CONTENT ) const CRYPT_CONTENT_TYPE contentType,
				  IN_HANDLE_OPT const CRYPT_HANDLE iPublicKey,
				  IN_BUFFER_OPT( passwordLength ) const void *password,
				  IN_LENGTH_SHORT_Z const int passwordLength,
				  OUT ERROR_INFO *errorInfo );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5, 9 ) ) \
int envelopeUnwrap( IN_BUFFER( inDataLength ) const void *inData, 
					IN_DATALENGTH_MIN( 16 ) const int inDataLength,
					OUT_BUFFER( outDataMaxLength, *outDataLength ) void *outData, 
					IN_DATALENGTH_MIN( 16 ) const int outDataMaxLength,
					OUT_DATALENGTH_Z int *outDataLength, 
					IN_HANDLE_OPT const CRYPT_CONTEXT iPrivKey,
					IN_BUFFER_OPT( passwordLength ) const void *password,
					IN_LENGTH_SHORT_Z const int passwordLength,
					OUT ERROR_INFO *errorInfo );
CHECK_RETVAL STDC_NONNULL_ARG( ( 3, 5 ) ) \
int envelopeSign( IN_BUFFER_OPT( inDataLength ) const void *inData, 
				  IN_DATALENGTH_Z const int inDataLength,
				  OUT_BUFFER( outDataMaxLength, *outDataLength ) void *outData, 
				  IN_DATALENGTH_MIN( 16 ) const int outDataMaxLength,
				  OUT_DATALENGTH_Z int *outDataLength, 
				  IN_ENUM_OPT( CRYPT_CONTENT ) const CRYPT_CONTENT_TYPE contentType,
				  IN_HANDLE const CRYPT_CONTEXT iSigKey,
				  IN_HANDLE_OPT const CRYPT_CERTIFICATE iCmsAttributes,
				  OUT ERROR_INFO *errorInfo );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5, 7 ) ) \
int envelopeSigCheck( IN_BUFFER( inDataLength ) const void *inData, 
					  IN_DATALENGTH_MIN( 16 ) const int inDataLength,
					  OUT_BUFFER( outDataMaxLength, *outDataLength ) void *outData, 
					  IN_DATALENGTH_MIN( 16 ) const int outDataMaxLength,
					  OUT_DATALENGTH_Z int *outDataLength, 
					  IN_HANDLE_OPT const CRYPT_CONTEXT iSigCheckKey,
					  OUT_STATUS int *sigResult, 
					  OUT_OPT_HANDLE_OPT CRYPT_CERTIFICATE *iSigningCert,
					  OUT_OPT_HANDLE_OPT CRYPT_CERTIFICATE *iCmsAttributes,
					  OUT ERROR_INFO *errorInfo );
#endif /* USE_ENVELOPES */

/****************************************************************************
*																			*
*							Bignum Manipulation Functions					*
*																			*
****************************************************************************/

/* Prototypes for functions in context/ctx_bnrw.c, used in the ASN.1/misc 
   read/write routines */

typedef enum {
	KEYSIZE_CHECK_NONE,		/* Don't check for short key sizes */
		KEYSIZE_CHECK_SPECIAL_NONE = KEYSIZE_CHECK_NONE,
	KEYSIZE_CHECK_PKC,		/* Check for a short PKC key */
	KEYSIZE_CHECK_ECC,		/* Check for a short ECC key */
		KEYSIZE_CHECK_LAST = KEYSIZE_CHECK_ECC + 1,
							/* Last valid normal check type */
	KEYSIZE_CHECK_SPECIAL,	/* Allow slightly oversize keys for DLP */
	KEYSIZE_CHECK_SPECIAL_LAST	/* Last valid check type */
	} KEYSIZE_CHECK_TYPE;

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int importBignum( INOUT TYPECAST( BIGNUM * ) void *bignumPtr, 
				  IN_BUFFER( length ) const void *buffer, 
				  IN_LENGTH_SHORT const int length,
				  IN_LENGTH_PKC const int minLength, 
				  IN_RANGE( 1, CRYPT_MAX_PKCSIZE + 8 ) \
					const int maxLength,	
					/* See DLP_OVERFLOW_SIZE = 8 in context.h */
				  IN_OPT TYPECAST( BIGNUM * ) const void *maxRangePtr,
				  IN_ENUM_OPT( KEYSIZE_CHECK_SPECIAL ) \
					const KEYSIZE_CHECK_TYPE checkType );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
int exportBignum( OUT_BUFFER( dataMaxLength, *dataLength ) void *data, 
				  IN_LENGTH_SHORT_MIN( 16 ) const int dataMaxLength, 
				  OUT_LENGTH_BOUNDED_Z( dataMaxLength ) int *dataLength,
				  IN TYPECAST( BIGNUM * ) const void *bignumPtr );
CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1, 2 ) ) \
BOOLEAN verifyBignumImport( TYPECAST( const BIGNUM * ) const void *bignumPtr, 
							IN_BUFFER( length ) const void *buffer, 
							IN_LENGTH_SHORT const int length );
#if defined( USE_ECDH ) || defined( USE_ECDSA ) 
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
int importECCPoint( INOUT void *bignumPtr1, 
					INOUT void *bignumPtr2, 
				    IN_BUFFER( length ) const void *buffer, 
				    IN_LENGTH_SHORT const int length,
					IN_LENGTH_PKC const int minLength, 
					IN_LENGTH_PKC const int maxLength, 
					IN_LENGTH_PKC const int fieldSize,
					IN_OPT const void *maxRangePtr,
					IN_ENUM( KEYSIZE_CHECK ) \
						const KEYSIZE_CHECK_TYPE checkType );
CHECK_RETVAL STDC_NONNULL_ARG( ( 3, 4, 5 ) ) \
int exportECCPoint( OUT_BUFFER_OPT( dataMaxLength, *dataLength ) void *data, 
					IN_LENGTH_SHORT_Z const int dataMaxLength, 
					OUT_LENGTH_BOUNDED_PKC_Z( dataMaxLength ) int *dataLength,
					IN const void *bignumPtr1, 
					IN const void *bignumPtr2,
					IN_LENGTH_PKC const int fieldSize );
#endif /* USE_ECDH || USE_ECDSA */

/****************************************************************************
*																			*
*					Signature Creation/Checking Functions					*
*																			*
****************************************************************************/

/* Prototypes for functions in mechs/sign_x509.c, used by certificates and
   sessions.  In the standard PKIX tradition there are a whole range of 
   b0rken PKI protocols that couldn't quite manage a cut & paste of two 
   lines of text, adding all sorts of unnecessary extra tagging and wrappers 
   to the signature.  
   
   The encoding of these odds and ends is handled via the X509SIG_FORMATINFO.  
   The basic form allows a user-supplied tag and an indication of whether 
   it's explicitly or implicitly tagged.  If the explicitTag flag is clear 
   the tag is encoded as [n] { ... }.  If it's set, it's encoded as 
   [n] { SEQUENCE { ... }}.  
   
   In addition the extraLength field allows for the optional insertion of 
   extra data by the caller, with the wrapper length being written to 
   include the extraLength, whose payload can then be appended by the 
   caller */

typedef struct {
	int tag;				/* Tag for signature */
	BOOLEAN isExplicit;		/* Whether tag is expicit */
	int extraLength;		/* Optional length for further data */
	} X509SIG_FORMATINFO;

#define setX509FormatInfo( formatInfo, formatTag, formatIsExplicit ) \
		memset( formatInfo, 0, sizeof( X509SIG_FORMATINFO ) ); \
		( formatInfo )->tag = ( formatTag ); \
		( formatInfo )->isExplicit = ( formatIsExplicit )

/* Create and verify an X.509-style signature, with optional extra odds and
   ends as specified in various PKI protocols */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
int createX509signature( OUT_BUFFER( signedObjectMaxLength, \
									 *signedObjectLength ) \
							void *signedObject, 
						 IN_DATALENGTH_Z const int signedObjectMaxLength, 
						 OUT_DATALENGTH_Z int *signedObjectLength,
						 IN_BUFFER( objectLength ) const void *object, 
						 IN_DATALENGTH const int objectLength,
						 IN_HANDLE const CRYPT_CONTEXT iSignContext,
						 IN_ALGO const CRYPT_ALGO_TYPE hashAlgo,
						 IN_OPT const X509SIG_FORMATINFO *formatInfo );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int checkX509signature( IN_BUFFER( signedObjectLength ) const void *signedObject, 
						IN_DATALENGTH const int signedObjectLength,
						IN_HANDLE const CRYPT_CONTEXT iSigCheckContext,
						IN_OPT const X509SIG_FORMATINFO *formatInfo );

/* Create and verify a raw signature */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
int createRawSignature( OUT_BUFFER( sigMaxLength, *signatureLength ) \
							void *signature, 
						IN_LENGTH_SHORT_MIN( MIN_CRYPT_OBJECTSIZE ) \
							const int sigMaxLength, 
						OUT_LENGTH_BOUNDED_Z( sigMaxLength ) \
							int *signatureLength, 
						IN_HANDLE const CRYPT_CONTEXT iSignContext,
						IN_HANDLE const CRYPT_CONTEXT iHashContext );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int checkRawSignature( IN_BUFFER( signatureLength ) const void *signature, 
					   IN_LENGTH_SHORT const int signatureLength,
					   IN_HANDLE const CRYPT_CONTEXT iSigCheckContext,
					   IN_HANDLE const CRYPT_CONTEXT iHashContext );

/****************************************************************************
*																			*
*							Miscellaneous Functions							*
*																			*
****************************************************************************/

/* Miscellaneous functions that need to be prototyped here (or at least in 
   some globally-visible header) in order for them to be visible in the 
   external modules that reference them */ 

/* Prototypes for functions in context/key_wr.c, used by devices */

CHECK_RETVAL STDC_NONNULL_ARG( ( 3, 6 ) ) \
int writeFlatPublicKey( OUT_BUFFER_OPT( bufMaxSize, *bufSize ) void *buffer, 
						IN_LENGTH_SHORT_Z const int bufMaxSize, 
						OUT_LENGTH_BOUNDED_Z( bufMaxSize ) int *bufSize,
						IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo, 
						IN_RANGE( 0, 100 ) const int intParam,
						IN_BUFFER( component1Length ) const void *component1, 
						IN_LENGTH_PKC const int component1Length,
						IN_BUFFER( component2Length ) const void *component2, 
						IN_LENGTH_PKC const int component2Length,
						IN_BUFFER_OPT( component3Length ) const void *component3, 
						IN_LENGTH_PKC_Z const int component3Length,
						IN_BUFFER_OPT( component4Length ) const void *component4, 
						IN_LENGTH_PKC_Z const int component4Length );

/* Prototypes for functions in cryptctx.c, used in numerous other modules */

CHECK_RETVAL_BOOL \
BOOLEAN checkContextCapability( IN_HANDLE const CRYPT_CONTEXT iCryptContext,
								IN_ENUM( MESSAGE_CHECK ) \
									const MESSAGE_CHECK_TYPE checkType );

/* Prototypes for functions in cryptcrt.c, used by devices, and a generic 
   one used by anything that fetches a certificate */

#if defined( USE_CERTIFICATES ) || defined( USE_PSEUDOCERTIFICATES )
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int createCertificateIndirect( INOUT MESSAGE_CREATEOBJECT_INFO *createInfo,
							   STDC_UNUSED const void *auxDataPtr, 
							   STDC_UNUSED const int auxValue );
#endif /* USE_CERTIFICATES || USE_PSEUDOCERTIFICATES */

#ifdef USE_CERTIFICATES
CHECK_RETVAL STDC_NONNULL_ARG( ( 3 ) ) \
int iCryptVerifyID( IN_HANDLE const CRYPT_CERTIFICATE iCertificate,
					IN_ENUM( CRYPT_KEYID ) const CRYPT_KEYID_TYPE keyIDtype,
					IN_BUFFER( keyIDlength ) const void *keyID, 
					IN_LENGTH_SHORT const int keyIDlength );
#endif /* USE_CERTIFICATES */
#endif /* _INTAPI_DEFINED */
