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

#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_PTR 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 ) || \
		    ( strnlen_s( password, CRYPT_MAX_TEXTSIZE ) < 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, and that an 
   integer value is non-suspicious.  The former is used as a sanity-check on 
   (supposedly) random keys before we load them, the latter on bignum 
   integers to try and detect suspicious values */

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
BOOLEAN checkEntropy( IN_BUFFER( dataLength ) const BYTE *data, 
					  IN_LENGTH_SHORT_MIN( MIN_KEYSIZE ) const int dataLength );
#ifndef NDEBUG
CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
BOOLEAN checkEntropyInteger( IN_BUFFER( length ) const BYTE *data, 
							 IN_LENGTH_PKC_Z const int length );
#else
  #define checkEntropyInteger( data, dataLength )		TRUE
#endif /* !NDEBUG */

/* 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 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.

   The caller can pass in an optional character-read function to override
   the default stream read, this is used to allow for buffered network 
   reads.

   Since the STREAM struct isn't visible at this point, we have to use a 
   forward declaration for it */

struct ST;

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

typedef enum {
	READTEXT_NONE,			/* No readtext option */
	READTEXT_MULTILINE,		/* Allow multi-line continuations */
	READTEXT_RAW,			/* Return raw, non-canonicalised input */
	READTEXT_LAST			/* Last valid readtext option type */
	} READTEXT_TYPE;

typedef CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
		int ( *READCHAR_FUNCTION )( INOUT_PTR TYPECAST( STREAM * ) struct ST *streamPtr );

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
int readTextLine( INOUT_PTR TYPECAST( STREAM * ) struct ST *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,
				  IN_PTR_OPT READCHAR_FUNCTION readCharFunctionOpt, 
				  IN_ENUM_OPT( READTEXT ) const READTEXT_TYPE options );
#endif /* USE_HTTP || USE_BASE64 || USE_SCEP || USE_SSH */

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

/* Get OS-specific values */

#if defined( __WIN32__ ) || defined( __WINCE__ )
typedef enum { 
	SYSVAR_NONE,			/* No system variable */
#if VC_LT_2010( _MSC_VER )
	SYSVAR_OSMAJOR,			/* OS major version number */
	SYSVAR_OSMINOR,			/* OS minor version number */
#endif /* VC++ < 2010 */
	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 */

#define HWINTRINS_FLAG_LAST			HWINTRINS_FLAG_MAX	/* Define for source code analyser */

/* 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_MAX			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.  Since 
	 the SECURITY_INFO struct isn't visible at this point, we have to use a 
	 forward declaration for it */
  #ifdef __WIN32__
	struct SECI;
	CHECK_RETVAL_PTR \
	void *initACLInfo( const int access );
	void *getACLInfo( INOUT_PTR_OPT struct SECI *securityInfoPtr );
	STDC_NONNULL_ARG( ( 1 ) ) \
	void freeACLInfo( IN_PTR struct SECI *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 ) )

/* 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_PTR_COND const char **newStringPtr, 
						IN_BUFFER( strLen ) const char *string, 
						IN_LENGTH_SHORT const int strLen );
CHECK_RETVAL_STRINGOP STDC_NONNULL_ARG( ( 1, 2 ) ) \
int strExtract( OUT_PTR_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_LENGTH STDC_NONNULL_ARG( ( 1, 3 ) ) \
int strParseNumeric( IN_BUFFER( strLen ) const char *str, 
					 IN_LENGTH_SHORT const int strMaxLen, 
					 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, 0xFFFF ) 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.  The main group follows a fixed pattern of "throw 
   an exception, return an internal-error code" or equivalent, e.g. a NULL
   pointer.  A second group incorporates cleanup functionality before 
   exiting, e.g. freeing memory or objects.
   
   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_Ext( value ) \
		{ \
		DEBUG_DUMP_STACKTRACE(); \
		assert( INTERNAL_ERROR ); \
		return( value ); \
		}

#define retIntError()			retIntError_Ext( CRYPT_ERROR_INTERNAL )
#define retIntError_Null()		retIntError_Ext( NULL )
#define retIntError_Boolean()	retIntError_Ext( FALSE )
#define retIntError_Dataptr()	retIntError_Ext( DATAPTR_NULL )
#define retIntError_Void() \
		{ \
		DEBUG_DUMP_STACKTRACE(); \
		assert( INTERNAL_ERROR ); \
		return; \
		}

#define retIntError_Ptr( ptr ) \
		{ \
		clFree( "Internal error", ptr ); \
		retIntError(); \
		}
#define retIntError_Obj( handle ) \
		{ \
		krnlReleaseObject( handle ); \
		retIntError(); \
		}
#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 ); 

   Note that the end-of-table delimiter is 0, not CRYPT_ERROR, since one of 
   the object types whose name we need to look up is status values */

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.  This
   is called as:

		retExt( status,
				( status, errorInfo, 
				  "Text message", args ) );
   
   In addition to the standard retExt() we also have several extended-form 
   versions of the function that take additional error info parameters:

	retExtAdditional() is a variation of the standard retExt() that appends 
		the error string to existing error information rather than creating 
		it from the string.  Called as:

		retExtAdditional( status,
						  ( status, errorInfo, 
							", however this may be a false positive" ) );

		See also checkErrorMessage() for checking whether the existing error
		message is what it's supposed to be.

	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.
		Call with an initial error string, if further error information is
		available it will be appended prefixed by 
		".  Additional information: ", so that for example "Error info" will
		become "Error info.  Additional information: More error info".  This
		is called as:

		retExtObj( status,
				   ( status, errorInfo, cryptHandle,
				     "Text message", args ) );

	retExtObjDirect() works as retExtObj() but just passes the extended 
		error information up from the lower-level object without modifying
		the text in any way.  This is used for things like devices acting as
		keysets (using an actual keyset) where the error string is passed up 
		from the underlying keyset.  This is called as:

		retExtObjDirect( status,
						 ( status, errorInfo, cryptHandle ) );

	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".  errorInfo and existingErrorInfo 
		can point to the same location.  Called as:

		clearErrorInfo( &localErrorInfo );
		[...]
		retExtErr( status,
				   ( status, errorInfo, lowerErrorInfo,
					 "Error trying to read from keyset: ", args ) );

	retExtErrOpt() is a variant of retExtErr() that uses the first error
		string to build the message if the lower-level error information is 
		present and the second error string if it isn't.  Called as:

		retExtErrOpt( status,
					  ( status, errorInfo, lowerErrorInfo,
						"Error trying to read from keyset", args ) ); 

	retExtSan() is used with arguments that need to be sanitised using 
		sanitiseString().  It takes up to three arguments that are passed to
		sanitiseString() if necessary.  The first argument is always
		sanitised, the second and third arguments are optional and are
		sanitised if a length is provided or treated as literal strings if
		not.  Called as:

		retExtSan( status,
				   ( status, errorInfo, 
					 "Invalid host name '%s' in server's certificate for "
					 "'%s'", certName, originalCertNameLength,
					 holderName, 0, NULL, 0 ) );

		where the first argument is sanitised, the second is used as-is, and
		the third is absent.
		
		This covers almost all cases where sanitisation is required, the 
		exceptions are where the arguments are san + %d (3 cases), %d + san
		(1 case), san + san + %d (1 case), and san + retExtObj (3 cases) */

#define clearErrorInfo( errorInfo ) \
		memset( ( errorInfo ), 0, sizeof( ERROR_INFO ) )

#ifdef USE_ERRMSGS
		/* Check whether the error message in the error info has a 
		   particular form.  This somewhat ugly function is sometimes
		   required in conjunction with retExtAdditional() to ensure that 
		   modifying the message returned from a lower-level function will 
		   produce a coherent overall message */
#define checkErrorMessage( errorInfo, message, messageLength ) \
		( ( errorInfo )->errorStringLength >= ( messageLength ) && \
		  !memcmp( ( errorInfo )->errorString, \
				   ( message ), ( messageLength ) ) )
STDC_NONNULL_ARG( ( 1, 3 ) ) \
void formatHexData( OUT_BUFFER_FIXED( hexTextMaxLen ) char *hexText, 
					IN_LENGTH_SHORT_MIN( 48 ) const int hexTextMaxLen,
					IN_BUFFER( hexDataLen ) const BYTE *hexData,
					IN_LENGTH_SHORT_MIN( 4 ) const int hexDataLen );
RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int readErrorInfo( OUT_PTR ERROR_INFO *errorInfo, 
				   IN_HANDLE const CRYPT_HANDLE objectHandle );
STDC_NONNULL_ARG( ( 1, 2 ) ) \
void setErrorString( OUT_PTR ERROR_INFO *errorInfo, 
					 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_PTR ERROR_INFO *errorInfo, 
			  FORMAT_STRING const char *format, ... );
CHECK_RETVAL STDC_NONNULL_ARG( ( 2, 3 ) ) STDC_PRINTF_FN( 3, 4 ) \
int retExtAdditionalFn( IN_ERROR const int status, 
						INOUT_PTR ERROR_INFO *errorInfo, 
						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_PTR ERROR_INFO *errorInfo, 
				 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_PTR ERROR_INFO *errorInfo, 
				 IN_HANDLE const CRYPT_HANDLE extErrorObject, 
				 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_PTR ERROR_INFO *errorInfo, 
				 IN_PTR const ERROR_INFO *existingErrorInfo, 
				 FORMAT_STRING const char *format, ... );
CHECK_RETVAL STDC_NONNULL_ARG( ( 2, 3, 4 ) ) STDC_PRINTF_FN( 4, 5 ) \
int retExtErrOptFn( IN_ERROR const int status, 
					OUT_PTR ERROR_INFO *errorInfo, 
					IN_PTR const ERROR_INFO *existingErrorInfo, 
					FORMAT_STRING const char *format, ... );
CHECK_RETVAL STDC_NONNULL_ARG( ( 2, 3, 4 ) ) \
int retExtSanFn( IN_ERROR const int status, 
				 OUT_PTR ERROR_INFO *errorInfo,
				 FORMAT_STRING const char *formatString,
				 IN_BUFFER( string1Length ) const BYTE *string1,
				 IN_LENGTH_SHORT_Z const int string1Length,
				 IN_BUFFER_OPT( string2Length ) const BYTE *string2,
				 IN_LENGTH_SHORT_Z const int string2Length,
				 IN_BUFFER_OPT( string3Length ) const BYTE *string3,
				 IN_LENGTH_SHORT_Z const int string3Length );
#else
  #define checkErrorMessage( errorInfo, message, messageLength ) \
		  FALSE
  #define formatHexData( hexText, hexTextMaxLen, hexData, hexDataLen )
  #define readErrorInfo( errorInfo, objectHandle ) \
		  CRYPT_ERROR
  #define setErrorString( errorInfo, string, stringLength )
#endif /* USE_ERRMSGS */
STDC_NONNULL_ARG( ( 1, 2 ) ) \
void copyErrorInfo( OUT_PTR ERROR_INFO *destErrorInfo, 
					IN_PTR const ERROR_INFO *srcErrorInfo );

#ifdef USE_ERRMSGS
  #define retExt( status, extStatus )		return retExtFn extStatus
  #define retExtAdditional( status, extStatus )	\
											return retExtAdditionalFn extStatus 
  #define retExtArg( status, extStatus )	return retExtArgFn extStatus
  #define retExtObj( status, extStatus )	return retExtObjFn extStatus
  #define retExtObjDirect( status, errorInfo, extErrorObject ) \
											return( retExtObjFn( status, errorInfo, \
																 extErrorObject, "NULL" ) ) 
  #define retExtErr( status, extStatus )	return retExtErrFn extStatus 
  #define retExtErrOpt( status, extStatus )	return retExtErrOptFn extStatus 
  #define retExtSan( status, extStatus )	return retExtSanFn 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 retExtAdditional( status, extStatus )	\
											return status
  #define retExtArg( status, extStatus )	return status
  #define retExtObj( status, extStatus )	return status
  #define retExtObjDirect( status, errorInfo, extErrorObject ) \
											return( status )
  #define retExtErr( status, extStatus )	return status
  #define retExtErrOpt( status, extStatus )	return status
  #define retExtSan( 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 CERTIFICATE_ERRINFO	&certInfoPtr->errorInfo
#define DEVICE_ERRINFO		&deviceInfoPtr->errorInfo
#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_PTR_NONNULL \
const char *getStatusName( IN_STATUS const int errorStatus );
CHECK_RETVAL_PTR_NONNULL \
const char *getAlgoName( IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo );
CHECK_RETVAL_PTR_NONNULL \
const char *getAlgoNameEx( IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo,
						   IN_RANGE( 0, 100 ) const int cryptParam );
CHECK_RETVAL_PTR_NONNULL \
const char *getModeName( IN_MODE const CRYPT_MODE_TYPE cryptMode );
CHECK_RETVAL_PTR_NONNULL \
const char *getKeyIDName( IN_KEYID const CRYPT_KEYID_TYPE keyID );
CHECK_RETVAL_PTR_NONNULL STDC_NONNULL_ARG( ( 2 ) ) \
const char *getCertHolderName( const CRYPT_CERTIFICATE iCryptCert,
							   OUT_BUFFER_FIXED( bufSize ) char *buffer,
							   IN_LENGTH_SHORT_MIN( 16 ) const int bufSize );
#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, 7 ) ) \
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,
							  INOUT_PTR ERROR_INFO *errorInfo );

