summaryrefslogtreecommitdiff
path: root/libdigidoc/DigiDocSAXParser.c
diff options
context:
space:
mode:
Diffstat (limited to 'libdigidoc/DigiDocSAXParser.c')
-rw-r--r--libdigidoc/DigiDocSAXParser.c3237
1 files changed, 3237 insertions, 0 deletions
diff --git a/libdigidoc/DigiDocSAXParser.c b/libdigidoc/DigiDocSAXParser.c
new file mode 100644
index 0000000..0bebe63
--- /dev/null
+++ b/libdigidoc/DigiDocSAXParser.c
@@ -0,0 +1,3237 @@
+//==================================================
+// FILE: DigiDocSAXParser.c
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc functions for xml parsing using SAX interface
+// 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 >=============================
+// 12.08.2004 Veiko Sinivee
+// Creation
+//==================================================
+
+#include <libdigidoc/DigiDocDefs.h>
+#include <libdigidoc/DigiDocSAXParser.h>
+#include <libdigidoc/DigiDocError.h>
+#include <libdigidoc/DigiDocDebug.h>
+#include <libdigidoc/DigiDocConvert.h>
+#include <libdigidoc/DigiDocMem.h>
+#include <libdigidoc/DigiDocLib.h>
+#include <libdigidoc/DigiDocCert.h>
+#include <libdigidoc/DigiDocConfig.h>
+#include <libdigidoc/DigiDocOCSP.h>
+#include <libdigidoc/DigiDocDfExtract.h>
+#include <libdigidoc/DigiDocVerify.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <libxml/globals.h>
+#include <libxml/xmlerror.h>
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h> /* only for xmlNewInputFromFile() */
+#include <libxml/tree.h>
+#include <libxml/debugXML.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/c14n.h>
+
+// string used to force parser to flush it's buffers
+static char g_szDataFileFlush1[] = "</DataFile>";
+static char g_szDataFileFlush2[] = "<DataFile Id=\"%s\" ContentType=\"%s\">";
+
+#ifdef WIN32
+ #define snprintf _snprintf
+ #include <wchar.h>
+#endif
+
+extern int ddocCheckFormatAndVer(const char* format, const char* version);
+extern char* canonicalizeXML(char* source, int len);
+extern int escapeXMLSymbols(const char* src, int srclen, char** dest);
+
+#define FLAG_XML_ELEM 1
+#define FLAG_SIGNATURE 2
+#define FLAG_SIG_PART 3
+#define FLAG_TS_INP 4
+
+//===============< SAX handlers >==============================
+
+/*
+* Working area for XML parsing with SAX
+*/
+typedef struct SigDocParse_st {
+ SignedDoc* pSigDoc; // document file to be filled with data
+ char tag[300]; // current tag
+ char ctx1[300]; // context1
+ char ctx2[300]; // context2
+ char ctx3[300]; // context3
+ char ctx4[300];
+ char ctx5[300];
+ BIO* bDataFile;
+ EVP_ENCODE_CTX ectx;
+ SHA_CTX sctx, sctx2; // sha1 digest context and alternat dig context
+ int errcode;
+ char* szInputFileName;
+ int checkFileDigest;
+ int nIgnoreDataFile; // incremented each time when EMBEDDED XML content is found.
+ // used to ignore such content
+ DigiDocMemBuf mbufElemData;
+ char bCollectElemData;
+ char bNoXMLElemData;
+ int checkUTF8;
+ DigiDocMemBuf mbufSigData; // <Signature>
+ char bCollectSigData;
+ DigiDocMemBuf mbufSigPartData; // <SignedInfo> and <SignedProperties>
+ char bCollectSigPartData;
+ long lMaxDFLen;
+ time_t tStartParse;
+ long lSize;
+ char bCollectDFData;
+ DigiDocMemBuf *pMemBufDF;
+ int bKeepBase64;
+ char b64line[66];
+ int b64pos;
+ DigiDocMemBuf mbufTags;
+ XmlElemInfo *eRoot, *eCurr;
+} SigDocParse;
+
+//--------------------------------------------------
+// Releases memory that might have been allocated during
+// the parsing process.
+// pctx - pointer to parsing context
+//--------------------------------------------------
+void ddocSAXCleanup(SigDocParse* pctx)
+{
+ // field: szInputFileName is not allocated in parser!
+ ddocMemBuf_free(&(pctx->mbufElemData));
+ ddocMemBuf_free(&(pctx->mbufSigData));
+ ddocMemBuf_free(&(pctx->mbufSigPartData));
+ ddocMemBuf_free(&(pctx->mbufTags));
+ if(pctx->pMemBufDF)
+ ddocMemBuf_free(pctx->pMemBufDF);
+ if(pctx->bDataFile)
+ BIO_free(pctx->bDataFile);
+ if(pctx->eRoot)
+ XmlElemInfo_free(pctx->eRoot);
+ memset(pctx, 0, sizeof(SigDocParse));
+}
+
+//--------------------------------------------------
+// Starts collecting some element data.
+// pctx - pointer to parsing context
+// nFlag - 1=element, 2=signature, 3=sigprop, 4=ts-input
+// bNoXml - no-xml flag
+//--------------------------------------------------
+int ddocSaxParseStartCollecting(SigDocParse* pctx, int nFlag, int bNoXml)
+{
+ RETURN_IF_NULL_PARAM(pctx);
+ switch(nFlag) {
+ case FLAG_XML_ELEM:
+ pctx->bCollectElemData = 1;
+ pctx->errcode = ddocMemBuf_free(&(pctx->mbufElemData));
+ break;
+ case FLAG_SIGNATURE:
+ pctx->bCollectSigData = 1;
+ pctx->errcode = ddocMemBuf_free(&(pctx->mbufSigData));
+ break;
+ case FLAG_SIG_PART:
+ pctx->bCollectSigPartData = 1;
+ pctx->errcode = ddocMemBuf_free(&(pctx->mbufSigPartData));
+ break;
+ }
+ pctx->bNoXMLElemData = bNoXml;
+ return pctx->errcode;
+}
+
+//--------------------------------------------------
+// Ends collecting some element data.
+// pctx - pointer to parsing context
+// nFlag - 1=element, 2=signature, 3=sigprop, 4=ts-input
+// bNoXml - no-xml flag
+//--------------------------------------------------
+int ddocSaxParseEndCollecting(SigDocParse* pctx, int nFlag, int bNoXml)
+{
+ RETURN_IF_NULL_PARAM(pctx);
+ switch(nFlag) {
+ case FLAG_XML_ELEM:
+ pctx->bCollectElemData = 0;
+ pctx->errcode = ddocMemBuf_free(&(pctx->mbufElemData));
+ break;
+ case FLAG_SIGNATURE:
+ pctx->bCollectSigData = 0;
+ pctx->errcode = ddocMemBuf_free(&(pctx->mbufSigData));
+ break;
+ case FLAG_SIG_PART:
+ pctx->bCollectSigPartData = 0;
+ pctx->errcode = ddocMemBuf_free(&(pctx->mbufSigPartData));
+ break;
+ }
+ pctx->bNoXMLElemData = bNoXml;
+ return pctx->errcode;
+}
+
+//--------------------------------------------------
+// Finds the desired atribute value.
+// atts - attributes array
+// name - name of searched atribute
+// defval - default value if not found
+//--------------------------------------------------
+const char* ddocSaxParseFindAttrib(const xmlChar **atts,
+ const char* name, const char* defval)
+{
+ int i;
+
+ for (i = 0; (atts != NULL) && (atts[i] != NULL); i += 2) {
+ if(!strcmp((const char*)atts[i], name))
+ return (const char*)atts[i+1];
+ }
+ return defval;
+}
+
+
+//--------------------------------------------------
+// Decodes a URI value in form #<id>-<type> or #<id>@<type>
+// into its components
+// uri - URI value
+// id - buffer for id
+// nIdLen - id buffer length
+// adr - buffer for adr
+// nAdrLen - adr buffer length
+//--------------------------------------------------
+void decodeURI(const char* uri, char* id, int nIdLen, char* adr, int nAdrLen)
+{
+ int j, b, i, a;
+
+ RETURN_VOID_IF_NULL(uri);
+ RETURN_VOID_IF_NULL(id);
+ RETURN_VOID_IF_NULL(adr);
+
+ id[0] = adr[0] = 0;
+ for(i = j = a = b = 0; uri[j] && (a < nAdrLen-1) && (i < nIdLen-1); j++) {
+ switch(uri[j]) {
+ case '#': continue;
+ case '@': // same as the next
+ case '-': b = 1; continue;
+ default:
+ if(b)
+ adr[a++] = uri[j];
+ else
+ id[i++] = uri[j];
+ }
+ }
+ adr[a] = 0;
+ id[i] = 0;
+}
+
+
+//--------------------------------------------------
+// handles the start of a <SignedDoc> element.
+// Creates SignedDoc structure to read in the info.
+// pctx - pointer to XML parsing work-area
+// name - tag name
+// atts - attributes
+//--------------------------------------------------
+void handleStartSignedDoc(SigDocParse* pctx, const xmlChar *name, const xmlChar **atts)
+{
+ int i;
+ const char *key = NULL, *value = NULL;
+
+ //RETURN_VOID_IF_NULL(pctx);
+ //RETURN_VOID_IF_NULL(name);
+ //RETURN_VOID_IF_NULL(atts);
+
+ strncpy(pctx->ctx1, (const char*)name, sizeof(pctx->ctx1)-1);
+ for (i = 0; (atts != NULL) && (atts[i] != NULL); i += 2) {
+ key = (const char*)atts[i];
+ value = (const char*)atts[i+1];
+ if(!strcmp(key, "format"))
+ setString(&(pctx->pSigDoc->szFormat), value, -1);
+ if(!strcmp(key, "version"))
+ setString(&(pctx->pSigDoc->szFormatVer), value, -1);
+ }
+ if(ddocCheckFormatAndVer(pctx->pSigDoc->szFormat,
+ pctx->pSigDoc->szFormatVer))
+ SET_LAST_ERROR(ERR_UNSUPPORTED_FORMAT);
+}
+
+void unescapeFilename(char** szFileName, const char* str1, const char* str2)
+{
+ DigiDocMemBuf mbuf1, mbuf2;
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ ddocDebug(4, "unescapeFilename", "In: %s replace: %s with: %s", *szFileName, str1, str2);
+ if(szFileName && strstr((const char*)(*szFileName), str1)) {
+ mbuf1.pMem = *szFileName; mbuf1.nLen = strlen(*szFileName);
+ ddocMemReplaceSubstr(&mbuf1, &mbuf2, str1, str2);
+ setString(szFileName, (const char*)mbuf2.pMem, -1);
+ ddocMemBuf_free(&mbuf2);
+ ddocDebug(4, "unescapeFilename", "Escaped: %s", *szFileName);
+ }
+}
+
+int utf8strlen(const char* src)
+{
+ int i, j;
+ unsigned char uc;
+ for(i = 0, j = 0; src && src[i]; i++) {
+ uc = (unsigned char)(0x000000FF & src[i]);
+ if(uc <= 0x7F || uc >= 0xC0)
+ j++;
+ }
+ ddocDebug(4, "utf8strlen", "Str: %s, len: %d", src, j);
+ return j;
+}
+
+//--------------------------------------------------
+// handles the start of a <DataFile> element.
+// Reads in id, filename, mime_type and embedded attributes
+// pctx - pointer to XML parsing work-area
+// name - tag name
+// atts - attributes
+//--------------------------------------------------
+void handleStartDataFile(SigDocParse* pctx, const xmlChar *name, const xmlChar **atts)
+{
+ int i, err = ERR_OK, j;
+ long size = -1;
+ const char *id = 0, *mime = 0, *dtype = 0, *dvalue = 0, *ctype = 0;
+ char *p = 0;
+ DigiDocMemBuf mbuf1, mbuf2;
+ DataFile* pDataFile = NULL;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ ddocDebug(4, "handleStartDataFile", "Ignore: %d", pctx->nIgnoreDataFile);
+ strncpy(pctx->ctx1, (const char*)name, sizeof(pctx->ctx1));
+ id = mime = dtype = dvalue = 0;
+ size = 0;
+ // allocate mem dynamically and calculate required size as necessary
+ if(!pctx->nIgnoreDataFile) {
+ pctx->bCollectElemData = 1;
+ }
+ for (i = 0; (atts != NULL) && (atts[i] != NULL); i += 2) {
+ if(!strcmp((const char*)atts[i], "Id"))
+ id = (const char*)atts[i+1];
+ if(!strcmp((const char*)atts[i], "Filename")) {
+ escapeXMLSymbols((const char*)atts[i+1], -1, &p);
+ if(p)
+ err = ddocMemAppendData(&mbuf1, p, -1);
+ free(p); p = 0;
+ ddocDebug(4, "handleStartDataFile", "Filename in: \'%s\' out: \'%s\'",
+ atts[i+1], (char*)mbuf1.pMem);
+ if(strchr((char*)mbuf1.pMem, '/') || strchr((char*)mbuf1.pMem, '\\')) {
+ ddocDebug(1, "handleStartDataFile", "Invalid filename: \'%s\'", (char*)mbuf1.pMem);
+ SET_LAST_ERROR(ERR_DF_NAME);
+ return;
+ }
+ }
+ if(!strcmp((const char*)atts[i], "MimeType"))
+ mime = (const char*)atts[i+1];
+ if(!strcmp((const char*)atts[i], "ContentType"))
+ ctype = (const char*)atts[i+1];
+ if(!strcmp((const char*)atts[i], "DigestType"))
+ dtype = (const char*)atts[i+1];
+ if(!strcmp((const char*)atts[i], "DigestValue"))
+ dvalue = (const char*)atts[i+1];
+ if(!strcmp((const char*)atts[i], "Size"))
+ size = atol((const char*)atts[i+1]);
+ }
+ if (!id || (strlen(id) > 21)) {
+ SET_LAST_ERROR(ERR_DIGIDOC_PARSE);
+ ddocDebug(1, "handleStartDataFile", "Arr err id: %s", id);
+ return;
+ }
+ // VS: check id uniqueness
+ for(j = 0; j < getCountOfDataFiles(pctx->pSigDoc); j++) {
+ pDataFile = getDataFile(pctx->pSigDoc, j);
+ if(pDataFile && pDataFile->szId && !strcmp(pDataFile->szId, id)) {
+ ddocDebug(1, "handleStartDataFile", "DF %d has same id: %s", j, id);
+ SET_LAST_ERROR(ERR_DIGIDOC_PARSE);
+ return;
+ }
+ }
+ if (!mime || (strlen(mime) > 255)) {
+ SET_LAST_ERROR(ERR_DIGIDOC_PARSE);
+ ddocDebug(1, "handleStartDataFile", "Arr err mime: %s", mime);
+ return;
+ }
+ if (!mbuf1.pMem || (utf8strlen(mbuf1.pMem) > 255)) {
+ SET_LAST_ERROR(ERR_DIGIDOC_PARSE);
+ return;
+ }
+ if (size < 0) {
+ SET_LAST_ERROR(ERR_DIGIDOC_PARSE);
+ ddocDebug(1, "handleStartDataFile", "Arr err size: %d", size);
+ return;
+ }
+ if (!ctype || (strlen(ctype) > 40)) {
+ SET_LAST_ERROR(ERR_DIGIDOC_PARSE);
+ ddocDebug(1, "handleStartDataFile", "Arr err ctype: %s", ctype);
+ return;
+ }
+ if (!pctx->pSigDoc->szFormatVer) {
+ SET_LAST_ERROR(ERR_DIGIDOC_PARSE);
+ ddocDebug(1, "handleStartDataFile", "Arr err sigdoc missing");
+ return;
+ }
+ if ((dtype && (strlen(dtype) > 10)) ||
+ (dvalue && (strlen(dvalue) > 100))) {
+ SET_LAST_ERROR(ERR_DIGIDOC_PARSE);
+ ddocDebug(1, "handleStartDataFile", "Arr err - dtype: %s dvalue: %s", dtype, dvalue);
+ return;
+ }
+ if((!ctype || strcmp(ctype, CONTENT_EMBEDDED_BASE64))
+ && !ConfigItem_lookup_bool("EMBEDDED_XML_SUPPORT", 0)) {
+ SET_LAST_ERROR(ERR_BAD_DATAFILE_CONTENT_TYPE);
+ return;
+ }
+ ddocDebug(4, "handleStartDataFile", "Check ignore");
+ // if not in ignore mode / level
+ if(!pctx->nIgnoreDataFile) {
+ strncpy(pctx->ctx2, id, sizeof(pctx->ctx2)-1);
+ ddocDebug(4, "handleStartDataFile", "Start DF: %s", id);
+ if(ctype && !strcmp(ctype, CONTENT_EMBEDDED_BASE64)) {
+ EVP_DecodeInit(&(pctx->ectx));
+ ddocDebug(3, "handleStartDataFile", "Init sha1");
+ SHA1_Init(&(pctx->sctx));
+ SHA1_Init(&(pctx->sctx2));
+ }
+ if(pctx->bDataFile)
+ pctx->bDataFile = BIO_new_file((char*)mbuf1.pMem, "w");
+ strncpy(pctx->ctx3, ctype, sizeof(pctx->ctx3)-1);
+ if(strcmp(pctx->pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER)) {
+ // copy value first
+ err = ddocMemAssignData(&mbuf2, (const char*)mbuf1.pMem, mbuf1.nLen+1);
+ // apply conversion - no length change
+ convWinToFName((const char*)mbuf1.pMem, (char*)mbuf2.pMem, mbuf2.nLen);
+ err = DataFile_new(&pDataFile, pctx->pSigDoc, id, (char*)mbuf2.pMem, ctype,
+ mime, size, NULL, 0, dtype, CHARSET_UTF_8);
+ }
+ else
+ err = DataFile_new(&pDataFile, pctx->pSigDoc, id, (char*)mbuf1.pMem, ctype,
+ mime, size, NULL, 0, dtype, CHARSET_UTF_8);
+ // RETURN_IF_NULL(pDataFile);
+ ddocDebug(4, "handleStartDataFile", "Create DF: \'%s\' - err: %d", id, err);
+ if(dvalue) {
+ err = ddocMemBuf_free(&mbuf2);
+ err = ddocDecodeBase64Data((void*)dvalue, -1, &mbuf2);
+ ddocDataFile_SetDetachedDigestValue(pDataFile, (const char*)mbuf2.pMem, mbuf2.nLen);
+ }
+ // add other attributes
+ for (i = 0; (atts != NULL) && (atts[i] != NULL); i += 2) {
+ if(strcmp((const char*)atts[i], "Id") && strcmp((const char*)atts[i], "Filename") &&
+ strcmp((const char*)atts[i], "MimeType") && strcmp((const char*)atts[i], "DigestValue") &&
+ strcmp((const char*)atts[i], "Size") && strcmp((const char*)atts[i], "ContentType") &&
+ strcmp((const char*)atts[i], "DigestType") && strcmp((const char*)atts[i], "xmlns"))
+ err = addDataFileAttribute(pDataFile, (const char*)atts[i], (const char*)atts[i+1]);
+ }
+ }
+ // is it pure XML ?
+ if(!strcmp(ctype, CONTENT_EMBEDDED) || pctx->nIgnoreDataFile)
+ pctx->nIgnoreDataFile++;
+ // cleanup
+ err = ddocMemBuf_free(&mbuf2);
+ err = ddocMemBuf_free(&mbuf1);
+ // replace &amp; with & if necessary
+ unescapeFilename(&(pDataFile->szFileName), "&amp;", "&");
+ unescapeFilename(&(pDataFile->szFileName), "&apos;", "'");
+ unescapeFilename(&(pDataFile->szFileName), "&quot;", "\"");
+ ddocDebug(4, "handleStartDataFile", "Final filename: \'%s\'", pDataFile->szFileName);
+}
+
+
+//--------------------------------------------------
+// handles the content of a <DataFile> element.
+// Reads in data file (Base64) data, decodes it
+// and writes to a file
+// pctx - pointer to XML parsing work-area
+// value - character values read from file
+// len - length of chars ???
+//--------------------------------------------------
+void handleDataFile(SigDocParse* pctx, const xmlChar *value, int len)
+{
+ int l, i, j;
+ char buf[1024], ch;
+ DataFile* pDf = 0;
+ DigiDocMemBuf mbuf1;
+ // decode the content data
+ ddocDebug(4, "handleDataFile", "DF: %s, append len: %d", pctx->ctx2, len);
+ pDf = getDataFileWithId(pctx->pSigDoc, pctx->ctx2);
+ RETURN_VOID_IF_NULL(pDf);
+ ddocAppendDataFileData(pDf, pctx->lMaxDFLen, (void*)value, len, !strcmp(pDf->szContentType, CONTENT_EMBEDDED_BASE64));
+ if(!strcmp(pctx->ctx3, CONTENT_EMBEDDED_BASE64)) {
+ // if using DataFile Base64 hack
+#ifdef WITH_BASE64_HASHING_HACK
+ if(pctx->pSigDoc->szFormatVer && strcmp(pctx->pSigDoc->szFormatVer, SK_XML_1_VER) &&
+ pctx->pSigDoc->szFormat && strcmp(pctx->pSigDoc->szFormat, SK_XML_1_NAME)) {
+ ch = ((char*)value)[len];
+ ((char*)value)[len] = 0;
+ ddocDebug(4, "handleDataFile", "sha1 update: \'%s\' len: %d", value, len);
+ mbuf1.pMem = (char*)value;
+ mbuf1.nLen = len;
+ ddocDebugWriteFile(4, "df-data.txt", &mbuf1);
+ ((char*)value)[len] = ch;
+ SHA1_Update(&(pctx->sctx), (char*)value, len);
+ SHA1_Update(&(pctx->sctx2), (char*)value, len);
+ ddocMemBuf_free(&(pctx->mbufElemData));
+ if(pctx->bDataFile) {
+ i = j = 0;
+ while(i < len) {
+ i = (i + 512 > len) ? len : i + 512;
+ l = sizeof(buf);
+ memset(buf, 0, sizeof(buf));
+ EVP_DecodeUpdate(&(pctx->ectx), (unsigned char*)buf, &l, (unsigned char*)value + j, i - j);
+ BIO_write(pctx->bDataFile, buf, l);
+ j = i;
+ }
+ }
+ } else {
+#endif
+ i = j = 0;
+ while(i < len) {
+ i = (i + 512 > len) ? len : i + 512;
+ l = sizeof(buf);
+ memset(buf, 0, sizeof(buf));
+ EVP_DecodeUpdate(&(pctx->ectx), (unsigned char*)buf, &l, (unsigned char*)value + j, i - j);
+ if(pctx->bDataFile)
+ BIO_write(pctx->bDataFile, buf, l);
+ buf[l] = 0;
+ ddocDebug(4, "handleDataFile", "update sha1: %s", buf);
+ SHA1_Update(&(pctx->sctx), buf, l);
+ SHA1_Update(&(pctx->sctx2), buf, l);
+ j = i;
+ }
+#ifdef WITH_BASE64_HASHING_HACK
+ }
+#endif
+ } else if(!strcmp(pctx->ctx3, CONTENT_EMBEDDED)) {
+ if(pctx->bDataFile)
+ BIO_write(pctx->bDataFile, value, len);
+ }
+}
+
+
+//--------------------------------------------------
+// handles the end of a <DataFile> element.
+// Finishes writing file data
+// pctx - pointer to XML parsing work-area
+// name - tag name
+//--------------------------------------------------
+void handleEndDataFile(SigDocParse* pctx, const xmlChar *name)
+{
+ int l1, err;
+ long l;
+ char buf[1024], *pTmp1 = 0, *pTmp2 = 0;
+ DataFile* pDf = 0;
+ time_t t1, t2;
+ DigiDocMemBuf mbuf1;
+
+ ddocDebug(4, "handleEndDataFile", "DF: %s", pctx->ctx2);
+ if(pctx->nIgnoreDataFile > 0 && !strcmp(pctx->ctx3, CONTENT_EMBEDDED))
+ pctx->nIgnoreDataFile--;
+ if(pctx->nIgnoreDataFile)
+ return;
+ pDf = getDataFileWithId(pctx->pSigDoc, pctx->ctx2);
+ RETURN_VOID_IF_NULL(pDf);
+ RETURN_VOID_IF_NULL(pDf->szContentType);
+
+ // if store file data
+ if(pctx->bDataFile &&
+ !strcmp(pDf->szContentType, CONTENT_EMBEDDED_BASE64)) {
+ l1 = sizeof(buf);
+ EVP_DecodeFinal(&(pctx->ectx), (unsigned char*)buf, &l1);
+ BIO_write(pctx->bDataFile, buf, l1);
+ BIO_free(pctx->bDataFile);
+ pctx->bDataFile = NULL;
+ }
+ // in version 1.0 we calculate digest over original data
+ if(pctx->pSigDoc->szFormat && !strcmp(pctx->pSigDoc->szFormat, SK_XML_1_NAME)) {
+ if(!strcmp(pDf->szContentType, CONTENT_EMBEDDED_BASE64)) {
+ ddocDebug(3, "handleEndDataFile", "final sha1");
+ SHA1_Final((unsigned char*)buf, &(pctx->sctx));
+ checkErrors();
+ ddocDataFile_SetDigestValue(pDf, buf, DIGEST_LEN);
+ SHA1_Final((unsigned char*)buf, &(pctx->sctx2));
+ ddocDataFile_SetWrongDigestValue(pDf, buf, DIGEST_LEN);
+ // debug
+ l1 = sizeof(buf);
+ bin2hex(pDf->mbufDigest.pMem, pDf->mbufDigest.nLen, buf, &l1);
+ ddocDebug(3, "handleEndDataFile", "DF: %s calc digest: %s len: %d",
+ pDf->szId, buf, l1);
+ } else if(!strcmp(pDf->szContentType, CONTENT_EMBEDDED)) {
+ if(pctx->mbufElemData.pMem) {
+ l1 = sizeof(buf);
+ // remove the tag end marker
+ pTmp2 = (char*)(pctx->mbufElemData.pMem) + pctx->mbufElemData.nLen - 1;
+ while(*pTmp2 != '<' && pTmp2 > (char*)pctx->mbufElemData.pMem)
+ pTmp2--;
+ if(*pTmp2 == '<')
+ *pTmp2 = 0;
+ //skip leading newlines
+ pTmp1 = (char*)pctx->mbufElemData.pMem;
+ while(*pTmp1 && *pTmp1 != '<') pTmp1++;
+ if(pctx->bDataFile) {
+ BIO_write(pctx->bDataFile, pTmp1, strlen(pTmp1));
+ BIO_free(pctx->bDataFile);
+ pctx->bDataFile = 0;
+ }
+ err = calculateDigest((const byte*)pTmp1, strlen(pTmp1),
+ DIGEST_SHA1, (byte*)buf, &l1);
+ if(!err)
+ ddocDataFile_SetDigestValue(pDf, buf, DIGEST_LEN);
+ // free collected data
+ // and mark the end of data collecting mode
+ ddocMemBuf_free(&(pctx->mbufElemData));
+ pctx->bCollectElemData = 0;
+ }
+ } else if(pctx->checkFileDigest) {
+ l1 = sizeof(buf);
+ err = calculateFileDigest(pDf->szFileName,
+ DIGEST_SHA1, (byte*)buf, &l1, &l);
+ if(!err)
+ ddocDataFile_SetDigestValue(pDf, buf, DIGEST_LEN);
+ else
+ ddocMemBuf_free(&(pDf->mbufDigest));
+ }
+ }
+ // in version 1.1 we calculate digest over the whole <DataFile>
+ // in canonicalized form
+ else {
+ // if use base64 hack of datafile
+#ifdef WITH_BASE64_HASHING_HACK
+ if(!strcmp(pDf->szContentType, CONTENT_EMBEDDED_BASE64)) {
+ strncpy(buf, "</DataFile>", sizeof(buf));
+ ddocDebug(3, "handleEndDataFile", "final sha1 update: \'%s\'", buf);
+ mbuf1.pMem = "</DataFile>";
+ mbuf1.nLen = strlen("</DataFile>");
+ ddocDebugWriteFile(4, "df-data.txt", &mbuf1);
+ SHA1_Update(&(pctx->sctx), buf, strlen(buf));
+ SHA1_Update(&(pctx->sctx2), buf, strlen(buf));
+ memset(buf, 0, sizeof(buf));
+ SHA1_Final((unsigned char*)buf, &(pctx->sctx));
+ ddocDataFile_SetDigestValue(pDf, buf, DIGEST_LEN);
+ SHA1_Final((unsigned char*)buf, &(pctx->sctx2));
+ ddocDataFile_SetWrongDigestValue(pDf, buf, DIGEST_LEN);
+ setString((char**)&(pDf->szDigestType), DIGEST_SHA1_NAME, -1);
+ // debug
+ l1 = sizeof(buf);
+ encode((const byte*)pDf->mbufDigest.pMem, pDf->mbufDigest.nLen, (byte*)buf, &l1);
+ ddocDebug(3, "handleEndDataFile", "DF: %s calc digest: %s len: %d", pDf->szId, buf, l1);
+ ddocMemBuf_free(&(pctx->mbufElemData));
+ pctx->bCollectElemData = 0;
+ // wrong digest
+ l1 = sizeof(buf);
+ encode((const byte*)pDf->mbufWrongDigest.pMem, pDf->mbufWrongDigest.nLen, (byte*)buf, &l1);
+ ddocDebug(3, "handleEndDataFile", "DF: %s alt calc digest: %s len: %d", pDf->szId, buf, l1);
+
+ } else {
+#endif
+ // debug
+ time(&t1);
+ ddocDebug(4, "handleEndDataFile", "DF: %s data-len: %ld, parsing time: %d [sek]",
+ (const char*)name, pctx->mbufElemData.nLen, (t1 - pctx->tStartParse));
+ ddocDebug(8, "handleEndDataFile", "DF: %s data:\n%s", (const char*)name, pctx->mbufElemData.pMem);
+ if(pctx->mbufElemData.pMem) {
+ pTmp2 = canonicalizeXML((char*)pctx->mbufElemData.pMem, pctx->mbufElemData.nLen);
+ time(&t2);
+ ddocDebug(4, "handleEndDataFile", "Canonicalizing: %s, time: %d [sek]",
+ (pTmp2 ? "OK" : "ERROR"), (t2 - t1));
+ if(pTmp2) {
+ SHA1_Init(&(pctx->sctx));
+ SHA1_Update(&(pctx->sctx), pTmp2, strlen(pTmp2));
+ SHA1_Final((unsigned char*)buf,&(pctx->sctx));
+ ddocDataFile_SetDigestValue(pDf, buf, DIGEST_LEN);
+ setString((char**)&(pDf->szDigestType), DIGEST_SHA1_NAME, -1);
+ ddocDebug(4, "handleEndDataFile", "DF: %s digest updated", pDf->szId);
+ l1 = sizeof(buf);
+ encode((byte*)pDf->mbufDigest.pMem, pDf->mbufDigest.nLen, (byte*)buf, &l1);
+ ddocDebug(4, "handleEndDataFile", "DF: %s calc digest: %s len: %d", pDf->szId, buf, l1);
+ // P.R ends
+ ddocDebug(4, "handleEndDataFile", "DF: %s canonical XML: \'%s\'", pDf->szId, pTmp2);
+
+ ddocDebug(4, "handleEndDataFile", "DF: %s calc digest: %s len: %d",
+ pDf->szId, buf, l1);
+ ddocDebug(4, "handleEndDataFile", "DF: %s canonical XML: \'%s\'",
+ pDf->szId, pTmp2);
+ free(pTmp2);
+ } // if(pTmp2)
+ ddocMemBuf_free(&(pctx->mbufElemData));
+ pctx->bCollectElemData = 0;
+ } // if(pctx->mbufElemData.pMem)
+#ifdef WITH_BASE64_HASHING_HACK
+ } // else not base64 hack
+#endif
+ } // else
+}
+
+
+//--------------------------------------------------
+// handles the start of a <Signature> element.
+// Adds a SignatureInfo struct to SignedDoc structure.
+// pctx - pointer to XML parsing work-area
+// name - tag name
+// atts - attributes
+//--------------------------------------------------
+void handleStartSignature(SigDocParse* pctx, const xmlChar **atts)
+{
+ int i, j;
+ SignatureInfo *pSignatureInfo;
+
+ if(!pctx->pSigDoc || !pctx->pSigDoc->szFormat) {
+ pctx->errcode = ERR_DIGIDOC_PARSE;
+ addError(pctx->errcode, __FILE__, __LINE__, "Signature not in ddoc container!");
+ // ddocDebug(1, "handleStartSignature", "Signature has no ddoc container");
+ // SET_LAST_ERROR(ERR_DIGIDOC_PARSE);
+ return;
+ }
+ for (i = 0; (atts != NULL) && (atts[i] != NULL); i += 2) {
+ if(!strcmp((const char*)atts[i], "Id")) {
+ memset(pctx->ctx1, 0, sizeof(pctx->ctx1));
+ memset(pctx->ctx2, 0, sizeof(pctx->ctx2));
+ memset(pctx->ctx3, 0, sizeof(pctx->ctx3));
+ strncpy(pctx->ctx1, (const char*)atts[i+1], /*sizeof(pctx->ctx1)-*/50);
+ // check id uniqueness
+ for(j = 0; j < getCountOfSignatures(pctx->pSigDoc); j++) {
+ pSignatureInfo = getSignature(pctx->pSigDoc, j);
+ if(pSignatureInfo && pSignatureInfo->szId && !strcmp(pSignatureInfo->szId, (const char*)atts[i+1])) {
+ ddocDebug(1, "handleStartSignature", "Signature: %d has same id: %s", j, (const char*)atts[i+1]);
+ SET_LAST_ERROR(ERR_DIGIDOC_PARSE);
+ return;
+ }
+ }
+ SignatureInfo_new(&pSignatureInfo, pctx->pSigDoc, (const char*)atts[i+1]); // MEMLEAK: ???
+ }
+ }
+}
+
+
+
+//--------------------------------------------------
+// handles the start of a <Reference> element.
+// Records the reference URI attribute
+// pctx - pointer to XML parsing work-area
+// atts - attributes
+//--------------------------------------------------
+void handleStartReference(SigDocParse* pctx, const xmlChar **atts)
+{
+ strncpy(pctx->ctx2, ddocSaxParseFindAttrib(atts, "URI", ""), sizeof(pctx->ctx2)-1);
+}
+
+//--------------------------------------------------
+// handles the start of a <SignatureMethod> element.
+// Records the signature method
+// pctx - pointer to XML parsing work-area
+// atts - attributes
+//--------------------------------------------------
+void handleStartSignatureMethod(SigDocParse* pctx, const xmlChar **atts)
+{
+ SignatureInfo *pSigInfo;
+ const char *alg;
+
+ alg = ddocSaxParseFindAttrib(atts, "Algorithm", NULL);
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ if((alg != NULL) && (pSigInfo != NULL) &&
+ !strcmp(alg+strlen(alg)-8, "rsa-sha1") &&
+ (pctx->ctx1[0] == 'S')) {
+ ddocSignatureValue_new(&(pSigInfo->pSigValue), 0, SIGN_RSA_NAME, 0, 0);
+ }
+#ifdef WITH_ECDSA
+ else if((alg != NULL) && (pSigInfo != NULL) &&
+ !strcmp(alg+strlen(alg)-10, "ecdsa-sha1") &&
+ (pctx->ctx1[0] == 'S')) {
+ ddocSignatureValue_new(&(pSigInfo->pSigValue), 0, SIGN_ECDSA_NAME, 0, 0);
+ }
+#endif
+}
+
+
+//--------------------------------------------------
+// handles the start of a <DigestMethod> element.
+// Records the digest method
+// pctx - pointer to XML parsing work-area
+// name - tag name
+// atts - attributes
+//--------------------------------------------------
+void handleStartDigestMethod(SigDocParse* pctx, const xmlChar **atts)
+{
+ SignatureInfo *pSigInfo;
+ const char *alg;
+
+ alg = ddocSaxParseFindAttrib(atts, "Algorithm", NULL);
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ if((alg != NULL) && (pSigInfo != NULL) &&
+ !strcmp(alg+strlen(alg)-4, "sha1"))
+ strncpy(pctx->ctx3, DIGEST_SHA1_NAME, sizeof(pctx->ctx3));
+ else
+ pctx->ctx3[0] = 0;
+}
+
+//--------------------------------------------------
+// This function should be called at the end of
+// </EncapsulatedOCSPValue> to determine the correct
+// types of CertID and CertValue objects.
+// pSigInfo - signature object
+//--------------------------------------------------
+int selectCertIdAndValueTypes(SignatureInfo* pSigInfo)
+{
+ int err = ERR_OK, i, j, l1;
+ CertID* cid;
+ CertValue *cval1, *cval2;
+ X509* pCert;
+ char buf1[300];
+ DigiDocMemBuf mbuf1, mbuf2;
+ const DigiDocMemBuf *pMBuf = 0;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ for(i = 0; pSigInfo->pCertIDs &&
+ i < ddocCertIDList_GetCertIDsCount(pSigInfo->pCertIDs); i++) {
+ cid = ddocCertIDList_GetCertID(pSigInfo->pCertIDs, i);
+ ddocDebug(3, "selectCertIdAndValueTypes", "CID type: %d serial %s - %s", cid->nType, cid->szIssuerSerial, cid->szIssuerName);
+ if(cid && cid->nType == CERTID_TYPE_UNKNOWN) {
+ ddocDebug(3, "selectCertIdAndValueTypes", "Find type for cid: %s - %s", cid->szIssuerSerial, cid->szIssuerName);
+ // find corresponding CertValue
+ cval1 = NULL;
+ for(j = 0; pSigInfo->pCertValues &&
+ (j < ddocCertValueList_GetCertValuesCount(pSigInfo->pCertValues)); j++) {
+ cval2 = ddocCertValueList_GetCertValue(pSigInfo->pCertValues, j);
+ if(cval2) {
+ pCert = ddocCertValue_GetCert(cval2);
+ l1 = sizeof(buf1);
+ memset(buf1, 0, l1);
+ ReadCertSerialNumber(buf1, l1, pCert);
+ //AM 19.09.08
+ if(cid->szIssuerSerial){
+ if(!strcmp(cid->szIssuerSerial, buf1)) {
+ cval1 = cval2;
+ break; // found it
+ }
+ }
+ // should I check also hash value?
+ }
+ } // for certValues
+ // if found matching CertID and CertValue
+ if(cval1) {
+ ddocDebug(3, "selectCertIdAndValueTypes", "CertID: %s - %s -> CertValue: %s",
+ cid->szIssuerSerial, cid->szIssuerName, cval1->szId);
+ // Test1: is this an OCSP responders cert?
+ if(pSigInfo->pNotary)
+ pMBuf = (DigiDocMemBuf*)ddocNotInfo_GetResponderId(pSigInfo->pNotary);
+ if(pMBuf) {
+ if(pSigInfo->pNotary->nRespIdType == RESPID_NAME_TYPE) {
+ err = ddocCertGetSubjectCN(ddocCertValue_GetCert(cval1), &mbuf1);
+ memset(buf1, 0, sizeof(buf1));
+ findCN((char*)pMBuf->pMem, buf1, sizeof(buf1)); // defined in DigiDocConfig.c
+ if(!strcmp(buf1, (const char*)mbuf1.pMem)) {
+ // yes this is a responders cert
+ ddocDebug(3, "selectCertIdAndValueTypes", "cert: %s responder %s -> RESPONDER",
+ (const char*)mbuf1.pMem, buf1);
+ cid->nType = CERTID_TYPE_RESPONDERS_CERTID;
+ cval1->nType = CERTID_VALUE_RESPONDERS_CERT;
+ snprintf(buf1, sizeof(buf1), "%s-RESPONDERS_CERTINFO", pSigInfo->szId);
+ ddocCertID_SetId(cid, buf1);
+ }
+ ddocMemBuf_free(&mbuf1);
+ } // ByName
+ if(pSigInfo->pNotary->nRespIdType == RESPID_KEY_TYPE) {
+ err = ddocCertGetPubkeyDigest(ddocCertValue_GetCert(cval1), &mbuf1);
+ l1 = sizeof(buf1);
+ memset(buf1, 0, l1);
+ bin2hex((const byte*)mbuf1.pMem, mbuf1.nLen, buf1, &l1);
+ ddocDebug(3, "selectCertIdAndValueTypes", "cert hash: %s", buf1);
+ l1 = sizeof(buf1);
+ memset(buf1, 0, l1);
+ bin2hex((const byte*)pMBuf->pMem, pMBuf->nLen, buf1, &l1);
+ ddocDebug(3, "selectCertIdAndValueTypes", "respid: %s", buf1);
+
+ ddocEncodeBase64(&mbuf1, &mbuf2);
+ ddocMemBuf_free(&mbuf1);
+ ddocEncodeBase64(pMBuf, &mbuf1);
+ ddocDebug(3, "selectCertIdAndValueTypes", "cert: %s responder %s",
+ (const char*)mbuf2.pMem, (const char*)mbuf1.pMem);
+ if(!strcmp((const char*)mbuf2.pMem, (const char*)mbuf1.pMem)) {
+ // yes this is a responders cert
+ ddocDebug(3, "selectCertIdAndValueTypes", "cert: %s responder %s -> RESPONDER",
+ (const char*)mbuf2.pMem, (const char*)mbuf1.pMem);
+ cid->nType = CERTID_TYPE_RESPONDERS_CERTID;
+ cval1->nType = CERTID_VALUE_RESPONDERS_CERT;
+ snprintf(buf1, sizeof(buf1), "%s-RESPONDERS_CERTINFO", pSigInfo->szId);
+ ddocCertID_SetId(cid, buf1);
+ }
+ ddocMemBuf_free(&mbuf1);
+ ddocMemBuf_free(&mbuf2);
+ } // ByKey
+ } // if pMBuf
+ }
+ } // for certids
+ }
+ return err;
+}
+
+
+//--------------------------------------------------
+// handles the start of a <EncapsulatedOCSPValue> element.
+// Records the OCSP response data
+// pctx - pointer to XML parsing work-area
+// name - tag name
+//--------------------------------------------------
+// FIXME : error handling
+void handleEndEncapsulatedOCSPValue(SigDocParse* pctx)
+{
+ OCSP_RESPONSE* pResp;
+ NotaryInfo* pNotInfo = 0;
+ SignatureInfo* pSig = 0;
+
+ // convert the X509 cert data to
+ // cert and replace the pointer value
+ RETURN_VOID_IF_NULL(pctx->pSigDoc->szFormatVer);
+ pNotInfo = ddocGetLastNotaryInfo(pctx->pSigDoc);
+ RETURN_VOID_IF_NULL(pNotInfo); // VS: 1.76 correct the check
+ pSig = ddocGetLastSignature(pctx->pSigDoc);
+ RETURN_VOID_IF_NULL(pSig);
+ /*pctx->errcode =*/ ddocDecodeOCSPResponsePEMData(&pResp,
+ (const byte*)pctx->mbufElemData.pMem, (int)pctx->mbufElemData.nLen);
+ // cleanup
+ ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+ if(pResp) {
+ // in ver 1.2 we have correct OCSP digest
+ // VS 1.76 - add 1.3 version too
+ if(!strcmp(pctx->pSigDoc->szFormatVer, DIGIDOC_XML_1_2_VER) ||
+ !strcmp(pctx->pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER))
+ pctx->errcode = initializeNotaryInfoWithOCSP(pctx->pSigDoc, pNotInfo, pResp, ddocSigInfo_GetOCSPRespondersCert(pSig), 0);
+ else // in older versions the digest was incorrect
+ /*pctx->errcode =*/ initializeNotaryInfoWithOCSP(pctx->pSigDoc, pNotInfo, pResp, ddocSigInfo_GetOCSPRespondersCert(pSig), 1);
+ OCSP_RESPONSE_free(pResp);
+ } /*else
+ checkErrors();*/
+ ddocDebug(3, "handleEndEncapsulatedOCSPValue", "RC: %d", pctx->errcode);
+ if(pctx->errcode)
+ return;
+ // now we have OCSP value too
+ // determine the correct types of certid and certvalue objects now
+ /*pctx->errcode =*/ selectCertIdAndValueTypes(pSig);
+}
+
+
+//--------------------------------------------------
+// handles the start of a <SignedProperties> element.
+// Records the id and target attributes
+// pctx - pointer to XML parsing work-area
+// name - tag name
+// atts - attributes
+//--------------------------------------------------
+void handleStartSignedProperties(SigDocParse* pctx, const xmlChar **atts)
+{
+ if(!pctx->nIgnoreDataFile)
+ ddocSaxParseStartCollecting(pctx, FLAG_SIG_PART, 0);
+ strncpy(pctx->ctx2, ddocSaxParseFindAttrib(atts, "Id", ""), sizeof(pctx->ctx2)-1);
+ strncpy(pctx->ctx3, ddocSaxParseFindAttrib(atts, "Target", ""), sizeof(pctx->ctx3)-1);
+}
+
+//--------------------------------------------------
+// handles the end of a <SignedProperties> element.
+// Records the digest of this element
+// pctx - pointer to XML parsing work-area
+// name - tag name
+//--------------------------------------------------
+void handleEndSignedProperties(SigDocParse* pctx)
+{
+ char* pTmp2;
+ char buf[DIGEST_LEN+3], buf2[40];
+ int l2;
+ SignatureInfo* pSigInfo;
+ DigiDocMemBuf mbuf1;
+
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ if(pctx->mbufSigPartData.pMem && pSigInfo) {
+ ddocDebug(5, "handleEndSignedProperties", "DATA: %d ->%s",
+ pctx->mbufSigPartData.nLen, (char*)pctx->mbufSigPartData.pMem);
+ ddocDebugWriteFile(4, "sigprop-can1.txt", &(pctx->mbufSigPartData));
+ pTmp2 = canonicalizeXML((char*)pctx->mbufSigPartData.pMem, pctx->mbufSigPartData.nLen);
+
+ //dumpInFile("sigprop-can2.txt", pTmp2);
+ if(pTmp2) {
+ mbuf1.pMem = pTmp2;
+ mbuf1.nLen = strlen(pTmp2);
+ ddocDebugWriteFile(4, "sigprop-can2.txt", &mbuf1);
+ ddocDebug(5, "handleEndSignedProperties", "HASH over: \n---\n%s\n---\n",
+ pTmp2);
+ SHA1_Init(&(pctx->sctx));
+ SHA1_Update(&(pctx->sctx), pTmp2, strlen(pTmp2));
+ SHA1_Final((unsigned char*)buf,&(pctx->sctx));
+ ddocSigInfo_SetSigPropRealDigest(pSigInfo, buf, DIGEST_LEN);
+ l2 = 40;
+ encode((const byte*)buf, DIGEST_LEN, (byte*)buf2, &l2);
+ ddocDebug(5, "handleEndSignedProperties", "SigProp hash: %s", buf2);
+ free(pTmp2);
+ }
+ ddocSaxParseEndCollecting(pctx, FLAG_SIG_PART, 0);
+ pctx->checkUTF8 = 0;
+ }
+}
+
+
+//--------------------------------------------------
+// handles the start of a <SignedInfo> element.
+// Starts recording data for digest calculation
+// pctx - pointer to XML parsing work-area
+// name - tag name
+// atts - attributes
+//--------------------------------------------------
+void handleStartSignedInfo(SigDocParse* pctx)
+{
+ if(!pctx->nIgnoreDataFile) {
+ // mark the start of data collect mode
+ pctx->errcode = ddocSaxParseStartCollecting(pctx, FLAG_SIG_PART, 0);
+ pctx->checkUTF8 = 1;
+ }
+}
+
+//--------------------------------------------------
+// handles the end of a <SignedInfo> element.
+// Records the digest of this element
+// pctx - pointer to XML parsing work-area
+// name - tag name
+//--------------------------------------------------
+void handleEndSignedInfo(SigDocParse* pctx)
+{
+ char* pTmp;
+ char buf[DIGEST_LEN+3];
+ SignatureInfo* pSigInfo;
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ if(pctx->mbufSigPartData.pMem && pSigInfo) {
+ ddocDebug(5, "handleEndSignedInfo", "DATA: %d ->%s",
+ pctx->mbufSigPartData.nLen, (char*)pctx->mbufSigPartData.pMem);
+ pTmp = canonicalizeXML((char*)pctx->mbufSigPartData.pMem, pctx->mbufSigPartData.nLen);
+ ddocDebug(5, "handleEndSignedInfo", "CANONICALIZED: %d ->%s", strlen(pTmp), (char*)pTmp);
+ if(pTmp) {
+ SHA1_Init(&(pctx->sctx));
+ SHA1_Update(&(pctx->sctx), pTmp, strlen(pTmp));
+ SHA1_Final((unsigned char*)buf,&(pctx->sctx));
+ ddocSigInfo_SetSigInfoRealDigest(pSigInfo, buf, DIGEST_LEN);
+ free(pTmp);
+ }
+ pctx->errcode = ddocSaxParseEndCollecting(pctx, FLAG_SIG_PART, 0);
+ pctx->checkUTF8 = 0;
+ }
+}
+
+
+//--------------------------------------------------
+// handles the start of a <Cert> element.
+// Records the id attribute
+// pctx - pointer to XML parsing work-area
+// name - tag name
+// atts - attributes
+//--------------------------------------------------
+void handleStartCert(SigDocParse* pctx, const xmlChar **atts)
+{
+ char *p = 0, buf1[50];
+ SignatureInfo* pSigInfo = NULL;
+ CertID *pCertID = NULL;
+
+ // used in old formats
+ p = (char*)ddocSaxParseFindAttrib(atts, "Id", NULL);
+ if(p)
+ strncpy(pctx->ctx2, p, sizeof(pctx->ctx2)-1);
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ ddocDebug(3, "handleStartCert", "Sig: %s", (pSigInfo ? pSigInfo->szId : "NULL"));
+ RETURN_VOID_IF_NULL(pSigInfo);
+ // only if we are in Notary since signers cert-id is handled by <SigningCertificate>
+ if(pSigInfo->pNotary) {
+ // don't know what cert-id it's going to be
+ ddocCertID_new(&pCertID, CERTID_TYPE_UNKNOWN, 0, 0, 0, 0, 0);
+ if(!pSigInfo->pCertIDs)
+ ddocCertIDList_new(&(pSigInfo->pCertIDs));
+ ddocCertIDList_addCertID(pSigInfo->pCertIDs, pCertID);
+ snprintf(buf1, sizeof(buf1), "%s-UNKNOWN_CERTINFO", pSigInfo->szId);
+ strncpy(pctx->ctx2, buf1, sizeof(pctx->ctx2)-1);
+ }
+}
+
+
+//--------------------------------------------------
+// handles the start of a <SigningCertificate> element.
+// pctx - pointer to XML parsing work-area
+// name - tag name
+// atts - attributes
+//--------------------------------------------------
+void handleStartSigningCertificate(SigDocParse* pctx)
+{
+ SignatureInfo* pSigInfo = NULL;
+ CertID *pCertID = NULL;
+ X509* x509 = NULL;
+ int ret = 0;
+ DigiDocMemBuf mbuf1, mbuf2;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ ddocDebug(3, "handleStartSigningCertificate", "Sig: %s",
+ (pSigInfo ? pSigInfo->szId : "NULL"));
+ RETURN_VOID_IF_NULL(pSigInfo);
+ pCertID = ddocSigInfo_GetOrCreateCertIDOfType(pSigInfo, CERTID_TYPE_SIGNERS_CERTID);
+ snprintf(pctx->ctx2, sizeof(pctx->ctx2)-1, "%s-CERTINFO", pSigInfo->szId);
+ x509 = ddocSigInfo_GetSignersCert(pSigInfo);
+ if(x509){
+ ret = ddocCertGetIssuerDN(x509, &mbuf1);
+ if(ret == 0) {
+ if(pCertID && mbuf1.pMem)
+ ddocCertID_SetIssuerName(pCertID, (char*)mbuf1.pMem);
+ }
+ }
+}
+
+
+//--------------------------------------------------
+// handles the start of a <UnsignedSignatureProperties> element.
+// pctx - pointer to XML parsing work-area
+// name - tag name
+// atts - attributes
+//--------------------------------------------------
+void handleStartUnsignedSignatureProperties(SigDocParse* pctx)
+{
+ SignatureInfo* pSigInfo = NULL;
+ NotaryInfo *pNotaryInfo;
+
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ ddocDebug(3, "handleStartUnsignedSignatureProperties", "Sig: %s",
+ (pSigInfo ? pSigInfo->szId : "NULL"));
+ RETURN_VOID_IF_NULL(pSigInfo);
+ (void)NotaryInfo_new(&pNotaryInfo, pctx->pSigDoc, pSigInfo);
+}
+
+
+//--------------------------------------------------
+// handles the start of a <CompleteCertificateRefs> element.
+// Records the signature id so that we can later
+// capture responders cert digest
+// pctx - pointer to XML parsing work-area
+// name - tag name
+// atts - attributes
+//--------------------------------------------------
+void handleStartCompleteCertificateRefs(SigDocParse* pctx)
+{
+ SignatureInfo* pSigInfo = 0;
+
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ ddocDebug(3, "handleStartCompleteCertificateRefs", "Sig: %s", (pSigInfo ? pSigInfo->szId : "NULL"));
+ RETURN_VOID_IF_NULL(pSigInfo);
+ snprintf(pctx->ctx2, sizeof(pctx->ctx2)-1, "%s-RESPONDER_CERTINFO", pSigInfo->szId);
+}
+
+
+//--------------------------------------------------
+// handles the start of a <OCSPIdentifier> element.
+// Records the id attribute
+// pctx - pointer to XML parsing work-area
+// name - tag name
+// atts - attributes
+//--------------------------------------------------
+void handleStartOCSPIdentifier(SigDocParse* pctx, const xmlChar **atts)
+{
+ strncpy(pctx->ctx2, ddocSaxParseFindAttrib(atts, "URI", ""), sizeof(pctx->ctx2)-1);
+}
+
+//--------------------------------------------------
+// handles the start of a <X509Certificate> element.
+// Records the digest method
+// pctx - pointer to XML parsing work-area
+// name - tag name
+//--------------------------------------------------
+void handleEndX509Certificate(SigDocParse* pctx)
+{
+ X509* x509 = 0;
+ SignatureInfo* pSigInfo = 0;
+
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ // convert the X509 cert data to
+ // cert and replace the pointer value
+ if(pSigInfo && pctx->mbufElemData.pMem) {
+ pctx->errcode = ddocDecodeX509PEMData(&x509,
+ (const char*)pctx->mbufElemData.pMem, (int)pctx->mbufElemData.nLen);
+ if(x509)
+ ddocSigInfo_SetSignersCert(pSigInfo, x509);
+ // cleanup
+ pctx->errcode = ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+ }
+}
+
+//--------------------------------------------------
+// handles the start of a <EncapsulatedX509Certificate> element.
+// Records the signature id so that we can later
+// capture responders cert digest
+// pctx - pointer to XML parsing work-area
+// name - tag name
+// atts - attributes
+//--------------------------------------------------
+void handleStartEncapsulatedX509Certificate(SigDocParse* pctx, const xmlChar **atts)
+{
+ SignatureInfo* pSigInfo = 0;
+ const char *p1 = 0;
+ CertValue *pCertValue;
+
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ p1 = ddocSaxParseFindAttrib(atts, "Id", NULL);
+
+ ddocDebug(3, "handleStartEncapsulatedX509Certificate", "Sig: %s, type: %s",
+ (pSigInfo ? pSigInfo->szId : "NULL"), (p1 ? p1 : "NULL"));
+ RETURN_VOID_IF_NULL(pSigInfo);
+ if(p1) {
+ if(strstr(p1, "TSA_CERT"))
+ pCertValue = ddocSigInfo_GetOrCreateCertValueOfType(pSigInfo, CERTID_VALUE_TSA_CERT);
+ if(strstr(p1, "RESPONDER_CERT"))
+ pCertValue = ddocSigInfo_GetOrCreateCertValueOfType(pSigInfo, CERTID_VALUE_RESPONDERS_CERT);
+ }
+ snprintf(pctx->ctx2, sizeof(pctx->ctx2)-1, "%s-RESPONDER_CERTINFO", pSigInfo->szId);
+ pctx->errcode = ddocSaxParseStartCollecting(pctx, FLAG_XML_ELEM, 1);
+}
+
+//--------------------------------------------------
+// handles the end of a <EncapsulatedX509Certificate> element.
+// Records the digest method
+// pctx - pointer to XML parsing work-area
+// name - tag name
+//--------------------------------------------------
+void handleEndEncapsulatedX509Certificate(SigDocParse* pctx)
+{
+ X509* x509 = 0;
+ NotaryInfo* pNotInf = 0;
+ SignatureInfo* pSigInfo = 0;
+ CertValue* pCertValue = 0;
+
+ // convert the X509 cert data to cert<
+ pNotInf = ddocGetLastNotaryInfo(pctx->pSigDoc);
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ pctx->errcode = ddocDecodeX509PEMData(&x509,
+ (const char*)pctx->mbufElemData.pMem, (int)pctx->mbufElemData.nLen);
+ if(x509 && pSigInfo) {
+ pCertValue = ddocSigInfo_GetLastCertValue(pSigInfo);
+ if(pCertValue)
+ ddocCertValue_SetCert(pCertValue, x509);
+ else
+ X509_free(x509); // not found, free it
+ }
+ // cleanup
+ ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+}
+
+char* PATH_DIGEST_VALUE_SIGNED_INFO = "/SignedDoc/Signature/SignedInfo/Reference";
+char* PATH_DIGEST_VALUE_SIG_CERT = "/SignedDoc/Signature/Object/QualifyingProperties/SignedProperties/SignedSignatureProperties/SigningCertificate/Cert/CertDigest";
+char* PATH_DIGEST_VALUE_CERT_REF = "/SignedDoc/Signature/Object/QualifyingProperties/UnsignedProperties/UnsignedSignatureProperties/CompleteCertificateRefs/CertRefs/Cert/CertDigest";
+char* PATH_DIGEST_VALUE_CERT_REF_1_0 = "/SignedDoc/Signature/Object/QualifyingProperties/UnsignedProperties/UnsignedSignatureProperties/CompleteCertificateRefs/Cert/CertDigest";
+char* PATH_DIGEST_VALUE_RVOK_REFS = "/SignedDoc/Signature/Object/QualifyingProperties/UnsignedProperties/UnsignedSignatureProperties/CompleteRevocationRefs/OCSPRefs/OCSPRef/DigestAlgAndValue";
+
+int checkValidDigestValPath(SigDocParse* pctx, SignatureInfo* pSigInfo)
+{
+ if(pctx && pctx->mbufTags.pMem) {
+ if(!strcmp((const char*)pctx->mbufTags.pMem, PATH_DIGEST_VALUE_CERT_REF_1_0)) {
+ pSigInfo->nErr1 = ERR_VER_1_0;
+ ddocDebug(1, "VER 1.0", "Ver 1.0 signature! Found element DigestValue in path: %s format: %s ver: %s", (const char*)pctx->mbufTags.pMem, pctx->pSigDoc->szFormat, pctx->pSigDoc->szFormatVer);
+ if(strcmp(pctx->pSigDoc->szFormat, SK_XML_1_NAME) &&
+ (strcmp(pctx->pSigDoc->szFormat, DIGIDOC_XML_1_1_NAME) ||
+ !strcmp(pctx->pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER))) {
+ ddocDebug(1, "checkValidDigestValPath10-12", "Invalid XML! Found element DigestValue in path: %s format: %s ver: %s", (const char*)pctx->mbufTags.pMem, pctx->pSigDoc->szFormat, pctx->pSigDoc->szFormatVer);
+ SET_LAST_ERROR(ERR_DIGIDOC_PARSE);
+ if(pSigInfo && !pSigInfo->nErr1)
+ pSigInfo->nErr1 = ERR_DIGIDOC_PARSE;
+ return ERR_DIGIDOC_PARSE;
+ }
+
+ } else {
+ if(strcmp((const char*)pctx->mbufTags.pMem, PATH_DIGEST_VALUE_SIGNED_INFO) &&
+ strcmp((const char*)pctx->mbufTags.pMem, PATH_DIGEST_VALUE_SIG_CERT) &&
+ strcmp((const char*)pctx->mbufTags.pMem, PATH_DIGEST_VALUE_CERT_REF) &&
+ strcmp((const char*)pctx->mbufTags.pMem, PATH_DIGEST_VALUE_RVOK_REFS)) {
+ ddocDebug(1, "checkValidDigestValPath", "Invalid XML! Found element DigestValue in path: %s format: %s ver: %s", (const char*)pctx->mbufTags.pMem, pctx->pSigDoc->szFormat, pctx->pSigDoc->szFormatVer);
+ SET_LAST_ERROR(ERR_DIGIDOC_PARSE);
+ if(pSigInfo && !pSigInfo->nErr1)
+ pSigInfo->nErr1 = ERR_DIGIDOC_PARSE;
+ return ERR_DIGIDOC_PARSE;
+ }
+ }
+ }
+ return 0;
+}
+
+char* PATH_CLAIMED_ROLE = "/SignedDoc/Signature/Object/QualifyingProperties/SignedProperties/SignedSignatureProperties/SignerRole/ClaimedRoles";
+
+int checkValidClaimedRolePath(SigDocParse* pctx, SignatureInfo* pSigInfo)
+{
+ if(pctx && pctx->mbufTags.pMem) {
+ if(strcmp((const char*)pctx->mbufTags.pMem, PATH_CLAIMED_ROLE)) {
+ ddocDebug(1, "checkValidClaimedRolePath", "Invalid XML! Found element ClaimedRole in path: %s", (const char*)pctx->mbufTags.pMem);
+ SET_LAST_ERROR(ERR_DIGIDOC_PARSE);
+ if(pSigInfo && !pSigInfo->nErr1)
+ pSigInfo->nErr1 = ERR_DIGIDOC_PARSE;
+ return ERR_DIGIDOC_PARSE;
+ }
+ }
+ return 0;
+}
+
+//--------------------------------------------------
+// handles the content of a <DigestValue> element.
+// Decodes and reads in digest value
+// pctx - pointer to XML parsing work-area
+// name - tag name
+// atts - attributes
+//--------------------------------------------------
+void handleEndDigestValue(SigDocParse* pctx)
+{
+ char id[100], type[100];
+ SignatureInfo* pSigInfo = NULL;
+ NotaryInfo* pNotInfo = NULL;
+ DocInfo* pDocInfo = NULL;
+ CertID* pCertID = NULL;
+ DigiDocMemBuf mbuf1;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ ddocDebug(4, "handleDigestValue", "DF: %s value: %s len: %d",
+ pctx->ctx2, (char*)pctx->mbufElemData.pMem, pctx->mbufElemData.nLen);
+ // decode digest value
+ ddocDecodeBase64(&(pctx->mbufElemData), &mbuf1);
+ ddocDebug(4, "handleDigestValue", "decoded len: %ld", mbuf1.nLen);
+ // cleanup
+ ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+ // find current signature
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ RETURN_VOID_IF_NULL(pSigInfo);
+ if(checkValidDigestValPath(pctx, pSigInfo))
+ return;
+
+ decodeURI(pctx->ctx2, id, sizeof(id), type, sizeof(type));
+ ddocDebug(4, "handleDigestValue", "ctx2: %s id: %s type: %s", pctx->ctx2, id, type);
+ if(id[0] == 'D' || !strcmp(id, "null")) {
+ RETURN_VOID_IF_NULL(pSigInfo);
+ pDocInfo = getDocInfoWithId(pSigInfo, id);
+ if(!strcmp(type, "MimeType") ||
+ !strcmp(type, "MIME")) {
+ if(pDocInfo == NULL) {
+ addDocInfo(&pDocInfo, pSigInfo, id, pctx->ctx3,
+ NULL, 0, (const byte*)mbuf1.pMem, mbuf1.nLen);
+ } else
+ setDocInfoMimeDigest(pDocInfo, (const byte*)mbuf1.pMem, mbuf1.nLen);
+ }
+ else {
+ if(pDocInfo == NULL) {
+ addDocInfo(&pDocInfo, pSigInfo, id, pctx->ctx3,
+ (const byte*)mbuf1.pMem, mbuf1.nLen, NULL, 0); // MEMLEAK: ???
+ } else
+ setDocInfoDigest(pDocInfo, (const byte*)mbuf1.pMem, mbuf1.nLen, pctx->ctx3);
+ }
+ }
+ if(id[0] == 'S') {
+ if(!strcmp(type, "SignedProperties")) {
+ RETURN_VOID_IF_NULL(pSigInfo);
+ ddocSigInfo_SetSigPropDigest(pSigInfo, (const char*)mbuf1.pMem, mbuf1.nLen);
+ }
+ if(!strcmp(type, "CERTINFO")) {
+ RETURN_VOID_IF_NULL(pSigInfo);
+ pCertID = ddocSigInfo_GetOrCreateCertIDOfType(pSigInfo, CERTID_TYPE_SIGNERS_CERTID);
+ RETURN_VOID_IF_NULL(pCertID);
+ ddocCertID_SetDigestValue(pCertID, (const char*)mbuf1.pMem, mbuf1.nLen);
+ }
+ if(!strcmp(type, "UNKNOWN_CERTINFO")) {
+ pCertID = ddocCertIDList_GetLastCertID(pSigInfo->pCertIDs);
+ RETURN_VOID_IF_NULL(pCertID);
+ ddocCertID_SetDigestValue(pCertID, (const char*)mbuf1.pMem, mbuf1.nLen);
+ }
+ }
+ if(id[0] == 'N') {
+ pNotInfo = getNotaryWithId(pctx->pSigDoc, id);
+ SET_LAST_ERROR_RETURN_VOID_IF_NOT(pNotInfo, ERR_OCSP_WRONG_RESPID);
+ ddocNotInfo_SetOcspDigest(pNotInfo, (const char*)mbuf1.pMem, mbuf1.nLen);
+ }
+ ddocMemBuf_free(&mbuf1);
+}
+
+
+//--------------------------------------------------
+// handles the content of a <SigningTime> element.
+// Reads in timestamp data
+// pctx - pointer to XML parsing work-area
+// value - character values read from file
+// len - length of chars ???
+//--------------------------------------------------
+void handleEndSigningTime(SigDocParse* pctx)
+{
+ SignatureInfo *pSigInfo;
+
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ RETURN_VOID_IF_NULL(pSigInfo);
+ if(pctx->mbufElemData.pMem) {
+ setString(&(pSigInfo->szTimeStamp), (char*)pctx->mbufElemData.pMem, -1);
+ ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+ }
+}
+
+#define ADR_ENTRY_CITY 1
+#define ADR_ENTRY_STATE 2
+#define ADR_ENTRY_COUNTRY 3
+#define ADR_ENTRY_ZIP 4
+
+//--------------------------------------------------
+// Handles address entry
+// pctx - pointer to XML parsing work-area
+//
+// value - character values read from file
+// len - length of chars ???
+//--------------------------------------------------
+void handleAdrEntry(SigDocParse* pctx, int nAdr)
+{
+ SignatureInfo* pSigInfo;
+
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ if(pSigInfo && pctx->mbufElemData.pMem) {
+ switch(nAdr) {
+ case ADR_ENTRY_CITY:
+ setString(&(pSigInfo->sigProdPlace.szCity), (const char*)pctx->mbufElemData.pMem, -1);
+ break;
+ case ADR_ENTRY_STATE:
+ setString(&(pSigInfo->sigProdPlace.szStateOrProvince), (const char*)pctx->mbufElemData.pMem, -1);
+ break;
+ case ADR_ENTRY_COUNTRY:
+ setString(&(pSigInfo->sigProdPlace.szCountryName), (const char*)pctx->mbufElemData.pMem, -1);
+ break;
+ case ADR_ENTRY_ZIP:
+ setString(&(pSigInfo->sigProdPlace.szPostalCode), (const char*)pctx->mbufElemData.pMem, -1);
+ break;
+ }
+ }
+ ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+}
+
+//--------------------------------------------------
+// handles the start of a <ClaimedRole> element.
+// Stores the collected claimed role
+// pctx - pointer to XML parsing work-area
+// name - tag name
+//--------------------------------------------------
+void handleEndClaimedRole(SigDocParse* pctx)
+{
+ SignatureInfo* pSigInfo;
+
+ if(pctx->mbufElemData.pMem) {
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ if(checkValidClaimedRolePath(pctx, pSigInfo)) return;
+ RETURN_VOID_IF_NULL(pSigInfo);
+ addSignerRole(pSigInfo, 0, (const char*)pctx->mbufElemData.pMem, -1, 0);
+ ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+ pctx->bNoXMLElemData = 0;
+ }
+}
+
+//--------------------------------------------------
+// handles the start of a <CertifiedRole> element.
+// Stores the collected certified role
+// pctx - pointer to XML parsing work-area
+// name - tag name
+//--------------------------------------------------
+void handleEndCertifiedRole(SigDocParse* pctx)
+{
+ SignatureInfo* pSigInfo;
+
+ if(pctx->mbufElemData.pMem) {
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ RETURN_VOID_IF_NULL(pSigInfo);
+ addSignerRole(pSigInfo, 1, (const char*)pctx->mbufElemData.pMem, -1, 0);
+ ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+ }
+}
+
+//--------------------------------------------------
+// handles the end of a <IssuerSerial> element.
+// Reads in cert isseur serial number
+// pctx - pointer to XML parsing work-area
+// value - character values read from file
+// len - length of chars ???
+//--------------------------------------------------
+void handleEndIssuerSerial(SigDocParse* pctx)
+{
+ SignatureInfo* pSigInfo;
+ char id[20], type[20];
+ CertID* pCertID;
+
+ decodeURI(pctx->ctx2, id, sizeof(id), type, sizeof(type));
+ if(!strcmp(type, "CERTINFO")) {
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ pCertID = ddocSigInfo_GetCertIDOfType(pSigInfo, CERTID_TYPE_SIGNERS_CERTID);
+ if(pCertID && pctx->mbufElemData.pMem)
+ ddocCertID_SetIssuerSerial(pCertID, (char*)pctx->mbufElemData.pMem);
+ }
+ if(!strcmp(type, "UNKNOWN_CERTINFO")) {
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ pCertID = ddocCertIDList_GetLastCertID(pSigInfo->pCertIDs);
+ if(pCertID && pctx->mbufElemData.pMem)
+ ddocCertID_SetIssuerSerial(pCertID, (char*)pctx->mbufElemData.pMem);
+ }
+ ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+}
+
+//--------------------------------------------------
+// handles the end of a <IssuerName> element.
+// Reads in cert isseur serial number
+// pctx - pointer to XML parsing work-area
+// value - character values read from file
+// len - length of chars ???
+//--------------------------------------------------
+void handleEndIssuerName(SigDocParse* pctx)
+{
+ SignatureInfo* pSigInfo;
+ char id[20], type[20];
+ CertID* pCertID;
+
+ decodeURI(pctx->ctx2, id, sizeof(id), type, sizeof(type));
+ if(!strcmp(type, "CERTINFO")) {
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ pCertID = ddocSigInfo_GetCertIDOfType(pSigInfo, CERTID_TYPE_SIGNERS_CERTID);
+ ddocDebug(3, "handleEndIssuerName", "Issuer name: %s", pctx->mbufElemData.pMem);
+ if(pCertID && pctx->mbufElemData.pMem)
+ ddocCertID_SetIssuerName(pCertID, (char*)pctx->mbufElemData.pMem);
+ }
+ if(!strcmp(type, "UNKNOWN_CERTINFO")) {
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ pCertID = ddocCertIDList_GetLastCertID(pSigInfo->pCertIDs);
+ if(pCertID && pctx->mbufElemData.pMem)
+ ddocCertID_SetIssuerName(pCertID, (char*)pctx->mbufElemData.pMem);
+ }
+ ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+}
+
+//--------------------------------------------------
+// tests if this is a textform responder id
+// we base the test on existence of certain
+// key elements in a DN.
+// return 1 if it is text form
+//--------------------------------------------------
+int isTextResponderId(const char* szRespId)
+{
+ return strstr(szRespId, "CN=") && strstr(szRespId, "C=");
+}
+
+//--------------------------------------------------
+// handles the end of a </ResponderId> or <ByName> element.
+// Reads in ResponderId data
+// pctx - pointer to XML parsing work-area
+// value - character values read from file
+// len - length of chars ???
+//--------------------------------------------------
+void handleEndResponderID(SigDocParse* pctx)
+{
+ NotaryInfo* pNotInf;
+ DigiDocMemBuf mbuf1;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ RETURN_VOID_IF_NULL(pctx->pSigDoc->szFormatVer);
+ pNotInf = ddocGetLastNotaryInfo(pctx->pSigDoc);
+ ddocDebug(3, "handleEndResponderId", "notary: %s id: %s, len: %d",
+ (pNotInf ? pNotInf->szId : "NULL"), (const char*)pctx->mbufElemData.pMem, pctx->mbufElemData.nLen);
+ if(pNotInf && pctx->mbufElemData.pMem) {
+ // in earlier format we din't have <ByName> and <ByKey>
+ // so we must detect if this is text or base64
+ if(isTextResponderId((const char*)pctx->mbufElemData.pMem)) {
+ pctx->errcode = ddocNotInfo_SetResponderId(pNotInf, (const char*)pctx->mbufElemData.pMem, pctx->mbufElemData.nLen);
+ pNotInf->nRespIdType = RESPID_NAME_TYPE;
+ } else {
+ ddocDecodeBase64Data(pctx->mbufElemData.pMem, pctx->mbufElemData.nLen, &mbuf1);
+ pctx->errcode = ddocNotInfo_SetResponderId(pNotInf, (const char*)mbuf1.pMem, mbuf1.nLen);
+ pNotInf->nRespIdType = RESPID_KEY_TYPE;
+ }
+ pctx->errcode = ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+ }
+}
+
+//--------------------------------------------------
+// handles the end of a </ProducedAt>
+// Reads in OCSP ProducedAt timestamp
+// pctx - pointer to XML parsing work-area
+// value - character values read from file
+// len - length of chars ???
+//--------------------------------------------------
+void handleEndProducedAt(SigDocParse* pctx)
+{
+ NotaryInfo* pNotInf = NULL;
+
+ RETURN_VOID_IF_NULL(pctx->pSigDoc);
+ pNotInf = ddocGetLastNotaryInfo(pctx->pSigDoc);
+ RETURN_VOID_IF_NULL(pNotInf);
+ ddocDebug(3, "handleEndProducedAt", "notary: %s produced at: %s len: %d",
+ (pNotInf ? pNotInf->szId : "NULL"), (const char*)pctx->mbufElemData.pMem, pctx->mbufElemData.nLen);
+ if(pNotInf && pctx->mbufElemData.pMem) {
+ setString(&(pNotInf->szProducedAt), (const char*)pctx->mbufElemData.pMem, -1 /* pctx->mbufElemData.nLen*/);
+ pctx->errcode = ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+ }
+}
+
+//--------------------------------------------------
+// handles the end of a <ByKey> element.
+// Reads in ResponderId data
+// pctx - pointer to XML parsing work-area
+// value - character values read from file
+// len - length of chars ???
+//--------------------------------------------------
+void handleEndByKey(SigDocParse* pctx)
+{
+ NotaryInfo* pNotInf;
+ DigiDocMemBuf mbuf1;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ pNotInf = ddocGetLastNotaryInfo(pctx->pSigDoc);
+ ddocDebug(3, "handleEndByKey", "notary: %s id: %s, len: %d",
+ (pNotInf ? pNotInf->szId : "NULL"), (const char*)pctx->mbufElemData.pMem, pctx->mbufElemData.nLen);
+ if(pNotInf && pctx->mbufElemData.pMem) {
+ ddocDecodeBase64Data(pctx->mbufElemData.pMem, pctx->mbufElemData.nLen, &mbuf1);
+ pctx->errcode = ddocNotInfo_SetResponderId(pNotInf, (const char*)mbuf1.pMem, mbuf1.nLen);
+ pctx->errcode = ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+ pNotInf->nRespIdType = RESPID_KEY_TYPE;
+ }
+ ddocMemBuf_free(&mbuf1);
+}
+
+//--------------------------------------------------
+// handles the end of a <SignatureValue> element.<
+// Decodes the base64 data in a buffer and assigns
+// to signature value
+// pctx - pointer to XML parsing work-area
+// name - tag name
+//--------------------------------------------------
+void handleEndSignatureValue(SigDocParse* pctx)
+{
+ SignatureInfo* pSigInfo;
+ DigiDocMemBuf mbuf1, mbuf2;
+ char *p1 = 0, *p2 = 0;
+ int l1;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ RETURN_VOID_IF_NULL(pctx->pSigDoc->szFormatVer);
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ // decode signature value
+ p1 = strchr((const char*)pctx->mbufElemData.pMem, '>');
+ if(p1)
+ p2 = strchr((const char*)p1, '<');
+ if(p1 && p2) {
+ p1++;
+ *p2 = 0;
+ l1 = strlen(p1) + 10;
+ ddocMemSetLength(&mbuf1, l1);
+ decode((const byte*)p1, strlen(p1), (byte*)mbuf1.pMem, &l1);
+ mbuf1.nLen = l1;
+ if(pSigInfo && mbuf1.nLen > 0)
+ ddocSigInfo_SetSignatureValue(pSigInfo, (char*)mbuf1.pMem, mbuf1.nLen);
+ ddocMemBuf_free(&mbuf1);
+ }
+ // cleanup
+ ddocSaxParseEndCollecting(pctx, FLAG_TS_INP, 0);
+}
+
+//--------------------------------------------------
+// Collects elements start-tag
+// pctx - pointer to XML parsing work-area
+// name - xml element tag name
+// atts - xml atributes
+// pcFlag - pointer to flag governing collection of this element
+// pMBuf - DigiDocMemBuf to collect it in
+//--------------------------------------------------
+int ddocSaxParseCollectStartTag(SigDocParse* pctx, const xmlChar *name, const xmlChar **atts,
+ char *pcFlag, DigiDocMemBuf* pMBuf)
+{
+ int i, addXmlns = 0, addXmlns3 = 0;
+ char *p = 0;
+ // if we are in collect data mode then
+ // record this tag data
+ if(*pcFlag) {
+ // don't use this attribute for 1.0 format
+ if(pctx->pSigDoc->szFormatVer && (!strcmp(pctx->pSigDoc->szFormatVer, DIGIDOC_XML_1_1_VER) ||
+ !strcmp(pctx->pSigDoc->szFormatVer, DIGIDOC_XML_1_2_VER)) &&
+ (!strcmp((const char*)name, "SignedProperties") ||
+ !strcmp((const char*)name, "SignedInfo"))) // must have this attribute
+ addXmlns = 1;
+ else
+ addXmlns = 0; // don't need this atribute
+ ddocDebug(3, "ddocSaxParseCollectStartTag", "Format: %s name: %s", pctx->pSigDoc->szFormatVer, (const char*)name);
+ if(pctx->pSigDoc->szFormatVer && !strcmp((const char*)name, "DataFile")) {
+ if(!strcmp(pctx->pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER)) // must have this attribute
+ addXmlns3 = 1;
+ }
+ pctx->errcode = ddocMemAppendData(pMBuf, "<", -1);
+ if(!pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, (const char*)name, -1);
+ for (i = 0; !pctx->errcode && (atts != NULL) && (atts[i] != NULL); i += 2) {
+ pctx->errcode = ddocMemAppendData(pMBuf, " ", -1);
+ if(!pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, (const char*)atts[i], -1);
+ if(!pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, "=\"", -1);
+ if(!pctx->errcode) {
+ escapeXMLSymbols((const char*)atts[i+1], -1, &p);
+ if(p) {
+ pctx->errcode = ddocMemAppendData(pMBuf, p, -1);
+ free(p);
+ }
+ }
+ if(!pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, "\"", -1);
+ if(!strcmp((const char*)atts[i], "xmlns")) {
+ addXmlns = 0; // already has this atribute
+ addXmlns3 = 0;
+ }
+ } // for
+ if(addXmlns && !pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, " xmlns=\"http://www.w3.org/2000/09/xmldsig#\"", -1);
+ if(addXmlns3 && !pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, " xmlns=\"http://www.sk.ee/DigiDoc/v1.3.0#\"", -1);
+ if(!pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, ">", -1);
+ ddocDebug(3, "ddocSaxParseCollectStartTag", "Element tag collected: %d - %s", pMBuf->nLen, (char*)pMBuf->pMem);
+ }
+ return pctx->errcode;
+}
+
+//--------------------------------------------------
+// Collects elements start-tag. Used for ddoc 1.3 alternate DataFile hash calc
+// pctx - pointer to XML parsing work-area
+// name - xml element tag name
+// atts - xml atributes
+// pMBuf - DigiDocMemBuf to collect it in
+//--------------------------------------------------
+int ddocSaxParseCollectDf3AltStartTag(SigDocParse* pctx, const xmlChar *name, const xmlChar **atts, DigiDocMemBuf* pMBuf)
+{
+ int i;
+ char *p = 0;
+ // if we are in collect data mode then
+ // record this tag data
+ pctx->errcode = ddocMemAppendData(pMBuf, "<", -1);
+ if(!pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, (const char*)name, -1);
+ for (i = 0; !pctx->errcode && (atts != NULL) && (atts[i] != NULL); i += 2) {
+ pctx->errcode = ddocMemAppendData(pMBuf, " ", -1);
+ if(!pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, (const char*)atts[i], -1);
+ if(!pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, "=\"", -1);
+ if(!pctx->errcode) {
+ escapeXMLSymbols((const char*)atts[i+1], -1, &p);
+ if(p) {
+ pctx->errcode = ddocMemAppendData(pMBuf, p, -1);
+ free(p);
+ }
+ }
+ if(!pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, "\"", -1);
+ } // for
+ if(!pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, ">", -1);
+ ddocDebug(3, "ddocSaxParseCollectDf3AltStartTag", "Element tag collected: %d - %s", pMBuf->nLen, (char*)pMBuf->pMem);
+ return pctx->errcode;
+}
+
+
+/**
+ * startElementHandler:
+ * @ctxt: An XML parser context
+ * @name: The element name
+ *
+ * called when an opening tag has been processed.
+ */
+static void startElementHandler(void *ctx, const xmlChar *name, const xmlChar **atts)
+{
+ SigDocParse* pctx = (SigDocParse*)ctx;
+ char *pTmp1 = NULL;
+ const char *sXmlns;
+ DigiDocMemBuf mbuf1, mbuf2;
+ SignatureInfo* pSig;
+ XmlElemInfo* eEl = NULL;
+
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ strncpy(pctx->tag, (const char*)name, sizeof(pctx->tag));
+ XmlElemInfo_new(&eEl, NULL, (const char*)name);
+ if(!pctx->eRoot)
+ pctx->eRoot = eEl;
+ if(pctx->eCurr) {
+ XmlElemInfo_addChild(pctx->eCurr, eEl);
+ }
+ pctx->eCurr = eEl;
+ pctx->errcode = validateElementPath(pctx->eCurr);
+ // do nothing if error has ocurred
+ if(pctx->errcode) return;
+ ddocMemPush(&(pctx->mbufTags), (const char*)name);
+ ddocDebug(4, "startElementHandler", "<%s> path: %s", (const char*)name, (const char*)pctx->mbufTags.pMem);
+
+ //printf("<%s>\n", (const char*)name);
+ if(!strcmp((const char*)name, "DataFile")) {
+ pctx->bCollectDFData++; // increment bypass mode
+ if(pctx->bCollectDFData == 1) // only the first time
+ handleStartDataFile(pctx, name, atts);
+ // collect wrong/alternate digest for ddoc 1.3
+ ddocSaxParseCollectDf3AltStartTag(pctx, name, atts, &mbuf2);
+ }
+ if(!strcmp((const char*)name, "SignedProperties"))
+ handleStartSignedProperties(pctx, atts);
+ if(!strcmp((const char*)name, "SignedInfo"))
+ handleStartSignedInfo(pctx);
+ // if we are not in a <DataFile> and we encounter
+ // the <Signature> tag then start collecting original content
+ if(!pctx->nIgnoreDataFile &&
+ (!strcmp((const char*)name, "Signature") || pctx->bCollectSigData)) {
+ if(!strcmp((const char*)name, "Signature"))
+ pctx->errcode = ddocSaxParseStartCollecting(pctx, FLAG_SIGNATURE, 0);
+ // collect general <Signature> data<
+ ddocSaxParseCollectStartTag(pctx, name, atts, &(pctx->bCollectSigData), &(pctx->mbufSigData));
+ }
+ // we need the tags here because of hash value calculation
+ // collect general tag data
+ if(!strcmp((const char*)name, "SignatureValue"))
+ pctx->errcode = ddocSaxParseStartCollecting(pctx, FLAG_XML_ELEM, 0);
+ ddocSaxParseCollectStartTag(pctx, name, atts, &(pctx->bCollectElemData), &(pctx->mbufElemData));
+ // use base64 DataFile parsing optimization
+ // only possible if: a) not 1.0 format b) base64 content c) check config settings
+#ifdef WITH_BASE64_HASHING_HACK
+ if((pctx->bCollectDFData == 1) && pctx->pSigDoc->szFormatVer && pctx->pSigDoc->szFormat &&
+ (strcmp(pctx->pSigDoc->szFormatVer, SK_XML_1_VER) && strcmp(pctx->pSigDoc->szFormat, SK_XML_1_NAME))&&
+ !strcmp(pctx->ctx3, CONTENT_EMBEDDED_BASE64) ) {
+ // append end tag
+ ddocMemAppendData(&(pctx->mbufElemData), "</DataFile>", -1);
+ pTmp1 = canonicalizeXML((char*)pctx->mbufElemData.pMem, pctx->mbufElemData.nLen);
+ if(pTmp1) {
+ // remove end tag again after canonicalization
+ pTmp1[strlen(pTmp1) - 11] = 0;
+ ddocDebug(4, "startElementHandler", "Initial sha1 update: \'%s\'", pTmp1);
+ mbuf1.pMem = pTmp1;
+ mbuf1.nLen = strlen(pTmp1);
+ ddocDebugWriteFile(4, "df-data.txt", &mbuf1);
+ SHA1_Update(&(pctx->sctx), pTmp1, strlen(pTmp1));
+ free(pTmp1);
+ pTmp1 = NULL;
+ }
+ // handle alternate digest
+ ddocMemAppendData(&mbuf2, "</DataFile>", -1);
+ pTmp1 = canonicalizeXML((char*)mbuf2.pMem, mbuf2.nLen);
+ if(pTmp1) {
+ // remove end tag again after canonicalization
+ pTmp1[strlen(pTmp1) - 11] = 0;
+ ddocDebug(4, "startElementHandler", "Initial alt sha1 update: \'%s\'", pTmp1);
+ SHA1_Update(&(pctx->sctx2), pTmp1, strlen(pTmp1));
+ free(pTmp1);
+ }
+ ddocMemBuf_free(&(pctx->mbufElemData));
+ }
+#endif
+ if(mbuf2.pMem)
+ ddocMemBuf_free(&mbuf2);
+ // collect general <SignedProperties> data
+ ddocSaxParseCollectStartTag(pctx, name, atts, &(pctx->bCollectSigPartData), &(pctx->mbufSigPartData));
+ // check other start-tag-actions
+ if(!pctx->nIgnoreDataFile) {
+ if(!strcmp((const char*)name, "SignedDoc"))
+ handleStartSignedDoc(pctx, name, atts);
+ if(!strcmp((const char*)name, "Signature"))
+ handleStartSignature(pctx, atts);
+ if(!strcmp((const char*)name, "Reference"))
+ handleStartReference(pctx, atts);
+ if(!strcmp((const char*)name, "SignatureMethod"))
+ handleStartSignatureMethod(pctx, atts);
+ if(!strcmp((const char*)name, "DigestMethod"))
+ handleStartDigestMethod(pctx, atts);
+ if(!strcmp((const char*)name, "Cert"))
+ handleStartCert(pctx, atts);
+ /*if(!strcmp((const char*)name, "ResponderID")) // TODO: do we need it ???
+ handleStartResponderId(pctx, name, atts);*/
+ /* if(!strcmp((const char*)name, "Certificate")) // TODO: do we need it ???
+ handleStartCertificate(pctx, name, atts);*/
+ if(!strcmp((const char*)name, "UnsignedSignatureProperties"))
+ handleStartUnsignedSignatureProperties(pctx);
+ if(!strcmp((const char*)name, "OCSPIdentifier"))
+ handleStartOCSPIdentifier(pctx, atts);
+ if(!strcmp((const char*)name, "SigningCertificate"))
+ handleStartSigningCertificate(pctx);
+ if(!strcmp((const char*)name, "CompleteCertificateRefs"))
+ handleStartCompleteCertificateRefs(pctx);
+ if(!strcmp((const char*)name, "EncapsulatedX509Certificate"))
+ handleStartEncapsulatedX509Certificate(pctx, atts);
+ // start collecting but release old if exists
+ if(!strcmp((const char*)name, "X509SerialNumber") ||
+ !strcmp((const char*)name, "X509IssuerName")) {
+ // check xmlns
+ sXmlns = ddocSaxParseFindAttrib(atts, "xmlns", NULL);
+ if(sXmlns == NULL || strcmp(sXmlns, NAMESPACE_XML_DSIG)) {
+ ddocDebug(1, "startElementHandler", "Invalid namespace %s for element: %s", sXmlns, name);
+ SET_LAST_ERROR(ERR_ISSUER_XMLNS);
+ //pctx->errcode = ERR_ISSUER_XMLNS;
+ pSig = ddocGetLastSignature(pctx->pSigDoc);
+ if(pSig && !pSig->nErr1)
+ pSig->nErr1 = ERR_ISSUER_XMLNS; // store this erro code by signature because it can't be found after parsing
+ }
+ ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+ pctx->errcode = ddocSaxParseStartCollecting(pctx, FLAG_XML_ELEM, 1);
+
+ }
+ // start collecting but release old if exists
+ if((!strcmp((const char*)name, "Transform") ||
+ !strcmp((const char*)name, "Transforms")) &&
+ pctx->pSigDoc->szFormat && !strcmp(pctx->pSigDoc->szFormat, DIGIDOC_XML_1_1_NAME)) {
+ SET_LAST_ERROR(ERR_TRANSFORM_UNSUPPORTED);
+ pSig = ddocGetLastSignature(pctx->pSigDoc);
+ if(pSig && !pSig->nErr1)
+ pSig->nErr1 = ERR_TRANSFORM_UNSUPPORTED; // store this erro code
+ }
+ // start collecting data of these elements
+ if(!strcmp((const char*)name, "CertifiedRole") ||
+ !strcmp((const char*)name, "ClaimedRole") ||
+ !strcmp((const char*)name, "DigestValue") ||
+ !strcmp((const char*)name, "EncapsulatedOCSPValue") ||
+ !strcmp((const char*)name, "EncapsulatedTimeStamp") ||
+ !strcmp((const char*)name, "X509Certificate") ||
+ !strcmp((const char*)name, "SigningTime") ||
+ !strcmp((const char*)name, "ResponderID") ||
+ !strcmp((const char*)name, "ProducedAt") ||
+ !strcmp((const char*)name, "ByName") ||
+ !strcmp((const char*)name, "ByKey") ||
+ !strcmp((const char*)name, "City") ||
+ !strcmp((const char*)name, "StateOrProvince") ||
+ !strcmp((const char*)name, "PostalCode") ||
+ !strcmp((const char*)name, "CountryName") ||
+ !strcmp((const char*)name, "IssuerSerial")
+ )
+ pctx->errcode = ddocSaxParseStartCollecting(pctx, FLAG_XML_ELEM, 1);
+ }
+}
+
+//--------------------------------------------------
+// Collects elements end-tag
+// pctx - pointer to XML parsing work-area
+// name - xml element tag name
+// pcFlag - pointer to flag governing collection of this element
+// pMBuf - DigiDocMemBuf to collect it in
+//--------------------------------------------------
+int ddocSaxParseCollectEndElement(SigDocParse* pctx, const xmlChar *name,
+ char* pcFlag, DigiDocMemBuf* pMBuf)
+{
+ if(*pcFlag) {
+ if(!pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, "</", -1);
+ if(!pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, (const char*)name, -1);
+ if(!pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, ">", -1);
+ }
+ return pctx->errcode;
+}
+
+/**
+ * endElementHandler:
+ * @ctxt: An XML parser context
+ * @name: The element name
+ *
+ * called when the end of an element has been detected.
+ */
+static void endElementHandler(void *ctx, const xmlChar *name)
+{
+ SignatureInfo* pSigInfo = NULL;
+ SigDocParse* pctx = (SigDocParse*)ctx;
+ const char* pTag = 0;
+
+ // do nothing if error has ocurred
+ if(pctx->errcode) return;
+ pTag = ddocMemPop(&(pctx->mbufTags));
+ if(pctx->eCurr)
+ pctx->eCurr =pctx->eCurr->pParent;
+ ddocDebug(4, "endElementHandler", "</%s>, popped: %s path: %s", (const char*)name, pTag, (const char*)pctx->mbufTags.pMem);
+ // if we are in collect data mode then
+ // collect the tag end
+ if(!pctx->bNoXMLElemData)
+ ddocSaxParseCollectEndElement(pctx, name, &(pctx->bCollectElemData), &(pctx->mbufElemData));
+
+ if(!strcmp((const char*)name, "DataFile")) {
+ pctx->bCollectDFData--; // decrement bypass mode
+ if(pctx->bCollectDFData == 0)
+ handleEndDataFile(pctx, name);
+ }
+ // collect separately <Signature> and <SignedProperties> data
+ ddocSaxParseCollectEndElement(pctx, name, &(pctx->bCollectSigData), &(pctx->mbufSigData));
+ ddocSaxParseCollectEndElement(pctx, name, &(pctx->bCollectSigPartData), &(pctx->mbufSigPartData));
+ if(pctx->mbufSigData.pMem && !strcmp((const char*)name, "Signature")) {
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ if(pSigInfo) {
+ // MEMLEAK: possible memleak if old content would not be released ???
+ ddocDebug(3, "endElementHandler", "Set orig-content %s old-mem-used: %s new-content: %d",
+ pSigInfo->szId, (pSigInfo->mbufOrigContent.pMem ? "TRUE" : "FALSE"), pctx->mbufSigData.nLen);
+ ddocMemBuf_free(&(pSigInfo->mbufOrigContent));
+ pSigInfo->mbufOrigContent.pMem = (byte*)pctx->mbufSigData.pMem;
+ pSigInfo->mbufOrigContent.nLen = pctx->mbufSigData.nLen;
+ pctx->mbufSigData.pMem = 0;
+ pctx->mbufSigData.nLen = 0;
+ }
+ }
+ if(!pctx->nIgnoreDataFile) {
+ if(!strcmp((const char*)name, "EncapsulatedX509Certificate"))
+ handleEndEncapsulatedX509Certificate(pctx);
+ if(!strcmp((const char*)name, "EncapsulatedOCSPValue"))
+ handleEndEncapsulatedOCSPValue(pctx);
+ if(!strcmp((const char*)name, "ClaimedRole"))
+ handleEndClaimedRole(pctx);
+ if(!strcmp((const char*)name, "CertifiedRole"))
+ handleEndCertifiedRole(pctx);
+ if(!strcmp((const char*)name, "X509Certificate"))
+ handleEndX509Certificate(pctx);
+ if(!strcmp((const char*)name, "SignedProperties"))
+ handleEndSignedProperties(pctx);
+ if(!strcmp((const char*)name, "SignedInfo"))
+ handleEndSignedInfo(pctx);
+ if(!strcmp((const char*)name, "SignatureValue"))
+ handleEndSignatureValue(pctx);
+ if(!strcmp((const char*)name, "ResponderID"))
+ handleEndResponderID(pctx);
+ if(!strcmp((const char*)name, "ProducedAt"))
+ handleEndProducedAt(pctx);
+ if(!strcmp((const char*)name, "ByName"))
+ handleEndResponderID(pctx);
+ if(!strcmp((const char*)name, "ByKey"))
+ handleEndByKey(pctx);
+ if(!strcmp((const char*)name, "DigestValue"))
+ handleEndDigestValue(pctx);
+ if(!strcmp((const char*)name, "SigningTime"))
+ handleEndSigningTime(pctx);
+ if(!strcmp((const char*)name, "IssuerSerial"))
+ handleEndIssuerSerial(pctx);
+ if(!strcmp((const char*)name, "X509SerialNumber"))
+ handleEndIssuerSerial(pctx);
+ if(!strcmp((const char*)name, "X509IssuerName"))
+ handleEndIssuerName(pctx);
+ //if(!strcmp((const char*)name, "Cert"))
+ // handleEndCert(pctx, name);
+ if(!strcmp((const char*)name, "City"))
+ handleAdrEntry(pctx, ADR_ENTRY_CITY);
+ if(!strcmp((const char*)name, "StateOrProvince"))
+ handleAdrEntry(pctx, ADR_ENTRY_STATE);
+ if(!strcmp((const char*)name, "PostalCode"))
+ handleAdrEntry(pctx, ADR_ENTRY_ZIP);
+ if(!strcmp((const char*)name, "CountryName"))
+ handleAdrEntry(pctx, ADR_ENTRY_COUNTRY);
+
+ }
+ // reset tag, but not the context because used
+ pctx->tag[0] = 0;
+}
+
+/**
+ * charactersHandler:
+ * @ctxt: An XML parser context
+ * @ch: a xmlChar string
+ * @len: the number of xmlChar
+ *
+ * receiving some chars from the parser.
+ * Question: how much at a time ???
+ */
+static void charactersHandler(void *ctx, const xmlChar *ch, int len)
+{
+ SigDocParse* pctx = (SigDocParse*)ctx;
+ char *p = 0;
+
+ // do nothing if error has ocurred
+ if(pctx->errcode) return;
+ // if we are in collect data mode then
+ // collect this data
+ ddocDebug(4, "charactersHandler", "tag: %s len: %d, elem-data: %s, sig-data: %s, collected: %d",
+ pctx->tag, len, (pctx->mbufElemData.pMem ? "Y" : "N"),
+ (pctx->mbufSigData.pMem ? "Y" : "N"), pctx->mbufElemData.nLen);
+//#ifndef WITH_BASE64_HASHING_HACK
+ if(pctx->bCollectElemData) {
+ if(!pctx->errcode) {
+ if(pctx->bNoXMLElemData) {
+ pctx->errcode = ddocMemAppendData(&(pctx->mbufElemData), (const char*)ch, len);
+ } else {
+ pctx->errcode = escapeXMLSymbols((const char*)ch, len, &p);
+ pctx->errcode = ddocMemAppendData(&(pctx->mbufElemData), (const char*)p, -1);
+ free(p);
+ }
+ }
+ }
+//#endif
+ if(pctx->bCollectSigData) {
+ if(!pctx->errcode) {
+ p = 0;
+ pctx->errcode = escapeTextNode((const char*)ch, len, &p);
+ pctx->errcode = ddocMemAppendData(&(pctx->mbufSigData), p, -1);
+ free(p);
+ }
+ }
+ if(pctx->bCollectSigPartData) {
+ if(!pctx->errcode) {
+ p = 0;
+ pctx->errcode = escapeXMLSymbols((const char*)ch, len, &p);
+ pctx->errcode = ddocMemAppendData(&(pctx->mbufSigPartData), p, -1);
+ free(p);
+ }
+ }
+
+ ddocDebug(5, "charactersHandler", "End collecting");
+ if(!strcmp(pctx->tag, "DataFile"))
+ handleDataFile(pctx, ch, len);
+ //else printf("Ignoring: (%s, %d)\n", ch, len);
+ ddocDebug(5, "charactersHandler", "End");
+}
+
+/**
+ * startElementHandler:
+ * @ctxt: An XML parser context
+ * @name: The element name
+ *
+ * called when an opening tag has been processed.
+ */
+static void extractStartElementHandler(void *ctx, const xmlChar *name, const xmlChar **atts)
+{
+ const char* id = 0, *ctype = 0;
+ int i, l1;
+ char *p1 = 0;
+
+ SigDocParse* pctx = (SigDocParse*)ctx;
+ strncpy(pctx->tag, (const char*)name, sizeof(pctx->tag));
+ ddocDebug(5, "extractStartElementHandler", "tag: %s", pctx->tag);
+ // do nothing if error has ocurred
+ if(pctx->errcode) return;
+ if(!strcmp((const char*)name, "DataFile")) {
+ for (i = 0; (atts != NULL) && (atts[i] != NULL); i += 2) {
+ if(!strcmp((const char*)atts[i], "Id"))
+ id = (const char*)atts[i+1];
+ if(!strcmp((const char*)atts[i], "ContentType"))
+ ctype = (const char*)atts[i+1];
+ }
+ if(!pctx->nIgnoreDataFile) {
+ strncpy(pctx->ctx2, id, sizeof(pctx->ctx2));
+ strncpy(pctx->ctx4, ctype, sizeof(pctx->ctx4));
+ if(!strcmp(pctx->ctx2, pctx->ctx3)) {
+ pctx->bCollectDFData++; // increment bypass mode
+ ddocDebug(4, "extractStartElementHandler", "Start DF: %s mode: %s skip: %d",
+ pctx->ctx3, pctx->ctx1, pctx->bCollectDFData);
+ if(pctx->bCollectDFData == 1) { // only the first time
+ ddocDebug(4, "extractStartElementHandler", "Init collecting DF: %s mode: %s",
+ pctx->ctx3, pctx->ctx1);
+ if(!strcmp(pctx->ctx4, CONTENT_EMBEDDED_BASE64) && !pctx->bKeepBase64) {
+ EVP_DecodeInit(&(pctx->ectx));
+ pctx->b64pos = 0;
+ pctx->lSize = 0;
+ }
+ // open output file if necessary
+ if(!pctx->bDataFile && !pctx->pMemBufDF) {
+ pctx->bDataFile = BIO_new_file(pctx->ctx5, "w");
+ ddocDebug(4, "extractStartElementHandler", "Opening file: %s", pctx->ctx5);
+ if(!pctx->bDataFile)
+ SET_LAST_ERROR(ERR_FILE_WRITE);
+ }
+ }
+ }
+ }
+ if(!strcmp(ctype, CONTENT_EMBEDDED) || pctx->nIgnoreDataFile)
+ pctx->nIgnoreDataFile++;
+ }
+ if(!strcmp(pctx->ctx2, pctx->ctx3) &&
+ !strcmp(pctx->ctx4, CONTENT_EMBEDDED) &&
+ strcmp((const char*)name, "DataFile")) {
+ if(!strcmp(pctx->ctx1, CHARSET_ISO_8859_1)) { // if must convert
+ // begining of the tag
+ l1 = strlen((char*)name) + 10;
+ p1 = (char*)malloc(l1);
+ RETURN_VOID_IF_BAD_ALLOC(p1);
+ if(pctx->pMemBufDF) {
+ ddocMemAppendData(pctx->pMemBufDF, "<", -1);
+ ddocMemAppendData(pctx->pMemBufDF, utf82ascii((const char*)name, p1, &l1), -1);
+ }
+ else
+ BIO_printf(pctx->bDataFile, "<%s", utf82ascii((const char*)name, p1, &l1));
+ free(p1);
+ p1 = 0;
+ for (i = 0; (atts != NULL) && (atts[i] != NULL); i += 2) {
+ l1 = strlen((char*)atts[i]) + 10;
+ p1 = (char*)malloc(l1);
+ RETURN_VOID_IF_BAD_ALLOC(p1);
+ if(pctx->pMemBufDF) {
+ ddocMemAppendData(pctx->pMemBufDF, " ", -1);
+ ddocMemAppendData(pctx->pMemBufDF, utf82ascii((const char*)atts[i], p1, &l1), -1);
+ ddocMemAppendData(pctx->pMemBufDF, "=", -1);
+ }
+ else
+ BIO_printf(pctx->bDataFile, " %s=", utf82ascii((const char*)atts[i], p1, &l1));
+ free(p1);
+ p1 = 0;
+ l1 = strlen((char*)atts[i+1]) + 10;
+ p1 = (char*)malloc(l1);
+ RETURN_VOID_IF_BAD_ALLOC(p1);
+ if(pctx->pMemBufDF) {
+ ddocMemAppendData(pctx->pMemBufDF, "\"", -1);
+ ddocMemAppendData(pctx->pMemBufDF, utf82ascii((const char*)atts[i+1], p1, &l1), -1);
+ ddocMemAppendData(pctx->pMemBufDF, "\"", -1);
+ }
+ else
+ BIO_printf(pctx->bDataFile, "\"%s\"", utf82ascii((const char*)atts[i+1], p1, &l1));
+ free(p1);
+ p1 = 0;
+ } // for - atributes
+ if(pctx->pMemBufDF)
+ ddocMemAppendData(pctx->pMemBufDF, ">", -1);
+ else
+ BIO_puts(pctx->bDataFile, ">");
+ } // if - must convert
+ else { // no need to convert
+ if(pctx->pMemBufDF) {
+ ddocMemAppendData(pctx->pMemBufDF, "<", -1);
+ ddocMemAppendData(pctx->pMemBufDF, (const char*)name, -1);
+ for (i = 0; (atts != NULL) && (atts[i] != NULL); i += 2) {
+ ddocMemAppendData(pctx->pMemBufDF, " ", -1);
+ ddocMemAppendData(pctx->pMemBufDF, (const char*)atts[i], -1);
+ p1 = 0;
+ ddocMemAppendData(pctx->pMemBufDF, "=\"", -1);
+ pctx->errcode = escapeXMLSymbols((const char*)atts[i+1],
+ strlen((const char*)atts[i+1]), &p1);
+ ddocMemAppendData(pctx->pMemBufDF, p1, -1);
+ free(p1);
+ ddocMemAppendData(pctx->pMemBufDF, "\"", -1);
+ }
+ ddocMemAppendData(pctx->pMemBufDF, ">", -1);
+ } else {
+ BIO_printf(pctx->bDataFile, "<%s", name);
+ for (i = 0; (atts != NULL) && (atts[i] != NULL); i += 2) {
+ BIO_printf(pctx->bDataFile, " %s=\"%s\"",
+ (const char*)atts[i], (const char*)atts[i+1]);
+ }
+ BIO_puts(pctx->bDataFile, ">");
+ }
+ } // else no conversion
+ } // if strcmp(DataFile)
+}
+
+
+//--------------------------------------------------
+// handles decoding base64 content. Removes all
+// whitespace and breaks the data in 64 symbol lines
+// to ensure correct decoding
+// pctx - pointer to XML parsing work-area
+// ch - input data
+// len - length of input data
+// lastBlock - 1=last base64 block
+//--------------------------------------------------
+void extractDecodeB64(SigDocParse* pctx, const char* ch, int len, int lastBlock)
+{
+ int l = 0, j;
+ char decData[70];
+
+ ddocDebug(4, "extractDecodeB64", "line: %d last: %d", len, lastBlock);
+ do {
+ // compose a 64 char base64 line for OpenSSL's decoder
+ while(pctx->b64pos < 64 && l < len) {
+ if(!isspace(ch[l])) {
+ pctx->b64line[pctx->b64pos] = ch[l];
+ pctx->b64pos++;
+ }
+ l++;
+ }
+ // if line is ready then terminate and use it
+ if(pctx->b64pos == 64 || (l == len && lastBlock)) {
+ pctx->b64line[pctx->b64pos] = '\n';
+ pctx->b64line[pctx->b64pos + 1] = 0;
+ j = sizeof(decData);
+ memset(decData, 0, j);
+ ddocDebug(5, "extractDecodeB64", "decoding: %s", pctx->b64line);
+ EVP_DecodeUpdate(&(pctx->ectx), (unsigned char*)decData, &j,
+ (unsigned char*)pctx->b64line, pctx->b64pos + 1);
+ ddocDebug(4, "extractDecodeB64", "decoding: %d -> got: %d", pctx->b64pos, j);
+ if(pctx->pMemBufDF)
+ ddocMemAppendData(pctx->pMemBufDF, decData, j);
+ else {
+ if(!pctx->pMemBufDF)
+ SET_LAST_ERROR_RETURN_VOID_IF_NOT(pctx->bDataFile, ERR_FILE_WRITE);
+ BIO_write(pctx->bDataFile, decData, j);
+ }
+ pctx->lSize += j;
+ if(l == len && lastBlock) {
+ j = sizeof(decData);
+ memset(decData, 0, j);
+ EVP_DecodeFinal(&(pctx->ectx), (unsigned char*)decData, &j);
+ ddocDebug(4, "extractDecodeB64", "decoding final got: %d", j);
+ if(j > 0) {
+ if(pctx->pMemBufDF)
+ ddocMemAppendData(pctx->pMemBufDF, decData, j);
+ else {
+ if(!pctx->pMemBufDF)
+ SET_LAST_ERROR_RETURN_VOID_IF_NOT(pctx->bDataFile, ERR_FILE_WRITE);
+ BIO_write(pctx->bDataFile, decData, j);
+ }
+ pctx->lSize += j;
+ }
+ }
+ // ready for next line
+ pctx->b64pos = 0;
+ //memset(&(pctx->b64line), 0, sizeof(pctx->b64line));
+ }
+ } while(l < len);
+}
+
+
+/**
+ * extractBodyHandler:
+ * @ctxt: An XML parser context
+ * @name: The element name
+ *
+ * called when bypassing xml parser for base64 data and extracting to file
+ */
+void extractBodyHandler(SigDocParse* pctx, const char* ch, int len)
+{
+ ddocDebug(4, "extractBodyHandler", "DF: %s data: %d", pctx->ctx2, len);
+ if(!pctx->pMemBufDF)
+ SET_LAST_ERROR_RETURN_VOID_IF_NOT(pctx->bDataFile, ERR_FILE_WRITE);
+ if(!pctx->bKeepBase64) {
+ extractDecodeB64(pctx, ch, len, 0);
+ } else {
+ if(pctx->pMemBufDF) {
+ ddocMemAppendData(pctx->pMemBufDF, ch, len);
+ }else {
+ ddocDebug(4, "extractBodyHandler", "Writing: %s len: %d", ch, len);
+ BIO_write(pctx->bDataFile, ch, len);
+ }
+ pctx->lSize += len;
+ }
+}
+
+/**
+ * extractBodyHandler:
+ * @ctxt: An XML parser context
+ * @name: The element name
+ *
+ * called when bypassing xml parser for bas64 data and extracting to file
+ */
+void extractNoChangeHandler(SigDocParse* pctx, const char* ch, int len)
+{
+ int l;
+ char *p = 0;
+
+ ddocDebug(4, "extractNoChangeHandler", "DF: %s data: %d", pctx->ctx2, len);
+ if(pctx->errcode) { return; }
+ if(!pctx->pMemBufDF)
+ SET_LAST_ERROR_RETURN_VOID_IF_NOT(pctx->bDataFile, ERR_FILE_WRITE);
+ if(!strcmp(pctx->ctx4, CONTENT_EMBEDDED_BASE64)) {
+ BIO_write(pctx->bDataFile, ch, len);
+ pctx->lSize += len;
+ } else {
+ pctx->errcode = escapeXMLSymbols((const char*)ch, len, &p);
+ l = strlen(p);
+ pctx->lSize += l;
+ if(pctx->pMemBufDF) {
+ ddocMemAppendData(pctx->pMemBufDF,p, l);
+ } else {
+ ddocDebug(5, "extractNoChangeHandler", "Writing: %s len: %d", p, l);
+ BIO_write(pctx->bDataFile, p, l);
+ }
+ free(p);
+ p = 0;
+ }
+}
+
+/**
+ * charactersHandler:
+ * @ctxt: An XML parser context
+ * @ch: a xmlChar string
+ * @len: the number of xmlChar
+ *
+ * receiving some chars from the parser.
+ * Question: how much at a time ???
+ */
+static void extractCharactersHandler(void *ctx, const xmlChar *ch, int len)
+{
+ int l;
+ char *p = 0, *p2 = 0;
+ SigDocParse* pctx = (SigDocParse*)ctx;
+
+ ddocDebug(5, "extractCharactersHandler", "tag: %s, data: %d - \'%s\'", pctx->tag, len, (char*)ch);
+ // do nothing if error has ocurred
+ if(pctx->errcode) { return; }
+ if(!strcmp(pctx->ctx2, pctx->ctx3)) {
+ if(!strcmp(pctx->ctx1, "NO-CHANGE")) { // NO-CHANGE
+ extractNoChangeHandler(pctx, (const char*)ch, len);
+ }
+ else { // NOT NO-CHANGE
+ if(!strcmp(pctx->ctx4, CONTENT_EMBEDDED_BASE64)) {
+ extractBodyHandler(pctx, (const char*)ch, len);
+ }
+ if(!strcmp(pctx->ctx4, CONTENT_EMBEDDED)) {
+ if(!strcmp(pctx->ctx1, CHARSET_ISO_8859_1)) {
+ l = len + 10;
+ p = (char*)malloc(l);
+ RETURN_VOID_IF_BAD_ALLOC(p);
+ memset(p, 0, l);
+ UTF8Toisolat1((unsigned char*)p, &l,
+ (const unsigned char*)ch, &len);
+ escapeXMLSymbols((const char*)p, l, &p2);
+ free(p);
+ p = 0;
+ l = strlen(p2);
+ if(pctx->pMemBufDF)
+ ddocMemAppendData(pctx->pMemBufDF, p, l);
+ else
+ BIO_write(pctx->bDataFile, (unsigned char*)p, l);
+ free(p2);
+ p2 = 0;
+ } else {
+ escapeXMLSymbols((const char*)ch, len, &p);
+ l = strlen(p);
+ if(pctx->pMemBufDF)
+ ddocMemAppendData(pctx->pMemBufDF, p, l);
+ else
+ BIO_write(pctx->bDataFile, (unsigned char*)p, l);
+ free(p);
+ }
+ }
+ } // NOT NO-CHANGE
+ }
+ ddocDebug(5, "extractCharactersHandler", "done, errs: %d", pctx->errcode);
+}
+
+/**
+ * extractEndElementHandler:
+ * @ctxt: An XML parser context
+ * @name: The element name
+ *
+ * called when the end of an element has been detected.
+ */
+static void extractEndElementHandler(void *ctx, const xmlChar *name)
+{
+ time_t t1;
+ SigDocParse* pctx = (SigDocParse*)ctx;
+
+ ddocDebug(5, "extractEndElementHandler", "tag: %s", (char*)name);
+ // do nothing if error has ocurred
+ if(pctx->errcode) { return; }
+ if(!strcmp((const char*)name, "DataFile")) {
+ if(pctx->nIgnoreDataFile > 0)
+ pctx->nIgnoreDataFile--;
+ ddocDebug(3, "extractEndElementHandler", "DF: %s end ignore: %d skip: %d",
+ pctx->ctx2, pctx->nIgnoreDataFile, pctx->bCollectDFData);
+ if(!strcmp(pctx->ctx2, pctx->ctx3) &&
+ !pctx->nIgnoreDataFile) {
+ pctx->bCollectDFData--;
+ if(!pctx->bCollectDFData) {
+ if(!strcmp(pctx->ctx4, CONTENT_EMBEDDED_BASE64) &&
+ strcmp(pctx->ctx1, "NO-CHANGE")) {
+ if(!pctx->bKeepBase64)
+ extractDecodeB64(pctx, NULL, 0, 1);
+ }
+ if(!strcmp(pctx->ctx1, "NO-CHANGE")) {
+ // todo ?
+ }
+ time(&t1);
+ ddocDebug(3, "extractEndElementHandler", "DF: %s mode: %s, time: %d [sek] total: %ld bytes",
+ pctx->ctx3, pctx->ctx1, (t1 - pctx->tStartParse), pctx->lSize);
+ // mark the end of data collecting
+ pctx->ctx3[0] = 0;
+ pctx->lSize = 0;
+ } // if bCollectDFData == 0
+ } // if not ignore DataFile
+ } // if "DataFile"
+ if(pctx->ctx3[0] && !strcmp(pctx->ctx4, CONTENT_EMBEDDED)) {
+ if(pctx->pMemBufDF) {
+ ddocDebug(5, "extractEndElementHandler", "Last name: %s collected: \'%s\'",
+ (char*)name, (char*)pctx->pMemBufDF->pMem);
+ ddocMemAppendData(pctx->pMemBufDF, "</", -1);
+ ddocMemAppendData(pctx->pMemBufDF, (char*)name, -1);
+ ddocMemAppendData(pctx->pMemBufDF, ">", -1);
+ ddocDebug(5, "extractEndElementHandler", "Result: \'%s\'",
+ (char*)pctx->pMemBufDF->pMem);
+
+ } else {
+ BIO_printf(pctx->bDataFile, "</%s>", name);
+ }
+ }
+ // reset tag
+ pctx->tag[0] = 0;
+}
+
+
+/**
+ * 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 cdataBlockHandler(void * ctx, const xmlChar *value, int len)
+{
+ fprintf(stdout, "SAX.pcdata(%.20s, %d)\n", (char *) value, len);
+}
+
+
+/**
+ * warningHandler:
+ * @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 warningHandler(void * ctx, const char *msg, ...)
+{
+ va_list args;
+
+ va_start(args, msg);
+ ddocDebugVaArgs(2, "warningHandler", msg, args);
+ va_end(args);
+}
+
+/**
+ * errorHandler:
+ * @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 errorHandler(void *ctx, const char *msg, ...)
+{
+ va_list args;
+ SigDocParse* pctx = (SigDocParse*)ctx;
+
+ va_start(args, msg);
+ pctx->errcode = ERR_DIGIDOC_PARSE;
+ ddocDebugVaArgs(1, "errorHandler", msg, args);
+ addError(pctx->errcode, __FILE__, __LINE__, "XML parsing error");
+ va_end(args);
+}
+
+/**
+ * fatalErrorHandler:
+ * @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 fatalErrorHandler(void *ctx, const char *msg, ...)
+{
+ va_list args;
+ SigDocParse* pctx = (SigDocParse*)ctx;
+
+ va_start(args, msg);
+ pctx->errcode = ERR_DIGIDOC_PARSE;
+ ddocDebugVaArgs(1, "fatalErrorHandler", msg, args);
+ addError(pctx->errcode, __FILE__, __LINE__, "XML parsing error");
+ va_end(args);
+}
+
+
+xmlSAXHandler debugSAXHandlerStruct = {
+ 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,
+ startElementHandler,
+ endElementHandler,
+ NULL, //referenceHandler,
+ charactersHandler,
+ NULL, //ignorableWhitespaceHandler,
+ NULL, //processingInstructionHandler,
+ NULL, //commentHandler,
+ warningHandler,
+ errorHandler,
+ fatalErrorHandler,
+ NULL, //getParameterEntityHandler,
+ cdataBlockHandler,
+ NULL, //externalSubsetHandler,
+ 1
+};
+
+
+xmlSAXHandlerPtr debugSAXHandler = &debugSAXHandlerStruct;
+
+
+xmlSAXHandler extractSAXHandlerStruct = {
+ 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,
+ extractStartElementHandler,
+ extractEndElementHandler,
+ NULL, //referenceHandler,
+ extractCharactersHandler,
+ NULL, //ignorableWhitespaceHandler,
+ NULL, //processingInstructionHandler,
+ NULL, //commentHandler,
+ warningHandler,
+ errorHandler,
+ fatalErrorHandler,
+ NULL, //getParameterEntityHandler,
+ NULL, //cdataBlockHandler,
+ NULL, //externalSubsetHandler,
+ 1
+};
+
+xmlSAXHandlerPtr extractSAXHandler = &extractSAXHandlerStruct;
+
+
+
+
+//--------------------------------------------------
+// Reads in signed XML document info from digidoc file
+// ppSigDoc - pointer to the buffer of newly read info pointer
+// szFileName - documents filename
+// checkFileDigest - indicates if digests of datafiles referred by the document must be checked
+// lMaxDFLen - maximum size for a DataFile whose contents will be
+// kept in memory
+//--------------------------------------------------
+EXP_OPTION int ddocSaxReadSignedDocFromFile(SignedDoc** ppSigDoc, const char* szFileName,
+ int checkFileDigest, long lMaxDFLen)
+{
+ int err = ERR_OK, ret, n;
+ FILE *f;
+ char chars[1028], *p, buf1[16385];
+ xmlParserCtxtPtr ctxt;
+ SigDocParse pctx;
+ DigiDocMemBuf mbuf1;
+#ifdef WIN32
+ wchar_t *convFileName = 0;
+ err = utf82unicode((const char*)szFileName, (char**)&convFileName, &ret);
+ ddocDebug(3, "ddocSaxReadSignedDocFromFile", "file: %s, conv-file: %s", szFileName, convFileName);
+#endif
+
+ ddocDebug(3, "ddocSaxReadSignedDocFromFile", "digidoc: %s, checkDig: %d, maxDF: %ld",
+ szFileName, checkFileDigest, lMaxDFLen);
+ RETURN_IF_NULL_PARAM(ppSigDoc);
+ RETURN_IF_NULL_PARAM(szFileName);
+ clearErrors();
+ memset(&pctx, 0, sizeof(pctx));
+ pctx.pSigDoc = (SignedDoc*)malloc(sizeof(SignedDoc));
+ RETURN_IF_BAD_ALLOC(pctx.pSigDoc);
+ memset(pctx.pSigDoc, 0, sizeof(SignedDoc));
+#ifdef WIN32
+ ddocDebug(3, "ddocSaxReadSignedDocFromFile", "Opening file: %s", convFileName);
+ if(!err && ((f = _wfopen(convFileName, L"rb")) != NULL)) {
+#else
+ ddocDebug(3, "ddocSaxReadSignedDocFromFile", "Opening file: %s", szFileName);
+ if(!err && ((f = fopen(szFileName, "rb")) != NULL)) {
+#endif
+ ddocDebug(4, "ddocSaxReadSignedDocFromFile", "file opened");
+ n=0;
+ if(ftell(f) > 0) {
+ ddocDebug(5, "ddocSaxReadSignedDocFromFile", "File position after open is: %d err: %d eof: %d, move to begin!", ftell(f), ferror(f), feof(f));
+ fseek(f, 0, SEEK_SET);
+ }
+ //memset(chars,0,sizeof(chars));
+ ret = fread(chars, 1, 100, f);
+ if (ret > 0) {
+ chars[ret] = 0; // zero terminate block data
+ p = strstr(chars, "<?xml");
+ if(!p)
+ p = chars;
+ n++;
+ //pctx.bDataFile = (BIO*)1;
+ pctx.szInputFileName = (char*)szFileName;
+ pctx.checkFileDigest = checkFileDigest;
+ pctx.lMaxDFLen = lMaxDFLen;
+ time(&(pctx.tStartParse));
+ ddocDebug(5, "ddocSaxReadSignedDocFromFile", "parse block: %d len: %d fpos: %d \n---\n%s\n---\n", n, ret, ftell(f), p);
+
+ ctxt = xmlCreatePushParserCtxt(debugSAXHandler, &pctx,
+ p, strlen(p), szFileName);
+ do {
+ //memset(chars, 0, sizeof(chars)); // no longer necessary as zero terminated later here
+ ret = fread(chars, 1, 1024, f);
+ ddocDebug(5, "ddocSaxReadSignedDocFromFile", "read block: %d got: %d fpos: %d err: %d eof: %d", n, ret, ftell(f), ferror(f), feof(f));
+ if((ferror(f) && ret <= 0) && !feof(f)) {
+ ddocDebug(1, "ddocSaxReadSignedDocFromFile", "Error %d reading file: %s", ferror(f), szFileName);
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_READ);
+ }
+ if(ret >= 0) {
+ chars[ret] = 0; // zero terminate block data
+ } else {
+ ddocDebug(1, "ddocSaxReadSignedDocFromFile", "No data could be read from: %s pos: %d", szFileName, ftell(f));
+ break;
+ }
+ n++;
+ ddocDebug(5, "ddocSaxReadSignedDocFromFile", "parse block: %d len: %d fpos: %d \n---\n%s\n---\n", n, ret, ftell(f), chars);
+
+ if(pctx.bCollectDFData > 0 && !strcmp(pctx.ctx4, CONTENT_EMBEDDED_BASE64)) { // bypass mode
+ // look for new element start "<"
+ p = strchr(chars, '<');
+ // if we just enetered the bypass mode then send flush command
+ // but increment bypass mode in order not to fall out of it
+ if(pctx.bCollectDFData == 1 && !p) { // start bypass mode
+ pctx.bCollectDFData += 2; // increment with 2 so we dont return to flushing
+ ddocDebug(4, "ddocSaxReadSignedDocFromFile", "Starting bypass mode, skip: %d",
+ pctx.bCollectDFData);
+ // force the parser to release element content
+ // before entering into bypass mode
+ ddocDebug(5, "ddocSaxReadSignedDocFromFile", "parse bypass data %s", g_szDataFileFlush1);
+ xmlParseChunk(ctxt, g_szDataFileFlush1, strlen(g_szDataFileFlush1), 0);
+ ddocDebug(4, "ddocSaxReadSignedDocFromFile", "Entering bypass mode, skip: %d",
+ pctx.bCollectDFData);
+ }
+ if(pctx.bCollectDFData >=2 && !p /*pctx.bCollectElemData*/) { // parse in bypass mode
+ ddocDebug(4, "ddocSaxReadSignedDocFromFile", "Parsing in bypass mode, skip: %d len: %d",
+ pctx.bCollectDFData, ret);
+#ifdef WITH_BASE64_HASHING_HACK
+ ddocDebug(4, "ddocSaxReadSignedDocFromFile", "update sha1: %d - %s", ret, chars);
+ SHA1_Update(&(pctx.sctx), chars, ret);
+ mbuf1.pMem = chars;
+ mbuf1.nLen = ret;
+ ddocDebugWriteFile(4, "df-data.txt", &mbuf1);
+#else
+ pctx.errcode = ddocMemAppendData(&(pctx.mbufElemData), chars, ret);
+ // update sha1
+ l1 = sizeof(buf1);
+ EVP_DecodeUpdate(&(pctx.ectx), (unsigned char*)buf1, &l1, (unsigned char*)chars, ret);
+ ddocDebug(4, "ddocSaxReadSignedDocFromFile", "update sha1: %d - %s", l1, buf1);
+ SHA1_Update(&(pctx.sctx), buf1, l1);
+#endif
+ }
+ if(p) { // finish bypass mode
+ ddocDebug(4, "ddocSaxReadSignedDocFromFile", "Ending bypass mode len: %d, skip: %d",
+ ret, pctx.bCollectDFData);
+ snprintf(buf1, sizeof(buf1), g_szDataFileFlush2, pctx.ctx3, pctx.ctx4);
+ // send finish command
+ ddocDebug(5, "ddocSaxReadSignedDocFromFile", "parse finish data %s", buf1);
+ xmlParseChunk(ctxt, buf1, strlen(buf1), 0);
+ pctx.bCollectDFData = 1;
+ // parse the normal chunk that caused end
+ xmlParseChunk(ctxt, chars, ret, 0);
+ }
+ } else { // normal mode
+ ddocDebug(4, "ddocSaxReadSignedDocFromFile", "parsing normal chunk");
+ xmlParseChunk(ctxt, chars, ret, 0);
+ }
+
+ } while(ret > 0/* && pctx.ctx3[0]*/);
+ ddocDebug(5, "ddocSaxReadSignedDocFromFile", "parse end0 \n---\n%s\n---\n", chars);
+ xmlParseChunk(ctxt, chars, 0, 1);
+ xmlFreeParserCtxt(ctxt);
+ }
+ *ppSigDoc = pctx.pSigDoc;
+ fclose(f);
+ }
+ else {
+ err = ERR_FILE_READ;
+ ddocDebug(1, "ddocSaxReadSignedDocFromFile", "error reading file: %s, err: %d", szFileName, err);
+ }
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ if(!err)
+ err = getLastError();
+ ddocDebug(3, "ddocSaxReadSignedDocFromFile", "success reading file: %s, err: %d", szFileName, err);
+ // cleanup parser context
+ ddocSAXCleanup(&pctx);
+ // check ddoc xmlns problem
+ checkDdocWrongDigests(*ppSigDoc);
+#ifdef WIN32
+ free(convFileName);
+#endif
+ return checkUnknownErr();
+}
+
+
+//--------------------------------------------------
+// Reads in signed XML document info
+// ppSigDoc - pointer to the buffer of newly read info pointer
+// szFileName - documents filename
+// checkFileDigest - indicates if digests of datafiles referred by the document must be checked
+// lMaxDFLen - maximum size for a DataFile whose contents will be
+// kept in memory
+//--------------------------------------------------
+EXP_OPTION int ddocSaxReadSignedDocFromMemory(SignedDoc** ppSigDoc, const void* pData,
+ int len, long lMaxDFLen)
+{
+ int err = ERR_OK;
+ int ret, l2;
+ SigDocParse pctx;
+ char * p = 0;
+
+ ddocDebug(3, "ddocSaxReadSignedDocFromMemory", "data len: %d, maxDF: %ld", len, lMaxDFLen);
+ RETURN_IF_NULL_PARAM(ppSigDoc);
+ RETURN_IF_NULL_PARAM(pData);
+
+ clearErrors();
+ memset(&pctx, 0, sizeof(pctx));
+ pctx.pSigDoc = (SignedDoc*)malloc(sizeof(SignedDoc));
+ RETURN_IF_BAD_ALLOC(pctx.pSigDoc);
+ memset(pctx.pSigDoc, 0, sizeof(SignedDoc));
+ //pctx.bDataFile = (BIO*)1;
+ pctx.szInputFileName = 0;
+ pctx.checkFileDigest = 0;
+ pctx.lMaxDFLen = lMaxDFLen;
+ // skip any BOM marks or other non-xml chars at the beginning
+ if(pData)
+ p = strstr((const char*)pData, "<?xml");
+ if(p) {
+ l2 = strlen(p);
+ } else {
+ p = (char*)pData;
+ l2 = len;
+ }
+ ret = xmlSAXUserParseMemory(debugSAXHandler, &pctx, (const char*)p, l2);
+ *ppSigDoc = pctx.pSigDoc;
+ if (err != ERR_OK) {
+ SET_LAST_ERROR(err);
+ ddocDebug(1, "ddocSaxReadSignedDocFromMemory", "parsing error: %d", err);
+ }
+ if(!err)
+ err = getLastError();
+ // cleanup parser context
+ ddocSAXCleanup(&pctx);
+ return err;
+}
+
+
+//--------------------------------------------------
+// Reads in signed XML document and extracts the desired data file
+// pSigDoc - signed document object if exists. Can be NULL
+// szFileName - digidoc filename
+// szDataFileName - name of the file where to store embedded data.
+// szDocId - DataFile Id atribute value
+// szCharset - convert DataFile content to charset
+//--------------------------------------------------
+EXP_OPTION int ddocSaxExtractDataFile(SignedDoc* pSigDoc, const char* szFileName,
+ const char* szDataFileName, const char* szDocId,
+ const char* szCharset)
+{
+ FILE *f;
+ int ret, err = ERR_OK;
+ long len;
+ char chars[1050], convFileName[1024],
+ convDataFileName[1024], *p;
+ xmlParserCtxtPtr ctxt;
+ SigDocParse pctx;
+ void* pBuf;
+ // test
+ ddocDebug(3, "ddocSaxExtractDataFile", "SigDoc: %s, docid: %s, digidoc: %s, file: %s, charset: %s", (pSigDoc ? "OK" : "NULL"), szDocId, szFileName, szDataFileName, szCharset);
+ return ddocExtractDataFile(pSigDoc, szFileName, szDataFileName, szDocId, szCharset);
+ RETURN_IF_NULL_PARAM(szFileName);
+ RETURN_IF_NULL_PARAM(szDataFileName);
+ RETURN_IF_NULL_PARAM(szDocId);
+ RETURN_IF_NULL_PARAM(szCharset);
+
+ clearErrors();
+ memset(&pctx, 0, sizeof(pctx));
+ memset(convFileName, 0, sizeof(convFileName));
+ memset(convDataFileName, 0, sizeof(convDataFileName));
+ ddocConvertFileName(convDataFileName, sizeof(convDataFileName), szDataFileName);
+ ddocConvertFileName(convFileName, sizeof(convFileName), szFileName);
+
+ // test
+ return ddocExtractDataFile(pSigDoc, szFileName, szDataFileName, szDocId, szCharset);
+
+ // try reading from memory if already cached?
+ ret = ddocGetDataFileCachedData(pSigDoc, szDocId, &pBuf, &len);
+ if(pBuf) { // gotcha
+ ddocDebug(3, "ddocSaxExtractDataFile", "Using cached data: %d bytes", len);
+ if((f = fopen(convDataFileName, "wb")) != NULL) {
+ fwrite(pBuf, 1, len, f);
+ fclose(f);
+ } else {
+ ddocDebug(1, "ddocSaxExtractDataFile", "Error writing file: %s", convDataFileName);
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_WRITE);
+ }
+ free(pBuf);
+ return ret;
+ }
+ strncpy(pctx.ctx5, convDataFileName, sizeof(pctx.ctx5));
+ if ((f = fopen(convFileName, "r")) != NULL) {
+ pctx.pSigDoc = NULL;
+ pctx.bDataFile = NULL;
+ pctx.ctx1[0] = pctx.ctx2[0] = pctx.ctx3[0] = pctx.tag[0] = pctx.ctx4[0] = 0;
+ pctx.errcode = ERR_OK;
+ time(&(pctx.tStartParse));
+ pctx.bDataFile = NULL; //BIO_new_file(szDataFileName, "w");
+ strncpy(pctx.ctx1, szCharset, sizeof(pctx.ctx1));
+ pctx.szInputFileName = (char*)szFileName;
+ strncpy(pctx.ctx3, szDocId, sizeof(pctx.ctx3));
+ memset(chars, 0, sizeof(chars));
+ ret = fread(chars, 1, 10, f);
+ if (ret > 0) {
+ p = strstr(chars, "<?xml");
+ if(!p)
+ p = chars;
+ ctxt = xmlCreatePushParserCtxt(extractSAXHandler, &pctx,
+ p, strlen(p), szFileName);
+ do {
+ memset(chars, 0, sizeof(chars));
+ ret = fread(chars, 1, 1024, f);
+ ddocDebug(6, "ddocSaxExtractDataFile", "Parsing %d bytes: \n%s\n", ret, chars);
+ if(ret <= 0) break;
+ if(pctx.bCollectDFData > 0 &&
+ !strcmp(pctx.ctx4, CONTENT_EMBEDDED_BASE64)) { // bypass mode
+ // look for new element start "<"
+ p = strchr(chars, '<');
+ // if we just entered the bypass mode then send flush command
+ // but increment bypass mode in order not to fall out of it
+ if(pctx.bCollectDFData == 1 && !p) { // start bypass mode
+ pctx.bCollectDFData += 2; // increment with 2 so we dont return to flushing
+ ddocDebug(4, "ddocSaxExtractDataFile", "Starting bypass mode, skip: %d",
+ pctx.bCollectDFData);
+ // force the parser to release element content
+ // before entering into bypass mode
+ xmlParseChunk(ctxt, g_szDataFileFlush1, strlen(g_szDataFileFlush1), 0);
+ ddocDebug(4, "ddocSaxExtractDataFile", "Entering bypass mode, skip: %d",
+ pctx.bCollectDFData);
+ }
+ if(pctx.bCollectDFData >=2 && !p) { // parse in bypass mode
+ ddocDebug(4, "ddocSaxExtractDataFile",
+ "Parsing in bypass mode, skip: %d len: %d",
+ pctx.bCollectDFData, ret);
+ if(!strcmp(pctx.ctx1, "NO-CHANGE")) { // NO-CHANGE
+ extractNoChangeHandler(&pctx, (const char*)chars, ret);
+ } else {
+ extractBodyHandler(&pctx, (const char*)chars, ret);
+ }
+ }
+ if(p) { // finish bypass mode
+ *p = 0;
+ ddocDebug(3, "ddocSaxExtractDataFile", "Last block %d bytes: \n%s\n", ret, chars);
+ pctx.bCollectDFData = 1;
+ //xmlParseChunk(ctxt, chars, strlen((const char*)chars), 0);
+ if(!strcmp(pctx.ctx1, "NO-CHANGE")) { // NO-CHANGE
+ extractNoChangeHandler(&pctx, (const char*)chars, strlen(chars));
+ } else {
+ extractBodyHandler(&pctx, (const char*)chars, strlen(chars));
+ extractDecodeB64(&pctx, NULL, 0, 1);
+ }
+ pctx.bCollectDFData = 0; // stopp bypass attempts
+ memset(chars, 0, sizeof(chars));
+ ret = 0; // stop parsing
+ }
+ } else { // normal mode
+ ddocDebug(3, "ddocSaxExtractDataFile", "parsing normal chunk \n%s\n", chars);
+ xmlParseChunk(ctxt, chars, ret, 0);
+ memset(chars, 0, sizeof(chars));
+ }
+
+ } while(ret > 0 && pctx.ctx3[0]);
+ ddocDebug(3, "ddocSaxExtractDataFile", "parsing last chunk\n---%s\n---", chars);
+ if(strlen(chars))
+ xmlParseChunk(ctxt, chars, 0, 1);
+ xmlFreeParserCtxt(ctxt);
+ }
+ ddocDebug(5, "ddocSaxExtractDataFile", "parsing complete");
+ fclose(f);
+ } else {
+ ddocDebug(1, "ddocSaxExtractDataFile", "Error reading file: %s", szFileName);
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_READ);
+ }
+ if(!err)
+ err = getLastError();
+ // cleanup parser context
+ ddocSAXCleanup(&pctx);
+ return err;
+}
+
+//--------------------------------------------------
+// Reads in signed XML document and returns the
+// desired DataFile-s content in a memory buffer.
+// caller is responsible for freeing the memory.
+// pSigDoc - signed document object if cached
+// szFileName - name of digidoc file
+// szDocId - id if DataFile
+// pOutBuf - address of buffer pointer
+// bKeepBase64 - 1=don't decode base64, 0=decode base64
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocSAXGetDataFile(SignedDoc* pSigDoc, const char* szFileName,
+ const char* szDocId, DigiDocMemBuf* pOutBuf,
+ int bKeepBase64)
+{
+ FILE *f;
+ int ret, err = ERR_OK;
+ char chars[1025], convFileName[1024], *p, buf1[200];
+ xmlParserCtxtPtr ctxt;
+ SigDocParse pctx;
+
+ RETURN_IF_NULL_PARAM(szFileName);
+ RETURN_IF_NULL_PARAM(szDocId);
+ clearErrors();
+ ddocDebug(3, "ddocSAXGetDataFile", "SigDoc: %s, docid: %s, digidoc: %s, keepb64: %d",
+ (pSigDoc ? "OK" : "NULL"), szDocId, szFileName, bKeepBase64);
+ // try reading from memory if already cached?
+ pOutBuf->pMem = 0;
+ pOutBuf->nLen = 0;
+ ret = ddocGetDataFileCachedData(pSigDoc, szDocId, &(pOutBuf->pMem), &pOutBuf->nLen);
+ if(pOutBuf->pMem) { // gotcha
+ ddocDebug(3, "ddocSAXGetDataFile", "Using cached data: %d bytes", pOutBuf->nLen);
+ return ret;
+ }
+ memset(&pctx, 0, sizeof(pctx));
+ ddocConvertFileName( convFileName, sizeof(convFileName), szFileName );
+ if ((f = fopen(convFileName, "r")) != NULL) {
+ pctx.pSigDoc = NULL;
+ pctx.bDataFile = NULL;
+ pctx.ctx1[0] = pctx.ctx2[0] = pctx.ctx3[0] = pctx.tag[0] = pctx.ctx4[0] = 0;
+ pctx.errcode = ERR_OK;
+ pctx.bKeepBase64 = bKeepBase64;
+ pOutBuf->pMem = 0;
+ pOutBuf->nLen = 0;
+ pctx.pMemBufDF = pOutBuf;
+ time(&(pctx.tStartParse));
+ pctx.bDataFile = NULL; //BIO_new_file(szDataFileName, "w");
+ //strcpy(pctx.ctx1, szCharset);
+ pctx.szInputFileName = (char*)szFileName;
+ strncpy(pctx.ctx3, szDocId, sizeof(pctx.ctx3));
+ memset(chars, 0, sizeof(chars));
+ ret = fread(chars, 1, 100, f);
+ if (ret > 0) {
+ p = strstr(chars, "<?xml");
+ if(!p)
+ p = chars;
+ ctxt = xmlCreatePushParserCtxt(extractSAXHandler, &pctx,
+ p, strlen(p), szFileName);
+ do {
+ memset(chars, 0, sizeof(chars));
+ ret = fread(chars, 1, sizeof(chars)-1, f);
+ if(ret <= 0) break;
+ if(ret > 0 && ret < sizeof(chars)) chars[ret] = 0;
+ if(pctx.bCollectDFData > 0) { // bypass mode
+ // look for new element start "<"
+ p = strchr(chars, '<');
+ // if we just enetered the bypass mode then send flush command
+ // but increment bypass mode in order not to fall out of it
+ if(pctx.bCollectDFData == 1 && !p) { // start bypass mode
+ pctx.bCollectDFData += 2; // increment with 2 so we dont return to flushing
+ ddocDebug(4, "ddocSAXGetDataFile", "Starting bypass mode, skip: %d",
+ pctx.bCollectDFData);
+ // force the parser to release element content
+ // before entering into bypass mode
+ xmlParseChunk(ctxt, g_szDataFileFlush1, strlen(g_szDataFileFlush1), 0);
+ ddocDebug(4, "ddocSAXGetDataFile", "Entering bypass mode, skip: %d",
+ pctx.bCollectDFData);
+ }
+ if(pctx.bCollectDFData >=2 && !p) { // parse in bypass mode
+ ddocDebug(4, "ddocSAXGetDataFile", "Parsing in bypass mode, skip: %d len: %d",
+ pctx.bCollectDFData, ret);
+ extractBodyHandler(&pctx, (const char*)chars, ret);
+ }
+ if(p) { // finish bypass mode
+ ddocDebug(4, "ddocSAXGetDataFile", "Ending bypass mode len: %d, skip: %d",
+ ret, pctx.bCollectDFData);
+ snprintf(buf1, sizeof(buf1), g_szDataFileFlush2, pctx.ctx3, pctx.ctx4);
+ // send finish command
+ xmlParseChunk(ctxt, buf1, strlen(buf1), 0);
+ pctx.bCollectDFData = 1;
+ // parse the normal chunk that caused end
+ xmlParseChunk(ctxt, chars, ret, 0);
+ }
+ } else { // normal mode
+ ddocDebug(4, "ddocSAXGetDataFile", "parsing normal chunk");
+ xmlParseChunk(ctxt, chars, ret, 0);
+ }
+
+ } while(ret > 0);
+ xmlParseChunk(ctxt, chars, 0, 1);
+ xmlFreeParserCtxt(ctxt);
+ }
+ fclose(f);
+ } else {
+ ddocDebug(1, "ddocSAXGetDataFile", "Error reading file: %s", szFileName);
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_READ);
+ }
+ if(!err)
+ err = getLastError();
+ // cleanup parser context
+ ddocSAXCleanup(&pctx);
+ return err;
+}
+
+
+//--------------------------------------------------
+// Reads new signatures from another digidoc file
+// and adds to existing digidoc. Adds only those
+// signatures that don't exist in old digidoc.
+// pSigDoc - signed document object
+// szFileName - name of digidoc file
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocReadNewSignaturesFromDdoc(SignedDoc* pSigDoc, const char* szFileName)
+{
+ SignedDoc *pSigDoc2 = 0;
+ int err = ERR_OK, n1 = 0, n2 = 0, i;
+ SignatureInfo** pSignatures = NULL;
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ RETURN_IF_NULL_PARAM(szFileName);
+ // read in digidoc file
+ err = ddocSaxReadSignedDocFromFile(&pSigDoc2, szFileName, 0, 0);
+ if(err) {
+ if(pSigDoc2)
+ SignedDoc_free(pSigDoc2);
+ return err;
+ }
+ // copy new signatures from digidoc just read in
+ // assumes that new signatures are at the end
+ n1 = getCountOfSignatures(pSigDoc);
+ n2 = getCountOfSignatures(pSigDoc2);
+ if(n2 > n1) {
+ pSignatures = (SignatureInfo**)realloc(pSigDoc->pSignatures, n2 * sizeof(void *));
+ if(!pSignatures) {
+ if(pSigDoc2)
+ SignedDoc_free(pSigDoc2);
+ RETURN_IF_BAD_ALLOC(pSignatures);
+ }
+ pSigDoc->pSignatures = pSignatures;
+ for(i = n1; i < n2; i++) {
+ pSigDoc->pSignatures[i] = pSigDoc2->pSignatures[i]; // take ownership
+ pSigDoc2->pSignatures[i] = 0; // set to NULL to prevent deallocation
+ // VS destroy hash - debug
+ ((char*)pSigDoc->pSignatures[i]->pDocs[0]->szDigest)[0] = 0x0A;
+ }
+ pSigDoc->nSignatures = n2;
+ pSigDoc2->nSignatures = n1;
+ }
+ // delete new digidoc object no longer necessary
+ SignedDoc_free(pSigDoc2);
+
+ return err;
+}
+
+char* pHdr1 = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\n";
+char* pHdr2 = "<SignedDoc format=\"DIGIDOC-XML\" version=\"1.3\" xmlns=\"http://www.sk.ee/DigiDoc/v1.3.0#\">\n";
+char* pHdr3 = "\n</SignedDoc>";
+
+//--------------------------------------------------
+// Adds new signature to existing ddoc
+// szFileName - ddoc file name
+// pSigBuf - buffer with new signature data
+// nSigLen - new signature data length
+//--------------------------------------------------
+EXP_OPTION int ddocAddSignatureFromMemory(SignedDoc* pSigDoc, const char* szFileName, const void* pSigBuf, int nSigLen)
+{
+ int err = ERR_OK, n1 = 0, n2 = 0, i;
+ SignatureInfo** pSignatures = NULL;
+ SignedDoc *pSigDoc2 = 0;
+ char buf1[102], *p1;
+ FILE* f;
+ DigiDocMemBuf mbuf1;
+#ifdef WIN32
+ wchar_t *convFileName = 0;
+ int ret = 0;
+#endif
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ //RETURN_IF_NULL_PARAM(szFileName && strlen(szFileName));
+ RETURN_IF_NULL_PARAM(pSigBuf);
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ clearErrors();
+ ddocDebug(3, "ddocAddSignatureFromMemory", "SigDoc: %s, file: %s, sig: %s, slen: %d",
+ (pSigDoc ? "OK" : "NULL"), szFileName, (pSigBuf ? "OK" : "NULL"), nSigLen);
+
+ // read in digidoc buffer
+ ddocMemAssignData(&mbuf1, pHdr1, -1);
+ ddocMemAppendData(&mbuf1, pHdr2, -1);
+ ddocMemAppendData(&mbuf1, pSigBuf, nSigLen);
+ ddocMemAppendData(&mbuf1, pHdr3, -1);
+ err = ddocSaxReadSignedDocFromMemory(&pSigDoc2, mbuf1.pMem, mbuf1.nLen, mbuf1.nLen);
+ ddocMemBuf_free(&mbuf1);
+ if(err) {
+ ddocDebug(1, "ddocAddSignatureFromMemory", "Error: %d reading signature", err);
+ if(pSigDoc2)
+ SignedDoc_free(pSigDoc2);
+ return err;
+ }
+ // copy new signatures from digidoc just read in
+ // assumes that new signatures are at the end
+ n1 = getCountOfSignatures(pSigDoc);
+ n2 = getCountOfSignatures(pSigDoc2);
+ if(n2 > n1) {
+ pSignatures = (SignatureInfo**)realloc(pSigDoc->pSignatures, n2 * sizeof(void *));
+ if(!pSignatures) {
+ if(pSigDoc2)
+ SignedDoc_free(pSigDoc2);
+ RETURN_IF_BAD_ALLOC(pSignatures);
+ }
+ pSigDoc->pSignatures = pSignatures;
+ for(i = n1; i < n2; i++) {
+ pSigDoc->pSignatures[i] = pSigDoc2->pSignatures[i]; // take ownership
+ pSigDoc2->pSignatures[i] = 0; // set to NULL to prevent deallocation
+ }
+ pSigDoc->nSignatures = n2;
+ pSigDoc2->nSignatures = n1;
+ }
+ // delete new digidoc object no longer necessary
+ SignedDoc_free(pSigDoc2);
+ ddocDebug(3, "ddocAddSignatureFromMemory", "RC: %d adding signature", err);
+ // now append new signature to existing ddoc file
+ if(szFileName && strlen(szFileName)) { // if we have to update ddoc on disc
+#ifdef WIN32
+ err = utf82unicode((const char*)szFileName, (char**)&convFileName, &ret);
+ ddocDebug(3, "ddocAddSignatureFromMemory", "file: %s, conv-file: %s", szFileName, convFileName);
+ ddocDebug(3, "ddocSaxReadSignedDocFromFile", "Opening file: %s", convFileName);
+ if(!err && ((f = _wfopen(convFileName, L"r+b")) != NULL)) {
+#else
+ ddocDebug(3, "ddocSaxReadSignedDocFromFile", "Opening file: %s", szFileName);
+ if(!err && ((f = fopen(szFileName, "r+b")) != NULL)) {
+#endif
+ ddocDebug(3, "ddocSaxReadSignedDocFromFile", "file opened, pos: %d", ftell(f));
+ // seek to file end -100 bytes anf find ddoc end tag
+ err = fseek(f, -30, SEEK_END);
+ ddocDebug(3, "ddocSaxReadSignedDocFromFile", "seek: %d new pos: %d", err, ftell(f));
+ memset(buf1, 0, sizeof(buf1));
+ n1 = fread(buf1, 1, 30, f);
+ ddocDebug(3, "ddocSaxReadSignedDocFromFile", "read: %d data: %s", n1, buf1);
+ p1 = strstr(buf1, "</SignedDoc>");
+ if(p1) {
+ *p1 = 0;
+ n2 = strlen(buf1);
+ ddocDebug(3, "ddocSaxReadSignedDocFromFile", "distance: %d", n2);
+ err = fseek(f, -1 * (30 - n2), SEEK_END);
+ ddocDebug(3, "ddocSaxReadSignedDocFromFile", "seek: %d new pos: %d", err, ftell(f));
+ n1 = fwrite(pSigBuf, 1, nSigLen, f);
+ ddocDebug(3, "ddocSaxReadSignedDocFromFile", "wrote: %d", n1);
+ fputs("</SignedDoc>", f);
+ }
+ fclose(f);
+ }
+ } // if szFileName
+ return err;
+}
+