/* 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 "digesttool.h" #include "argparse.h" #include "nss_scoped_ptrs.h" #include "util.h" #include #include #include #include #include // contains supported digest types #include #include #include static SECOidData* HashTypeToOID(HASH_HashType hashtype) { SECOidTag hashtag; if (hashtype <= HASH_AlgNULL || hashtype >= HASH_AlgTOTAL) { return nullptr; } switch (hashtype) { case HASH_AlgMD5: hashtag = SEC_OID_MD5; break; case HASH_AlgSHA1: hashtag = SEC_OID_SHA1; break; case HASH_AlgSHA224: hashtag = SEC_OID_SHA224; break; case HASH_AlgSHA256: hashtag = SEC_OID_SHA256; break; case HASH_AlgSHA384: hashtag = SEC_OID_SHA384; break; case HASH_AlgSHA512: hashtag = SEC_OID_SHA512; break; default: return nullptr; } return SECOID_FindOIDByTag(hashtag); } static SECOidData* HashNameToOID(const std::string& hashName) { for (size_t htype = HASH_AlgNULL + 1; htype < HASH_AlgTOTAL; htype++) { SECOidData* hashOID = HashTypeToOID(static_cast(htype)); if (hashOID && std::string(hashOID->desc) == hashName) { return hashOID; } } return nullptr; } static bool Digest(const ArgParser& parser, SECOidData* hashOID); static bool ComputeDigest(std::istream& is, ScopedPK11Context& hashCtx); bool DigestTool::Run(const std::vector& arguments) { ArgParser parser(arguments); if (parser.GetPositionalArgumentCount() != 1) { Usage(); return false; } // no need for a db for the digest tool SECStatus rv = NSS_NoDB_Init("."); if (rv != SECSuccess) { std::cerr << "NSS init failed!" << std::endl; return false; } std::string hashName = parser.GetPositionalArgument(0); std::transform(hashName.begin(), hashName.end(), hashName.begin(), ::toupper); SECOidData* hashOID = HashNameToOID(hashName); if (hashOID == nullptr) { std::cerr << "Error: Unknown digest type " << parser.GetPositionalArgument(0) << "." << std::endl; return false; } bool ret = Digest(parser, hashOID); // shutdown nss if (NSS_Shutdown() != SECSuccess) { std::cerr << "NSS Shutdown failed!" << std::endl; return false; } return ret; } void DigestTool::Usage() { std::cerr << "Usage: nss digest md5|sha-1|sha-224|sha-256|sha-384|sha-512 " "[--infile ]" << std::endl; } static bool Digest(const ArgParser& parser, SECOidData* hashOID) { std::string inputFile; if (parser.Has("--infile")) { inputFile = parser.Get("--infile"); } ScopedPK11Context hashCtx(PK11_CreateDigestContext(hashOID->offset)); if (hashCtx == nullptr) { std::cerr << "Creating digest context failed." << std::endl; return false; } PK11_DigestBegin(hashCtx.get()); std::ifstream fis; std::istream& is = GetStreamFromFileOrStdin(inputFile, fis); if (!is.good() || !ComputeDigest(is, hashCtx)) { return false; } unsigned char digest[HASH_LENGTH_MAX]; unsigned int len; SECStatus rv = PK11_DigestFinal(hashCtx.get(), digest, &len, HASH_LENGTH_MAX); if (rv != SECSuccess || len == 0) { std::cerr << "Calculating final hash value failed." << std::endl; return false; } // human readable output for (size_t i = 0; i < len; i++) { std::cout << std::setw(2) << std::setfill('0') << std::hex << static_cast(digest[i]); } std::cout << std::endl; return true; } static bool ComputeDigest(std::istream& is, ScopedPK11Context& hashCtx) { while (is) { unsigned char buf[4096]; is.read(reinterpret_cast(buf), sizeof(buf)); if (is.fail() && !is.eof()) { std::cerr << "Error reading from input stream." << std::endl; return false; } SECStatus rv = PK11_DigestOp(hashCtx.get(), buf, is.gcount()); if (rv != SECSuccess) { std::cerr << "PK11_DigestOp failed." << std::endl; return false; } } return true; }