/* 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_PTR TYPECAST( STREAM * ) struct ST *streamPtr, 
								OUT_HANDLE_OPT CRYPT_CONTEXT *iPubkeyContext,
								IN_HANDLE const CRYPT_DEVICE iCreatorHandle, 
								IN_BOOL 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 */

typedef enum {
	QUERYOBJECT_NONE,		/* No query object type */
	QUERYOBJECT_KEYEX,		/* Keyex object */
	QUERYOBJECT_SIGNATURE,	/* Signature object */
	QUERYOBJECT_UNKNOWN,	/* Unknown object (use content sniffing) */
	QUERYOBJECT_LAST		/* Last valid query object type */
	} QUERYOBJECT_TYPE;

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int queryAsn1Object( INOUT_PTR TYPECAST( STREAM * ) struct ST *streamPtr, 
					 OUT_PTR QUERY_INFO *queryInfo,
					 const QUERYOBJECT_TYPE objectTypeHint );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int queryPgpObject( INOUT_PTR TYPECAST( STREAM * ) struct ST *streamPtr, \
					OUT_PTR QUERY_INFO *queryInfo,
					const QUERYOBJECT_TYPE objectTypeHint );

/* 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.
   
   Note the non-orthogonal nature of the format specifiers to 
   exportCertToStream()/importCertFromStream, for the export we use a
   format specifier since the object type is known and we're specifying
   a format to write it as, e.g. a certificate formatted as a
   certificate chain, for the import we specify a type such as a
   certificate set */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int exportAttributeToStream( INOUT_PTR TYPECAST( STREAM * ) struct ST *streamPtr, 
							 IN_HANDLE const CRYPT_HANDLE cryptHandle,
							 IN_ATTRIBUTE \
								const CRYPT_ATTRIBUTE_TYPE attributeType );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int exportVarsizeAttributeToStream( INOUT_PTR TYPECAST( STREAM * ) struct ST *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_PTR TYPECAST( STREAM * ) struct ST *streamPtr,
						IN_HANDLE const CRYPT_CERTIFICATE cryptCertificate,
						IN_ENUM( CRYPT_CERTFORMAT ) \
							const CRYPT_CERTFORMAT_TYPE certFormatType );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 7 ) ) \
