diff options
Diffstat (limited to 'libdigidoc/DigiDocLib.c')
-rw-r--r-- | libdigidoc/DigiDocLib.c | 1173 |
1 files changed, 1173 insertions, 0 deletions
diff --git a/libdigidoc/DigiDocLib.c b/libdigidoc/DigiDocLib.c new file mode 100644 index 0000000..4ec82e2 --- /dev/null +++ b/libdigidoc/DigiDocLib.c @@ -0,0 +1,1173 @@ +//================================================== +// FILE: DigiDocLib.c +// PROJECT: Digi Doc +// DESCRIPTION: Digi Doc functions for creating +// and reading signed documents. +// 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 >============================= +// 20.09.2004 Changed createOCSPRequest() to use custom functions for adding +// OCSP nonce to OCSP request for digidoc formats 1.0, 1.1 and 1.2 +// thereby guaranteing that in case of those formats only 20 bytes are sent. +// This is necessary to guarantee backward compatibility with OpenSSL 0.9.6 +// 22.08.2004 Added DataFile content caching, function ddocGetDataFileCachedData() +// and modified functions readSignedDoc(), extractDataFile(), +// ddocExtractDataFile(), ddocGetDataFile() and ddocCopyDataFile() to use it. +// Added function ddocSaxReadSignedDocFromMemory() +// New debugging interface ddocDebug() +// 12.08.2004 Moved all SAX xml parsing functions to DigiDocSAXParser.c +// and fixed some memory problems +// 03.08.2004 Added check to initializeNotaryInfoWithOCSP() to handle 22 byte ASN.1 +// encoded nonce with OpenSSL 0.9.7d +// added a check on output filename for extractDataFile() function. +// added a check for verifyNotaryInfoCERT() function to check empty certificate array size. +// Added back the function verifyCertificateByOCSP() +// 14.06.2004 Changed generateDataFileXML() to replaces '&' with '&' +// int file names. Changed handleStartDataFile() acordingly. +// 20.05.2004 Added new error codes to handle OCSP response +// status and fixed initializeNotaryInfoWithOCSP() +// 19.05.2004 Added a nullpointer test to checkFileExists() +// 12.05.2004 Fixed convertStringToTimeT() by changing +// timestamp format pattern according to 1.3 format version +// 11.05.2004 Added error code ERR_OCSP_WRONG_URL to sendOCSPRequest +// to indicate that the given server is not an OCSP server +// 23.03.2004 fixed setSignatureValueFromFile() that was affected +// by siganture caching. Fixed getConfirmation() to +// allowe sending not signed OCSP requests. +// 17.03.2004 fixed getSignerCode() to handle certs that +// have no comma in CN. Fixed NotaryInfo_new to +// reset szOrigContent of signature. Added function +// handleOCSPCertStatus() to check cert status +// and modified initializeNotaryInfoWithOCSP() and +// checkNonceAndCertbyOCSP() +// 11.03.2004 added SignedDoc namespace in format 1.3 +// generateDataFileXML(), createSignedXMLDoc() +// handleStartDataFile(), +// bugs in emptying buffers +// unicode2ascii(), getSignerLastName() +// Veiko Sinivee +// 25.11.2003 added functions calculateFileLength(), +// verifyCertificateByOCSP() and helper functions +// 21.11.2003 Fixed SignatureValue decoding problem +// Veiko Sinivee +// 17.11.2003 Aare Amenberg +// Changed error texts +// Changed sendOCSPRequest +// (added more error checkings) +// 14.11.2003 Aare Amenberg +// Removed WriteOCSPResponse +// Changed addNotaryInfoXML by Veiko +// 11.11.2003 Aare Amenberg +// Added CorrectCharacters +// Added error 96 ERR_WRONG_URL_OR_PROXY +// 31.10.2003 Aare Amenberg +// Added error text 95 +// Removed if(single->singleExtensions) +// SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_NO_SINGLE_EXT); +// Function initializeNotaryInfoWithOCSP +// 29.10.2003 Aare Amenberg +// WIN32_CSP functions moved +// to module DigiDocCsp +// 1.0 09.04.2002 Veiko Sinivee +// Supports XML format (Type: SK-XML-1.0) +//================================================== + +#include <libdigidoc/DigiDocDefs.h> + +#define WIN32_PKCS 1 + +#ifdef WIN32 + #include <wincrypt.h> +#endif + +#include <config.h> + +#include <libdigidoc/DigiDocLib.h> +#include <libdigidoc/DigiDocSAXParser.h> +#include <libdigidoc/DigiDocDebug.h> +#include <libdigidoc/DigiDocConvert.h> +#include <libdigidoc/DigiDocConfig.h> +#include <libdigidoc/DigiDocCert.h> +#include <libdigidoc/DigiDocGen.h> +//AM +#include <libdigidoc/DigiDocObj.h> + +#include <stdio.h> +#include <stdlib.h> +#include <memory.h> +#include <string.h> +#include <assert.h> +#include <ctype.h> +#include <fcntl.h> +#include <time.h> + +#include <openssl/sha.h> +#include <openssl/rsa.h> +#include <openssl/evp.h> +#include <openssl/objects.h> +#include <openssl/x509.h> +#include <openssl/x509v3.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/ssl.h> +#include <openssl/ocsp.h> +#include <openssl/pkcs12.h> +#include <openssl/rand.h> + +long int tzone = -7200; /* default for Estonia, but see initDigiDocLib() */ +int daylight = 0; /* default, but see initDigiDocLib() */ + +//==========< global constants >==================== + +char g_szLibName[] = "CDigiDoc"; +char g_szLibVer[] = DIGIDOC_VERSION; +//char g_szLibVer[] = VERSION; +char* g_szSupportedVersions[] = { "1.0", "1.1", "1.2", "1.3", "0.7" + }; + +char* g_arrFormats[] = { SK_XML_1_NAME, DIGIDOC_XML_1_1_NAME, 0 }; + +FormatAndVer g_supportedFormatsAndVersions[] = { + { SK_XML_1_NAME, SK_XML_1_VER }, + { DIGIDOC_XML_1_1_NAME, DIGIDOC_XML_1_1_VER }, + { DIGIDOC_XML_1_1_NAME, DIGIDOC_XML_1_2_VER }, + { DIGIDOC_XML_1_1_NAME, DIGIDOC_XML_1_3_VER }, + { NULL, NULL } // list end marker +}; + +// static buffer for name & version of the program using this library +#define GUI_VERSION_LEN 100 +char g_szGUIVersion[GUI_VERSION_LEN]; + +//==========< global variables >==================== + + + +// forward deklaratsioon +int notary2ocspBasResp(const SignedDoc* pSigDoc, const NotaryInfo* pNotInfo, X509* notCert, OCSP_BASICRESP** pBasResp); +int calculateOcspBasicResponseDigest(OCSP_BASICRESP* pBsResp, byte* digBuf, int* digLen); + +int createOCSPRequest(SignedDoc* pSigDoc, OCSP_REQUEST **req, + X509 *cert, X509 *pCA, byte* nonce, int nlen); +EXP_OPTION int signOCSPRequestPKCS12(OCSP_REQUEST *req, const char* filename, const char* passwd); + +int verifyOCSPResponse(OCSP_RESPONSE* pResp, + const X509** caCerts, const char *CApath, + const X509* notCert); +int checkNonceAndCertbyOCSP(OCSP_RESPONSE* resp, X509* cert, byte* nonce1, int nonceLen); + +int verifyResp(OCSP_BASICRESP* bs, const char *CA2file, const char *CA1file, + const char *CApath, const char* notCertFile); + +extern int writeCertToXMLFile(BIO* bout, X509* cert); + +//==========< utility functions >==================== + + +#ifdef WIN32 + CRITICAL_SECTION cs_ddocLocaltime; +#endif + +//-------------------------------------------------- +// Converts timestamp (time_t) value to a struct +// tm value. Caller must provide address of tm struct. +// This function is used because loacltime() is not +// thread-safe and win32 has no equvalent of localtime_r(). +// pTime - time_t value address +// pTmStruct - struct tm address +// bLocal - 1=localtime_r, 0=gmtime_r +// returns error code or ERR_OK +//-------------------------------------------------- +EXP_OPTION int ddocLocalTime(time_t* pTime, struct tm* pTmStruct, int bLocal) +{ +#ifdef WIN32 + struct tm *pTm; +#endif + RETURN_IF_NULL_PARAM(pTime); + RETURN_IF_NULL_PARAM(pTmStruct); + +#ifdef WIN32 + EnterCriticalSection(&cs_ddocLocaltime); + if(bLocal) + pTm = localtime(pTime); + else + pTm = gmtime(pTime); + *pTmStruct = *pTm; + LeaveCriticalSection(&cs_ddocLocaltime); +#else + if(bLocal) + localtime_r(pTime, pTmStruct); + else + gmtime_r(pTime, pTmStruct); +#endif + return ERR_OK; +} + + +//==========< admin functions >==================== + +//-------------------------------------------------- +// returns the library name +//-------------------------------------------------- +EXP_OPTION const char* getLibName() +{ + return g_szLibName; +} + +//-------------------------------------------------- +// returns the library version +//-------------------------------------------------- +EXP_OPTION const char* getLibVersion() +{ + return g_szLibVer; +} + +//-------------------------------------------------- +// returns an array of supported formats terminated by NULL +//-------------------------------------------------- +EXP_OPTION const char** getSupportedFormats() +{ + return (const char**)g_arrFormats; +} + +//-------------------------------------------------- +// returns an array of supported formats and versions terminated by NULL +//-------------------------------------------------- +EXP_OPTION FormatAndVer* getSupportedFormatsAndVersions() +{ + return g_supportedFormatsAndVersions; +} + +//-------------------------------------------------- +// Cheks a combination of format and version for validity +// format - digidoc format name +// version - version name +// returns error code or ERR_OK +//-------------------------------------------------- +int ddocCheckFormatAndVer(const char* format, const char* version) +{ + int i; + if(!format || !version) + return ERR_UNSUPPORTED_FORMAT; + for(i = 0; i < SUPPORTED_VERSION_COUNT; i++) + if(!strcmp(g_supportedFormatsAndVersions[i].szFormat, format) && + !strcmp(g_supportedFormatsAndVersions[i].szVersion, version)) + return ERR_OK; + return ERR_UNSUPPORTED_FORMAT; +} + +//-------------------------------------------------- +// initializes DigiDoc library +//-------------------------------------------------- +EXP_OPTION void initDigiDocLib() +{ + memset(g_szGUIVersion, 0, sizeof(g_szGUIVersion)); +#if defined(__FreeBSD__) + struct tm local_tm; + time_t t; + time(&t); + ddocLocalTime(&t, &local_tm, 1); // Extract timezone info from struct tm + _timezone = - local_tm.tm_gmtoff; + _daylight = local_tm.tm_isdst; +#endif + //ddocDebug(1, "initDigiDocLib", "init openssl & digidoc lib"); + ERR_load_ERR_strings(); + ERR_load_crypto_strings(); + ERR_clear_error(); + OpenSSL_add_all_algorithms(); + SSL_library_init(); +#ifdef WIN32 + InitializeCriticalSection(&cs_ddocErrors); + InitializeCriticalSection(&cs_ddocLocaltime); +#endif +} + +//-------------------------------------------------- +// returns the GUI version +//-------------------------------------------------- +EXP_OPTION const char* getGUIVersion() +{ + return g_szGUIVersion; +} + +//-------------------------------------------------- +// sets the GUI version +//-------------------------------------------------- +EXP_OPTION void setGUIVersion(const char* szVer) +{ + strncpy(g_szGUIVersion, szVer, sizeof(g_szGUIVersion)-1); +} + +//-------------------------------------------------- +// cleanup of DigiDoc library +//-------------------------------------------------- +EXP_OPTION void finalizeDigiDocLib() +{ + ERR_free_strings(); + EVP_cleanup(); +} + +//==========< general crypto fucntions >============ + + +//-------------------------------------------------- +// Checks and prints errors +//-------------------------------------------------- +EXP_OPTION long checkErrors() +{ + char buf[200]; + long e=0; + + while((ERR_peek_error()) > ERR_LIB_NONE) { + e = ERR_get_error(); + ERR_error_string_n(e, buf, sizeof(buf)); + // VS: keep silent !!! + printf("ERROR: %ld - %s \n", e, buf); + } + ERR_clear_error(); + return e; +} + + + + +//-------------------------------------------------- +// Calculates files SHA1 digest +// szFileName - file name +// nDigestType - digest type. Supports only SHA1 (0) +// pDigestBuf - buffer to store the digest +// nDigestLen - buffer size, must be at least 20 +// will be updated by actual digest length +// lFileLen - pointer to a buffer where to store the file length +// returns error code or ERR_OK for success +//-------------------------------------------------- +EXP_OPTION int calculateFileDigest(const char* szFileName, int nDigestType, + byte* pDigestBuf, int* nDigestLen, long* lFileLen) +{ + int err = ERR_OK; + byte buf[FILE_BUFSIZE]; + int i; + FILE *f = NULL; + + RETURN_IF_NULL_PARAM(szFileName); + RETURN_IF_NULL_PARAM(pDigestBuf); + RETURN_IF_NULL_PARAM(nDigestLen); + RETURN_IF_NULL_PARAM(lFileLen); + + memset(pDigestBuf, 0, *nDigestLen); + if(nDigestType == DIGEST_SHA1) { + if(*nDigestLen >= SHA_DIGEST_LENGTH) { + SHA_CTX ctx; + *nDigestLen = SHA_DIGEST_LENGTH; + if((f = fopen(szFileName,"rb")) != NULL) { + //byte *data,*temp_data; + SHA1_Init(&ctx); + *lFileLen = 0; + for (;;) { + i = fread(buf, sizeof(char), FILE_BUFSIZE, f); + if (i <= 0) break; + *lFileLen += i; + SHA1_Update(&ctx, buf, (unsigned long)i); + } + SHA1_Final(pDigestBuf,&ctx); + fclose(f); + } // if - fopen + else + err = ERR_FILE_READ; + } + else + err = ERR_DIGEST_LEN; + } //AM 22.04.08 + else if(nDigestType == DIGEST_SHA256){ + if(*nDigestLen >= SHA_DIGEST_LENGTH) { + SHA256_CTX ctx; + *nDigestLen = SHA256_DIGEST_LENGTH; + if((f = fopen(szFileName,"rb")) != NULL) { + //byte *data,*temp_data; + SHA256_Init(&ctx); + *lFileLen = 0; + for (;;) { + i = fread(buf, sizeof(char), FILE_BUFSIZE, f); + if (i <= 0) break; + *lFileLen += i; + SHA256_Update(&ctx, buf, (unsigned long)i); + } + SHA256_Final(pDigestBuf,&ctx); + fclose(f); + } // if - fopen + else + err = ERR_FILE_READ; + } + else + err = ERR_DIGEST_LEN; + } + else + err = ERR_UNSUPPORTED_DIGEST; + if (err != ERR_OK) SET_LAST_ERROR(err); + return err; +} + + +//-------------------------------------------------- +// Calculates file size +// szFileName - file name +// lFileLen - pointer to a buffer where to store the file length +// returns error code or ERR_OK for success +//-------------------------------------------------- +EXP_OPTION int calculateFileSize(const char* szFileName, long* lFileLen) +{ + FILE* hFile = 0; +#ifdef WIN32 + int i = 0, err = ERR_OK; + wchar_t *convFileName = 0; +#endif + + RETURN_IF_NULL_PARAM(szFileName); + RETURN_IF_NULL_PARAM(lFileLen); + if(!szFileName || !strlen(szFileName)) return 0; +#ifdef WIN32 + err = utf82unicode((const char*)szFileName, (char**)&convFileName, &i); + ddocDebug(3, "calculateFileSize", "Opening FILE: %s, conv-file: %s len: %d", szFileName, convFileName, i); + if((hFile = _wfopen(convFileName,L"rb")) != NULL) { +#else + if((hFile = fopen(szFileName,"rb")) != NULL) { +#endif + fseek(hFile, 0, SEEK_END); + (*lFileLen) = ftell(hFile); + ddocDebug(3, "calculateFileSize", "Closing FILE: %s, size: %ld", szFileName, (*lFileLen)); + fclose(hFile); + } // if - fopen + else + SET_LAST_ERROR_RETURN_CODE(ERR_FILE_READ); +#ifdef WIN32 + if(convFileName) free(convFileName); +#endif + + return ERR_OK; +} + + +//-------------------------------------------------- +// Calculates files SHA1-RSA signature +// szFileName - file name +// nDigestType - digest type. Supports only SHA1 (0) +// pSigBuf - buffer to store the signature +// nSigLen - buffer size, must be at least 128 +// will be updated by actual signature length +// keyfile - name of the private key file +// passwd - private key password +// returns error code or ERR_OK for success +//-------------------------------------------------- +EXP_OPTION int calculateFileSignature(const char* szFileName, int nDigestType, + byte* pSigBuf, int* nSigLen, + const char *keyfile, const char* passwd) +{ + int err = ERR_OK; + EVP_MD_CTX ctx; + byte buf[FILE_BUFSIZE]; + int i; + FILE *f = NULL; + EVP_PKEY* pkey = NULL; + + RETURN_IF_NULL_PARAM(szFileName); + RETURN_IF_NULL_PARAM(pSigBuf); + RETURN_IF_NULL_PARAM(nSigLen); + RETURN_IF_NULL_PARAM(keyfile); + RETURN_IF_NULL_PARAM(passwd); + + memset(pSigBuf, 0, *nSigLen); + if(nDigestType == DIGEST_SHA1) { + if(*nSigLen >= SIGNATURE_LEN) { + if((err = ReadPrivateKey(&pkey, keyfile, passwd, FILE_FORMAT_PEM)) == ERR_OK) { + if((f = fopen(szFileName,"rb")) != NULL) { + EVP_SignInit(&ctx, EVP_sha1()); + for (;;) { + i = fread(buf, sizeof(char), FILE_BUFSIZE, f); + if (i <= 0) break; + EVP_SignUpdate (&ctx, buf, (unsigned long)i); + } + err = EVP_SignFinal(&ctx, pSigBuf, (unsigned int*)nSigLen, pkey); + if(err == ERR_LIB_NONE) + err = ERR_OK; + fclose(f); + EVP_PKEY_free(pkey); + } // if - fopen + else + err = ERR_FILE_READ; + } + else + err = ERR_PRIVKEY_READ; + } + else + err = ERR_SIGNATURE_LEN; + } + else + err = ERR_UNSUPPORTED_DIGEST; + if (err != ERR_OK) SET_LAST_ERROR(err); + return err; +} + + +//-------------------------------------------------- +// Calculates input datas SHA1-RSA signature +// data - input data +// dlen - input data length +// nDigestType - digest type. Supports only SHA1 (0) +// pSigBuf - buffer to store the signature +// nSigLen - buffer size, must be at least 128 +// will be updated by actual signature length +// keyfile - name of the private key file +// passwd - private key password +// returns error code or ERR_OK for success +//-------------------------------------------------- +EXP_OPTION int signData(const byte* data, int dlen, byte* pSigBuf, int* nSigLen, + int nDigestType, const char *keyfile, const char* passwd) +{ + int err = ERR_OK; + EVP_MD_CTX ctx; + EVP_PKEY* pkey; + + RETURN_IF_NULL_PARAM(data); + RETURN_IF_NULL_PARAM(pSigBuf); + RETURN_IF_NULL_PARAM(nSigLen); + RETURN_IF_NULL_PARAM(keyfile); + RETURN_IF_NULL_PARAM(passwd); + + memset(pSigBuf, 0, *nSigLen); + if(nDigestType == DIGEST_SHA1) { + if(*nSigLen >= SIGNATURE_LEN) { + if((err = ReadPrivateKey(&pkey, keyfile, passwd, FILE_FORMAT_PEM)) == ERR_OK) { + EVP_SignInit(&ctx, EVP_sha1()); + EVP_SignUpdate (&ctx, data, (unsigned long)dlen); + err = EVP_SignFinal(&ctx, pSigBuf, (unsigned int*)nSigLen, pkey); + if(err == ERR_LIB_NONE) + err = ERR_OK; + EVP_PKEY_free(pkey); + } + else + err = ERR_PRIVKEY_READ; + } + else + err = ERR_SIGNATURE_LEN; + } + else + err = ERR_UNSUPPORTED_DIGEST; + + if (err != ERR_OK) SET_LAST_ERROR(err); + return err; +} + +//-------------------------------------------------- +// Calculates files SHA1 digest +// szFileName - file name +// nDigestType - digest type. Supports only SHA1 (0) +// pDigestBuf - buffer to store the digest +// nDigestLen - buffer size, must be at least 20 +// will be updated by actual digest length +// returns error code or ERR_OK for success +//-------------------------------------------------- +EXP_OPTION int calculateDigest(const byte* data, int nDataLen, int nDigestType, + byte* pDigestBuf, int* nDigestLen) +{ + int err = ERR_OK; + + RETURN_IF_NULL_PARAM(data); + RETURN_IF_NULL_PARAM(pDigestBuf); + RETURN_IF_NULL_PARAM(nDigestLen); + memset(pDigestBuf, 0, *nDigestLen); + if(nDigestType == DIGEST_SHA1) { + if(*nDigestLen >= SHA_DIGEST_LENGTH) { + *nDigestLen = SHA_DIGEST_LENGTH; + SHA1(data, nDataLen, pDigestBuf); + } + }//AM 22.04.08 + else if(nDigestType == DIGEST_SHA256) { + if(*nDigestLen >= SHA256_DIGEST_LENGTH) { + *nDigestLen = SHA256_DIGEST_LENGTH; + SHA256(data, nDataLen, pDigestBuf); + } + else + err = ERR_DIGEST_LEN; + } + else + err = ERR_UNSUPPORTED_DIGEST; + if (err != ERR_OK) SET_LAST_ERROR(err); + return err; +} + + + + +//==========< signed doc fucntions >================ + + + +//============================================================ +// Get the filename part of full file name +//============================================================ +EXP_OPTION const char* getSimpleFileName(const char* szFileName) +{ + const char *p; + + RETURN_OBJ_IF_NULL(szFileName, NULL); + + for(p = szFileName + strlen(szFileName) -1; + (p > szFileName) && (*p != '\\') && (*p != '/'); + p--); + if((*p == '\\') || (*p == '/')) + p++; + return p; +} + +//============================================================ +// Get the absolute filename with path +//============================================================ +EXP_OPTION int getFullFileName(const char* szFileName, char* szDest, int len) +{ + int err = ERR_OK; + memset(szDest, 0, len); + // if this is a filename with path then we are ready + if(strchr(szFileName, '/') || strchr(szFileName, '\\')) { + strncpy(szDest, szFileName, len); + } else { // local filename, must prepend directory + _getcwd(szDest, len); +#ifdef WIN32 + if(strlen(szDest) < (size_t)(len - 2)) + strncat(szDest, "\\", sizeof(szDest) - strlen(szDest)); +#else + if(strlen(szDest) < (size_t)(len - 2)) + strncat(szDest, "/", sizeof(szDest) - strlen(szDest)); +#endif + if(strlen(szDest) + strlen(szFileName) < (size_t)(len - 2)) + strncat(szDest, szFileName, sizeof(szDest) - strlen(szDest)); + } + return err; +} + + +//============================================================ +// Get the path part of full file name +//============================================================ +EXP_OPTION int getFileNamePath(const char* szFileName, char* szPath, int len) +{ + int nFound = 0, i, err = ERR_OK; + + RETURN_IF_NULL_PARAM(szFileName); + RETURN_IF_NULL_PARAM(szPath); + strncpy(szPath, szFileName, len); + for(i = strlen(szPath); i >= 0; i--) { + if(szPath[i] == '\\') { + szPath[i+1] = 0; + nFound = 1; + break; + } + } + if(!nFound) + szPath[0] = 0; + return err; +} + + +//============================================================ +// Gets a new temporary filename +// buf - filename buffer +//============================================================ +EXP_OPTION int getTempFileName(char* szFileName, int len) +{ + int f = 0; + char* pFileName = 0; + RETURN_IF_NULL_PARAM(szFileName); + memset(szFileName, 0, len); +#ifdef WIN32 + pFileName = _tempnam(0, "ddoc"); +#else + pFileName = tempnam(0, "ddoc"); +#endif + strncpy(szFileName, pFileName, len); + free(pFileName); + return ERR_OK; +} + + +//============================================================ +// Sets the signatures certificate and calculates +// certificate digest & serial number +// pSigInfo - signature info object +// cert - certficate +//============================================================ +EXP_OPTION int setSignatureCert(SignatureInfo* pSigInfo, X509* cert) +{ + int err = ERR_OK; + + RETURN_IF_NULL_PARAM(pSigInfo); + RETURN_IF_NULL_PARAM(cert); + err = ddocSigInfo_addCert(pSigInfo, cert, CERTID_TYPE_SIGNERS_CERTID); + // release old content if it exists + ddocMemBuf_free(&(pSigInfo->mbufOrigContent)); + return ERR_OK; +} + +//============================================================ +// Sets the signatures certificate and calculates +// certificate digest & serial number +// pSigInfo - signature info object +// certFile - certficate file in PEM +//============================================================ +EXP_OPTION int setSignatureCertFile(SignatureInfo* pSigInfo, const char* certFile) +{ + X509 *cert = NULL; + int err = ERR_OK; + + RETURN_IF_NULL_PARAM(pSigInfo); + RETURN_IF_NULL_PARAM(certFile); + err = ReadCertificate(&cert, certFile); + RETURN_IF_NOT(err == ERR_OK, err); + return setSignatureCert(pSigInfo, cert);; +} + + +//-------------------------------------------------- +// Checks if this file exists +// szFileName - file name +// returns 1 if exists +// AA 2004/05/20 debuggeri all viga, kui null pikkus +//-------------------------------------------------- +EXP_OPTION int checkFileExists(const char* szFileName) +{ + FILE* hFile = 0; + int exists = 0; +#ifdef WIN32 + int i = 0, err = ERR_OK; + wchar_t *convFileName = 0; +#endif + if(szFileName && strlen(szFileName) > 0) { +#ifdef WIN32 + err = utf82unicode((const char*)szFileName, (char**)&convFileName, &i); + if((hFile = _wfopen(convFileName, L"r")) != NULL) { +#else + if((hFile = fopen(szFileName, "r")) != NULL) { +#endif + exists = 1; + fclose(hFile); + } + } +#ifdef WIN32 + if(convFileName) free(convFileName); +#endif + return exists; +} + + +//================< certficate info functions> ================================= + +//-------------------------------------------------- +// Returns the user signatures certificate data +// pSignInfo - signature object +// returns cert data. This is actually X509*. Obsolete function +//-------------------------------------------------- +EXP_OPTION X509* getSignCertData(const SignatureInfo* pSignInfo) +{ + RETURN_OBJ_IF_NULL(pSignInfo, 0); + return ddocSigInfo_GetSignersCert(pSignInfo); +} + + +//-------------------------------------------------- +// sends an OCSP_REQUES object to remore server and +// retrieves the OCSP_RESPONSE object +// resp - buffer to store the new responses pointer +// req - request objects pointer +// url - OCSP responder URL +//-------------------------------------------------- +int ddocPullUrl(const char* url, DigiDocMemBuf* pSendData, DigiDocMemBuf* pRecvData, + const char* proxyHost, const char* proxyPort) +{ + BIO* cbio = 0, *sbio = 0; + SSL_CTX *ctx = NULL; + char *host = NULL, *port = NULL, *path = "/", buf[200]; + int err = ERR_OK, use_ssl = -1, rc; + long e; + + //RETURN_IF_NULL_PARAM(pSendData); // may be null if nothing to send? + RETURN_IF_NULL_PARAM(pRecvData); + RETURN_IF_NULL_PARAM(url); + + ddocDebug(4, "ddocPullUrl", "URL: %s, in: %d bytes", url, pSendData->nLen); + //there is an HTTP proxy - connect to that instead of the target host + if (proxyHost != 0 && *proxyHost != '\0') { + host = (char*)proxyHost; + if(proxyPort != 0 && *proxyPort != '\0') + port = (char*)proxyPort; + path = (char*)url; + } else { + if(OCSP_parse_url((char*)url, &host, &port, &path, &use_ssl) == 0) { + ddocDebug(1, "ddocPullUrl", "Failed to parse the URL"); + return ERR_WRONG_URL_OR_PROXY; + } + } + + if((cbio = BIO_new_connect(host)) != 0) { + ddocDebug(4, "ddocPullUrl", "Host: %s port: %s", host, port); + if(port != NULL) { + BIO_set_conn_port(cbio, port); + } + if(use_ssl == 1) { + ctx = SSL_CTX_new(SSLv23_client_method()); + SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); + sbio = BIO_new_ssl(ctx, 1); + cbio = BIO_push(sbio, cbio); + } + if ((rc = BIO_do_connect(cbio)) > 0) { + ddocDebug(4, "ddocPullUrl", "Connected: %d", rc); + if(pSendData && pSendData->nLen && pSendData->pMem) { + rc = BIO_write(cbio, pSendData->pMem, pSendData->nLen); + ddocDebug(4, "ddocPullUrl", "Sent: %d bytes, got: %d", pSendData->nLen, rc); + } + do { + memset(buf, 0, sizeof(buf)); + rc = BIO_read(cbio, buf, sizeof(buf)-1); + ddocDebug(4, "ddocPullUrl", "Received: %d bytes\n", rc); + if(rc > 0) + err = ddocMemAppendData(pRecvData, buf, rc); + } while(rc > 0); + ddocDebug(4, "ddocPullUrl", "Total received: %d bytes\n", pRecvData->nLen); + } else { + //if no connection + e = checkErrors(); + if(ERR_GET_REASON(e) == BIO_R_BAD_HOSTNAME_LOOKUP || + ERR_GET_REASON(e) == OCSP_R_SERVER_WRITE_ERROR) + err = ERR_CONNECTION_FAILURE; + else + err = (host != NULL) ? ERR_WRONG_URL_OR_PROXY : ERR_CONNECTION_FAILURE; + } + BIO_free_all(cbio); + if (use_ssl != -1) { + OPENSSL_free(host); + OPENSSL_free(port); + OPENSSL_free(path); + SSL_CTX_free(ctx); + } + } + else + err = ERR_CONNECTION_FAILURE; + return(err); +} + + + + +// ASN1 structure prefix - RSA-SHA1 signature with 20 bytes follows +char g_sigPrefix[] = { 48, 33, 48, 9, 6, 5, 43, 14, 3, 2, 26, 5, 0, 4, 20 }; + +//-------------------------------------------------- +// Prepares a new signature for signing and calculates +// the final hash value to sign. +// pSigDoc - signed document object +// ppSigInfo - pointer for address of newly allocated signature +// manifest - manifest or role +// city - signers address , city +// state - signers address , state or province +// zip - signers address , postal code +// country - signers address , country name +// id - id for new signature. Optional, use NULL for default +// return returns error code or ERR_OK +//-------------------------------------------------- +EXP_OPTION int ddocPrepareSignature(SignedDoc* pSigDoc, SignatureInfo** ppSigInfo, + const char* manifest, const char* city, + const char* state, const char* zip, + const char* country, X509* pCert, const char* id) +{ + int err = ERR_OK, l1; + DigiDocMemBuf mbuf1, *pMBuf1; + char buf1[50]; + + mbuf1.pMem = 0; + mbuf1.nLen = 0; + ddocDebug(3, "ddocPrepareSignature", "Preparing signature manifest: %s country: %s, state: %s, city: %s, zip: %s, cert: %s, id: %s", + (manifest ? manifest : "NULL"), (country ? country : "NULL"), + (state ? state : "NULL"), (city ? city : "NULL"), (zip ? zip : "NULL"), + (pCert ? "OK" : "ERROR"), (id ? id : "NULL")); + // check mandator fields + RETURN_IF_NULL_PARAM(pSigDoc); + RETURN_IF_NULL_PARAM(ppSigInfo); + RETURN_IF_NULL_PARAM(pCert); + clearErrors(); + // add new signature + err = SignatureInfo_new(ppSigInfo, pSigDoc, id); + RETURN_IF_NOT(err == ERR_OK, err); + // automatically calculate doc-info elements for this signature + addAllDocInfos(pSigDoc, *ppSigInfo); + // add signature production place + if (city || state || zip || country) + err = setSignatureProductionPlace(*ppSigInfo, city, state, zip, country); + // add user roles/manifests + if (manifest) + err = addSignerRole(*ppSigInfo, 0, manifest, -1, 0); + RETURN_IF_NOT(err == ERR_OK, err); + // add signers certificate + err = setSignatureCert(*ppSigInfo, pCert); + RETURN_IF_NOT(err == ERR_OK, err); + // timestamp + createTimestamp(pSigDoc, (char*)buf1, sizeof(buf1)); + setString((char**)&((*ppSigInfo)->szTimeStamp), (const char*)buf1, -1); + // now calculate signed properties digest + err = calculateSignedPropertiesDigest(pSigDoc, *ppSigInfo); + // TODO: replace later + pMBuf1 = ddocDigestValue_GetDigestValue((*ppSigInfo)->pSigPropDigest); + ddocSigInfo_SetSigPropRealDigest(*ppSigInfo, + (const char*)pMBuf1->pMem, pMBuf1->nLen); + // signature type & val + ddocSignatureValue_new(&((*ppSigInfo)->pSigValue), 0, SIGN_RSA_NAME, 0, 0); + // calc signed-info digest + l1 = sizeof(buf1); + err = calculateSignedInfoDigest(pSigDoc, *ppSigInfo, (byte*)buf1, &l1); + err = ddocSigInfo_SetSigInfoRealDigest(*ppSigInfo, buf1, l1); + // debug output - final hash to sign + pMBuf1 = ddocDigestValue_GetDigestValue((*ppSigInfo)->pSigInfoRealDigest); + ddocEncodeBase64(pMBuf1, &mbuf1); + ddocDebug(3, "ddocPrepareSignature", "signing hash %s len: %d b64len: %d", + (char*)mbuf1.pMem, mbuf1.nLen, l1); + ddocMemBuf_free(&mbuf1); + return err; +} + +//-------------------------------------------------- +// Returns the hash to be signed with or without ASN1 +// prefix and with or without base64 encoding +// pSigInfo - signature address +// pBuf - buffer for hash value with or without prefix +// pBufLen - pointer to buffer length +// enc - return 0=unencoded, 1=base64, 2=hex +// bWithAsn1Prefix - return with or without ASN1 prefix 1/0 +// return returns error code or ERR_OK +//-------------------------------------------------- +EXP_OPTION int ddocGetSignedHash(SignatureInfo* pSigInfo, + char* pBuf, int* pBufLen, int enc, int bWithAsn1Prefix) +{ + int err = ERR_OK, l1 = 0; + char buf1[50]; + DigiDocMemBuf *pMBuf; + + RETURN_IF_NULL_PARAM(pSigInfo); + RETURN_IF_NULL_PARAM(pBuf); + //RETURN_IF_NOT(err == ERR_OK, err); + // TODO: check buflen + pMBuf = ddocDigestValue_GetDigestValue(pSigInfo->pSigInfoRealDigest); + RETURN_IF_NULL_PARAM(pMBuf); + memset(buf1, 0, sizeof(buf1)); + if(enc == 2) { // hex mode + if(bWithAsn1Prefix) { + if(sizeof(buf1) > sizeof(g_sigPrefix) + pMBuf->nLen) { + memcpy(buf1, g_sigPrefix, sizeof(g_sigPrefix)); + memcpy(buf1 + sizeof(g_sigPrefix), pMBuf->pMem, pMBuf->nLen); + l1 = pMBuf->nLen + sizeof(g_sigPrefix); + } + else + err = ERR_BUF_LEN; + } + else { + if(sizeof(buf1) > (size_t)pMBuf->nLen) { + memcpy(buf1, pMBuf->pMem, pMBuf->nLen); + l1 = pMBuf->nLen; + } + else + err = ERR_BUF_LEN; + } + bin2hex((const byte*)buf1, l1, (char*)pBuf, pBufLen); + } else if(enc == 1) { // base64 mode + if(bWithAsn1Prefix) { + if(sizeof(buf1) > sizeof(g_sigPrefix) + (size_t)pMBuf->nLen) { + memcpy(buf1, g_sigPrefix, sizeof(g_sigPrefix)); + memcpy(buf1 + sizeof(g_sigPrefix), pMBuf->pMem, pMBuf->nLen); + l1 = pMBuf->nLen + sizeof(g_sigPrefix); + } + else + err = ERR_BUF_LEN; + } + else { + if(sizeof(buf1) > (size_t)pMBuf->nLen) { + memcpy(buf1, pMBuf->pMem, pMBuf->nLen); + l1 = pMBuf->nLen; + } + else + err = ERR_BUF_LEN; + } + encode((const byte*)buf1, l1, (byte*)pBuf, pBufLen); + } else { + if(bWithAsn1Prefix) { + if(*pBufLen > (int)sizeof(g_sigPrefix) + pMBuf->nLen) { + memcpy(pBuf, g_sigPrefix, sizeof(g_sigPrefix)); + memcpy(pBuf + sizeof(g_sigPrefix), pMBuf->pMem, pMBuf->nLen); + *pBufLen = pMBuf->nLen + sizeof(g_sigPrefix); + } + else + err = ERR_BUF_LEN; + } + else { + if(*pBufLen > pMBuf->nLen) { + *pBufLen = pMBuf->nLen; + memcpy(pBuf, pMBuf->pMem, pMBuf->nLen); + } + else + err = ERR_BUF_LEN; + } + } + return err; +} + +//================< deprecated functions> ================================= + +#ifdef WITH_DEPRECATED_FUNCTIONS + +// get signers id-code +EXP_OPTION int getSignerCode(const SignatureInfo* pSigInfo, char* buf) +{ + int err, l1; + X509* cert; + char buf1[500], *p; + + RETURN_IF_NULL_PARAM(pSigInfo); + RETURN_IF_NULL_PARAM(buf); + cert = getSignCertData(pSigInfo); + if (!cert) SET_LAST_ERROR_RETURN_CODE(ERR_CERT_INVALID); + l1 = sizeof(buf1); + err = getCertSubjectName(cert, buf1, &l1); + if (err != ERR_OK) SET_LAST_ERROR_RETURN_CODE(err); + err = ERR_CERT_READ; + p = strstr(buf1, "CN="); + if (p) { + p = strchr(p, ','); + if(p) { + p = strchr(p+1, ','); + if(p) { + strncpy(buf, p+1, 11); + buf[11] = 0; + err = ERR_OK; + } + } else { // no comma -> no id-code ! + buf[0] = 0; + // is this really an error ? + err = ERR_WRONG_CERT; + } + } + if (err != ERR_OK) SET_LAST_ERROR(err); + return err; +} + +// get signers first name +EXP_OPTION int getSignerFirstName(const SignatureInfo* pSigInfo, char* buf) +{ + int err = ERR_OK, l1; + X509* cert; + char buf1[500], *p, *p2, *p1; + + RETURN_IF_NULL_PARAM(pSigInfo); + RETURN_IF_NULL_PARAM(buf); + cert = getSignCertData(pSigInfo); + if (!cert) SET_LAST_ERROR_RETURN_CODE(ERR_CERT_INVALID); + l1 = sizeof(buf1); + err = getCertSubjectName(cert, buf1, &l1); + if (err != ERR_OK) SET_LAST_ERROR_RETURN_CODE(err); + p = strstr(buf1, "CN="); + if (p) { + p1 = strchr(p, ','); + if(!p1) + p1 = strchr(p, '/'); + if (p1) { + p1 += 1; + p2 = strchr(p1, ','); + if(!p2) + p2 = strchr(p1, '/'); + if(p2) { + strncpy(buf, p1, p2-p1); + buf[p2-p1] = 0; + err = ERR_OK; + } + } + } + if (err != ERR_OK) SET_LAST_ERROR(err); + return err; +} + +// get signers last name +EXP_OPTION int getSignerLastName(const SignatureInfo* pSigInfo, char* buf) +{ + int err = ERR_OK, l1; + X509* cert; + char buf1[500], *p, *p2; + + RETURN_IF_NULL_PARAM(pSigInfo); + RETURN_IF_NULL_PARAM(buf); + cert = getSignCertData(pSigInfo); + if (!cert) SET_LAST_ERROR_RETURN_CODE(ERR_CERT_INVALID); + l1 = sizeof(buf1); + err = getCertSubjectName(cert, buf1, &l1); + if (err != ERR_OK) SET_LAST_ERROR_RETURN_CODE(err); + p = strstr(buf1, "CN="); + if(p) { + p += 3; + p2 = strchr(p, ','); + if(!p2) + p2 = strchr(p, '/'); + if(p2) { + strncpy(buf, p, p2-p); + buf[p2-p] = 0; + err = ERR_OK; + } else { + strncpy(buf, p, strlen(p)); + } + } + if (err != ERR_OK) SET_LAST_ERROR(err); + return err; +} + +EXP_OPTION int getSignerCN(const SignatureInfo* pSigInfo, char* buf, int bUTF8) +{ + int err = ERR_OK, l1; + X509* cert; + char buf1[500], *p, *p2, buf2[500]; + + RETURN_IF_NULL_PARAM(pSigInfo); + RETURN_IF_NULL_PARAM(buf); + cert = getSignCertData(pSigInfo); + if (!cert) SET_LAST_ERROR_RETURN_CODE(ERR_CERT_INVALID); + l1 = sizeof(buf1); + err = getCertSubjectName(cert, buf1, &l1); + if (err != ERR_OK) SET_LAST_ERROR_RETURN_CODE(err); + if(!bUTF8) { + l1 = sizeof(buf2); + utf82ascii(buf1, buf2, &l1); + strncpy(buf1, buf2, sizeof(buf1)); + } + err = ERR_CERT_READ; + p = strstr(buf1, "CN="); + if (p) { + p += 3; + p2 = strchr(p, '/'); + if(!p2) + p2 = p + strlen(p); + if (p2) { + strncpy(buf, p, p2-p); + buf[p2-p] = 0; + err = ERR_OK; + } + } + + if (err != ERR_OK) SET_LAST_ERROR(err); + return err; +} + +#endif // WITH_DEPRECATED_FUNCTIONS + + |