diff options
author | Andrew Shadura <andrewsh@debian.org> | 2015-11-01 19:41:28 +0100 |
---|---|---|
committer | Andrew Shadura <andrewsh@debian.org> | 2015-11-01 19:41:28 +0100 |
commit | 61c1a106bd81794f48e4cd85bae129f9270279e8 (patch) | |
tree | 29ecf644c4a13c2645bd8067e66ae8944dd2daf9 /libdigidoc/DigiDocConfig.c |
libdigidoc (3.10.1.1208-1) unstable; urgency=medium
* Initial upload (Closes: #658300).
# imported from the archive
Diffstat (limited to 'libdigidoc/DigiDocConfig.c')
-rw-r--r-- | libdigidoc/DigiDocConfig.c | 2211 |
1 files changed, 2211 insertions, 0 deletions
diff --git a/libdigidoc/DigiDocConfig.c b/libdigidoc/DigiDocConfig.c new file mode 100644 index 0000000..67db4d7 --- /dev/null +++ b/libdigidoc/DigiDocConfig.c @@ -0,0 +1,2211 @@ +//================================================== +// 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 <Windows.h> include +// 08.01.2004 Veiko Sinivee +// Creation +//================================================== + +// config data comes from there +#include <config.h> + +//AA 04/01/26 +#ifdef WIN32 +#include <windows.h> +#define snprintf _snprintf +#elif defined(__APPLE__) +#include <CoreFoundation/CoreFoundation.h> +#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 <stdio.h> +#include <stdlib.h> +#include <memory.h> +#include <string.h> +#include <ctype.h> + +#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; +} + |