int importCertFromStream( INOUT_PTR TYPECAST( STREAM * ) struct ST *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,
						  INOUT_PTR ERROR_INFO *errorInfo );

/* 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( 8 ) 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 */

/* PKI user data en/decode routines */

#ifdef USE_BASE64ID

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
BOOLEAN isPKIUserValue( IN_BUFFER( encValLength ) const char *encVal, 
						IN_LENGTH_SHORT_MIN( 16 ) 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 );
#endif /* USE_BASE64ID */

/* TOTP (as Base32) en/decode routines */

#if defined( USE_TLS ) || defined( USE_SSH )

CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
BOOLEAN isBase32Value( IN_BUFFER( encValLength ) const char *encVal, 
					   IN_LENGTH_SHORT_MIN( 16 ) const int encValLength );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
int decodeBase32Value( OUT_BUFFER( valueMaxLen, *valueLen ) BYTE *value, 
					   IN_LENGTH_SHORT_MIN( 32 ) const int valueMaxLen, 
					   OUT_LENGTH_BOUNDED_Z( valueMaxLen ) int *valueLen,
					   IN_BUFFER( encValLength ) const char *encVal, 
					   IN_LENGTH_SHORT_MIN( 16 ) const int encValLength );

#endif /* USE_TLS || USE_SSH */

