diff --git a/lib/load_obj.cpp b/lib/load_obj.cpp index da72a054..8fed71cc 100644 --- a/lib/load_obj.cpp +++ b/lib/load_obj.cpp @@ -152,6 +152,14 @@ load_db::load_db() caption = QObject::tr("Open XCA Database"); } +/* OpenVPN TA key */ +load_takey::load_takey() + :load_base() +{ + filter = QObject::tr("OpenVPN tls-auth key ( *.key );;") + filter; + caption = QObject::tr("Import OpenVPN tls-auth key"); +} + /* Shared library */ load_pkcs11::load_pkcs11() :load_base() diff --git a/lib/load_obj.h b/lib/load_obj.h index a3559ed2..0cae699d 100644 --- a/lib/load_obj.h +++ b/lib/load_obj.h @@ -79,6 +79,12 @@ class load_db: public load_base load_db(); }; +class load_takey: public load_base +{ + public: + load_takey(); +}; + class load_pkcs11: public load_base { public: diff --git a/lib/pki_x509.cpp b/lib/pki_x509.cpp index 44edc6bb..22264908 100644 --- a/lib/pki_x509.cpp +++ b/lib/pki_x509.cpp @@ -276,6 +276,9 @@ pki_x509 *pki_x509::getBySerial(const a1int &a) const return NULL; } +#define D5 "-----" +#define OVPN_TA_KEY "OpenVPN Static key V1" + QString pki_x509::getTaKey() { XSqlQuery q; @@ -304,14 +307,69 @@ QString pki_x509::getTaKey() qDebug() << "Generated TA key" << this << b.size() << QString::fromLatin1(b.toHex()).left(6); } TransCommit(); - QString takey("-----BEGIN OpenVPN Static key V1-----\n"); + QString takey(D5 "BEGIN " OVPN_TA_KEY D5 "\n"); QString hex(QString::fromLatin1(b.toHex())); for (int i=0; i<16; i++) takey += hex.mid(32*i, 32) + "\n"; - takey += "-----END OpenVPN Static key V1-----\n"; + takey += D5 "END " OVPN_TA_KEY D5 "\n"; return takey; } +bool pki_x509::importTaKey(const QByteArray &takey) +{ + int start = takey.indexOf(D5 "BEGIN " OVPN_TA_KEY D5); + int end = takey.indexOf(D5 "END " OVPN_TA_KEY D5); + QByteArray data, existing_takey; + bool existed= false; + + if (start >= 0 && end > 0 && start < end) { + start += sizeof D5 "BEGIN " OVPN_TA_KEY D5; + data = QByteArray::fromHex(takey.mid(start, end-start)); + qDebug() << "TAKEY content" << start << end << data.size(); + } + if (data.size() != 2048/8) { + XCA_ERROR(tr("Invalid OpenVPN tls-auth key")); + return false; + } + + XSqlQuery q; + Transaction; + if (!TransBegin()) + return false; + + SQL_PREPARE(q, "SELECT value FROM takeys WHERE item = ?"); + q.bindValue(0, sqlItemId); + q.exec(); + if (q.next()) { + existed = true; + existing_takey = QByteArray::fromBase64(q.value(0).toByteArray()); + qDebug() << "Existing TA key" << this << existing_takey.size() + << QString::fromLatin1(existing_takey.toHex()).left(6); + } + if (existing_takey != data) { + if (existed) + SQL_PREPARE(q, "UPDATE takeys SET value = ? WHERE item = ?"); + else + SQL_PREPARE(q, "INSERT INTO takeys (item, value) VALUES ( ?, ? )"); + q.bindValue(0, sqlItemId); + q.bindValue(1, data.toBase64()); + q.exec(); + } + TransCommit(); + QSqlError e = q.lastError(); + if (e.isValid()) { + XCA_ERROR(tr("Failed to import tls-auth key")); + return false; + } else if (existing_takey == data) { + XCA_INFO(tr("Same tls-auth key already stored for this CA")); + } else if (existing_takey.isEmpty()) { + XCA_INFO(tr("New tls-auth key successfully imported")); + } else { + XCA_INFO(tr("Existing tls-auth key successfully replaced")); + } + return true; +} + a1int pki_x509::hashInfo(const EVP_MD *md) const { unsigned char digest[EVP_MAX_MD_SIZE]; diff --git a/lib/pki_x509.h b/lib/pki_x509.h index 3aec5eea..b48b37bf 100644 --- a/lib/pki_x509.h +++ b/lib/pki_x509.h @@ -164,6 +164,7 @@ class pki_x509 : public pki_x509super QStringList icsVEVENT() const; QStringList icsVEVENT_ca() const; QString getTaKey(); + bool importTaKey(const QByteArray &takey); }; Q_DECLARE_METATYPE(pki_x509 *); diff --git a/widgets/CertTreeView.cpp b/widgets/CertTreeView.cpp index f8b01fa6..8f2b5820 100644 --- a/widgets/CertTreeView.cpp +++ b/widgets/CertTreeView.cpp @@ -19,6 +19,7 @@ #include #include +#include #include void CertTreeView::fillContextMenu(QMenu *menu, QMenu *subExport, @@ -27,7 +28,6 @@ void CertTreeView::fillContextMenu(QMenu *menu, QMenu *subExport, QMenu *subCa; bool parentCanSign, multi, hasScard, sameParent, allRevoked, allUnrevoked; - pki_key *privkey; X509SuperTreeView::fillContextMenu(menu, subExport, index, indexes); @@ -35,13 +35,12 @@ void CertTreeView::fillContextMenu(QMenu *menu, QMenu *subExport, menu->addAction(tr("Import from PKCS#7"), this, SLOT(loadPKCS7())); pki_x509 *cert = db_base::fromIndex(index); - pki_x509 *parent; if (indexes.size() == 0 || !cert) return; - privkey = cert->getRefKey(); - parent = cert->getSigner(); + pki_key *privkey = cert->getRefKey(); + pki_x509 *parent = cert->getSigner(); parentCanSign = parent && parent->canSign() && (parent != cert); hasScard = pkcs11::libraries.loaded(); @@ -79,8 +78,11 @@ void CertTreeView::fillContextMenu(QMenu *menu, QMenu *subExport, subCa->addAction(tr("Properties"), this, SLOT(caProperties())); subCa->addAction(tr("Generate CRL"), this, SLOT(genCrl())); subCa->addAction(tr("Manage revocations"), this, - SLOT(manageRevocations())); + SLOT(manageRevocations())); subCa->setEnabled(cert->canSign()); + + menu->addAction(tr("Import OpenVPN tls-auth key"), this, + SLOT(loadTaKey()))->setEnabled(cert->isCA()); } if (parent == cert && parent->canSign()) menu->addAction(tr("Renewal"), this, SLOT(certRenewal())); @@ -125,6 +127,22 @@ void CertTreeView::loadPKCS7() load_default(&l); } +void CertTreeView::loadTaKey() +{ + pki_x509 *ca = db_base::fromIndex(currentIndex()); + if (!ca || !ca->isCA()) + return; + + load_takey l; + QString fname = QFileDialog::getOpenFileName(this, l.caption, + getHomeDir(), l.filter); + if (fname.isEmpty()) + return; + XFile f(fname); + f.open_read(); + ca->importTaKey(f.read(4096)); +} + void CertTreeView::genCrl() { pki_x509 *ca = db_base::fromIndex(currentIndex()); diff --git a/widgets/CertTreeView.h b/widgets/CertTreeView.h index a89386cc..10f381b9 100644 --- a/widgets/CertTreeView.h +++ b/widgets/CertTreeView.h @@ -42,5 +42,6 @@ class CertTreeView: public X509SuperTreeView void revoke(); void unRevoke(); void load(); + void loadTaKey(); }; #endif