/* $Id: diFirmaSat2.h $ */

/* Copyright (C) 2006-12 DI Management Services Pty Limited. 
   All rights reserved. <www.di-mgt.com.au> <www.cryptosys.net>

   Last updated:
   $Date: 2012-02-23 07:33 $
   $Revision: 5.1.0 $
*/

/* [v5.1] updated this source file with markup for Doxygen documentation <http://www.doxygen.org/> */
/** 
  @file
  @brief The C/C++ interface to the \b diFirmaSat2.dll library.
  @par Note re output to szOut buffer
Functions that provide output in `szOut` require the buffer to be pre-dimensioned 
(i.e. allocated) to at least the specified length \c nOutChars
PLUS one extra for the null-terminating byte.
These functions always return the total length in bytes of the string they tried to create.
To find the required length, pass a NULL `szOut` or zero `nOutChars` argument,
then add one to the result for the required buffer size.
For example:
@code
char *xmlfile = "test.xml";
long nchars;
char *lpszOut;
// Find out how many bytes we need
nchars = SAT_MakePipeStringFromXml(NULL, 0, xmlfile, 0);
if (nchars <= 0) error();
// Pre-dimension, i.e allocate memory for string buffer
lpszOut = malloc(nchars+1);  // NB +1
if (!lpszOut) error();
nchars = SAT_MakePipeStringFromXml(lpszOut, nchars, xmlfile, 0);
// ...
// do something with lpszOut...
// ...
free(lpszOut);
@endcode
*/

#ifndef DIFIRMASAT2_H_
#define DIFIRMASAT2_H_ 1

/* __stdcall convention required for Win32 DLL only */
#if defined(unix) || defined (linux) || defined(__linux)
#define _stdcall
#endif  

/* OPTION FLAGS */
/** Use default hash algorithm (SHA-1) */
#define SAT_HASH_DEFAULT   0        /* Default is SHA-1 */
/** Use MD5 hash algorithm (not relevant after 2010-12-31) */
#define SAT_HASH_MD5       0x10
/** Force the SHA-1 hash algorithm [\e deprecated - use 0 instead] */
#define SAT_HASH_SHA1      0x20
/** Return start date instead of expiry when using SAT_GetCertExpiry() 
[\e deprecated - use SAT_QueryCert() with \c notBefore instead]  */
#define SAT_DATE_NOTBEFORE 0x1000
/** Operate on Timbre Fiscal Digital (TFD) instead of Combrobante */
#define SAT_TFD            0x8000   /* New in [v4.0] */
/** Use strict XML type checking with SAT_ValidateXml() (default in v5.0 and above)  */
#define SAT_XML_STRICT     0
/** Use loose XML type checking with SAT_ValidateXml() (like default before v5.0) */
#define SAT_XML_LOOSE      0x4000
/** Encode output in UTF-8 (default) */
#define SAT_ENCODE_UTF8    0
/** Encode output in Latin-1 (ISO-8859-1) */
#define SAT_ENCODE_LATIN1  1
/** Flag to retrieve platform type with SAT_ModuleName() */
#define SAT_GEN_PLATFORM   0x40
/* CONSTANTS */
/** Maximum number of characters in hex-encoded hash digest value */
#define SAT_MAX_HASH_CHARS 40

#ifdef __cplusplus
extern "C" {
#endif

/* GENERAL DIAGNOSTIC FUNCTIONS */

/** Gets version number of the core DLL 
  @return Version number as an integer in the form \c major*100+minor*10+revision 
  e.g. DLL file version 3.2.x.1 will return 321 */
long _stdcall SAT_Version(void);

/** Gets date and time the core DLL module was last compiled 
  @param [out] szOut Buffer to receive output string
  @param [in] nOutChars Maximum length of output string in bytes
  @return Number of characters in or required for output string;
  or a @link SAT_ErrorLookup() negative error code @endlink. */ 
long _stdcall SAT_CompileTime(char *szOut, long nOutChars);

/** Gets full path name of core DLL module 
  @param [out] szOut Buffer to receive output string
  @param [in] nOutChars Maximum length of output string in bytes
  @param [in] nOptions \c SAT_GEN_PLATFORM to retrieve platform type ("Win32" or "Win64") instead
  @return Number of characters in or required for output string; 
  or a @link SAT_ErrorLookup() negative error code @endlink */
long _stdcall SAT_ModuleName(char *szOut, long nOutChars, long nOptions);

/** Gets the licence type. 
  @return The ASCII value of the licence type, either 'D' (68, 0x44) for the Developer Edition 
  or 'T' (84, 0x54) for the Trial Edition. */
long _stdcall SAT_LicenceType(void);


/* ERROR-RELATED FUNCTIONS */

/** Retrieves the last error message (if available).
  @param [out] szOut Buffer to receive output string
  @param [in] nOutChars Maximum length of output string in bytes
  @return Number of characters in or required for output string; 
  or a @link SAT_ErrorLookup() negative error code @endlink.
  @remark Call this function to find out more information about the last error.
  Not all functions set this.
*/
long _stdcall SAT_LastError(char *szOut, long nOutChars);


/** Looks up error code.
  @param [out] szOut Buffer to receive output string
  @param [in] nOutChars Maximum length of output string in bytes
  @param [in] nErrCode Value of error code to lookup (positive or negative)
  @return Number of characters in or required for output string; 
  or a @link SAT_ErrorLookup() negative error code @endlink. */
long _stdcall SAT_ErrorLookup(char *szOut, long nOutChars, long nErrCode);


/** @cond */
/******************************************************************************/
/* NOTE: As of [v4.0] these queries of the CryptoSys PKI DLL are redundant
/* -- because the CryptoSys PKI Toolkit (diCrPKI.dll) is no longer required.
/******************************************************************************/
/** Returns version number of CryptoSys PKI DLL as called by diFirmaSAT2.dll  */
long _stdcall SAT_PKIVersion(void);
/** Gets date and time the CryptoSys PKI DLL module was last compiled */
long _stdcall SAT_PKICompileTime(char *szOut, long nOutChars);
/** Gets full path name of CryptoSys PKI DLL module */
long _stdcall SAT_PKIModuleName(char *szOut, long nOutChars, long reserved);
/******************************************************************************/
/** @endcond */

/* SAT XML FUNCTIONS */

/** Creates the "pipe" string (cadena original) from an XML file.
  @param [out] szOut Buffer to receive output string
  @param [in] nOutChars Maximum length of output string in bytes
  @param [in] szXmlFile Name of XML file to be processed
  @param [in] nOptions Use \c SAT_ENCODE_LATIN1 to encode in Latin1.
  The default (0) is \c SAT_ENCODE_UTF8 for UTF-8.
  @return Number of characters in or required for output string; 
  or a @link SAT_ErrorLookup() negative error code @endlink.
  @remark Final string length may be shorter after extra spaces are removed.
  @see Note re output to szOut buffer. 
  */
long _stdcall SAT_MakePipeStringFromXml(char *szOut, long nOutChars, const char *szXmlFile, long nOptions);


/** Creates the signature as a base64 string ready for insertion as `sello` node
  @param[out] szOut Buffer to receive output string
  @param [in] nOutChars Maximum length of output string in bytes
  @param [in] szXmlFile Name of XML file to be processed
  @param [in] szKeyFile Encrypted key file
  @param [in] szPassword Password for encrypted key file
  @return Number of characters in or required for output string; 
  or a @link SAT_ErrorLookup() negative error code @endlink.
  @remark This will use the default hash algorithm (SHA-1). 
  For advanced options use SAT_MakeSignatureFromXmlEx().
  */
long _stdcall SAT_MakeSignatureFromXml(char *szOut, long nOutChars, const char *szXmlFile,
  const char *szKeyFile, const char *szPassword);


/** Creates the signature as a base64 string ready for insertion as `sello` node
  @param[out] szOut Buffer to receive output string
  @param [in] nOutChars Maximum length of output string in bytes
  @param [in] szXmlFile Name of XML file to be processed
  @param [in] szKeyFile Encrypted key file
  @param [in] szPassword Password for encrypted key file
  @param [in] nOptions \c SAT_HASH_SHA1 | \c SAT_HASH_MD5 to select hash algorithm. The default (0) is SHA-1.
         Add \c SAT_TFD to make `selloSAT` for Timbre Fiscal Digital instead.
  @return Number of characters in or required for output string; 
  or a @link SAT_ErrorLookup() negative error code @endlink. 
  */
long _stdcall SAT_MakeSignatureFromXmlEx(char *szOut, long nOutChars, const char *szXmlFile,
  const char *szKeyFile, const char *szPassword, long nOptions);


/** Validates an XML file against SAT specification.
  @param [in] szXmlFile Name of XML file to be processed
  @param [in] nOptions \c SAT_XML_LOOSE to stop strict checks on XML restrictions [new in v5.0].
  Default (0) is \c SAT_XML_STRICT.
  @return Zero (0) on success or a @link SAT_ErrorLookup() negative error code @endlink. 
  @remark This only does a check that the XML elements are well-formed and in the correct order.
  It does not check the signature and may not catch all XML facet restriction errors that a strict XML parser may find.
  This function is meant as a quick check for structural problems in the XML file, not as a replacement
  for a full XSD checker.
*/
long _stdcall SAT_ValidateXml(const char *szXmlFile, long nOptions);


/** Verifies the signature (`sello`) in an XML file.
  @param [in] szXmlFile Name of XML file to be processed.
  @param [in] szCertFile (optional) certificate file
  @param [in] nOptions \c SAT_TFD to verify `selloSAT` in Timbre Fiscal Digital instead [new in v4.0].
  @return Zero (0) on success or a @link SAT_ErrorLookup() negative error code @endlink. 
  @remark If no certificate file is specified, then the `certificado` node in the XML file will be used.
         If a separate certificate file is specified, it will be used instead.
    @note A separate certificate file is always required for the \c SAT_TFD option.
*/
long _stdcall SAT_VerifySignature(const char *szXmlFile, const char *szCertFile, long nOptions);


/** Signs an XML file.
  @param [in] szOutputFile Name of new output file to be created with 
    `sello`, `certificado` and `noCertificado` nodes completed.
  @param [in] szXmlFile Name of input XML file to be processed 
    with empty `sello` and (optionally) `certificado` and `noCertificado` nodes.
  @param [in] szKeyFile Encrypted private key file
  @param [in] szPassword Password for encrypted key file
  @param [in] szCertFile (optional) X.509 certificate file
  @param [in] nOptions \c SAT_HASH_SHA1 | \c SAT_HASH_MD5 to select hash algorithm. The default (0) is SHA-1.
  @return Zero (0) on success or a @link SAT_ErrorLookup() negative error code @endlink.
  @remark This will complete an empty `Comprobante/\@sello` node found in the input file (i.e. \c sello="" )
  and write the result to the output file. 
  Any existing file called `szOutputFile` will be over-written without warning.
  The input and output files can be the same. 
  If a certificate file is specified and empty `certificado` and `noCertificado` 
  nodes exist in the input file, then these nodes will also be completed in the output file.
@code
<Comprobante ...
noCertificado=""
certificado=""
sello=""
...>
@endcode
  @note It is an error if the private key and certificate do not match.
*/
long _stdcall SAT_SignXml(const char *szOutputFile, const char *szXmlFile,
  const char *szKeyFile, const char *szPassword, const char *szCertFile, long nOptions);


/** Forms the hex-encoded hash digest of piped string (cadena original) from an XML file.
  @param[out] szOut Buffer to receive output string
  @param [in] nOutChars Maximum length of output string in bytes (expect 40 by default)
  @param [in] szXmlFile Name of XML file to be processed
  @param [in] nOptions \c SAT_HASH_SHA1 | \c SAT_HASH_MD5 to select hash algorithm. The default (0) is SHA-1.
    Add \c SAT_TFD to make digest of the cadena original del Timbre Fiscal Digital instead.
  @return Number of characters in or required for output string; 
  or a @link SAT_ErrorLookup() negative error code @endlink. 
  */
long _stdcall SAT_MakeDigestFromXml(char *szOut, long nOutChars, const char *szXmlFile, long nOptions);


/** Extracts the hex-encoded message digest from the signature (sello) in an XML file.
  @param[out] szOut Buffer to receive output string
  @param [in] nOutChars Maximum length of output string in bytes (expect 40 by default)
  @param [in] szXmlFile Name of XML file to be processed
  @param [in] szCertFile (optional) certificate file
  @param [in] nOptions \c SAT_TFD to extract digest instead from `selloSAT` of Timbre Fiscal Digital.
  @return Number of characters in or required for output string; 
  or a @link SAT_ErrorLookup() negative error code @endlink.
  @remark If the XML file contains a `certificado` node, then that certificate will be used for the public key;
    otherwise the user must specify a separate certificate file.
  @note A separate certificate file \e must be specified to use the \c SAT_TFD option.
*/
long _stdcall SAT_ExtractDigestFromSignature(char *szOut, long nOutChars, const char *szXmlFile, 
  const char *szCertFile, long nOptions);


/** Gets the serial number of the X.509 certificate in special SAT format (20 ASCII digits) [\e deprecated].
  @param[out] szOut Buffer to receive output string
  @param [in] nOutChars Maximum length of output string in bytes (expect 20 characters)
  @param [in] szFileName X.509 certificate file or XML file with a `certificado` node
  @param [in] nOptions None. Use 0.
  @return Number of characters in or required for output string; 
  or a @link SAT_ErrorLookup() negative error code @endlink.
  @remark This only works with a certificate issed by SAT with their special serial number format.
         If input is an XML file, this extracts the number indirectly from the `certificado` node,
         not the `noCertificado` node.
  @see Use instead @link SAT_QueryCert() @endlink with query \c serialNumber.
*/
long _stdcall SAT_GetCertNumber(char *szOut, long nOutChars, const char *szFileName, long nOptions);


/** Gets the expiry date of the X.509 certificate in ISO time format 'yyyy-mm-ddThh:nn:ssZ' [\e deprecated].
  @param[out] szOut Buffer to receive output string
  @param [in] nOutChars Maximum length of output string in bytes (expect 20 characters)
  @param [in] szFileName X.509 certificate file or XML file with a `certificado` node
  @param [in] nOptions Use \c SAT_DATE_NOTBEFORE to get start date instead of expiry date; otherwise use 0.
  @return Number of characters in or required for output string; 
  or a @link SAT_ErrorLookup() negative error code @endlink.
  @remark The time is GMT (UTC, Zulu time), not local.
  @see Use instead @link SAT_QueryCert() @endlink with query \c notAfter or \c notBefore.
*/
long _stdcall SAT_GetCertExpiry(char *szOut, long nOutChars, const char *szFileName, long nOptions);


/** Gets the certificate data as a base64 string.
  @param[out] szOut Buffer to receive output string
  @param [in] nOutChars Maximum length of output string in bytes.
  @param [in] szFileName X.509 certificate file or XML file with a `certificado` node
  @param [in] nOptions None. Use 0.
  @return Number of characters in or required for output string; 
  or a @link SAT_ErrorLookup() negative error code @endlink.
  @remark Use to obtain the base64 value for the `certificado` node from a .CER file.
  It is an error if szOut is too small.
    If the input is an XML file, this function is equivalent to 
  @code SAT_GetXmlAttribute(szFileName, "certificado", "Comprobante"); @endcode         
*/
long _stdcall SAT_GetCertAsString(char *szOut, long nOutChars, const char *szFileName, long nOptions);

/** Extracts attribute data for a given element in an XML file
  @param[out] szOut Buffer to receive output string
  @param [in] nOutChars Maximum length of output string in bytes
  @param [in] szXmlFile Name of XML file to be processed
  @param [in] szAttribute Name of attribute to find
  @param [in] szElement Name of element to find
  @return Number of characters in or required for output string; 
  or a @link SAT_ErrorLookup() negative error code @endlink. 
  @remark Attribute and element names are case-sensitive. 
  The default behaviour is to get the attribute from the \e first element found with the given name.
  Specify the element name in the form \c "element[N]"
  to extract the attribute for the N'th element found in the XML document, where \c N=1,2,3,...
  For example:
@code
char buf[256];
char *fname = "ejemplo1cfdv3.xml";
nchars = SAT_GetXmlAttribute(buf, sizeof(buf)-1, fname, "descripcion", "Concepto[1]");
nchars = SAT_GetXmlAttribute(buf, sizeof(buf)-1, fname, "descripcion", "Concepto[2]");
nchars = SAT_GetXmlAttribute(buf, sizeof(buf)-1, fname, "descripcion", "Concepto[3]");
@endcode
  will get the attribute `descripcion` from the 1st, 2nd and 3rd elements named
  `Concepto` found in the file \c fname. The XML fragment
@code
<cfdi:Conceptos>
  <cfdi:Concepto unidad="CAPSULAS" importe="244.00" cantidad="1.0" descripcion="VIBRAMICINA 100MG 10" valorUnitario="244.00"/>
  <cfdi:Concepto unidad="BOTELLA" importe="137.93" cantidad="1.0" descripcion="CLORUTO 500M" valorUnitario="137.93"/>
  <cfdi:Concepto unidad="TABLETAS" importe="84.50" cantidad="1.0" descripcion="SEDEPRON 250MG 10" valorUnitario="84.50"/>
</cfdi:Conceptos>
@endcode
will yield the result
<pre>
VIBRAMICINA 100MG 10
CLORUTO 500M
SEDEPRON 250MG 10
</pre>
@note It is an error if the element or attribute is not present.
For example, attempting to use "Concepto[4]" in the above example will return error code -21 (\c NO_MATCH_ERROR).
*/
long _stdcall SAT_GetXmlAttribute(char *szOut, long nOutChars, const char *szXmlFile,
  const char *szAttribute, const char *szElement);

/** Verifies that the public key in an X.509 certificate matches the private key.
  @param [in] szKeyFile PKCS#8 encrypted key file
  @param [in] szPassword Password for encrypted key file
  @param [in] szCertFile X.509 certificate file or XML file with a `certificado` node
  @param [in] nOptions None. Use 0.
  @return Zero (0) if keys match or a @link SAT_ErrorLookup() negative error code @endlink.
  @remark This will also verify that the password is correct for the key file.
*/
long _stdcall SAT_CheckKeyAndCert(const char *szKeyFile, const char *szPassword, const char *szCertFile, long nOptions);


/** Finds version number of `Comprobante` element in a XML file.
  @param [in] szXmlFile Name of XML file to be processed
  @param [in] nOptions None. Use 0.
  @return A positive integer: 2 if version="2.0", 3 if version="3.0", 22 if version="2.2", 32 if version="3.2"; 
  or a @link SAT_ErrorLookup() negative error code @endlink.
*/
long _stdcall SAT_XmlReceiptVersion(const char *szXmlFile, long nOptions);


/* [v4.0.1] ADDED TO FIX JULY 2011 SAT PROBLEM */

/** Adds a UTF-8 byte order mark (BOM) to a file if not already present.
  @param [in] szOutputFile Name of output file to be created.
  @param [in] szInputFile Name of input file to be processed.
  @param [in] nOptions None. Use 0.
  @return Zero (0) if output file with BOM successfully created, 
  or a @link SAT_ErrorLookup() negative error code @endlink.
  @remark This works with \e any UTF-8 input file. It is an error if the input file contains invalid UTF-8 characters.
*/
long _stdcall SAT_FixBOM(const char *szOutputFile, const char *szInputFile, long nOptions);


/* [v5.0] ADDED NEW FUNCTION */

/** Gets the private key as a base64 string to use in XML de Cancelación.
  @param[out] szOut Buffer to receive output string
  @param [in] nOutChars Maximum length of output string in bytes
  @param [in] szKeyFile Encrypted key file
  @param [in] szPassword Password for encrypted key file
  @param [in] nOptions None. Use 0.
  @return Number of characters in or required for output string; 
  or a @link SAT_ErrorLookup() negative error code @endlink. 
  @remark This creates a private key in base64 form suitable for a `llaveCertificado` node 
  in a `Cancelacion` element.
  @warning This outputs your private key in \e unencrypted form. Using it is a huge security risk. Use with caution.
*/
long _stdcall SAT_GetKeyAsString(char *szOut, long nOutChars, const char *szKeyFile, const char *szPassword, long nOptions);

/* [v5.1] NEW FUNCTIONS */

/** Creates a PFX (PKCS-12) file in PEM format suitable for a Cancelación.
  @param [in] szOutputFile Name of output PFX file to be created.
  @param [in] szPfxPassword Password to open new PFX file
  @param [in] szKeyFile Name of encrypted key file
  @param [in] szKeyPassword Password for encrypted key file
  @param [in] szCertFile Name of X.509 certificate file
  @param [in] nOptions None. Use 0.
  @return Zero (0) if output file is successfully created, 
  or a @link SAT_ErrorLookup() negative error code @endlink.
  @warning Giving the PFX password to a third party is a security risk. Use with caution.
*/
long _stdcall SAT_WritePfxFile(const char *szOutputFile, const char *szPfxPassword, const char *szKeyFile, const char *szKeyPassword, const char *szCertFile, long nOptions);

/** Queries an X.509 certificate.
  @param[out] szOut Buffer to receive output string
  @param [in] nOutChars Maximum length of output string in bytes
  @param [in] szFileName X.509 certificate file or XML file with a `certificado` node
  @param [in] szQuery Query string. Select one from 
  { \b rfc | \b organizationName | \b notAfter | \b notBefore | \b serialNumber }.
  @param [in] nOptions None. Use 0
  @return Number of characters in or required for output string; 
  or a @link SAT_ErrorLookup() negative error code @endlink.
  @remark New in v5.1. Valid queries are:
  - \b rfc to get the subject's RFC (expect 12 or 13 characters)
  - \b organizationName to get the issuer's organization name 
  (expect "Servicio de Administración Tributaria", always in Latin-1 encoding)
  - \b notAfter to get the expiry date [a replacement for SAT_GetCertExpiry()]
  - \b notBefore to get the start date [a replacement for SAT_GetCertExpiry() with \c SAT_DATE_NOTBEFORE option]
  - \b serialNumber to get the 20-digit SAT-specific serial number [a replacement for SAT_GetCertNumber()]
  .
  @note Times are GMT (UTC, Zulu time), not local, and are in the ISO time format 'yyyy-mm-ddThh:nn:ssZ'. 
*/
long _stdcall SAT_QueryCert(char *szOut, long nOutChars, const char *szFileName, const char *szQuery, long nOptions);

#ifdef __cplusplus
}
#endif

#endif /* DIFIRMASAT2_H_ */