/****************************************************************************
*																			*
*						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_PTR_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 \
		DATAPTR ( *DATAPTR_GETATTR_FUNCTION ) \
							( IN_DATAPTR_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_PTR_OPT const void *attributePtr,
						  IN_PTR GETATTR_FUNCTION getAttrFunction );
CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 2 ) ) \
void *attributeFindEnd( IN_PTR_OPT const void *attributePtr,
						IN_PTR GETATTR_FUNCTION getAttrFunction );
CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 2 ) ) \
void *attributeFind( IN_PTR_OPT const void *attributePtr,
					 IN_PTR GETATTR_FUNCTION getAttrFunction,
					 IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attributeID );
CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 2 ) ) \
void *attributeFindEx( IN_PTR_OPT const void *attributePtr,
					   IN_PTR 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_PTR_OPT const void *attributePtr,
								 IN_PTR GETATTR_FUNCTION getAttrFunction );
CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 2 ) ) \
const void *attributeMoveCursor( IN_PTR_OPT const void *currentCursor,
								 IN_PTR 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_DATAPTR_OPT const DATAPTR attributePtr,
							  IN_PTR GETATTR_FUNCTION getAttrFunction,
							  IN_ATTRIBUTE \
								const CRYPT_ATTRIBUTE_TYPE attributeID );
CHECK_RETVAL_DATAPTR STDC_NONNULL_ARG( ( 2 ) ) \
DATAPTR dataptrAttributeFindEx( IN_DATAPTR_OPT const DATAPTR attributePtr,
								IN_PTR 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_DATAPTR_OPT DATAPTR attributePtr,
										  IN_PTR GETATTR_FUNCTION getAttrFunction );
CHECK_RETVAL_DATAPTR STDC_NONNULL_ARG( ( 2 ) ) \
DATAPTR dataptrAttributeMoveCursor( IN_DATAPTR_OPT const DATAPTR currentCursor,
									IN_PTR GETATTR_FUNCTION getAttrFunction,
									IN_ATTRIBUTE \
										const CRYPT_ATTRIBUTE_TYPE attributeMoveType,
									IN_RANGE( CRYPT_CURSOR_LAST, CRYPT_CURSOR_FIRST )
										const int cursorMoveType );	/* Values are -ve */

/****************************************************************************
*																			*
*								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 addition we may require special-case 
   capabilities from time-handling functions such as returning a time that's
   not too accurate in order to defeat, or at least make harder, timing 
   attacks based on the fact that every signing operation that we perform
   typically ends up being timestamped somewhere.  To deal with this, we
   provide the following options for the get-time function:

	GETTIME_NONE		Return the time with no special-case handling, used
						when checking timestamps.
	GETTIME_NOFAIL		Return a best-effort guaranteed non-zero time, 
						potentially an approximate value hardcoded in at 
						compile time if GETTIME_NONE would produce an error.
	GETTIME_MINUTES		Round the time to the nearest minute to mitigate
						timing-based attacks, used when emitting timestamps.

   Alongside the standard getTime() we also have a getReliableTime() which
   tries to get the time associated with a handle, for example to a context 
   in an HSM, and if that falls back to getTime() via the system device */

#include <time.h>

typedef enum {
	GETTIME_NONE,		/* No get-time option */
	GETTIME_NOFAIL,		/* Always return some sort of time value */
	GETTIME_MINUTES,	/* Get time to the nearest minute */
	GETTIME_NOFAIL_MINUTES,	/* Combination of the above two */
	GETTIME_LAST		/* Last valid get-time option */
	} GETTIME_TYPE;

time_t getTime( IN_ENUM_OPT( GETTIME ) const GETTIME_TYPE getTimeType );
time_t getReliableTime( IN_HANDLE const CRYPT_HANDLE cryptHandle,
						IN_ENUM_OPT( GETTIME ) const GETTIME_TYPE getTimeType );

