blob: 465df4a22205d44547b1aebd3381d42b0932f668 [file] [log] [blame]
NingSun0c89b3c2018-02-08 08:34:03 -08001/*
2 * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27/*****************************************************************************
28 softhsm2-util.cpp
29
30 This program can be used for interacting with HSMs using PKCS#11.
31 The default library is the libsofthsm2.so
32 *****************************************************************************/
33
34#include <config.h>
35#include "softhsm2-util.h"
36#include "findslot.h"
37#include "getpw.h"
38#include "library.h"
39#include "log.h"
40#include "Configuration.h"
41#include "SimpleConfigLoader.h"
42#include "Directory.h"
43#include "MutexFactory.h"
44#include "ObjectStoreToken.h"
45#include "OSPathSep.h"
46
47#if defined(WITH_OPENSSL)
48#include "OSSLCryptoFactory.h"
49#else
50#include "BotanCryptoFactory.h"
51#endif
52
53#include <stdio.h>
54#include <stdlib.h>
55#include <getopt.h>
56#include <string.h>
57#ifndef _WIN32
58#include <unistd.h>
59#include <sys/types.h>
60#include <sys/stat.h>
61#include <dirent.h>
62#else
63#include <direct.h>
64#include <io.h>
65#endif
66#include <iostream>
67#include <fstream>
68
69// Initialise the one-and-only instance
70
71#ifdef HAVE_CXX11
72
73std::unique_ptr<MutexFactory> MutexFactory::instance(nullptr);
74std::unique_ptr<SecureMemoryRegistry> SecureMemoryRegistry::instance(nullptr);
75#if defined(WITH_OPENSSL)
76std::unique_ptr<OSSLCryptoFactory> OSSLCryptoFactory::instance(nullptr);
77#else
78std::unique_ptr<BotanCryptoFactory> BotanCryptoFactory::instance(nullptr);
79#endif
80
81#else
82
83std::auto_ptr<MutexFactory> MutexFactory::instance(NULL);
84std::auto_ptr<SecureMemoryRegistry> SecureMemoryRegistry::instance(NULL);
85#if defined(WITH_OPENSSL)
86std::auto_ptr<OSSLCryptoFactory> OSSLCryptoFactory::instance(NULL);
87#else
88std::auto_ptr<BotanCryptoFactory> BotanCryptoFactory::instance(NULL);
89#endif
90
91#endif
92
93// Display the usage
94void usage()
95{
96 printf("Support tool for PKCS#11\n");
97 printf("Usage: softhsm2-util [ACTION] [OPTIONS]\n");
98 printf("Action:\n");
99 printf(" --delete-token Delete the token at a given slot.\n");
100 printf(" Use with --token or --serial.\n");
101 printf(" WARNING: Any content in token will be erased.\n");
102 printf(" -h Shows this help screen.\n");
103 printf(" --help Shows this help screen.\n");
104 printf(" --import <path> Import a key pair from the given path.\n");
105 printf(" The file must be in PKCS#8-format.\n");
106 printf(" Use with --slot or --token or --serial, --file-pin,\n");
107 printf(" --label, --id, --no-public-key, and --pin.\n");
108 printf(" --init-token Initialize the token at a given slot.\n");
109 printf(" Use with --slot or --token or --serial or --free,\n");
110 printf(" --label, --so-pin, and --pin.\n");
111 printf(" WARNING: Any content in token will be erased.\n");
112 printf(" --show-slots Display all the available slots.\n");
113 printf(" -v Show version info.\n");
114 printf(" --version Show version info.\n");
115 printf("Options:\n");
116 printf(" --aes Used to tell import to use file as is and import it as AES.\n");
117 printf(" --file-pin <PIN> Supply a PIN if the file is encrypted.\n");
118 printf(" --force Used to override a warning.\n");
119 printf(" --free Use the first free/uninitialized token.\n");
120 printf(" --id <hex> Defines the ID of the object. Hexadecimal characters.\n");
121 printf(" Use with --force if multiple key pairs may share\n");
122 printf(" the same ID.\n");
123 printf(" --label <text> Defines the label of the object or the token.\n");
124 printf(" --module <path> Use another PKCS#11 library than SoftHSM.\n");
125 printf(" --no-public-key Do not import the public key.\n");
126 printf(" --pin <PIN> The PIN for the normal user.\n");
127 printf(" --serial <number> Will use the token with a matching serial number.\n");
128 printf(" --slot <number> The slot where the token is located.\n");
129 printf(" --so-pin <PIN> The PIN for the Security Officer (SO).\n");
130 printf(" --token <label> Will use the token with a matching token label.\n");
131}
132
133// Enumeration of the long options
134enum {
135 OPT_DELETE_TOKEN = 0x100,
136 OPT_FILE_PIN,
137 OPT_FORCE,
138 OPT_FREE,
139 OPT_HELP,
140 OPT_ID,
141 OPT_IMPORT,
142 OPT_INIT_TOKEN,
143 OPT_LABEL,
144 OPT_MODULE,
145 OPT_NO_PUBLIC_KEY,
146 OPT_PIN,
147 OPT_SERIAL,
148 OPT_SHOW_SLOTS,
149 OPT_SLOT,
150 OPT_SO_PIN,
151 OPT_TOKEN,
152 OPT_VERSION,
153 OPT_AES
154};
155
156// Text representation of the long options
157static const struct option long_options[] = {
158 { "delete-token", 0, NULL, OPT_DELETE_TOKEN },
159 { "file-pin", 1, NULL, OPT_FILE_PIN },
160 { "force", 0, NULL, OPT_FORCE },
161 { "free", 0, NULL, OPT_FREE },
162 { "help", 0, NULL, OPT_HELP },
163 { "id", 1, NULL, OPT_ID },
164 { "import", 1, NULL, OPT_IMPORT },
165 { "init-token", 0, NULL, OPT_INIT_TOKEN },
166 { "label", 1, NULL, OPT_LABEL },
167 { "module", 1, NULL, OPT_MODULE },
168 { "no-public-key", 0, NULL, OPT_NO_PUBLIC_KEY },
169 { "pin", 1, NULL, OPT_PIN },
170 { "serial", 1, NULL, OPT_SERIAL },
171 { "show-slots", 0, NULL, OPT_SHOW_SLOTS },
172 { "slot", 1, NULL, OPT_SLOT },
173 { "so-pin", 1, NULL, OPT_SO_PIN },
174 { "token", 1, NULL, OPT_TOKEN },
175 { "version", 0, NULL, OPT_VERSION },
176 { "aes", 0, NULL, OPT_AES },
177 { NULL, 0, NULL, 0 }
178};
179
180CK_FUNCTION_LIST_PTR p11;
181
182// The main function
183int main(int argc, char* argv[])
184{
185 int option_index = 0;
186 int opt;
187
188 char* inPath = NULL;
189 char* soPIN = NULL;
190 char* userPIN = NULL;
191 char* filePIN = NULL;
192 char* label = NULL;
193 char* module = NULL;
194 char* objectID = NULL;
195 char* slot = NULL;
196 char* serial = NULL;
197 char* token = NULL;
198 char* errMsg = NULL;
199 int forceExec = 0;
200 bool freeToken = false;
201 int noPublicKey = 0;
202 bool importAES = false;
203
204 int doInitToken = 0;
205 int doShowSlots = 0;
206 int doImport = 0;
207 int doDeleteToken = 0;
208 int action = 0;
209 bool needP11 = false;
210 int rv = 0;
211 CK_SLOT_ID slotID = 0;
212
213 moduleHandle = NULL;
214 p11 = NULL;
215
216 while ((opt = getopt_long(argc, argv, "hv", long_options, &option_index)) != -1)
217 {
218 switch (opt)
219 {
220 case OPT_SHOW_SLOTS:
221 doShowSlots = 1;
222 action++;
223 needP11 = true;
224 break;
225 case OPT_INIT_TOKEN:
226 doInitToken = 1;
227 action++;
228 needP11 = true;
229 break;
230 case OPT_IMPORT:
231 doImport = 1;
232 action++;
233 inPath = optarg;
234 needP11 = true;
235 break;
236 case OPT_AES:
237 importAES = true;
238 break;
239 case OPT_DELETE_TOKEN:
240 doDeleteToken = 1;
241 action++;
242 break;
243 case OPT_SLOT:
244 slot = optarg;
245 break;
246 case OPT_LABEL:
247 label = optarg;
248 break;
249 case OPT_SERIAL:
250 serial = optarg;
251 break;
252 case OPT_TOKEN:
253 token = optarg;
254 break;
255 case OPT_MODULE:
256 module = optarg;
257 break;
258 case OPT_NO_PUBLIC_KEY:
259 noPublicKey = 1;
260 break;
261 case OPT_ID:
262 objectID = optarg;
263 break;
264 case OPT_SO_PIN:
265 soPIN = optarg;
266 break;
267 case OPT_PIN:
268 userPIN = optarg;
269 break;
270 case OPT_FILE_PIN:
271 filePIN = optarg;
272 break;
273 case OPT_FORCE:
274 forceExec = 1;
275 break;
276 case OPT_FREE:
277 freeToken = true;
278 break;
279 case OPT_VERSION:
280 case 'v':
281 printf("%s\n", PACKAGE_VERSION);
282 exit(0);
283 break;
284 case OPT_HELP:
285 case 'h':
286 default:
287 usage();
288 exit(0);
289 break;
290 }
291 }
292
293 // No action given, display the usage.
294 if (action != 1)
295 {
296 usage();
297 exit(1);
298 }
299
300 if (needP11)
301 {
302 // Check the basic setup of SoftHSM
303 if (!checkSetup())
304 {
305 fprintf(stderr, "ERROR: Please verify that the SoftHSM configuration is correct.\n");
306 exit(1);
307 }
308
309 // Get a pointer to the function list for PKCS#11 library
310 CK_C_GetFunctionList pGetFunctionList = loadLibrary(module, &moduleHandle, &errMsg);
311 if (!pGetFunctionList)
312 {
313 fprintf(stderr, "ERROR: Could not load the PKCS#11 library/module: %s\n", errMsg);
314 fprintf(stderr, "ERROR: Please check log files for additional information.\n");
315 exit(1);
316 }
317
318 // Load the function list
319 (*pGetFunctionList)(&p11);
320
321 // Initialize the library
322 CK_RV p11rv = p11->C_Initialize(NULL_PTR);
323 if (p11rv != CKR_OK)
324 {
325 fprintf(stderr, "ERROR: Could not initialize the PKCS#11 library/module: %s\n", module ? module : DEFAULT_PKCS11_LIB);
326 fprintf(stderr, "ERROR: Please check log files for additional information.\n");
327 exit(1);
328 }
329 }
330
331 // We should create the token.
332 if (doInitToken)
333 {
334 // Get the slotID
335 rv = findSlot(slot, serial, token, freeToken, slotID);
336 if (!rv)
337 {
338 rv = initToken(slotID, label, soPIN, userPIN);
339 }
340 }
341
342 // Show all available slots
343 if (!rv && doShowSlots)
344 {
345 rv = showSlots();
346 }
347
348 // Import a key pair from the given path
349 if (!rv && doImport)
350 {
351 // Get the slotID
352 rv = findSlot(slot, serial, token, slotID);
353 if (!rv)
354 {
355 rv = importAES ? importSecretKey(inPath, slotID, userPIN, label, objectID)
356 : importKeyPair(inPath, filePIN, slotID, userPIN, label, objectID, forceExec, noPublicKey);
357 }
358 }
359
360 // We should delete the token.
361 if (!rv && doDeleteToken)
362 {
363 if (deleteToken(serial, token))
364 {
365 rv = 0;
366 }
367 else
368 {
369 rv = 1;
370 }
371 }
372
373 // Finalize the library
374 if (needP11)
375 {
376 p11->C_Finalize(NULL_PTR);
377 unloadLibrary(moduleHandle);
378 }
379
380 return rv;
381}
382
383// Check the basic setup of SoftHSM
384bool checkSetup()
385{
386 // Initialize the SoftHSM internal functions
387 if (!initSoftHSM())
388 {
389 finalizeSoftHSM();
390 return false;
391 }
392
393 std::string basedir = Configuration::i()->getString("directories.tokendir", DEFAULT_TOKENDIR);
394
395 // Try open the token directory
396 Directory storeDir(basedir);
397 if (!storeDir.isValid())
398 {
399 fprintf(stderr, "ERROR: Failed to enumerate object store in %s\n", basedir.c_str());
400 finalizeSoftHSM();
401 return false;
402 }
403
404 finalizeSoftHSM();
405 return true;
406}
407
408// Initialize the token
409int initToken(CK_SLOT_ID slotID, char* label, char* soPIN, char* userPIN)
410{
411 char so_pin_copy[MAX_PIN_LEN+1];
412 char user_pin_copy[MAX_PIN_LEN+1];
413
414 if (label == NULL)
415 {
416 fprintf(stderr, "ERROR: A label for the token must be supplied. "
417 "Use --label <text>\n");
418 return 1;
419 }
420
421 if (strlen(label) > 32)
422 {
423 fprintf(stderr, "ERROR: The token label must not have a length "
424 "greater than 32 chars.\n");
425 return 1;
426 }
427
428 // Get the passwords
429 if (getPW(soPIN, so_pin_copy, CKU_SO) != 0)
430 {
431 fprintf(stderr, "ERROR: Could not get SO PIN\n");
432 return 1;
433 }
434 if (getPW(userPIN, user_pin_copy, CKU_USER) != 0)
435 {
436 fprintf(stderr, "ERROR: Could not get user PIN\n");
437 return 1;
438 }
439
440 // Load the variables
441 CK_UTF8CHAR paddedLabel[32];
442 memset(paddedLabel, ' ', sizeof(paddedLabel));
443 memcpy(paddedLabel, label, strlen(label));
444
445 CK_RV rv = p11->C_InitToken(slotID, (CK_UTF8CHAR_PTR)so_pin_copy, strlen(so_pin_copy), paddedLabel);
446
447 switch (rv)
448 {
449 case CKR_OK:
450 break;
451 case CKR_SLOT_ID_INVALID:
452 fprintf(stderr, "CKR_SLOT_ID_INVALID: Slot %lu does not exist.\n", slotID);
453 return 1;
454 break;
455 case CKR_PIN_INCORRECT:
456 fprintf(stderr, "CKR_PIN_INCORRECT: The given SO PIN does not match the "
457 "one in the token. Needed when reinitializing the token.\n");
458 return 1;
459 break;
460 case CKR_TOKEN_NOT_PRESENT:
461 fprintf(stderr, "CKR_TOKEN_NOT_PRESENT: The token is not present. "
462 "Please read the HSM manual for further assistance.\n");
463 return 1;
464 break;
465 default:
466 fprintf(stderr, "ERROR rv=0x%08X: Could not initialize the token.\n", (unsigned int)rv);
467 fprintf(stderr, "Please check log files for additional information.\n");
468 return 1;
469 break;
470 }
471
472 CK_SESSION_HANDLE hSession;
473 rv = p11->C_OpenSession(slotID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &hSession);
474 if (rv != CKR_OK)
475 {
476 fprintf(stderr, "ERROR: Could not open a session with the library.\n");
477 return 1;
478 }
479
480 rv = p11->C_Login(hSession, CKU_SO, (CK_UTF8CHAR_PTR)so_pin_copy, strlen(so_pin_copy));
481 if (rv != CKR_OK)
482 {
483 fprintf(stderr, "ERROR: Could not log in on the token.\n");
484 return 1;
485 }
486
487 rv = p11->C_InitPIN(hSession, (CK_UTF8CHAR_PTR)user_pin_copy, strlen(user_pin_copy));
488 if (rv != CKR_OK)
489 {
490 fprintf(stderr, "ERROR: Could not initialize the user PIN.\n");
491 return 1;
492 }
493
494 // Get the token info
495 CK_TOKEN_INFO tokenInfo;
496 rv = p11->C_GetTokenInfo(slotID, &tokenInfo);
497 if (rv != CKR_OK)
498 {
499 fprintf(stderr, "ERROR: Could not get info about the initialized token in slot %lu.\n", slotID);
500 return 1;
501 }
502
503 // Reload the library
504 p11->C_Finalize(NULL_PTR);
505 rv = p11->C_Initialize(NULL_PTR);
506 if (rv != CKR_OK)
507 {
508 fprintf(stderr, "ERROR: Could not initialize the library.\n");
509 return 1;
510 }
511
512 // Get the slotID
513 CK_SLOT_ID newSlotID;
514 if (findSlot(tokenInfo, newSlotID))
515 {
516 return 1;
517 }
518
519 if (slotID == newSlotID)
520 {
521 printf("The token has been initialized on slot %lu\n", newSlotID);
522 }
523 else
524 {
525 printf("The token has been initialized and is reassigned to slot %lu\n", newSlotID);
526 }
527
528 return 0;
529}
530
531// Delete the token
532bool deleteToken(char* serial, char* token)
533{
534 if (serial == NULL && token == NULL)
535 {
536 fprintf(stderr, "ERROR: A token must be supplied. "
537 "Use --serial <serial> or --token <label>\n");
538 return false;
539 }
540
541 // Initialize the SoftHSM internal functions
542 if (!initSoftHSM())
543 {
544 finalizeSoftHSM();
545 return false;
546 }
547
548 bool rv = true;
549 std::string basedir = Configuration::i()->getString("directories.tokendir", DEFAULT_TOKENDIR);
550 std::string tokendir;
551
552 rv = findTokenDirectory(basedir, tokendir, serial, token);
553
554 if (rv)
555 {
556 std::string fulldir = basedir;
557 if (fulldir.find_last_of(OS_PATHSEP) != (fulldir.size()-1))
558 {
559 fulldir += OS_PATHSEP + tokendir;
560 }
561 else
562 {
563 fulldir += tokendir;
564 }
565
566 rv = rmdir(fulldir);
567 if (rv)
568 {
569 printf("The token (%s) has been deleted.\n", fulldir.c_str());
570 }
571 }
572
573 finalizeSoftHSM();
574
575 return rv;
576}
577
578bool initSoftHSM()
579{
580 // Not using threading
581 MutexFactory::i()->disable();
582
583 // Initiate SecureMemoryRegistry
584 if (SecureMemoryRegistry::i() == NULL)
585 {
586 fprintf(stderr, "ERROR: Could not initiate SecureMemoryRegistry.\n");
587 return false;
588 }
589
590 // Build the CryptoFactory
591 if (CryptoFactory::i() == NULL)
592 {
593 fprintf(stderr, "ERROR: Could not initiate CryptoFactory.\n");
594 return false;
595 }
596
597#ifdef WITH_FIPS
598 // Check the FIPS status
599 if (!CryptoFactory::i()->getFipsSelfTestStatus())
600 {
601 fprintf(stderr, "ERROR: FIPS self test failed.\n");
602 return false;
603 }
604#endif
605
606 // Load the configuration
607 if (!Configuration::i()->reload(SimpleConfigLoader::i()))
608 {
609 fprintf(stderr, "ERROR: Could not load the SoftHSM configuration.\n");
610 return false;
611 }
612
613 // Configure the log level
614 if (!setLogLevel(Configuration::i()->getString("log.level", DEFAULT_LOG_LEVEL)))
615 {
616 fprintf(stderr, "ERROR: Could not configure the log level.\n");
617 return false;
618 }
619
620 // Configure object store storage backend used by all tokens.
621 if (!ObjectStoreToken::selectBackend(Configuration::i()->getString("objectstore.backend", DEFAULT_OBJECTSTORE_BACKEND)))
622 {
623 fprintf(stderr, "ERROR: Could not select token backend.\n");
624 return false;
625 }
626
627 return true;
628}
629
630void finalizeSoftHSM()
631{
632 CryptoFactory::reset();
633 SecureMemoryRegistry::reset();
634}
635
636// Find the token directory
637bool findTokenDirectory(std::string basedir, std::string& tokendir, char* serial, char* label)
638{
639 if (serial == NULL && label == NULL)
640 {
641 return false;
642 }
643
644 // Load the variables
645 CK_UTF8CHAR paddedSerial[16];
646 CK_UTF8CHAR paddedLabel[32];
647 if (serial != NULL)
648 {
649 size_t inSize = strlen(serial);
650 size_t outSize = sizeof(paddedSerial);
651 if (inSize > outSize)
652 {
653 fprintf(stderr, "ERROR: --serial is too long.\n");
654 return false;
655 }
656 memset(paddedSerial, ' ', outSize);
657 memcpy(paddedSerial, serial, inSize);
658 }
659 if (label != NULL)
660 {
661 size_t inSize = strlen(label);
662 size_t outSize = sizeof(paddedLabel);
663 if (inSize > outSize)
664 {
665 fprintf(stderr, "ERROR: --token is too long.\n");
666 return false;
667 }
668 memset(paddedLabel, ' ', outSize);
669 memcpy(paddedLabel, label, inSize);
670 }
671
672 // Find all tokens in the specified path
673 Directory storeDir(basedir);
674
675 if (!storeDir.isValid())
676 {
677 fprintf(stderr, "Failed to enumerate object store in %s\n", basedir.c_str());
678
679 return false;
680 }
681
682 // Assume that all subdirectories are tokens
683 std::vector<std::string> dirs = storeDir.getSubDirs();
684
685 ByteString tokenLabel;
686 ByteString tokenSerial;
687 CK_UTF8CHAR paddedTokenSerial[16];
688 CK_UTF8CHAR paddedTokenLabel[32];
689 size_t counter = 0;
690 for (std::vector<std::string>::iterator i = dirs.begin(); i != dirs.end(); i++)
691 {
692 memset(paddedTokenSerial, ' ', sizeof(paddedTokenSerial));
693 memset(paddedTokenLabel, ' ', sizeof(paddedTokenLabel));
694
695 // Create a token instance
696 ObjectStoreToken* token = ObjectStoreToken::accessToken(basedir, *i);
697
698 if (!token->isValid())
699 {
700 delete token;
701 continue;
702 }
703
704 if (token->getTokenLabel(tokenLabel) && tokenLabel.size() <= sizeof(paddedTokenLabel))
705 {
706 strncpy((char*) paddedTokenLabel, (char*) tokenLabel.byte_str(), tokenLabel.size());
707 }
708 if (token->getTokenSerial(tokenSerial) && tokenSerial.size() <= sizeof(paddedTokenSerial))
709 {
710 strncpy((char*) paddedTokenSerial, (char*) tokenSerial.byte_str(), tokenSerial.size());
711 }
712
713 if (serial != NULL && label == NULL &&
714 memcmp(paddedTokenSerial, paddedSerial, sizeof(paddedSerial)) == 0)
715 {
716 printf("Found token (%s) with matching serial.\n", i->c_str());
717 tokendir = i->c_str();
718 counter++;
719 }
720 if (serial == NULL && label != NULL &&
721 memcmp(paddedTokenLabel, paddedLabel, sizeof(paddedLabel)) == 0)
722 {
723 printf("Found token (%s) with matching token label.\n", i->c_str());
724 tokendir = i->c_str();
725 counter++;
726 }
727 if (serial != NULL && label != NULL &&
728 memcmp(paddedTokenSerial, paddedSerial, sizeof(paddedSerial)) == 0 &&
729 memcmp(paddedTokenLabel, paddedLabel, sizeof(paddedLabel)) == 0)
730 {
731 printf("Found token (%s) with matching serial and token label.\n", i->c_str());
732 tokendir = i->c_str();
733 counter++;
734 }
735
736 delete token;
737 }
738
739 if (counter == 1) return true;
740 if (counter > 1)
741 {
742 fprintf(stderr, "ERROR: Found multiple matching tokens.\n");
743 return false;
744 }
745
746 fprintf(stderr, "ERROR: Could not find a token using --serial or --token.\n");
747 return false;
748}
749
750
751// Delete a directory
752bool rmdir(std::string path)
753{
754 bool rv = true;
755
756#ifndef _WIN32
757 // Enumerate the directory
758 DIR* dir = opendir(path.c_str());
759
760 if (dir == NULL)
761 {
762 fprintf(stderr, "ERROR: Failed to open directory %s\n", path.c_str());
763 return false;
764 }
765
766 // Enumerate the directory
767 struct dirent* entry = NULL;
768
769 while ((entry = readdir(dir)) != NULL)
770 {
771 bool handled = false;
772
773 // Check if this is the . or .. entry
774 if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
775 {
776 continue;
777 }
778
779 // Convert the name of the entry to a C++ string
780 std::string name(entry->d_name);
781 std::string fullPath = path + OS_PATHSEP + name;
782
783#if defined(_DIRENT_HAVE_D_TYPE) && defined(_BSD_SOURCE)
784 // Determine the type of the entry
785 switch(entry->d_type)
786 {
787 case DT_DIR:
788 // This is a directory
789 rv = rmdir(fullPath);
790 handled = true;
791 break;
792 case DT_REG:
793 // This is a regular file
794 rv = rm(fullPath);
795 handled = true;
796 break;
797 default:
798 break;
799 }
800#endif
801
802 if (rv == false)
803 break;
804
805 if (!handled)
806 {
807 // The entry type has to be determined using lstat
808 struct stat entryStatus;
809
810 if (!lstat(fullPath.c_str(), &entryStatus))
811 {
812 if (S_ISDIR(entryStatus.st_mode))
813 {
814 // This is a directory
815 rv = rmdir(fullPath);
816 }
817 else if (S_ISREG(entryStatus.st_mode))
818 {
819 // This is a regular file
820 rv = rm(fullPath);
821 }
822 }
823
824 if (rv == false)
825 break;
826 }
827 }
828
829 // Close the directory
830 closedir(dir);
831#else
832 // Enumerate the directory
833 std::string pattern;
834 intptr_t h;
835 struct _finddata_t fi;
836
837 if ((path.back() == '/') || (path.back() == '\\'))
838 pattern = path + "*";
839 else
840 pattern = path + "/*";
841 memset(&fi, 0, sizeof(fi));
842 h = _findfirst(pattern.c_str(), &fi);
843 if (h == -1)
844 {
845 // empty directory
846 if (errno == ENOENT)
847 goto finished;
848
849 fprintf(stderr, "ERROR: Failed to open directory %s\n", path.c_str());
850
851 return false;
852 }
853
854 // scan files & subdirs
855 do
856 {
857 // Check if this is the . or .. entry
858 if (!strcmp(fi.name, ".") || !strcmp(fi.name, ".."))
859 continue;
860
861 std::string fullPath = path + OS_PATHSEP + fi.name;
862 if ((fi.attrib & _A_SUBDIR) == 0)
863 {
864 // This is a regular file
865 rv = rm(fullPath);
866 }
867 else
868 {
869 // This is a directory
870 rv = rmdir(fullPath);
871 }
872
873 memset(&fi, 0, sizeof(fi));
874
875 if (rv == false)
876 break;
877 } while (_findnext(h, &fi) == 0);
878
879 (void) _findclose(h);
880
881 finished:
882#endif
883
884 if (rv == false)
885 return false;
886
887 int result;
888#ifndef _WIN32
889 result = ::rmdir(path.c_str());
890#else
891 result = _rmdir(path.c_str());
892#endif
893
894 if (result != 0)
895 {
896 fprintf(stderr, "ERROR: Could not delete the directory: %s\n", path.c_str());
897 return false;
898 }
899
900 return true;
901}
902
903// Delete a file
904bool rm(std::string path)
905{
906 int result;
907
908#ifndef _WIN32
909 result = ::remove(path.c_str());
910#else
911 result = _unlink(path.c_str());
912#endif
913
914 if (result != 0)
915 {
916 fprintf(stderr, "ERROR: Could not delete the file: %s\n", path.c_str());
917 return false;
918 }
919
920 return true;
921}
922
923// Show what slots are available
924int showSlots()
925{
926 CK_ULONG ulSlotCount;
927 CK_RV rv = p11->C_GetSlotList(CK_FALSE, NULL_PTR, &ulSlotCount);
928 if (rv != CKR_OK)
929 {
930 fprintf(stderr, "ERROR: Could not get the number of slots.\n");
931 return 1;
932 }
933
934 CK_SLOT_ID_PTR pSlotList = (CK_SLOT_ID_PTR) malloc(ulSlotCount*sizeof(CK_SLOT_ID));
935 if (!pSlotList)
936 {
937 fprintf(stderr, "ERROR: Could not allocate memory.\n");
938 return 1;
939 }
940
941 rv = p11->C_GetSlotList(CK_FALSE, pSlotList, &ulSlotCount);
942 if (rv != CKR_OK)
943 {
944 fprintf(stderr, "ERROR: Could not get the slot list.\n");
945 free(pSlotList);
946 return 1;
947 }
948
949 printf("Available slots:\n");
950
951 for (CK_ULONG i = 0; i < ulSlotCount; i++)
952 {
953 CK_SLOT_INFO slotInfo;
954 CK_TOKEN_INFO tokenInfo;
955
956 rv = p11->C_GetSlotInfo(pSlotList[i], &slotInfo);
957 if (rv != CKR_OK)
958 {
959 fprintf(stderr, "ERROR: Could not get info about slot %lu.\n", pSlotList[i]);
960 continue;
961 }
962
963 printf("Slot %lu\n", pSlotList[i]);
964 printf(" Slot info:\n");
965 printf(" Description: %.*s\n", 64, slotInfo.slotDescription);
966 printf(" Manufacturer ID: %.*s\n", 32, slotInfo.manufacturerID);
967 printf(" Hardware version: %i.%i\n", slotInfo.hardwareVersion.major,
968 slotInfo.hardwareVersion.minor);
969 printf(" Firmware version: %i.%i\n", slotInfo.firmwareVersion.major,
970 slotInfo.firmwareVersion.minor);
971 printf(" Token present: ");
972 if ((slotInfo.flags & CKF_TOKEN_PRESENT) == 0)
973 {
974 printf("no\n");
975 continue;
976 }
977
978 printf("yes\n");
979 printf(" Token info:\n");
980
981 rv = p11->C_GetTokenInfo(pSlotList[i], &tokenInfo);
982 if (rv != CKR_OK)
983 {
984 fprintf(stderr, "ERROR: Could not get info about the token in slot %lu.\n",
985 pSlotList[i]);
986 continue;
987 }
988
989 printf(" Manufacturer ID: %.*s\n", 32, tokenInfo.manufacturerID);
990 printf(" Model: %.*s\n", 16, tokenInfo.model);
991 printf(" Hardware version: %i.%i\n", tokenInfo.hardwareVersion.major,
992 tokenInfo.hardwareVersion.minor);
993 printf(" Firmware version: %i.%i\n", tokenInfo.firmwareVersion.major,
994 tokenInfo.firmwareVersion.minor);
995 printf(" Serial number: %.*s\n", 16, tokenInfo.serialNumber);
996 printf(" Initialized: ");
997 if ((tokenInfo.flags & CKF_TOKEN_INITIALIZED) == 0)
998 {
999 printf("no\n");
1000 }
1001 else
1002 {
1003 printf("yes\n");
1004 }
1005
1006 printf(" User PIN init.: ");
1007 if ((tokenInfo.flags & CKF_USER_PIN_INITIALIZED) == 0)
1008 {
1009 printf("no\n");
1010 }
1011 else
1012 {
1013 printf("yes\n");
1014 }
1015
1016 printf(" Label: %.*s\n", 32, tokenInfo.label);
1017
1018 }
1019
1020 free(pSlotList);
1021
1022 return 0;
1023}
1024
1025// Import a key pair from given path
1026int importKeyPair
1027(
1028 char* filePath,
1029 char* filePIN,
1030 CK_SLOT_ID slotID,
1031 char* userPIN,
1032 char* label,
1033 char* objectID,
1034 int forceExec,
1035 int noPublicKey
1036)
1037{
1038 char user_pin_copy[MAX_PIN_LEN+1];
1039
1040 if (label == NULL)
1041 {
1042 fprintf(stderr, "ERROR: A label for the object must be supplied. "
1043 "Use --label <text>\n");
1044 return 1;
1045 }
1046
1047 if (objectID == NULL)
1048 {
1049 fprintf(stderr, "ERROR: An ID for the object must be supplied. "
1050 "Use --id <hex>\n");
1051 return 1;
1052 }
1053
1054 size_t objIDLen = 0;
1055 char* objID = hexStrToBin(objectID, strlen(objectID), &objIDLen);
1056 if (objID == NULL)
1057 {
1058 fprintf(stderr, "Please edit --id <hex> to correct error.\n");
1059 return 1;
1060 }
1061
1062 CK_SESSION_HANDLE hSession;
1063 CK_RV rv = p11->C_OpenSession(slotID, CKF_SERIAL_SESSION | CKF_RW_SESSION,
1064 NULL_PTR, NULL_PTR, &hSession);
1065 if (rv != CKR_OK)
1066 {
1067 if (rv == CKR_SLOT_ID_INVALID)
1068 {
1069 fprintf(stderr, "ERROR: The given slot does not exist.\n");
1070 }
1071 else
1072 {
1073 fprintf(stderr, "ERROR: Could not open a session on the given slot.\n");
1074 }
1075 free(objID);
1076 return 1;
1077 }
1078
1079 // Get the password
1080 if (getPW(userPIN, user_pin_copy, CKU_USER) != 0)
1081 {
1082 fprintf(stderr, "ERROR: Could not get user PIN\n");
1083 free(objID);
1084 return 1;
1085 }
1086
1087 rv = p11->C_Login(hSession, CKU_USER, (CK_UTF8CHAR_PTR)user_pin_copy, strlen(user_pin_copy));
1088 if (rv != CKR_OK)
1089 {
1090 if (rv == CKR_PIN_INCORRECT) {
1091 fprintf(stderr, "ERROR: The given user PIN does not match the one in the token.\n");
1092 }
1093 else
1094 {
1095 fprintf(stderr, "ERROR: Could not log in on the token.\n");
1096 }
1097 free(objID);
1098 return 1;
1099 }
1100
1101 CK_OBJECT_HANDLE oHandle = searchObject(hSession, objID, objIDLen);
1102 if (oHandle != CK_INVALID_HANDLE && forceExec == 0)
1103 {
1104 free(objID);
1105 fprintf(stderr, "ERROR: The ID is already assigned to another object. "
1106 "Use --force to override this message.\n");
1107 return 1;
1108 }
1109
1110 crypto_init();
1111 int result = crypto_import_key_pair(hSession, filePath, filePIN, label, objID, objIDLen, noPublicKey);
1112 crypto_final();
1113
1114 free(objID);
1115
1116 return result;
1117}
1118
1119// Import a secret key from given path
1120int importSecretKey(char* filePath, CK_SLOT_ID slotID, char* userPIN, char* label, char* objectID)
1121{
1122 char user_pin_copy[MAX_PIN_LEN+1];
1123
1124 if (label == NULL)
1125 {
1126 fprintf(stderr, "ERROR: A label for the object must be supplied. "
1127 "Use --label <text>\n");
1128 return 1;
1129 }
1130
1131 if (objectID == NULL)
1132 {
1133 fprintf(stderr, "ERROR: An ID for the object must be supplied. "
1134 "Use --id <hex>\n");
1135 return 1;
1136 }
1137
1138 size_t objIDLen = 0;
1139 char* objID = hexStrToBin(objectID, strlen(objectID), &objIDLen);
1140 if (objID == NULL)
1141 {
1142 fprintf(stderr, "Please edit --id <hex> to correct error.\n");
1143 return 1;
1144 }
1145
1146 // Get the password
1147 if (getPW(userPIN, user_pin_copy, CKU_USER) != 0)
1148 {
1149 fprintf(stderr, "ERROR: Could not get user PIN\n");
1150 return 1;
1151 }
1152
1153 CK_SESSION_HANDLE hSession;
1154 CK_RV rv = p11->C_OpenSession(slotID, CKF_SERIAL_SESSION | CKF_RW_SESSION,
1155 NULL_PTR, NULL_PTR, &hSession);
1156 if (rv != CKR_OK)
1157 {
1158 if (rv == CKR_SLOT_ID_INVALID)
1159 {
1160 fprintf(stderr, "ERROR: The given slot does not exist.\n");
1161 }
1162 else
1163 {
1164 fprintf(stderr, "ERROR: Could not open a session on the given slot.\n");
1165 }
1166 return 1;
1167 }
1168
1169 rv = p11->C_Login(hSession, CKU_USER, (CK_UTF8CHAR_PTR)user_pin_copy, strlen(user_pin_copy));
1170 if (rv != CKR_OK)
1171 {
1172 if (rv == CKR_PIN_INCORRECT) {
1173 fprintf(stderr, "ERROR: The given user PIN does not match the one in the token.\n");
1174 }
1175 else
1176 {
1177 fprintf(stderr, "ERROR: Could not log in on the token.\n");
1178 }
1179 return 1;
1180 }
1181
1182 crypto_init();
1183 int result = crypto_import_aes_key(hSession, filePath, label, objID, objIDLen);
1184 crypto_final();
1185
1186 return result;
1187}
1188
1189// Convert a char array of hexadecimal characters into a binary representation
1190char* hexStrToBin(char* objectID, int idLength, size_t* newLen)
1191{
1192 char* bytes = NULL;
1193
1194 if (idLength < 2 || idLength % 2 != 0)
1195 {
1196 fprintf(stderr, "ERROR: Invalid length on hex string.\n");
1197 return NULL;
1198 }
1199
1200 for (int i = 0; i < idLength; i++)
1201 {
1202 if (hexdigit_to_int(objectID[i]) == -1)
1203 {
1204 fprintf(stderr, "ERROR: Invalid character in hex string.\n");
1205 return NULL;
1206 }
1207 }
1208
1209 *newLen = idLength / 2;
1210 bytes = (char*) malloc(*newLen);
1211 if (bytes == NULL)
1212 {
1213 fprintf(stderr, "ERROR: Could not allocate memory.\n");
1214 return NULL;
1215 }
1216
1217 for (size_t i = 0; i < *newLen; i++)
1218 {
1219 bytes[i] = hexdigit_to_int(objectID[2*i]) * 16 +
1220 hexdigit_to_int(objectID[2*i+1]);
1221 }
1222
1223 return bytes;
1224}
1225
1226// Return the integer value of a hexadecimal character
1227int hexdigit_to_int(char ch)
1228{
1229 switch (ch)
1230 {
1231 case '0':
1232 return 0;
1233 case '1':
1234 return 1;
1235 case '2':
1236 return 2;
1237 case '3':
1238 return 3;
1239 case '4':
1240 return 4;
1241 case '5':
1242 return 5;
1243 case '6':
1244 return 6;
1245 case '7':
1246 return 7;
1247 case '8':
1248 return 8;
1249 case '9':
1250 return 9;
1251 case 'a':
1252 case 'A':
1253 return 10;
1254 case 'b':
1255 case 'B':
1256 return 11;
1257 case 'c':
1258 case 'C':
1259 return 12;
1260 case 'd':
1261 case 'D':
1262 return 13;
1263 case 'e':
1264 case 'E':
1265 return 14;
1266 case 'f':
1267 case 'F':
1268 return 15;
1269 default:
1270 return -1;
1271 }
1272}
1273
1274// Search for an object
1275CK_OBJECT_HANDLE searchObject(CK_SESSION_HANDLE hSession, char* objID, size_t objIDLen)
1276{
1277 if (objID == NULL)
1278 {
1279 return CK_INVALID_HANDLE;
1280 }
1281
1282 CK_OBJECT_CLASS oClass = CKO_PRIVATE_KEY;
1283 CK_OBJECT_HANDLE hObject = CK_INVALID_HANDLE;
1284 CK_ULONG objectCount = 0;
1285
1286 CK_ATTRIBUTE objTemplate[] = {
1287 { CKA_CLASS, &oClass, sizeof(oClass) },
1288 { CKA_ID, objID, objIDLen }
1289 };
1290
1291 CK_RV rv = p11->C_FindObjectsInit(hSession, objTemplate, 2);
1292 if (rv != CKR_OK)
1293 {
1294 fprintf(stderr, "ERROR: Could not prepare the object search.\n");
1295 return CK_INVALID_HANDLE;
1296 }
1297
1298 rv = p11->C_FindObjects(hSession, &hObject, 1, &objectCount);
1299 if (rv != CKR_OK)
1300 {
1301 fprintf(stderr, "ERROR: Could not get the search results.\n");
1302 return CK_INVALID_HANDLE;
1303 }
1304
1305 rv = p11->C_FindObjectsFinal(hSession);
1306 if (rv != CKR_OK)
1307 {
1308 fprintf(stderr, "ERROR: Could not finalize the search.\n");
1309 return CK_INVALID_HANDLE;
1310 }
1311
1312 if (objectCount == 0)
1313 {
1314 return CK_INVALID_HANDLE;
1315 }
1316
1317 return hObject;
1318}