libdigidocpp
digidoc-tool.cpp
Go to the documentation of this file.
1 /*
2  * libdigidocpp
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  *
18  */
19 
20 #include "log.h"
21 #include "BDoc.h"
22 #include "Conf.h"
23 #include "Document.h"
24 #include "Signature.h"
25 #include "crypto/cert/X509Cert.h"
27 #include "util/File.h"
28 
29 #ifdef _WIN32
31 #include <Windows.h>
32 #endif
33 
34 #define SUCCESS 0
35 #define FAILURE 1
36 
37 #define PRINT_EXCEPTION \
38  catch(const BDocException& e) { printf("Caught BDocException: %s\n", parseException(e).c_str()); } \
39  catch(const IOException& e) { printf("Caught IOException: %s\n", parseException(e).c_str()); } \
40  catch(const SignException& e) { printf("Caught SignException: %s\n", parseException(e).c_str()); } \
41  catch(const SignatureException& e) { printf("Caught SignatureException: %s\n", parseException(e).c_str()); } \
42  catch(const Exception& e) { printf("Caught Exception: %s\n", parseException(e).c_str()); } \
43  catch(...) { printf("Caught unknown exception\n"); }
44 
45 using namespace digidoc;
46 
47 const char* CERT_STATUSES[3] = { "GOOD", "REVOKED", "UNKNOWN" };
48 
49 static std::string decodeParameter(const std::string &param)
50 {
51  if(param.empty())
52  return std::string();
53 #ifdef _WIN32
54  int len = MultiByteToWideChar(CP_ACP, 0, param.data(), int(param.size()), 0, 0);
55  std::wstring out(len, 0);
56  len = MultiByteToWideChar(CP_ACP, 0, param.data(), int(param.size()), &out[0], len);
57  return util::File::decodeName(out);
58 #else
59  return util::File::decodeName(param);
60 #endif
61 }
62 
63 
69 {
70 public:
71  DemoEstEIDConsolePinSigner(const std::string &driver, const std::string &pin) throw(SignException);
73 
74 private:
75  std::string getPin(const PKCS11Cert &certificate) throw(SignException);
76  PKCS11Signer::PKCS11Cert selectSigningCertificate(
77  const std::vector<PKCS11Signer::PKCS11Cert> &certificates) const throw(SignException);
78  void printPKCS11Cert(const PKCS11Signer::PKCS11Cert &cert) const;
79 
80  std::string m_pin;
81 };
82 
83 
84 
88 void printUsage(const char *executable)
89 {
90  printf("Usage: %s COMMAND [OPTIONS FILE]\n\n", executable);
91  printf(" Command create:\n");
92  printf(" Example: %s create --file=file1.txt --file=file2.txt --profile=TM demo-container.bdoc\n", executable);
93  printf(" Available options:\n");
94  printf(" --file - The option can occur multiple times. File(s) to be signed\n");
95  printf(" --city - optional, city of production place\n");
96  printf(" --state - optional, state of production place\n");
97  printf(" --postalCode - optional, postalCode of production place\n");
98  printf(" --country - optional, country of production place\n");
99  printf(" --role - optional, option can occur multiple times. Signer role(s)\n");
100 #ifdef _WIN32
101  printf(" --cng - optional, Use CNG api for signing under windows.\n");
102  printf(" --selectFirst - optional, Select first certificate in store.\n");
103 #endif
104  printf(" --pkcs11Driver - optional, default is '%s'. Path of PKCS11 driver.\n", Conf::getInstance()->getPKCS11DriverPath().c_str());
105  printf(" --pin - optional, default asks pin from prompt\n");
106  printf(" --profile - optional, default TM. Signing profile, available values: BES, TM\n");
107  printf(" Command open:\n");
108  printf(" Example: %s open --list --validateOnline container-file.bdoc\n", executable);
109  printf(" Available options:\n");
110  printf(" --extractAll - extracts documents (to path when provided)\n");
111  printf(" --list - lists documents and signatures\n");
112  printf(" --validateOnline - Whether online validate all signatures\n");
113  printf(" Command sign:\n");
114  printf(" Example: %s sign --profile=TM demo-container.bdoc\n", executable);
115  printf(" Available options:\n");
116  printf(" --city - optional, city of production place\n");
117  printf(" --state - optional, state of production place\n");
118  printf(" --postalCode - optional, postalCode of production place\n");
119  printf(" --country - optional, country of production place\n");
120  printf(" --role - optional, option can occur multiple times. Signer role(s)\n");
121 #ifdef _WIN32
122  printf(" --cng - optional, Use CNG api for signing under windows.\n");
123  printf(" --selectFirst - optional, Select first certificate in store.\n");
124 #endif
125  printf(" --pkcs11Driver - optional, default is '%s'. Path of PKCS11 driver.\n", Conf::getInstance()->getPKCS11DriverPath().c_str());
126  printf(" --pin - optional, default asks pin from prompt\n");
127  printf(" --profile - optional, default TM. Signing profile, available values: BES, TM\n");
128 }
129 
130 std::string parseException(const Exception &e)
131 {
132  std::string result = e.getMsg() + "\n";
133  for(size_t i = 0; i < e.getCauses().size(); ++i)
134  result += parseException(e.getCauses()[i]);
135  return result;
136 }
137 
152 int open(int argc, char* argv[])
153 {
154  bool validateOnline = false, listContent = false, extractAll = false;
155  std::string path, extractPath;
156  bool validStatus = true, extractStatus = true;
157 
158  // Parse command line arguments.
159  for(int i = 2; i < argc; i++)
160  {
161  std::string arg( decodeParameter( argv[i] ) );
162  if(arg.find("--validateOnline") == 0)
163  {
164  validateOnline = true;
165  }
166  else if(arg.find("--list") == 0)
167  {
168  listContent = true;
169  }
170  else if(arg.find("--extractAll") == 0)
171  {
172  extractAll = true;
173  size_t pos = arg.find("=");
174  if(pos != std::string::npos)
175  extractPath = arg.substr(pos + 1);
176  }
177  else
178  path = arg;
179  }
180 
181  if(path.empty())
182  {
183  printUsage(argv[0]);
184  return FAILURE;
185  }
186 
187  try
188  {
189  // Open BDOC container.
190  BDoc bdoc(path);
191 
192  if(extractAll)
193  {
194  printf("Extracting documents:\n");
195  for(unsigned int i = 0; i < bdoc.documentCount(); ++i)
196  {
197  try {
198  Document doc = bdoc.getDocument(i);
199  std::string dst = extractPath.empty() ? doc.getFileName() : extractPath + "/" + doc.getFileName();
200  doc.saveAs(dst);
201  printf(" Document %u (%s) extracted to %s (%lu bytes)\n", i, doc.getMediaType().c_str(), dst.c_str(), doc.getSize());
202  }
203  catch(...) {
204  printf(" Document %u extraction: FAILED\n", i);
205  extractStatus = false;
206  }
207  }
208  }
209 
210  if(listContent)
211  {
212  // Print container document list.
213  printf("Documents (%u):\n", bdoc.documentCount());
214  for(unsigned int i = 0; i < bdoc.documentCount(); i++)
215  {
216  Document doc = bdoc.getDocument(i);
217  printf(" Document %u (%s): %s (%lu bytes)\n", i, doc.getMediaType().c_str(), doc.getFileName().c_str(), doc.getSize());
218  }
219 
220  // Print container signatures list.
221  printf("\nSignatures (%u):\n", bdoc.signatureCount());
222 
223  for(unsigned int i = 0; i < bdoc.signatureCount(); i++)
224  {
225  // Get signature from bdoc cotainer.
226  const Signature* sig = bdoc.getSignature(i);
227 
228  printf(" Signature %u (%s):\n", i, sig->getMediaType().c_str());
229 
230  // Validate signature offine. Checks, whether signature format is correct
231  // and signed documents checksums are correct.
232  try
233  {
234  sig->validateOffline();
235  printf(" Offline validation: OK\n");
236  }
237  catch(const SignatureException& e)
238  {
239  // If signature is not offline valid, other data fields can not be read from it.
240  printf(" Offline validation: FAILED\n");
241  printf(" Exception:\n%s\n", parseException(e).c_str());
242  validStatus = false;
243  }
244 
245  // Validate signature online. Checks the validity of the certificate used to sign the bdoc container.
246  if(validateOnline)
247  {
248  try
249  {
250  printf(" Online validation: %s\n", CERT_STATUSES[sig->validateOnline()]);
251  }
252  catch(const SignatureException& e)
253  {
254  printf(" Online validation: FAILED\n");
255  printf(" Exception:\n%s\n", parseException(e).c_str());
256  validStatus = false;
257  }
258  }
259 
260  // Get signature production place info.
262  if(!spp.isEmpty())
263  {
264  printf(" Signature production place:\n");
265  printf(" Country: %s\n", spp.countryName.c_str());
266  printf(" State or Province: %s\n", spp.stateOrProvince.c_str());
267  printf(" City: %s\n", spp.city.c_str());
268  printf(" Postal code: %s\n", spp.postalCode.c_str());
269  }
270 
271  // Get signer role info.
272  SignerRole roles = sig->getSignerRole();
273  if(!roles.isEmpty())
274  {
275  printf(" Signer role(s):\n");
276  for(std::vector<std::string>::const_iterator iter = roles.claimedRoles.begin(); iter != roles.claimedRoles.end(); iter++)
277  printf(" %s\n", iter->c_str());
278  }
279 
280  printf(" Signing time: %s\n", sig->getSigningTime().c_str());
281  printf(" Signing cert: %s\n", sig->getSigningCertificate().getSubjectName("CN").c_str());
282  }
283 
284  }
285  }
287 
288  return validStatus && extractStatus ? SUCCESS : FAILURE;
289 }
290 
298 int create(int argc, char* argv[])
299 {
300  std::string path, pkcs11Driver, pin, city, state, postalCode, country;
301  std::vector<std::string> files, roles;
302  BDoc::Type profile = BDoc::TM;
303  int returnCode = FAILURE;
304 #ifdef _WIN32
305  bool cng = false, selectFirst = false;
306 #endif
307  Signer *signer = 0;
308 
309  // Parse command line arguments.
310  for(int i = 2; i < argc; i++)
311  {
312  std::string arg( decodeParameter( argv[i] ) );
313 
314  if(arg.find("--file=") == 0)
315  {
316  files.push_back(arg.substr(7));
317  }
318  else if(arg.find("--profile=") == 0)
319  {
320  arg = arg.substr(10);
321  if(std::string("BES") == arg) { profile = BDoc::BES; }
322  else if(std::string("TM") == arg) { profile = BDoc::TM; }
323  else
324  {
325  printUsage(argv[0]);
326  return FAILURE;
327  }
328  }
329 #ifdef _WIN32
330  else if(arg.find("--cng") == 0)
331  cng = true;
332  else if(arg.find("--selectFirst") == 0)
333  selectFirst = true;
334 #endif
335  else if(arg.find("--pkcs11Driver=") == 0)
336  pkcs11Driver = arg.substr(15);
337  else if(arg.find("--pin=") == 0)
338  pin = arg.substr(6);
339  else if(arg.find("--city=") == 0)
340  city = arg.substr(7);
341  else if(arg.find("--state=") == 0)
342  state = arg.substr(8);
343  else if(arg.find("--postalCode=") == 0)
344  postalCode = arg.substr(13);
345  else if(arg.find("--country=") == 0)
346  country = arg.substr(10);
347  else if(arg.find("--role=") == 0)
348  roles.push_back(arg.substr(7));
349  else
350  path = arg;
351  }
352 
353  // No bdoc container path given or no files given to sign
354  if(path.empty() || files.empty())
355  {
356  printUsage(argv[0]);
357  return FAILURE;
358  }
359 
360  try
361  {
362  if(pkcs11Driver.empty())
363  pkcs11Driver = Conf::getInstance()->getPKCS11DriverPath();
364 
365  // Create new BDOC container.
366  BDoc bdoc;
367 
368  // Add all the documents to the container.
369  for(std::vector<std::string>::const_iterator iter = files.begin(); iter != files.end(); iter++)
370  bdoc.addDocument(Document(*iter, "file"));
371 
372  // Initialize signer implementation.
373 #ifdef _WIN32
374  if(cng)
375  signer = new CNGSigner(pin, selectFirst);
376  else
377 #endif
378  signer = new DemoEstEIDConsolePinSigner(pkcs11Driver, pin);
379 
380  // Add signature production place.
381  if(!city.empty() || !state.empty() || !postalCode.empty() || !country.empty())
382  {
383  SignatureProductionPlace spp(city, state, postalCode, country);
384  signer->setSignatureProductionPlace(spp);
385  }
386 
387  // Add signer role(s).
388  if(!roles.empty())
389  {
390  SignerRole role;
391  role.claimedRoles = roles;
392  signer->setSignerRole(role);
393  }
394 
395  // Sign the BDOC container.
396  bdoc.sign(signer, profile);
397 
398  // Save the BDOC container.
399  bdoc.saveTo(path);
400 
401  returnCode = SUCCESS;
402  }
404  delete signer;
405 
406  return returnCode;
407 }
408 
416 int sign(int argc, char* argv[])
417 {
418  std::string path, pkcs11Driver, pin, city, state, postalCode, country;
419  std::vector<std::string> roles;
420  BDoc::Type profile = BDoc::TM;
421  int returnCode = FAILURE;
422 #ifdef _WIN32
423  bool cng = false, selectFirst = false;
424 #endif
425  Signer *signer = 0;
426 
427  // Parse command line arguments.
428  for(int i = 2; i < argc; i++)
429  {
430  std::string arg( decodeParameter( argv[i] ) );
431 
432  if(arg.find("--profile=") == 0)
433  {
434  arg = arg.substr(10);
435  if(std::string("BES") == arg) { profile = BDoc::BES; }
436  else if(std::string("TM") == arg) { profile = BDoc::TM; }
437  else
438  {
439  printUsage(argv[0]);
440  return FAILURE;
441  }
442  }
443 #ifdef _WIN32
444  else if(arg.find("--cng") == 0)
445  cng = true;
446  else if(arg.find("--selectFirst") == 0)
447  selectFirst = true;
448 #endif
449  else if(arg.find("--pkcs11Driver=") == 0)
450  pkcs11Driver = arg.substr(15);
451  else if(arg.find("--pin=") == 0)
452  pin = arg.substr(6);
453  else if(arg.find("--city=") == 0)
454  city = arg.substr(7);
455  else if(arg.find("--state=") == 0)
456  state = arg.substr(8);
457  else if(arg.find("--postalCode=") == 0)
458  postalCode = arg.substr(13);
459  else if(arg.find("--country=") == 0)
460  country = arg.substr(10);
461  else if(arg.find("--role=") == 0)
462  roles.push_back(arg.substr(7));
463  else
464  path = arg;
465  }
466 
467  // No bdoc container path given.
468  if(path.empty())
469  {
470  printUsage(argv[0]);
471  return FAILURE;
472  }
473 
474  try
475  {
476  if(pkcs11Driver.empty())
477  pkcs11Driver = Conf::getInstance()->getPKCS11DriverPath();
478 
479  // Create new BDOC container.
480  BDoc bdoc(path);
481 
482  // Initialize signer implementation.
483 #ifdef _WIN32
484  if(cng)
485  signer = new CNGSigner(pin, selectFirst);
486  else
487 #endif
488  signer = new DemoEstEIDConsolePinSigner(pkcs11Driver, pin);
489 
490  // Add signature production place.
491  if(!city.empty() || !state.empty() || !postalCode.empty() || !country.empty())
492  {
493  SignatureProductionPlace spp(city, state, postalCode, country);
494  signer->setSignatureProductionPlace(spp);
495  }
496 
497  // Add signer role(s).
498  if(!roles.empty())
499  {
500  SignerRole role;
501  role.claimedRoles = roles;
502  signer->setSignerRole(role);
503  }
504 
505  // Sign the BDOC container.
506  bdoc.sign(signer, profile);
507 
508  // Save the BDOC container.
509  bdoc.saveTo(path);
510 
511  returnCode = SUCCESS;
512  }
514  delete signer;
515 
516  return returnCode;
517 }
518 
526 DemoEstEIDConsolePinSigner::DemoEstEIDConsolePinSigner(const std::string &driver, const std::string &pin) throw(SignException)
527  : EstEIDConsolePinSigner(driver)
528  , m_pin(pin)
529 {
530 }
531 
532 std::string DemoEstEIDConsolePinSigner::getPin(const PKCS11Cert &certificate) throw(SignException)
533 {
534  return m_pin.empty() ? EstEIDConsolePinSigner::getPin(certificate) : m_pin;
535 }
536 
545  const std::vector<PKCS11Signer::PKCS11Cert> &certificates) const throw(SignException)
546 {
547  printf("Available certificates:\n");
548  for(std::vector<PKCS11Signer::PKCS11Cert>::const_iterator iter = certificates.begin(); iter != certificates.end(); iter++)
549  printPKCS11Cert(*iter);
551  printf("Selected:\n");
552  printPKCS11Cert(cert);
553  return cert;
554 }
555 
562 {
563  printf(" -------------------------------------------------------\n");
564  printf(" token label: %s\n", cert.token.label.c_str());
565  printf(" token manufacturer: %s\n", cert.token.manufacturer.c_str());
566  printf(" token model: %s\n", cert.token.model.c_str());
567  printf(" token serial Nr: %s\n", cert.token.serialNr.c_str());
568  printf(" label: %s\n", cert.label.c_str());
569 }
570 
578 int main(int argc, char* argv[])
579 {
580  int returnCode = FAILURE;
581 
583 
584  printf("Version\n");
585  printf(" digidoc-tool version: %s\n", VER_STR(MAJOR_VER.MINOR_VER.RELEASE_VER.BUILD_VER));
586  printf(" libdigidocpp version: %s\n", digidoc::version().c_str());
587 
588  if(argc < 2)
589  {
590  printUsage(argv[0]);
591  return FAILURE;
592  }
593 
594  std::string command(argv[1]);
595 
596  if(command.compare("open") == 0)
597  returnCode = open(argc, argv);
598  else if(command.compare("create") == 0)
599  returnCode = create(argc, argv);
600  else if(command.compare("sign") == 0)
601  returnCode = sign(argc, argv);
602  else if(command.compare("version") == 0)
603  returnCode = SUCCESS;
604  else
605  printUsage(argv[0]);
606 
608 
609  return returnCode;
610 }