/* 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;
	int badTimeCount;
	} MONOTIMER_INFO;

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int setMonoTimer( OUT_PTR MONOTIMER_INFO *timerInfo, 
				  IN_INT_Z const int duration );
STDC_NONNULL_ARG( ( 1 ) ) \
void extendMonoTimer( INOUT_PTR MONOTIMER_INFO *timerInfo, 
					  IN_INT const int duration );
CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
BOOLEAN checkMonoTimerExpired( INOUT_PTR MONOTIMER_INFO *timerInfo );
CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
BOOLEAN checkMonoTimerExpiryImminent( INOUT_PTR 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 );

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

/* Allocate storage from the built-in storage block.  We use a single enum 
   for both system storage (kernel-only) and general storage to make sure
   that enums with identical values can't be passed to the wrong function */

typedef enum {
	BUILTIN_STORAGE_NONE,

	/* System storage, accessible only to the kernel */
	SYSTEM_STORAGE_KRNLDATA,
	SYSTEM_STORAGE_OBJECT_TABLE,

	/* Built-in storage, generally accessible */
	BUILTIN_STORAGE_RANDOM_INFO,
#ifdef USE_CERTIFICATES
	BUILTIN_STORAGE_TRUSTMGR,
#endif /* USE_CERTIFICATES */
#ifdef USE_TCP
	BUILTIN_STORAGE_SOCKET_POOL,
#endif /* USE_TCP */
#ifdef USE_TLS
	BUILTIN_STORAGE_SCOREBOARD,
#endif /* USE_TLS */
	BUILTIN_STORAGE_OPTION_INFO,
	BUILTIN_STORAGE_LAST
	} BUILTIN_STORAGE_TYPE;

void *getBuiltinStorage( IN_ENUM( BUILTIN_STORAGE ) \
							const BUILTIN_STORAGE_TYPE storageType );
#ifndef NDEBUG
int getBuiltinStorageSize( IN_ENUM( BUILTIN_STORAGE ) \
								const BUILTIN_STORAGE_TYPE storageType );
#endif /* !NDEBUG */
CHECK_RETVAL_BOOL \
BOOLEAN checkBuiltinStorage( IN_ENUM( BUILTIN_STORAGE ) \
								const BUILTIN_STORAGE_TYPE storageType );

/* 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_PTR DYNBUF *dynBuf, 
			   IN_HANDLE const CRYPT_HANDLE cryptHandle,
			   IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attributeType );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int dynCreateCert( OUT_PTR DYNBUF *dynBuf, 
				   IN_HANDLE const CRYPT_HANDLE cryptHandle,
				   IN_ENUM( CRYPT_CERTFORMAT ) \
					const CRYPT_CERTFORMAT_TYPE formatType );
STDC_NONNULL_ARG( ( 1 ) ) \
void dynDestroy( INOUT_PTR 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.

   The MEMPOOL_STATE define provides an opaque memory block for this 
   corresponding to the MEMPOOL_INFO structure defined in misc/int_mem.c.  
   This contains 3 machine-word-sized elements (a pointer and two integers) 
   that we overallocate by two to get a worst-case of 6 words */

typedef ALIGN_DATA_TYPE( MEMPOOL_STATE[ 6 ] );

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int initMemPool( OUT_PTR 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_PTR void *statePtr, IN_LENGTH_SHORT const int size );
STDC_NONNULL_ARG( ( 1, 2 ) ) \
void freeMemPool( INOUT_PTR void *statePtr, IN_PTR 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 ]' unless the
   compiler supports C99 flexible arrays, in which case we have to explicitly 
   use '[]' to  let the compiler know that it's a flexible array.  See also
   the comment for HAS_STDC_FLEXARRAY in misc/os_spec.h.

   Note the order in which the fields are initialised by initVarStruct(), 
   this is required because, while clang allows the standard order of
   value-then-size, gcc requires that the size field be initialised first
   otherwise it produces strange crashes at runtime (unusually for gcc it
   actually produces warnings, although they tell you nothing about what
   the problem is, and then it outputs code that crashes when run).
   
   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 */

#ifdef HAS_STDC_FLEXARRAY
  /* Non-clang versions of IBM's xlc have erratic flexarray support, using
	 C99 flexarrays results in "1506-995 (W) An aggregate containing a 
	 flexible array member cannot be used as a member of a structure or as 
	 an array element" when used in a struct (kernel/storage.c) despite the
	 docs saying they can, see
	 https://www.ibm.com/docs/en/zos/2.5.0?topic=types-structures-unions,
	 however declaring the same thing in the alternate form '[0]' instead of 
	 '[]' results in it working without any problems */
  #ifdef __xlC__
	#define DECLARE_VARSTRUCT_VARS \
			int storageSize; \
			void *_align_value; \
			BYTE storage[ 0 ]
  #else
	#define DECLARE_VARSTRUCT_VARS \
			int storageSize; \
			void *_align_value; \
			BUFFER_FIXED( storageSize ) \
			BYTE storage[] FLEXARRAY_COUNT( storageSize )
  #endif /* IBM C vs. everything else */
