From a293142f83420788ec272aa42155d9728e0c6183 Mon Sep 17 00:00:00 2001 From: Stefan Gschiel Date: Fri, 10 Mar 2017 16:57:55 +0100 Subject: Bug 1346250 - Implement --import-key for nss-tool r=ttaubert Differential Revision: https://nss-review.dev.mozaws.net/D235 --- nss-tool/common/util.cc | 31 ++++++++++++++++ nss-tool/common/util.h | 2 ++ nss-tool/db/dbtool.cc | 96 ++++++++++++++++++++++++++++++++----------------- nss-tool/db/dbtool.h | 4 +-- 4 files changed, 98 insertions(+), 35 deletions(-) (limited to 'nss-tool') diff --git a/nss-tool/common/util.cc b/nss-tool/common/util.cc index f8abf82b3..7cc4352c6 100644 --- a/nss-tool/common/util.cc +++ b/nss-tool/common/util.cc @@ -4,6 +4,7 @@ #include "util.h" +#include #include #include #include @@ -73,6 +74,17 @@ static char *GetModulePassword(PK11SlotInfo *slot, int retry, void *arg) { return nullptr; } +static std::vector ReadFromIstream(std::istream &is) { + std::vector certData; + while (is) { + char buf[1024]; + is.read(buf, sizeof(buf)); + certData.insert(certData.end(), buf, buf + is.gcount()); + } + + return certData; +} + bool InitSlotPassword(void) { ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); if (slot.get() == nullptr) { @@ -133,3 +145,22 @@ std::string StringToHex(const ScopedSECItem &input) { return ss.str(); } + +std::vector ReadInputData(std::string &dataPath) { + std::vector data; + if (dataPath.empty()) { + std::cout << "No input file path given, using stdin." << std::endl; + data = ReadFromIstream(std::cin); + } else { + std::ifstream is(dataPath, std::ifstream::binary); + if (is.good()) { + data = ReadFromIstream(is); + } else { + std::cerr << "IO Error when opening " << dataPath << std::endl; + std::cerr << "Input file does not exist or you don't have permissions." + << std::endl; + } + } + + return data; +} diff --git a/nss-tool/common/util.h b/nss-tool/common/util.h index d4fc257ff..8b3b0f11e 100644 --- a/nss-tool/common/util.h +++ b/nss-tool/common/util.h @@ -9,6 +9,7 @@ #include #include +#include enum PwDataType { PW_NONE = 0, PW_FROMFILE = 1, PW_PLAINTEXT = 2 }; typedef struct { @@ -19,5 +20,6 @@ typedef struct { bool InitSlotPassword(void); bool DBLoginIfNeeded(const ScopedPK11SlotInfo &slot); std::string StringToHex(const ScopedSECItem &input); +std::vector ReadInputData(std::string &dataPath); #endif // util_h__ diff --git a/nss-tool/db/dbtool.cc b/nss-tool/db/dbtool.cc index f88ba4187..f1d1b0edd 100644 --- a/nss-tool/db/dbtool.cc +++ b/nss-tool/db/dbtool.cc @@ -8,27 +8,32 @@ #include "util.h" #include -#include #include #include -#include #include #include #include #include #include +#include #include #include const std::vector kCommandArgs({"--create", "--list-certs", - "--import-cert", "--list-keys"}); + "--import-cert", "--list-keys", + "--import-key"}); 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 bool HasArgumentRequiringWriteAccess(const ArgParser &parser) { + return parser.Has("--create") || parser.Has("--import-cert") || + parser.Has("--import-key"); +} + static std::string PrintFlags(unsigned int flags) { std::stringstream ss; if ((flags & CERTDB_VALID_CA) && !(flags & CERTDB_TRUSTED_CA) && @@ -62,17 +67,6 @@ static std::string PrintFlags(unsigned int flags) { return ss.str(); } -static std::vector ReadFromIstream(std::istream &is) { - std::vector certData; - while (is) { - char buf[1024]; - is.read(buf, sizeof(buf)); - certData.insert(certData.end(), buf, buf + is.gcount()); - } - - return certData; -} - static const char *const keyTypeName[] = {"null", "rsa", "dsa", "fortezza", "dh", "kea", "ec"}; @@ -83,6 +77,7 @@ void DBTool::Usage() { std::cerr << " --import-cert [] --name [--trusts ]" << std::endl; std::cerr << " --list-keys" << std::endl; + std::cerr << " --import-key [ [-- name ]]" << std::endl; } bool DBTool::Run(const std::vector &arguments) { @@ -95,7 +90,7 @@ bool DBTool::Run(const std::vector &arguments) { PRAccessHow how = PR_ACCESS_READ_OK; bool readOnly = true; - if (parser.Has("--create") || parser.Has("--import-cert")) { + if (HasArgumentRequiringWriteAccess(parser)) { how = PR_ACCESS_WRITE_OK; readOnly = false; } @@ -149,6 +144,8 @@ bool DBTool::Run(const std::vector &arguments) { } } else if (parser.Has("--list-keys")) { ret = ListKeys(); + } else if (parser.Has("--import-key")) { + ret = ImportKey(parser); } // shutdown nss @@ -233,6 +230,7 @@ bool DBTool::ImportCertificate(const ArgParser &parser) { if (!parser.Has("--name")) { std::cerr << "A name (--name) is required to import a certificate." << std::endl; + Usage(); return false; } @@ -250,27 +248,13 @@ bool DBTool::ImportCertificate(const ArgParser &parser) { return false; } - ScopedPK11SlotInfo slot = ScopedPK11SlotInfo(PK11_GetInternalKeySlot()); + ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); if (slot.get() == nullptr) { std::cerr << "Error: Init PK11SlotInfo failed!" << std::endl; return false; } - std::vector certData; - if (derFilePath.empty()) { - std::cout << "No Certificate file path given, using stdin." << std::endl; - certData = ReadFromIstream(std::cin); - } else { - std::ifstream is(derFilePath, std::ifstream::binary); - if (!is.good()) { - std::cerr << "IO Error when opening " << derFilePath << std::endl; - std::cerr - << "Certificate file does not exist or you don't have permissions." - << std::endl; - return false; - } - certData = ReadFromIstream(is); - } + std::vector certData = ReadInputData(derFilePath); ScopedCERTCertificate cert( CERT_DecodeCertFromPackage(certData.data(), certData.size())); @@ -300,7 +284,7 @@ bool DBTool::ImportCertificate(const ArgParser &parser) { } bool DBTool::ListKeys() { - ScopedPK11SlotInfo slot = ScopedPK11SlotInfo(PK11_GetInternalKeySlot()); + ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); if (slot.get() == nullptr) { std::cerr << "Error: Init PK11SlotInfo failed!" << std::endl; return false; @@ -322,7 +306,7 @@ bool DBTool::ListKeys() { 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); + std::string keyName(keyNameRaw ? keyNameRaw : ""); if (keyName.empty()) { ScopedCERTCertificate cert(PK11_GetCertFromPrivateKey(node->key)); @@ -367,3 +351,49 @@ bool DBTool::ListKeys() { return true; } + +bool DBTool::ImportKey(const ArgParser &parser) { + std::string privKeyFilePath = parser.Get("--import-key"); + std::string name; + if (parser.Has("--name")) { + name = parser.Get("--name"); + } + + ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); + if (slot.get() == nullptr) { + std::cerr << "Error: Init PK11SlotInfo failed!" << std::endl; + return false; + } + + if (!DBLoginIfNeeded(slot)) { + return false; + } + + std::vector privKeyData = ReadInputData(privKeyFilePath); + if (privKeyData.empty()) { + return false; + } + SECItem pkcs8PrivKeyItem = { + siBuffer, reinterpret_cast(privKeyData.data()), + static_cast(privKeyData.size())}; + + SECItem nickname = {siBuffer, nullptr, 0}; + if (!name.empty()) { + nickname.data = const_cast( + reinterpret_cast(name.c_str())); + nickname.len = static_cast(name.size()); + } + + SECStatus rv = PK11_ImportDERPrivateKeyInfo( + slot.get(), &pkcs8PrivKeyItem, + nickname.data == nullptr ? nullptr : &nickname, nullptr /*publicValue*/, + true /*isPerm*/, false /*isPrivate*/, KU_ALL, nullptr); + if (rv != SECSuccess) { + std::cerr << "Importing a private key in DER format failed with error " + << PR_ErrorToName(PR_GetError()) << std::endl; + return false; + } + + std::cout << "Key import succeeded." << std::endl; + return true; +} diff --git a/nss-tool/db/dbtool.h b/nss-tool/db/dbtool.h index ed44e74ae..9d5ddedb2 100644 --- a/nss-tool/db/dbtool.h +++ b/nss-tool/db/dbtool.h @@ -13,13 +13,13 @@ class DBTool { public: bool Run(const std::vector& arguments); - void Usage(); - private: + void Usage(); bool PathHasDBFiles(std::string path); void ListCertificates(); bool ImportCertificate(const ArgParser& parser); bool ListKeys(); + bool ImportKey(const ArgParser& parser); }; #endif // dbtool_h__ -- cgit v1.2.1