//================================================== // FILE: DigiDocCfonfig.c // PROJECT: Digi Doc // DESCRIPTION: Digi Doc functions for configuration management // 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 >============================= // 17.06.2004 Fixed buffer overflow vulnerability in setPrivateConfigFile() // 27.03.2004 Fixed ConfigItem_lookup_bool() // 20.03.2004 Added functions createOrReplacePrivateConfigItem() // writeConfigFile(), writePrivateConfigFile() // 20.03.2004 changed function notarizeSignature to check for PKCS12 arguments // 10.02.2004 Integrated // 29.01.2004 changed function notarizeSignature // 26.01.2004 Added include // 08.01.2004 Veiko Sinivee // Creation //================================================== // config data comes from there #include //AA 04/01/26 #ifdef WIN32 #include #define snprintf _snprintf #elif defined(__APPLE__) #include #endif #include "libdigidoc/DigiDocConfig.h" #include "libdigidoc/DigiDocPKCS11.h" #include "libdigidoc/DigiDocDebug.h" #include "libdigidoc/DigiDocCert.h" #include "libdigidoc/DigiDocObj.h" #include "libdigidoc/DigiDocOCSP.h" #include "libdigidoc/DigiDocConvert.h" #ifdef WIN32 #include "libdigidoc/DigiDocCsp.h" #endif #include #include #include #include #include #ifndef _MAX_PATH #define _MAX_PATH 200 #endif #ifdef WIN32 #define DIGIDOC_CONF_NAME "digidoc.ini" #define HOME_ENV "USERPROFILE" #define DIGIDOC_CONF_FMT "%s\\%s" char g_szGlobalConfigFile[_MAX_PATH]; #else #define DIGIDOC_CONF_NAME "digidoc.conf" #define HOME_ENV "HOME" #define DIGIDOC_CONF_FMT "%s/.%s" char g_szGlobalConfigFile[_MAX_PATH] = SYSCONFDIR "/" DIGIDOC_CONF_NAME; # ifdef FRAMEWORK char g_frameworkResources[_MAX_PATH]; # endif #endif char g_szPrivateConfigFile[_MAX_PATH]; #define NUM_SEARCH_CAS 10 //==========< private types and functions >==================== // forward deklarations of private helper functions int ConfigItem_new(ConfigItem** pItem, const char* key, const char* value, int type, int status); void ConfigItem_free(ConfigItem* pItem); ConfigItem* ConfigItem_find(const char* key); int CertificateItem_new(CertificateItem** pItem, const char* key, X509* pCert); void CertificateItem_free(CertificateItem* pItem); CertificateItem* CertificateItem_find(const char* key); X509* Cert_find(const char* key); //==========< global variables >==================== // currently I see the need only for one common configuration store // Distinction can be made by item type ConfigurationStore g_configStore = {0, 0, 0, 0}; //==========< win32 specific functions >=================== #ifdef WIN32 //-------------------------------------------------- // Retrieves a Windows registry key value // key - key name // buf - value buffer // len - value buffer length //-------------------------------------------------- void getRegKey(const char* key, LPBYTE buf, DWORD* len) { LONG rc; HKEY hKey; memset(buf, 0, *len); rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(key), 0, KEY_QUERY_VALUE, &hKey ); if(rc == ERROR_SUCCESS) { rc = RegQueryValueEx(hKey, NULL, NULL, NULL, buf, len); RegCloseKey( hKey ); if(rc == ERROR_SUCCESS) { buf[*len] = 0; } else { buf[0] = 0; } } } //-------------------------------------------------- // Retrieves a Windows registry key value. If the key // is not set then uses the default value and sets it // key - key name // buf - value buffer // len - value buffer length // defValue - default value //-------------------------------------------------- void getOrSetRegKey(const char* key, LPBYTE buf, DWORD* len, const char* defValue) { LONG rc; HKEY hKey; memset(buf, 0, *len); rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(key), 0, KEY_QUERY_VALUE, &hKey ); if(rc == ERROR_SUCCESS) { rc = RegQueryValueEx(hKey, TEXT(""), NULL, NULL, buf, len); RegCloseKey( hKey ); if(rc == ERROR_SUCCESS) { buf[*len] = 0; } } else { rc = RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT(key), 0, "", 0, KEY_READ | KEY_WRITE, 0, &hKey, 0); if(rc == ERROR_SUCCESS) { rc = RegSetValueEx(hKey, TEXT(""), 0, REG_SZ, (const BYTE*)defValue, lstrlen(defValue)); RegCloseKey(hKey); } } } //-------------------------------------------------- // Sets a Windows registry key value // key - key name // buf - value buffer // len - value buffer length //-------------------------------------------------- void setRegKey(const char* key, LPBYTE buf, DWORD len) { LONG rc; HKEY hKey; rc = RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT(key), 0, "", 0, KEY_READ | KEY_WRITE, 0, &hKey, 0); if(rc == ERROR_SUCCESS) { rc = RegSetValueEx(hKey, TEXT(""), 0, REG_SZ, buf, len); RegCloseKey(hKey); } } //-------------------------------------------------- // Retrieves the number of subkeys Windows registry // key value. // returns number of subkeys //-------------------------------------------------- int getNumSubKeys(const char* key) { int n = 0; HKEY hKey; DWORD num; if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(key), 0, KEY_QUERY_VALUE, &hKey ) == ERROR_SUCCESS) { if(RegQueryInfoKey(hKey, NULL, NULL, NULL, &num, NULL, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) n = (int)num; RegCloseKey( hKey ); } return n; } //-------------------------------------------------- // Deletes a subkey from Windows registry // key - parent key // subkey - subkey to be deleted //-------------------------------------------------- void deleteSubKey(const char* key, const char* subkey) { HKEY hKey; if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(key), 0, KEY_QUERY_VALUE, &hKey ) == ERROR_SUCCESS) { RegDeleteKey(hKey, subkey); RegCloseKey(hKey); } } char* g_regDigiDocRoot = "SOFTWARE\\DigiDocLib"; //-------------------------------------------------- // Retrieves the digidoc librarys config items from registry // returns error coder or ERR_OK //-------------------------------------------------- EXP_OPTION int readConfigFromRegistry() { HKEY hKey; DWORD rc, l, i; int err = 0; char keyName[255], fullName[500]; char keyValue[3000]; FILETIME ft; if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(g_regDigiDocRoot), 0, KEY_READ, &hKey ) != ERROR_SUCCESS ) return ERR_CONF_FILE; i = 0; do { l = sizeof(keyName); *keyName = 0; rc = RegEnumKeyEx(hKey, i, keyName, &l, NULL, NULL, NULL, &ft); if ( (rc == ERROR_SUCCESS) && *keyName ) { l = sizeof(keyValue); *keyValue = 0; snprintf(fullName, sizeof(fullName), "%s\\%s", g_regDigiDocRoot, keyName); getRegKey(fullName, (BYTE*)keyValue, &l); if (*keyValue) { ddocDebug(3, "readConfigFromRegistry", "Reg key: %s val: %s", (const char*)keyName, (const char*)keyValue); err = addConfigItem(NULL, (const char*)keyName, (const char*)keyValue, ITEM_TYPE_PRIVATE, ITEM_STATUS_OK); } SET_LAST_ERROR_IF_NOT(err == ERR_OK, err); } i++; } while ( (rc == ERROR_SUCCESS) && *keyName ); RegCloseKey(hKey); return err; } #endif // WIN32 //==========< item handling functions >==================== //-------------------------------------------------- // Returns true (not 0) if config store structure has been inited //-------------------------------------------------- EXP_OPTION int isConfigInited() { return g_configStore.pItems && g_configStore.nItems; } //-------------------------------------------------- // Initializes configuration store // szConfigFile - name of config file. Use NULL for default //-------------------------------------------------- EXP_OPTION int initConfigStore(const char* szConfigFile) { int err = ERR_OK, at_least_one_conf = 0; //g_configStore.nItems = 0; //g_configStore.pItems = 0; if (szConfigFile && checkFileExists(szConfigFile)) { err = readConfigFile(szConfigFile, ITEM_TYPE_GLOBAL); //printf("config file: %s rc: %d", szConfigFile, err); return err; } #ifdef WIN32 snprintf(g_szGlobalConfigFile, sizeof(g_szGlobalConfigFile), "%s\\%s", getenv("SystemRoot"), DIGIDOC_CONF_NAME); /*if(!*g_szGlobalConfigFile && getenv("SystemRoot")) { strncpy(g_szGlobalConfigFile, getenv("SystemRoot"), sizeof(g_szGlobalConfigFile)); printf("Init win32 2: %s\n", g_szGlobalConfigFile); if(!g_szGlobalConfigFile[strlen(g_szGlobalConfigFile)-1] == '\\') strncat(g_szGlobalConfigFile, "\\", sizeof(g_szGlobalConfigFile) - strlen(g_szGlobalConfigFile)); printf("Init win32 3: %s\n", g_szGlobalConfigFile); strncat(g_szGlobalConfigFile, DIGIDOC_CONF_NAME, sizeof(g_szGlobalConfigFile) - strlen(g_szGlobalConfigFile)); }*/ #endif #ifdef FRAMEWORK CFStringRef identifier = CFStringCreateWithCString(0, "ee.ria.libdigidoc", kCFStringEncodingUTF8); CFBundleRef bundle = CFBundleGetBundleWithIdentifier(identifier); if(bundle) { CFURLRef url = CFBundleCopyResourcesDirectoryURL(bundle); if(url) { if(CFURLGetFileSystemRepresentation(url, TRUE, (UInt8 *)g_frameworkResources, _MAX_PATH)) snprintf(g_szGlobalConfigFile, _MAX_PATH, "%s/%s", g_frameworkResources, DIGIDOC_CONF_NAME); CFRelease(url); } CFRelease(bundle); } CFRelease(identifier); #endif //printf( "Reading global config file: %s\n", g_szGlobalConfigFile); ddocDebug(3, "initConfigStore", "Reading global config file: %s", g_szGlobalConfigFile); if(checkFileExists(g_szGlobalConfigFile)) err = readConfigFile(g_szGlobalConfigFile, ITEM_TYPE_GLOBAL); // MEMLEAK: ??? if(err == ERR_CONF_FILE) err = ERR_OK; else at_least_one_conf = 1; if(err) return err; setPrivateConfigFile(NULL); // set default private conf file if(g_szPrivateConfigFile[0]) { //printf( "Reading private config file: %s\n", g_szPrivateConfigFile); ddocDebug(3, "initConfigStore", "Reading private config file: %s", (g_szPrivateConfigFile ? g_szPrivateConfigFile : "NULL")); if(checkFileExists(g_szPrivateConfigFile)) err = readConfigFile(g_szPrivateConfigFile, ITEM_TYPE_PRIVATE); if(err == ERR_CONF_FILE) err = ERR_OK; else at_least_one_conf = 1; if(err) return err; } if(DIGIDOC_CONF_NAME) { //printf( "Reading config file: %s\n", DIGIDOC_CONF_NAME); ddocDebug(2, "initConfigStore", "Reading config file: %s", (DIGIDOC_CONF_NAME ? DIGIDOC_CONF_NAME: "NULL")); if(checkFileExists(DIGIDOC_CONF_NAME)) err = readConfigFile(DIGIDOC_CONF_NAME, ITEM_TYPE_PRIVATE); if(err == ERR_CONF_FILE) err = ERR_OK; else at_least_one_conf = 1; if(err) return err; } #ifdef WIN32 err = readConfigFromRegistry(); if(err == ERR_CONF_FILE) err = ERR_OK; else at_least_one_conf = 1; if(err) return err; #endif // init certs err = initCertificateItems(); if(!at_least_one_conf) err = ERR_CONF_FILE; return err; } //-------------------------------------------------- // Cleans memory of configuration store // pConfStore - configuration collection (use NULL for default) //-------------------------------------------------- EXP_OPTION void cleanupConfigStore(ConfigurationStore *pConfStore) { int i; if(!pConfStore) pConfStore = &g_configStore; for(i = 0; (i < pConfStore->nItems) && pConfStore->pItems && pConfStore->pItems[i]; i++) ConfigItem_free(pConfStore->pItems[i]); free(pConfStore->pItems); pConfStore->pItems = 0; pConfStore->nItems = 0; for(i = 0; (i < pConfStore->nCerts) && pConfStore->pCerts && pConfStore->pCerts[i]; i++) CertificateItem_free(pConfStore->pCerts[i]); free(pConfStore->pCerts); pConfStore->pCerts = 0; pConfStore->nCerts = 0; } //-------------------------------------------------- // Creates a new configration item // pItem - address of new pointer location // key - items key // value - items value // type - item type // status - item status // returns ERR_OK on success //-------------------------------------------------- int ConfigItem_new(ConfigItem** pItem, const char* key, const char* value, int type, int status) { RETURN_IF_NULL_PARAM(key); RETURN_IF_NULL_PARAM(value); RETURN_IF_NULL_PARAM(pItem); if((*pItem = (ConfigItem*)malloc(sizeof(ConfigItem))) != NULL) { (*pItem)->szKey = strdup(key); (*pItem)->szValue = strdup(value); (*pItem)->nType = type; (*pItem)->nStatus = status; if(!(*pItem)->szKey || !(*pItem)->szValue) { ConfigItem_free(*pItem); *pItem = NULL; SET_LAST_ERROR_RETURN_CODE(ERR_BAD_ALLOC); } } else SET_LAST_ERROR_RETURN_CODE(ERR_BAD_ALLOC); return ERR_OK; } //-------------------------------------------------- // Cleanup of config items memory // pItem - address of config item //-------------------------------------------------- void ConfigItem_free(ConfigItem* pItem) { if(pItem) { if(pItem->szKey) free(pItem->szKey); if(pItem->szValue) free(pItem->szValue); free(pItem); } } //-------------------------------------------------- // Adds a new configration item // pConfStore - configuration collection (use NULL for default) // key - items key // value - items value // type - item type // status - item status // returns ERR_OK on success //-------------------------------------------------- EXP_OPTION int addConfigItem(ConfigurationStore *pConfStore, const char* key, const char* value, int type, int status) { int err = ERR_OK; ConfigItem* pItem; ConfigItem** pItems; if(!pConfStore) pConfStore = &g_configStore; if((err = ConfigItem_new(&pItem, key, value, type, status)) == ERR_OK) { if((pItems = (ConfigItem**)realloc(pConfStore->pItems, sizeof(void*) * (pConfStore->nItems + 1))) != NULL) { pItems[pConfStore->nItems] = pItem; pConfStore->nItems++; pConfStore->pItems = pItems; } else SET_LAST_ERROR_RETURN_CODE(ERR_BAD_ALLOC); } else SET_LAST_ERROR_RETURN_CODE(err); return ERR_OK; } //-------------------------------------------------- // Creates a new cert item // pItem - address of new pointer location // key - items key // pCert - certificate // returns ERR_OK on success //-------------------------------------------------- int CertificateItem_new(CertificateItem** pItem, const char* key, X509* pCert) { RETURN_IF_NULL_PARAM(key); RETURN_IF_NULL_PARAM(pCert); RETURN_IF_NULL_PARAM(pItem); if((*pItem = (CertificateItem*)malloc(sizeof(CertificateItem))) != NULL) { (*pItem)->szKey = strdup(key); (*pItem)->pCert = pCert; // take ownership ! } else SET_LAST_ERROR_RETURN_CODE(ERR_BAD_ALLOC); return ERR_OK; } //-------------------------------------------------- // Cleanup of cert items memory // pItem - address of cert item //-------------------------------------------------- void CertificateItem_free(CertificateItem* pItem) { if(pItem) { if(pItem->szKey) free(pItem->szKey); if(pItem->pCert) X509_free(pItem->pCert); free(pItem); } } //-------------------------------------------------- // Adds a new cert item // pConfStore - configuration collection (use NULL for default) // key - items key // pCert - certificate // returns ERR_OK on success //-------------------------------------------------- EXP_OPTION int addCertificateItem(ConfigurationStore *pConfStore, const char* key, X509* pCert) { int err = ERR_OK; CertificateItem* pItem; CertificateItem** pItems; if(!pConfStore) pConfStore = &g_configStore; if((err = CertificateItem_new(&pItem, key, pCert)) == ERR_OK) { if((pItems = (CertificateItem**)realloc(pConfStore->pCerts, sizeof(void*) * (pConfStore->nCerts + 1))) != NULL) { pItems[pConfStore->nCerts] = pItem; pConfStore->nCerts++; pConfStore->pCerts = pItems; } else SET_LAST_ERROR_RETURN_CODE(ERR_BAD_ALLOC); } else SET_LAST_ERROR_RETURN_CODE(err); return ERR_OK; } //-------------------------------------------------- // Finds a new cert item by key // key - items key // returns item pointer or NULL if not found //-------------------------------------------------- CertificateItem* CertificateItem_find(const char* key) { int i; for(i = 0; (i < g_configStore.nCerts) && g_configStore.pCerts && g_configStore.pCerts[i]; i++) { if(g_configStore.pCerts[i]->szKey && !strcmp(g_configStore.pCerts[i]->szKey, key)) return g_configStore.pCerts[i]; } return NULL; } //-------------------------------------------------- // Finds a cert by key // key - items key // returns X509 pointer or NULL if not found. Must be X509_free()-d because it will be duplicated here //-------------------------------------------------- X509* Cert_find(const char* key) { int i; X509* pCert = 0; for(i = 0; (i < g_configStore.nCerts) && g_configStore.pCerts && g_configStore.pCerts[i] && !pCert; i++) { if(g_configStore.pCerts[i]->szKey && !strcmp(g_configStore.pCerts[i]->szKey, key)) pCert = g_configStore.pCerts[i]->pCert; } ddocDebug(3, "Cert_find", "%s cache %s", key, (pCert ? "OK" : "NULL")); return X509_dup(pCert); } //-------------------------------------------------- // Adds a new private configration item or modifies // an existing one // pConfStore - configuration collection (use NULL for default) // key - items key // value - items value // returns ERR_OK on success //-------------------------------------------------- EXP_OPTION int createOrReplacePrivateConfigItem(ConfigurationStore *pConfStore, const char* key, const char* value) { int err = ERR_OK, i; ConfigItem* pItem = NULL; #ifdef WIN32 char keyName[500]; #endif ddocDebug(3, "createOrReplacePrivateConfigItem", "%s = %s", (key ? key : "NULL"), (value ? value : "NULL")); if(!pConfStore) pConfStore = &g_configStore; // first try to find a private config item for(i = 0; (i < pConfStore->nItems) && pConfStore->pItems && pConfStore->pItems[i]; i++) { if(pConfStore->pItems[i]->szKey && !strcmp(pConfStore->pItems[i]->szKey, key) && pConfStore->pItems[i]->nType == ITEM_TYPE_PRIVATE) { pItem = pConfStore->pItems[i]; break; } } if(pItem) { // if found then modify it if(pItem->szValue) free(pItem->szValue); pItem->szValue = (char*)malloc(strlen(value)+1); if(pItem->szValue) strncpy(pItem->szValue, value, strlen(value)+1); else SET_LAST_ERROR_RETURN_CODE(ERR_BAD_ALLOC); pItem->nStatus = ITEM_STATUS_MODIFIED; } else { // else create a new private config item err = addConfigItem(pConfStore, key, value, ITEM_TYPE_PRIVATE, ITEM_STATUS_MODIFIED); } #ifdef WIN32 snprintf(keyName, sizeof(keyName), "%s\\%s", g_regDigiDocRoot, key); setRegKey(keyName, (BYTE*)value, (value ? (DWORD)strlen(value) : (DWORD)0)); if(pItem) pItem->nStatus = ITEM_STATUS_OK; #endif return err; } //-------------------------------------------------- // Deletes configration item // key - items key // returns ERR_OK on success //-------------------------------------------------- EXP_OPTION int ConfigItem_delete(const char* key) { int err = ERR_OK, i, j; // first try to find a private config item for(i = j = 0; (i < g_configStore.nItems) && g_configStore.pItems && g_configStore.pItems[i]; i++) { if(g_configStore.pItems[i]->szKey && !strcmp(g_configStore.pItems[i]->szKey, key) && g_configStore.pItems[i]->nType == ITEM_TYPE_PRIVATE) { ConfigItem_free(g_configStore.pItems[i]); g_configStore.pItems[i] = 0; continue; } g_configStore.pItems[j] = g_configStore.pItems[i]; // no-op until moving the last items forward j++; } g_configStore.nItems = j; #ifdef WIN32 deleteSubKey(g_regDigiDocRoot, key); #endif return err; } //-------------------------------------------------- // Finds a new configration item by key // key - items key // returns item pointer or NULL if not found //-------------------------------------------------- ConfigItem* ConfigItem_find(const char* key) { int i; for(i = 0; (i < g_configStore.nItems) && g_configStore.pItems && g_configStore.pItems[i]; i++) { if(g_configStore.pItems[i]->szKey && !strcmp(g_configStore.pItems[i]->szKey, key)) return g_configStore.pItems[i]; } return NULL; } //-------------------------------------------------- // Finds a all configration items that start with this prefix // prefix - item keys prefix // returns error code or ERR_OK //-------------------------------------------------- int ConfigItem_findByPrefix(ConfigurationStore *pConfStore, const char* prefix) { int i, err = ERR_OK; for(i = 0; (i < g_configStore.nItems) && g_configStore.pItems && g_configStore.pItems[i]; i++) { if(g_configStore.pItems[i]->szKey && !strncmp(g_configStore.pItems[i]->szKey, prefix, strlen(prefix))) err = addConfigItem(pConfStore, g_configStore.pItems[i]->szKey, g_configStore.pItems[i]->szValue, g_configStore.pItems[i]->nType, g_configStore.pItems[i]->nStatus); } return err; } //-------------------------------------------------- // Finds a new configration items value by key // key - items key // returns value of config item or NULL if not found //-------------------------------------------------- EXP_OPTION const char* ConfigItem_lookup(const char* key) { #ifdef FRAMEWORK if(strcmp(key, "CA_CERT_PATH") == 0) return g_frameworkResources; #endif int i; // first try to find a private item for(i = 0; (i < g_configStore.nItems) && g_configStore.pItems && g_configStore.pItems[i]; i++) { if(g_configStore.pItems[i]->szKey && !strcmp(g_configStore.pItems[i]->szKey, key) && g_configStore.pItems[i]->nType == ITEM_TYPE_PRIVATE) return g_configStore.pItems[i]->szValue; } // if not found use any type of item with the given key for(i = 0; (i < g_configStore.nItems) && g_configStore.pItems && g_configStore.pItems[i]; i++) { if(g_configStore.pItems[i]->szKey && !strcmp(g_configStore.pItems[i]->szKey, key)) return g_configStore.pItems[i]->szValue; } return NULL; } //-------------------------------------------------- // Finds a new configration items value by key from the store // key - items key // pConfStore - store to search in // returns value of config item or NULL if not found //-------------------------------------------------- EXP_OPTION const char* ConfigItem_lookup_fromStore(ConfigurationStore *pConfStore, const char* key) { int i; for(i = 0; pConfStore && (i < pConfStore->nItems) && pConfStore->pItems && pConfStore->pItems[i]; i++) { if(pConfStore->pItems[i]->szKey && !strcmp(pConfStore->pItems[i]->szKey, key)) return pConfStore->pItems[i]->szValue; } return NULL; } //-------------------------------------------------- // Finds a numeric configration items value by key // key - items key // defValue - default value to be returned // returns value of config item or defValue if not found //-------------------------------------------------- EXP_OPTION int ConfigItem_lookup_int(const char* key, int defValue) { int rc = defValue; const char* p = ConfigItem_lookup(key); if (p) rc = atoi(p); return rc; } //-------------------------------------------------- // Finds a new configration items value by key // key - items key // returns value of config item or NULL if not found //-------------------------------------------------- EXP_OPTION const char* ConfigItem_lookup_str(const char* key, const char* defValue) { const char* p = ConfigItem_lookup(key); if (p) return p; else return defValue; } //-------------------------------------------------- // Finds a bolean configration items value by key // key - items key // defValue - default value to be returned // returns value of config item or defValue if not found //-------------------------------------------------- EXP_OPTION int ConfigItem_lookup_bool(const char* key, int defValue) { int rc = defValue; const char* p = ConfigItem_lookup(key); if(p) #ifdef WIN32 rc = (!stricmp(p, "true")) ? 1 : 0; #else rc = (!strcasecmp(p, "TRUE")) ? 1 : 0; #endif return rc; } //-------------------------------------------------- // Reads and parses configuration file // fileName - configuration file name // type - type of config file global/private // return error code or 0 for success //-------------------------------------------------- EXP_OPTION int readConfigFile(const char* fileName, int type) { FILE* hFile; char buf[5000]; char *p; int err = ERR_OK; if((hFile = fopen(fileName, "rt")) != NULL) { ddocDebug(2, "readConfigFile", "Reading config file: %s", fileName); while(fgets(buf, sizeof(buf), hFile) != NULL && !err) { // trim line separators and spaces while(strlen(buf) && (buf[strlen(buf)-1] == '\n' || buf[strlen(buf)-1] == '\r' || buf[strlen(buf)-1] == '\t' || buf[strlen(buf)-1] == ' ')) buf[strlen(buf)-1] = 0; if(strlen(buf) && buf[0] != '#') { if((p = strchr(buf, '=')) != NULL) { *p = 0; p++; err = addConfigItem(NULL, (const char*)buf, (const char*)p, type, ITEM_STATUS_OK); SET_LAST_ERROR_IF_NOT(err == ERR_OK, err); //printf("CONF: %s = %s\n", buf, p); } } } fclose(hFile); return err; } else { ddocDebug(1, "readConfigFile", "Error opening config file: %s", fileName); SET_LAST_ERROR_RETURN_CODE(ERR_CONF_FILE); // MEMLEAK: ??? } } //-------------------------------------------------- // Writes a configuration file // fileName - configuration file name // type - type of config file global/private // return error code or 0 for success //-------------------------------------------------- EXP_OPTION int writeConfigFile(const char* fileName, int type) { FILE* hFile; //char buf[300]; //char *p; int err = ERR_OK, i; if((hFile = fopen(fileName, "wt")) != NULL) { // first try to find a private item for(i = 0; (i < g_configStore.nItems) && g_configStore.pItems && g_configStore.pItems[i]; i++) { if(g_configStore.pItems[i]->nType == type) { fprintf(hFile, "%s=%s\n", g_configStore.pItems[i]->szKey, g_configStore.pItems[i]->szValue); g_configStore.pItems[i]->nStatus = ITEM_STATUS_OK; } } fclose(hFile); return err; } else SET_LAST_ERROR_RETURN_CODE(ERR_CONF_FILE); } //-------------------------------------------------- // Saves all private config items in correct file // return error code or 0 for success //-------------------------------------------------- EXP_OPTION int writePrivateConfigFile() { #ifndef WIN32 return writeConfigFile(g_szPrivateConfigFile, ITEM_TYPE_PRIVATE); #else return ERR_OK; #endif } //-------------------------------------------------- // Sets a new name for private config file. Can be // used to override default of env(HOME)/.digidoc.conf // Use NULL to restore default value //-------------------------------------------------- EXP_OPTION void setPrivateConfigFile(const char* fileName) { if (fileName) { strncpy( g_szPrivateConfigFile, fileName, sizeof(g_szPrivateConfigFile) ); } else { // use default snprintf(g_szPrivateConfigFile, sizeof(g_szPrivateConfigFile)-1, DIGIDOC_CONF_FMT, getenv(HOME_ENV), DIGIDOC_CONF_NAME); } } //-------------------------------------------------- // Finds CA certificates index by it's CN // idx - address if index // cn - CN of the CA // return -1 if not found or 0 for success //-------------------------------------------------- int findCAindexByCN(int* idx, const char* cn) { int i, n; char buf1[100]; const char* p; *idx = 0; p = ConfigItem_lookup("CA_CERTS"); RETURN_IF_NOT(p != NULL, ERR_CONF_LINE); n = atoi(p); for(i = 1; (i <= n) && !(*idx); i++) { snprintf(buf1, sizeof(buf1), "CA_CERT_%d_CN", i); p = ConfigItem_lookup(buf1); ddocDebug(1, "findCAindexByCN", "ERR112 Unknown CA: %s", buf1); RETURN_IF_NOT(p != NULL, ERR_UNKNOWN_CA); if(!strcmp(p, cn)) { // found it *idx = i; break; } } return ERR_OK; } //-------------------------------------------------- // Finds Responder certificates index by it's CN // idx - address if index // cn - CN of the responder cert // hash - responder certs hash in base64 form // ca - responder CA CN // return error code or 0 for success //-------------------------------------------------- int findResponderIndex(int* idx, const char* cn, const char* hash, const char* ca) { int err = ERR_OK, i, n; char buf1[100]; const char* p; *idx = 0; ddocDebug(3, "findResponderIndex", "Find CA: %s hash: %s ca-cn: %s", (cn ? cn : "NULL"), (hash ? hash : "NULL"), (ca ? ca : "NULL")); p = ConfigItem_lookup("DIGIDOC_OCSP_RESPONDER_CERTS"); RETURN_IF_NOT(p != NULL, ERR_CONF_LINE); n = atoi(p); for(i = 1; (i <= n) && !(*idx); i++) { if(cn) { snprintf(buf1, sizeof(buf1), "DIGIDOC_OCSP_RESPONDER_CERT_%d_CN", i); p = ConfigItem_lookup(buf1); if(p && !strcmp(p, cn)) { // found it *idx = i; break; } } else if(hash) { snprintf(buf1, sizeof(buf1), "DIGIDOC_OCSP_RESPONDER_CERT_%d_HASH", i); p = ConfigItem_lookup(buf1); if(p && !strcmp(p, hash)) { // found it *idx = i; break; } } else if(ca) { snprintf(buf1, sizeof(buf1), "DIGIDOC_OCSP_RESPONDER_CERT_%d_CA", i); p = ConfigItem_lookup(buf1); if(p && !strcmp(p, ca)) { // found it *idx = i; break; } } } return err; } //-------------------------------------------------- // Finds CA certificate by CN // ppCA - address of found CA // szCN - CA certs common name // pHash - authority-key-identifier to search for CA // return error code or 0 for success //-------------------------------------------------- DIGIDOC_DEPRECATED EXP_OPTION int findCAForCN(X509** ppCA, const char* szCN, DigiDocMemBuf *pHash) { return findCAForCNAndSigTime(ppCA, szCN, pHash, 0); } //-------------------------------------------------- // Read ca and ocsp responder certs from files and cache in memory //-------------------------------------------------- int initCertificateItems() { int err = ERR_OK, i, n, e2, j; const char *p1, *p2, *p3; char buf2[300], buf1[50]; X509 *x509 = NULL; // read CA certs p1 = ConfigItem_lookup("CA_CERTS"); RETURN_IF_NOT(p1 != NULL, ERR_CONF_LINE); p2 = ConfigItem_lookup("CA_CERT_PATH"); RETURN_IF_NOT(p2 != NULL, ERR_CONF_LINE); ddocDebug(3, "initCertificateItems", "Init ca certs: %s ca-path: %s", p1, p2); n = atoi(p1); for(i = 1; i <= n; i++) { snprintf(buf1, sizeof(buf1), "CA_CERT_%d_CN", i); p1 = ConfigItem_lookup(buf1); snprintf(buf1, sizeof(buf1), "CA_CERT_%d", i); p3 = ConfigItem_lookup(buf1); if(p1 && p3) { #ifdef WIN32 snprintf(buf2, sizeof(buf2), "%s\\%s", p2, p3); #else snprintf(buf2, sizeof(buf2), "%s/%s", p2, p3); #endif x509 = 0; e2 = ReadCertificateNoErr(&x509, buf2); if(x509) { ddocDebug(3, "initCertificateItems", "CA Cert item: %d CN: %s file: %s", i, p1, p3); addCertificateItem(&g_configStore, p1, x509); // release ownership on x509! } else { ddocDebug(1, "initCertificateItems", "Error: %d reading item: %d CN: %s file: %s", e2, i, p1, p3); } } } // read ocsp responder certs p1 = ConfigItem_lookup("DIGIDOC_OCSP_RESPONDER_CERTS"); RETURN_IF_NOT(p1 != NULL, ERR_CONF_LINE); ddocDebug(3, "initCertificateItems", "Init ocsp certs: %s ca-path: %s", p1, p2); n = atoi(p1); for(i = 1; i <= n; i++) { snprintf(buf1, sizeof(buf1), "DIGIDOC_OCSP_RESPONDER_CERT_%d_CN", i); p1 = ConfigItem_lookup(buf1); snprintf(buf1, sizeof(buf1), "DIGIDOC_OCSP_RESPONDER_CERT_%d", i); p3 = ConfigItem_lookup(buf1); if(p1 && p3) { #ifdef WIN32 snprintf(buf2, sizeof(buf2), "%s\\%s", p2, p3); #else snprintf(buf2, sizeof(buf2), "%s/%s", p2, p3); #endif x509 = 0; e2 = ReadCertificateNoErr(&x509, buf2); if(x509) { ddocDebug(3, "initCertificateItems", "OCSP Cert item: %d CN: %s file: %s", i, p1, p3); addCertificateItem(&g_configStore, buf1, x509); // release ownership on x509! } else { ddocDebug(1, "initCertificateItems", "Error: %d reading item: %d CN: %s file: %s", e2, i, p1, p3); } } for(j = 1; j < 10; j++) { snprintf(buf1, sizeof(buf1), "DIGIDOC_OCSP_RESPONDER_CERT_%d_%d", i, j); p3 = ConfigItem_lookup(buf1); if(p1 && p3) { #ifdef WIN32 snprintf(buf2, sizeof(buf2), "%s\\%s", p2, p3); #else snprintf(buf2, sizeof(buf2), "%s/%s", p2, p3); #endif x509 = 0; e2 = ReadCertificateNoErr(&x509, buf2); if(x509) { ddocDebug(3, "initCertificateItems", "OCSP Cert item: %d CN: %s file: %s", i, p1, p3); addCertificateItem(&g_configStore, buf1, x509); // release ownership on x509! } else { ddocDebug(1, "initCertificateItems", "Error: %d reading item: %d CN: %s file: %s", e2, i, p1, p3); } } } } return err; } //-------------------------------------------------- // Finds CA certificate by CN // ppCA - address of found CA // szCN - CA certs common name // pHash - authority-key-identifier to search for CA // tSigTime - signing time or 0 // return error code or 0 for success //-------------------------------------------------- EXP_OPTION int findCAForCNAndSigTime(X509** ppCA, const char* szCN, DigiDocMemBuf *pHash, time_t tSigTime) { int err = ERR_OK, i, n; char buf2[300], buf1[30], buf3[50]; const char *p1, *p2; X509 *x509 = NULL; DigiDocMemBuf mbuf2, mbuf3, mbuf1; time_t tFrom = 0, tTo = 0; mbuf1.pMem = 0; mbuf1.nLen = 0; mbuf2.pMem = 0; mbuf2.nLen = 0; mbuf3.pMem = 0; mbuf3.nLen = 0; ddocEncodeBase64(pHash, &mbuf3); ddocBin2Hex(pHash, &mbuf2); ddocDebug(3, "findCAForCN", "Find CN: %s subj-hash: %s subj-hash-hex: %s sig-time: %ld", szCN, (char*)mbuf3.pMem, (char*)mbuf2.pMem, (unsigned long)tSigTime); ddocMemBuf_free(&mbuf3); ddocMemBuf_free(&mbuf2); // initialize *ppCA = NULL; p1 = ConfigItem_lookup("CA_CERTS"); RETURN_IF_NOT(p1 != NULL, ERR_CONF_LINE); n = atoi(p1); for(i = 1; (i <= n) && !(*ppCA); i++) { snprintf(buf1, sizeof(buf1), "CA_CERT_%d_CN", i); p1 = ConfigItem_lookup(buf1); x509 = NULL; ddocDebug(3, "findCAForCN", "CA: %s -> %s", buf1, p1); if(p1 && !strcmp(p1, szCN)) { // found CN, try read cert snprintf(buf1, sizeof(buf1), "CA_CERT_%d", i); p1 = ConfigItem_lookup(buf1); if(p1) { p2 = ConfigItem_lookup("CA_CERT_PATH"); RETURN_IF_NOT(p2 != NULL, ERR_CONF_LINE); #ifdef WIN32 snprintf(buf2, sizeof(buf2), "%s\\%s", p2, p1); #else snprintf(buf2, sizeof(buf2), "%s/%s", p2, p1); #endif // check cache first x509 = Cert_find(szCN); if(!x509) err = ReadCertificate(&x509, buf2); ddocDebug(4, "findCAForCN", "Read cert: %s rc: %d\n", buf2, err); if(err == ERR_FILE_READ) err = ERR_UNKNOWN_CA; if(pHash && pHash->pMem && x509) { memset(buf3, 0, sizeof(buf3)); ReadCertSerialNumber(buf3, sizeof(buf3), x509); readSubjectKeyIdentifier(x509, &mbuf2); ddocEncodeBase64(&mbuf2, &mbuf3); ddocBin2Hex(&mbuf2, &mbuf1); tFrom = getCertNotBeforeTimeT(x509); tTo = getCertNotAfterTimeT(x509); if(!ddocMemCompareMemBufs(pHash, &mbuf2) && (!tSigTime || (tSigTime >= tFrom && tSigTime <= tTo))) { *ppCA = x509; err = ERR_OK; ddocDebug(4, "findCAForCN", "Found cert: %s with nr: %s from: %ld to: %ld", szCN, buf3, tFrom, tTo); } else { ddocDebug(4, "findCAForCN", "Release cert: %s with nr: %s", szCN, buf3); X509_free(x509); // release wrong cert *ppCA = NULL; err = ERR_UNKNOWN_CA; } ddocDebug(3, "findCAForCN", "Compare CA: %s subj-hash: %s hex: %s err: %d", buf1, (char*)mbuf3.pMem, (char*)mbuf1.pMem, err); ddocMemBuf_free(&mbuf2); ddocMemBuf_free(&mbuf3); ddocMemBuf_free(&mbuf1); } else { // plain CN match is enough if(x509) { *ppCA = x509; err = ERR_OK; ddocDebug(4, "findCAForCN", "Found cert: %s with cn", szCN); } } } else { ddocDebug(3, "findCAForCN", "No cert file for: %s", buf1); } } } RETURN_IF_NOT(err == ERR_OK, err); //*ppCA = x509; if(*ppCA) { ddocCertGetSubjectDN(*ppCA, &mbuf2); ddocDebug(4, "findCAForCN", "Found cert: %s with cn %s", (char*)mbuf2.pMem, szCN); ddocMemBuf_free(&mbuf2); } return err; } //-------------------------------------------------- // Finds Responders certificate by CN // ppResp - address of found cert // szCN - Responder certs common name // hash - responder certs hash in base64 // nIdx - index of the certificate for this respnder. Starts at 0 // return error code or 0 for success //-------------------------------------------------- EXP_OPTION int findResponderByCNAndHashAndIndex(X509** ppResp, const char* szCN, const char* hash, int nIdx) { int err = ERR_OK, i; char buf[300]; const char *p1, *p2; RETURN_IF_NULL_PARAM(ppResp); // initialize *ppResp = NULL; err = findResponderIndex(&i, szCN, hash, NULL); ddocDebug(3, "findResponderByCNAndHashAndIndex", "CN: %s hash: %s resp-index: %d, cert-index: %d", (szCN ? szCN : "NULL"), (hash ? hash : "NULL"), i, nIdx); RETURN_IF_NOT(err == ERR_OK, err); // check cache first *ppResp = Cert_find(szCN); if(*ppResp) return ERR_OK; // compose search key if(!nIdx) snprintf(buf, sizeof(buf), "DIGIDOC_OCSP_RESPONDER_CERT_%d", i); else snprintf(buf, sizeof(buf), "DIGIDOC_OCSP_RESPONDER_CERT_%d_%d", i, nIdx); p1 = ConfigItem_lookup(buf); ddocDebug(3, "findResponderByCNAndHashAndIndex", "Read cert key: %s file: %s", buf, (p1 ? p1 : "NULL")); if(p1) { if(checkFileExists(p1)) { err = ReadCertificate(ppResp, p1); } else { p2 = ConfigItem_lookup("CA_CERT_PATH"); if(p2) { #ifdef WIN32 snprintf(buf, sizeof(buf), "%s\\%s", p2, p1); #else snprintf(buf, sizeof(buf), "%s/%s", p2, p1); #endif if(checkFileExists(buf)) err = ReadCertificate(ppResp, buf); ddocDebug(3, "findResponderByCNAndHashAndIndex", "Read cert: %s rc: %d got: %s", buf, err, (*ppResp ? "OK" : "NULL")); } } } // if p1 return err; } //-------------------------------------------------- // Finds Responders certificate by CN // ppResp - address of found cert // szCN - Responder certs common name // hash - responder certs hash in base64 form // szCertSerial - specific serial number to search // return error code or 0 for success //-------------------------------------------------- EXP_OPTION int findResponder(X509** ppResp, const char* szCN, const char* szHash, char* szCertSerial) { int err = ERR_OK, i, j; char buf[300], szSerial[100]; const char *p1, *p2; time_t t1, t2; X509 *x509; RETURN_IF_NULL_PARAM(ppResp); // initialize *ppResp = NULL; err = findResponderIndex(&i, szCN, szHash, NULL); ddocDebug(3, "findResponder", "CN: %s hash: %s index: %d, search notary: %s", (szCN ? szCN : "NULL"), (szHash ? szHash : "NULL"), i, (szCertSerial ? szCertSerial : "LATEST")); RETURN_IF_NOT(err == ERR_OK, err); j = 0; t1 = t2 = 0; do { x509 = 0; p1 = p2 = 0; // compose search key if(!j) snprintf(buf, sizeof(buf), "DIGIDOC_OCSP_RESPONDER_CERT_%d", i); else snprintf(buf, sizeof(buf), "DIGIDOC_OCSP_RESPONDER_CERT_%d_%d", i, j); p1 = ConfigItem_lookup(buf); ddocDebug(3, "findResponder", "Read cert key: %s file: %s", buf, (p1 ? p1 : "NULL")); if(p1) { // check cache first x509 = Cert_find(buf); if(!x509) { // if not found in cache if(checkFileExists(p1)) { err = ReadCertificate(&x509, p1); if(x509) t2 = getCertNotAfterTimeT(x509); ddocDebug(3, "findResponder", "Read cert: %s rc: %d not-after: %ld", p1, err, (unsigned long)t2); } else { p2 = ConfigItem_lookup("CA_CERT_PATH"); RETURN_IF_NOT(p2 != NULL, ERR_CONF_LINE); #ifdef WIN32 snprintf(buf, sizeof(buf), "%s\\%s", p2, p1); #else snprintf(buf, sizeof(buf), "%s/%s", p2, p1); #endif err = ReadCertificate(&x509, buf); if(x509) t2 = getCertNotAfterTimeT(x509); ddocDebug(3, "findResponder", "Read cert: %s rc: %d not-after: %ld", buf, err, (unsigned long)t2); } // else } // !x509 if(!err && x509) { // if cert read successfully if(szCertSerial) { // check for specific notary cert serial szSerial[0] = 0; ReadCertSerialNumber(szSerial, sizeof(szSerial), x509); if(!strcmp(szSerial, szCertSerial)) { *ppResp = x509; ddocDebug(4, "findResponder", "assigning CA 1"); return ERR_OK; } } if(!t1 || t2 > t1) { // first cert to check t1 = t2; ddocDebug(4, "findResponder", "assigning CA 2"); *ppResp = x509; } } } // if p1 j++; } while(x509 || j < 10); // until any potential cert found and I have tried to find one of the multiple certs RETURN_IF_NOT(err == ERR_OK, ERR_CERT_READ); ddocDebug(3, "findResponder", "CN: %s hash: %s index: %d, search notary: %s", (szCN ? szCN : "NULL"), (szHash ? szHash : "NULL"), err, (*ppResp ? "OK" : "NULL")); return err; } //-------------------------------------------------- // Finds Responder certificates CA certs CN // caCN - buffer for responders CA CN // len - length of buffer for CA CN // szCN - responder certs common name // hash - responder certs hash in base64 form // return error code or 0 for success //-------------------------------------------------- EXP_OPTION int findResponderCA(char* caCN, int len, const char* szCN, const char* hash) { int err = ERR_OK, i=0; char buf[50]; const char* p; // initialize RETURN_IF_NULL_PARAM(caCN); caCN[0] = 0; ddocDebug(3, "findResponderCA", "CA cn: %s, cn-l: %d", caCN, len); err = findResponderIndex(&i, szCN, hash, NULL); ddocDebug(3, "findResponderCA", "Resp idx: %d", i); RETURN_IF_NOT(err == ERR_OK, err); snprintf(buf, sizeof(buf), "DIGIDOC_OCSP_RESPONDER_CERT_%d_CA", i); p = ConfigItem_lookup(buf); ddocDebug(3, "findResponderCA", "Lookup: %s found: %s len: %d", buf, p, len); RETURN_IF_NOT(p != NULL, ERR_OCSP_RESP_NOT_TRUSTED); strncpy(caCN, p, len); return ERR_OK; } //-------------------------------------------------- // Finds CA certificate of the given certificate // ppCA - address of found CA // pCert - certificate whose CA we are looking for // return error code or 0 for success // deprecated use findCAForCertificateAndSigTime() //-------------------------------------------------- DIGIDOC_DEPRECATED EXP_OPTION int findCAForCertificate(X509** ppCA, const X509* pCert) { return findCAForCertificateAndSigTime(ppCA, pCert, 0); } //-------------------------------------------------- // Finds CA certificate of the given certificate // ppCA - address of found CA // pCert - certificate whose CA we are looking for // tSigTime - signature timestamp // return error code or 0 for success //-------------------------------------------------- EXP_OPTION int findCAForCertificateAndSigTime(X509** ppCA, const X509* pCert, time_t tSigTime) { int err = ERR_OK; DigiDocMemBuf mbuf1, mbuf2; mbuf1.pMem = 0; mbuf1.nLen = 0; mbuf2.pMem = 0; mbuf2.nLen = 0; // read cert issuers CN err = ddocCertGetIssuerCN((X509*)pCert, &mbuf1); RETURN_IF_NOT(err == ERR_OK, ERR_PKCS_CERT_DECODE); RETURN_IF_NOT(mbuf1.pMem, ERR_PKCS_CERT_DECODE); // PR. fix crash err = readAuthorityKeyIdentifier((X509*)pCert, &mbuf2); RETURN_IF_NOT(err == ERR_OK, err); err = findCAForCNAndSigTime(ppCA, (const char*)mbuf1.pMem, &mbuf2, tSigTime); ddocMemBuf_free(&mbuf1); ddocMemBuf_free(&mbuf2); RETURN_IF_NOT(err == ERR_OK, err); return err; } //-------------------------------------------------- // Finds CA chain // ppChain - address of cert pointer array // nMaxChain - index of last cert in returned array - 0 based // szCN - CN of the first CA cert (not the child cert!) // pCert - certificate to search ca-s for // return error code or 0 for success // deprecated use findCAChainForCNAndSigTime() //-------------------------------------------------- DIGIDOC_DEPRECATED EXP_OPTION int findCAChainForCN(X509** ppChain, int* nMaxChain, const char* szCN, X509* pCert) { return findCAChainForCNAndSigTime(ppChain, nMaxChain, szCN, pCert, 0); } //-------------------------------------------------- // Finds CA chain // ppChain - address of cert pointer array // nMaxChain - index of last cert in returned array - 0 based // szCN - CN of the first CA cert (not the child cert!) // pCert - certificate to search ca-s for // tSigTime - signature timestamp // return error code or 0 for success //-------------------------------------------------- EXP_OPTION int findCAChainForCNAndSigTime(X509** ppChain, int* nMaxChain, const char* szCN, X509* pCert, time_t tSigTime) { int err = ERR_OK, i; char oldcn[300], buf3[100]; X509 * caCerts[NUM_SEARCH_CAS]; DigiDocMemBuf mbuf1, mbuf2, mbuf3; mbuf1.pMem = 0; mbuf1.nLen = 0; mbuf2.pMem = 0; mbuf2.nLen = 0; mbuf3.pMem = 0; mbuf3.nLen = 0; RETURN_IF_NULL_PARAM(ppChain); RETURN_IF_NULL_PARAM(nMaxChain); RETURN_IF_NULL_PARAM(szCN); // initialize for(i = 0; i < NUM_SEARCH_CAS; i++) caCerts[i] = 0; for(i = 0; i < NUM_SEARCH_CAS; i++) ppChain[i] = NULL; i = 0; memset(oldcn, 0, sizeof(oldcn)); strncpy(oldcn, szCN, sizeof(oldcn)); *nMaxChain = -1; if(pCert != NULL) { err = readAuthorityKeyIdentifier(pCert, &mbuf2); ddocEncodeBase64(&mbuf2, &mbuf3); memset(buf3, 0, sizeof(buf3)); ReadCertSerialNumber(buf3, sizeof(buf3), pCert); ddocDebug(3, "findCAChainForCN", "Subj cert nr: %s, auth-key: %s", buf3, (char*)mbuf3.pMem); ddocMemBuf_free(&mbuf3); } do { if(caCerts[i]) { // for first ca it is null err = readAuthorityKeyIdentifier(caCerts[i], &mbuf2); ddocEncodeBase64(&mbuf2, &mbuf3); ddocDebug(3, "findCAChainForCN", "CA cert: %d, auth-key: %s", i, (char*)mbuf3.pMem); ddocMemBuf_free(&mbuf3); if(err) return err; } err = findCAForCNAndSigTime(&caCerts[i], oldcn, &mbuf2, tSigTime); ddocMemBuf_free(&mbuf2); ddocDebug(3, "findCAChainForCN", "Read CA for CN: %s idx: %d rc: %d", oldcn, i, err); SET_LAST_ERROR_IF_NOT(err == ERR_OK, err); if (caCerts[i] && !err) { err = ddocCertGetIssuerCN(caCerts[i], &mbuf1); ddocDebug(3, "findCAChainForCN", "Issuer: %s old was: %s, rc: %d", (const char*)mbuf1.pMem, oldcn, err); SET_LAST_ERROR_IF_NOT(err == ERR_OK, err); } if(caCerts[i] && !err && mbuf1.pMem && !strcmp((const char*)mbuf1.pMem, oldcn) && i == 0) { ppChain[0] = caCerts[0]; *nMaxChain = 0; return err; } else if(!err && mbuf1.pMem && strcmp((const char*)mbuf1.pMem, oldcn)) { i++; if(!err) strncpy(oldcn, (const char*)mbuf1.pMem, sizeof(oldcn) ); ddocMemBuf_free(&mbuf1); } else { ddocMemBuf_free(&mbuf1); break; } } while (err == ERR_OK); *nMaxChain = i; ddocDebug(3, "findCAChainForCN", "Found: %d certs", (*nMaxChain) + 1); // now reverse the chain such that the root CA is at the top - is it necessary??? // PR fix index for(i = 0; i <= *nMaxChain; i++) ppChain[i] = caCerts[(*nMaxChain) - i]; return err; } //------------------------------------------ // Get a notary confirmation for signature // pSigDoc - signed document pointer // pSigInfo - signature to notarize // returns error code //------------------------------------------ EXP_OPTION int notarizeSignature(SignedDoc* pSigDoc, SignatureInfo* pSigInfo) { return notarizeSignatureWithIp(pSigDoc, pSigInfo, 0); } //------------------------------------------ // Selects correct OCSP URL for this certificate // issuerDN - certificate issuer DN // ppOcspUrl - returned OCSP url or NULL if not found // returns error code or ERR_OK //------------------------------------------ int ddocSelectOcspUrl(char* issuerDN, char** ppOcspUrl) { int err = ERR_OK, i; char buf1[100], *p; RETURN_IF_NULL_PARAM(ppOcspUrl); // get default OCSP URL *ppOcspUrl = (char*)ConfigItem_lookup("DIGIDOC_OCSP_URL"); // if possible find OCSP URL by signers CA ddocDebug(3, "ddocSelectOcspUrl", "signers CA: %s", (issuerDN ? issuerDN : "NULL")); if(issuerDN) { buf1[0] = 0; findCN(issuerDN, buf1, sizeof(buf1)); ddocDebug(3, "ddocSelectOcspUrl", "signers CA CN: %s", buf1); findResponderIndex(&i, NULL, NULL, buf1); if(i > 0) { snprintf(buf1, sizeof(buf1), "DIGIDOC_OCSP_RESPONDER_CERT_%d_URL", i); p = (char*)ConfigItem_lookup(buf1); if(p) { *ppOcspUrl = p; ddocDebug(3, "ddocSelectOcspUrl", "Selected OCSP URL: %s", p); } } buf1[0] = 0; } if(!(*ppOcspUrl)) { ddocDebug(1, "ddocSelectOcspUrl", "ERR112 ocsp url: %s", (*ppOcspUrl ? *ppOcspUrl : "NULL")); SET_LAST_ERROR(ERR_UNKNOWN_CA); err = ERR_UNKNOWN_CA; } else { ddocDebug(3, "ddocSelectOcspUrl", "Selected OCSP URL: %s", *ppOcspUrl); } return err; } int ddocFindCaChainForCert(X509* pCert, X509** caCerts, int *nCerts, char* szCA, int caLen) { int err = ERR_OK, i; DigiDocMemBuf mbuf1, mbuf2; RETURN_IF_NULL_PARAM(caCerts); RETURN_IF_NULL_PARAM(nCerts); RETURN_IF_NULL_PARAM(szCA); mbuf1.pMem = 0; mbuf1.nLen = 0; mbuf2.pMem = 0; mbuf2.nLen = 0; for(i = 0; i < NUM_SEARCH_CAS; i++) caCerts[i] = 0; szCA[0] = 0; err = ddocCertGetIssuerDN(pCert, &mbuf1); err = ddocCertGetSubjectDN(pCert, &mbuf2); ddocDebug(3, "ddocFindCaChainForCert", "Find chain for: %s issuer: %s", (char*)mbuf2.pMem, (char*)mbuf1.pMem); if(!err) { err = findCN((char*)mbuf1.pMem, szCA, caLen); ddocDebug(3, "ddocFindCaChainForCert", "Find chain for CN: %s", szCA); if(!err) { err = findCAChainForCNAndSigTime(caCerts, nCerts, szCA, pCert, 0); ddocDebug(3, "ddocFindCaChainForCert", "Chain length: %d, err: %d", *nCerts, err); } } ddocMemBuf_free(&mbuf1); ddocMemBuf_free(&mbuf2); return err; } int ddocFindOcspCnCaAndCerts(OCSP_RESPONSE* pResp, int *nType, X509** caCerts, int *nCerts, char* szCN, int cnLen, char* szCA, int caLen) { int err = ERR_OK, i; DigiDocMemBuf mbuf1; RETURN_IF_NULL_PARAM(pResp); RETURN_IF_NULL_PARAM(nType); RETURN_IF_NULL_PARAM(caCerts); RETURN_IF_NULL_PARAM(nCerts); RETURN_IF_NULL_PARAM(szCN); RETURN_IF_NULL_PARAM(szCA); mbuf1.pMem = 0; mbuf1.nLen = 0; for(i = 0; i <= NUM_SEARCH_CAS; i++) caCerts[i] = 0; szCN[0] = szCA[0] = 0; // find responder id type and value ddocDebug(3, "ddocFindOcspCnCaAndCerts", "OCSP: %s", (pResp ? "OK" : "NO")); err = ddocGetOcspRespIdTypeAndValue(pResp, nType, &mbuf1); if((*nType) == RESPID_NAME_TYPE) { err = findCN((char*)mbuf1.pMem, szCN, cnLen); if (!err) err = findResponderCA(szCA, caLen, szCN, NULL); } else if((*nType) == RESPID_KEY_TYPE) { i = sizeof(szCN); encode((const byte*)mbuf1.pMem, mbuf1.nLen, (byte*)szCN, &i); if (!err) err = findResponderCA(szCA, caLen, NULL, szCN); } else { SET_LAST_ERROR(ERR_OCSP_WRONG_RESPID); err = ERR_OCSP_WRONG_RESPID; } ddocDebug(3, "ddocFindOcspCnCaAndCerts", "Responder CN: %s CA: %s, RC: %d", szCN, szCA, err); // find CA chain if(err == ERR_OK) err = findCAChainForCNAndSigTime(caCerts, nCerts, szCA, NULL, 0); ddocDebug(3, "ddocFindOcspCnCaAndCerts", "Chain length: %d, err: %d", *nCerts, err); // cleanup ddocMemBuf_free(&mbuf1); return err; } //------------------------------------------ // Get a notary confirmation for signature // pSigDoc - signed document pointer // pSigInfo - signature to notarize // ip - callers ip address if known // returns error code //------------------------------------------ EXP_OPTION int notarizeSignatureWithIp(SignedDoc* pSigDoc, SignatureInfo* pSigInfo, unsigned long ip) { NotaryInfo* pNotInfo; int err = ERR_OK, nCAs = NUM_SEARCH_CAS, i, j, err2 = 0, nType; X509* caCerts[NUM_SEARCH_CAS+1]; X509* pNotCert, *pSigCert = 0, *pSigCa = 0; //AM 24.09.08 szCA size from 30 to 100 for Portuguese ID card char szCN[200], szCA[100]; char *pkcs12file, *pkcs12passwd, *ocspUrl; char *proxyHost, *proxyPort, *proxyUser, *proxyPass; OCSP_RESPONSE *pResp = 0; CertValue *pCertValue = 0; // PR. index fix for(i = 0; i < NUM_SEARCH_CAS; i++) caCerts[i] = 0; if(ConfigItem_lookup_bool("SIGN_OCSP", 1)) { pkcs12file = (char*)ConfigItem_lookup("DIGIDOC_PKCS_FILE"); RETURN_IF_NOT(pkcs12file, ERR_OCSP_PKCS12_NO_FILE); pkcs12passwd = (char*)ConfigItem_lookup("DIGIDOC_PKCS_PASSWD"); //RETURN_IF_NOT(pkcs12passwd, ERR_OCSP_PKCS12_NO_PASSWD); } else { pkcs12file = pkcs12passwd = NULL; } if(ConfigItem_lookup_bool("USE_PROXY", 1)) { proxyHost = (char*)ConfigItem_lookup("DIGIDOC_PROXY_HOST"); RETURN_IF_NOT(proxyHost, ERR_WRONG_URL_OR_PROXY); proxyPort = (char*)ConfigItem_lookup("DIGIDOC_PROXY_PORT"); RETURN_IF_NOT(proxyPort, ERR_WRONG_URL_OR_PROXY); proxyUser = (char*)ConfigItem_lookup("DIGIDOC_PROXY_USER"); proxyPass = (char*)ConfigItem_lookup("DIGIDOC_PROXY_PASS"); ddocDebug(4, "notarizeSignature", "proxy: %s port : %s", proxyHost, proxyPort); } else { proxyHost = proxyPort = proxyUser = proxyPass = NULL; } err = ddocSelectOcspUrl((char*)ddocSigInfo_GetSignersCert_IssuerName(pSigInfo), &ocspUrl); RETURN_IF_NOT(err == ERR_OK, err); // get signers ca certs pSigCert = ddocSigInfo_GetSignersCert(pSigInfo); err = ddocFindCaChainForCert(pSigCert, caCerts, &nCAs, szCA, sizeof(szCA)); RETURN_IF_NOT(nCAs >= 0, ERR_SIGNERS_CERT_NOT_TRUSTED); pSigCa = caCerts[nCAs]; // get OCSP confirmation ddocDebug(3, "notarizeSignatureWithIp", "Getting OCSP confirmation"); err = getConfirmationWithIpEx(pSigDoc, pSigInfo, (const X509 **)caCerts, NULL, pkcs12file, pkcs12passwd, ocspUrl, proxyHost, proxyPort, proxyUser, proxyPass, ip); // release ca certs nCAs=10; for(i = 0; i < NUM_SEARCH_CAS; i++) { if(caCerts[i] && caCerts[i] != pSigCa) { X509_free(caCerts[i]); caCerts[i] = 0; } } // continue with the rest RETURN_IF_NOT(err == ERR_OK, err); pNotInfo = getNotaryWithSigId(pSigDoc, pSigInfo->szId); RETURN_IF_NOT(pNotInfo != NULL, ERR_NOTARY_SIG_MATCH); // get OCSP response pResp = ddocNotInfo_GetOCSPResponse_Value(pNotInfo); RETURN_IF_NOT(pResp != NULL, ERR_NOTARY_SIG_MATCH); // find CN from responder-id, right CA and CA certs chain err = ddocFindOcspCnCaAndCerts(pResp, &nType, (X509**)caCerts, &nCAs, szCN, sizeof(szCN), szCA, sizeof(szCA)); // find usable responder cert by trying all of them // until verification with one succedes if(err == ERR_OK) { j = 0; do { pNotCert = 0; err2 = ERR_OK; if(nType == RESPID_NAME_TYPE) findResponderByCNAndHashAndIndex(&pNotCert, szCN, NULL, j); else if(nType == RESPID_KEY_TYPE) findResponderByCNAndHashAndIndex(&pNotCert, NULL, szCN, j); ddocDebug(1, "notarizeSignatureWithIp", "Find notary: %s idx: %d cert: %s", szCN, j, (pNotCert ? "OK" : "NULL")); if(pNotCert) { err2 = finalizeAndVerifyNotary2(pSigDoc, pSigInfo, pNotInfo, (const X509**)&caCerts, (const X509*)pNotCert, (const X509*)pSigCa); ddocDebug(1, "notarizeSignatureWithIp", "Verifying notary: %d", err); j++; if(err2) { // VS: release ownership before deletion pCertValue = ddocSigInfo_GetOrCreateCertValueOfType(pSigInfo, CERTID_VALUE_RESPONDERS_CERT); if(pCertValue && pCertValue->pCert == pNotCert) { ddocDebug(1, "notarizeSignatureWithIp", "Release notary cert err2: %d", err2); pCertValue->pCert = NULL; } X509_free(pNotCert); } } } while(pNotCert && err2 != ERR_OK); } if(pSigCa) X509_free(pSigCa); if(err2) err = err2; else clearErrors(); for(i = 0; i < NUM_SEARCH_CAS; i++) if(caCerts[i]) X509_free(caCerts[i]); if(pResp) OCSP_RESPONSE_free(pResp); // test if not cert is ok pCertValue = ddocSigInfo_GetOrCreateCertValueOfType(pSigInfo, CERTID_VALUE_RESPONDERS_CERT); ddocDebug(3, "notarizeSignatureWithIp", "End Notary: cert-val: %s cert: %s", ((pCertValue && pCertValue->pCert) ? "OK" : "NULL"), (pNotCert ? "OK" : "NULL")); // please note that we cannot free pNotCert here because we gave ownership to pNotInf! return err; } //-------------------------------------------------- // Signs the document and gets configrmation // pSigDoc - signed document pointer // ppSigInfo - address of new signature pointer // pin - smart card PIN // manifest - manifest / resolution (NULL) // city - signers city (NULL) // state - signers state (NULL) // zip - signers postal code (NULL) // country - signers country (NULL) //-------------------------------------------------- EXP_OPTION int signDocument(SignedDoc* pSigDoc, SignatureInfo** ppSigInfo, const char* pin, const char* manifest, const char* city, const char* state, const char* zip, const char* country) { return signDocumentWithSlot(pSigDoc, ppSigInfo, pin, manifest, city, state, zip, country, ConfigItem_lookup_int("DIGIDOC_SIGNATURE_SLOT", 0), 1, 1); } //-------------------------------------------------- // Signs the document and gets configrmation // pSigDoc - signed document pointer // ppSigInfo - address of new signature pointer // pin - smart card PIN // manifest - manifest / resolution (NULL) // city - signers city (NULL) // state - signers state (NULL) // zip - signers postal code (NULL) // country - signers country (NULL) //-------------------------------------------------- EXP_OPTION int signDocumentWithSlot(SignedDoc* pSigDoc, SignatureInfo** ppSigInfo, const char* pin, const char* manifest, const char* city, const char* state, const char* zip, const char* country, int nSlot, int nOcsp, int nSigner) { return signDocumentWithSlotAndSigner(pSigDoc, ppSigInfo, pin, manifest, city, state, zip, country, nSlot, nOcsp, nSigner, NULL); } //-------------------------------------------------- // Signs the document and gets configrmation // pSigDoc - signed document pointer // ppSigInfo - address of new signature pointer // pin - smart card PIN // manifest - manifest / resolution (NULL) // city - signers city (NULL) // state - signers state (NULL) // zip - signers postal code (NULL) // country - signers country (NULL) // nSigner - 1=PKCS11, 2=CNG (Microsoft CAPI) // szPkcs12FileName - PKCS#12 file name to be used for signing (required if nSigner=3) //-------------------------------------------------- EXP_OPTION int signDocumentWithSlotAndSigner(SignedDoc* pSigDoc, SignatureInfo** ppSigInfo, const char* pin, const char* manifest, const char* city, const char* state, const char* zip, const char* country, int nSlot, int nOcsp, int nSigner, const char* szPkcs12FileName) { int err = ERR_OK; SignatureInfo* pSigInfo = NULL; RETURN_IF_NULL_PARAM(pSigDoc); RETURN_IF_NULL_PARAM(ppSigInfo); if(nSigner == 3) RETURN_IF_NULL_PARAM(szPkcs12FileName) if(!pSigDoc->szFormatVer || strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER) || !pSigDoc->szFormat || strcmp(pSigDoc->szFormat, DIGIDOC_XML_1_1_NAME)) { SET_LAST_ERROR(ERR_UNSUPPORTED_FORMAT); return ERR_UNSUPPORTED_FORMAT; } clearErrors(); ddocDebug(1, "signDocument", "Creating new digital signature"); RETURN_IF_NOT(err == ERR_OK, err); // add new signature with default id err = SignatureInfo_new(&pSigInfo, pSigDoc, NULL); RETURN_IF_NOT(err == ERR_OK, err); *ppSigInfo = pSigInfo; // 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 if (manifest) err = addSignerRole(*ppSigInfo, 0, manifest, -1, 0); ddocDebug(1, "signDocument", "Calc signature"); // now sign the doc if(nSigner == 1 || !nSigner) err = calculateSignatureWithEstID(pSigDoc, *ppSigInfo, nSlot, pin); #ifdef WIN32 if(nSigner == 2) err = calculateSigInfoSignatureWithCSPEstID(pSigDoc, *ppSigInfo, 0, pin); #endif if(nSigner == 3) err = calculateSignatureWithPkcs12(pSigDoc, *ppSigInfo, szPkcs12FileName, pin); if(err == ERR_PKCS_LOGIN) return err; RETURN_IF_NOT(err == ERR_OK, ERR_PKCS_SIGN_DATA); if(nOcsp) err = notarizeSignature(pSigDoc, *ppSigInfo); RETURN_IF_NOT(err == ERR_OK, err); return ERR_OK; } //-------------------------------------------------- // Verify this notary // pSigDoc - signed document pointer // pNotInfo - notary to verify // returns error code //-------------------------------------------------- int verifyNotary(SignedDoc* pSigDoc, SignatureInfo* pSigInfo, NotaryInfo* pNotInfo) { int err = ERR_OK, nCAs = NUM_SEARCH_CAS, i, err2 = 0; X509 * caCerts[NUM_SEARCH_CAS]; X509* pNotCert = 0, *pCaCert = 0; const DigiDocMemBuf *pMBuf = 0; char buf1[300], buf2[300], szNotSerial[100]; int mustFreeNotaryCert = 0; for (i = 0; i < NUM_SEARCH_CAS; i++) caCerts[i] = 0; // get responder certs serial nr szNotSerial[0] = 0; if(ddocSigInfo_GetOCSPRespondersCert(pSigInfo)) err = ReadCertSerialNumber(szNotSerial, sizeof(szNotSerial), ddocSigInfo_GetOCSPRespondersCert(pSigInfo)); // find responder cert and it's CA cert pMBuf = ddocNotInfo_GetResponderId(pNotInfo); RETURN_IF_NULL(pMBuf); memset(buf2, 0, sizeof(buf2)); // use responders cert from ddoc //pNotCert = ddocSigInfo_GetOCSPRespondersCert(pSigInfo); if(pNotInfo->nRespIdType == RESPID_NAME_TYPE) { err = findCN((char*)pMBuf->pMem, buf1, sizeof(buf1)); ddocDebug(3, "verifyNotary", "Responder text: %s", buf1); if (!err) { err = findResponderCA(buf2, sizeof(buf2), buf1, NULL); ddocDebug(3, "verifyNotary", "Responder CA: %s", buf2); } if(!err) { err = findResponder(&pNotCert, buf1, NULL, (strlen(szNotSerial) ? szNotSerial : NULL)); ddocDebug(3, "verifyNotary", "Responder %s cert: %s, err: %d", buf1, (pNotCert ? "OK" : "NULL"), err); } } else if(pNotInfo->nRespIdType == RESPID_KEY_TYPE) { i = sizeof(buf1); encode((const byte*)pMBuf->pMem, pMBuf->nLen, (byte*)buf1, &i); ddocDebug(3, "verifyNotary", "Responder bin: %s", buf1); if (!err) { err = findResponderCA(buf2, sizeof(buf2), NULL, buf1); ddocDebug(3, "verifyNotary", "Responder CA: %s", buf2); } if(!err) { err = findResponder(&pNotCert, NULL, buf1, (strlen(szNotSerial) ? szNotSerial : NULL)); ddocDebug(3, "verifyNotary", "Responder %s cert: %s, err: %d", buf1, (pNotCert ? "OK" : "NULL"), err); } } else { SET_LAST_ERROR(ERR_OCSP_WRONG_RESPID); err = ERR_OCSP_WRONG_RESPID; } if (!err) { ddocDebug(3, "verifyNotary", "Find ca chain for: %s", buf2); err = findCAChainForCNAndSigTime((X509**)caCerts, &nCAs, buf2, pNotCert, 0); ddocDebug(3, "verifyNotary", "CA chain for: %s, ca-s: %d, rc: %d", buf2, nCAs+1, err); } // use specific error code for responders cert not found! if(err) { SET_LAST_ERROR(ERR_OCSP_RESP_NOT_TRUSTED); err = ERR_OCSP_RESP_NOT_TRUSTED; } ddocDebug(3, "verifyNotary", "Chain length: %d, err: %d", nCAs+1, err); if(pNotCert) { // #23784 - donŠt use responders cert in signature, use local copy err = ddocSigInfo_SetOCSPRespondersCert(pSigInfo, pNotCert); ddocDebug(3, "verifyNotary", "assigned notary cert from local store"); } else { mustFreeNotaryCert = 1; } if (!err) { ddocDebug(3, "verifyNotary", "Verifying Notary %s - cert: %s CA-s: %d", pNotInfo->szId, ((pNotCert) ? "OK" : "NULL"),nCAs+1); err = findCAForCertificateAndSigTime(&pCaCert, ddocSigInfo_GetSignersCert(pSigInfo), 0); err = verifyNotaryInfoCERT2(pSigDoc, pSigInfo, pNotInfo, (const X509**)caCerts, ConfigItem_lookup("CA_CERT_PATH"), pNotCert, pCaCert); ddocDebug(3, "verifyNotary", "Verifying Notary %s - %s", pNotInfo->szId, ((!err) ? "OK" : "ERROR")); } if (mustFreeNotaryCert) { ddocDebug(3, "verifyNotary", "freed notary cert, hopefully all is OK"); X509_free(pNotCert); } if (!err) { err = isCertSignedByCERT(ddocSigInfo_GetOCSPRespondersCert(pSigInfo), caCerts[nCAs]); if(err) { err2 = isCertSignedByCERT(ddocSigInfo_GetOCSPRespondersCert(pSigInfo), caCerts[nCAs - 1]); if(!err2) clearErrors(); else err = err2; } ddocDebug(3, "verifyNotary", "\tCertificate trusted - %s", ((!err) ? "OK" : "ERROR")); } // verify notary digest if (!err) { err = verifyNotaryDigest(pSigDoc, pNotInfo); ddocDebug(3, "verifyNotary", "\tNotary digest - %s", ((!err) ? "OK" : "ERROR")); } for (i = 0; i < NUM_SEARCH_CAS; i++) { if(caCerts[i]) { X509_free(caCerts[i]); caCerts[i] = 0; } } if (err != ERR_OK) SET_LAST_ERROR(err); return err; } //-------------------------------------------------- // Verify this signature and it's notary // pSigDoc - signed document pointer // pSigInfo - signature to verify // szFileName - input digidoc filename // returns error code //-------------------------------------------------- EXP_OPTION int verifySignatureAndNotary(SignedDoc* pSigDoc, SignatureInfo* pSigInfo, const char* szFileName) { int err1 = ERR_OK, err2 = ERR_OK, k; X509* pCA = 0; NotaryInfo* pNotInfo; time_t tProdAt = 0; pNotInfo = getNotaryWithSigId(pSigDoc, pSigInfo->szId); if(pNotInfo) ddocNotInfo_GetProducedAt_timet(pNotInfo, &tProdAt); err1 = findCAForCertificateAndSigTime(&pCA, ddocSigInfo_GetSignersCert(pSigInfo), tProdAt); ddocDebug(3, "verifySignatureAndNotary", "Sig: %s find ca: %d, CA: %s sig-time: %ld", pSigInfo->szId, err1, (pCA ? "OK" : "NULL"), (unsigned long)tProdAt); //RETURN_IF_NOT(err == ERR_OK, err); //RETURN_IF_NOT(pCA, ERR_SIGNERS_CERT_NOT_TRUSTED); if(!pCA) { err1 = ERR_SIGNERS_CERT_NOT_TRUSTED; SET_LAST_ERROR(err1); } if(pCA) err2 = verifySignatureInfoCERT(pSigDoc, pSigInfo, pCA, szFileName, 1); if(err2) { SET_LAST_ERROR(err2); err1 = err2; } if (pNotInfo) { err2 = verifyNotary(pSigDoc, pSigInfo, pNotInfo); if(err2) { SET_LAST_ERROR(err2); if(!err1) err1 = err2; } ddocDebug(3, "verifySignatureAndNotary", "verify notary: %d", err2); } else { ddocDebug(3, "verifySignatureAndNotary", "\tSignature has no OCSP confirmation!\n"); SET_LAST_ERROR(ERR_NO_OCSP); err2 = ERR_NO_OCSP; if(!err1) err1 = err2; } if((k = getCountOfSignerRoles(pSigInfo, 0)) > 1) { ddocDebug(1, "verifySignatureInfo", "Number of roles: %d, Currently supports max 1 roles", k); SET_LAST_ERROR(ERR_MAX_1_ROLES); err2 = ERR_MAX_1_ROLES; if(!err1) err1 = err2; } //} else // SET_LAST_ERROR(err2); if (pCA) X509_free(pCA); if(pSigInfo->nErr1) // restore possibly cleared parsing err SET_LAST_ERROR(pSigInfo->nErr1); ddocDebug(3, "verifySignatureAndNotary", "Sig: %s err: %d haserr: %d", pSigInfo->szId, err1, hasUnreadErrors()); return checkUnknownErr(); } //-------------------------------------------------- // Extract common name from cert DN or responder id // src - DN // dest - buffer for CN // destLen - size of output buffer in bytes //-------------------------------------------------- int findCN(char* src, char* dest, int destLen) { char* p1, *p2; int n; p1 = strstr(src, "CN="); if(p1) { p1 += 3; // start of CN field // find start of next field p2 = strchr(p1, '='); if(!p2) // if not found then this was the last field p2 = strchr(p1, 0); // if we have found = of next field then move back until before field name if(p2 && *p2 == '=') while(p2 > p1 && isalpha(*(p2-1))) p2--; // remove possible field separators while(p2 > p1 && (*(p2-1) == ' ' || *(p2-1) == ',' || *(p2-1) == '/')) p2--; if(p2) { n = (int)(p2-p1); if(n >= destLen) n = destLen - 1; strncpy(dest, p1, n); dest[n] = 0; return ERR_OK; } } SET_LAST_ERROR_RETURN_CODE(ERR_CERT_INVALID); } //------------------------------------------ // Verify certificate by OCSP // pCert - certificate to check // ppResp - address to return OCSP response. Use NULL if // you don't want OCSP response to be returned // returns error code //------------------------------------------ EXP_OPTION int ddocVerifyCertByOCSP(X509* pCert, OCSP_RESPONSE **ppResp) { return ddocVerifyCertByOCSPWithIp(pCert, ppResp, 0); } //------------------------------------------ // Verify certificate by OCSP // pCert - certificate to check // ppResp - address to return OCSP response. Use NULL if // you don't want OCSP response to be returned // returns error code //------------------------------------------ EXP_OPTION int ddocVerifyCertByOCSPWithIp(X509* pCert, OCSP_RESPONSE **ppResp, unsigned long ip) { int err = ERR_OK, nCAs = NUM_SEARCH_CAS, i, j, err2 = ERR_OK, nType; X509 * caCerts[NUM_SEARCH_CAS]; X509 *pNotCert = 0; char *pkcs12file, *pkcs12passwd; char *proxyHost, *proxyPort; char szCN[100], szCA[100], *ocspUrl; OCSP_RESPONSE *pResp = NULL; DigiDocMemBuf mbuf1; mbuf1.pMem = 0; mbuf1.nLen = 0; // check if OCSP must be signed if(ConfigItem_lookup_bool("SIGN_OCSP", 1)) { pkcs12file = (char*)ConfigItem_lookup("DIGIDOC_PKCS_FILE"); RETURN_IF_NOT(pkcs12file, ERR_OCSP_PKCS12_NO_FILE); pkcs12passwd = (char*)ConfigItem_lookup("DIGIDOC_PKCS_PASSWD"); RETURN_IF_NOT(pkcs12passwd, ERR_OCSP_PKCS12_NO_PASSWD); } else { pkcs12file = pkcs12passwd = NULL; } // check proxy usage if(ConfigItem_lookup_bool("USE_PROXY", 1)) { proxyHost = (char*)ConfigItem_lookup("DIGIDOC_PROXY_HOST"); RETURN_IF_NOT(proxyHost, ERR_WRONG_URL_OR_PROXY); proxyPort = (char*)ConfigItem_lookup("DIGIDOC_PROXY_PORT"); RETURN_IF_NOT(proxyPort, ERR_WRONG_URL_OR_PROXY); ddocDebug(4, "ddocVerifyCertByOCSPWithIp", "proxy: %s port : %s", proxyHost, proxyPort); } else { proxyHost = proxyPort = NULL; } // send OCSP request and don't verify result immediately err = ddocCertGetIssuerDN(pCert, &mbuf1); RETURN_IF_NOT(err == ERR_OK, err); err = ddocSelectOcspUrl((char*)mbuf1.pMem, &ocspUrl); ddocMemBuf_free(&mbuf1); RETURN_IF_NOT(err == ERR_OK, err); // find cert oweners CA cert chain err = ddocFindCaChainForCert(pCert, (X509**)caCerts, &nCAs, szCA, sizeof(szCA)); // if possible find OCSP URL by signers CA ddocDebug(3, "ddocVerifyCertByOCSPWithIp", "OCSP URL: %s CA: %s chain: %d", (ocspUrl ? ocspUrl : "NULL"), szCA, nCAs); err = verifyCertificateByOCSPWithIp(pCert, (const X509 **)caCerts, NULL, ocspUrl, proxyHost, proxyPort, pkcs12file, pkcs12passwd, &pResp, ip); ddocDebug(3, "ddocVerifyCertByOCSPWithIp", "OCSP verification - RC: %d, resp: %s", err, (pResp ? "OK" : "NULL")); // release cert CA chain, PR. index fix for(i = 0; i < NUM_SEARCH_CAS; i++) { if(caCerts[i]) { X509_free(caCerts[i]); caCerts[i] = 0; } } // verify OCSP response // find CN from responder-id, right CA and CA certs chain if(!err) err = ddocFindOcspCnCaAndCerts(pResp, &nType, (X509**)caCerts, &nCAs, szCN, sizeof(szCN), szCA, sizeof(szCA)); // find usable responder cert by trying all of them // until verification with one succedes if(err == ERR_OK) { j = 0; do { pNotCert = 0; err2 = ERR_OK; if(nType == RESPID_NAME_TYPE) findResponderByCNAndHashAndIndex(&pNotCert, szCN, NULL, j); else if(nType == RESPID_KEY_TYPE) findResponderByCNAndHashAndIndex(&pNotCert, NULL, szCN, j); ddocDebug(1, "ddocVerifyCertByOCSPWithIp", "Find notary: %s idx: %d cert: %s", szCN, j, (pNotCert ? "OK" : "NULL")); if(pNotCert) err2 = verifyOCSPResponse(pResp, (const X509**)&caCerts, NULL, (const X509*)pNotCert); ddocDebug(1, "ddocVerifyCertByOCSPWithIp", "Verifying notary: %d", err); j++; if(pNotCert) X509_free(pNotCert); } while(pNotCert && err2 != ERR_OK); } if(err2) err = err2; else clearErrors(); for(i = 0; i < NUM_SEARCH_CAS; i++) if(caCerts[i]) X509_free(caCerts[i]); // return OCSP response if requested if(pResp) { if(ppResp) *ppResp = pResp; else OCSP_RESPONSE_free(pResp); } return err; } //------------------------------------------ // Reads an arbitrary file into memory buffer // szFileName - file name and path // pData - memory buffer object // returns error code //------------------------------------------ EXP_OPTION int ddocReadFile(const char* szFileName, DigiDocMemBuf* pData) { int err = ERR_OK; long l1; FILE *hFile; char buf1[2050]; #ifdef WIN32 wchar_t *convFileName = 0; int i= 0; err = utf82unicode((const char*)szFileName, (char**)&convFileName, &i); ddocDebug(3, "ddocReadFile", "file: %s, conv-file: %s len: %d", szFileName, convFileName, i); #endif RETURN_IF_NULL_PARAM(szFileName); RETURN_IF_NULL_PARAM(pData); pData->pMem = 0; pData->nLen = 0; #ifdef WIN32 hFile = _wfopen(convFileName, L"rb"); #else hFile = fopen(szFileName, "rb"); #endif RETURN_IF_NOT(hFile, ERR_FILE_READ); do { l1 = fread(buf1, 1, 2048, hFile); err = ddocMemAppendData(pData, buf1, (long)l1); } while(l1 == 2048 && !err); fclose(hFile); return err; } //------------------------------------------ // Writes an arbitrary file into memory buffer // szFileName - file name and path // pData - memory buffer object // returns error code //------------------------------------------ EXP_OPTION int ddocWriteFile(const char* szFileName, DigiDocMemBuf* pData) { int err = ERR_OK; FILE *hFile; #ifdef WIN32 wchar_t *convFileName = 0; int i= 0; err = utf82unicode((const char*)szFileName, (char**)&convFileName, &i); ddocDebug(3, "ddocReadFile", "file: %s, conv-file: %s len: %d", szFileName, convFileName, i); #endif RETURN_IF_NULL_PARAM(szFileName); RETURN_IF_NULL_PARAM(pData); #ifdef WIN32 hFile = _wfopen(convFileName, L"wb"); #else hFile = fopen(szFileName, "wb"); #endif RETURN_IF_NOT(hFile, ERR_FILE_WRITE); if(hFile) fwrite(pData->pMem, 1, pData->nLen, hFile); fclose(hFile); return err; }