#else
  #define DECLARE_VARSTRUCT_VARS \
		  int storageSize; \
		  void *_align_value; \
		  BUFFER_FIXED( storageSize ) \
		  BYTE storage[ 1 ]
#endif /* HAS_STDC_FLEXARRAY */

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

#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 )
#define sizeofVarStructStorage( structure ) \
		structure->storageSize

#define checkVarStruct( structure ) \
		( structure->storageSize >= 0 && \
		  structure->storageSize <= MAX_BUFFER_SIZE )

/****************************************************************************
*																			*
*							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.  The output buffer can be the
   same as the input 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.  To
   use the function:

	HASH_FUNCTION hashFunction;
	HASHINFO hashInfo;

	getHashParameters( CRYPT_ALGO_SHA2, bitsToBytes( 256 ), &hashFunction, 
					   NULL, NULL );
	hashFunction( hashInfo, NULL, 0, part1, part1len, HASH_STATE_START );
	hashFunction( hashInfo, NULL, 0, part2, part2len, HASH_STATE_CONTINUE );
	hashFunction( hashInfo, hashValue, CRYPT_MAX_HASHSIZE, 
				  part3, part3len, HASH_STATE_END );

   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 /* USE_SHA2_EXT */

typedef void ( *HASH_FUNCTION )( OUT_WHEN( hashState == HASH_STATE_START ) \
								 INOUT_WHEN( hashState != HASH_STATE_START ) \
									HASHINFO hashInfo, 
								 OUT_BUFFER_OPT_C( outBufMaxLength, 32 ) \
									BYTE *outBuffer, 
								 IN_LENGTH_SHORT_Z const int outBufMaxLength,
								 IN_BUFFER_OPT( inLength ) const void *inBuffer, 
								 IN_LENGTH_SHORT_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_C( outBufMaxLength, 20 ) \
											BYTE *outBuffer,
										IN_LENGTH_SHORT_MIN( 20 ) \
											const int outBufMaxLength,
										IN_BUFFER( inLength ) \
											const void *inBuffer,
										IN_LENGTH_SHORT const int inLength );

STDC_NONNULL_ARG( ( 3 ) ) \
void getHashParameters( IN_ALGO const CRYPT_ALGO_TYPE hashAlgorithm,
						IN_LENGTH_HASH_Z const int hashParam,
						OUT_PTR_PTR HASH_FUNCTION *hashFunction, 
						OUT_OPT_LENGTH_SHORT_Z int *hashOutputSize,
						OUT_OPT_LENGTH_SHORT_Z int *hashBlockSize );
STDC_NONNULL_ARG( ( 3 ) ) \
void getHashAtomicParameters( IN_ALGO const CRYPT_ALGO_TYPE hashAlgorithm,
							  IN_LENGTH_HASH_Z const int hashParam,
							  OUT_PTR_PTR \
								HASH_FUNCTION_ATOMIC *hashFunctionAtomic, 
							  OUT_OPT_LENGTH_SHORT_Z int *hashOutputSize );

/* The HMAC functions are used constantly in TLS 1.3 so we have to provide
   an internal API for them as well.  Since they're only used for short data
   blocks we only provide an Atomic API for these.  This makes things a lot
   easier since all of the state is contained inside the internal function.
   
   The interface for this is slightly different to the hash one in that 
   there are no parameters passed in or out in the get-function, this is
   because it's only used with parameterised algorithms and in an atomic
   manner so the macParam is the same as the macOutputSize and is only 
   needed once when the MAC function is called */

typedef STDC_NONNULL_ARG( ( 1, 4, 6 ) ) \
		void ( *MAC_FUNCTION_ATOMIC )( OUT_BUFFER_C( outBufMaxLength, 20 ) \
											BYTE *outBuffer,
									   IN_LENGTH_SHORT_MIN( 20 ) \
											const int outBufMaxLength,
									   IN_LENGTH_HASH_Z const int macParam,
									   IN_BUFFER( keyLength ) const void *key,
									   IN_LENGTH_SHORT_MIN( 16 ) \
											const int keyLength,
									   IN_BUFFER( inLength ) \
											const void *inBuffer,
									   IN_LENGTH_SHORT const int inLength );

STDC_NONNULL_ARG( ( 2 ) ) \
void getMacAtomicFunction( IN_ALGO const CRYPT_ALGO_TYPE macAlgorithm,
						   OUT_PTR_PTR \
								MAC_FUNCTION_ATOMIC *macFunctionAtomic );

/* 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 );

/* Data compares that run in a time-independent manner.  This is used to 
   avoid potential timing attacks on memcmp(), which bails out as soon as
   it finds a mismatch */

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 );
CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
BOOLEAN checkZeroConstTime( IN_BUFFER( strLen ) const void *data,
							IN_LENGTH_SHORT const int length );

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

/* Signatures usually sign a hash of the data, with an optional second hash 
   for TLS 1.0 - 1.1 signatures, but some special-snowflake designs want to 
   sign the entire message so we need to also allow for that */

typedef struct {
	/* Message hash information.  The hash algorithm and parameter are filled
	   in by iCryptCreateSignature() if required */
	CRYPT_CONTEXT hashContext;		/* Hash context to sign */
	CRYPT_ALGO_TYPE hashAlgo;		/* Hash algorithm and parameters */
	int hashParam;
	CRYPT_CONTEXT hashContext2;		/* Secondary hash context (TLS 1.0-1.1) */
	
	/* Message data information */
	BUFFER_FIXED( length ) \
	const void *data;				/* Data to sign */
	int length;						/* Length of data */
	} SIG_DATA_INFO;

