Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  dbtool.cc   Sprache: C

 
/* 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 "dbtool.h"
#include "argparse.h"
#include "nss_scoped_ptrs.h"
#include "util.h"

#include <iomanip>
#include <iostream>
#include <regex>
#include <sstream>

#include <cert.h>
#include <certdb.h>
#include <nss.h>
#include <pk11pub.h>
#include <prerror.h>
#include <prio.h>

const std::vector<std::string> kCommandArgs(
    {"--create""--list-certs""--import-cert""--list-keys""--import-key",
     "--delete-cert""--delete-key""--change-password"});

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") || parser.Has("--delete-cert") ||
         parser.Has("--delete-key") || parser.Has("--change-password");
}

static std::string PrintFlags(unsigned int flags) {
  std::stringstream ss;
  if ((flags & CERTDB_VALID_CA) && !(flags & CERTDB_TRUSTED_CA) &&
      !(flags & CERTDB_TRUSTED_CLIENT_CA)) {
    ss << "c";
  }
  if ((flags & CERTDB_TERMINAL_RECORD) && !(flags & CERTDB_TRUSTED)) {
    ss << "p";
  }
  if (flags & CERTDB_TRUSTED_CA) {
    ss << "C";
  }
  if (flags & CERTDB_TRUSTED_CLIENT_CA) {
    ss << "T";
  }
  if (flags & CERTDB_TRUSTED) {
    ss << "P";
  }
  if (flags & CERTDB_USER) {
    ss << "u";
  }
  if (flags & CERTDB_SEND_WARN) {
    ss << "w";
  }
  if (flags & CERTDB_INVISIBLE_CA) {
    ss << "I";
  }
  if (flags & CERTDB_GOVT_APPROVED_CA) {
    ss << "G";
  }
  return ss.str();
}

static const char *const keyTypeName[] = {"null""rsa""dsa""fortezza",
                                          "dh",   "kea""ec"};

void DBTool::Usage() {
  std::cerr << "Usage: nss db [--path ]" << std::endl;
  std::cerr << " --create" << std::endl;
  std::cerr << " --change-password" << std::endl;
  std::cerr << " --list-certs" << std::endl;
  std::cerr << " --import-cert [] --name [--trusts ]"
            << std::endl;
  std::cerr << " --list-keys" << std::endl;
  std::cerr << " --import-key [ [-- name ]]" << std::endl;
  std::cerr << " --delete-cert " << std::endl;
  std::cerr << " --delete-key " << std::endl;
}

bool DBTool::Run(const std::vector<std::string> &arguments) {
  ArgParser parser(arguments);

  if (!HasSingleCommandArgument(parser)) {
    Usage();
    return false;
  }

  PRAccessHow how = PR_ACCESS_READ_OK;
  bool readOnly = true;
  if (HasArgumentRequiringWriteAccess(parser)) {
    how = PR_ACCESS_WRITE_OK;
    readOnly = false;
  }

  std::string initDir(".");
  if (parser.Has("--path")) {
    initDir = parser.Get("--path");
  }
  if (PR_Access(initDir.c_str(), how) != PR_SUCCESS) {
    std::cerr << "Directory '" << initDir
              << "' does not exist or you don't have permissions!" << std::endl;
    return false;
  }

  std::cout << "Using database directory: " << initDir << std::endl
            << std::endl;

  bool dbFilesExist = PathHasDBFiles(initDir);
  if (parser.Has("--create") && dbFilesExist) {
    std::cerr << "Trying to create database files in a directory where they "
                 "already exists. Delete the db files before creating new ones."
              << std::endl;
    return false;
  }
  if (!parser.Has("--create") && !dbFilesExist) {
    std::cerr << "No db files found." << std::endl;
    std::cerr << "Create them using 'nss db --create [--path /foo/bar]' before "
                 "continuing."
              << std::endl;
    return false;
  }

  // init NSS
  const char *certPrefix = "";  // certutil -P option  --- can leave this empty
  SECStatus rv = NSS_Initialize(initDir.c_str(), certPrefix, certPrefix,
                                "secmod.db", readOnly ? NSS_INIT_READONLY : 0);
  if (rv != SECSuccess) {
    std::cerr << "NSS init failed!" << std::endl;
    return false;
  }

  bool ret = true;
  if (parser.Has("--list-certs")) {
    ListCertificates();
  } else if (parser.Has("--import-cert")) {
    ret = ImportCertificate(parser);
  } else if (parser.Has("--create")) {
    ret = InitSlotPassword();
    if (ret) {
      std::cout << "DB files created successfully." << std::endl;
    }
  } else if (parser.Has("--list-keys")) {
    ret = ListKeys();
  } else if (parser.Has("--import-key")) {
    ret = ImportKey(parser);
  } else if (parser.Has("--delete-cert")) {
    ret = DeleteCert(parser);
  } else if (parser.Has("--delete-key")) {
    ret = DeleteKey(parser);
  } else if (parser.Has("--change-password")) {
    ret = ChangeSlotPassword();
  }

  // shutdown nss
  if (NSS_Shutdown() != SECSuccess) {
    std::cerr << "NSS Shutdown failed!" << std::endl;
    return false;
  }

  return ret;
}

bool DBTool::PathHasDBFiles(std::string path) {
  std::regex certDBPattern("cert.*\\.db");
  std::regex keyDBPattern("key.*\\.db");

  PRDir *dir = PR_OpenDir(path.c_str());
  if (!dir) {
    std::cerr << "Directory " << path << " could not be accessed!" << std::endl;
    return false;
  }

  PRDirEntry *ent;
  bool dbFileExists = false;
  while ((ent = PR_ReadDir(dir, PR_SKIP_BOTH))) {
    if (std::regex_match(ent->name, certDBPattern) ||
        std::regex_match(ent->name, keyDBPattern) ||
        "secmod.db" == std::string(ent->name)) {
      dbFileExists = true;
      break;
    }
  }

  (void)PR_CloseDir(dir);
  return dbFileExists;
}

void DBTool::ListCertificates() {
  ScopedCERTCertList list(PK11_ListCerts(PK11CertListAll, nullptr));
  CERTCertListNode *node;

  std::cout << std::setw(60) << std::left << "Certificate Nickname"
            << " "
            << "Trust Attributes" << std::endl;
  std::cout << std::setw(60) << std::left << ""
            << " "
            << "SSL,S/MIME,JAR/XPI" << std::endl
            << std::endl;

  for (node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list);
       node = CERT_LIST_NEXT(node)) {
    CERTCertificate *cert = node->cert;

    std::string name("(unknown)");
    char *appData = static_cast<char *>(node->appData);
    if (appData && strlen(appData) > 0) {
      name = appData;
    } else if (cert->nickname && strlen(cert->nickname) > 0) {
      name = cert->nickname;
    } else if (cert->emailAddr && strlen(cert->emailAddr) > 0) {
      name = cert->emailAddr;
    }

    CERTCertTrust trust;
    std::string trusts;
    if (CERT_GetCertTrust(cert, &trust) == SECSuccess) {
      std::stringstream ss;
      ss << PrintFlags(trust.sslFlags);
      ss << ",";
      ss << PrintFlags(trust.emailFlags);
      ss << ",";
      ss << PrintFlags(trust.objectSigningFlags);
      trusts = ss.str();
    } else {
      trusts = ",,";
    }
    std::cout << std::setw(60) << std::left << name << " " << trusts
              << std::endl;
  }
}

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;
  }

  std::string derFilePath = parser.Get("--import-cert");
  std::string certName = parser.Get("--name");
  std::string trustString("TCu,Cu,Tu");
  if (parser.Has("--trusts")) {
    trustString = parser.Get("--trusts");
  }

  CERTCertTrust trust;
  SECStatus rv = CERT_DecodeTrustString(&trust, trustString.c_str());
  if (rv != SECSuccess) {
    std::cerr << "Cannot decode trust string!" << std::endl;
    return false;
  }

  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
  if (slot.get() == nullptr) {
    std::cerr << "Error: Init PK11SlotInfo failed!" << std::endl;
    return false;
  }

  std::vector<uint8_t> certData = ReadInputData(derFilePath);

  ScopedCERTCertificate cert(CERT_DecodeCertFromPackage(
      reinterpret_cast<char *>(certData.data()), certData.size()));
  if (cert.get() == nullptr) {
    std::cerr << "Error: Could not decode certificate!" << std::endl;
    return false;
  }

  rv = PK11_ImportCert(slot.get(), cert.get(), CK_INVALID_HANDLE,
                       certName.c_str(), PR_FALSE);
  if (rv != SECSuccess) {
    // TODO handle authentication -> PK11_Authenticate (see certutil.c line
    // 134)
    std::cerr << "Error: Could not add certificate to database!" << std::endl;
    return false;
  }

  rv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), cert.get(), &trust);
  if (rv != SECSuccess) {
    std::cerr << "Cannot change cert's trust" << std::endl;
    return false;
  }

  std::cout << "Certificate import was successful!" << std::endl;
  // TODO show information about imported certificate
  return true;
}

bool DBTool::ListKeys() {
  ScopedPK11SlotInfo slot(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) << ""
                << 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;
}

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<uint8_t> privKeyData = ReadInputData(privKeyFilePath);
  if (privKeyData.empty()) {
    return false;
  }
  SECItem pkcs8PrivKeyItem = {
      siBuffer, reinterpret_cast<unsigned char *>(privKeyData.data()),
      static_cast<unsigned int>(privKeyData.size())};

  SECItem nickname = {siBuffer, nullptr, 0};
  if (!name.empty()) {
    nickname.data = const_cast<unsigned char *>(
        reinterpret_cast<const unsigned char *>(name.c_str()));
    nickname.len = static_cast<unsigned int>(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;
}

bool DBTool::DeleteCert(const ArgParser &parser) {
  std::string certName = parser.Get("--delete-cert");
  if (certName.empty()) {
    std::cerr << "A name is required to delete a certificate." << std::endl;
    Usage();
    return false;
  }

  ScopedCERTCertificate cert(CERT_FindCertByNicknameOrEmailAddr(
      CERT_GetDefaultCertDB(), certName.c_str()));
  if (!cert) {
    std::cerr << "Could not find certificate with name " << certName << "."
              << std::endl;
    return false;
  }

  SECStatus rv = SEC_DeletePermCertificate(cert.get());
  if (rv != SECSuccess) {
    std::cerr << "Unable to delete certificate with name " << certName << "."
              << std::endl;
    return false;
  }

  std::cout << "Certificate with name " << certName << " deleted successfully."
            << std::endl;
  return true;
}

bool DBTool::DeleteKey(const ArgParser &parser) {
  std::string keyName = parser.Get("--delete-key");
  if (keyName.empty()) {
    std::cerr << "A name is required to delete a key." << std::endl;
    Usage();
    return false;
  }

  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
  if (slot.get() == nullptr) {
    std::cerr << "Error: Init PK11SlotInfo failed!" << std::endl;
    return false;
  }

  if (!DBLoginIfNeeded(slot)) {
    return false;
  }

  ScopedSECKEYPrivateKeyList list(PK11_ListPrivKeysInSlot(
      slot.get(), const_cast<char *>(keyName.c_str()), nullptr));
  if (list.get() == nullptr) {
    std::cerr << "Fetching private keys with nickname " << keyName
              << " failed with error " << PR_ErrorToName(PR_GetError())
              << std::endl;
    return false;
  }

  unsigned int foundKeys = 0, deletedKeys = 0;
  SECKEYPrivateKeyListNode *node;
  for (node = PRIVKEY_LIST_HEAD(list.get());
       !PRIVKEY_LIST_END(node, list.get()); node = PRIVKEY_LIST_NEXT(node)) {
    SECKEYPrivateKey *privKey = node->key;
    foundKeys++;
    // see PK11_DeleteTokenPrivateKey for example usage
    // calling PK11_DeleteTokenPrivateKey directly does not work because it also
    // destroys the SECKEYPrivateKey (by calling SECKEY_DestroyPrivateKey) -
    // then SECKEY_DestroyPrivateKeyList does not
    // work because it also calls SECKEY_DestroyPrivateKey
    SECStatus rv =
        PK11_DestroyTokenObject(privKey->pkcs11Slot, privKey->pkcs11ID);
    if (rv == SECSuccess) {
      deletedKeys++;
    }
  }

  if (foundKeys > deletedKeys) {
    std::cerr << "Some keys could not be deleted." << std::endl;
  }

  if (deletedKeys > 0) {
    std::cout << "Found " << foundKeys << " keys." << std::endl;
    std::cout << "Successfully deleted " << deletedKeys
              << " key(s) with nickname " << keyName << "." << std::endl;
  } else {
    std::cout << "No key with nickname " << keyName << " found to delete."
              << std::endl;
  }

  return true;
}

Messung V0.5
C=97 H=97 G=96

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge