summaryrefslogtreecommitdiff
path: root/libdigidoc/DigiDocEncSAXParser.c
diff options
context:
space:
mode:
Diffstat (limited to 'libdigidoc/DigiDocEncSAXParser.c')
-rw-r--r--libdigidoc/DigiDocEncSAXParser.c1155
1 files changed, 1155 insertions, 0 deletions
diff --git a/libdigidoc/DigiDocEncSAXParser.c b/libdigidoc/DigiDocEncSAXParser.c
new file mode 100644
index 0000000..bfd347b
--- /dev/null
+++ b/libdigidoc/DigiDocEncSAXParser.c
@@ -0,0 +1,1155 @@
+//==================================================
+// FILE: DigiDocEncSAXParser.c
+// PROJECT: Digi Doc Encryption
+// DESCRIPTION: DigiDocEnc XML SAX parsing
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 11.10.2004 Veiko Sinivee
+// Creation
+//==================================================
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <libdigidoc/DigiDocDefs.h>
+#include <libdigidoc/DigiDocEncSAXParser.h>
+#include <libdigidoc/DigiDocError.h>
+#include <libdigidoc/DigiDocDebug.h>
+#include <libdigidoc/DigiDocStack.h>
+#include <libdigidoc/DigiDocConvert.h>
+#include <libdigidoc/DigiDocLib.h>
+#include <libdigidoc/DigiDocPKCS11.h>
+#include <libdigidoc/DigiDocCert.h>
+#include <libdigidoc/DigiDocDfExtract.h>
+
+#include <openssl/sha.h>
+#include <openssl/rsa.h>
+#include <openssl/evp.h>
+#include <zlib.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <string.h>
+
+
+#include <libxml/globals.h>
+#include <libxml/xmlerror.h>
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h> /* only for xmlNewInputFromFile() */
+
+//===============< SAX handlers >==============================
+
+/*
+* Working area for XML parsing with SAX
+*/
+typedef struct DEncParse_st {
+ DEncEncryptedData* pEncData; // document file to be filled with data
+ int errcode;
+ ElementEntry dencStack; // stack used for keeping the current parsing position
+ DigiDocMemBuf mbufContent; // used for collecting element content
+ int bCollectMode; // flag to switch collection of content on and off
+ char errmsg[100];
+} DEncParse;
+
+
+//--------------------------------------------------
+// Cleans up the memory that might habe been allocated
+// during parsing process
+// pctx - SAX parser context
+//--------------------------------------------------
+void dencSaxCleanup(DEncParse* pctx)
+{
+ ddocMemBuf_free(&(pctx->mbufContent));
+ memset(pctx, 0, sizeof(DEncParse));
+}
+
+//--------------------------------------------------
+// Handles the <EncryptedData> start event
+// pctx - SAX parser context
+// atts - array of atribute names and values
+// returns error code or ERR_OK.
+//--------------------------------------------------
+
+int dencSaxHandleStartEncryptedData(DEncParse* pctx, const xmlChar** atts)
+{
+ int i, err = ERR_OK;
+ char *id = NULL, *type = NULL, *mime = NULL, *xmlns = NULL;
+
+ // check the atributes
+ for(i = 0; atts && atts[i] && atts[i+1]; i++) {
+ if(!strcmp((char*)atts[i], "Id"))
+ id = (char*)atts[i+1];
+ if(!strcmp((char*)atts[i], "Type"))
+ type = (char*)atts[i+1];
+ if(!strcmp((char*)atts[i], "MimeType"))
+ mime = (char*)atts[i+1];
+ if(!strncmp((char*)atts[i], "xmlns", 5))
+ xmlns = (char*)atts[i+1];
+ }
+ // create new EncryptedData object
+ err = dencEncryptedData_new(&(pctx->pEncData), xmlns, NULL, id, type, mime);
+ // delete automatically generated meta info to read the stuff from file
+ err = dencMetaInfo_deleteVersionInfo(pctx->pEncData);
+ return err;
+}
+
+//--------------------------------------------------
+// Handles the <EncryptionMethod> start event
+// pctx - SAX parser context
+// atts - array of atribute names and values
+// returns error code or ERR_OK.
+//--------------------------------------------------
+int dencSaxHandleStartEncryptionMethod(DEncParse* pctx, const xmlChar** atts)
+{
+ int i, err = ERR_OK;
+ char *alg = NULL;
+
+ // check the atributes
+ for(i = 0; atts && atts[i] && atts[i+1]; i++) {
+ if(!strcmp((char*)atts[i], "Algorithm"))
+ alg = (char*)atts[i+1];
+ }
+ // check the EncryptionMethod position in xml doc
+ if(ddocStackHasParentWithName(&(pctx->dencStack), (xmlChar*)"EncryptedKey", NULL)) {
+ DEncEncryptedKey* pEncKey = dencEncryptedData_GetLastEncryptedKey(pctx->pEncData);
+ if(pEncKey)
+ err = dencEncryptedKey_SetEncryptionMethod(pEncKey, alg);
+ } else
+ if(ddocStackHasParentWithName(&(pctx->dencStack), (xmlChar*)"EncryptedData", NULL))
+ err = dencEncryptedData_SetEncryptionMethod(pctx->pEncData, alg);
+ return err;
+}
+
+//--------------------------------------------------
+// Handles the <EncryptedKey> start event
+// pctx - SAX parser context
+// atts - array of atribute names and values
+// returns error code or ERR_OK.
+//--------------------------------------------------
+int dencSaxHandleStartEncryptedKey(DEncParse* pctx, const xmlChar** atts)
+{
+ int i;
+ char *id = NULL, *recipient = NULL;
+ DEncEncryptedKey* pEncKey = 0;
+
+ // check the atributes
+ for(i = 0; atts && atts[i] && atts[i+1]; i++) {
+ if(!strcmp((char*)atts[i], "Id"))
+ id = (char*)atts[i+1];
+ if(!strcmp((char*)atts[i], "Recipient"))
+ recipient = (char*)atts[i+1];
+ }
+ // create new EncryptedData object
+ return dencEncryptedKey_new(pctx->pEncData, &pEncKey, NULL, NULL,
+ id, recipient, NULL, NULL);
+}
+
+//--------------------------------------------------
+// Handles the <X509Certificate> end event
+// pctx - SAX parser context
+// atts - array of atribute names and values
+// returns error code or ERR_OK.
+//--------------------------------------------------
+int dencSaxHandleEndX509Certificate(DEncParse* pctx)
+{
+ int err = ERR_OK;
+ X509 *pCert = 0;
+ DEncEncryptedKey* pEncKey = 0;
+
+ err = ddocDecodeX509PEMData(&pCert, (const char*)pctx->mbufContent.pMem, (int)pctx->mbufContent.nLen);
+ if(err) return err;
+ pEncKey = dencEncryptedData_GetLastEncryptedKey(pctx->pEncData);
+ if(pEncKey)
+ err = dencEncryptedKey_SetCertificate(pEncKey, pCert);
+ ddocDebug(4, "dencSaxHandleEndX509Certificate", "EncKey: %s, cert: %s rc: %d",
+ (pEncKey ? "OK" : "NULL"), (pCert ? "OK" : "NULL"), err);
+ // reset collect mode and cleanup
+ pctx->bCollectMode = 0;
+ ddocMemBuf_free(&(pctx->mbufContent));
+ return err;
+}
+
+//--------------------------------------------------
+// Handles the <KeyName> end event
+// pctx - SAX parser context
+// atts - array of atribute names and values
+// returns error code or ERR_OK.
+//--------------------------------------------------
+int dencSaxHandleEndKeyName(DEncParse* pctx)
+{
+ int err = ERR_OK;
+
+ DEncEncryptedKey* pEncKey = dencEncryptedData_GetLastEncryptedKey(pctx->pEncData);
+ if(pEncKey)
+ err = dencEncryptedKey_SetKeyName(pEncKey, (char*)pctx->mbufContent.pMem);
+ ddocDebug(4, "dencSaxHandleEndKeyName", "EncKey: %s, KeyName: %s rc: %d",
+ (pEncKey ? "OK" : "NULL"), (pctx->mbufContent.pMem ? pctx->mbufContent.pMem : "NULL"), err);
+ // reset collect mode and cleanup
+ pctx->bCollectMode = 0;
+ ddocMemBuf_free(&(pctx->mbufContent));
+ return err;
+}
+
+//--------------------------------------------------
+// Handles the <CarriedKeyName> end event
+// pctx - SAX parser context
+// atts - array of atribute names and values
+// returns error code or ERR_OK.
+//--------------------------------------------------
+int dencSaxHandleEndCarriedKeyName(DEncParse* pctx)
+{
+ int err = ERR_OK;
+
+ DEncEncryptedKey* pEncKey = dencEncryptedData_GetLastEncryptedKey(pctx->pEncData);
+ if(pEncKey)
+ err = dencEncryptedKey_SetCarriedKeyName(pEncKey, (char*)pctx->mbufContent.pMem);
+ ddocDebug(4, "dencSaxHandleEndKeyName", "EncKey: %s, CarriedKeyName: %s rc: %d",
+ (pEncKey ? "OK" : "NULL"), (pctx->mbufContent.pMem ? pctx->mbufContent.pMem : "NULL"), err);
+ // reset collect mode and cleanup
+ pctx->bCollectMode = 0;
+ ddocMemBuf_free(&(pctx->mbufContent));
+ return err;
+}
+
+//--------------------------------------------------
+// Handles the <CipherValue> end event
+// pctx - SAX parser context
+// atts - array of atribute names and values
+// returns error code or ERR_OK.
+//--------------------------------------------------
+int dencSaxHandleEndCipherValue(DEncParse* pctx)
+{
+ int err = ERR_OK, l = 0, i;
+ char *p = 0;
+ EVP_ENCODE_CTX ectx;
+
+ if(pctx->mbufContent.pMem && pctx->mbufContent.nLen) {
+ l = pctx->mbufContent.nLen; // enough since it's shrinking
+ p = (char*)malloc(l);
+ RETURN_IF_BAD_ALLOC(p)
+ //decode((const byte*)pctx->mbufContent.pMem, pctx->mbufContent.nLen, p, &l);
+ EVP_DecodeInit(&ectx);
+ EVP_DecodeUpdate(&ectx, (unsigned char*)p, &l, (unsigned char*)pctx->mbufContent.pMem, pctx->mbufContent.nLen);
+ ddocDebug(3, "dencSaxHandleEndCipherValue", "Initial decoding: %d -> %d bytes", pctx->mbufContent.nLen, l);
+ i = pctx->mbufContent.nLen - l;
+ EVP_DecodeFinal(&ectx, (unsigned char*)p+l, &i);
+ l += i;
+ ddocDebug(3, "dencSaxHandleEndCipherValue", "Final decoding: %d bytes", i);
+ ddocDebug(3, "dencSaxHandleEndCipherValue", "Decoding: %d bytes of base64 data, got: %d bytes", pctx->mbufContent.nLen, l);
+ ddocMemBuf_free(&(pctx->mbufContent));
+ }
+ if(p) {
+ // check the EncryptionMethod position in xml doc
+ if(ddocStackHasParentWithName(&(pctx->dencStack), (xmlChar*)"EncryptedKey", NULL)) {
+ DEncEncryptedKey* pEncKey = dencEncryptedData_GetLastEncryptedKey(pctx->pEncData);
+ if(pEncKey) {
+ pEncKey->mbufTransportKey.pMem = p;
+ pEncKey->mbufTransportKey.nLen = l;
+ ddocDebug(4, "dencSaxHandleEndCipherValue", "Set encrypted tarnsport key: %d bytes", l);
+ } else
+ free(p);
+ } else {
+ if(ddocStackHasParentWithName(&(pctx->dencStack), (xmlChar*)"EncryptedData", NULL)) {
+ pctx->pEncData->mbufEncryptedData.pMem = p;
+ pctx->pEncData->mbufEncryptedData.nLen = l;
+ ddocDebug(4, "dencSaxHandleEndCipherValue", "Set encrypted data: %d bytes", l);
+ if(pctx->pEncData->szMimeType &&
+ (!strcmp(pctx->pEncData->szMimeType, DENC_ENCDATA_MIME_ZLIB)))
+ pctx->pEncData->nDataStatus = DENC_DATA_STATUS_ENCRYPTED_AND_COMPRESSED;
+ else
+ pctx->pEncData->nDataStatus = DENC_DATA_STATUS_ENCRYPTED_AND_NOT_COMPRESSED;
+ } else
+ free(p);
+ }
+ }
+ // reset collect mode and cleanup
+ pctx->bCollectMode = 0;
+ return err;
+}
+
+//--------------------------------------------------
+// Handles the <EncryptionProperties> start event
+// pctx - SAX parser context
+// atts - array of atribute names and values
+// returns error code or ERR_OK.
+//--------------------------------------------------
+int dencSaxHandleStartEncryptionProperties(DEncParse* pctx, const xmlChar** atts)
+{
+ int i, err = ERR_OK;
+ char *id = NULL;
+
+ // check the atributes
+ for(i = 0; atts && atts[i] && atts[i+1]; i++) {
+ if(!strcmp((char*)atts[i], "Id"))
+ id = (char*)atts[i+1];
+ }
+ if(id)
+ err = dencEncryptedData_SetEncryptionPropertiesId(pctx->pEncData, id);
+ return err;
+}
+
+//--------------------------------------------------
+// Handles the <EncryptionProperty> start event
+// pctx - SAX parser context
+// atts - array of atribute names and values
+// returns error code or ERR_OK.
+//--------------------------------------------------
+int dencSaxHandleStartEncryptionProperty(DEncParse* pctx, const xmlChar** atts)
+{
+ int i, err = ERR_OK;
+ char *id = NULL, *target = NULL, *name = NULL;
+ DEncEncryptionProperty* pEncProperty = 0;
+
+ // check the atributes
+ for(i = 0; atts && atts[i] && atts[i+1]; i++) {
+ if(!strcmp((char*)atts[i], "Id"))
+ id = (char*)atts[i+1];
+ if(!strcmp((char*)atts[i], "Target"))
+ target = (char*)atts[i+1];
+ if(!strcmp((char*)atts[i], "Name"))
+ name = (char*)atts[i+1];
+ }
+ err = dencEncryptionProperty_new(pctx->pEncData, &pEncProperty,
+ id, target, name, NULL);
+ if(err) return err;
+ pctx->bCollectMode = 1;
+ ddocMemBuf_free(&(pctx->mbufContent));
+ return err;
+}
+
+//--------------------------------------------------
+// Handles the <EncryptionProperty> end event
+// pctx - SAX parser context
+// atts - array of atribute names and values
+// returns error code or ERR_OK.
+//--------------------------------------------------
+int dencSaxHandleEndEncryptionProperty(DEncParse* pctx)
+{
+ int err = ERR_OK;
+ DEncEncryptionProperty* pEncProperty = 0;
+
+ if(pctx->mbufContent.pMem && pctx->mbufContent.nLen) {
+ pEncProperty = dencEncryptedData_GetLastEncryptionProperty(pctx->pEncData);
+ if(pEncProperty)
+ err = dencEncryptionProperty_SetContent(pEncProperty, (char*)pctx->mbufContent.pMem);
+ ddocMemBuf_free(&(pctx->mbufContent));
+ }
+ pctx->bCollectMode = 0;
+ return err;
+}
+
+
+
+//===============< SAX handlers >==============================
+
+//--------------------------------------------------
+// dencStartElementHandler:
+// @ctxt: An XML parser context
+// @name: The element name
+// called when an opening tag has been processed.
+//--------------------------------------------------
+static void dencStartElementHandler(void *ctx, const xmlChar *name, const xmlChar **atts)
+{
+ DEncParse* pctx = (DEncParse*)ctx;
+ ElementEntry* pCurrElem = 0;
+
+ ddocDebug(5, "dencStartElementHandler", "<%s>, err: %d", (const char*)name, pctx->errcode);
+ if(pctx->errcode) return; // if error skip all additional parsing
+ pctx->errcode = ddocStackPushElementSAX(&(pctx->dencStack), name, atts, &pCurrElem);
+ if(pctx->errcode) return;
+ // check the element name
+ if(pCurrElem) {
+ if(!strcmp((const char*)pCurrElem->tag, "EncryptedData"))
+ pctx->errcode = dencSaxHandleStartEncryptedData(pctx, atts);
+ if(!strcmp((const char*)pCurrElem->tag, "EncryptionMethod"))
+ pctx->errcode = dencSaxHandleStartEncryptionMethod(pctx, atts);
+ if(!strcmp((const char*)pCurrElem->tag, "EncryptedKey"))
+ pctx->errcode = dencSaxHandleStartEncryptedKey(pctx, atts);
+ // start collecting certificate data
+ if(!strcmp((const char*)pCurrElem->tag, "X509Certificate") ||
+ !strcmp((const char*)pCurrElem->tag, "KeyName") ||
+ !strcmp((const char*)pCurrElem->tag, "CipherValue") ||
+ !strcmp((const char*)pCurrElem->tag, "CarriedKeyName") ) {
+ pctx->bCollectMode = 1;
+ ddocMemBuf_free(&(pctx->mbufContent));
+ }
+ if(!strcmp((const char*)pCurrElem->tag, "EncryptionProperties"))
+ pctx->errcode = dencSaxHandleStartEncryptionProperties(pctx, atts);
+ if(!strcmp((const char*)pCurrElem->tag, "EncryptionProperty"))
+ pctx->errcode = dencSaxHandleStartEncryptionProperty(pctx, atts);
+ }
+}
+
+//--------------------------------------------------
+// dencEndElementHandler:
+// @ctxt: An XML parser context
+// @name: The element name
+// called when the end of an element has been detected.
+//--------------------------------------------------
+static void dencEndElementHandler(void *ctx, const xmlChar *name)
+{
+ DEncParse* pctx = (DEncParse*)ctx;
+ ElementEntry* pCurrElem = 0;
+
+ ddocDebug(5, "dencEndElementHandler", "</%s>, err: %d", (const char*)name, pctx->errcode);
+ if(pctx->errcode) return; // if error skip all additional parsing
+ // find last element
+ pCurrElem = ddocStackFindEnd(&(pctx->dencStack));
+ // check the element name
+ if(pCurrElem) {
+ if(!strcmp((const char*)pCurrElem->tag, "X509Certificate"))
+ pctx->errcode = dencSaxHandleEndX509Certificate(pctx);
+ if(!strcmp((const char*)pCurrElem->tag, "KeyName"))
+ pctx->errcode = dencSaxHandleEndKeyName(pctx);
+ if(!strcmp((const char*)pCurrElem->tag, "CarriedKeyName"))
+ pctx->errcode = dencSaxHandleEndCarriedKeyName(pctx);
+ if(!strcmp((const char*)pCurrElem->tag, "CipherValue"))
+ pctx->errcode = dencSaxHandleEndCipherValue(pctx);
+ if(!strcmp((const char*)pCurrElem->tag, "EncryptionProperty"))
+ pctx->errcode = dencSaxHandleEndEncryptionProperty(pctx);
+ }
+ // pop stack
+ pctx->errcode = ddocStackPopElement(&(pctx->dencStack), 0, NULL);
+}
+
+//--------------------------------------------------
+// dencCharactersHandler:
+// @ctxt: An XML parser context
+// @ch: a xmlChar string
+// @len: the number of xmlChar
+// receiving some chars from the parser.
+//--------------------------------------------------
+static void dencCharactersHandler(void *ctx, const xmlChar *ch, int len)
+{
+ DEncParse* pctx = (DEncParse*)ctx;
+
+ ddocDebug(5, "dencCharactersHandler", "err: %d", pctx->errcode);
+ if(pctx->errcode) return; // if error skip all additional parsing
+
+ if(pctx->bCollectMode) {
+ pctx->errcode = ddocMemAppendData(&(pctx->mbufContent), (char*)ch, len);
+ }
+
+ ddocDebug(5, "dencCharactersHandler: %s", "End");
+}
+
+
+//--------------------------------------------------
+// cdataBlockHandler:
+// @ctx: the user data (XML parser context)
+// @value: The pcdata content
+// @len: the block length
+// called when a pcdata block has been parsed
+//--------------------------------------------------
+static void dencCdataBlockHandler(void * ctx, const xmlChar *value, int len)
+{
+ ddocDebug(5, "dencCdataBlockHandler", "SAX.pcdata(%.20s, %d)", (char*)value, len);
+}
+
+
+//--------------------------------------------------
+// dencWarningHandler:
+// @ctxt: An XML parser context
+// @msg: the message to display/transmit
+// @...: extra parameters for the message display
+// Display and format a warning messages, gives file, line, position and
+// extra parameters
+//--------------------------------------------------
+static void dencWarningHandler(void * ctx, const char *msg, ...)
+{
+ va_list args;
+
+ va_start(args, msg);
+ ddocDebug(2, "dencWarningHandler", msg, args);
+ fprintf(stdout, "SAX.warning: ");
+ vfprintf(stdout, msg, args);
+ va_end(args);
+}
+
+//--------------------------------------------------
+// dencErrorHandler:
+// @ctxt: An XML parser context
+// @msg: the message to display/transmit
+// @...: extra parameters for the message display
+// Display and format a error messages, gives file, line, position and
+// extra parameters.
+//--------------------------------------------------
+static void dencErrorHandler(void *ctx, const char *msg, ...)
+{
+ va_list args;
+ DEncParse* pctx = (DEncParse*)ctx;
+
+ va_start(args, msg);
+ pctx->errcode = ERR_DIGIDOC_PARSE;
+ ddocDebugVaArgs(1, "dencErrorHandler", msg, args);
+ addError(pctx->errcode, __FILE__, __LINE__, "XML parsing error");
+ va_end(args);
+}
+
+//--------------------------------------------------
+// dencFatalErrorHandler:
+// @ctxt: An XML parser context
+// @msg: the message to display/transmit
+// @...: extra parameters for the message display
+// Display and format a fatalError messages, gives file, line, position and
+// extra parameters.
+//--------------------------------------------------
+static void dencFatalErrorHandler(void *ctx, const char *msg, ...)
+{
+ va_list args;
+ DEncParse* pctx = (DEncParse*)ctx;
+
+ va_start(args, msg);
+ pctx->errcode = ERR_DIGIDOC_PARSE;
+ ddocDebugVaArgs(1, "dencFatalErrorHandler", msg, args);
+ addError(pctx->errcode, __FILE__, __LINE__, "XML parsing error");
+ va_end(args);
+}
+
+xmlSAXHandler dencSAXHandlerStruct = {
+ NULL, //internalSubsetHandler,
+ NULL, //isStandaloneHandler,
+ NULL, //hasInternalSubsetHandler,
+ NULL, //hasExternalSubsetHandler,
+ NULL, //resolveEntityHandler,
+ NULL, //getEntityHandler,
+ NULL, //entityDeclHandler,
+ NULL, //notationDeclHandler,
+ NULL, //attributeDeclHandler,
+ NULL, //elementDeclHandler,
+ NULL, //unparsedEntityDeclHandler,
+ NULL, //setDocumentLocatorHandler,
+ NULL, //startDocumentHandler,
+ NULL, //endDocumentHandler,
+ dencStartElementHandler,
+ dencEndElementHandler,
+ NULL, //referenceHandler,
+ dencCharactersHandler,
+ NULL, //ignorableWhitespaceHandler,
+ NULL, //processingInstructionHandler,
+ NULL, //commentHandler,
+ dencWarningHandler,
+ dencErrorHandler,
+ dencFatalErrorHandler,
+ NULL, //getParameterEntityHandler,
+ dencCdataBlockHandler,
+ NULL, //externalSubsetHandler,
+ 1
+};
+
+
+xmlSAXHandlerPtr dencSAXHandler = &dencSAXHandlerStruct;
+
+
+
+//--------------------------------------------------
+// Reads in encrypted XML document.
+// ppEncData - address for new encrypted data object [REQUIRED]
+// szFileName - input file name
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencSaxReadEncryptedData(DEncEncryptedData** ppEncData, const char* szFileName)
+{
+ FILE *f;
+ int ret;
+ char chars[1025];
+ xmlParserCtxtPtr ctxt;
+ DEncParse pctx;
+#ifdef WIN32
+ wchar_t *convFileName = 0;
+ int i= 0;
+#endif
+
+ RETURN_IF_NULL_PARAM(szFileName)
+ RETURN_IF_NULL_PARAM(ppEncData)
+ clearErrors();
+ *ppEncData = 0; // mark as not read yet
+ memset(&pctx, 0, sizeof(pctx));
+ //ddocConvertFileName(chars, sizeof(chars), szFileName );
+ ddocDebug(3, "dencSaxReadEncryptedData", "Opening file: %s", szFileName);
+#ifdef WIN32
+ i = 0;
+ ret = utf82unicode((const char*)szFileName, (char**)&convFileName, &i);
+ ddocDebug(3, "dencSaxReadEncryptedData", "file: %s, conv-file: %s len: %d, rc: %d", szFileName, convFileName, i, ret);
+ if((f = _wfopen(convFileName, L"rb")) != NULL) {
+ ddocDebug(3, "dencSaxReadEncryptedData", "Opened w-file: %s", convFileName);
+#else
+ if((f = fopen(szFileName, "rb")) != NULL) {
+ ddocDebug(3, "dencSaxReadEncryptedData", "Opened file: %s", szFileName);
+#endif
+ ret = fread(chars, 1, 1024, f);
+ if (ret > 0) {
+ ddocDebug(3, "dencSaxReadEncryptedData", "Read first %d bytes", ret);
+ ctxt = xmlCreatePushParserCtxt(dencSAXHandler, &pctx,
+ chars, ret, szFileName);
+ while ((ret = fread(chars, 1, 1024, f)) > 0) {
+ ddocDebug(3, "dencSaxReadEncryptedData", "Parsing %d bytes", ret);
+ xmlParseChunk(ctxt, chars, ret, 0);
+ }
+ xmlParseChunk(ctxt, chars, 0, 1);
+ xmlFreeParserCtxt(ctxt);
+ }
+ fclose(f);
+ } else {
+ ddocDebug(1, "dencSaxReadEncryptedData", "Error reading file: %s", szFileName);
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_READ);
+ }
+ // cleanup stack
+ ret = pctx.errcode = ddocStackPopElement(&(pctx.dencStack), 1, NULL);
+ ddocDebug(3, "dencSaxReadEncryptedData", "End parsing file: %s - RC: %d", szFileName, ret);
+ if(ret == 0)
+ *ppEncData = pctx.pEncData;
+ // cleanup
+ dencSaxCleanup(&pctx);
+ return ret;
+}
+
+//--------------------------------------------------
+// Reads in encrypted XML document.
+// ppEncData - address for new encrypted data object [REQUIRED]
+// pData - input data [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencSaxReadEncryptedDataFromMemory(DEncEncryptedData** ppEncData, DigiDocMemBuf* pData)
+{
+ int ret;
+ DEncParse pctx;
+
+ RETURN_IF_NULL_PARAM(pData)
+ RETURN_IF_NULL_PARAM(ppEncData)
+ clearErrors();
+ *ppEncData = 0; // mark as not read yet
+ memset(&pctx, 0, sizeof(pctx));
+ ddocDebug(3, "dencSaxReadEncryptedData", "Reading from mem %d bytes", pData->nLen);
+ ret = xmlSAXUserParseMemory(dencSAXHandler, &pctx, (const char*)pData->pMem, pData->nLen);
+ // cleanup stack
+ ret = pctx.errcode = ddocStackPopElement(&(pctx.dencStack), 1, NULL);
+ ddocDebug(3, "dencSaxReadEncryptedData", "End parsing mem: %d - RC: %d", pData->nLen, ret);
+ if(ret == 0)
+ *ppEncData = pctx.pEncData;
+ // cleanup
+ dencSaxCleanup(&pctx);
+ return ret;
+}
+
+
+//===============< Large file decryption SAX handlers >==============================
+
+/*
+* Working area for XML parsing with SAX
+*/
+typedef struct DEncDecryptParse_st {
+ int errcode;
+ ElementEntry dencStack; // stack used for keeping the current parsing position
+ FILE* hOutFile;
+ DigiDocMemBuf mbufTransportKey;
+ DigiDocMemBuf mbufTemp;
+ X509* pCert;
+ EVP_PKEY* pkey;
+ char* szPin;
+ int nSlot;
+ long lB64Len, lBinLen, lDecLen;
+ EVP_ENCODE_CTX ectx;
+ EVP_CIPHER_CTX dctx;
+ int nB64SkipMode;
+ char errmsg[100];
+ char szCertSerial[100];
+ int nCipherInited;
+} DEncDecryptParse;
+
+
+//--------------------------------------------------
+// Cleans up data that might have been allocated
+// during the parsing process
+// pctx: An XML parser context
+//--------------------------------------------------
+void dencDecryptSaxCleanup(DEncDecryptParse* pctx)
+{
+ ddocMemBuf_free(&(pctx->mbufTransportKey));
+ ddocMemBuf_free(&(pctx->mbufTemp));
+ if(pctx->pCert)
+ X509_free(pctx->pCert);
+ if(pctx->hOutFile)
+ fclose(pctx->hOutFile);
+ memset(pctx, 0, sizeof(DEncDecryptParse));
+}
+
+//--------------------------------------------------
+// dencDecryptStartElementHandler:
+// @ctxt: An XML parser context
+// @name: The element name
+// called when an opening tag has been processed.
+//--------------------------------------------------
+static void dencDecryptStartElementHandler(void *ctx, const xmlChar *name, const xmlChar **atts)
+{
+ DEncDecryptParse* pctx = (DEncDecryptParse*)ctx;
+ ElementEntry* pCurrElem = 0;
+ char *mime = NULL;
+ int i;
+
+ // check the atributes
+ for(i = 0; atts && atts[i] && atts[i+1]; i++) {
+ if(!strcmp((char*)atts[i], "MimeType")) {
+ mime = (char*)atts[i+1];
+ }
+ }
+ ddocDebug(4, "dencDecryptStartElementHandler", "<%s>, err: %d", (const char*)name, pctx->errcode);
+ if(pctx->errcode) return; // if error skip all additional parsing
+ pctx->errcode = ddocStackPushElementSAX(&(pctx->dencStack), name, atts, &pCurrElem);
+ // initialize decoding and decryption
+ if(pCurrElem && !strcmp((const char*)pCurrElem->tag, "CipherValue") &&
+ !ddocStackHasParentWithName(&(pctx->dencStack), (xmlChar*)"EncryptedKey", NULL)) {
+ if(pctx->nB64SkipMode == 0) {
+ ddocDebug(4, "dencDecryptStartElementHandler", "Decode init");
+ EVP_DecodeInit(&(pctx->ectx));
+ EVP_CIPHER_CTX_init(&(pctx->dctx));
+ pctx->lB64Len = pctx->lBinLen = pctx->lDecLen = 0;
+ }
+ pctx->nB64SkipMode++; // increment skip mode
+ ddocDebug(4, "dencDecryptStartElementHandler", "Decode start, skip: %d", pctx->nB64SkipMode);
+ }
+ // check mime
+ if(strstr((char*)name, "EncryptedData")) {
+
+ }
+ // <X509Certificate>
+ if(strstr((char*)name, "X509Certificate")) {
+ ddocDebug(4, "dencDecryptStartElementHandler", "Start collecting cert");
+ ddocMemBuf_free(&(pctx->mbufTemp));
+ }
+}
+
+//--------------------------------------------------
+// dencDecryptEndElementHandler:
+// @ctxt: An XML parser context
+// @name: The element name
+// called when the end of an element has been detected.
+//--------------------------------------------------
+static void dencDecryptEndElementHandler(void *ctx, const xmlChar *name)
+{
+ DEncDecryptParse* pctx = (DEncDecryptParse*)ctx;
+ char buf1[4096], buf2[4096];
+ int l1, l2, l3;
+ DigiDocMemBuf mbuf1;
+
+ mbuf1.pMem = NULL;
+ mbuf1.nLen = 0;
+ ddocDebug(4, "dencDecryptEndElementHandler", "</%s>, err: %d", (const char*)name, pctx->errcode);
+ if(pctx->errcode) return; // if error skip all additional parsing
+ // decode the certificate data
+ if(strstr((char*)name, "X509Certificate")) {
+ pctx->errcode = ddocDecodeX509PEMData(&(pctx->pCert), (const char*)pctx->mbufTemp.pMem, (int)pctx->mbufTemp.nLen);
+ ddocDebug(4, "dencDecryptEndElementHandler", "Decoding pem: %d cert: %s, rc: %d",
+ pctx->mbufTemp.nLen, (pctx->pCert ? "OK" : "NULL"), pctx->errcode);
+ ddocMemBuf_free(&(pctx->mbufTemp));
+ //EVP_DecodeFinal(&(pctx->ectx),out,outl)
+ pctx->nB64SkipMode = 0;
+ }
+ // check if it was the right key and decrypt transport key
+ if(strstr((char*)name, "EncryptedKey")) {
+ memset(buf1, 0, sizeof(buf1));
+ pctx->errcode = ReadCertSerialNumber(buf1, sizeof(buf1), pctx->pCert);
+ ddocCertGetDN(pctx->pCert, &mbuf1, 0);
+ ddocDebug(4, "dencDecryptEndElementHandler", "Looking for cert: %s, found: %s - %s, rc: %d",
+ pctx->szCertSerial, buf1, (char*)mbuf1.pMem, pctx->errcode);
+ ddocMemBuf_free(&mbuf1);
+ if(!strcmp(pctx->szCertSerial, buf1)) {
+ l1 = sizeof(buf1);
+ memset(buf1, 0, l1);
+ decode((const byte*)pctx->mbufTemp.pMem, pctx->mbufTemp.nLen, (byte*)buf1, &l1);
+ ddocDebug(4, "dencDecryptEndElementHandler", "Decoded key-len: %d got: %d",
+ pctx->mbufTemp.nLen, l1);
+ // cleanup temp buffer
+ ddocMemBuf_free(&(pctx->mbufTemp));
+ if(l1 < DENC_ENCRYPTED_KEY_LEN) {
+ SET_LAST_ERROR(ERR_DENC_DECRYPT);
+ pctx->errcode = ERR_DENC_DECRYPT;
+ return;
+ }
+ // decrypt the transport key
+ pctx->mbufTransportKey.nLen = l1;
+ pctx->mbufTransportKey.pMem = (char*)malloc(l1);
+ if(!pctx->mbufTransportKey.pMem) {
+ SET_LAST_ERROR(ERR_BAD_ALLOC);
+ pctx->errcode = ERR_BAD_ALLOC;
+ return;
+ }
+ memset(pctx->mbufTransportKey.pMem, 0, l1);
+ l3 = pctx->mbufTransportKey.nLen;
+ if(pctx->pkey) {
+#if OPENSSL_VERSION_NUMBER > 0x10000000
+ l3 = EVP_PKEY_decrypt_old((unsigned char *)pctx->mbufTransportKey.pMem,
+ (const unsigned char*)buf1, l1, pctx->pkey);
+#else
+ l3 = EVP_PKEY_decrypt((unsigned char *)pctx->mbufTransportKey.pMem,
+ (const unsigned char*)buf1, l1, pctx->pkey);
+#endif
+ pctx->mbufTransportKey.nLen = l3;
+ if(l3 != 16)
+ pctx->errcode = ERR_DENC_DECRYPT;
+ } else {
+ pctx->errcode = decryptWithEstID(pctx->nSlot, pctx->szPin, (char *)buf1, l1,
+ (char*)pctx->mbufTransportKey.pMem, &l3);
+ pctx->mbufTransportKey.nLen = l3;
+ }
+ ddocDebug(4, "dencDecryptEndElementHandler", "Decrypted key-len: %d rc: %d",
+ pctx->mbufTransportKey.nLen, pctx->errcode);
+ if(pctx->mbufTransportKey.nLen != DENC_DECRYPTED_KEY_LEN) {
+ SET_LAST_ERROR(ERR_DENC_DECRYPT);
+ pctx->errcode = ERR_DENC_DECRYPT;
+ return;
+ }
+ }
+ }
+ // last block of encrypted data
+ if(strstr((char*)name, "CipherValue") &&
+ !ddocStackHasParentWithName(&(pctx->dencStack), (xmlChar*)"EncryptedKey", NULL)) {
+ ddocDebug(4, "dencDecryptEndElementHandler", "Decode end, skip: %d", pctx->nB64SkipMode);
+ if(pctx->nB64SkipMode > 0)
+ pctx->nB64SkipMode--;
+ if(pctx->nB64SkipMode == 0) {
+ l1 = sizeof(buf1);
+ memset(buf1, 0, l1);
+ ddocDebug(4, "dencDecryptEndElementHandler", "Decoding: final into: %d", l1);
+ EVP_DecodeFinal(&(pctx->ectx), (unsigned char*)buf1, &l1);
+ pctx->lBinLen += l1;
+ ddocDebug(4, "dencDecryptEndElementHandler", "Decoded: final got: %d, total %d -> %d", l1, pctx->lB64Len, pctx->lBinLen);
+ // decrypt decoded data
+ l2 = sizeof(buf2);
+ memset(buf2, 0, l2);
+ ddocDebug(3, "dencDecryptEndElementHandler", "Decrypting: final into: %d", l2);
+ EVP_CipherFinal_ex(&(pctx->dctx), (unsigned char*)buf2, &l2);
+ ddocDebug(4, "dencDecryptEndElementHandler", "Decrypted: final got: %d", l2);
+ // write to file
+ if(pctx->hOutFile) {
+ if(l2)
+ pctx->lDecLen += fwrite(buf2, 1, l2, pctx->hOutFile);
+ fclose(pctx->hOutFile);
+ pctx->hOutFile = 0;
+ }
+ ddocDebug(3, "dencDecryptEndElementHandler", "Total base64: %d decoded: %d decrypted: %d RC: %d",
+ pctx->lB64Len, pctx->lBinLen, pctx->lDecLen, pctx->errcode);
+ pctx->nB64SkipMode = 0;
+ }
+ }
+ // pop stack
+ pctx->errcode = ddocStackPopElement(&(pctx->dencStack), 0, NULL);
+}
+
+//--------------------------------------------------
+// dencDecryptCharactersHandler:
+// @ctxt: An XML parser context
+// @ch: a xmlChar string
+// @len: the number of xmlChar
+// receiving some chars from the parser.
+//--------------------------------------------------
+static void dencDecryptCharactersHandler(void *ctx, const xmlChar *ch, int len)
+{
+ DEncDecryptParse* pctx = (DEncDecryptParse*)ctx;
+ ElementEntry* pCurrElem = 0;
+ char *buf1=0, *buf2=0, *p1=0;
+ int l1, l2, i, l;
+
+ ddocDebug(4, "dencDecryptCharactersHandler", "Parsing: %d chars err: %d, skip: %d", len, pctx->errcode, pctx->nB64SkipMode);
+ if(pctx->errcode) return; // if error skip all additional parsing
+ // find last element
+ pCurrElem = ddocStackFindEnd(&(pctx->dencStack));
+ // if this is data belonging to <CipherValue> tag and
+ // the latter is not a child of <EncryptedKey>, thus
+ // it must be the main content, then decrypt it
+ if(pCurrElem && !strcmp((const char*)pCurrElem->tag, "X509Certificate")) {
+ // collect the certificate data
+ pctx->errcode = ddocMemAppendData(&(pctx->mbufTemp), (char*)ch, len);
+ }
+ if(pCurrElem || pctx->nB64SkipMode > 0) {
+ // handle encrypted data
+ if((pCurrElem && !strcmp((const char*)pCurrElem->tag, "CipherValue")) || pctx->nB64SkipMode > 0) {
+ // collect encrypted transport key data
+ if(pCurrElem &&
+ ddocStackHasParentWithName(&(pctx->dencStack), (xmlChar*)"EncryptedKey", NULL)) {
+ pctx->errcode = ddocMemAppendData(&(pctx->mbufTemp), (char*)ch, len);
+ }
+ // if this is the real encrypted content not a key then decrypt it
+ else {
+ // check if the transport key is ready for decryption
+ if(pctx->mbufTransportKey.nLen != DENC_DECRYPTED_KEY_LEN) {
+ ddocDebug(1, "dencDecryptCharactersHandler", "Transport key len: %d", pctx->mbufTransportKey.nLen);
+ SET_LAST_ERROR(ERR_DENC_NO_KEY_FOUND); // not encrypted for this user!
+ pctx->errcode = ERR_DENC_NO_KEY_FOUND;
+ return;
+ }
+ // decode base64 encrypted data
+ pctx->lB64Len += len;
+ l1 = len * 2;
+ buf1 = (char*)malloc(l1);
+ if(!buf1) {
+ SET_LAST_ERROR(ERR_BAD_ALLOC);
+ return;
+ }
+ memset(buf1, 0, l1);
+ ddocDebug(4, "dencDecryptCharactersHandler", "Decoding: %d into: %d, skip: %d", len, l1, pctx->nB64SkipMode);
+ EVP_DecodeUpdate(&(pctx->ectx), (unsigned char*)buf1, &l1, (unsigned char*)ch, len);
+ ddocDebug(4, "dencDecryptCharactersHandler", "Decoded: %d got: %d, skip: %d", len, l1, pctx->nB64SkipMode);
+ // if this was the first block of decoded base64 data
+ // then use the first 16 bytes as the IV value
+ p1 = buf1;
+ if(pctx->lBinLen == 0) {
+ ddocDebug(4, "dencDecryptCharactersHandler", "Using 16 bytes for IV. Initing cipher");
+ p1 += 16; // don't decrypt the IV data
+ l1 -= 16;
+ EVP_CipherInit_ex(&(pctx->dctx), EVP_aes_128_cbc(), NULL,
+ (const unsigned char*)pctx->mbufTransportKey.pMem, (const unsigned char*)buf1, DECRYPT);
+ }
+ pctx->lBinLen += l1;
+ ddocDebug(4, "dencDecryptCharactersHandler", "Decoded: %d got: %d, skip: %d", len, l1, pctx->nB64SkipMode);
+ // decrypt decoded data
+ l = l2 = l1 * 2;
+ buf2 = (char*)malloc(l2);
+ if(!buf2) {
+ SET_LAST_ERROR(ERR_BAD_ALLOC);
+ return;
+ }
+ memset(buf2, 0, l2);
+ //if(pctx->nB64SkipMode == 4)
+ // l1 += 16; // ???
+ ddocDebug(4, "dencDecryptCharactersHandler", "Decrypting: %d into: %d", l1, l2);
+ EVP_CipherUpdate(&(pctx->dctx), (unsigned char*)buf2, &l, (const unsigned char*)p1, l1);
+ ddocDebug(4, "dencDecryptCharactersHandler", "Decrypted: %d got: %d, skip: %d", l1, l, pctx->nB64SkipMode);
+ if(buf1)
+ free(buf1);
+
+ // no padding until the final chunk
+ if((pctx->nB64SkipMode == 0 || pctx->nB64SkipMode == 4)) {
+ // on the last block check for a block with all 0x0F
+ l1 = (int)(unsigned char)buf2[l-1];
+ if(l1 == 16) {
+ ddocDebug(4, "dencDecryptCharactersHandler", "Check 0x0F padding 1: %d", l1);
+ for(i = l - l1; i < l - 1; i++) {
+ ddocDebug(4, "dencDecryptCharactersHandler", "Pad pos: %d = %d", i, buf2[i]);
+ if(buf2[i] != 16) {
+ l1 = 0; // set not matched flag
+ break;
+ }
+ }
+ if(l1) {
+ ddocDebug(4, "dencDecryptCharactersHandler", "Decrypted len: %d reduce by: %d -> %d", l2, l1, (l-l1));
+ l -= l1;
+ }
+ }
+ // remove padding
+ l1 = (int)(unsigned char)buf2[l-1];
+ if(l1 > 0 && l1 <= 16) {
+ ddocDebug(4, "dencDecryptCharactersHandler", "Check padding: %d", l1);
+ for(i = l - l1; i < l - 1; i++) {
+ ddocDebug(4, "dencDecryptCharactersHandler", "Pad pos: %d = %d", i, buf2[i]);
+ if(buf2[i]) {
+ l1 = 0; // set not matched flag
+ break;
+ }
+ }
+ if(l1) {
+ ddocDebug(4, "dencDecryptCharactersHandler", "Decrypted len: %d reduce by: %d -> %d", l2, l1, (l-l1));
+ l -= l1;
+ }
+ }
+ else
+ ddocDebug(4, "dencDecryptCharactersHandler", "Impossible padding: %d", l1);
+ if(pctx->nB64SkipMode == 4)
+ pctx->nB64SkipMode = 1; // reset flag - look for padding
+ }
+ // write to file
+ if(pctx->hOutFile && buf2)
+ pctx->lDecLen += fwrite(buf2, 1, l, pctx->hOutFile);
+ free(buf2);
+ }
+
+ }
+
+ }
+
+ ddocDebug(5, "dencDecryptCharactersHandler", "End");
+}
+
+
+xmlSAXHandler dencDecryptSAXHandlerStruct = {
+ NULL, //internalSubsetHandler,
+ NULL, //isStandaloneHandler,
+ NULL, //hasInternalSubsetHandler,
+ NULL, //hasExternalSubsetHandler,
+ NULL, //resolveEntityHandler,
+ NULL, //getEntityHandler,
+ NULL, //entityDeclHandler,
+ NULL, //notationDeclHandler,
+ NULL, //attributeDeclHandler,
+ NULL, //elementDeclHandler,
+ NULL, //unparsedEntityDeclHandler,
+ NULL, //setDocumentLocatorHandler,
+ NULL, //startDocumentHandler,
+ NULL, //endDocumentHandler,
+ dencDecryptStartElementHandler,
+ dencDecryptEndElementHandler,
+ NULL, //referenceHandler,
+ dencDecryptCharactersHandler,
+ NULL, //ignorableWhitespaceHandler,
+ NULL, //processingInstructionHandler,
+ NULL, //commentHandler,
+ dencWarningHandler,
+ dencErrorHandler,
+ dencFatalErrorHandler,
+ NULL, //getParameterEntityHandler,
+ dencCdataBlockHandler,
+ NULL, //externalSubsetHandler,
+ 1
+};
+
+
+xmlSAXHandlerPtr dencDecryptSAXHandler = &dencDecryptSAXHandlerStruct;
+
+// string used to force parser to flush it's buffers
+static char g_szCipherValueFlush1[] = "</denc:CipherValue>";
+static char g_szCipherValueFlush2[] = "<denc:CipherValue>";
+
+//--------------------------------------------------
+// Decrypts an encrypted XML document and stores the
+// cleartext data in another document.
+// szInputFileName - input file name [REQUIRED]
+// szOutputFileName - output file name [REQUIRED]
+// szPin - PIN1 of the id-card to decrypt the transport key [REQUIRED]
+// szPkcs12File - pkcs12 key container filename [OPTIONAL]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencSaxReadDecryptFile(const char* szInputFileName,
+ const char* szOutputFileName,
+ const char* szPin, const char* szPkcs12File)
+{
+ FILE *f;
+ int ret;
+ char chars[1025], convInFileName[256], convOutFileName[256], *p;
+ xmlParserCtxtPtr ctxt;
+ DEncDecryptParse pctx;
+ X509* pCert = 0;
+ EVP_PKEY *pkey = NULL;
+ DigiDocMemBuf mbuf1;
+
+ mbuf1.pMem = NULL;
+ mbuf1.nLen = 0;
+ RETURN_IF_NULL_PARAM(szInputFileName)
+ RETURN_IF_NULL_PARAM(szOutputFileName)
+ RETURN_IF_NULL_PARAM(szPin)
+ clearErrors();
+ ddocDebug(3, "dencSaxReadDecryptFile", "input-file: %s, output-file: %s",
+ szInputFileName, szOutputFileName);
+ memset(&pctx, 0, sizeof(pctx));
+
+ ddocConvertFileName(convInFileName, sizeof(convInFileName), szInputFileName);
+ ddocConvertFileName(convOutFileName, sizeof(convOutFileName), szOutputFileName);
+
+ //store decryption params
+ pctx.nSlot = ConfigItem_lookup_int("DIGIDOC_AUTH_KEY_SLOT", 0);
+ pctx.szPin = (char*)szPin;
+ pctx.hOutFile = fopen(convOutFileName, "wb");
+ pctx.nB64SkipMode = 0;
+ if(!pctx.hOutFile) {
+ ddocDebug(1, "dencSaxReadDecryptFile", "Error writing to file: %s", szOutputFileName);
+ SET_LAST_ERROR_RETURN(ERR_FILE_WRITE, ERR_FILE_WRITE)
+ }
+ // if using pkcs12 file for decryption
+ if(szPkcs12File) {
+ pctx.errcode = ReadCertificateByPKCS12(&pCert, szPkcs12File, szPin, &pkey);
+ pctx.pkey = pkey;
+ } else {
+ pctx.errcode = findUsersCertificate(pctx.nSlot, &pCert);
+ }
+ if(pCert) {
+ pctx.errcode = ReadCertSerialNumber(pctx.szCertSerial, sizeof(pctx.szCertSerial), pCert);
+ ddocCertGetDN(pCert, &mbuf1, 0);
+ ddocDebug(3, "dencSaxReadDecryptFile", "Decrypting using certificate: %s - %s", pctx.szCertSerial, (char*)mbuf1.pMem);
+ ddocMemBuf_free(&mbuf1);
+ } else {
+ ddocDebug(1, "dencSaxReadDecryptFile", "Users cert for decryption could not be read from card!");
+ return pctx.errcode;
+ }
+
+ // parse and decrypt data in file
+ if((f = fopen(convInFileName, "r")) != NULL && !pctx.errcode) {
+ ret = fread(chars, 1, 1024, f);
+ if (ret > 0) {
+ ctxt = xmlCreatePushParserCtxt(dencDecryptSAXHandler, &pctx,
+ chars, ret, convInFileName);
+ do {
+ memset(chars, 0, sizeof(chars));
+ ret = fread(chars, 1, 1024, f);
+ if(ret == 0)
+ ret = strlen(chars);
+ ddocDebug(4, "dencSaxReadDecryptFile", "In: %d Parsed: %d, skip: %d", ret, ctxt->nbChars, pctx.nB64SkipMode);
+ // this horrible chemistry is done to prevent
+ // libxml2 to start colecting huge memory structures
+ // Since we cannot disable it we'll just bypass parser
+ // with a large amount of base64 data
+ if(pctx.nB64SkipMode > 0) {
+ p = strchr(chars, '<');
+ // if <CipherValue> was found and no "<" (beginn of new element)
+ // is found then send the "flush command" and enter bypass mode
+ if(pctx.nB64SkipMode == 1 && !p) {
+ pctx.nB64SkipMode += 2;
+ ddocDebug(4, "dencSaxReadDecryptFile", "Starting bypass mode, skip: %d", pctx.nB64SkipMode);
+ // force the parser to release element content
+ // before entering into bypass mode
+ xmlParseChunk(ctxt, g_szCipherValueFlush1, strlen(g_szCipherValueFlush1), 0);
+ ddocDebug(4, "dencSaxReadDecryptFile", "Entering bypass mode, skip: %d", pctx.nB64SkipMode);
+ }
+ if(pctx.nB64SkipMode >= 2 && !p) {
+ ddocDebug(4, "dencSaxReadDecryptFile", "Parsing in bypass mode, skip: %d", pctx.nB64SkipMode);
+ dencDecryptCharactersHandler(&pctx, (const xmlChar *)chars, ret);
+ }
+ // if we reached the first block that contains a start of xml element
+ // then stop bypass mode
+ if(strchr(chars, '<')) {
+ pctx.nB64SkipMode = 2;
+ xmlParseChunk(ctxt, g_szCipherValueFlush2, strlen(g_szCipherValueFlush2), 0);
+ ddocDebug(4, "dencSaxReadDecryptFile", "Ending bypass mode len: %d, skip: %d", ret, pctx.nB64SkipMode);
+ }
+ } // if bypass mode
+ // if in normal mode or finished bypass mode
+ if(pctx.nB64SkipMode == 0 || pctx.nB64SkipMode == 3) {
+ if(pctx.nB64SkipMode == 3)
+ pctx.nB64SkipMode = 4; // used as flag: last block - look for padding
+ ddocDebug(4, "dencSaxReadDecryptFile", "parsing normal chunk");
+ xmlParseChunk(ctxt, chars, ret, 0);
+ }
+ //memset(chars, 0, sizeof(chars));
+ } while(ret == 1024); // do-while
+ // last block of data
+ ddocDebug(4, "dencSaxReadDecryptFile", "parsing final chunk: %d", strlen(chars));
+ if(!pctx.errcode)
+ xmlParseChunk(ctxt, NULL, 0, 1);
+ xmlFreeParserCtxt(ctxt);
+ } // if(ret > 0)
+ fclose(f);
+ } else {
+ ddocDebug(1, "dencSaxReadDecryptFile", "Error reading file: %s", szInputFileName);
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_READ);
+ }
+ // cleanup stack
+ ret = pctx.errcode = ddocStackPopElement(&(pctx.dencStack), 1, NULL);
+ // cleanup
+ dencDecryptSaxCleanup(&pctx);
+ ddocDebug(1, "dencSaxReadDecryptFile",
+ "End parsing file: %s - RC: %d", szInputFileName, ret);
+ return ret;
+}
+