#define setSigDataInfoHash( sigDataInfo, hash ) \
	{ \
	memset( sigDataInfo, 0, sizeof( SIG_DATA_INFO ) ); \
	( sigDataInfo )->hashContext = hash; \
	( sigDataInfo )->hashContext2 = CRYPT_UNUSED; \
	}

#define setSigDataInfoMessage( sigDataInfo, messageData, messageLength ) \
	{ \
	memset( sigDataInfo, 0, sizeof( SIG_DATA_INFO ) ); \
	( sigDataInfo )->hashContext = \
		( sigDataInfo )->hashContext2 = CRYPT_UNUSED; \
	( sigDataInfo )->data = ( messageData ); \
	( sigDataInfo )->length = ( messageLength ); \
	}

/* 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;
	} SIG_PARAMS;

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

#define setSigParamsPGP( sigParams, pgpSigType, pgpAttrs, pgpAttrSize ) \
	{ \
	memset( ( sigParams ), 0, sizeof( SIG_PARAMS ) ); \
	( sigParams )->iAuthAttr = ( sigParams )->iTspSession = 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, 6, 8 ) ) \
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_PTR const SIG_DATA_INFO *sigDataInfo,
						   IN_PTR_OPT const SIG_PARAMS *sigParams,
						   INOUT_PTR ERROR_INFO *errorInfo );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 5, 7 ) ) \
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_PTR const SIG_DATA_INFO *sigDataInfo,
						  OUT_OPT_HANDLE_OPT CRYPT_HANDLE *extraData,
						  INOUT_PTR ERROR_INFO *errorInfo );
#ifdef USE_INT_CMS
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 7 ) ) \
int iCryptImportKey( IN_BUFFER( encryptedKeyLength ) \
						const void *encryptedKey, 
					 IN_LENGTH_SHORT_MIN( MIN_CRYPT_OBJECTSIZE ) \
						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,
					 INOUT_PTR ERROR_INFO *errorInfo );
CHECK_RETVAL STDC_NONNULL_ARG( ( 3, 7 ) ) \
int iCryptExportKey( OUT_BUFFER_OPT( encryptedKeyMaxLength, \
									 *encryptedKeyLength ) \
						void *encryptedKey, 
					 IN_LENGTH_SHORT_Z const int encryptedKeyMaxLength,
					 OUT_LENGTH_BOUNDED_SHORT_Z( encryptedKeyMaxLength ) \
						int *encryptedKeyLength,
					 IN_ENUM( CRYPT_FORMAT ) \
						const CRYPT_FORMAT_TYPE formatType,
					 IN_HANDLE_OPT const CRYPT_CONTEXT iSessionKeyContext,
					 IN_HANDLE const CRYPT_CONTEXT iExportKey,
					 INOUT_PTR ERROR_INFO *errorInfo );
#endif /* USE_INT_CMS */

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

#ifdef USE_ENVELOPES

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

typedef enum {
	ENVELOPE_OPTION_NONE,			/* No envelope option type */
	ENVELOPE_OPTION_EMPTYOK,		/* Message body isn't required */
	ENVELOPE_OPTION_LAST			/* Last valid envelope option type */
	} ENVELOPE_OPTION_TYPE;

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_PTR 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_PTR ERROR_INFO *errorInfo );
CHECK_RETVAL STDC_NONNULL_ARG( ( 3, 5, 9 ) ) \
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_PTR ERROR_INFO *errorInfo );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5, 8, 11 ) ) \
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,
					  IN_ENUM_OPT( ENVELOPE_OPTION ) \
							const ENVELOPE_OPTION_TYPE options,
					  OUT_STATUS int *sigResult, 
					  OUT_OPT_HANDLE_OPT CRYPT_CERTIFICATE *iSigningCert,
					  OUT_OPT_HANDLE_OPT CRYPT_CERTIFICATE *iCmsAttributes,
					  OUT_PTR 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.  Since the BIGNUM struct isn't visible at this 
   point, we have to use a forward declaration for it.
   
   For the bignum checks, the difference between BIGNUM_CHECK_VALUE and
   BIGNUM_CHECK_VALUE_PKC/ECC is that the latter check that the value is
   within range for PKC or ECC values, for example for a PKC that it's in 
   the range MIN_PKCSIZE ... CRYPT_MAX_PKCSIZE.  These checks only apply to 
   the nominal keysize-providing parameters of a PKC algorithm, for example
   for DH it applies to the p and y values but not the g and x values */

typedef enum {
	BIGNUM_CHECK_NONE,		/* Don't perform any checks */
	BIGNUM_CHECK_VALUE,		/* Check for valid bignum */
	BIGNUM_CHECK_VALUE_PKC,	/* Check for valid BN and correct-size PKC key */
	BIGNUM_CHECK_VALUE_ECC,	/* Check for valid BN and correct-size ECC key */
	BIGNUM_CHECK_VALUE_FIXEDLEN,/* Check for fixed-length-encoded value */
	BIGNUM_CHECK_LAST		/* Last valid check type */
	} BIGNUM_CHECK_TYPE;

