summaryrefslogtreecommitdiff
path: root/libdigidoc/DigiDocGen.c
diff options
context:
space:
mode:
Diffstat (limited to 'libdigidoc/DigiDocGen.c')
-rw-r--r--libdigidoc/DigiDocGen.c1925
1 files changed, 1925 insertions, 0 deletions
diff --git a/libdigidoc/DigiDocGen.c b/libdigidoc/DigiDocGen.c
new file mode 100644
index 0000000..dc016b1
--- /dev/null
+++ b/libdigidoc/DigiDocGen.c
@@ -0,0 +1,1925 @@
+//==================================================
+// FILE: DigiDocGen.c
+// PROJECT: Digi Doc
+// DESCRIPTION: DigiDoc helper routines for XML generation
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 11.04.2006 Veiko Sinivee
+// Creation
+//==================================================
+
+
+#include <libdigidoc/DigiDocDefs.h>
+#include <libdigidoc/DigiDocLib.h>
+#include <libdigidoc/DigiDocDebug.h>
+#include <libdigidoc/DigiDocConfig.h>
+#include <libdigidoc/DigiDocConvert.h>
+#include <libdigidoc/DigiDocCert.h>
+#include <libdigidoc/DigiDocSAXParser.h>
+#include <libdigidoc/DigiDocDfExtract.h>
+#include <libdigidoc/DigiDocGen.h>
+#include <libdigidoc/DigiDocError.h>
+#include <string.h>
+#include <time.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>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+
+#include <fcntl.h>
+
+//-----------< helper functions >----------------------------
+
+
+//--------------------------------------------------
+// Appends an xml element start to buffer, but no ">"
+// pBuf - memory buffer to store xml [REQUIRED]
+// elemName - xml element name [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocGen_startElemBegin(DigiDocMemBuf* pBuf, const char* elemName)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pBuf)
+ RETURN_IF_NULL_PARAM(elemName)
+ err = ddocMemAppendData(pBuf, "<", -1);
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, elemName, -1);
+ return err;
+}
+
+//--------------------------------------------------
+// Appends an xml element start tag end to buffer - ">"
+// pBuf - memory buffer to store xml [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocGen_startElemEnd(DigiDocMemBuf* pBuf)
+{
+ RETURN_IF_NULL_PARAM(pBuf)
+ return ddocMemAppendData(pBuf, ">", -1);
+}
+
+//--------------------------------------------------
+// Appends an xml element start to buffer - <tag>
+// pBuf - memory buffer to store xml [REQUIRED]
+// elemName - xml element name [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocGen_startElem(DigiDocMemBuf* pBuf, const char* elemName)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pBuf)
+ RETURN_IF_NULL_PARAM(elemName)
+ err = ddocMemAppendData(pBuf, "<", -1);
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, elemName, -1);
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, ">", -1);
+ return err;
+}
+
+//--------------------------------------------------
+// Appends an xml element end to buffer
+// pBuf - memory buffer to store xml [REQUIRED]
+// elemName - xml element name [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocGen_endElem(DigiDocMemBuf* pBuf, const char* elemName)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pBuf)
+ RETURN_IF_NULL_PARAM(elemName)
+ err = ddocMemAppendData(pBuf, "</", -1);
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, elemName, -1);
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, ">", -1);
+ return err;
+}
+
+//--------------------------------------------------
+// Appends an xml element's atribute to buffer
+// pBuf - memory buffer to store xml [REQUIRED]
+// name - xml atribute name [REQUIRED]
+// value - xml atribute value [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocGen_addAtribute(DigiDocMemBuf* pBuf, const char* name, const char* value)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pBuf)
+ RETURN_IF_NULL_PARAM(name)
+ RETURN_IF_NULL_PARAM(value)
+ err = ddocMemAppendData(pBuf, " ", -1);
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, name, -1);
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, "=\"", -1);
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, value, -1);
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, "\"", -1);
+ return err;
+}
+
+//================< functions Timestamp_st > =================================
+#ifdef WITH_TIMETSTAMP_STRUCT
+
+//===================================================================
+// converts string to timestamp
+// IN const char* szTimestamp - timestamp string
+// OUT Timestamp* pTimestamp
+//===================================================================
+EXP_OPTION int convertStringToTimestamp(const SignedDoc* pSigDoc, const char* szTimestamp, Timestamp* pTimestamp)
+{
+ RETURN_IF_NULL_PARAM(szTimestamp);
+ RETURN_IF_NULL_PARAM(pTimestamp);
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ // in version 1.3 we use format CCYY-MM-DDTHH:MM:SS-TZ
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER) ) {
+ sscanf(szTimestamp, "%04d-%02d-%04dT%02d:%02d:%02dZ",
+ &(pTimestamp->year), &(pTimestamp->mon), &(pTimestamp->day),
+ &(pTimestamp->hour), &(pTimestamp->min), &(pTimestamp->sec));
+ pTimestamp->tz = 0;
+ } else
+ // in version 1.0 we use format CCYY.MM.DDTHH:MM:SS-TZ
+ if(!strcmp(pSigDoc->szFormat, SK_XML_1_NAME) && !strcmp(pSigDoc->szFormatVer, SK_XML_1_VER)) {
+ sscanf(szTimestamp, "%04d.%02d.%04dT%02d:%02d:%02d%3d:00",
+ &(pTimestamp->year), &(pTimestamp->mon), &(pTimestamp->day),
+ &(pTimestamp->hour), &(pTimestamp->min), &(pTimestamp->sec), &(pTimestamp->tz));
+ } else { // in version 1.1 we use format CCYY.MM.DDTHH:MM:SSZ and allways UTC time
+ sscanf(szTimestamp, "%04d.%02d.%04dT%02d:%02d:%02dZ",
+ &(pTimestamp->year), &(pTimestamp->mon), &(pTimestamp->day),
+ &(pTimestamp->hour), &(pTimestamp->min), &(pTimestamp->sec));
+ pTimestamp->tz = 0;
+ }
+ return ERR_OK;
+}
+
+//===================================================================
+// converts string to timestamp
+// IN const char* szTimestamp - timestamp string
+// OUT Timestamp* pTimestamp
+//===================================================================
+EXP_OPTION int convertTimestampToString(const SignedDoc* pSigDoc, const Timestamp* pTimestamp,
+ char* szTimestamp, int len)
+{
+ RETURN_IF_NULL_PARAM(szTimestamp);
+ RETURN_IF_NULL_PARAM(pTimestamp);
+ //RETURN_IF_NULL_PARAM(pSigDoc); // if null then latest format is used
+
+ // in version 1.3 we use format CCYY-MM-DDTHH:MM:SS-TZ
+ //AM 30.04.08 also in bdoc
+ if(!pSigDoc || (pSigDoc && (
+ !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER) ))) {
+ snprintf(szTimestamp, len, "%04d-%02d-%02dT%02d:%02d:%02dZ",pTimestamp->year,
+ pTimestamp->mon, pTimestamp->day, pTimestamp->hour , pTimestamp->min,
+ pTimestamp->sec);
+ } else // in version 1.0 we use format CCYY.MM.DDTHH:MM:SS-TZ
+ if(!strcmp(pSigDoc->szFormat, SK_XML_1_NAME) && !strcmp(pSigDoc->szFormatVer, SK_XML_1_VER)) {
+ snprintf(szTimestamp, len, "%04d.%02d.%02dT%02d:%02d:%02d%+03d:00",pTimestamp->year,
+ pTimestamp->mon, pTimestamp->day, pTimestamp->hour , pTimestamp->min,
+ pTimestamp->sec, pTimestamp->tz);
+ } else { // in version 1.1 we use format CCYY.MM.DDTHH:MM:SSZ and allways UTC time
+ snprintf(szTimestamp, len, "%04d.%02d.%02dT%02d:%02d:%02dZ",pTimestamp->year,
+ pTimestamp->mon, pTimestamp->day, pTimestamp->hour , pTimestamp->min,
+ pTimestamp->sec);
+ }
+ return ERR_OK;
+}
+
+// converts date integers to timestamp object
+EXP_OPTION int Timestamp_new(Timestamp **ppTimestamp, int year,int month,int day,int hour,int minute,int second,int timezone){
+ Timestamp* pTimestamp;
+ pTimestamp = (Timestamp*)malloc(sizeof(Timestamp));
+ RETURN_IF_BAD_ALLOC(pTimestamp);
+ memset(pTimestamp, 0, sizeof(Timestamp));
+ pTimestamp->year=year;
+ pTimestamp->mon=month;
+ pTimestamp->day=day;
+ pTimestamp->hour=hour;
+ pTimestamp->min=minute;
+ pTimestamp->sec=second;
+ pTimestamp->tz=timezone;
+ *ppTimestamp = pTimestamp;
+ return ERR_OK;
+}
+
+//======================================================================
+// frees timestamp object
+//======================================================================
+EXP_OPTION void Timestamp_free(Timestamp* pTimestamp){
+ free(pTimestamp);
+}
+
+
+#endif
+
+//===================================================================
+// converts timestamp string to time_t value
+// IN const char* szTimestamp - timestamp string
+// OUT Timestamp* pTimestamp
+//===================================================================
+EXP_OPTION time_t convertStringToTimeT(const SignedDoc* pSigDoc, const char* szTimestamp)
+{
+ struct tm tm1;
+ int tz, dmz = 0;
+ time_t t2;
+
+ memset(&tm1, 0, sizeof(tm1));
+ tzset();
+ t2 = 0;
+ // in version 1.0 we use format CCYY.MM.DDTHH:MM:SS-TZ
+ if(!strcmp(pSigDoc->szFormat, SK_XML_1_NAME) && !strcmp(pSigDoc->szFormatVer, SK_XML_1_VER)) {
+ sscanf(szTimestamp, "%04d.%02d.%02dT%02d:%02d:%02d+%03d:00",
+ &(tm1.tm_year), &(tm1.tm_mon), &(tm1.tm_mday),
+ &(tm1.tm_hour) , &(tm1.tm_min), &(tm1.tm_sec), &tz);
+ } else if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_1_VER) ||
+ !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_2_VER)) { // in version 1.1 we use format CCYY.MM.DDTHH:MM:SSZ and allways UTC time
+ sscanf(szTimestamp, "%04d.%02d.%02dT%02d:%02d:%02dZ", //crash?
+ &(tm1.tm_year), &(tm1.tm_mon), &(tm1.tm_mday),
+ &(tm1.tm_hour), &(tm1.tm_min), &(tm1.tm_sec));
+ } else { // in version 1.3 we use format CCYY-MM-DDTHH:MM:SSZ and allways UTC time
+ sscanf(szTimestamp, "%04d-%02d-%02dT%02d:%02d:%02dZ",
+ &(tm1.tm_year), &(tm1.tm_mon), &(tm1.tm_mday),
+ &(tm1.tm_hour), &(tm1.tm_min), &(tm1.tm_sec));
+ }
+ tm1.tm_year -= 1900;
+ tm1.tm_mon -= 1;
+ tm1.tm_isdst = daylight;
+ t2 = mktime(&tm1);
+ if(_daylight != 0) {
+ if(_timezone < 0)
+ dmz = (_timezone / 3600) - daylight;
+ else
+ dmz = (_timezone / 3600) + daylight;
+ }
+ else
+ dmz = _timezone / 3600;
+ t2 -= (dmz * 3600);
+ return t2;
+}
+
+
+//================< functions generating DigiDoc formats 1.0 - 1.3 > =================================
+
+
+
+//============================================================
+// Creates a timestamp string
+// buf - output buffer
+// len - length of output buffer
+// returns number of output bytes written
+//============================================================
+int createTimestamp(const SignedDoc* pSigDoc, char* buf, int len)
+{
+ time_t t;
+ struct tm tm1;
+ Timestamp *pTimestamp;
+ int dmz=0;
+
+ RETURN_OBJ_IF_NULL(buf, 0);
+ _tzset();
+ time(&t);
+ // in version 1.0 we use format CCYY.MM.DDTHH:MM:SS-TZ
+ if(pSigDoc && pSigDoc->szFormatVer && !strcmp(pSigDoc->szFormatVer, "1.0")) {
+ ddocLocalTime(&t, &tm1, 1);
+ if(_daylight != 0) {
+ /*if(_timezone<0){*/
+ dmz=(_timezone - (_daylight*3600))/ 3600;
+ /*}else{
+ dmz=(_timezone + (_daylight*3600))/ 3600;
+ }*/
+ }else{
+ dmz = _timezone / 3600;
+ }
+ } else { // in version 1.1 we use UTC time
+ ddocLocalTime(&t, &tm1, 0);
+ }
+ (void)Timestamp_new(&pTimestamp, tm1.tm_year + 1900, tm1.tm_mon + 1, tm1.tm_mday,
+ tm1.tm_hour, tm1.tm_min, tm1.tm_sec, dmz);
+ (void)convertTimestampToString(pSigDoc, pTimestamp, buf, len);
+ Timestamp_free(pTimestamp);
+ return strlen(buf);
+}
+
+//============================================================
+// Canonicalizes XML
+// source - input data
+// len - input length
+// returns a newly allocated buffer with canonicalized XML
+// Caller must free() the result.
+//============================================================
+char* canonicalizeXML(char* source, int len)
+{
+ xmlDocPtr doc = NULL;
+ xmlChar* pBuf = NULL;
+ int rc, n;
+ char* dest = NULL;
+
+ ddocDebug(5, "canonicalizeXML", "Canonicalizing: %d bytes", len);
+ if((doc = xmlParseMemory(source, len)) != NULL) {
+ ddocDebug(5, "canonicalizeXML", "Canonicalizing parse: %s", (doc ? "OK" : "ERROR"));
+ rc = xmlC14NDocDumpMemory(doc, NULL, 0, NULL, 0, &pBuf);
+ ddocDebug(5, "canonicalizeXML", "Canonicalizing RC: %d: BUF: %s", rc, (pBuf ? "OK" : "ERROR"));
+ if(pBuf) {
+ n = strlen((char*)pBuf);
+ dest = (char*)malloc(n + 1);
+ if(dest) {
+ strncpy(dest, (char*)pBuf, n);
+ dest[n] = 0;
+ }
+ else
+ SET_LAST_ERROR_IF_NOT(dest, ERR_BAD_ALLOC);
+ xmlFree(pBuf);
+ }
+ xmlFreeDoc(doc);
+ }
+ return dest;
+}
+
+
+
+
+//============================================================
+// Canonicalizes XML
+// source - input data
+// len - input length
+// returns a newly allocated buffer with canonicalized XML
+// Caller must free() the result.
+//============================================================
+char* canonicalizeXMLBlock(char* source, int len, char* block, char* prefix)
+{
+ xmlDocPtr doc = NULL;
+ xmlChar* pBuf = NULL;
+ int rc, n;
+ char* dest = NULL;
+ xmlXPathContextPtr xpathCtx;
+ xmlXPathObjectPtr xpathObj;
+ //xmlChar* incpref[] = {(xmlChar*)"ds", (xmlChar*)"xades", NULL};
+
+ ddocDebug(5, "canonicalizeXMLBlock", "Canonicalizing: %d bytes", len);
+ if((doc = xmlParseMemory(source, len)) != NULL) {
+ ddocDebug(5, "canonicalizeXMLBlock", "Canonicalizing parse: %s", (doc ? "OK" : "ERROR"));
+ /* Create xpath evaluation context */
+ xpathCtx = xmlXPathNewContext(doc);
+ if(xpathCtx == NULL) {
+ ddocDebug(5, "canonicalizeXMLBlock", "Error: unable to create new XPath context");
+ xmlFreeDoc(doc);
+ return NULL;
+ }
+ if(prefix && strlen(prefix)){
+ ddocDebug(5, "canonicalizeXMLBlock","xmlXPathRegisterNs");
+ if(xmlXPathRegisterNs(xpathCtx, prefix, "http://www.w3.org/2000/09/xmldsig#") != 0) {
+ ddocDebug(5, "canonicalizeXMLBlock","Error: failed to register namespace");
+ xmlXPathFreeContext(xpathCtx);
+ xmlFreeDoc(doc);
+ return NULL;
+ }
+ }
+ ddocDebug(5, "canonicalizeXMLBlock","xmlXPathRegisterNs123");
+ if(xmlXPathRegisterNs(xpathCtx, "xs", "http://uri.etsi.org/01903/v1.3.2#") != 0) {
+ ddocDebug(5, "canonicalizeXMLBlock","Error: failed to register namespace2\n");
+ xmlXPathFreeContext(xpathCtx);
+ xmlFreeDoc(doc);
+ return NULL;
+ }
+ /* Evaluate xpath expression */
+ xpathObj = xmlXPathEvalExpression(block, xpathCtx);
+ if(xpathObj == NULL) {
+ ddocDebug(5, "canonicalizeXMLBlock","Error: unable to evaluate xpath expression \"%s\"\n", block);
+ xmlXPathFreeContext(xpathCtx);
+ xmlFreeDoc(doc);
+ }
+ rc = xmlC14NDocDumpMemory(doc, xpathObj->nodesetval, 0, NULL, 0, &pBuf);
+ ddocDebug(5, "canonicalizeXMLBlock", "Canonicalizing RC: %d: BUF: %s", rc, (pBuf ? "OK" : "ERROR"));
+ if(pBuf) {
+ n = strlen((char*)pBuf);
+ dest = (char*)malloc(n + 1);
+ if(dest)
+ strncpy(dest, (char*)pBuf, n+1);
+ else
+ SET_LAST_ERROR_IF_NOT(dest, ERR_BAD_ALLOC);
+ xmlFree(pBuf);
+ }
+ xmlFreeDoc(doc);
+ }
+ return dest;
+}
+
+//--------------------------------------------------
+// Helper function that escapes XML special chars in xml element body
+// src - input data
+// srclen - length of input data. Use -1 for 0 terminated strings
+// dest - address of output buffer. Caller is responsible for deallocating it!
+// returns error code or ERR_OK
+//--------------------------------------------------
+int escapeTextNode(const char* src, int srclen, char** dest)
+{
+ int j, i, n = srclen, l;
+ char *p = 0;
+
+ RETURN_IF_NULL_PARAM(src);
+ RETURN_IF_NULL_PARAM(dest);
+ *dest = 0;
+ if(n < 0)
+ n = strlen(src);
+ if(n > 0 && ConfigItem_lookup_int("DEBUG_LEVEL", 1) >= 5) {
+ p = (char*)malloc(n+1);
+ if(p) {
+ memset(p, 0, n+1);
+ memcpy(p, src, n);
+ ddocDebug(5, "escapeTextNode", "src: \"%s\" len: %d", p, n);
+ free(p);
+ }
+ }
+ else
+ ddocDebug(5, "escapeTextNode", "src: \"%s\" len: %d", src, n);
+ // count the amount of memory needed for conversion
+ for(i = l = 0; i < n; i++) {
+ switch(src[i]) {
+ case '<': l += 4; break;
+ case '>': l += 4; break;
+ case '&': l += 5; break;
+ case '\r': l += 5; break;
+ default: l ++; break;
+ }
+ }
+ // count the last terminator char
+ l++;
+ ddocDebug(5, "escapeTextNode", "allocating: %d bytes", l);
+ *dest = (char*)malloc(l);
+ memset(*dest, 0, l);
+ // now convert the data
+ for(i = j = 0; i < n; i++) {
+ switch(src[i]) {
+ case '<': strncat(*dest, "&lt;", l - strlen(*dest)); j += 4; break;
+ case '>': strncat(*dest, "&gt;", l - strlen(*dest)); j += 4; break;
+ case '&':
+ if(src[i+3] != ';' && src[i+4] != ';' && src[i+5] != ';') {
+ if(src[i+1] != '#') {
+ strncat(*dest, "&amp;", l - strlen(*dest)); j += 5; break;
+ } else {
+ if(!strncmp(src+i, "&#38;", 5)) {
+ strncat(*dest, "&amp;", l - strlen(*dest)); j += 5; i += 4; break;
+ }
+ // but others?
+ }
+ } else {
+ (*dest)[j] = src[i]; j++;
+ }
+ break;
+ case '\r': strncat(*dest, "&#xD;", l - strlen(*dest)); j += 5; break;
+ default: (*dest)[j] = src[i]; j++; break;
+ }
+ }
+ ddocDebug(4, "escapeTextNode", "Src: %s Converted: \'%s\' len: %d", src, *dest, j);
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Helper function that escapes XML special chars
+// src - input data
+// srclen - length of input data. Use -1 for 0 terminated strings
+// dest - address of output buffer. Caller is responsible for deallocating it!
+// returns error code or ERR_OK
+//--------------------------------------------------
+int escapeXMLSymbols(const char* src, int srclen, char** dest)
+{
+ int j, i, n = srclen, l;
+ char *p = 0;
+
+ RETURN_IF_NULL_PARAM(src);
+ RETURN_IF_NULL_PARAM(dest);
+ *dest = 0;
+ if(n < 0)
+ n = strlen(src);
+ if(n > 0 && ConfigItem_lookup_int("DEBUG_LEVEL", 1) >= 5) {
+ p = (char*)malloc(n+1);
+ if(p) {
+ memset(p, 0, n+1);
+ memcpy(p, src, n);
+ ddocDebug(5, "escapeXMLSymbols", "src: \"%s\" len: %d", p, n);
+ free(p);
+ }
+ }
+ else
+ ddocDebug(5, "escapeXMLSymbols", "src: \"%s\" len: %d", src, n);
+ // count the amount of memory needed for conversion
+ for(i = l = 0; i < n; i++) {
+ switch(src[i]) {
+ case '<': l += 4; break;
+ case '>': l += 4; break;
+ case '&': l += 5; break;
+ case '\r': l += 5; break;
+ case '\'': l += 6; break;
+ case '\"': l += 6; break;
+ default: l ++; break;
+ }
+ }
+ // count the last terminator char
+ l++;
+ ddocDebug(5, "escapeXMLSymbols", "allocating: %d bytes", l);
+ *dest = (char*)malloc(l);
+ memset(*dest, 0, l);
+ // now convert the data
+ for(i = j = 0; i < n; i++) {
+ switch(src[i]) {
+ case '<': strncat(*dest, "&lt;", l - strlen(*dest)); j += 4; break;
+ case '>': strncat(*dest, "&gt;", l - strlen(*dest)); j += 4; break;
+ case '&':
+ if(src[i+3] != ';' && src[i+4] != ';' && src[i+5] != ';') {
+ if(src[i+1] != '#') {
+ strncat(*dest, "&amp;", l - strlen(*dest)); j += 5; break;
+ } else {
+ if(!strncmp(src+i, "&#38;", 5)) {
+ strncat(*dest, "&amp;", l - strlen(*dest)); j += 5; i += 4; break;
+ }
+ // but others?
+ }
+ } else {
+ (*dest)[j] = src[i]; j++;
+ }
+ break;
+ case '\r': strncat(*dest, "&#xD;", l - strlen(*dest)); j += 5; break;
+ case '\'': strncat(*dest, "&apos;", l - strlen(*dest)); j += 6; break;
+ case '\"': strncat(*dest, "&quot;", l - strlen(*dest)); j += 6; break;
+ default: (*dest)[j] = src[i]; j++; break;
+ }
+ }
+ ddocDebug(4, "escapeXMLSymbols", "Src: %s Converted: \'%s\' len: %d", src, *dest, j);
+ return ERR_OK;
+}
+
+
+//============================================================
+// Creates a <SignedProperties> XML block
+// pSigDoc - signed document pointer
+// pSigInfo - signature info data
+// bWithEscapes - 1=escape xml symbols, 0=don't escape
+// returns new <SignedProperties> node
+//============================================================
+char* createXMLSignedProperties(const SignedDoc* pSigDoc, const SignatureInfo* pSigInfo, int bWithEscapes)
+{
+ char buf1[1024], *pRet = 0, *p1, *p2;
+ int len1, i, err;
+ xmlNodePtr pSigProp, pSigSigProp, pSigCert, pN1, pN2, pN3;
+ static xmlChar nl[] = "\n";
+ xmlDocPtr doc;
+ DigiDocMemBuf *pMBuf1;
+ xmlChar *pBuf = NULL;
+
+ // XML doc
+ doc = xmlNewDoc((const xmlChar*)"1.0");
+ // <SignedProperties>
+ pSigProp = doc->children = xmlNewDocNode(doc, NULL, (const xmlChar*)"SignedProperties", NULL);
+ // Ver 1.76 - in format 1.3 xmlns atribute is not used
+ // in ver 1.1 we need this namespace def
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_1_VER) ||
+ !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_2_VER)) {
+ xmlNewNs(pSigProp, (const xmlChar*)NAMESPACE_XML_DSIG, NULL);
+ } else if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER)) { // in 1.3 we use the correct etsi namespace
+ xmlNewNs(pSigProp, (const xmlChar*)NAMESPACE_XADES_111, NULL);
+ }
+ // in 1.0 we had this buggy URI
+ if(!strcmp(pSigDoc->szFormat, SK_XML_1_NAME) && !strcmp(pSigDoc->szFormatVer, SK_XML_1_VER))
+ snprintf(buf1, sizeof(buf1), "#%s-SignedProperties", pSigInfo->szId);
+ else // current version is 1.1
+ snprintf(buf1, sizeof(buf1), "%s-SignedProperties", pSigInfo->szId);
+ xmlSetProp(pSigProp, (const xmlChar*)"Id", (const xmlChar*)buf1);
+
+ // Ver 1.76 - in format 1.3 Target atribute is not used
+ if(strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER) ) {
+ snprintf(buf1, sizeof(buf1), "#%s", pSigInfo->szId);
+ xmlSetProp(pSigProp, (const xmlChar*)"Target", (const xmlChar*)buf1);
+ }
+ // <SignedSignatureProperties>
+ pSigSigProp = xmlNewChild(pSigProp, NULL, (const xmlChar*)"SignedSignatureProperties", nl);
+ // <SigningTime>
+ pN1 = xmlNewChild(pSigSigProp, NULL, (const xmlChar*)"SigningTime", (const xmlChar*)pSigInfo->szTimeStamp);
+ xmlNodeAddContent(pSigSigProp, nl);
+ // <SigningCertificate>
+ pSigCert = xmlNewChild(pSigSigProp, NULL, (const xmlChar*)"SigningCertificate", nl);
+ // <Cert>
+ pN1 = xmlNewChild(pSigCert, NULL, (const xmlChar*)"Cert", nl);
+ // Ver 1.76 - in format 1.3 Id atribute is not used
+ if(strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER) ) {
+ // in 1.0 we had this buggy URI
+ if(!strcmp(pSigDoc->szFormat, SK_XML_1_NAME) && !strcmp(pSigDoc->szFormatVer, SK_XML_1_VER))
+ snprintf(buf1, sizeof(buf1), "#%s-CERTINFO", pSigInfo->szId);
+ else
+ snprintf(buf1, sizeof(buf1), "%s-CERTINFO", pSigInfo->szId);
+ xmlSetProp(pN1, (const xmlChar*)"Id", (const xmlChar*)buf1);
+ }
+ // <CertDigest>
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"CertDigest", nl);
+ // <DigestMethod>
+ pN3 = xmlNewChild(pN2, NULL, (const xmlChar*)"DigestMethod", nl);
+
+ xmlNodeAddContent(pN2, nl);
+ xmlSetProp(pN3, (const xmlChar*)"Algorithm", (const xmlChar*)DIGEST_METHOD_SHA1);
+
+ // <DigestValue>
+ len1 = sizeof(buf1);
+ buf1[0] = 0;
+ pMBuf1 = ddocSigInfo_GetSignersCert_DigestValue(pSigInfo);
+ if(pMBuf1)
+ encode((const byte*)pMBuf1->pMem, pMBuf1->nLen, (byte*)buf1, &len1);
+ pN3 = xmlNewChild(pN2, NULL, (const xmlChar*)"DigestValue", (const xmlChar*)buf1);
+
+ xmlNodeAddContent(pN2, nl);
+ // <IssuerSerial>
+ xmlNodeAddContent(pN1, nl);
+ // In 1.3 we use subelements of <IssuerSerial>
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER) ) {
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"IssuerSerial", nl);
+ pN3 = xmlNewChild(pN2, NULL, (const xmlChar*)"X509IssuerName",
+ (const xmlChar*)ddocSigInfo_GetSignersCert_IssuerName((SignatureInfo*)pSigInfo));
+ xmlSetProp(pN3, (const xmlChar*)"xmlns", (const xmlChar*)NAMESPACE_XML_DSIG);
+ xmlNodeAddContent(pN2, nl);
+ pN3 = xmlNewChild(pN2, NULL, (const xmlChar*)"X509SerialNumber",
+ (const xmlChar*)ddocSigInfo_GetSignersCert_IssuerSerial((SignatureInfo*)pSigInfo));
+ xmlSetProp(pN3, (const xmlChar*)"xmlns", (const xmlChar*)NAMESPACE_XML_DSIG);
+ xmlNodeAddContent(pN2, nl);
+ } else {
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"IssuerSerial",
+ (const xmlChar*)ddocSigInfo_GetSignersCert_IssuerSerial((SignatureInfo*)pSigInfo));
+ }
+ // <SignaturePolicyIdentifier>
+ if((!strcmp(pSigDoc->szFormatVer, SK_XML_1_VER) && !strcmp(pSigDoc->szFormat, SK_XML_1_NAME)) ||
+ !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_1_VER) ||
+ !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_2_VER) ||
+ !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER)) {
+ xmlNodeAddContent(pSigSigProp, nl);
+ pN1 = xmlNewChild(pSigSigProp, NULL, (const xmlChar*)"SignaturePolicyIdentifier", nl);
+ // <SignaturePolicyImplied>
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"SignaturePolicyImplied", nl);
+ xmlNodeAddContent(pN1, nl);
+ }
+ // <SignatureProductionPlace>
+ if(pSigInfo->sigProdPlace.szCity || pSigInfo->sigProdPlace.szStateOrProvince ||
+ pSigInfo->sigProdPlace.szPostalCode || pSigInfo->sigProdPlace.szCountryName) {
+ xmlNodeAddContent(pSigSigProp, nl);
+ pN1 = xmlNewChild(pSigSigProp, NULL, (const xmlChar*)"SignatureProductionPlace", nl);
+ if(pSigInfo->sigProdPlace.szCity) {
+ if(bWithEscapes) {
+ escapeTextNode(pSigInfo->sigProdPlace.szCity, -1, &p2);
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"City", (const xmlChar*)p2);
+ free(p2);
+ }
+ else
+ pN2 = xmlNewTextChild(pN1, NULL, (const xmlChar*)"City", (const xmlChar*)pSigInfo->sigProdPlace.szCity);
+ xmlNodeAddContent(pN1, nl);
+ }
+ if(pSigInfo->sigProdPlace.szStateOrProvince) {
+ if(bWithEscapes) {
+ escapeTextNode(pSigInfo->sigProdPlace.szStateOrProvince, -1, &p2);
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"StateOrProvince", (const xmlChar*)p2);
+ free(p2);
+ }
+ else
+ pN2 = xmlNewTextChild(pN1, NULL, (const xmlChar*)"StateOrProvince", (const xmlChar*)pSigInfo->sigProdPlace.szStateOrProvince);
+ xmlNodeAddContent(pN1, nl);
+ }
+ if(pSigInfo->sigProdPlace.szPostalCode) {
+ if(bWithEscapes) {
+ escapeTextNode(pSigInfo->sigProdPlace.szPostalCode, -1, &p2);
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"PostalCode", (const xmlChar*)p2);
+ free(p2);
+ }
+ else
+ pN2 = xmlNewTextChild(pN1, NULL, (const xmlChar*)"PostalCode", (const xmlChar*)pSigInfo->sigProdPlace.szPostalCode);
+ xmlNodeAddContent(pN1, nl);
+ }
+ if(pSigInfo->sigProdPlace.szCountryName) {
+ if(bWithEscapes) {
+ escapeTextNode(pSigInfo->sigProdPlace.szCountryName, -1, &p2);
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"CountryName", (const xmlChar*)p2);
+ free(p2);
+ }
+ else
+ pN2 = xmlNewTextChild(pN1, NULL, (const xmlChar*)"CountryName", (const xmlChar*)pSigInfo->sigProdPlace.szCountryName);
+ xmlNodeAddContent(pN1, nl);
+ }
+ xmlNodeAddContent(pSigSigProp, nl);
+ }
+ // <SignerRole>
+ if(pSigInfo->signerRole.nClaimedRoles ||
+ pSigInfo->signerRole.nCertifiedRoles) {
+ pN1 = xmlNewChild(pSigSigProp, NULL, (const xmlChar*)"SignerRole", nl);
+ // <ClaimedRoles>
+ if(pSigInfo->signerRole.nClaimedRoles) {
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"ClaimedRoles", nl);
+ for(i = 0; i < pSigInfo->signerRole.nClaimedRoles; i++) {
+ if(bWithEscapes) {
+ escapeTextNode(pSigInfo->signerRole.pClaimedRoles[i], -1, &p2);
+ ddocDebug(4, "createXMLSignedProperties", "role: %s --> %s", pSigInfo->signerRole.pClaimedRoles[i], p2);
+ pN3 = xmlNewChild(pN2, NULL, (const xmlChar*)"ClaimedRole", (const xmlChar*)p2);
+ free(p2);
+ } else
+ pN3 = xmlNewTextChild(pN2, NULL, (const xmlChar*)"ClaimedRole", (const xmlChar*)pSigInfo->signerRole.pClaimedRoles[i]);
+ xmlNodeAddContent(pN2, nl);
+ }
+ xmlNodeAddContent(pN1, nl);
+ }
+ // <CertifiedRoles>
+ if(pSigInfo->signerRole.nCertifiedRoles) {
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"CertifiedRoles", nl);
+ for(i = 0; i < pSigInfo->signerRole.nClaimedRoles; i++) {
+ p2 = NULL;
+ escapeXMLSymbols(pSigInfo->signerRole.pCertifiedRoles[i], -1, &p2);
+ if(p2)
+ pN3 = xmlNewChild(pN2, NULL, (const xmlChar*)"CertifiedRole", (const xmlChar*)p2);
+ free(p2);
+ p2 = NULL;
+ xmlNodeAddContent(pN2, nl);
+ }
+ xmlNodeAddContent(pN1, nl);
+ }
+ xmlNodeAddContent(pSigSigProp, nl);
+ }
+ // <SignedDataObjectProperties>
+ xmlNodeAddContent(pSigProp, nl);
+ pN1 = xmlNewChild(pSigProp, NULL, (const xmlChar*)"SignedDataObjectProperties", nl);
+ xmlNodeAddContent(pSigProp, nl);
+ // convert to string
+ err = xmlC14NDocDumpMemory(doc, NULL, 0, NULL, 0, &pBuf);
+ if(pBuf) {
+ len1 = strlen((char*)pBuf);
+ pRet = malloc(len1+1);
+ if(pRet) {
+ strncpy(pRet, (char*)pBuf, len1);
+ pRet[len1] = 0;
+ }
+ xmlFree(pBuf);
+ }
+ xmlFreeDoc(doc);
+ // return <SignedProperties> node
+ return pRet;
+}
+
+
+//============================================================
+// Creates a <SignedInfo> XML block for a signature
+// This is the actual data to be signed
+// pSigInfo - signature info data
+// buf - output buffer
+// returns number of output bytes written
+//============================================================
+EXP_OPTION char* createXMLSignedInfo(const SignedDoc* pSigDoc, const SignatureInfo* pSigInfo)
+{
+ char buf1[300], *pRet = 0, *p1, *p2;
+ int i, err, l1;
+ xmlNodePtr pnSigInfo, pN1, pN2, pN3;
+ static xmlChar nl[] = "\n";
+ xmlDocPtr doc;
+ xmlChar* pBuf;
+ //FILE* hFile;
+ DataFile* pDF;
+ DigiDocMemBuf mbuf1;
+ //AM 13.02.09 ecdsa-sha1 support
+ EVP_PKEY* pubKey = NULL;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ RETURN_OBJ_IF_NULL(pSigInfo, 0);
+ // XML doc
+ doc = xmlNewDoc((const xmlChar*)"1.0");
+ doc->children = xmlNewDocNode(doc, NULL, (const xmlChar*)"", NULL);
+ // <SignedInfo>
+ pnSigInfo = xmlNewChild(doc->children, NULL, (const xmlChar*)"SignedInfo", nl);
+ // in ver 1.1 we need this namespace def
+ xmlNewNs(pnSigInfo, (const xmlChar*)NAMESPACE_XML_DSIG, NULL);
+ // <CanonicalizationMethod>
+ pN1 = xmlNewChild(pnSigInfo, NULL, (const xmlChar*)"CanonicalizationMethod", nl);
+ xmlSetProp(pN1, (const xmlChar*)"Algorithm", (const xmlChar*)"http://www.w3.org/TR/2001/REC-xml-c14n-20010315");
+ xmlNodeAddContent(pnSigInfo, nl);
+ // <SignatureMethod>
+ pN1 = xmlNewChild(pnSigInfo, NULL, (const xmlChar*)"SignatureMethod", nl);
+ err = GetPublicKey(&pubKey, ddocSigInfo_GetSignersCert(pSigInfo));
+ if(pubKey) {
+#ifdef WITH_ECDSA
+ if(pubKey->type==NID_X9_62_id_ecPublicKey)
+ xmlSetProp(pN1, (const xmlChar*)"Algorithm", (const xmlChar*)"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1");
+ else
+#endif
+ xmlSetProp(pN1, (const xmlChar*)"Algorithm", (const xmlChar*)"http://www.w3.org/2000/09/xmldsig#rsa-sha1");
+ EVP_PKEY_free(pubKey);
+ }
+ xmlNodeAddContent(pnSigInfo, nl);
+ // <Reference>
+ for(i = 0; i < pSigInfo->nDocs; i++) {
+ // documents digest
+ pN1 = xmlNewChild(pnSigInfo, NULL, (const xmlChar*)"Reference", nl);
+ snprintf(buf1, sizeof(buf1), "#%s", pSigInfo->pDocs[i]->szDocId);
+ xmlSetProp(pN1, (const xmlChar*)"URI", (const xmlChar*)buf1);
+ pDF = getDataFileWithId(pSigDoc, pSigInfo->pDocs[i]->szDocId);
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"DigestMethod", nl);
+ xmlSetProp(pN2, (const xmlChar*)"Algorithm", (const xmlChar*)"http://www.w3.org/2000/09/xmldsig#sha1");
+ xmlNodeAddContent(pN1, nl);
+ // in ver 1.0 we use Transforms
+ if(!strcmp(pSigDoc->szFormat, SK_XML_1_NAME) && !strcmp(pSigDoc->szFormatVer, SK_XML_1_VER)) {
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"Transforms", NULL);
+ pN3 = xmlNewChild(pN2, NULL, (const xmlChar*)"Transform", NULL);
+ xmlSetProp(pN3, (const xmlChar*)"Algorithm", (const xmlChar*)"http://www.w3.org/2000/09/xmldsig#enveloped-signature");
+ xmlNodeAddContent(pN1, nl);
+ }
+ l1 = sizeof(buf1);
+ encode(pSigInfo->pDocs[i]->szDigest,
+ pSigInfo->pDocs[i]->nDigestLen, (byte*)buf1, &l1);
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"DigestValue", (const xmlChar*)buf1);
+ xmlNodeAddContent(pN1, nl);
+ xmlNodeAddContent(pnSigInfo, nl);
+ // in ver 1.1 we don't use mime digest Reference blocks
+ //AM 29.08.10
+ if(!strcmp(pSigDoc->szFormatVer, SK_XML_1_VER) && !strcmp(pSigDoc->szFormat, SK_XML_1_NAME)) {
+ // document mime type digest
+ pN1 = xmlNewChild(pnSigInfo, NULL, (const xmlChar*)"Reference", nl);
+ if(!strcmp(pSigDoc->szFormatVer, "1.0"))
+ snprintf(buf1, sizeof(buf1), "#%s-MIME", pSigInfo->pDocs[i]->szDocId);
+ else // current version is 1.1
+ snprintf(buf1, sizeof(buf1), "#%s@MimeType", pSigInfo->pDocs[i]->szDocId);
+ xmlSetProp(pN1, (const xmlChar*)"URI", (const xmlChar*)buf1);
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"DigestMethod", nl);
+ xmlSetProp(pN2, (const xmlChar*)"Algorithm", (const xmlChar*)DIGEST_METHOD_SHA1);
+ xmlNodeAddContent(pN1, nl);
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"Transforms", NULL);
+ pN3 = xmlNewChild(pN2, NULL, (const xmlChar*)"Transform", NULL);
+ xmlSetProp(pN3, (const xmlChar*)"Algorithm", (const xmlChar*)"http://www.w3.org/2000/09/xmldsig#enveloped-signature");
+ xmlNodeAddContent(pN1, nl);
+ l1 = sizeof(buf1);
+ encode(pSigInfo->pDocs[i]->szMimeDigest,
+ pSigInfo->pDocs[i]->nMimeDigestLen, (byte*)buf1, &l1);
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"DigestValue", (const xmlChar*)buf1);
+ xmlNodeAddContent(pN1, nl);
+ }
+ }
+ // signed properties digest
+ pN1 = xmlNewChild(pnSigInfo, NULL, (const xmlChar*)"Reference", nl);
+ snprintf(buf1, sizeof(buf1), "#%s-SignedProperties", pSigInfo->szId);
+ xmlSetProp(pN1, (const xmlChar*)"URI", (const xmlChar*)buf1);
+ // in version 1.2 we ise the Type atribute
+ // for References that contain <SignedProperties> digest
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_2_VER) ||
+ !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER)) {
+ xmlSetProp(pN1, (const xmlChar*)"Type", (const xmlChar*)"http://uri.etsi.org/01903/v1.1.1#SignedProperties");
+ }
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"DigestMethod", nl);
+ xmlSetProp(pN2, (const xmlChar*)"Algorithm", (const xmlChar*)DIGEST_METHOD_SHA1);
+ xmlNodeAddContent(pN1, nl);
+ // in 1.0 we used transforms here
+ if(!strcmp(pSigDoc->szFormat, SK_XML_1_NAME) && !strcmp(pSigDoc->szFormatVer, SK_XML_1_VER)) {
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"Transforms", NULL);
+ pN3 = xmlNewChild(pN2, NULL, (const xmlChar*)"Transform", NULL);
+ xmlSetProp(pN3, (const xmlChar*)"Algorithm", (const xmlChar*)"http://www.w3.org/2000/09/xmldsig#enveloped-signature");
+ xmlNodeAddContent(pN1, nl);
+ }
+ ddocEncodeBase64(ddocDigestValue_GetDigestValue(pSigInfo->pSigPropDigest), &mbuf1);
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"DigestValue", (const xmlChar*)mbuf1.pMem);
+ ddocMemBuf_free(&mbuf1);
+ xmlNodeAddContent(pN1, nl);
+ xmlNodeAddContent(pnSigInfo, nl);
+ // convert to string
+ pBuf = NULL;
+ err = xmlC14NDocDumpMemory(doc, NULL, 0, NULL, 0, &pBuf);
+ p1 = strstr((const char*)pBuf, "<SignedInfo");
+ l1 = strlen(p1);
+ if(p1) {
+ p2 = strstr((const char*)pBuf, "</SignedInfo>");
+ if(p2) {
+ p2[strlen("</SignedInfo>")] = 0;
+ pRet = malloc(l1);
+ if(pRet) {
+ memset(pRet, 0, l1);
+ strncpy(pRet, p1, strlen(p1));
+ //pRet = strdup(p1);
+ }
+ }
+ }
+ xmlFree(pBuf);
+ xmlFreeDoc(doc);
+ return pRet;
+}
+
+//============================================================
+// Calculates the digest of OCSP_RESPONSE
+// pResp - OCSP_RESPONSE data
+// digBuf - signature buffer
+// digLen - signature buffer length
+// returns error code
+//============================================================
+int calculateOcspBasicResponseDigest(OCSP_BASICRESP* pBsResp, byte* digBuf, int* digLen)
+{
+ int err = ERR_OK, l1;
+ byte *buf, *p;
+
+ RETURN_IF_NULL_PARAM(pBsResp);
+ l1 = i2d_OCSP_BASICRESP(pBsResp, NULL);
+ buf = (byte*)malloc(l1+10);
+ RETURN_IF_BAD_ALLOC(buf);
+ p = buf;
+ i2d_OCSP_BASICRESP(pBsResp, &p);
+ err = calculateDigest(buf, l1, DIGEST_SHA1, digBuf, digLen);
+ free(buf);
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+//============================================================
+// Writes OCSP_RESPONSE to file without the usual PEM headers
+// bout - output file
+// pResp - OCSP_RESPONSE
+// returns error code
+//============================================================
+/*int writeOcspToXMLFile(DigiDocMemBuf* pBuf, OCSP_RESPONSE* pResp)
+{
+ int l1, l2;
+ char *p1, *p2;
+
+ RETURN_IF_NULL_PARAM(pBuf);
+ RETURN_IF_NULL_PARAM(pResp);
+ l1 = i2d_OCSP_RESPONSE(pResp, NULL);
+ p1 = (char*)malloc(l1+10);
+ RETURN_IF_BAD_ALLOC(p1);
+ p2 = p1;
+ i2d_OCSP_RESPONSE(pResp, (unsigned char**)&p2);
+ l2 = l1 * 2;
+ p2 = (char*)malloc(l2);
+ if(p2 == NULL) {
+ free(p1);
+ RETURN_IF_BAD_ALLOC(p2);
+ }
+ encode((const byte*)p1, l1, (byte*)p2, &l2);
+ ddocMemAppendData(pBuf, p2, -1);
+ free(p2);
+ free(p1);
+ return ERR_OK;
+}*/
+
+
+//============================================================
+// Adds a notary signature to signed document buffer
+// pMBufXML - output buffer
+// pSigDoc - signed doc pointer
+// pNotInfo - notary signature info
+// returns error code
+//============================================================
+int addNotaryInfoXML(DigiDocMemBuf *pMBufXML, const SignedDoc *pSigDoc, const SignatureInfo* pSigInfo, const NotaryInfo* pNotInfo)
+{
+ int err = ERR_OK, i;
+ DigiDocMemBuf mbuf1;
+ const DigiDocMemBuf *pMBuf;
+ CertValue *pCertValue = 0;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(pNotInfo);
+ RETURN_IF_NULL_PARAM(pMBufXML);
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ // unsigned prop begin
+ // Ver 1.76 - in format 1.3 we don't use the Target atribute
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER)) {
+ ddocMemAppendData(pMBufXML,"<UnsignedProperties>\n<UnsignedSignatureProperties>", -1);
+ } else {
+ ddocMemAppendData(pMBufXML,"<UnsignedProperties Target=\"", -1);
+ ddocMemAppendData(pMBufXML,pSigInfo->szId, -1);
+ ddocMemAppendData(pMBufXML,"\">\n<UnsignedSignatureProperties>", -1);
+ }
+ // <CompleteCertificateRefs>
+ err = ddocCompleteCertificateRefs_toXML((SignedDoc*)pSigDoc, (SignatureInfo*)pSigInfo, &mbuf1);
+ ddocMemAppendData(pMBufXML,(const char*)mbuf1.pMem, -1);
+ ddocMemBuf_free(&mbuf1);
+ // <CompleteRevocationRefs>
+ err = ddocCompleteRevocationRefs_toXML((SignedDoc*)pSigDoc, (SignatureInfo*)pSigInfo, &mbuf1);
+ ddocMemAppendData(pMBufXML,(const char*)mbuf1.pMem, -1);
+ ddocMemBuf_free(&mbuf1);
+
+ // responder cert
+ ddocMemAppendData(pMBufXML,"<CertificateValues>\n", -1);
+ // TODO format cert without header
+ for(i = 0; i < ddocCertValueList_GetCertValuesCount(pSigInfo->pCertValues); i++) {
+ pCertValue = ddocCertValueList_GetCertValue(pSigInfo->pCertValues, i);
+ if(pCertValue && pCertValue->nType != CERTID_VALUE_SIGNERS_CERT) {
+ ddocDebug(3, "addNotaryInfoXML", "Write CertVal-type: %d cert: %s", pCertValue->nType, (pCertValue->pCert ? "OK" : "NULL"));
+ ddocCertValue_toXML(pCertValue, &mbuf1);
+ ddocMemAppendData(pMBufXML, (const char*)mbuf1.pMem, -1);
+ ddocMemAppendData(pMBufXML, "\n", -1);
+ ddocMemBuf_free(&mbuf1);
+ }
+ }
+ ddocMemAppendData(pMBufXML, "</CertificateValues>\n", -1);
+ // revocation values
+ ddocMemAppendData(pMBufXML, "<RevocationValues>", -1);
+ // Ver 1.76 - in format 1.3 we use here additionally element <OCSPValues>
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER))
+ ddocMemAppendData(pMBufXML, "<OCSPValues>", -1);
+ // OCSP response
+ ddocMemAppendData(pMBufXML, "<EncapsulatedOCSPValue Id=\"", -1);
+ ddocMemAppendData(pMBufXML, pNotInfo->szId, -1);
+ ddocMemAppendData(pMBufXML, "\">\n", -1);
+ pMBuf = ddocNotInfo_GetOCSPResponse(pNotInfo);
+ RETURN_IF_NULL(pMBuf);
+ // fix for backward compatibility with 2.1.5
+ // remove trailing \n after base64 content
+ if(mbuf1.pMem && ((char*)mbuf1.pMem)[strlen((const char*)mbuf1.pMem)-1] == '\n')
+ ((char*)mbuf1.pMem)[strlen((const char*)mbuf1.pMem)-1] = 0;
+ ddocEncodeBase64(pMBuf, &mbuf1);
+ ddocMemAppendData(pMBufXML, (const char*)mbuf1.pMem, -1);
+ ddocMemBuf_free(&mbuf1);
+ ddocMemAppendData(pMBufXML, "</EncapsulatedOCSPValue>\n", -1);
+ // Ver 1.76 - in format 1.3 we use here additionally element <OCSPValues>
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER))
+ ddocMemAppendData(pMBufXML,"</OCSPValues>", -1);
+ ddocMemAppendData(pMBufXML,"</RevocationValues>", -1);
+ // unsigned prop end
+ ddocMemAppendData(pMBufXML, "</UnsignedSignatureProperties>\n</UnsignedProperties>", -1);
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+//============================================================
+// Swaps bytes in this byte array. Length must be an even number
+// used for big-endian <--> small-endian conversion
+//============================================================
+void swapBytes(byte* src, int len)
+{
+ byte b;
+ int i;
+
+ if(len % 2 == 0) {
+ for(i = 0; i < (len / 2); i++) {
+ b = src[i];
+ src[i] = src[len - i - 1];
+ src[len - i - 1] = b;
+ }
+ }
+}
+
+
+//============================================================
+// Adds a signature to signed document file
+// hFile - output file
+// pSigInfo - signature info
+// cert - signers certificate
+// returns error code
+//============================================================
+int addSignatureInfoXML(DigiDocMemBuf *pMBufXML, SignedDoc* pSigDoc, SignatureInfo* pSigInfo)
+{
+ int err = ERR_OK;
+ unsigned char buf2[500], *buf1 = 0;
+ int len2, len1;
+ EVP_PKEY* pubKey = NULL;
+ SignatureValue *pSigVal;
+ DigiDocMemBuf mbuf1;
+
+ RETURN_IF_NULL_PARAM(pMBufXML);
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ //TODO: xmlns = http://uri.etsi.org/01903/v1.3.2#
+ ddocMemAppendData(pMBufXML,"<Signature Id=\"", -1);
+ ddocMemAppendData(pMBufXML,pSigInfo->szId, -1);
+ ddocMemAppendData(pMBufXML,"\" xmlns=\"http://www.w3.org/2000/09/xmldsig#\">\n", -1);
+ buf1 = (unsigned char*)createXMLSignedInfo(pSigDoc, pSigInfo);
+ RETURN_IF_NULL(buf1);
+ ddocMemAppendData(pMBufXML,(const char*)buf1, -1);
+ free(buf1);
+ buf1 = 0; // mark free
+ len1 = 1024;
+ buf1 = (unsigned char*)malloc(len1);
+ RETURN_IF_BAD_ALLOC(buf1);
+ memset(buf1, 0, len1);
+ // <SignatureValue>
+ pSigVal = ddocSigInfo_GetSignatureValue(pSigInfo);
+ //RETURN_IF_NULL(pSigVal);
+ ddocSignatureValue_toXML(pSigVal, &mbuf1);
+ ddocMemAppendData(pMBufXML,(const char*)mbuf1.pMem, -1);
+ ddocMemBuf_free(&mbuf1);
+ // cert data...
+ if(!strcmp(pSigDoc->szFormat, SK_XML_1_NAME) && !strcmp(pSigDoc->szFormatVer, SK_XML_1_VER)) {
+ ddocMemAppendData(pMBufXML,"<KeyInfo><X509Data><X509Certificate Id=\"", -1);
+ ddocMemAppendData(pMBufXML,pSigInfo->szId, -1);
+ ddocMemAppendData(pMBufXML,"-CERT\">\n", -1);
+ } else {
+ // RSA KEY value
+ ddocMemAppendData(pMBufXML,"<KeyInfo>\n", -1);
+ err = GetPublicKey(&pubKey, ddocSigInfo_GetSignersCert(pSigInfo));
+ // FIXME
+ // modulus
+ //AM 11.02.09
+ if(!err && pubKey->type==NID_rsaEncryption) {
+ ddocMemAppendData(pMBufXML,"<KeyValue>\n<RSAKeyValue>\n", -1);
+ len1 = BN_bn2bin(pubKey->pkey.rsa->n, buf1);
+ // in version 1.1 we output modulus as it is
+ // starting from 1.2 we convert it to big-endian
+ /*len2 = sizeof(buf2);
+ memset(buf2, 0, len2);
+ encode(buf1, len1, buf2, &len2);
+ printf("Old modulus: %s\n", buf2);
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_1_VER)) {
+ swapBytes((byte*)buf1, len1);
+ }*/
+ len2 = sizeof(buf2);
+ memset(buf2, 0, len2);
+ encode(buf1, len1, buf2, &len2);
+ //printf("New modulus: %s len: %d\n", buf2, len1);
+ ddocMemAppendData(pMBufXML, "<Modulus>", -1);
+ ddocMemAppendData(pMBufXML, (char*)buf2, -1);
+ ddocMemAppendData(pMBufXML,"</Modulus>\n", -1);
+ // exponent
+ memset(buf1, 0, len1);
+ len1 = BN_bn2bin(pubKey->pkey.rsa->e, buf1);
+ len2 = sizeof(buf2);
+ memset(buf2, 0, len2);
+ encode(buf1, len1, buf2, &len2);
+ ddocMemAppendData(pMBufXML,"<Exponent>", -1);
+ ddocMemAppendData(pMBufXML, (char*)buf2, -1);
+ ddocMemAppendData(pMBufXML,"</Exponent>\n", -1);
+ ddocMemAppendData(pMBufXML,"</RSAKeyValue>\n</KeyValue>\n", -1);
+ }
+ // cert data
+ ddocMemAppendData(pMBufXML,"<X509Data><X509Certificate>\n", -1);
+ }
+ free(buf1);
+ buf1 = 0; // mark freed
+ RETURN_IF_NOT(err == ERR_OK, err); // check sig-value encode errors
+ err = getCertPEM(ddocSigInfo_GetSignersCert(pSigInfo), 0, (char**)&buf1);
+ RETURN_IF_NULL(buf1);
+ ddocMemAppendData(pMBufXML, (char*)buf1, -1);
+ free(buf1);
+ ddocMemAppendData(pMBufXML,"</X509Certificate></X509Data></KeyInfo>\n", -1);
+ // VS in releases prior to 1.76 we had incorrect <QualifyingProperties> atributes
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER)) {
+ ddocMemAppendData(pMBufXML,"<Object><QualifyingProperties xmlns=\"http://uri.etsi.org/01903/v1.1.1#\" Target=\"#", -1);
+ ddocMemAppendData(pMBufXML,pSigInfo->szId, -1);
+ ddocMemAppendData(pMBufXML,"\">\n", -1);
+ } else {
+ ddocMemAppendData(pMBufXML,"<Object><QualifyingProperties>\n", -1);
+ }
+ EVP_PKEY_free(pubKey);
+ // signed properties
+ buf1 = (unsigned char*)createXMLSignedProperties(pSigDoc, pSigInfo, 1);
+ RETURN_IF_NULL(buf1);
+ ddocMemAppendData(pMBufXML,(const char*)buf1, -1);
+ free(buf1);
+ // unsigned properties
+ if(pSigInfo->pNotary)
+ addNotaryInfoXML(pMBufXML, pSigDoc, pSigInfo, pSigInfo->pNotary);
+ // qualifying properties end
+ ddocMemAppendData(pMBufXML,"</QualifyingProperties></Object>\n", -1);
+ // signature end
+ ddocMemAppendData(pMBufXML,"</Signature>\n", -1);
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ ddocMemBuf_free(&mbuf1);
+ return err;
+}
+
+
+//============================================================
+// Canonicalizes PCDATA text value. Simple caninicalization
+// only that replaces "\n\r" with "\n", by removing the "\r"
+// and shifting the data left. Modification is done in place.
+// src - input data. will be modified
+// return error code or ERR_OK
+//============================================================
+int ddocCanonicalizePCDATA(char * src)
+{
+ int i, j;
+
+ RETURN_IF_NULL_PARAM(src);
+ for(i = j = 0; src[j]; ) {
+ if(src[j] == '\r') {
+ j++;
+ } else {
+ if(i != j)
+ src[i] = src[j];
+ i++;
+ j++;
+ }
+ }
+ src[i] = 0;
+ return ERR_OK;
+}
+
+//============================================================
+// Generates DataFile elements XML form and stores it in a file
+// pSigDoc - signed document
+// pDataFile - data file object to be converted
+// szDataFile - input file name
+// hFile - output file handle
+// pMBufDigest - pointer to buffer for digest if we only want the digest
+// pMBufXML - output buffer if we want data to be returned in mem buf
+//============================================================
+EXP_OPTION int generateDataFileXML(SignedDoc* pSigDoc, DataFile* pDataFile,
+ const char* szDataFile, FILE* hFile, DigiDocMemBuf* pMBufXML)
+{
+ int err = ERR_OK, len1, len2, j, k;
+ char buf1[2050], buf2[5000], fixedFileName[1024], *p = 0;
+ char *name, *value, *fName;
+ FILE *fIn = 0;
+ EVP_ENCODE_CTX ectx;
+ SHA_CTX sctx;
+ DigiDocMemBuf mbuf1, mbuf2, mbuf3;
+#ifdef WIN32
+ wchar_t *convFileName = 0;
+#endif
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ RETURN_IF_NULL_PARAM(pDataFile);
+ //RETURN_IF_NULL_PARAM(szDataFile);
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ len1 = sizeof(buf1);
+ ddocDebug(3, "generateDataFileXML", "DF: %s in-df-file: %s out-file: %s mbuf: %s", pDataFile->szId, szDataFile, (hFile ? "Y" : "N"), (pMBufXML ? "Y" : "N"));
+ // replaces '&' with '&amp;'
+ memset(fixedFileName, 0, sizeof(fixedFileName));
+ fName = (char*)getSimpleFileName(pDataFile->szFileName);
+ escapeXMLSymbols(fName, -1, &p);
+ if(p)
+ strncpy(fixedFileName, p, sizeof(fixedFileName));
+ free(p); p = 0;
+ //in versions 1.0, 1.1 and 1.2 we used bad encoding
+ if((!strcmp(pSigDoc->szFormatVer, SK_XML_1_VER) && !strcmp(pSigDoc->szFormat, SK_XML_1_NAME)) ||
+ !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_1_VER) ||
+ !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_2_VER)) {
+#ifdef WIN32
+ utf82oem(fixedFileName, buf1, sizeof(buf1));
+ len2 = sizeof(buf2);
+ ascii2utf8(buf1, buf2, &len2);
+#else
+ convFNameToWin(fixedFileName, buf2, sizeof(buf2));
+#endif
+ strncpy(fixedFileName, buf2, sizeof(fixedFileName));
+ }
+ // in version 1.0 we use DigestType and DigestValue attributes, PR. - size fix
+ ddocMemSetLength(&mbuf2, 1024);
+ if((!strcmp(pSigDoc->szFormat, SK_XML_1_NAME) && !strcmp(pSigDoc->szFormatVer, SK_XML_1_VER))) {
+ ddocEncodeBase64(ddocDataFile_GetDigestValue(pDataFile), &mbuf1);
+ //AM 17.11.08 moved these 2 lines after ddocEncodeBase64
+ if(mbuf1.pMem && ((char*)mbuf1.pMem)[strlen((const char*)mbuf1.pMem)-1] == '\n')
+ ((char*)mbuf1.pMem)[strlen((const char*)mbuf1.pMem)-1] = 0;
+ snprintf((char*)mbuf2.pMem, mbuf2.nLen,
+ "<DataFile ContentType=\"%s\" Filename=\"%s\" Id=\"%s\" MimeType=\"%s\" Size=\"%ld\" DigestType=\"%s\" DigestValue=\"%s\"",
+ pDataFile->szContentType,
+ fixedFileName, pDataFile->szId, pDataFile->szMimeType,
+ pDataFile->nSize, pDataFile->szDigestType, (char*)mbuf1.pMem);
+ ddocMemBuf_free(&mbuf1);
+ } else {
+ snprintf((char*)mbuf2.pMem, mbuf2.nLen, "<DataFile ContentType=\"%s\" Filename=\"%s\" Id=\"%s\" MimeType=\"%s\" Size=\"%ld\"",
+ pDataFile->szContentType,
+ fixedFileName, pDataFile->szId, pDataFile->szMimeType, pDataFile->nSize);
+ }
+ mbuf2.nLen = strlen((const char*)mbuf2.pMem);
+ k = getCountOfDataFileAttributes(pDataFile);
+ for(j = 0; j < k; j++) {
+ getDataFileAttribute(pDataFile, j, &name, &value);
+ escapeXMLSymbols(value, -1, &p);
+ ddocMemAppendData(&mbuf2, " ", -1);
+ ddocMemAppendData(&mbuf2, name, -1);
+ ddocMemAppendData(&mbuf2, "=\"", -1);
+ if(p)
+ ddocMemAppendData(&mbuf2, p, -1);
+ ddocMemAppendData(&mbuf2, "\"", -1);
+ free(p);
+ p = NULL;
+ }
+ // VS - ver 1.80 - in format 1.3 we started using SignedDoc schema
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER))
+ ddocMemAppendData(&mbuf2, " xmlns=\"http://www.sk.ee/DigiDoc/v1.3.0#\"", -1);
+ ddocMemAppendData(&mbuf2, ">", -1); // end of generating <DataFile> header
+ // if DataFile content is already in memory then convert to base64 and use it
+ if(pDataFile->mbufContent.pMem && pDataFile->mbufContent.nLen && pMBufXML) {
+ if(!strcmp(pDataFile->szContentType, CONTENT_EMBEDDED) ||
+ !strcmp(pDataFile->szContentType, CONTENT_EMBEDDED_BASE64)) { //allready in base64
+ ddocMemAppendData(&mbuf2, pDataFile->mbufContent.pMem, pDataFile->mbufContent.nLen);
+ }
+ ddocMemAppendData(&mbuf2, "</DataFile>", -1);
+ p = canonicalizeXML((char*)mbuf2.pMem, mbuf2.nLen);
+ RETURN_IF_NULL(p);
+ ddocDebug(3, "generateDataFileXML", "canonicalized df: \'%s\'", p);
+ //ddocDebugWriteFile(3, "df-data0.txt", &mbuf2);
+ SHA1_Init(&sctx);
+ SHA1_Update(&sctx, (const char*)p, strlen(p));
+ free(p); p = 0;
+ len2 = sizeof(buf2);
+ SHA1_Final((unsigned char*)buf2, &sctx);
+ ddocDataFile_SetDigestValue(pDataFile, buf2, DIGEST_LEN);
+ if(pMBufXML)
+ ddocMemAppendData(pMBufXML, mbuf2.pMem, mbuf2.nLen);
+ if(hFile)
+ fwrite(mbuf2.pMem, sizeof(char), mbuf2.nLen, hFile);
+
+ ddocMemBuf_free(&mbuf2);
+ len1 = sizeof(buf1);
+ bin2hex(pDataFile->mbufDigest.pMem, pDataFile->mbufDigest.nLen, buf1, &len1);
+ ddocDebug(3, "generateDataFileXML", "DataFile: %s calc-digest: %s", pDataFile->szId, buf1);
+ len1 = sizeof(buf1);
+ encode((const byte*)pDataFile->mbufDigest.pMem, pDataFile->mbufDigest.nLen, (byte*)buf1, &len1);
+ ddocDebug(3, "generateDataFileXML", "DataFile: %s calc-digest: %s", pDataFile->szId, buf1);
+
+ return err;
+ }
+
+ if(hFile)
+ fputs((const char*)mbuf2.pMem, hFile);
+#ifdef WITH_BASE64_HASHING_HACK
+ SHA1_Init(&sctx);
+ if(!strcmp(pDataFile->szContentType, CONTENT_EMBEDDED_BASE64) &&
+ strcmp(pSigDoc->szFormat, SK_XML_1_NAME)) { // in ddoc 1.0 we calculate hash over original data
+ ddocMemAppendData(&mbuf2, "</DataFile>", -1);
+ p = canonicalizeXML((char*)mbuf2.pMem, mbuf2.nLen);
+ RETURN_IF_NULL(p);
+ p[strlen(p)-11] = 0;
+ ddocDebug(4, "generateDataFileXML", "sha1 initial update: \'%s\'", p);
+ mbuf3.pMem = p;
+ mbuf3.nLen = strlen(p);
+ ddocDebugWriteFile(4, "df-data0.txt", &mbuf3);
+ SHA1_Update(&sctx, (const char*)p, strlen(p));
+ free(p); p = 0;
+ }
+#endif
+// in base64 hashing hack mode we don't keep DF content constantly in memory
+#ifdef WITH_BASE64_HASHING_HACK
+ if(!strcmp(pDataFile->szContentType, CONTENT_EMBEDDED_BASE64))
+ ddocMemBuf_free(&mbuf2);
+#endif
+
+ //err = ddocConvertFileName(fixedFileName, sizeof(fixedFileName), pDataFile->szFileName);
+ //if(err) return err;
+ strncpy(fixedFileName, pDataFile->szFileName, sizeof(fixedFileName));
+ // if this is our temp file not a real input file
+ // then don't change anything in it.
+ if(strcmp(pDataFile->szFileName, szDataFile) != 0) {
+#ifdef WIN32
+ len2 = 0;
+ err = utf82unicode((const char*)szDataFile, (char**)&convFileName, &len2);
+ fIn = _wfopen(convFileName, L"rb");
+ ddocDebug(3, "generateDataFileXML", "Opening FILE1: %s, conv-file: %s len: %d, RC: %d", szDataFile, convFileName, len2, (fIn != NULL));
+ free(convFileName); // now I don't need it any more
+ if(fIn != NULL) {
+#else
+ if((fIn = fopen(szDataFile, "rb")) != NULL) {
+#endif
+ ddocDebug(4, "generateDataFileXML", "Opened FILE01: %s", szDataFile);
+ if(!strcmp(pSigDoc->szFormat, SK_XML_1_NAME))
+ EVP_DecodeInit(&ectx);
+ while((len1 = fread(buf1, 1, sizeof(buf1)-2, fIn)) > 0) {
+#ifdef WITH_BASE64_HASHING_HACK
+ if(!strcmp(pDataFile->szContentType, CONTENT_EMBEDDED_BASE64)) {
+ buf1[len1] = 0;
+#ifdef WIN32 // must remove \r that was generated during data file extact
+ if(strcmp(pSigDoc->szFormat, SK_XML_1_NAME)) {
+ ddocCanonicalizePCDATA(buf1);
+ len1 = strlen(buf1);
+ }
+#endif
+ if(strcmp(pSigDoc->szFormat, SK_XML_1_NAME)) {
+ ddocDebug(4, "generateDataFileXML", "sha1 update: \'%s\'", buf1);
+ SHA1_Update(&sctx, (const char*)buf1, len1);
+ mbuf3.pMem = buf1;
+ mbuf3.nLen = len1;
+ ddocDebugWriteFile(4, "df-data0.txt", &mbuf3);
+ } else { // in ddoc 1.0 we calculate hash over original data
+ p = buf1;
+ while(*p == ' ' || *p == '\n' || *p == '\r') p++;
+ ddocDebug(4, "generateDataFileXML", "decode: %s", p);
+ len2 = sizeof(buf2);
+ EVP_DecodeUpdate(&ectx, (unsigned char*)buf2, &len2, (unsigned char*)p, strlen(p));
+ ddocDebug(4, "generateDataFileXML", "sha1 update orig: %d: dec: %d", len1, len2);
+ SHA1_Update(&sctx, (const char*)buf2, len2);
+ //ddocDebugWriteFile(4, "df-data0.txt", &mbuf3);
+ }
+ } else {
+#endif
+ ddocMemAppendData(&mbuf2, buf1, len1);
+#ifdef WITH_BASE64_HASHING_HACK
+ }
+#endif
+
+ if(hFile)
+ fwrite(buf1, sizeof(char), len1, hFile);
+ }
+ fclose(fIn);
+ ddocDebug(4, "generateDataFileXML", "Closed FILE01: %s", szDataFile);
+ fIn = 0;
+ if(!strcmp(pSigDoc->szFormat, SK_XML_1_NAME)) {
+ len2 = sizeof(buf2);
+ EVP_DecodeFinal(&ectx, (unsigned char*)buf2, &len2);
+ SHA1_Update(&sctx, (const char*)buf2, len2);
+ ddocDebug(4, "generateDataFileXML", "sha1 final dec: %d", len1, len2);
+ len2 = sizeof(buf2);
+ SHA1_Final((unsigned char*)buf2, &sctx);
+ ddocDataFile_SetDigestValue(pDataFile, buf2, DIGEST_LEN);
+ len1 = sizeof(buf1);
+ bin2hex(pDataFile->mbufDigest.pMem, pDataFile->mbufDigest.nLen, buf1, &len1);
+ ddocDebug(3, "generateDataFileXML", "DataFile: %s calc-digest: %s", pDataFile->szId, buf1);
+ }
+ }
+ } else {
+ // if the file must be embedded
+ if(!strcmp(pDataFile->szContentType, CONTENT_EMBEDDED_BASE64) ||
+ !strcmp(pDataFile->szContentType, CONTENT_EMBEDDED)) {
+#ifdef WIN32
+ len2 = 0;
+ err = utf82unicode((const char*)fixedFileName, (char**)&convFileName, &len2);
+ fIn = _wfopen(convFileName, L"rb");
+ ddocDebug(3, "generateDataFileXML", "Opening FILE2: %s, conv-file: %s len: %d, RC: %d", fixedFileName, convFileName, len2, (fIn != NULL));
+ free(convFileName); // now I don't need it any more
+ if(fIn != NULL) {
+#else
+ if((fIn = fopen(fixedFileName, "rb")) != NULL) {
+#endif
+ ddocDebug(4, "generateDataFileXML", "Opened FILE2: %s", fixedFileName);
+ // if encoded
+ if(!strcmp(pDataFile->szContentType, CONTENT_EMBEDDED_BASE64)) {
+ EVP_EncodeInit(&ectx);
+ while((len1 = fread(buf1, 1, sizeof(buf1), fIn)) > 0) {
+ len2 = sizeof(buf2);
+ EVP_EncodeUpdate(&ectx, (unsigned char*)buf2, &len2, (unsigned char*)buf1, len1);
+ buf2[len2] = 0;
+#ifdef WITH_BASE64_HASHING_HACK
+ ddocCanonicalizePCDATA(buf2);
+ len2 = strlen(buf2);
+ ddocDebug(4, "generateDataFileXML", "sha1 update: \'%s\'", buf2);
+ SHA1_Update(&sctx, (const char*)buf2, len2);
+ mbuf3.pMem = buf2;
+ mbuf3.nLen = len2;
+ ddocDebugWriteFile(4, "df-data0.txt", &mbuf3);
+#else
+ ddocMemAppendData(&mbuf2, buf2, len2);
+#endif
+ if(hFile)
+ fwrite(buf2, sizeof(char), len2, hFile);
+ }
+ EVP_EncodeFinal(&ectx, (unsigned char*)buf2, &len2);
+ buf2[len2] = 0;
+#ifdef WITH_BASE64_HASHING_HACK
+ ddocCanonicalizePCDATA(buf2);
+ len2 = strlen(buf2);
+ ddocDebug(4, "generateDataFileXML", "sha1 update: \'%s\'", buf2);
+ SHA1_Update(&sctx, (const char*)buf2, len2);
+ mbuf3.pMem = buf2;
+ mbuf3.nLen = len2;
+ ddocDebugWriteFile(4, "df-data0.txt", &mbuf3);
+#else
+ ddocMemAppendData(&mbuf2, buf2, len2);
+#endif
+ if(hFile)
+ fwrite(buf2, sizeof(char), len2, hFile);
+ } else
+ if(!strcmp(pDataFile->szContentType, CONTENT_EMBEDDED)) {
+ while((len1 = fread(buf1, 1, sizeof(buf1), fIn)) > 0) {
+ if(!strcmp(pDataFile->szCharset, CHARSET_UTF_8)) {
+ ddocMemAppendData(&mbuf2, buf1, len1);
+ if(hFile)
+ fwrite(buf1, sizeof(char), len1, hFile);
+ } else
+ if(!strcmp(pDataFile->szCharset, CHARSET_ISO_8859_1)) {
+ len2 = sizeof(buf2);
+ memset(buf2, 0, len2);
+ isolat1ToUTF8((unsigned char*)buf2, &len2,
+ (const unsigned char*)buf1, &len1);
+ ddocMemAppendData(&mbuf2, buf2, len2);
+ if(hFile)
+ fwrite(buf2, sizeof(char), len2, hFile);
+ //if(pMBufXML)
+ // ddocMemAppendData(pMBufXML, buf2, len2);
+ } else
+ SET_LAST_ERROR(ERR_UNSUPPORTED_CHARSET);
+ }
+ if(!strcmp(pDataFile->szCharset, CHARSET_UTF_8)) {
+ ddocMemAppendData(&mbuf2, buf1, len1);
+ if(hFile)
+ fwrite(buf1, sizeof(char), len1, hFile);
+ //if(pMBufXML)
+ // ddocMemAppendData(pMBufXML, buf1, len1);
+ } else
+ if(!strcmp(pDataFile->szCharset, CHARSET_ISO_8859_1)) {
+ len2 = sizeof(buf2);
+ memset(buf2, 0, len2);
+ isolat1ToUTF8((unsigned char*)buf2, &len2,
+ (const unsigned char*)buf1, &len1);
+ ddocMemAppendData(&mbuf2, buf2, len2);
+ if(hFile)
+ fwrite(buf2, sizeof(char), len2, hFile);
+ //if(pMBufXML)
+ // ddocMemAppendData(pMBufXML, buf2, len2);
+ } else
+ SET_LAST_ERROR(ERR_UNSUPPORTED_CHARSET);
+ }
+ fclose(fIn);
+ ddocDebug(4, "generateDataFileXML", "Closed FILE2: %s", szDataFile);
+ fIn = 0;
+ } else {
+ ddocDebug(1, "generateDataFileXML", "Error reading FILE2: %s", szDataFile);
+ err = ERR_FILE_READ;
+ }
+ }
+ } // not temp file
+ // print suffix-whitespace
+ //if(pDataFile->szDataSuffix)
+ // BIO_puts(bOutFile, pDataFile->szDataSuffix);
+ setString(&(pDataFile->szDigestType), DIGEST_SHA1_NAME, -1);
+#ifdef WITH_BASE64_HASHING_HACK
+ if(!strcmp(pDataFile->szContentType, CONTENT_EMBEDDED_BASE64)) {
+ if(strcmp(pSigDoc->szFormat, SK_XML_1_NAME)) { // in ddoc 1.0 we calculate hash over original data
+ ddocDebug(4, "generateDataFileXML", "sha1 update: \'%s\'", "</DataFile>");
+ SHA1_Update(&sctx, "</DataFile>", 11);
+ mbuf3.pMem = "</DataFile>";
+ mbuf3.nLen = strlen("</DataFile>");
+ ddocDebugWriteFile(4, "df-data0.txt", &mbuf3);
+ }
+ memset(buf2, 0, sizeof(buf2));
+ SHA1_Final((unsigned char*)buf2, &sctx);
+ ddocDataFile_SetDigestValue(pDataFile, buf2, DIGEST_LEN);
+ ddocEncodeBase64(ddocDataFile_GetDigestValue(pDataFile), &mbuf2);
+ if(pMBufXML) {
+ if(((char*)mbuf2.pMem)[strlen((char*)mbuf2.pMem)-1] == '\n')
+ ((char*)mbuf2.pMem)[strlen((char*)mbuf2.pMem)-1] = 0;
+ ddocMemAppendData(pMBufXML, (const char*)mbuf2.pMem, -1);
+ }
+ ddocDebug(4, "generateDataFileXML", "DF digest: %s", (char*)mbuf2.pMem);
+ ddocMemBuf_free(&mbuf2);
+ } else {
+#endif
+ ddocMemAppendData(&mbuf2, "</DataFile>", -1);
+ memset(buf2, 0, sizeof(buf2));
+ p = canonicalizeXML((char*)mbuf2.pMem, mbuf2.nLen);
+ ddocMemBuf_free(&mbuf2);
+ RETURN_IF_NULL(p);
+ SHA1((const unsigned char*)p, strlen(p), (unsigned char*)buf2);
+ ddocDebug(4, "generateDataFileXML", "CANONICAL XML: \'%s\'", p);
+ free(p);
+ ddocDebug(4, "generateDataFileXML", "will update DF digest as ctype is %s", pDataFile->szContentType);
+ ddocDataFile_SetDigestValue(pDataFile, buf2, DIGEST_LEN);
+ ddocEncodeBase64(ddocDataFile_GetDigestValue(pDataFile), &mbuf2);
+ if(pMBufXML) {
+ if(((char*)mbuf2.pMem)[strlen((char*)mbuf2.pMem)-1] == '\n')
+ ((char*)mbuf2.pMem)[strlen((char*)mbuf2.pMem)-1] = 0;
+ ddocMemAppendData(pMBufXML, (const char*)mbuf2.pMem, -1);
+ }
+ ddocDebug(4, "generateDataFileXML", "DF digest: %s", (char*)mbuf2.pMem);
+ ddocMemBuf_free(&mbuf2);
+#ifdef WITH_BASE64_HASHING_HACK
+ }
+#endif
+ if(hFile)
+ fputs("</DataFile>", hFile);
+ if(pMBufXML) {
+ ddocMemAppendData(pMBufXML, (const char*)"\">", -1);
+ ddocMemAppendData(pMBufXML, "</DataFile>", -1);
+ }
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ ddocDebug(4, "generateDataFileXML", "done: %d", err);
+ return err;
+}
+
+#define DD_TEMP_FILE_MAX 200
+
+//--------------------------------------------------
+// Creates a new signed XML document
+// pSigDoc - signed doc info
+// szSigDocFile - output XML file name. If the file exists,
+// pMBufXML - output buffer if required to pass back in memory
+// then it will be used to read in embedded DataFile contents.
+// returns error code or ERR_OK for success
+//--------------------------------------------------
+int createSignedXMLDoc(SignedDoc* pSigDoc, const char* szOldFile, const char* szSigDocFile, DigiDocMemBuf* pMBufXML)
+{
+ int err = ERR_OK, i, nFiles;
+ FILE *hFile = 0;
+ DataFile* pDf = NULL;
+ char ** arrTempFiles = NULL;
+ char buf1[1024];
+ DigiDocMemBuf mbuf1;
+#ifdef WIN32
+ wchar_t *convFileName = 0;
+#endif
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ //RETURN_IF_NULL_PARAM(szSigDocFile || pMBufXML);
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ buf1[0] = 0;
+ nFiles = getCountOfDataFiles(pSigDoc);
+ ddocDebug(3, "createSignedXMLDoc", "Old file: %s new file: %s mbuf: %s, DFs: %d",
+ szOldFile, (szSigDocFile ? szSigDocFile : "NULL"), (pMBufXML ? "Y" : "N"), nFiles);
+ // check if the file exists allready
+ // and extracts data files. They
+ // will be used later to construct
+ // a new document and then removed
+ if(szOldFile && checkFileExists(szOldFile)) {
+ arrTempFiles = (char**)malloc(nFiles * sizeof(void*));
+ RETURN_IF_BAD_ALLOC(arrTempFiles);
+ memset(arrTempFiles, 0, nFiles * sizeof(void*));
+ for(i = 0; i < nFiles; i++) {
+ pDf = getDataFile(pSigDoc, i);
+ ddocDebug(3, "createSignedXMLDoc", "DataFile: %s - %s", pDf->szId, pDf->szFileName);
+ arrTempFiles[i] = (char*)malloc(DD_TEMP_FILE_MAX);
+ arrTempFiles[i][0] = 0;
+ // do not copy newly added files
+ if(!strchr((const char*)pDf->szFileName, '/') &&
+ !strchr((const char*)pDf->szFileName, '\\')) {
+ err = getTempFileName(arrTempFiles[i], DD_TEMP_FILE_MAX);
+ // VS: test the new parser based on xmlReader interface
+ //err = ddocXRdrCopyDataFile(pSigDoc, szOldFile, (const char*)arrTempFiles[i], pDf->szId, CHARSET_ISO_8859_1, CHARSET_ISO_8859_1);
+ ddocDebug(3, "createSignedXMLDoc", "Store DataFile: %s to: %s size: %d", pDf->szId, (const char*)arrTempFiles[i], pDf->nSize);
+ err = ddocExtractDataFile(pSigDoc, szOldFile, (const char*)arrTempFiles[i], pDf->szId, "NO-CHANGE");
+ }
+ }
+ }
+ if(szSigDocFile) {
+#ifdef WIN32
+ i = 0;
+ err = utf82unicode((const char*)szSigDocFile, (char**)&convFileName, &i);
+ ddocDebug(3, "createSignedXMLDoc", "Opening FILE: %s, conv-file: %s len: %d", szSigDocFile, convFileName, i);
+ if(err) return err;
+#else
+ err = ddocConvertFileName(buf1, sizeof(buf1), szSigDocFile);
+ ddocDebug(3, "createSignedXMLDoc", "Opening FILE: %s", buf1);
+ if(err) return err;
+#endif
+ }
+ // now create the new document
+#ifdef WIN32
+ if((szSigDocFile && (hFile = _wfopen(convFileName, L"wb")) != NULL) || pMBufXML) {
+#else
+ if((szSigDocFile && (hFile = fopen(buf1, "wb")) != NULL) || pMBufXML) {
+#endif
+ if(szSigDocFile)
+ fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", hFile);
+ if(pMBufXML)
+ ddocMemAppendData(pMBufXML, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", -1);
+ // VS: ver 1.80 - in version 1.3 we started using SignedDoc namespace
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER)) {
+ if(szSigDocFile)
+ fprintf(hFile, "<SignedDoc format=\"%s\" version=\"%s\" xmlns=\"http://www.sk.ee/DigiDoc/v1.3.0#\">\n", pSigDoc->szFormat, pSigDoc->szFormatVer);
+ if(pMBufXML) {
+ ddocMemAppendData(pMBufXML, "<SignedDoc format=\"", -1);
+ ddocMemAppendData(pMBufXML, pSigDoc->szFormat, -1);
+ ddocMemAppendData(pMBufXML, "\" version=\"", -1);
+ ddocMemAppendData(pMBufXML, pSigDoc->szFormatVer, -1);
+ ddocMemAppendData(pMBufXML, "\" xmlns=\"http://www.sk.ee/DigiDoc/v1.3.0#\">\n", -1);
+ }
+ } else {
+ if(szSigDocFile)
+ fprintf(hFile, "<SignedDoc format=\"%s\" version=\"%s\">\n", pSigDoc->szFormat, pSigDoc->szFormatVer);
+ if(pMBufXML) {
+ ddocMemAppendData(pMBufXML, "<SignedDoc format=\"", -1);
+ ddocMemAppendData(pMBufXML, pSigDoc->szFormat, -1);
+ ddocMemAppendData(pMBufXML, "\" version=\"", -1);
+ ddocMemAppendData(pMBufXML, pSigDoc->szFormatVer, -1);
+ ddocMemAppendData(pMBufXML, "\">\n", -1);
+ }
+ }
+ // DataFile objects
+ for(i = 0; i < nFiles; i++) {
+ pDf = getDataFile(pSigDoc, i);
+ ddocDebug(3, "createSignedXMLDoc", "DF: %d file: %s temp: %s", i, pDf->szFileName, (arrTempFiles ? arrTempFiles[i] : "NONE"));
+ // if the file must be embedded
+ if(arrTempFiles && arrTempFiles[i] && checkFileExists(arrTempFiles[i])) {
+ ddocDebug(3, "createSignedXMLDoc", "Use temp file: %s", arrTempFiles[i]);
+ err = generateDataFileXML(pSigDoc, pDf, (const char*)arrTempFiles[i], hFile, &mbuf1);
+ ddocDebug(3, "createSignedXMLDoc", "Use temp file: %s rc: %d", arrTempFiles[i], err);
+ if(!err && pMBufXML)
+ ddocMemAppendData(pMBufXML, mbuf1.pMem, mbuf1.nLen);
+ ddocMemBuf_free(&mbuf1);
+ ddocDebug(3, "createSignedXMLDoc", "Used temp file: %s", arrTempFiles[i]);
+ } else if(checkFileExists(pDf->szFileName) || pDf->mbufContent.pMem) { // TODO: test id out-mem sign works
+ ddocDebug(3, "createSignedXMLDoc", "Create new data file: %s", pDf->szFileName);
+ err = generateDataFileXML(pSigDoc, pDf, (const char*)pDf->szFileName, hFile, &mbuf1);
+ ddocDebug(3, "createSignedXMLDoc", "Create new data file: %s rc: %d", pDf->szFileName, err);
+ if(!err && pMBufXML)
+ ddocMemAppendData(pMBufXML, mbuf1.pMem, mbuf1.nLen);
+ ddocMemBuf_free(&mbuf1);
+ ddocDebug(3, "createSignedXMLDoc", "Created new data file: %s", pDf->szFileName);
+ }
+ if(szSigDocFile)
+ fputs("\n", hFile);
+ if(pMBufXML)
+ ddocMemAppendData(pMBufXML, "\n", -1);
+ }
+ ddocDebug(3, "createSignedXMLDoc", "Gen sigs");
+ for(i = 0; i < pSigDoc->nSignatures; i++) {
+ ddocDebug(3, "createSignedXMLDoc", "Gen sig: %d", i);
+
+ // VS: if Signature has been read from file then
+ // use the original content
+ if(pSigDoc->pSignatures[i]->mbufOrigContent.pMem) {
+ if(szSigDocFile)
+ fwrite(pSigDoc->pSignatures[i]->mbufOrigContent.pMem, sizeof(char),
+ pSigDoc->pSignatures[i]->mbufOrigContent.nLen, hFile);
+ if(pMBufXML)
+ err = ddocMemAppendData(pMBufXML, (const char*)pSigDoc->pSignatures[i]->mbufOrigContent.pMem,
+ pSigDoc->pSignatures[i]->mbufOrigContent.nLen);
+ } else {
+ err = addSignatureInfoXML(&mbuf1, pSigDoc, pSigDoc->pSignatures[i]);
+ if(szSigDocFile)
+ fputs((char*)mbuf1.pMem, hFile);
+ if(pMBufXML)
+ err = ddocMemAppendData(pMBufXML, (const char*)mbuf1.pMem, mbuf1.nLen);
+ ddocMemBuf_free(&mbuf1);
+ }
+ } // for i < pSigDoc->nSignatures
+ if(szSigDocFile) {
+ fputs("</SignedDoc>", hFile);
+ }
+ if(hFile) {
+ ddocDebug(3, "createSignedXMLDoc", "Closing FILE: %s", buf1);
+ fclose(hFile);
+ }
+ if(pMBufXML)
+ ddocMemAppendData(pMBufXML, "</SignedDoc>", -1);
+ ddocDebug(3, "createSignedXMLDoc", "Generated");
+
+ // delete temporary files we created when
+ // extracting the data files from original XML signed doc
+ // VS: fix the bug of deleting input files
+ // This happened because prefix was empty and
+ // thus doc names where the same as original
+ // input file names
+ if(szOldFile && arrTempFiles) { // check if temp files were created
+ for(i = 0; i < nFiles; i++) {
+ pDf = getDataFile(pSigDoc, i);
+ // ignore not being able to delete temp file. It returns -1
+ //_unlink((const char*)arrTempFiles[i]);
+ free(arrTempFiles[i]);
+ }
+ free(arrTempFiles);
+ }
+ } else {
+ err = ERR_FILE_WRITE;
+ #ifdef WIN32
+ ddocDebug(1, "createSignedXMLDoc", "Error1: %d opening file: %s errno: %d doserrno: %d perror: %s",
+ err, szSigDocFile, _errno, _doserrno, strerror(_errno));
+ if(_errno == 1933280595) {
+ err = ERR_NETWORK_SYNC;
+ ddocDebug(1, "createSignedXMLDoc", "Error2 %d opening file for writing. Network sync err?", err);
+ }
+ #endif
+ }
+ ddocDebug(3, "createSignedXMLDoc", "Cleanup1");
+#ifdef WIN32
+ if(convFileName) free(convFileName);
+#endif
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ ddocDebug(3, "createSignedXMLDoc", "Done");
+ return err;
+}
+
+
+//--------------------------------------------------
+// Creates a new signed document
+// pSigDoc - signed doc info
+// returns error code or ERR_OK for success
+//--------------------------------------------------
+EXP_OPTION int createSignedDoc(SignedDoc* pSigDoc, const char* szOldFile, const char* szOutputFile)
+{
+ int err = ERR_OK;
+ int nWait, nRetries, i;
+ long lSize = 0;
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ RETURN_IF_NULL_PARAM(szOutputFile);
+ RETURN_IF_NULL_PARAM(pSigDoc->szFormat);
+ if(szOldFile && strlen(szOldFile)) {
+ calculateFileSize(szOldFile, &lSize);
+ ddocDebug(3, "createSignedDoc", "Old file: %s ddoc-size: %ld", szOldFile, lSize);
+ if(lSize == 0) {
+ ddocDebug(1, "createSignedDoc", "Invalid old file: %s ddoc-size: %ld", szOldFile, lSize);
+ SET_LAST_ERROR(ERR_FILE_READ);
+ return ERR_FILE_READ;
+ }
+ }
+ clearErrors();
+ if(hasSignatureWithWrongDataFileHash(pSigDoc)) {
+ ddocDebug(1, "createSignedDoc", "Cannot save ddoc: %s size: %ld with invalid DataFile hashes!", szOldFile, lSize);
+ return ERR_FILE_WRITE;
+ }
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER) &&
+ !strcmp(pSigDoc->szFormat, DIGIDOC_XML_1_1_NAME)) {
+ err = createSignedXMLDoc(pSigDoc, szOldFile, szOutputFile, NULL);
+ ddocDebug(3, "createSignedDoc", "Done, rc: %d", err);
+ #ifdef WIN32
+ if(err = ERR_NETWORK_SYNC) {
+ nWait = 1; // oli parameeter NETWORK_SYNC_WAIT
+ nRetries = 3; // oli parameeter NETWORK_SYNC_RETRIES
+ ddocDebug(3, "createSignedDoc", "Network sync wait: %d retries: %d", nWait, nRetries);
+ for(i = 0; (err == ERR_NETWORK_SYNC) && (i < nRetries); i++) {
+ ddocDebug(3, "createSignedDoc", "Network sync wait: %d", nWait);
+ Sleep(1000 * nWait);
+ ddocDebug(3, "createSignedDoc", "Network sync write: %d of: %d retries", i, nRetries);
+ clearErrors(); // reset errors from past failed write attempt
+ err = createSignedXMLDoc(pSigDoc, szOldFile, szOutputFile, NULL);
+ }
+ }
+ #endif
+ }
+ else
+ err = ERR_UNSUPPORTED_FORMAT;
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+//--------------------------------------------------
+// Creates a new signed document in memory buffer
+// pSigDoc - signed doc info
+// szOldFile - name of old file on disk to copy DataFile contents
+// pMBuf - buffer for new digidoc document
+// returns error code or ERR_OK for success
+//--------------------------------------------------
+EXP_OPTION int createSignedDocInMemory(SignedDoc* pSigDoc, const char* szOldFile, DigiDocMemBuf* pMBuf)
+{
+ int err = ERR_OK;
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ RETURN_IF_NULL_PARAM(pMBuf);
+ RETURN_IF_NULL_PARAM(pSigDoc->szFormat);
+ clearErrors();
+ if(hasSignatureWithWrongDataFileHash(pSigDoc)) {
+ ddocDebug(1, "createSignedDocInMemory", "Cannot save ddoc: %s with invalid DataFile hashes!", szOldFile);
+ return ERR_FILE_WRITE;
+ }
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER) &&
+ !strcmp(pSigDoc->szFormat, DIGIDOC_XML_1_1_NAME)) {
+ err = createSignedXMLDoc(pSigDoc, szOldFile, NULL, pMBuf);
+ }
+ else
+ err = ERR_UNSUPPORTED_FORMAT;
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+//--------------------------------------------------
+// Removes incomplete or orphoned signatures.
+// Signature is incomplete if it hasn't got the signature
+// value
+// pSigDoc - signed doc info
+// returns error code or ERR_OK for success
+//--------------------------------------------------
+EXP_OPTION int removeIncompleteSignatures(SignedDoc* pSigDoc)
+{
+ int err = ERR_OK, i, n, b;
+ SignatureInfo *pSigInfo;
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ do {
+ b = 0;
+ n = getCountOfSignatures(pSigDoc);
+ for(i = 0; i < n; i++){
+ pSigInfo = getSignature(pSigDoc, i);
+ if(!pSigInfo->pSigValue ||
+ (pSigInfo->pSigValue && !pSigInfo->pSigValue->mbufSignatureValue.pMem)) {
+ SignatureInfo_free(pSigInfo); // remove incomplete signature
+ break;
+ }
+ }
+ } while(b);
+ return err;
+}
+
+//--------------------------------------------------
+// Checks for incomplete or orphoned signatures.
+// Signature is incomplete if it hasn't got the signature
+// value
+// pSigDoc - signed doc info
+// returns error code if DigiDoc has orphoned signature or ERR_OK for success
+//--------------------------------------------------
+EXP_OPTION int hasIncompleteSignatures(SignedDoc* pSigDoc)
+{
+ int i;
+ SignatureInfo *pSigInfo;
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ for(i = 0; i < getCountOfSignatures(pSigDoc); i++){
+ pSigInfo = getSignature(pSigDoc, i);
+ if(!pSigInfo->pSigValue ||
+ (pSigInfo->pSigValue && !pSigInfo->pSigValue->mbufSignatureValue.pMem)) {
+ return ERR_ORPHONED_SIGNATURE;
+ }
+ }
+ return ERR_OK;
+}
+