mirror of
https://github.com/chris2511/xca.git
synced 2026-09-13 18:46:25 +05:00
This is a large squash of many small commits. Allow porting data from the legacy format to SQL. Store Binaries base64 encoded and use db->transaction Update password hash to be 8000 x SHA512 with 8 byte Salt Add revocations table and fixup CRL generation Add comment and insertion date columns Fix column saving, remove trust, add XcaDialog Allow changing the internal name and comment in Cert/Req details view Extend Comment functionality, Replace About.ui by XcaDialog.ui
359 lines
8.6 KiB
C++
359 lines
8.6 KiB
C++
/* vi: set sw=4 ts=4:
|
|
*
|
|
* Copyright (C) 2001 - 2015 Christian Hohnstaedt.
|
|
*
|
|
* All rights reserved.
|
|
*/
|
|
|
|
|
|
#include "db_key.h"
|
|
#include "pki_evp.h"
|
|
|
|
#include "pki_scard.h"
|
|
#include <QDialog>
|
|
#include <QLabel>
|
|
#include <QPushButton>
|
|
|
|
#include <QMessageBox>
|
|
#include <QProgressBar>
|
|
#include <QStatusBar>
|
|
#include <QContextMenuEvent>
|
|
|
|
#include "exception.h"
|
|
#include "ui_NewKey.h"
|
|
#include "pkcs11.h"
|
|
|
|
#include "widgets/PwDialog.h"
|
|
#include "widgets/ExportDialog.h"
|
|
#include "widgets/KeyDetail.h"
|
|
#include "widgets/NewKey.h"
|
|
|
|
db_key::db_key(MainWindow *mw)
|
|
:db_base(mw)
|
|
{
|
|
class_name = "keys";
|
|
sqlHashTable = "public_keys";
|
|
pkitype << asym_key << smartCard;
|
|
updateHeaders();
|
|
loadContainer();
|
|
}
|
|
|
|
dbheaderList db_key::getHeaders()
|
|
{
|
|
dbheaderList h = db_base::getHeaders();
|
|
h << new dbheader(HD_key_type, true, tr("Type")) <<
|
|
new dbheader(HD_key_size, true, tr("Size")) <<
|
|
#ifndef OPENSSL_NO_EC
|
|
new dbheader(HD_key_curve, false,tr("EC Group")) <<
|
|
#endif
|
|
new dbheader(HD_key_use, true, tr("Use")) <<
|
|
new dbheader(HD_key_passwd, true, tr("Password"));
|
|
return h;
|
|
}
|
|
|
|
pki_base *db_key::newPKI(enum pki_type type)
|
|
{
|
|
if (type == asym_key)
|
|
return new pki_evp("");
|
|
return new pki_scard("");
|
|
}
|
|
|
|
QList<pki_base *> db_key::getAllKeys()
|
|
{
|
|
return sqlSELECTpki("SELECT item from public_keys");
|
|
}
|
|
|
|
QList<pki_base *> db_key::getUnusedKeys()
|
|
{
|
|
return sqlSELECTpki("SELECT public_keys.item FROM public_keys "
|
|
"LEFT OUTER JOIN x509super ON x509super.key = public_keys.item "
|
|
"WHERE x509super.item IS NULL");
|
|
}
|
|
|
|
void db_key::remFromCont(QModelIndex &idx)
|
|
{
|
|
db_base::remFromCont(idx);
|
|
XSqlQuery q;
|
|
pki_key *pki = static_cast<pki_key*>(idx.internalPointer());
|
|
|
|
QList<pki_base*> items = sqlSELECTpki(
|
|
"SELECT item FROM x509super WHERE key=?",
|
|
QList<QVariant>() << QVariant(pki->getSqlItemId()));
|
|
foreach(pki_base *b, items) {
|
|
pki_x509super *x509s = static_cast<pki_x509super*>(b);
|
|
x509s->setRefKey(NULL);
|
|
}
|
|
|
|
SQL_PREPARE(q, "UPDATE x509super SET key=NULL WHERE item=?");
|
|
q.bindValue(0, pki->getSqlItemId());
|
|
q.exec();
|
|
mainwin->dbSqlError(q.lastError());
|
|
}
|
|
|
|
void db_key::inToCont(pki_base *pki)
|
|
{
|
|
db_base::inToCont(pki);
|
|
pki_key *key = static_cast<pki_key*>(pki);
|
|
unsigned hash = key->hash();
|
|
QList<pki_base*> items = sqlSELECTpki(
|
|
"SELECT item FROM x509super WHERE key IS NULL AND key_hash=?",
|
|
QList<QVariant>() << QVariant(hash));
|
|
XSqlQuery q;
|
|
SQL_PREPARE(q, "UPDATE x509super SET key=? WHERE item=?");
|
|
q.bindValue(0, key->getSqlItemId());
|
|
foreach(pki, items) {
|
|
pki_x509super *x509s = static_cast<pki_x509super*>(pki);
|
|
if (!x509s->compareRefKey(key))
|
|
continue;
|
|
/* Found item matching this key */
|
|
x509s->setRefKey(key);
|
|
q.bindValue(1, x509s->getSqlItemId());
|
|
q.exec();
|
|
mainwin->dbSqlError(q.lastError());
|
|
}
|
|
}
|
|
|
|
pki_base* db_key::insert(pki_base *item)
|
|
{
|
|
pki_key *lkey = (pki_key *)item;
|
|
pki_key *oldkey;
|
|
|
|
oldkey = (pki_key *)getByReference(lkey);
|
|
if (oldkey != NULL) {
|
|
if ((oldkey->isPrivKey() && lkey->isPrivKey()) || lkey->isPubKey()){
|
|
XCA_INFO(
|
|
tr("The key is already in the database as:\n'%1'\nand is not going to be imported").arg(oldkey->getIntName()));
|
|
delete(lkey);
|
|
return NULL;
|
|
}
|
|
else {
|
|
XCA_INFO(
|
|
tr("The database already contains the public part of the imported key as\n'%1\nand will be completed by the new, private part of the key").arg(oldkey->getIntName()));
|
|
lkey->setIntName(oldkey->getIntName());
|
|
deletePKI(index(oldkey->row(), 0, QModelIndex()));
|
|
}
|
|
}
|
|
insertPKI(lkey);
|
|
|
|
return lkey;
|
|
}
|
|
|
|
void db_key::newItem() {
|
|
newItem("");
|
|
}
|
|
|
|
void db_key::newItem(QString name)
|
|
{
|
|
NewKey *dlg = new NewKey(qApp->activeWindow(), name);
|
|
QProgressBar *bar;
|
|
QStatusBar *status = mainwin->statusBar();
|
|
pki_evp *nkey = NULL;
|
|
pki_scard *cardkey = NULL;
|
|
pki_key *key = NULL;
|
|
|
|
if (!dlg->exec()) {
|
|
delete dlg;
|
|
return;
|
|
}
|
|
int ksize = dlg->getKeysize();
|
|
if (ksize > 0) {
|
|
if (ksize < 32) {
|
|
XCA_WARN(tr("Key size too small !"));
|
|
delete dlg;
|
|
return;
|
|
}
|
|
if (ksize < 1024 || ksize > 8192)
|
|
if (!XCA_YESNO(tr("You are sure to create a key of the size: %1 ?").arg(ksize))) {
|
|
delete dlg;
|
|
return;
|
|
}
|
|
}
|
|
mainwin->repaint();
|
|
bar = new QProgressBar();
|
|
status->addPermanentWidget(bar, 1);
|
|
try {
|
|
if (dlg->isToken()) {
|
|
key = cardkey = new pki_scard(dlg->keyDesc->text());
|
|
cardkey->generateKey_card(dlg->getKeytype(),
|
|
dlg->getKeyCardSlot(), ksize,
|
|
dlg->getKeyCurve_nid(), bar);
|
|
} else {
|
|
key = nkey = new pki_evp(dlg->keyDesc->text());
|
|
nkey->generate(ksize, dlg->getKeytype(), bar,
|
|
dlg->getKeyCurve_nid());
|
|
}
|
|
key = (pki_key*)insert(key);
|
|
emit keyDone(key);
|
|
createSuccess(key);
|
|
|
|
} catch (errorEx &err) {
|
|
delete key;
|
|
mainwin->Error(err);
|
|
}
|
|
if (dlg->rememberDefault->isChecked()) {
|
|
QString def = dlg->getAsString();
|
|
if (dlg->setDefault(def) == 0)
|
|
mainwin->storeSetting("defaultkey", def);
|
|
}
|
|
status->removeWidget(bar);
|
|
delete bar;
|
|
delete dlg;
|
|
}
|
|
|
|
void db_key::load(void)
|
|
{
|
|
load_key l;
|
|
load_default(l);
|
|
}
|
|
|
|
void db_key::showPki(pki_base *pki)
|
|
{
|
|
pki_evp *key = (pki_evp *)pki;
|
|
KeyDetail *dlg = new KeyDetail(mainwin);
|
|
if (dlg) {
|
|
dlg->setKey(key);
|
|
dlg->exec();
|
|
delete dlg;
|
|
}
|
|
}
|
|
exportType::etype db_key::clipboardFormat(QModelIndexList indexes) const
|
|
{
|
|
QList<exportType> types;
|
|
bool allPriv = true;
|
|
bool allRSADSA = true;
|
|
|
|
foreach(QModelIndex idx, indexes) {
|
|
pki_key *key = static_cast<pki_key*>
|
|
(idx.internalPointer());
|
|
if (key->isPubKey() || key->isToken())
|
|
allPriv = false;
|
|
if (key->getKeyType() != EVP_PKEY_RSA &&
|
|
key->getKeyType() != EVP_PKEY_DSA)
|
|
allRSADSA = false;
|
|
}
|
|
if (!allPriv && !allRSADSA)
|
|
return exportType::PEM_key;
|
|
|
|
types << exportType(exportType::PEM_key, "pem", tr("PEM public"));
|
|
if (allRSADSA)
|
|
types << exportType(exportType::SSH2_public,
|
|
"pub", tr("SSH2 public"));
|
|
if (allPriv)
|
|
types << exportType(exportType::PEM_private, "pem",
|
|
tr("PEM private"))
|
|
<< exportType(exportType::PKCS8, "pk8",
|
|
"PKCS#8");
|
|
|
|
ExportDialog *dlg = new ExportDialog(mainwin,
|
|
tr("Export keys to Clipboard"), QString(), NULL,
|
|
MainWindow::keyImg, types);
|
|
|
|
dlg->filename->setText(tr("Clipboard"));
|
|
dlg->filename->setEnabled(false);
|
|
dlg->fileBut->setEnabled(false);
|
|
if (!dlg->exec()) {
|
|
delete dlg;
|
|
return exportType::Separator;
|
|
}
|
|
return dlg->type();
|
|
}
|
|
|
|
void db_key::store(QModelIndex index)
|
|
{
|
|
const EVP_CIPHER *enc = NULL;
|
|
QString title = tr("Export public key [%1]");
|
|
QList<exportType> types;
|
|
|
|
if (!index.isValid())
|
|
return;
|
|
|
|
pki_key *key =static_cast<pki_evp*>(index.internalPointer());
|
|
pki_evp *privkey = (pki_evp *)key;
|
|
|
|
types <<
|
|
exportType(exportType::PEM_key, "pem", tr("PEM public")) <<
|
|
exportType(exportType::DER_key, "der", tr("DER public"));
|
|
if (key->getKeyType() == EVP_PKEY_RSA ||
|
|
key->getKeyType() == EVP_PKEY_DSA)
|
|
types << exportType(exportType::SSH2_public,
|
|
"pub", tr("SSH2 public"));
|
|
if (!key->isPubKey() && !key->isToken()) {
|
|
QList<exportType> usual;
|
|
types <<
|
|
exportType(exportType::DER_private, "der",
|
|
tr("DER private")) <<
|
|
exportType(exportType::PEM_private_encrypt, "pem",
|
|
tr("PEM encryped")) <<
|
|
exportType(exportType::PKCS8, "pk8",
|
|
"PKCS#8");
|
|
usual <<
|
|
exportType(exportType::PEM_private, "pem",
|
|
tr("PEM private")) <<
|
|
exportType(exportType::PKCS8_encrypt, "pk8",
|
|
tr("PKCS#8 encrypted"));
|
|
title = tr("Export private key [%1]");
|
|
types = usual << exportType() << types;
|
|
}
|
|
ExportDialog *dlg = new ExportDialog(mainwin,
|
|
title.arg(key->getTypeString()),
|
|
tr("Private Keys ( *.pem *.der *.pk8 );; "
|
|
"SSH Public Keys ( *.pub )"), key,
|
|
key->isToken() ? MainWindow::scardImg : MainWindow::keyImg,
|
|
types);
|
|
|
|
if (!dlg->exec()) {
|
|
delete dlg;
|
|
return;
|
|
}
|
|
QString fname = dlg->filename->text();
|
|
try {
|
|
exportType::etype type = dlg->type();
|
|
switch (type) {
|
|
case exportType::DER_key:
|
|
key->writePublic(fname, false);
|
|
break;
|
|
case exportType::DER_private:
|
|
privkey->writeKey(fname, NULL, NULL, false);
|
|
break;
|
|
case exportType::PEM_key:
|
|
key->writePublic(fname, true);
|
|
break;
|
|
case exportType::PEM_private_encrypt:
|
|
enc = EVP_des_ede3_cbc();
|
|
/* fallthrough */
|
|
case exportType::PEM_private:
|
|
privkey->writeKey(fname, enc,
|
|
PwDialog::pwCallback, true);
|
|
break;
|
|
case exportType::PKCS8_encrypt:
|
|
enc = EVP_des_ede3_cbc();
|
|
/* fallthrough */
|
|
case exportType::PKCS8:
|
|
privkey->writePKCS8(fname, enc,
|
|
PwDialog::pwCallback, true);
|
|
break;
|
|
case exportType::SSH2_public:
|
|
key->writeSSH2public(fname);
|
|
break;
|
|
default:
|
|
exit(1);
|
|
}
|
|
}
|
|
catch (errorEx &err) {
|
|
mainwin->Error(err);
|
|
}
|
|
delete dlg;
|
|
}
|
|
|
|
void db_key::setOwnPass(QModelIndex idx, enum pki_key::passType x)
|
|
{
|
|
pki_evp *targetKey;
|
|
if (!idx.isValid())
|
|
return;
|
|
targetKey = static_cast<pki_evp*>(idx.internalPointer());
|
|
if (targetKey->isToken()) {
|
|
throw errorEx(tr("Tried to change password of a token"));
|
|
}
|
|
targetKey->setOwnPass(x);
|
|
}
|