2
* libdigidocpp - a C++ library for creating and validating BDOC-1.0 documents
4
* Copyright (C) 2009-2010 Estonian Informatics Centre
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2.1 of the License, or (at your option) any later version.
11
* This library is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Lesser General Public License for more details.
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with this library; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
37
#include "util/File.h"
38
#include "util/String.h"
40
#include <xsd/cxx/xml/dom/parsing-source.hxx> //for parsing xml data into DOMDocument
41
#include <stdlib.h>//getenv
44
#ifndef DIGIDOCPP_PATH_REGISTRY_KEY
45
#define DIGIDOCPP_PATH_REGISTRY_KEY "SOFTWARE\\Estonian ID Card\\digidocpp"
50
* Path to default configuration files
52
std::string digidoc::XmlConf::DEFAULT_CONF_LOC = "";
53
std::string digidoc::XmlConf::USER_CONF_LOC = "";
55
const std::string digidoc::XmlConf::DIGEST_URI = "digest.uri";
56
const std::string digidoc::XmlConf::PKCS11_DRIVER_PATH = "pkcs11.driver.path";
57
const std::string digidoc::XmlConf::CERT_STORE_PATH = "cert.store.path";
58
const std::string digidoc::XmlConf::MANIFEST_XSD_PATH = "manifest.xsd.path";
59
const std::string digidoc::XmlConf::XADES_XSD_PATH = "xades.xsd.path";
60
const std::string digidoc::XmlConf::DSIG_XSD_PATH = "dsig.xsd.path";
61
const std::string digidoc::XmlConf::PROXY_HOST = "proxy.host";
62
const std::string digidoc::XmlConf::PROXY_PORT = "proxy.port";
63
const std::string digidoc::XmlConf::PROXY_USER = "proxy.user";
64
const std::string digidoc::XmlConf::PROXY_PASS = "proxy.pass";
65
const std::string digidoc::XmlConf::PKCS12_CERT = "pkcs12.cert";
66
const std::string digidoc::XmlConf::PKCS12_PASS = "pkcs12.pass";
69
* Use digidoc::XmlConf as configuration instance.
71
void digidoc::XmlConf::initialize()
76
if(!Conf::isInitialized())
80
Conf::init(new XmlConf());
82
catch(const digidoc::IOException& e)
84
ERR("%s\n", e.getMsg().c_str());
85
THROW_IOEXCEPTION("Could not initialize XmlConf");
92
* Tries to initialize XmlConf by using file defined in DIGIDOCPP_OVERRIDE_CONF environment variable.
93
* If this is undefined, tries to load configuration from defined Default and user configuration file
95
digidoc::XmlConf::XmlConf() throw(IOException)
98
if (!DEFAULT_CONF_LOC.size())
99
THROW_IOEXCEPTION("XmlConf not initialized!");
100
if(util::File::fileExists(DEFAULT_CONF_LOC))
101
init(DEFAULT_CONF_LOC);
103
THROW_IOEXCEPTION("Error loading xml configuration from '%s' file",DEFAULT_CONF_LOC.c_str());
105
if( !getenv("DIGIDOCPP_OVERRIDE_CONF") && util::File::fileExists(USER_CONF_LOC))
110
* Initialize xml conf from path
111
* @param path to use for initializing conf
114
digidoc::XmlConf::XmlConf(const std::string& path) throw(IOException)
116
if(util::File::fileExists(path))
122
THROW_IOEXCEPTION("Error loading xml configuration from file '%s'", path.c_str());
126
digidoc::XmlConf::~XmlConf()
131
* Gets default configuration file directory.
132
* @return default configuration file directory full path.
134
std::string digidoc::XmlConf::getDefaultConfDir()
136
// the file path in conf is relative to the conf file's location
137
const char *env = DEFAULT_CONF_LOC.c_str();
139
return digidoc::util::File::directory( env );
140
char *path = getcwd( NULL, 0 );
149
* Load and parse xml from path. Initialize XmlConf member variables from xml.
150
* @param path to use for initializing conf
152
void digidoc::XmlConf::init(const std::string& path) throw(IOException)
154
DEBUG("digidoc::XmlConf::init(%s)", path.c_str());
157
std::auto_ptr< ::Configuration > conf( configuration (path, xml_schema::Flags::dont_initialize));
158
Configuration::ParamSequence paramSeq = conf->param();
160
for( Configuration::ParamSequence::const_iterator it = paramSeq.begin(); it != paramSeq.end(); it++)
162
if(DIGEST_URI.compare(it->name()) == 0)
166
else if(MANIFEST_XSD_PATH.compare(it->name()) == 0)
168
manifestXsdPath = *it;
170
else if(XADES_XSD_PATH.compare(it->name()) == 0)
174
else if(DSIG_XSD_PATH.compare(it->name()) == 0)
178
else if(PKCS11_DRIVER_PATH.compare(it->name()) == 0)
180
pkcs11DriverPath = *it;
182
else if(CERT_STORE_PATH.compare(it->name()) == 0)
186
else if(PROXY_HOST.compare(it->name()) == 0)
190
else if(PROXY_PORT.compare(it->name()) == 0)
194
else if(PROXY_USER.compare(it->name()) == 0)
198
else if(PROXY_PASS.compare(it->name()) == 0)
202
else if(PKCS12_CERT.compare(it->name()) == 0)
206
else if(PKCS12_PASS.compare(it->name()) == 0)
212
WARN("Unknown configuration parameter %s", it->name().c_str());
216
std::string conf_fullpath = getDefaultConfDir();
217
if( !conf_fullpath.empty() ) conf_fullpath += "/";
218
Configuration::OcspSequence ocspSeq = conf->ocsp();
219
for( Configuration::OcspSequence::const_iterator it = ocspSeq.begin(); it != ocspSeq.end(); ++it)
222
o.issuer = it->issuer();
225
o.cert.insert(0, conf_fullpath);
229
catch(const xml_schema::Exception& e)
231
std::ostringstream oss;
233
THROW_IOEXCEPTION("Failed to parse configuration: %s", oss.str().c_str());
238
* Sets Default (global) configuration file path in DEFAULT_CONF_LOC variable.
240
void digidoc::XmlConf::setDefaultConfPath() throw(IOException)
242
char * overrideConf = getenv( "DIGIDOCPP_OVERRIDE_CONF" );
243
if (overrideConf != NULL) //if there is environment variable defined, use this conf instead of others
245
if(util::File::fileExists(overrideConf))
246
DEFAULT_CONF_LOC = overrideConf;
248
THROW_IOEXCEPTION("Error loading override xml configuration from '%s' file",overrideConf);
256
TCHAR tcConfPath[MAX_PATH];
257
//Open Registry to get path for default configuration file
258
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(DIGIDOCPP_PATH_REGISTRY_KEY), 0, KEY_QUERY_VALUE, &hkey)==ERROR_SUCCESS)
260
dwSize = MAX_PATH * sizeof(TCHAR);
261
dwRet = RegQueryValueEx(hkey, "ConfigFile", NULL, NULL, (LPBYTE)tcConfPath, &dwSize);
263
if (dwRet == ERROR_SUCCESS)
264
DEFAULT_CONF_LOC = tcConfPath;
265
else //if couldn't open regkey value
266
THROW_IOEXCEPTION("Failed to open registry key \"%s\" ConfigFile value ", DIGIDOCPP_PATH_REGISTRY_KEY);
268
else //if key doesn't exist
269
THROW_IOEXCEPTION("Failed to read registry key \"%s\"", DIGIDOCPP_PATH_REGISTRY_KEY);
271
DEFAULT_CONF_LOC = DIGIDOCPP_CONFIG_DIR "/digidocpp.conf";
277
* Sets User specific configuration file path in USER_CONF_LOC variable.
279
void digidoc::XmlConf::setUserConfPath()
282
USER_CONF_LOC = getenv ("APPDATA");
283
if (USER_CONF_LOC.size())
284
USER_CONF_LOC += "\\digidocpp\\digidocpp.conf";
286
USER_CONF_LOC = getenv("HOME");
287
if (USER_CONF_LOC.size())
288
USER_CONF_LOC += "/.digidocpp/digidocpp.conf";
293
* Digest method used to calculate digest values in BDOC (e.g. 'http://www.w3.org/2000/09/xmldsig#sha1' for SHA1)
295
* For available method URIs see:
297
* <ul><b>W3C XML Encryption Syntax and Processing</b> (10 December 2005) http://www.w3.org/TR/xmlenc-core/</ul>
298
* <ul><b>RFC 4051</b> http://www.ietf.org/rfc/rfc4051.txt</ul>
303
std::string digidoc::XmlConf::getDigestUri() const
309
* Gets user specific configuration file directory.
310
* @return returns user configuration file directory.
312
std::string digidoc::XmlConf::getUserConfDir() const
314
return util::File::directory(USER_CONF_LOC);
318
* Gets Manifest schema file location.
319
* @return Manifest schema full path location.
321
std::string digidoc::XmlConf::getManifestXsdPath() const
323
return digidoc::util::File::fullPathUrl(getDefaultConfDir(), manifestXsdPath);
327
* Gets Xades schema file location.
328
* @return Xades schema full path location.
330
std::string digidoc::XmlConf::getXadesXsdPath() const
332
return digidoc::util::File::fullPathUrl(getDefaultConfDir(), xadesXsdPath);
336
* Gets Dsig schema file location.
337
* @return Dsig schema full path location.
339
std::string digidoc::XmlConf::getDsigXsdPath() const
341
return digidoc::util::File::fullPathUrl(getDefaultConfDir(), dsigXsdPath);
345
* Gets PKCS11 driver file path.
346
* @return PKCS11 driver file location.
348
std::string digidoc::XmlConf::getPKCS11DriverPath() const
350
return pkcs11DriverPath;
354
* Gets OCSP data by issuer.
355
* @param issuer OCSP issuer.
356
* @return returns OCSP data structure, containing issuer, url and certificate location.
358
digidoc::Conf::OCSPConf digidoc::XmlConf::getOCSP(const std::string &issuer) const
360
int pos = issuer.find( "CN=", 0 ) + 3;
361
std::string _issuer = issuer.substr( pos, issuer.find( ",", pos ) - pos );
362
for(std::vector<OCSPConf>::const_iterator i = ocsp.begin(); i != ocsp.end(); ++i)
364
if(i->issuer == _issuer)
372
* Gets Certificate store location.
373
* @return Certificate store full path location.
375
std::string digidoc::XmlConf::getCertStorePath() const
377
return getDefaultConfDir() + "/" + certStorePath;
381
* Gets proxy host address.
382
* @return proxy host address.
384
std::string digidoc::XmlConf::getProxyHost() const
390
* Gets proxy port number.
391
* @return proxy port.
393
std::string digidoc::XmlConf::getProxyPort() const
399
* Gets proxy user name.
400
* @return proxy user name.
402
std::string digidoc::XmlConf::getProxyUser() const
408
* Gets proxy login password.
409
* @return proxy password.
411
std::string digidoc::XmlConf::getProxyPass() const
417
* Gets PKCS12 certificate file location.
418
* @return PKCS12 certificate full path location.
420
std::string digidoc::XmlConf::getPKCS12Cert() const
426
* Gets PKCS12 password.
427
* @return PKCS12 password.
429
std::string digidoc::XmlConf::getPKCS12Pass() const
435
* Sets a Proxy host address. Also adds or replaces proxy host data in the user configuration file.
437
* @param host proxy host address.
438
* @throws IOException exception is thrown if saving a proxy host address into a user configuration file fails.
440
void digidoc::XmlConf::setProxyHost( const std::string &host ) throw(IOException)
443
setUserConf(PROXY_HOST, host);
447
* Sets a Proxy port number. Also adds or replaces proxy port data in the user configuration file.
449
* @param port proxy port number.
450
* @throws IOException exception is thrown if saving a proxy port number into a user configuration file fails.
452
void digidoc::XmlConf::setProxyPort( const std::string &port ) throw(IOException)
455
setUserConf(PROXY_PORT, port);
459
* Sets a Proxy user name. Also adds or replaces proxy user name in the user configuration file.
461
* @param user proxy user name.
462
* @throws IOException exception is thrown if saving a proxy user name into a user configuration file fails.
464
void digidoc::XmlConf::setProxyUser( const std::string &user ) throw(IOException)
467
setUserConf(PROXY_USER, user);
471
* Sets a Proxy password. Also adds or replaces proxy password in the user configuration file.
473
* @param pass proxy password.
474
* @throws IOException exception is thrown if saving a proxy password into a user configuration file fails.
476
void digidoc::XmlConf::setProxyPass( const std::string &pass ) throw(IOException)
479
setUserConf(PROXY_PASS, pass);
483
* Sets a PKCS#12 certficate path. Also adds or replaces PKCS#12 certificate path in the user configuration file.
484
* By default the PKCS#12 certificate file should be located at default path, given by getUserConfDir() function.
486
* @param cert PKCS#12 certificate location path.
487
* @throws IOException exception is thrown if saving a PKCS#12 certificate path into a user configuration file fails.
489
void digidoc::XmlConf::setPKCS12Cert( const std::string &cert ) throw(IOException)
492
setUserConf(PKCS12_CERT, cert);
496
* Sets a PKCS#12 certificate password. Also adds or replaces PKCS#12 certificate password in the user configuration file.
498
* @param pass PKCS#12 certificate password.
499
* @throws IOException exception is thrown if saving a PKCS#12 certificate password into a user configuration file fails.
501
void digidoc::XmlConf::setPKCS12Pass( const std::string &pass ) throw(IOException)
504
setUserConf(PKCS12_PASS, pass);
508
* Adds or replaces OCSP parameters in the user configuration file.
510
* @param issuer an ocsp certificate issuer.
511
* @param url an OCSP server url.
512
* @param cert an OCSP certificate location path.
513
* @throws IOException exception is thrown if saving an OCSP parameters into a user configuration file fails.
515
void digidoc::XmlConf::setOCSP(const std::string &issuer, const std::string &url, const std::string &cert) throw(IOException)
518
confData.issuer = issuer;
520
confData.cert = cert;
521
setUserOCSP(confData);
525
* Sets any parameter in a user configuration file. Also creates a configuration file if it is missing.
527
* @param paramName name of parameter that needs to be changed or created.
528
* @param value value for changing or adding to a given parameter. If value is an empty string, the walue for a given parameter will be erased.
529
* @throws IOException exception is thrown if reading, writing or creating of a user configuration file fails.
531
void digidoc::XmlConf::setUserConf(const std::string ¶mName, const std::string &value) throw(IOException)
533
Param newParam(value, paramName);
534
std::auto_ptr< ::Configuration > conf;
535
Configuration::ParamSequence paramSeq;
539
if(util::File::fileExists(USER_CONF_LOC))
542
//open user conf file
543
conf = configuration (USER_CONF_LOC, xml_schema::Flags::dont_initialize);
544
paramSeq = conf->param();
545
Configuration::ParamSequence::iterator it;
547
for( it = paramSeq.begin(); it != paramSeq.end(); it++)
549
if (paramName.compare(it->name()) == 0)
552
if (value.size()) //if we do not want to just erase
553
paramSeq.insert(it, newParam);
558
if (it == paramSeq.end() && value.size()) //if it's a new parameter
559
paramSeq.push_back(newParam);
563
//Check if directory exists
564
if (!util::File::directoryExists(getUserConfDir()))
565
util::File::createDirectory(getUserConfDir());
568
//copy global conf and erase data
569
conf = configuration (DEFAULT_CONF_LOC, xml_schema::Flags::dont_initialize);
570
Configuration::OcspSequence ocspSeq;
571
paramSeq.push_back(newParam);
572
conf->ocsp(ocspSeq); //replace all ocsp data with empty ocsp sequence
574
conf->param(paramSeq); //replace all param data with new modified param sequence
576
catch (const xml_schema::Exception& e)
578
std::ostringstream oss;
580
THROW_IOEXCEPTION("(in set %s) Failed to parse configuration: %s", paramName.c_str(), oss.str().c_str());
582
serializeUserConf(*conf);
586
* Sets OCSP configuration parmeters in a user configuration file. Also creates a configuration file if it is missing.
588
* @param ocspData OCSP configuration structure defined in Conf.h (OCSPConf). Contains: OCSP issuer, OCSP URL and OCSP certificate location. Empty URL or cert location will erase this parameter for given issuer.
589
* @throws IOException exception is thrown if reading, writing or creating of a user configuration file fails.
591
void digidoc::XmlConf::setUserOCSP(const Conf::OCSPConf &ocspData) throw(IOException)
593
Ocsp newOcsp(ocspData.url, ocspData.cert, ocspData.issuer);
594
std::auto_ptr< ::Configuration > conf;
595
Configuration::OcspSequence ocspSeq;
598
if(util::File::fileExists(USER_CONF_LOC))
600
conf = configuration (USER_CONF_LOC, xml_schema::Flags::dont_initialize);
601
ocspSeq = conf->ocsp();
602
Configuration::OcspSequence::iterator it;
604
for(it = ocspSeq.begin(); it != ocspSeq.end(); ++it)
606
if (ocspData.issuer.compare(it->issuer()) == 0)
609
if (ocspData.url.size() || ocspData.cert.size()) //if we do not want to just erase
610
ocspSeq.insert(it, newOcsp);
614
if (it == ocspSeq.end() && (ocspData.url.size() || ocspData.cert.size())) //if it's a new parameter
615
ocspSeq.push_back(newOcsp);
619
//Check if directory exists
620
if (!util::File::directoryExists(getUserConfDir()))
621
util::File::createDirectory(getUserConfDir());
624
//copy global conf and erase data
625
conf = configuration (DEFAULT_CONF_LOC, xml_schema::Flags::dont_initialize);
626
Configuration::ParamSequence paramSeq;
627
conf->param(paramSeq); //replace all param data with empty param sequence
628
ocspSeq.push_back(newOcsp);
630
conf->ocsp(ocspSeq); //replace all ocsp data with new modified ocsp sequence
632
catch(const xml_schema::Exception& e)
634
std::ostringstream oss;
636
THROW_IOEXCEPTION("(in set OCSP) Failed to parse configuration: %s", oss.str().c_str());
638
serializeUserConf(*conf);
642
* Writes configuration data to user specific configuration xml file.
644
* @param pConf configuration data in xsd object using conf.xsd schema.
645
* @throws IOException exception is thrown if opening of user configuration file fails.
647
void digidoc::XmlConf::serializeUserConf(const ::Configuration &pConf) throw(IOException)
650
ofs.open(USER_CONF_LOC.c_str());
653
ofs.close(); //just in case it was left open
654
THROW_IOEXCEPTION("Failed to open configuration: %s", USER_CONF_LOC.c_str());
656
xml_schema::NamespaceInfomap map;
658
map[""].schema = getConfSchemaLocation().c_str();
659
configuration(ofs, pConf, map);
664
* Gets configuration file schema location with full path.
665
* @throws IOException exception is thrown if failed to parse schema location from default conf file.
666
* @return returns configuration file schema location.
668
std::string digidoc::XmlConf::getConfSchemaLocation() throw(IOException)
670
xml_schema::ErrorHandler *errH = NULL;
671
xml_schema::dom::auto_ptr< xercesc::DOMDocument > domDoc;
674
//Parse default configuration file into a DOM document
675
domDoc = ::xsd::cxx::xml::dom::parse< char > ( DEFAULT_CONF_LOC, *errH,
676
xml_schema::Properties (), xml_schema::Flags::dont_initialize );
680
THROW_IOEXCEPTION("Failed to parse %s into DOMDocument", DEFAULT_CONF_LOC.c_str());
683
//Get access to root element
684
xercesc::DOMElement* root = domDoc->getDocumentElement();
685
//Get schema location atributes.
686
const XMLCh* xsl = root->getAttributeNS (
687
xercesc::SchemaSymbols::fgURI_XSI,
688
xercesc::SchemaSymbols::fgXSI_NONAMESPACESCHEMALOCACTION);
691
THROW_IOEXCEPTION("Failed to parse schema location in: %s", DEFAULT_CONF_LOC.c_str());
693
return digidoc::util::File::path ( getDefaultConfDir(),
694
::xsd::cxx::xml::transcode<char> (xsl) );