summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Kiagiadakis <kiagiadakis.george@gmail.com>2012-05-07 12:38:11 (GMT)
committerGeorge Kiagiadakis <kiagiadakis.george@gmail.com>2012-05-09 21:05:56 (GMT)
commitd96ba6ab3a27204c51cfac8f4d4711d82fc8b5c3 (patch)
tree98187e23e35ede3f0788dada947a27abe2d47628
parent34526a2677c4f4f4c9672bc05d42c8f9e9534e83 (diff)
downloadqca-d96ba6ab3a27204c51cfac8f4d4711d82fc8b5c3.tar.gz
qca-d96ba6ab3a27204c51cfac8f4d4711d82fc8b5c3.tar.xz
-rw-r--r--plugins/qca-ossl/qca-ossl.cpp140
-rw-r--r--unittest/certunittest/certunittest.cpp104
2 files changed, 222 insertions, 22 deletions
diff --git a/plugins/qca-ossl/qca-ossl.cpp b/plugins/qca-ossl/qca-ossl.cpp
index 875ac65..80ff0b1 100644
--- a/plugins/qca-ossl/qca-ossl.cpp
+++ b/plugins/qca-ossl/qca-ossl.cpp
@@ -36,6 +36,7 @@
#include <openssl/x509v3.h>
#include <openssl/pkcs12.h>
#include <openssl/ssl.h>
+#include <openssl/ocsp.h>
#ifndef OSSL_097
// comment this out if you'd rather use openssl 0.9.6
@@ -3102,6 +3103,7 @@ QDateTime ASN1_UTCTIME_QDateTime(ASN1_UTCTIME *tm, int *isGmt)
qdate.setYMD(y+1900, M, d);
qtime.setHMS(h,m,s);
qdt.setDate(qdate); qdt.setTime(qtime);
+ qdt.setTimeSpec(gmt ? Qt::UTC : Qt::LocalTime);
auq_err:
if (isGmt) *isGmt = gmt;
return qdt;
@@ -3661,12 +3663,8 @@ public:
return cert;
}
- virtual CRLContext *createCRL(const QDateTime &nextUpdate) const
- {
- // TODO: implement
- Q_UNUSED(nextUpdate)
- return 0;
- }
+ // implemented later because it depends on MyCRLContext
+ virtual CRLContext *createCRL(const QDateTime &nextUpdate) const;
virtual void setup(const CertContext &cert, const PKeyContext &priv)
{
@@ -3774,14 +3772,8 @@ public:
return cert;
}
- virtual CRLContext *updateCRL(const CRLContext &crl, const QList<CRLEntry> &entries, const QDateTime &nextUpdate) const
- {
- // TODO: implement
- Q_UNUSED(crl)
- Q_UNUSED(entries)
- Q_UNUSED(nextUpdate)
- return 0;
- }
+ // implemented later because it depends on MyCRLContext
+ virtual CRLContext *updateCRL(const CRLContext &crl, const QList<CRLEntry> &entries, const QDateTime &nextUpdate) const;
virtual Provider::Context *clone() const
{
@@ -4561,6 +4553,126 @@ Validity MyCertContext::validate_chain(const QList<CertContext*> &chain, const Q
return ValidityGood;
}
+CRLContext *MyCAContext::createCRL(const QDateTime &nextUpdate) const
+{
+ const EVP_MD *md;
+ if(privateKey->key()->type() == PKey::RSA)
+ md = EVP_sha1();
+ else if(privateKey->key()->type() == PKey::DSA)
+ md = EVP_dss1();
+ else
+ return 0;
+
+ X509_CRL *crl = X509_CRL_new();
+ X509_CRL_set_issuer_name(crl, X509_get_subject_name(caCert.cert));
+
+ ASN1_TIME *lastUpdateASN1 = ASN1_TIME_new();
+ ASN1_TIME_set(lastUpdateASN1, QDateTime::currentDateTime().toTime_t());
+ X509_CRL_set_lastUpdate(crl, lastUpdateASN1);
+ ASN1_TIME_free(lastUpdateASN1);
+
+ ASN1_TIME *nextUpdateASN1 = ASN1_TIME_new();
+ ASN1_TIME_set(nextUpdateASN1, nextUpdate.toTime_t());
+ X509_CRL_set_nextUpdate(crl, nextUpdateASN1);
+ ASN1_TIME_free(nextUpdateASN1);
+
+ if (!X509_CRL_sign(crl, privateKey->get_pkey(), md))
+ {
+ X509_CRL_free(crl);
+ return 0;
+ }
+
+ MyCRLContext *cntxt = new MyCRLContext(provider());
+ cntxt->fromX509(crl);
+ X509_CRL_free(crl);
+ return cntxt;
+}
+
+CRLContext *MyCAContext::updateCRL(const CRLContext &crl, const QList<CRLEntry> &entries, const QDateTime &nextUpdate) const
+{
+ const EVP_MD *md;
+ if(privateKey->key()->type() == PKey::RSA)
+ md = EVP_sha1();
+ else if(privateKey->key()->type() == PKey::DSA)
+ md = EVP_dss1();
+ else
+ return 0;
+
+ MyCRLContext *cntxt = static_cast<MyCRLContext*>(crl.clone());
+ X509_CRL *x = cntxt->item.crl;
+
+ foreach(const CRLEntry & entry, entries) {
+ X509_REVOKED *r = X509_REVOKED_new();
+
+ //revocation date
+ ASN1_TIME *revDate = ASN1_TIME_new();
+ ASN1_TIME_set(revDate, entry.time().toTime_t());
+ X509_REVOKED_set_revocationDate(r, revDate);
+ ASN1_TIME_free(revDate);
+
+ // serial
+ BIGNUM *bn = bi2bn(entry.serialNumber());
+ ASN1_INTEGER *tmpint = BN_to_ASN1_INTEGER(bn, NULL);
+ X509_REVOKED_set_serialNumber(r, tmpint);
+ ASN1_INTEGER_free(tmpint);
+ BN_free(bn);
+
+ //reason
+ ASN1_ENUMERATED *reason = ASN1_ENUMERATED_new();
+ switch(entry.reason()) {
+ case CRLEntry::KeyCompromise:
+ ASN1_ENUMERATED_set(reason, OCSP_REVOKED_STATUS_KEYCOMPROMISE);
+ break;
+ case CRLEntry::CACompromise:
+ ASN1_ENUMERATED_set(reason, OCSP_REVOKED_STATUS_CACOMPROMISE);
+ break;
+ case CRLEntry::AffiliationChanged:
+ ASN1_ENUMERATED_set(reason, OCSP_REVOKED_STATUS_AFFILIATIONCHANGED);
+ break;
+ case CRLEntry::Superseded:
+ ASN1_ENUMERATED_set(reason, OCSP_REVOKED_STATUS_SUPERSEDED);
+ break;
+ case CRLEntry::CessationOfOperation:
+ ASN1_ENUMERATED_set(reason, OCSP_REVOKED_STATUS_CESSATIONOFOPERATION);
+ break;
+ case CRLEntry::CertificateHold:
+ ASN1_ENUMERATED_set(reason, OCSP_REVOKED_STATUS_CERTIFICATEHOLD);
+ break;
+ case CRLEntry::RemoveFromCRL:
+ ASN1_ENUMERATED_set(reason, OCSP_REVOKED_STATUS_REMOVEFROMCRL);
+ break;
+ default:
+ ASN1_ENUMERATED_set(reason, OCSP_REVOKED_STATUS_UNSPECIFIED);
+ break;
+ }
+ X509_REVOKED_add1_ext_i2d(r, NID_crl_reason, reason, 0, 0);
+ ASN1_ENUMERATED_free(reason);
+
+ X509_CRL_add0_revoked(x, r);
+ }
+
+ X509_CRL_sort(x);
+
+ ASN1_TIME *lastUpdateASN1 = ASN1_TIME_new();
+ ASN1_TIME_set(lastUpdateASN1, QDateTime::currentDateTime().toTime_t());
+ X509_CRL_set_lastUpdate(x, lastUpdateASN1);
+ ASN1_TIME_free(lastUpdateASN1);
+
+ ASN1_TIME *nextUpdateASN1 = ASN1_TIME_new();
+ ASN1_TIME_set(nextUpdateASN1, nextUpdate.toTime_t());
+ X509_CRL_set_nextUpdate(x, nextUpdateASN1);
+ ASN1_TIME_free(nextUpdateASN1);
+
+ if (!X509_CRL_sign(x, privateKey->get_pkey(), md))
+ {
+ delete cntxt;
+ return 0;
+ }
+
+ cntxt->make_props();
+ return cntxt;
+}
+
class MyPKCS12Context : public PKCS12Context
{
public:
diff --git a/unittest/certunittest/certunittest.cpp b/unittest/certunittest/certunittest.cpp
index c2c5595..5cc1ca4 100644
--- a/unittest/certunittest/certunittest.cpp
+++ b/unittest/certunittest/certunittest.cpp
@@ -1,5 +1,6 @@
/**
* Copyright (C) 2004-2006 Brad Hards <bradh@frogmouth.net>
+ * Copyright (C) 2012 George Kiagiadakis <kiagiadakis.george@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -50,6 +51,7 @@ private slots:
void crl2();
void csr();
void csr2();
+ void certificateAuthority();
void cleanupTestCase();
private:
QCA::Initializer* m_init;
@@ -998,8 +1000,8 @@ void CertUnitTest::crl()
// No keyid extension on this crl
QCOMPARE( QCA::arrayToHex( crl1.issuerKeyId() ), QString("") );
- QCOMPARE( crl1.thisUpdate(), QDateTime(QDate(2001, 8, 17), QTime(11, 12, 03)) );
- QCOMPARE( crl1.nextUpdate(), QDateTime(QDate(2006, 8, 16), QTime(11, 12, 03)) );
+ QCOMPARE( crl1.thisUpdate(), QDateTime(QDate(2001, 8, 17), QTime(11, 12, 03), Qt::UTC) );
+ QCOMPARE( crl1.nextUpdate(), QDateTime(QDate(2006, 8, 16), QTime(11, 12, 03), Qt::UTC) );
QCOMPARE( crl1.signatureAlgorithm(), QCA::EMSA3_MD5 );
@@ -1015,8 +1017,8 @@ void CertUnitTest::crl()
QCOMPARE( revokedList[1].serialNumber(), QCA::BigInteger("5") );
QCOMPARE( revokedList[0].reason(), QCA::CRLEntry::Unspecified );
QCOMPARE( revokedList[1].reason(), QCA::CRLEntry::Unspecified );
- QCOMPARE( revokedList[0].time(), QDateTime(QDate(2001, 8, 17), QTime(11, 10, 39)) );
- QCOMPARE( revokedList[1].time(), QDateTime(QDate(2001, 8, 17), QTime(11, 11, 59)) );
+ QCOMPARE( revokedList[0].time(), QDateTime(QDate(2001, 8, 17), QTime(11, 10, 39), Qt::UTC) );
+ QCOMPARE( revokedList[1].time(), QDateTime(QDate(2001, 8, 17), QTime(11, 11, 59), Qt::UTC) );
// convert to DER
QByteArray derCRL1 = crl1.toDER();
@@ -1054,8 +1056,8 @@ void CertUnitTest::crl2()
QVERIFY( issuer.values(QCA::Organization).contains("Test Certificates") );
QVERIFY( issuer.values(QCA::CommonName).contains("Good CA") );
- QCOMPARE( crl1.thisUpdate(), QDateTime(QDate(2001, 4, 19), QTime(14, 57, 20)) );
- QCOMPARE( crl1.nextUpdate(), QDateTime(QDate(2011, 4, 19), QTime(14, 57, 20)) );
+ QCOMPARE( crl1.thisUpdate(), QDateTime(QDate(2001, 4, 19), QTime(14, 57, 20), Qt::UTC) );
+ QCOMPARE( crl1.nextUpdate(), QDateTime(QDate(2011, 4, 19), QTime(14, 57, 20), Qt::UTC) );
QCOMPARE( crl1.signatureAlgorithm(), QCA::EMSA3_SHA1 );
@@ -1071,8 +1073,8 @@ void CertUnitTest::crl2()
QCOMPARE( revokedList[1].serialNumber(), QCA::BigInteger("15") );
QCOMPARE( revokedList[0].reason(), QCA::CRLEntry::KeyCompromise );
QCOMPARE( revokedList[1].reason(), QCA::CRLEntry::KeyCompromise );
- QCOMPARE( revokedList[0].time(), QDateTime(QDate(2001, 4, 19), QTime(14, 57, 20)) );
- QCOMPARE( revokedList[1].time(), QDateTime(QDate(2001, 4, 19), QTime(14, 57, 20)) );
+ QCOMPARE( revokedList[0].time(), QDateTime(QDate(2001, 4, 19), QTime(14, 57, 20), Qt::UTC) );
+ QCOMPARE( revokedList[1].time(), QDateTime(QDate(2001, 4, 19), QTime(14, 57, 20), Qt::UTC) );
// convert to DER
QByteArray derCRL1 = crl1.toDER();
@@ -1202,6 +1204,92 @@ void CertUnitTest::csr2()
}
}
}
+
+void CertUnitTest::certificateAuthority()
+{
+ QStringList providersToTest;
+ providersToTest.append("qca-ossl");
+ // providersToTest.append("qca-botan");
+
+ foreach(const QString provider, providersToTest) {
+ if( !QCA::isSupported( "ca,cert,crl,pkey,rsa", provider ) )
+ QWARN( QString( "Certificate authority not supported for "+provider).toLocal8Bit() );
+ else {
+ QCA::KeyGenerator keygen;
+ QCA::PrivateKey caKey = keygen.createRSA(1024, 65537, provider);
+
+ QCA::CertificateOptions options;
+ options.setAsCA();
+ options.setValidityPeriod(QDateTime::currentDateTime(),
+ QDateTime::currentDateTime().addYears(5));
+
+ QCA::CertificateInfoOrdered info;
+ info.append(QCA::CertificateInfoPair(QCA::CommonName, QLatin1String("CA Test")));
+ info.append(QCA::CertificateInfoPair(QCA::Email, QLatin1String("test@example.org")));
+ info.append(QCA::CertificateInfoPair(QCA::Organization, QLatin1String("KDE")));
+ info.append(QCA::CertificateInfoPair(QCA::Country, QLatin1String("USA")));
+ options.setInfoOrdered(info);
+
+ QCA::Certificate cacert(options, caKey, provider);
+ QVERIFY(!cacert.isNull());
+ QVERIFY(cacert.isCA());
+ QCOMPARE(cacert.commonName(), QLatin1String("CA Test"));
+
+ QCA::CertificateAuthority ca(cacert, caKey, provider);
+ QCOMPARE(ca.certificate(), cacert);
+
+ info.clear();
+ info.append(QCA::CertificateInfoPair(QCA::CommonName, QLatin1String("QCA")));
+ info.append(QCA::CertificateInfoPair(QCA::Email, QLatin1String("qca@example.org")));
+ info.append(QCA::CertificateInfoPair(QCA::Organization, QLatin1String("Qt")));
+ info.append(QCA::CertificateInfoPair(QCA::Country, QLatin1String("UK")));
+ options.setInfoOrdered(info);
+ options.setAsUser();
+ options.setSerialNumber(2);
+
+ QCA::PrivateKey certKey = keygen.createRSA(1024, 65537, provider);
+ QCA::Certificate cert = ca.createCertificate(certKey.toPublicKey(), options);
+
+ QVERIFY(!cert.isNull());
+ QVERIFY(!cert.isCA());
+ QCOMPARE(cert.commonName(), QLatin1String("QCA"));
+ QCOMPARE(cert.subjectInfo().value(QCA::CommonName), QLatin1String("QCA"));
+ QCOMPARE(cert.subjectInfo().value(QCA::Email), QLatin1String("qca@example.org"));
+ QCOMPARE(cert.subjectInfo().value(QCA::Organization), QLatin1String("Qt"));
+ QCOMPARE(cert.subjectInfo().value(QCA::Country), QLatin1String("UK"));
+ QCOMPARE(cert.issuerInfo().value(QCA::CommonName), QLatin1String("CA Test"));
+// QCOMPARE(cert.issuerInfo().value(QCA::Email), QLatin1String("test@example.org"));
+// QCOMPARE(cert.issuerInfo().value(QCA::Organization), QLatin1String("KDE"));
+// QCOMPARE(cert.issuerInfo().value(QCA::Country), QLatin1String("USA"));
+ QCOMPARE(cert.subjectPublicKey(), certKey.toPublicKey());
+ QVERIFY(cacert.isIssuerOf(cert));
+
+ QCOMPARE(QDateTime::currentDateTime().toTime_t(), QDateTime::currentDateTimeUtc().toTime_t());
+
+ QDateTime nextUpdate = QDateTime::currentDateTime().addYears(1);
+ QCA::CRL crl = ca.createCRL(nextUpdate);
+ QVERIFY(!crl.isNull());
+ QCOMPARE(crl.nextUpdate(), QDateTime::fromTime_t(nextUpdate.toTime_t()) /*drop msecs*/);
+ QCOMPARE(crl.issuerInfo().value(QCA::CommonName), QLatin1String("CA Test"));
+// QCOMPARE(crl.issuerInfo().value(QCA::Email), QLatin1String("test@example.org"));
+// QCOMPARE(crl.issuerInfo().value(QCA::Organization), QLatin1String("KDE"));
+// QCOMPARE(crl.issuerInfo().value(QCA::Country), QLatin1String("USA"));
+ QVERIFY(crl.revoked().isEmpty());
+
+ QCA::CRLEntry entry(cert, QCA::CRLEntry::KeyCompromise);
+ crl = ca.updateCRL(crl, QList<QCA::CRLEntry>() << entry, nextUpdate);
+ QVERIFY(!crl.isNull());
+ QCOMPARE(crl.nextUpdate(), QDateTime::fromTime_t(nextUpdate.toTime_t()) /*drop msecs*/);
+ QCOMPARE(crl.issuerInfo().value(QCA::CommonName), QLatin1String("CA Test"));
+ QVERIFY(!crl.revoked().isEmpty());
+ QCOMPARE(crl.revoked().size(), 1);
+ QVERIFY(!crl.revoked().at(0).isNull());
+ QCOMPARE(crl.revoked().at(0).reason(), QCA::CRLEntry::KeyCompromise);
+ QCOMPARE(crl.revoked().at(0).serialNumber(), cert.serialNumber());
+ }
+ }
+}
+
QTEST_MAIN(CertUnitTest)
#include "certunittest.moc"