struct BN;

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int importBignum( INOUT_PTR TYPECAST( BIGNUM * ) struct BN *bignumPtr, 
				  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_PTR_OPT TYPECAST( BIGNUM * ) \
					const struct BN *maxRangePtr,
				  IN_ENUM_OPT( BIGNUM_CHECK ) \
					const BIGNUM_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_PTR TYPECAST( BIGNUM * ) const struct BN *bignumPtr );
CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1, 2 ) ) \
BOOLEAN verifyBignumImport( TYPECAST( const BIGNUM * ) \
								const struct BN *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_PTR TYPECAST( BIGNUM * ) struct BN *bignumPtr1, 
					INOUT_PTR TYPECAST( BIGNUM * ) struct BN *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_PTR_OPT TYPECAST( const BIGNUM * ) \
						const struct BN *maxRangePtr,
					IN_ENUM( BIGNUM_CHECK ) \
						const BIGNUM_CHECK_TYPE checkType );
CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
BOOLEAN verifyECCPointImport( TYPECAST( const BIGNUM * ) \
									const struct BN *bignumPtr1,
							  TYPECAST( const BIGNUM * ) \
									const struct BN *bignumPtr2,	 
							  IN_BUFFER( length ) const void *buffer, 
							  IN_LENGTH_SHORT const int length,
							  IN_LENGTH_PKC const int fieldSize );
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_PTR TYPECAST( const BIGNUM * ) const struct BN *bignumPtr1, 
					IN_PTR TYPECAST( const BIGNUM * ) const struct BN *bignumPtr2,
					IN_LENGTH_PKC const int fieldSize );
#endif /* USE_ECDH || USE_ECDSA */
#if defined( USE_X25519 ) || defined( USE_ED25519 )
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
int import25519ByteString( INOUT_PTR TYPECAST( BIGNUM * ) 
								struct BN *bignumPtr, 
						   IN_BUFFER( length ) const void *buffer, 
						   IN_LENGTH_SHORT_MIN( MIN_PKCSIZE_BERNSTEIN ) \
								const int length );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
int export25519ByteString( OUT_BUFFER( dataMaxLength, *dataLength ) 
								void *data, 
						   IN_LENGTH_SHORT_MIN( MIN_PKCSIZE_BERNSTEIN ) \
								const int dataMaxLength, 
						   OUT_LENGTH_BOUNDED_Z( dataMaxLength ) 
								int *dataLength,
						   IN_PTR TYPECAST( BIGNUM * ) 
								const struct BN *bignumPtr );
#endif /* USE_X25519 || USE_ED25519 */

/****************************************************************************
*																			*
*					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 explicit */
	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, 10 ) ) \
int createX509signature( OUT_BUFFER( signedObjectMaxLength, \
									 *signedObjectLength ) \
							void *signedObject, 
						 IN_DATALENGTH const int signedObjectMaxLength, 
						 OUT_LENGTH_BOUNDED_Z( signedObjectMaxLength ) \
							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_LENGTH_HASH const int hashParam,
						 IN_PTR_OPT const X509SIG_FORMATINFO *formatInfo,
						 INOUT_PTR ERROR_INFO *errorInfo );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 5 ) ) \
int checkX509signature( IN_BUFFER( signedObjectLength ) const void *signedObject, 
						IN_DATALENGTH const int signedObjectLength,
						IN_HANDLE const CRYPT_CONTEXT iSigCheckContext,
						IN_PTR_OPT const X509SIG_FORMATINFO *formatInfo,
						INOUT_PTR ERROR_INFO *errorInfo );

/* Create and verify a raw signature */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 6 ) ) \
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,
						INOUT_PTR ERROR_INFO *errorInfo );
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 5 ) ) \
int checkRawSignature( IN_BUFFER( signatureLength ) const void *signature, 
					   IN_LENGTH_SHORT_MIN( 40 ) const int signatureLength,
					   IN_HANDLE const CRYPT_CONTEXT iSigCheckContext,
					   IN_HANDLE const CRYPT_CONTEXT iHashContext,
					   INOUT_PTR ERROR_INFO *errorInfo );

/****************************************************************************
*																			*
*							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_OPT( component2Length ) const void *component2, 
						IN_LENGTH_PKC_Z 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_PTR 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 */

/* Prototypes for functions in cryptkey.c, used by hardware devices without
   native object storage */

#if defined( USE_HARDWARE ) || defined( USE_TPM )
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int createKeysetIndirect( INOUT_PTR MESSAGE_CREATEOBJECT_INFO *createInfo,
						  STDC_UNUSED const void *auxDataPtr, 
						  STDC_UNUSED const int auxValue );
#endif /* USE_HARDWARE || USE_TPM */

/* Prototypes for self-test functions in int_api.c */

CHECK_RETVAL_BOOL \
BOOLEAN testIntAPI( void );
CHECK_RETVAL_BOOL \
BOOLEAN testIntString( void );
CHECK_RETVAL_BOOL \
BOOLEAN testIntTime( void );
CHECK_RETVAL_BOOL \
BOOLEAN testIntBN( void );

#endif /* _INTAPI_DEFINED */
