summaryrefslogtreecommitdiff
path: root/nss-tool
diff options
context:
space:
mode:
authorStefan Gschiel <stefan.gschiel.sg@gmail.com>2017-02-24 13:04:52 +0100
committerStefan Gschiel <stefan.gschiel.sg@gmail.com>2017-02-24 13:04:52 +0100
commitaeff143e65b856db4438854127df1822a433cfca (patch)
tree070be881784b54b2beeb558b625bae72ba1d7ec8 /nss-tool
parentcd1df3aceab87225aa5357b7c46332d09cc88838 (diff)
downloadnss-hg-aeff143e65b856db4438854127df1822a433cfca.tar.gz
Bug 1342351 - Implement --list-keys for nss-tool r=ttaubert
Differential Revision: https://nss-review.dev.mozaws.net/D191
Diffstat (limited to 'nss-tool')
-rw-r--r--nss-tool/common/util.cc135
-rw-r--r--nss-tool/common/util.h23
-rw-r--r--nss-tool/db/dbtool.cc96
-rw-r--r--nss-tool/db/dbtool.h1
-rw-r--r--nss-tool/nss_tool.cc1
-rw-r--r--nss-tool/nss_tool.gyp1
6 files changed, 252 insertions, 5 deletions
diff --git a/nss-tool/common/util.cc b/nss-tool/common/util.cc
new file mode 100644
index 000000000..f8abf82b3
--- /dev/null
+++ b/nss-tool/common/util.cc
@@ -0,0 +1,135 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "util.h"
+
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include <prerror.h>
+
+#if defined(__unix__) || defined(__APPLE__)
+#include <termios.h>
+#include <unistd.h>
+#elif defined(WIN32) || defined(_WIN64)
+#include <Windows.h>
+#endif
+
+static std::string GetPassword(const std::string &prompt) {
+ std::cout << prompt << std::endl;
+
+#if defined(__unix__) || defined(__APPLE__)
+ termios oldt;
+ tcgetattr(STDIN_FILENO, &oldt);
+ termios newt = oldt;
+ newt.c_lflag &= ~ECHO;
+ tcsetattr(STDIN_FILENO, TCSANOW, &newt);
+#elif defined(WIN32) || defined(_WIN64)
+ HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
+ DWORD mode = 0;
+ GetConsoleMode(hStdin, &mode);
+ SetConsoleMode(hStdin, mode & (~ENABLE_ECHO_INPUT));
+#endif
+
+ std::string pw;
+ std::getline(std::cin, pw);
+
+#if defined(__unix__) || defined(__APPLE__)
+ tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
+#elif defined(WIN32) || defined(_WIN64)
+ SetConsoleMode(hStdin, mode);
+#endif
+
+ return pw;
+}
+
+static char *GetModulePassword(PK11SlotInfo *slot, int retry, void *arg) {
+ if (arg == nullptr) {
+ return nullptr;
+ }
+
+ PwData *pwData = reinterpret_cast<PwData *>(arg);
+
+ if (retry > 0) {
+ std::cerr << "Incorrect password/PIN entered." << std::endl;
+ return nullptr;
+ }
+
+ switch (pwData->source) {
+ case PW_NONE:
+ case PW_FROMFILE:
+ std::cerr << "Password input method not supported." << std::endl;
+ return nullptr;
+ case PW_PLAINTEXT:
+ return PL_strdup(pwData->data);
+ default:
+ break;
+ }
+
+ std::cerr << "Password check failed: No password found." << std::endl;
+ return nullptr;
+}
+
+bool InitSlotPassword(void) {
+ ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
+ if (slot.get() == nullptr) {
+ std::cerr << "Error: Init PK11SlotInfo failed!" << std::endl;
+ return false;
+ }
+
+ std::cout << "Enter a password which will be used to encrypt your keys."
+ << std::endl
+ << std::endl;
+ std::string pw;
+
+ while (true) {
+ pw = GetPassword("Enter new password: ");
+ if (pw == GetPassword("Re-enter password: ")) {
+ break;
+ }
+
+ std::cerr << "Passwords do not match. Try again." << std::endl;
+ }
+
+ SECStatus rv = PK11_InitPin(slot.get(), nullptr, pw.c_str());
+ if (rv != SECSuccess) {
+ std::cerr << "Init db password failed." << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+bool DBLoginIfNeeded(const ScopedPK11SlotInfo &slot) {
+ if (!PK11_NeedLogin(slot.get())) {
+ return true;
+ }
+
+ PK11_SetPasswordFunc(&GetModulePassword);
+ std::string pw = GetPassword("Enter your password: ");
+ PwData pwData = {PW_PLAINTEXT, const_cast<char *>(pw.c_str())};
+ SECStatus rv = PK11_Authenticate(slot.get(), true /*loadCerts*/, &pwData);
+ if (rv != SECSuccess) {
+ std::cerr << "Could not authenticate to token "
+ << PK11_GetTokenName(slot.get()) << ". Failed with error "
+ << PR_ErrorToName(PR_GetError()) << std::endl;
+ return false;
+ }
+ std::cout << std::endl;
+
+ return true;
+}
+
+std::string StringToHex(const ScopedSECItem &input) {
+ std::stringstream ss;
+ ss << "0x";
+ for (size_t i = 0; i < input->len; i++) {
+ ss << std::hex << std::setfill('0') << std::setw(2)
+ << static_cast<int>(input->data[i]);
+ }
+
+ return ss.str();
+}
diff --git a/nss-tool/common/util.h b/nss-tool/common/util.h
new file mode 100644
index 000000000..d4fc257ff
--- /dev/null
+++ b/nss-tool/common/util.h
@@ -0,0 +1,23 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef util_h__
+#define util_h__
+
+#include "scoped_ptrs.h"
+
+#include <secmodt.h>
+#include <string>
+
+enum PwDataType { PW_NONE = 0, PW_FROMFILE = 1, PW_PLAINTEXT = 2 };
+typedef struct {
+ PwDataType source;
+ char *data;
+} PwData;
+
+bool InitSlotPassword(void);
+bool DBLoginIfNeeded(const ScopedPK11SlotInfo &slot);
+std::string StringToHex(const ScopedSECItem &input);
+
+#endif // util_h__
diff --git a/nss-tool/db/dbtool.cc b/nss-tool/db/dbtool.cc
index bc82b308f..f88ba4187 100644
--- a/nss-tool/db/dbtool.cc
+++ b/nss-tool/db/dbtool.cc
@@ -5,6 +5,7 @@
#include "dbtool.h"
#include "argparse.h"
#include "scoped_ptrs.h"
+#include "util.h"
#include <dirent.h>
#include <fstream>
@@ -17,8 +18,17 @@
#include <cert.h>
#include <certdb.h>
#include <nss.h>
+#include <prerror.h>
#include <prio.h>
+const std::vector<std::string> kCommandArgs({"--create", "--list-certs",
+ "--import-cert", "--list-keys"});
+
+static bool HasSingleCommandArgument(const ArgParser &parser) {
+ auto pred = [&](const std::string &cmd) { return parser.Has(cmd); };
+ return std::count_if(kCommandArgs.begin(), kCommandArgs.end(), pred) == 1;
+}
+
static std::string PrintFlags(unsigned int flags) {
std::stringstream ss;
if ((flags & CERTDB_VALID_CA) && !(flags & CERTDB_TRUSTED_CA) &&
@@ -63,19 +73,23 @@ static std::vector<char> ReadFromIstream(std::istream &is) {
return certData;
}
+static const char *const keyTypeName[] = {"null", "rsa", "dsa", "fortezza",
+ "dh", "kea", "ec"};
+
void DBTool::Usage() {
std::cerr << "Usage: nss db [--path <directory>]" << std::endl;
std::cerr << " --create" << std::endl;
std::cerr << " --list-certs" << std::endl;
std::cerr << " --import-cert [<path>] --name <name> [--trusts <trusts>]"
<< std::endl;
+ std::cerr << " --list-keys" << std::endl;
}
bool DBTool::Run(const std::vector<std::string> &arguments) {
ArgParser parser(arguments);
- if (!parser.Has("--create") && !parser.Has("--list-certs") &&
- !parser.Has("--import-cert")) {
+ if (!HasSingleCommandArgument(parser)) {
+ Usage();
return false;
}
@@ -129,7 +143,12 @@ bool DBTool::Run(const std::vector<std::string> &arguments) {
} else if (parser.Has("--import-cert")) {
ret = ImportCertificate(parser);
} else if (parser.Has("--create")) {
- std::cout << "DB files created successfully." << std::endl;
+ ret = InitSlotPassword();
+ if (ret) {
+ std::cout << "DB files created successfully." << std::endl;
+ }
+ } else if (parser.Has("--list-keys")) {
+ ret = ListKeys();
}
// shutdown nss
@@ -233,7 +252,7 @@ bool DBTool::ImportCertificate(const ArgParser &parser) {
ScopedPK11SlotInfo slot = ScopedPK11SlotInfo(PK11_GetInternalKeySlot());
if (slot.get() == nullptr) {
- std::cerr << "Error: Init PK11SlotInfo failed!\n";
+ std::cerr << "Error: Init PK11SlotInfo failed!" << std::endl;
return false;
}
@@ -279,3 +298,72 @@ bool DBTool::ImportCertificate(const ArgParser &parser) {
// TODO show information about imported certificate
return true;
}
+
+bool DBTool::ListKeys() {
+ ScopedPK11SlotInfo slot = ScopedPK11SlotInfo(PK11_GetInternalKeySlot());
+ if (slot.get() == nullptr) {
+ std::cerr << "Error: Init PK11SlotInfo failed!" << std::endl;
+ return false;
+ }
+
+ if (!DBLoginIfNeeded(slot)) {
+ return false;
+ }
+
+ ScopedSECKEYPrivateKeyList list(PK11_ListPrivateKeysInSlot(slot.get()));
+ if (list.get() == nullptr) {
+ std::cerr << "Listing private keys failed with error "
+ << PR_ErrorToName(PR_GetError()) << std::endl;
+ return false;
+ }
+
+ SECKEYPrivateKeyListNode *node;
+ int count = 0;
+ for (node = PRIVKEY_LIST_HEAD(list.get());
+ !PRIVKEY_LIST_END(node, list.get()); node = PRIVKEY_LIST_NEXT(node)) {
+ char *keyNameRaw = PK11_GetPrivateKeyNickname(node->key);
+ std::string keyName(keyNameRaw ? "" : keyNameRaw);
+
+ if (keyName.empty()) {
+ ScopedCERTCertificate cert(PK11_GetCertFromPrivateKey(node->key));
+ if (cert.get()) {
+ if (cert->nickname && strlen(cert->nickname) > 0) {
+ keyName = cert->nickname;
+ } else if (cert->emailAddr && strlen(cert->emailAddr) > 0) {
+ keyName = cert->emailAddr;
+ }
+ }
+ if (keyName.empty()) {
+ keyName = "(none)"; // default value
+ }
+ }
+
+ SECKEYPrivateKey *key = node->key;
+ ScopedSECItem keyIDItem(PK11_GetLowLevelKeyIDForPrivateKey(key));
+ if (keyIDItem.get() == nullptr) {
+ std::cerr << "Error: PK11_GetLowLevelKeyIDForPrivateKey failed!"
+ << std::endl;
+ continue;
+ }
+
+ std::string keyID = StringToHex(keyIDItem);
+
+ if (count++ == 0) {
+ // print header
+ std::cout << std::left << std::setw(20) << "<key#, key name>"
+ << std::setw(20) << "key type"
+ << "key id" << std::endl;
+ }
+
+ std::stringstream leftElem;
+ leftElem << "<" << count << ", " << keyName << ">";
+ std::cout << std::left << std::setw(20) << leftElem.str() << std::setw(20)
+ << keyTypeName[key->keyType] << keyID << std::endl;
+ }
+
+ if (count == 0) {
+ std::cout << "No keys found." << std::endl;
+ }
+
+ return true;
+}
diff --git a/nss-tool/db/dbtool.h b/nss-tool/db/dbtool.h
index 430ce244d..ed44e74ae 100644
--- a/nss-tool/db/dbtool.h
+++ b/nss-tool/db/dbtool.h
@@ -19,6 +19,7 @@ class DBTool {
bool PathHasDBFiles(std::string path);
void ListCertificates();
bool ImportCertificate(const ArgParser& parser);
+ bool ListKeys();
};
#endif // dbtool_h__
diff --git a/nss-tool/nss_tool.cc b/nss-tool/nss_tool.cc
index 5d476f692..0b6b734bb 100644
--- a/nss-tool/nss_tool.cc
+++ b/nss-tool/nss_tool.cc
@@ -33,7 +33,6 @@ int main(int argc, char **argv) {
std::vector<std::string> arguments(argv + 2, argv + argc);
DBTool tool;
if (!tool.Run(arguments)) {
- tool.Usage();
exit_code = 1;
}
diff --git a/nss-tool/nss_tool.gyp b/nss-tool/nss_tool.gyp
index 26eecfe0c..95b627070 100644
--- a/nss-tool/nss_tool.gyp
+++ b/nss-tool/nss_tool.gyp
@@ -13,6 +13,7 @@
'sources' : [
'nss_tool.cc',
'common/argparse.cc',
+ 'common/util.cc',
'db/dbtool.cc',
],
'include_dirs': [