mirror of
https://github.com/chris2511/xca.git
synced 2026-09-12 19:51:05 +05:00
Close #89: ta.key for OpenVPN tls-auth
The ta-key will be generated on-demand and assigned to the issuing CA. All issued certificates of this CA will use the same ta-key. It can be exported as single file and will also be part of the exported openvpn configuration file. Extend export tests to validate the output of ta-keys and adapt the OpenVPN conf file export test to also check the ta-key.
This commit is contained in:
parent
0dd587a3f2
commit
1199d776d2
@ -72,8 +72,8 @@ const QString &database_model::detect_provider()
|
||||
|
||||
QSqlError database_model::initSqlDB()
|
||||
{
|
||||
#define MAX_SCHEMAS 7
|
||||
#define SCHEMA_VERSION "7"
|
||||
#define MAX_SCHEMAS 8
|
||||
#define SCHEMA_VERSION "8"
|
||||
|
||||
QStringList schemas[MAX_SCHEMAS];
|
||||
|
||||
|
||||
@ -305,6 +305,16 @@
|
||||
<< "UPDATE settings SET value='7' WHERE key_='schema'"
|
||||
;
|
||||
|
||||
schemas[7]
|
||||
// OpenVPN TA (tls-auth) keys associated to the CA to be
|
||||
// the same for all issued certificates
|
||||
<< "CREATE TABLE takeys ("
|
||||
"item INTEGER UNIQUE, " // reference to items(id) of the CA
|
||||
"value " B64_BLOB ", " // The base64 encoded 2048 bit key
|
||||
"FOREIGN KEY (item) REFERENCES items (id))"
|
||||
<< "UPDATE settings SET value='8' WHERE key_='schema'"
|
||||
;
|
||||
|
||||
/* When adding new tables or views, also add them to the list
|
||||
* in XSqlQuery::rewriteQuery(QString) in lib/sql.cpp
|
||||
*/
|
||||
|
||||
@ -566,11 +566,11 @@ int db_x509::exportFlags(const QModelIndex &idx) const
|
||||
return disable_flags;
|
||||
}
|
||||
|
||||
void db_x509::writeTaggedPEM(BioByteArray &b, const QString &tag, XFile &file)
|
||||
void db_x509::writeTaggedPEM(const BioByteArray &b, const QString &tag, XFile &file)
|
||||
{
|
||||
if (b.size() > 0) {
|
||||
file.write(QString("<%1>\n").arg(tag).toLatin1());
|
||||
file.write(b);
|
||||
file.write(b.byteArray());
|
||||
file.write(QString("</%1>\n").arg(tag).toLatin1());
|
||||
}
|
||||
}
|
||||
@ -609,6 +609,7 @@ void db_x509::exportItems(const QModelIndexList &list,
|
||||
writeTaggedPEM(extra, "extra-certs", file);
|
||||
writeTaggedPEM(cert, "cert", file);
|
||||
writeTaggedPEM(key, "key", file);
|
||||
writeTaggedPEM(crt->getTaKey().toLatin1(), "tls-auth", file);
|
||||
} else if (xport->match_all(F_CHAIN)) {
|
||||
for (; crt && crt != oldcrt; oldcrt = crt, crt = crt->getSigner())
|
||||
crt->writeCert(file, true);
|
||||
@ -655,6 +656,8 @@ void db_x509::exportItems(const QModelIndexList &list,
|
||||
writeVcalendar(file, vcal);
|
||||
} else if (xport->match_all(F_CONFIG)) {
|
||||
crt->opensslConf(file);
|
||||
} else if (xport->match_all(F_TAKEY)) {
|
||||
file.write(crt->getTaKey().toLatin1());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -23,7 +23,7 @@ class db_x509: public db_x509super
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
static void writeTaggedPEM(BioByteArray &b,
|
||||
static void writeTaggedPEM(const BioByteArray &b,
|
||||
const QString &tag, XFile &file);
|
||||
protected:
|
||||
dbheaderList getHeaders();
|
||||
|
||||
@ -77,6 +77,7 @@ new pki_export(16, x509, "txt", tr("Certificate Index file"), F_INDEX | F_CA,
|
||||
new pki_export(17, x509, "ics", tr("vCalendar"), F_CAL, tr("vCalendar expiry reminder for the selected items")),
|
||||
new pki_export(18, x509, "ics", tr("CA vCalendar"), F_CAL | F_CA, tr("vCalendar expiry reminder containing all issued, valid certificates, the CA itself and the latest CRL")),
|
||||
new pki_export(38, x509, "conf", tr("OpenSSL config"), F_SINGLE | F_CONFIG, tr("OpenSSL configuration file to create a certificate or request with the openssl commandline tool")),
|
||||
new pki_export(39, x509, "key", tr("OpenVPN tls-auth key"), F_SINGLE | F_TAKEY, tr("The OpenVPN tls-auth key is a secret key shared between endpoints")),
|
||||
|
||||
new pki_export(19, asym_key, "pem", tr("PEM public"), F_PEM | F_CLIPBOARD, tr("Text format of the public key in one PEM file")),
|
||||
new pki_export(20, asym_key, "pem", tr("PEM private"), F_PEM | F_PRIVATE | F_USUAL | F_CLIPBOARD, tr("Unencrypted private key in text format")),
|
||||
|
||||
@ -49,6 +49,7 @@ enum {
|
||||
F_DER = BIT(19),/* DER format */
|
||||
F_OVPN = BIT(20),/* OpenVPN format */
|
||||
F_CONFIG = BIT(21),/* OpenSSL config format */
|
||||
F_TAKEY = BIT(22),/* OpenVPN TLS-Auth key */
|
||||
};
|
||||
|
||||
class pki_export : public QObject {
|
||||
|
||||
@ -17,6 +17,8 @@
|
||||
#include "exception.h"
|
||||
#include "pass_info.h"
|
||||
|
||||
#include <openssl/rand.h>
|
||||
|
||||
pki_x509::pki_x509(X509 *c)
|
||||
:pki_x509super(), cert(c)
|
||||
{
|
||||
@ -143,6 +145,7 @@ QSqlError pki_x509::deleteSqlData()
|
||||
<< "UPDATE crls SET issuer=NULL WHERE issuer=?"
|
||||
<< "UPDATE certs SET issuer=NULL WHERE issuer=?"
|
||||
<< "DELETE FROM revocations WHERE caId=?"
|
||||
<< "DELETE FROM takeys WHERE item=?"
|
||||
;
|
||||
foreach(QString task, tasks) {
|
||||
SQL_PREPARE(q, task);
|
||||
@ -273,6 +276,42 @@ pki_x509 *pki_x509::getBySerial(const a1int &a) const
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QString pki_x509::getTaKey()
|
||||
{
|
||||
XSqlQuery q;
|
||||
QByteArray b;
|
||||
pki_x509 *issuer = getSigner();
|
||||
if (!isCA() && issuer && issuer != this)
|
||||
return issuer->getTaKey();
|
||||
|
||||
Transaction;
|
||||
if (!TransBegin())
|
||||
return QString();
|
||||
|
||||
SQL_PREPARE(q, "SELECT value FROM takeys WHERE item = ?");
|
||||
q.bindValue(0, sqlItemId);
|
||||
q.exec();
|
||||
if (q.next()) {
|
||||
b = QByteArray::fromBase64(q.value(0).toByteArray());
|
||||
qDebug() << "Loaded TA key" << this << b.size() << QString::fromLatin1(b.toHex()).left(6);
|
||||
} else {
|
||||
b.resize(2048/8);
|
||||
RAND_bytes((unsigned char*)b.data(), 2048/8);
|
||||
SQL_PREPARE(q, "INSERT INTO takeys (item, value) VALUES ( ?, ? )");
|
||||
q.bindValue(0, sqlItemId);
|
||||
q.bindValue(1, b.toBase64());
|
||||
q.exec();
|
||||
qDebug() << "Generated TA key" << this << b.size() << QString::fromLatin1(b.toHex()).left(6);
|
||||
}
|
||||
TransCommit();
|
||||
QString takey("-----BEGIN OpenVPN Static key V1-----\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";
|
||||
return takey;
|
||||
}
|
||||
|
||||
a1int pki_x509::hashInfo(const EVP_MD *md) const
|
||||
{
|
||||
unsigned char digest[EVP_MAX_MD_SIZE];
|
||||
|
||||
@ -163,6 +163,7 @@ class pki_x509 : public pki_x509super
|
||||
void restoreSql(const QSqlRecord &rec);
|
||||
QStringList icsVEVENT() const;
|
||||
QStringList icsVEVENT_ca() const;
|
||||
QString getTaKey();
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(pki_x509 *);
|
||||
|
||||
@ -125,7 +125,7 @@ QString XSqlQuery::rewriteQuery(QString _q)
|
||||
"items" , "crls" , "private_keys" , "public_keys" ,
|
||||
"tokens" , "token_mechanism" , "templates" , "certs" ,
|
||||
"authority" , "revocations" , "requests" , "x509super" ,
|
||||
"settings" ,
|
||||
"settings" , "takeys",
|
||||
|
||||
"view_public_keys" , "view_certs" , "view_requests" ,
|
||||
"view_crls" , "view_templates" , "view_private",
|
||||
|
||||
@ -24,14 +24,14 @@
|
||||
void check_pems(const QString &name, int n, QStringList matches = QStringList())
|
||||
{
|
||||
int begin = 0, end = 0;
|
||||
qWarning() << "Expecting" << n << "PEMs in" << name;
|
||||
qDebug() << "Expecting" << n << "PEMs in" << name;
|
||||
|
||||
#if 0
|
||||
// This is an endless loop: open_read() succeeds,
|
||||
// but isOpen returns false. Stop investigating, use POSIX open()
|
||||
XFile F(name);
|
||||
while (!F.isOpen()) {
|
||||
qWarning() << "OPEN" << name;
|
||||
qDebug() << "OPEN" << name;
|
||||
F.close();
|
||||
Q_ASSERT(F.open_read());
|
||||
}
|
||||
@ -45,7 +45,7 @@ void check_pems(const QString &name, int n, QStringList matches = QStringList())
|
||||
QByteArray all(buf, ret);
|
||||
close(fd);
|
||||
#endif
|
||||
qWarning() << "ALL" << name << all.size();
|
||||
qDebug() << "ALL" << name << all.size();
|
||||
|
||||
foreach(QByteArray b, all.split('\n')) {
|
||||
if (b.indexOf("-----BEGIN ") == 0)
|
||||
@ -63,7 +63,7 @@ void check_pems(const QString &name, int n, QStringList matches = QStringList())
|
||||
QCOMPARE(begin, n);
|
||||
QCOMPARE(end, n);
|
||||
foreach(QString m, matches) {
|
||||
qWarning() << QString("Pattern %1 not found in %2").arg(m).arg(name);
|
||||
qDebug() << QString("Pattern %1 not found in %2").arg(m).arg(name);
|
||||
}
|
||||
QCOMPARE(matches.size(), 0);
|
||||
}
|
||||
@ -76,7 +76,7 @@ void verify_key(const QString &name, QList<unsigned> hashes, bool priv)
|
||||
QCOMPARE(pems->get().size(), hashes.size());
|
||||
foreach (pki_base *pki, pems->get()) {
|
||||
unsigned hash = pki->hash();
|
||||
qWarning() << pki->getIntName() << hash;
|
||||
qDebug() << pki->getIntName() << hash;
|
||||
QVERIFY2(hashes.contains(hash),
|
||||
qPrintable(QString("%1 not expected in %2")
|
||||
.arg(pki->getIntName())
|
||||
@ -220,10 +220,11 @@ void test_main::exportFormat()
|
||||
export_by_id(4, file, list, certs);
|
||||
verify_key(file, QList<unsigned> {
|
||||
ROOT_HASH, INTER_HASH, END_HASH, ENDKEY_HASH }, true);
|
||||
check_pems(file, 4, QStringList { " RSA PRIVATE KEY-",
|
||||
check_pems(file, 5, QStringList { " RSA PRIVATE KEY-",
|
||||
" CERTIFICATE-", " CERTIFICATE-"," CERTIFICATE-",
|
||||
"<ca>", "</ca>", "<extra-certs>", "</extra-certs>",
|
||||
"<cert>", "</cert>", "<key>", "</key>" });
|
||||
"<cert>", "</cert>", "<key>", "</key>",
|
||||
"<tls-auth>", "</tls-auth>" });
|
||||
// Export Endentity as PKCS#7
|
||||
file = AUTOFILE(CERTP7)
|
||||
export_by_id(8, file, list, certs);
|
||||
@ -235,9 +236,15 @@ void test_main::exportFormat()
|
||||
verify_file(file, QList<unsigned> { ROOT_HASH, INTER_HASH, END_HASH });
|
||||
check_pems(file, 0);
|
||||
// Export Endentity as DER certificate
|
||||
file = AUTOFILE(CERTDER)
|
||||
export_by_id(13, file, list, certs);
|
||||
verify_file(file, QList<unsigned> { END_HASH });
|
||||
check_pems(file, 0);
|
||||
// Export Endentity as OpenVPN config file
|
||||
file = AUTOFILE(OPENVPNTA)
|
||||
export_by_id(39, file, list, certs);
|
||||
check_pems(file, 1, QStringList {
|
||||
"BEGIN OpenVPN Static key V1", "END OpenVPN Static key V1" });
|
||||
|
||||
// Export Endentity key
|
||||
list.clear();
|
||||
|
||||
@ -68,6 +68,7 @@ void test_main::openDB()
|
||||
new pw_expect("testdbpass", pw_ok),
|
||||
});
|
||||
mainwin->close_database();
|
||||
QFile::remove("testdb.xdb");
|
||||
Database.open("testdb.xdb");
|
||||
Settings["pkcs12_keep_legacy"] = true;
|
||||
mainwin->setup_open_database();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user