//================================================== // FILE: DigiDocService.c // PROJECT: Digi Doc // DESCRIPTION: Digi Doc functions for DigiDocService access // AUTHOR: Veiko Sinivee, Sunset Software O† //================================================== // 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 //================================================== // config data comes from there #include #include #include #include #include #include #include #include #include #include #include #include char* g_xmlHdr1 = "\n"; char* g_xmlEnd1 = ""; char* g_xmlHdr2 = "\n"; char* g_xmlEnd2 = ""; char* g_ddsUrl = "https://digidocservice.sk.ee/DigiDocService"; int ddocXmlElem(DigiDocMemBuf* pMbuf, const char* szElem, const char* szValue) { int err = ERR_OK; if(szValue) { err = ddocGen_startElem(pMbuf, szElem); if(!err) err = ddocMemAppendData(pMbuf, szValue, -1); if(!err) err = ddocGen_endElem(pMbuf, szElem); } return err; } int findXmlElemValue(DigiDocMemBuf* pMbMsg, const char* szTag, DigiDocMemBuf* pMbValue) { char *p1, *p2; char tag[50]; p1 = (char*)pMbMsg->pMem; if(p1) { snprintf(tag, sizeof(tag), "<%s", szTag); p1 = strstr(p1, tag); if(p1) { while(*p1 && *p1 != '>') p1++; if(*p1 && *p1 == '>') p1++; snprintf(tag, sizeof(tag), " (long)p1) { ddocMemAssignData(pMbValue, p1, (int)(p2 - p1)); return 0; } } } return -1; } //-------------------------------------------------- // Signs the document and gets return status back // pSigDoc - signed document object // szIdCode - personal id code // szPhoneNo - users phone number // szLang - language code // manifest - manifest or role // city - signers address , city // state - signers address , state or province // zip - signers address , postal code // country - signers address , country name // pSesscode - pointer to long int buffer for returning session code // szChallenge - buffer for returning challenge code (char 4) // nChalLen - length of challenge buffer // return error code or ERR_OK //-------------------------------------------------- EXP_OPTION int ddsSign(SignedDoc* pSigDoc, const char* szIdCode, const char* szPhoneNo, const char* szLang, const char* szServiceName, const char* manifest, const char* city, const char* state, const char* zip, const char* country, char* url, char* proxyHost, char* proxyPort, long* pSesscode, char* szChallenge, int nChalLen) { int err = ERR_OK, i, l1; char *p1 = 0; DataFile *pDf = 0; DigiDocMemBuf mbuf1, mbuf2, mbuf3; char buf1[40]; mbuf1.pMem = 0; mbuf1.nLen = 0; mbuf2.pMem = 0; mbuf2.nLen = 0; mbuf3.pMem = 0; mbuf3.nLen = 0; ddocDebug(3, "ddsSign", "Creating M-ID signature using: %s", szPhoneNo); RETURN_IF_NULL_PARAM(pSigDoc); RETURN_IF_NULL_PARAM(szIdCode); RETURN_IF_NULL_PARAM(country); RETURN_IF_NULL_PARAM(szPhoneNo); //RETURN_IF_NULL_PARAM(url); if(url == NULL) url = g_ddsUrl; RETURN_IF_NULL_PARAM(pSesscode); RETURN_IF_NULL_PARAM(szChallenge); ddocMemAssignData(&mbuf2, g_xmlHdr1, -1); // create xml request err = ddocXmlElem(&mbuf2, "IDCode", szIdCode); err = ddocXmlElem(&mbuf2, "SignersCountry", country); err = ddocXmlElem(&mbuf2, "PhoneNo", szPhoneNo); err = ddocXmlElem(&mbuf2, "Language", szLang); err = ddocXmlElem(&mbuf2, "ServiceName", szServiceName); err = ddocXmlElem(&mbuf2, "Role", manifest); err = ddocXmlElem(&mbuf2, "City", city); err = ddocXmlElem(&mbuf2, "StateOrProvince", state); err = ddocXmlElem(&mbuf2, "PostalCode", zip); err = ddocXmlElem(&mbuf2, "CountryName", country); err = ddocGen_startElem(&mbuf2, "DataFiles"); for(i = 0; i < getCountOfDataFiles(pSigDoc); i++) { pDf = getDataFile(pSigDoc, i); err = ddocGen_startElem(&mbuf2, "DataFileDigest"); err = ddocXmlElem(&mbuf2, "Id", pDf->szId); err = ddocXmlElem(&mbuf2, "DigestType", pDf->szDigestType); l1 = sizeof(buf1); memset(buf1, 0, l1); encode((const byte*)pDf->mbufDigest.pMem, pDf->mbufDigest.nLen, (byte*)buf1, &l1); err = ddocXmlElem(&mbuf2, "DigestValue", buf1); err = ddocGen_endElem(&mbuf2, "DataFileDigest"); } err = ddocGen_endElem(&mbuf2, "DataFiles"); err = ddocXmlElem(&mbuf2, "Format", pSigDoc->szFormat); err = ddocXmlElem(&mbuf2, "Version", pSigDoc->szFormatVer); sprintf(buf1, "S%d", getNextSignatureId(pSigDoc)); err = ddocXmlElem(&mbuf2, "SignatureID", buf1); err = ddocXmlElem(&mbuf2, "MessagingMode", "asynchClientServer"); err = ddocXmlElem(&mbuf2, "AsyncConfiguration", "0"); ddocMemAppendData(&mbuf2, g_xmlEnd1, -1); // create http req ddocMemAssignData(&mbuf1, "POST ", -1); if(proxyHost || (proxyPort && atoi(proxyPort) > 0)) { ddocMemAppendData(&mbuf1, url, -1); } else { p1 = strstr(url, "://"); if(p1) p1 += 3; if(p1) p1 = strchr(p1, '/'); if(p1) ddocMemAppendData(&mbuf1, p1, -1); else ddocMemAppendData(&mbuf1, "/", -1); } ddocMemAppendData(&mbuf1, " HTTP/1.0\r\n", -1); ddocMemAppendData(&mbuf1, "User-Agent: DigiDocLib\r\n", -1); ddocMemAppendData(&mbuf1, "Content-Type: text/xml; charset=utf-8\r\n", -1); snprintf(buf1, sizeof(buf1), "Content-Length: %d\r\n", (int)mbuf2.nLen); ddocMemAppendData(&mbuf1, buf1, -1); ddocMemAppendData(&mbuf1, "Connection: Close\r\n", -1); if(proxyHost || (proxyPort && atoi(proxyPort) > 0)) // if we use proxy then send also Proxy-Connection ddocMemAppendData(&mbuf1, "Proxy-Connection: Close\r\n", -1); ddocMemAppendData(&mbuf1, "SOAPAction: \"\"\r\n", -1); ddocMemAppendData(&mbuf1, "\r\n", -1); ddocMemAppendData(&mbuf1, mbuf2.pMem, mbuf2.nLen); ddocDebug(4, "ddsSign", "Send to host: %s request len: %d", url, mbuf1.nLen); ddocDebug(4, "ddsSign", "Sending: \n---\n%s\n---\n", mbuf1.pMem); ddocMemBuf_free(&mbuf2); err = ddocPullUrl(url, &mbuf1, &mbuf2, proxyHost, proxyPort); ddocDebug(4, "ddsSign", "Recevied len: %d RC: %d", mbuf2.nLen, err); //ddocDebug(3, "ddsSign", "Received: \n---\n%s\n---\n", mbuf2.pMem); if(!err && ((l1 = ddocGetHttpResponseCode(&mbuf2)) == 200)) { err = ddocGetHttpPayload(&mbuf2, &mbuf3); ddocMemBuf_free(&mbuf2); ddocDebug(4, "ddsSign", "SOAP: \n---\n%s\n---\n", mbuf3.pMem); err = findXmlElemValue(&mbuf3, "Sesscode", &mbuf2); if(!err) (*pSesscode) = atol((char*)mbuf2.pMem); //ddocDebug(3, "ddsSign", "Sesscode: %ld", (*pSesscode)); ddocMemBuf_free(&mbuf2); err = findXmlElemValue(&mbuf3, "ChallengeID", &mbuf2); //ddocDebug(3, "ddsSign", "Challenge id %s", mbuf2.pMem); if(!err && mbuf2.pMem && mbuf2.nLen) { memset(szChallenge, 0, nChalLen); strncpy(szChallenge, mbuf2.pMem, mbuf2.nLen); } ddocDebug(3, "ddsSign", "Sesscode: %ld Challenge id %s RC: %d", (*pSesscode), szChallenge, err); ddocMemBuf_free(&mbuf2); } ddocMemBuf_free(&mbuf1); ddocMemBuf_free(&mbuf2); ddocMemBuf_free(&mbuf3); RETURN_IF_NOT(err == ERR_OK, err); return err; } //------------------------------------------ // Gets DigiDocService session status and returns status code // If session is ready then signature will be returned // pSigDoc - signed document object to be modified // lSesscode - session code // url - dds service url // proxyHost - proxy hostname // proxyPort -proxy port // pStatus - buffer for returning status // pMBufSig - buffer for returning signature // returns DigiDocService session status code // deprecated use ddsGetStatus(pSigDoc, lSesscode, url, proxyHost, proxyPort, pStatus, szFileName) //------------------------------------------ DIGIDOC_DEPRECATED EXP_OPTION int ddsGetStatus(SignedDoc* pSigDoc, long lSesscode, char* url, char* proxyHost, char* proxyPort, int* pStatus) { return ddsGetStatusWithFile(pSigDoc, lSesscode, url, proxyHost, proxyPort, pStatus, NULL); } //------------------------------------------ // Gets DigiDocService session status and returns status code // If session is ready then signature will be returned // pSigDoc - signed document object to be modified // lSesscode - session code // url - dds service url // proxyHost - proxy hostname // proxyPort -proxy port // pStatus - buffer for returning status // szFileName - ddoc filename to add signature from dds (optional) // pMBufSig - buffer for returning signature // returns DigiDocService session status code //------------------------------------------ EXP_OPTION int ddsGetStatusWithFile(SignedDoc* pSigDoc, long lSesscode, char* url, char* proxyHost, char* proxyPort, int* pStatus, const char* szFileName) { int err = ERR_OK, l1; SignatureInfo *pSigInfo = 0; DigiDocMemBuf mbuf1, mbuf2, mbuf3; char buf1[40], *p1; mbuf1.pMem = 0; mbuf1.nLen = 0; mbuf2.pMem = 0; mbuf2.nLen = 0; mbuf3.pMem = 0; mbuf3.nLen = 0; ddocDebug(3, "ddsGetStatus", "Get Status for sess: %ld", lSesscode); RETURN_IF_NULL_PARAM(pSigDoc); //RETURN_IF_NULL_PARAM(url); if(url == NULL) url = g_ddsUrl; RETURN_IF_NULL_PARAM(pStatus); *pStatus = 0; ddocMemAssignData(&mbuf2, g_xmlHdr2, -1); // create xml request sprintf(buf1, "%ld", lSesscode); err = ddocXmlElem(&mbuf2, "Sesscode", buf1); err = ddocXmlElem(&mbuf2, "WaitSignature", "false"); ddocMemAppendData(&mbuf2, g_xmlEnd2, -1); // create http req ddocMemAssignData(&mbuf1, "POST ", -1); if(proxyHost || (proxyPort && atoi(proxyPort) > 0)) { ddocMemAppendData(&mbuf1, url, -1); } else { p1 = strstr(url, "://"); if(p1) p1 += 3; if(p1) p1 = strchr(p1, '/'); if(p1) ddocMemAppendData(&mbuf1, p1, -1); else ddocMemAppendData(&mbuf1, "/", -1); } ddocMemAppendData(&mbuf1, " HTTP/1.0\r\n", -1); ddocMemAppendData(&mbuf1, "User-Agent: DigiDocLib\r\n", -1); ddocMemAppendData(&mbuf1, "Content-Type: text/xml; charset=utf-8\r\n", -1); snprintf(buf1, sizeof(buf1), "Content-Length: %d\r\n", (int)mbuf2.nLen); ddocMemAppendData(&mbuf1, buf1, -1); ddocMemAppendData(&mbuf1, "Connection: Close\r\n", -1); if(proxyHost || (proxyPort && atoi(proxyPort) > 0)) // if we use proxy then send also Proxy-Connection ddocMemAppendData(&mbuf1, "Proxy-Connection: Close\r\n", -1); ddocMemAppendData(&mbuf1, "SOAPAction: \"\"\r\n", -1); ddocMemAppendData(&mbuf1, "\r\n", -1); ddocMemAppendData(&mbuf1, mbuf2.pMem, mbuf2.nLen); ddocDebug(4, "ddsGetStatus", "Send to host: %s request len: %d", url, mbuf1.nLen); ddocDebug(4, "ddsGetStatus", "Sending: \n---\n%s\n---\n", mbuf1.pMem); ddocMemBuf_free(&mbuf2); err = ddocPullUrl(url, &mbuf1, &mbuf2, proxyHost, proxyPort); ddocDebug(4, "ddsGetStatus", "Recevied len: %d RC: %d", mbuf2.nLen, err); //ddocDebug(3, "ddsSign", "Received: \n---\n%s\n---\n", mbuf2.pMem); if(!err && ((l1 = ddocGetHttpResponseCode(&mbuf2)) == 200)) { err = ddocGetHttpPayload(&mbuf2, &mbuf3); ddocMemBuf_free(&mbuf2); ddocDebug(4, "ddsGetStatus", "SOAP: \n---\n%s\n---\n", mbuf3.pMem); err = findXmlElemValue(&mbuf3, "Status", &mbuf2); if(!err && mbuf2.pMem) { if(!strcmp((char*)mbuf2.pMem, "OUTSTANDING_TRANSACTION")) (*pStatus) = STATUS_OUTSTANDING_TRANSACTION; if(!strcmp((char*)mbuf2.pMem, "SIGNATURE")) (*pStatus) = STATUS_SIGNATURE; if(!strcmp((char*)mbuf2.pMem, "ERROR")) (*pStatus) = STATUS_ERROR; } ddocDebug(3, "ddsGetStatus", "Sesscode: %ld Status: %d RC: %d", lSesscode, (*pStatus), err); ddocMemBuf_free(&mbuf2); if((*pStatus) == STATUS_SIGNATURE) { err = findXmlElemValue(&mbuf3, "Signature", &mbuf2); ddocDebug(4, "ddsGetStatus", "Sig-esacped: \n---\n%s\n---\n", mbuf2.pMem); p1 = escape2xmlsym((char*)mbuf2.pMem); ddocDebug(4, "ddsGetStatus", "Signature: \n---\n%s\n---\n", p1); err = ddocAddSignatureFromMemory(pSigDoc, szFileName, (const void*)p1, strlen(p1)); /*sprintf(buf1, "S%d", getNextSignatureId(pSigDoc)); SignatureInfo_new(&pSigInfo, pSigDoc, buf1); ddocMemAssignData(&(pSigInfo->mbufOrigContent), p1, -1);*/ free(p1); } } ddocMemBuf_free(&mbuf1); ddocMemBuf_free(&mbuf2); ddocMemBuf_free(&mbuf3); RETURN_IF_NOT(err == ERR_OK, err); return err; }