Add the ability to verify a chain of certificates

Currently it is only possible to verify a certificate chain when
connecting to a server. This change makes it possible to verify a
chain at any time.

Change-Id: Ib70ad7b81418f880e995f391b82ce59561ededb8
Merge-request: 11
Reviewed-by: Peter Hartmann <peter.hartmann@nokia.com>
Reviewed-on: http://codereview.qt.nokia.com/1509
This commit is contained in:
Richard Moore 2011-06-18 15:53:53 +01:00 committed by Qt by Nokia
parent ad35a41739
commit 451f3b3785
14 changed files with 547 additions and 26 deletions

View File

@ -121,6 +121,7 @@
#include <QtCore/qfile.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qmap.h>
#include <QtCore/qmutex.h>
#include <QtCore/qstring.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qvarlengtharray.h>
@ -666,6 +667,17 @@ QList<QSslCertificate> QSslCertificate::fromData(const QByteArray &data, QSsl::E
: QSslCertificatePrivate::certificatesFromDer(data);
}
/*!
Verifies a certificate chain. If a hostName is specified then the certificate is
also checked to see if it is valid for the specified hostName.
Note that the first certificate in the list should be the leaf certificate of
the chain to be verified.
*/
QList<QSslError> QSslCertificate::verify(QList<QSslCertificate> certificateChain, const QString &hostName)
{
return QSslSocketBackendPrivate::verify(certificateChain, hostName);
}
void QSslCertificatePrivate::init(const QByteArray &data, QSsl::EncodingFormat format)
{
if (!data.isEmpty()) {

View File

@ -62,6 +62,7 @@ QT_MODULE(Network)
class QDateTime;
class QIODevice;
class QSslError;
class QSslKey;
class QStringList;
template <typename T, typename U> class QMultiMap;
@ -122,6 +123,8 @@ public:
static QList<QSslCertificate> fromData(
const QByteArray &data, QSsl::EncodingFormat format = QSsl::Pem);
static QList<QSslError> verify(QList<QSslCertificate> certificateChain, const QString &hostName = QString());
Qt::HANDLE handle() const;
private:

View File

@ -1283,33 +1283,14 @@ bool QSslSocketBackendPrivate::startHandshake()
// if we're the server, don't check CN
if (mode == QSslSocket::SslClientMode) {
QString peerName = (verificationPeerName.isEmpty () ? q->peerName() : verificationPeerName);
QStringList commonNameList = configuration.peerCertificate.subjectInfo(QSslCertificate::CommonName);
bool matched = false;
foreach (const QString &commonName, commonNameList) {
if (isMatchingHostname(commonName.toLower(), peerName.toLower())) {
matched = true;
break;
}
}
if (!matched) {
foreach (const QString &altName, configuration.peerCertificate
.alternateSubjectNames().values(QSsl::DnsEntry)) {
if (isMatchingHostname(altName.toLower(), peerName.toLower())) {
matched = true;
break;
}
}
}
if (!matched) {
// No matches in common names or alternate names.
QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate);
errors << error;
emit q->peerVerifyError(error);
if (q->state() != QAbstractSocket::ConnectedState)
return false;
if (!isMatchingHostname(configuration.peerCertificate, peerName)) {
// No matches in common names or alternate names.
QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate);
errors << error;
emit q->peerVerifyError(error);
if (q->state() != QAbstractSocket::ConnectedState)
return false;
}
}
} else {
@ -1444,6 +1425,25 @@ QString QSslSocketBackendPrivate::getErrorsFromOpenSsl()
return errorString;
}
bool QSslSocketBackendPrivate::isMatchingHostname(const QSslCertificate &cert, const QString &peerName)
{
QStringList commonNameList = cert.subjectInfo(QSslCertificate::CommonName);
foreach (const QString &commonName, commonNameList) {
if (isMatchingHostname(commonName.toLower(), peerName.toLower())) {
return true;
}
}
foreach (const QString &altName, cert.alternateSubjectNames().values(QSsl::DnsEntry)) {
if (isMatchingHostname(altName.toLower(), peerName.toLower())) {
return true;
}
}
return false;
}
bool QSslSocketBackendPrivate::isMatchingHostname(const QString &cn, const QString &hostname)
{
int wildcard = cn.indexOf(QLatin1Char('*'));
@ -1484,4 +1484,133 @@ bool QSslSocketBackendPrivate::isMatchingHostname(const QString &cn, const QStri
return true;
}
QList<QSslError> QSslSocketBackendPrivate::verify(QList<QSslCertificate> certificateChain, const QString &hostName)
{
QList<QSslError> errors;
if (certificateChain.count() <= 0) {
errors << QSslError(QSslError::UnspecifiedError);
return errors;
}
// Setup the store with the default CA certificates
X509_STORE *certStore = q_X509_STORE_new();
if (!certStore) {
qWarning() << "Unable to create certificate store";
errors << QSslError(QSslError::UnspecifiedError);
return errors;
}
QList<QSslCertificate> expiredCerts;
foreach (const QSslCertificate &caCertificate, QSslSocket::defaultCaCertificates()) {
// add expired certs later, so that the
// valid ones are used before the expired ones
if (!caCertificate.isValid()) {
expiredCerts.append(caCertificate);
} else {
q_X509_STORE_add_cert(certStore, (X509 *)caCertificate.handle());
}
}
bool addExpiredCerts = true;
#if defined(Q_OS_MAC) && (MAC_OS_X_VERSION_MAX_ALLOWED == MAC_OS_X_VERSION_10_5)
//On Leopard SSL does not work if we add the expired certificates.
if (QSysInfo::MacintoshVersion == QSysInfo::MV_10_5)
addExpiredCerts = false;
#endif
// now add the expired certs
if (addExpiredCerts) {
foreach (const QSslCertificate &caCertificate, expiredCerts) {
q_X509_STORE_add_cert(certStore, (X509 *)caCertificate.handle());
}
}
_q_sslErrorList()->mutex.lock();
// Register a custom callback to get all verification errors.
X509_STORE_set_verify_cb_func(certStore, q_X509Callback);
// Build the chain of intermediate certificates
STACK_OF(X509) *intermediates = 0;
if (certificateChain.length() > 1) {
intermediates = (STACK_OF(X509) *) q_sk_new_null();
if (!intermediates) {
q_X509_STORE_free(certStore);
errors << QSslError(QSslError::UnspecifiedError);
return errors;
}
bool first = true;
foreach (const QSslCertificate &cert, certificateChain) {
if (first) {
first = false;
continue;
}
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
q_sk_push( (_STACK *)intermediates, (X509 *)cert.handle());
#else
q_sk_push( (STACK *)intermediates, (X509 *)cert.handle());
#endif
}
}
X509_STORE_CTX *storeContext = q_X509_STORE_CTX_new();
if (!storeContext) {
q_X509_STORE_free(certStore);
errors << QSslError(QSslError::UnspecifiedError);
return errors;
}
if (!q_X509_STORE_CTX_init(storeContext, certStore, (X509 *)certificateChain[0].handle(), intermediates)) {
q_X509_STORE_CTX_free(storeContext);
q_X509_STORE_free(certStore);
errors << QSslError(QSslError::UnspecifiedError);
return errors;
}
// Now we can actually perform the verification of the chain we have built.
// We ignore the result of this function since we process errors via the
// callback.
(void) q_X509_verify_cert(storeContext);
q_X509_STORE_CTX_free(storeContext);
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
q_sk_free( (_STACK *) intermediates);
#else
q_sk_free( (STACK *) intermediates);
#endif
// Now process the errors
const QList<QPair<int, int> > errorList = _q_sslErrorList()->errors;
_q_sslErrorList()->errors.clear();
_q_sslErrorList()->mutex.unlock();
// Translate the errors
if (QSslCertificatePrivate::isBlacklisted(certificateChain[0])) {
QSslError error(QSslError::CertificateBlacklisted, certificateChain[0]);
errors << error;
}
// Check the certificate name against the hostname if one was specified
if ((!hostName.isEmpty()) && (!isMatchingHostname(certificateChain[0], hostName))) {
// No matches in common names or alternate names.
QSslError error(QSslError::HostNameMismatch, certificateChain[0]);
errors << error;
}
// Translate errors from the error list into QSslErrors.
for (int i = 0; i < errorList.size(); ++i) {
const QPair<int, int> &errorAndDepth = errorList.at(i);
int err = errorAndDepth.first;
int depth = errorAndDepth.second;
errors << _q_OpenSSL_to_QSslError(err, certificateChain.value(depth));
}
q_X509_STORE_free(certStore);
return errors;
}
QT_END_NAMESPACE

View File

@ -120,7 +120,9 @@ public:
static QSslCipher QSslCipher_from_SSL_CIPHER(SSL_CIPHER *cipher);
static QList<QSslCertificate> STACKOFX509_to_QSslCertificates(STACK_OF(X509) *x509);
static bool isMatchingHostname(const QSslCertificate &cert, const QString &peerName);
Q_AUTOTEST_EXPORT static bool isMatchingHostname(const QString &cn, const QString &hostname);
static QList<QSslError> verify(QList<QSslCertificate> certificateChain, const QString &hostName);
static QString getErrorsFromOpenSsl();
};

View File

@ -157,9 +157,13 @@ DEFINEFUNC(void, RSA_free, RSA *a, a, return, DUMMYARG)
DEFINEFUNC(int, sk_num, STACK *a, a, return -1, return)
DEFINEFUNC2(void, sk_pop_free, STACK *a, a, void (*b)(void*), b, return, DUMMYARG)
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
DEFINEFUNC(_STACK *, sk_new_null, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC2(void, sk_push, _STACK *a, a, void *b, b, return, DUMMYARG)
DEFINEFUNC(void, sk_free, _STACK *a, a, return, DUMMYARG)
DEFINEFUNC2(void *, sk_value, STACK *a, a, int b, b, return 0, return)
#else
DEFINEFUNC(STACK *, sk_new_null, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC2(void, sk_push, STACK *a, a, void *b, b, return, DUMMYARG)
DEFINEFUNC(void, sk_free, STACK *a, a, return, DUMMYARG)
DEFINEFUNC2(char *, sk_value, STACK *a, a, int b, b, return 0, return)
#endif
@ -710,6 +714,8 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(RAND_seed)
RESOLVEFUNC(RAND_status)
RESOLVEFUNC(RSA_free)
RESOLVEFUNC(sk_new_null)
RESOLVEFUNC(sk_push)
RESOLVEFUNC(sk_free)
RESOLVEFUNC(sk_num)
RESOLVEFUNC(sk_pop_free)

View File

@ -263,9 +263,13 @@ void q_RSA_free(RSA *a);
int q_sk_num(STACK *a);
void q_sk_pop_free(STACK *a, void (*b)(void *));
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
_STACK *q_sk_new_null();
void q_sk_push(_STACK *st, void *data);
void q_sk_free(_STACK *a);
void * q_sk_value(STACK *a, int b);
#else
STACK *q_sk_new_null();
void q_sk_push(STACK *st, void *data);
void q_sk_free(STACK *a);
char * q_sk_value(STACK *a, int b);
#endif

View File

@ -116,6 +116,7 @@ private slots:
void toText();
void multipleCommonNames();
void subjectAndIssuerAttributes();
void verify();
// ### add tests for certificate bundles (multiple certificates concatenated into a single
// structure); both PEM and DER formatted
@ -901,6 +902,71 @@ void tst_QSslCertificate::subjectAndIssuerAttributes()
QVERIFY(attributes.contains(QByteArray("1.3.6.1.4.1.311.60.2.1.3")));
}
void tst_QSslCertificate::verify()
{
QList<QSslError> errors;
QList<QSslCertificate> toVerify;
// Empty chain is unspecified error
errors = QSslCertificate::verify(toVerify);
QVERIFY(errors.count() == 1);
QVERIFY(errors[0] == QSslError(QSslError::UnspecifiedError));
errors.clear();
// Verify a valid cert signed by a CA
QList<QSslCertificate> caCerts = QSslCertificate::fromPath(SRCDIR "verify-certs/cacert.pem");
QSslSocket::addDefaultCaCertificate(caCerts.first());
toVerify = QSslCertificate::fromPath(SRCDIR "verify-certs/test-ocsp-good-cert.pem");
errors = QSslCertificate::verify(toVerify);
QVERIFY(errors.count() == 0);
errors.clear();
// Test a blacklisted certificate
toVerify = QSslCertificate::fromPath(SRCDIR "verify-certs/test-addons-mozilla-org-cert.pem");
errors = QSslCertificate::verify(toVerify);
bool foundBlack = false;
foreach (const QSslError &error, errors) {
if (error.error() == QSslError::CertificateBlacklisted) {
foundBlack = true;
break;
}
}
QVERIFY(foundBlack);
errors.clear();
// This one is expired and untrusted
toVerify = QSslCertificate::fromPath(SRCDIR "more-certificates/cert-large-serial-number.pem");
errors = QSslCertificate::verify(toVerify);
QVERIFY(errors.contains(QSslError(QSslError::SelfSignedCertificate, toVerify[0])));
QVERIFY(errors.contains(QSslError(QSslError::CertificateExpired, toVerify[0])));
errors.clear();
toVerify.clear();
// This one is signed by a valid cert, but the signer is not a valid CA
toVerify << QSslCertificate::fromPath(SRCDIR "verify-certs/test-intermediate-not-ca-cert.pem").first();
toVerify << QSslCertificate::fromPath(SRCDIR "verify-certs/test-ocsp-good-cert.pem").first();
errors = QSslCertificate::verify(toVerify);
QVERIFY(errors.contains(QSslError(QSslError::InvalidCaCertificate, toVerify[1])));
toVerify.clear();
// This one is signed by a valid cert, and the signer is a valid CA
toVerify << QSslCertificate::fromPath(SRCDIR "verify-certs/test-intermediate-is-ca-cert.pem").first();
toVerify << QSslCertificate::fromPath(SRCDIR "verify-certs/test-intermediate-ca-cert.pem").first();
errors = QSslCertificate::verify(toVerify);
QVERIFY(errors.length() == 0);
// Recheck the above with hostname validation
errors = QSslCertificate::verify(toVerify, QLatin1String("example.com"));
QVERIFY(errors.length() == 0);
// Recheck the above with a bad hostname
errors = QSslCertificate::verify(toVerify, QLatin1String("fail.example.com"));
QVERIFY(errors.contains(QSslError(QSslError::HostNameMismatch, toVerify[0])));
toVerify.clear();
}
#endif // QT_NO_OPENSSL
QTEST_MAIN(tst_QSslCertificate)

View File

@ -0,0 +1,2 @@
openssl verify -CAfile cacert.pem -untrusted test-intermediate-ca-cert.pem test-intermediate-is-ca-cert.pem
openssl verify -CAfile cacert.pem -untrusted test-ocsp-good-cert.pem test-intermediate-not-ca-cert.pem

View File

@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIID6zCCAtOgAwIBAgIJALIOhqebAhS9MA0GCSqGSIb3DQEBBQUAMIGrMSYwJAYD
VQQDEx1XZXN0cG9pbnQgQ2VydGlmaWNhdGUgVGVzdCBDQTETMBEGA1UECBMKTGFu
Y2FzaGlyZTELMAkGA1UEBhMCVUsxHTAbBgkqhkiG9w0BCQEWDmNhQGV4YW1wbGUu
Y29tMUAwPgYDVQQKEzdXZXN0cG9pbnQgQ2VydGlmaWNhdGUgVGVzdCBSb290IENl
cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTExMDYyNjE5MzYzOVoXDTExMDcyNjE5
MzYzOVowgasxJjAkBgNVBAMTHVdlc3Rwb2ludCBDZXJ0aWZpY2F0ZSBUZXN0IENB
MRMwEQYDVQQIEwpMYW5jYXNoaXJlMQswCQYDVQQGEwJVSzEdMBsGCSqGSIb3DQEJ
ARYOY2FAZXhhbXBsZS5jb20xQDA+BgNVBAoTN1dlc3Rwb2ludCBDZXJ0aWZpY2F0
ZSBUZXN0IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQCoP3znXuxcIAWkyu51aPWwXYX0kSPnBO1gcJj6
xQa4ycOHv9Cs9XTVTGvpj4aoc6lP+6/jUe14cVCR7018zHRe7u5g4ozO1aZqISqS
Y4hdWkTSFPmFoiyXkACl0ZGwcfv6QdFhNnK4COBrff4D6lndfQUZu8CnRYxlKGuR
1vGiUcJ88t0dDmMEFEdYNtlDnYlxXHbTS4VdRb2u3EGFzV24ENJwgqYuFrBAG/+N
TRXahWMsdfP0whCYJOsaNBwXaoeoxGlYz35gMU8A8AFmYOJLohsWqHcHmMV3X6hn
aKGnL3nOa8zlNKNr948Dwenucaggf5KquDCHVf2Ms+ROxlfTAgMBAAGjEDAOMAwG
A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAGmY4+AeMyx+FkpPxeNY3DAH
Jys0WfndLZFABARYfKdJE1dqQi3uXaRkKMkV7npb46cw92jmwFT+v9rHd88UmgMs
KGJNWjARD6Ai1dzenMNYBJz9GFkDJ0Pr4Gqj2tR9JuzEOdxss+nZ4r6vhC+/yeAB
4jGT4QMuYU+14Rfsv5Aw0HjbcH955zTy1pJ6ck9OWWyzET8ALxz+RTFOok/4r4++
yhE5Hh8+2aE52AcZqKa4hKXdVBCb9oewl93h3rmYcA/Yz36w+GRkSnOPZUgDDL5D
HKnICDidtf9ZZBZ4iJxaBg4iCraeuei20V+0g+9/1aoIWJ5TrelVYVCx8O0x+E0=
-----END CERTIFICATE-----

View File

@ -0,0 +1,34 @@
-----BEGIN CERTIFICATE-----
MIIF+DCCBOCgAwIBAgIRAJI51TSPQNFpWnRUcOHyP0MwDQYJKoZIhvcNAQEFBQAw
gZcxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtl
IENpdHkxHjAcBgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMY
aHR0cDovL3d3dy51c2VydHJ1c3QuY29tMR8wHQYDVQQDExZVVE4tVVNFUkZpcnN0
LUhhcmR3YXJlMB4XDTExMDMxNTAwMDAwMFoXDTE0MDMxNDIzNTk1OVowgeIxCzAJ
BgNVBAYTAlVTMQ4wDAYDVQQREwUzODQ3NzEQMA4GA1UECBMHRmxvcmlkYTEQMA4G
A1UEBxMHRW5nbGlzaDEXMBUGA1UECRMOU2VhIFZpbGxhZ2UgMTAxFDASBgNVBAoT
C0dvb2dsZSBMdGQuMRMwEQYDVQQLEwpUZWNoIERlcHQuMSgwJgYDVQQLEx9Ib3N0
ZWQgYnkgR1RJIEdyb3VwIENvcnBvcmF0aW9uMRQwEgYDVQQLEwtQbGF0aW51bVNT
TDEbMBkGA1UEAxMSYWRkb25zLm1vemlsbGEub3JnMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAq8ZtNvMVc3iDc850hdWu7LLw4CQfE4O4IKy7mv6Iu6uh
HQsfRQCqSbc1Nwxq70dMudG+41cSBI2Sx7bsAby22seBOCCtcoXmDvyBbAetaHY4
xUTXzMZKxZc+ZPRR5vB+suxW9yWCTUmYyxaY3SPxiZHRF5dAmSbW4qIrXt+9ifIb
GlMtzFBBetA9KgxVcBQB6VhJEHoLk4KL4R7tOoAQgs6WijTwzNfTubRQh1VUCbid
QihVAOWMNVS/3SWRRrcN5V2DqOWL+4TkPK522sRDK1t0C/i+XWjxeFu1zn3xXZlA
2sruOIFQvpihbLgkrfOvjA/XESgshBhMfbXZjzC1GwIDAQABo4IB8DCCAewwHwYD
VR0jBBgwFoAUoXJfJhsomEOVXQc31YWWnUvSw0UwHQYDVR0OBBYEFN2A0lQ990xw
yqOw3TR6MuToO1o7MA4GA1UdDwEB/wQEAwIFoDAMBgNVHRMBAf8EAjAAMB0GA1Ud
JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBGBgNVHSAEPzA9MDsGDCsGAQQBsjEB
AgEDBDArMCkGCCsGAQUFBwIBFh1odHRwczovL3NlY3VyZS5jb21vZG8uY29tL0NQ
UzB7BgNVHR8EdDByMDigNqA0hjJodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9VVE4t
VVNFUkZpcnN0LUhhcmR3YXJlLmNybDA2oDSgMoYwaHR0cDovL2NybC5jb21vZG8u
bmV0L1VUTi1VU0VSRmlyc3QtSGFyZHdhcmUuY3JsMHEGCCsGAQUFBwEBBGUwYzA7
BggrBgEFBQcwAoYvaHR0cDovL2NydC5jb21vZG9jYS5jb20vVVROQWRkVHJ1c3RT
ZXJ2ZXJDQS5jcnQwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNv
bTA1BgNVHREELjAsghJhZGRvbnMubW96aWxsYS5vcmeCFnd3dy5hZGRvbnMubW96
aWxsYS5vcmcwDQYJKoZIhvcNAQEFBQADggEBADM7YxX8sewULJPddZTegVrZTpm+
+0qkOVVNoUB63hMqh6k3z+jV+63Re21vjCCHglTmV0m8ICiEzdYB2ZOLF24jZuWE
yIA/xqFwgOTsTR35/JFac2IpmvcgHGHgizmfyrx+jd282bHjn57fFVORIVIL2Roj
D2Y226yTlkqjpSLPKfeimaj2ttlArtl+tvZYLpusNspkj2VS3IacgqtuUEvaX/oF
AIgwDt6NVr+BR409BuKyYpJnj57ImrLlBrhwJLh3fCMKOMN5CNixUZ2slRHHQBee
oxyP8hGnaCfaSQWEGHxYLQFnXOWfoSm7SjlFL78Rqnmi7bTUtWVDt5NGitM=
-----END CERTIFICATE-----

View File

@ -0,0 +1,66 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 28 (0x1c)
Signature Algorithm: sha1WithRSAEncryption
Issuer: CN=Westpoint Certificate Test CA, ST=Lancashire, C=UK/emailAddress=ca@example.com, O=Westpoint Certificate Test Root Certification Authority
Validity
Not Before: Jun 26 19:36:42 2011 GMT
Not After : Jun 23 19:36:42 2021 GMT
Subject: ST=Lancashire, C=UK/emailAddress=test@example.com, O=Test intermediate CA
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (1024 bit)
Modulus:
00:a7:ed:3f:86:ee:ad:f8:b7:60:44:63:fc:1b:2c:
79:3c:90:8b:47:b8:51:b5:3e:96:6d:5d:f1:97:b3:
de:90:b2:9a:aa:9e:54:7e:2b:b1:6d:91:ae:20:29:
b6:69:7b:8a:e5:6c:41:10:b6:d3:73:4c:20:30:38:
57:c9:c8:ef:67:7e:76:39:c4:1c:df:6b:73:4e:2b:
21:2d:79:5a:c5:60:5e:85:11:52:3b:8e:ef:b0:e5:
2f:0c:e8:a3:fc:05:27:91:08:64:ea:2e:5a:f2:82:
0c:08:48:bc:bc:ca:60:02:1c:6a:38:eb:c8:02:a6:
f7:e8:c8:31:20:29:e6:e4:8d
Exponent: 65537 (0x10001)
X509v3 extensions:
Authority Information Access:
OCSP - URI:http://ocsp.example.com:8888/
X509v3 Basic Constraints:
CA:TRUE
Signature Algorithm: sha1WithRSAEncryption
94:1a:91:6a:05:41:0c:40:f9:46:35:e9:46:15:f1:3e:e4:d9:
50:d6:0e:14:d8:1f:85:9e:a6:98:a2:db:db:ee:ff:56:55:6c:
46:fd:0e:b0:03:79:a6:96:0f:c1:85:c3:3e:68:e0:17:10:a6:
9c:10:34:88:96:f7:c8:ef:32:31:24:f4:3c:2d:eb:51:08:d6:
87:83:f7:db:68:43:ed:d9:af:46:a2:48:74:d2:9d:c9:af:0f:
29:42:ad:a2:cf:1e:ab:50:6f:ef:33:18:d3:07:ef:13:13:10:
50:db:a9:56:db:f4:38:c1:db:05:fa:5a:67:92:72:69:fb:7a:
5b:ec:d4:dd:fd:a2:21:06:59:b0:0d:48:5f:53:c1:65:94:aa:
d4:4e:1c:e8:9f:b4:7d:9b:10:85:4a:b6:be:df:d8:33:b5:72:
b0:ac:46:a9:67:55:1e:3e:58:a5:52:ed:b6:4a:cb:e9:d2:e5:
f8:fe:56:b4:2c:5e:9f:3c:d1:7f:b4:eb:05:8d:46:1f:47:32:
2b:4f:2e:ac:8d:c3:3c:eb:f1:0c:2f:3a:e0:fa:46:0b:e4:c5:
f2:03:24:70:fc:ef:1a:fd:7b:a9:9c:d9:b6:4f:0e:74:07:52:
23:eb:cd:66:61:67:a1:91:7f:76:a2:9d:42:54:d4:c6:5e:10:
26:eb:37:e7
-----BEGIN CERTIFICATE-----
MIIDUDCCAjigAwIBAgIBHDANBgkqhkiG9w0BAQUFADCBqzEmMCQGA1UEAxMdV2Vz
dHBvaW50IENlcnRpZmljYXRlIFRlc3QgQ0ExEzARBgNVBAgTCkxhbmNhc2hpcmUx
CzAJBgNVBAYTAlVLMR0wGwYJKoZIhvcNAQkBFg5jYUBleGFtcGxlLmNvbTFAMD4G
A1UEChM3V2VzdHBvaW50IENlcnRpZmljYXRlIFRlc3QgUm9vdCBDZXJ0aWZpY2F0
aW9uIEF1dGhvcml0eTAeFw0xMTA2MjYxOTM2NDJaFw0yMTA2MjMxOTM2NDJaMGIx
EzARBgNVBAgTCkxhbmNhc2hpcmUxCzAJBgNVBAYTAlVLMR8wHQYJKoZIhvcNAQkB
FhB0ZXN0QGV4YW1wbGUuY29tMR0wGwYDVQQKExRUZXN0IGludGVybWVkaWF0ZSBD
QTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAp+0/hu6t+LdgRGP8Gyx5PJCL
R7hRtT6WbV3xl7PekLKaqp5UfiuxbZGuICm2aXuK5WxBELbTc0wgMDhXycjvZ352
OcQc32tzTishLXlaxWBehRFSO47vsOUvDOij/AUnkQhk6i5a8oIMCEi8vMpgAhxq
OOvIAqb36MgxICnm5I0CAwEAAaNLMEkwOQYIKwYBBQUHAQEELTArMCkGCCsGAQUF
BzABhh1odHRwOi8vb2NzcC5leGFtcGxlLmNvbTo4ODg4LzAMBgNVHRMEBTADAQH/
MA0GCSqGSIb3DQEBBQUAA4IBAQCUGpFqBUEMQPlGNelGFfE+5NlQ1g4U2B+FnqaY
otvb7v9WVWxG/Q6wA3mmlg/BhcM+aOAXEKacEDSIlvfI7zIxJPQ8LetRCNaHg/fb
aEPt2a9Gokh00p3Jrw8pQq2izx6rUG/vMxjTB+8TExBQ26lW2/Q4wdsF+lpnknJp
+3pb7NTd/aIhBlmwDUhfU8FllKrUThzon7R9mxCFSra+39gztXKwrEapZ1UePlil
Uu22Ssvp0uX4/la0LF6fPNF/tOsFjUYfRzIrTy6sjcM86/EMLzrg+kYL5MXyAyRw
/O8a/XupnNm2Tw50B1Ij681mYWehkX92op1CVNTGXhAm6zfn
-----END CERTIFICATE-----

View File

@ -0,0 +1,53 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 29 (0x1d)
Signature Algorithm: sha1WithRSAEncryption
Issuer: ST=Lancashire, C=UK/emailAddress=test@example.com, O=Test intermediate CA
Validity
Not Before: Jun 26 19:36:42 2011 GMT
Not After : Jun 23 19:36:42 2021 GMT
Subject: CN=example.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (1024 bit)
Modulus:
00:ba:f2:dc:f9:77:b0:ad:fd:9d:42:4f:22:15:6d:
87:40:ed:30:8a:04:ad:ac:7a:0b:d4:7a:a4:a7:ef:
e0:e7:9b:f2:5e:62:56:24:ed:88:bd:bd:e3:64:d2:
d4:b4:01:39:b8:9e:6f:c7:b0:fc:b9:fd:a8:4d:46:
c8:9e:6a:43:82:ca:56:83:d4:4b:ea:63:d5:56:d1:
99:46:4f:8b:28:d0:2f:db:bf:04:65:64:82:c2:61:
aa:66:50:27:e5:7a:57:e3:72:e3:ae:22:8d:92:7e:
25:90:a2:7c:0c:04:79:c5:ab:64:58:a9:83:79:67:
7f:72:33:cc:5f:5b:cd:74:bb
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Authority Information Access:
OCSP - URI:http://ocsp.example.com:8888/
Signature Algorithm: sha1WithRSAEncryption
19:e8:ce:9d:4d:ef:cc:4f:6c:e5:ab:df:aa:e2:3c:d8:6b:a8:
dd:b8:fa:50:e4:b6:04:fc:66:92:fb:e8:11:73:81:60:1a:88:
b2:18:0b:8c:89:05:47:16:50:09:be:bc:a6:3c:fe:2e:45:01:
00:e3:27:30:72:f6:93:49:7f:d0:3b:a8:0e:cb:e7:01:95:28:
8b:40:95:f7:b1:5b:c9:ff:26:ff:ad:4a:c4:e4:99:f7:65:fc:
e4:5e:d2:56:ea:98:42:dc:93:62:46:1a:33:53:0d:43:9d:ef:
14:03:35:a7:13:fa:27:24:92:2f:9a:f9:0a:62:99:cc:c0:80:
79:10
-----BEGIN CERTIFICATE-----
MIICNjCCAZ+gAwIBAgIBHTANBgkqhkiG9w0BAQUFADBiMRMwEQYDVQQIEwpMYW5j
YXNoaXJlMQswCQYDVQQGEwJVSzEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxl
LmNvbTEdMBsGA1UEChMUVGVzdCBpbnRlcm1lZGlhdGUgQ0EwHhcNMTEwNjI2MTkz
NjQyWhcNMjEwNjIzMTkzNjQyWjAWMRQwEgYDVQQDEwtleGFtcGxlLmNvbTCBnzAN
BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuvLc+Xewrf2dQk8iFW2HQO0wigStrHoL
1Hqkp+/g55vyXmJWJO2Ivb3jZNLUtAE5uJ5vx7D8uf2oTUbInmpDgspWg9RL6mPV
VtGZRk+LKNAv278EZWSCwmGqZlAn5XpX43LjriKNkn4lkKJ8DAR5xatkWKmDeWd/
cjPMX1vNdLsCAwEAAaNIMEYwCQYDVR0TBAIwADA5BggrBgEFBQcBAQQtMCswKQYI
KwYBBQUHMAGGHWh0dHA6Ly9vY3NwLmV4YW1wbGUuY29tOjg4ODgvMA0GCSqGSIb3
DQEBBQUAA4GBABnozp1N78xPbOWr36riPNhrqN24+lDktgT8ZpL76BFzgWAaiLIY
C4yJBUcWUAm+vKY8/i5FAQDjJzBy9pNJf9A7qA7L5wGVKItAlfexW8n/Jv+tSsTk
mfdl/ORe0lbqmELck2JGGjNTDUOd7xQDNacT+ickki+a+QpimczAgHkQ
-----END CERTIFICATE-----

View File

@ -0,0 +1,54 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 27 (0x1b)
Signature Algorithm: sha1WithRSAEncryption
Issuer: CN=example.com, ST=Lancashire, C=UK/emailAddress=test@example.com, O=Some organisation
Validity
Not Before: Jun 26 19:36:42 2011 GMT
Not After : Jun 23 19:36:42 2021 GMT
Subject: CN=example.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (1024 bit)
Modulus:
00:d7:b6:a8:07:83:27:b8:72:da:85:ad:50:bf:c2:
3f:cc:d4:e7:97:55:b5:45:aa:d2:cb:df:b6:34:6f:
c2:8f:86:e2:15:8a:cd:3e:af:f5:c0:f9:2e:61:80:
70:17:d3:db:0f:8a:e6:2c:a8:e3:12:2d:92:e1:8d:
10:e0:e7:30:94:98:ec:b0:21:c3:86:f7:ff:29:58:
2b:ab:b1:23:e4:ca:66:66:6a:18:b5:73:dc:c7:44:
04:30:55:bf:f9:3b:74:f6:de:bd:d9:ef:46:b0:15:
56:3b:43:cc:55:c2:cc:2e:5d:17:f8:04:dc:3d:bf:
1b:cc:0a:41:61:c8:35:02:1b
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Authority Information Access:
OCSP - URI:http://ocsp.example.com:8888/
Signature Algorithm: sha1WithRSAEncryption
18:e2:06:f3:4b:42:46:b6:29:d1:8d:50:ef:5b:8b:e5:33:24:
f3:f1:3e:58:4d:7f:3e:51:e9:c4:a2:cb:64:5f:d1:51:ce:8d:
b6:15:63:23:30:4b:7c:70:30:61:ce:1f:70:bb:99:63:5b:15:
d9:ce:aa:da:65:87:66:ab:ad:64:e8:09:37:ea:79:d0:3a:a2:
e0:cf:0b:1b:a7:35:3d:f8:45:4c:4b:96:15:ec:fe:64:9f:e0:
1d:04:52:35:a1:b4:7e:31:34:84:7e:e6:e0:58:1e:14:02:df:
68:f6:b6:eb:dc:10:eb:da:fe:8e:06:ab:52:b7:ca:15:c3:8d:
5a:8a
-----BEGIN CERTIFICATE-----
MIICSTCCAbKgAwIBAgIBGzANBgkqhkiG9w0BAQUFADB1MRQwEgYDVQQDEwtleGFt
cGxlLmNvbTETMBEGA1UECBMKTGFuY2FzaGlyZTELMAkGA1UEBhMCVUsxHzAdBgkq
hkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20xGjAYBgNVBAoTEVNvbWUgb3JnYW5p
c2F0aW9uMB4XDTExMDYyNjE5MzY0MloXDTIxMDYyMzE5MzY0MlowFjEUMBIGA1UE
AxMLZXhhbXBsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANe2qAeD
J7hy2oWtUL/CP8zU55dVtUWq0svftjRvwo+G4hWKzT6v9cD5LmGAcBfT2w+K5iyo
4xItkuGNEODnMJSY7LAhw4b3/ylYK6uxI+TKZmZqGLVz3MdEBDBVv/k7dPbevdnv
RrAVVjtDzFXCzC5dF/gE3D2/G8wKQWHINQIbAgMBAAGjSDBGMAkGA1UdEwQCMAAw
OQYIKwYBBQUHAQEELTArMCkGCCsGAQUFBzABhh1odHRwOi8vb2NzcC5leGFtcGxl
LmNvbTo4ODg4LzANBgkqhkiG9w0BAQUFAAOBgQAY4gbzS0JGtinRjVDvW4vlMyTz
8T5YTX8+UenEostkX9FRzo22FWMjMEt8cDBhzh9wu5ljWxXZzqraZYdmq61k6Ak3
6nnQOqLgzwsbpzU9+EVMS5YV7P5kn+AdBFI1obR+MTSEfubgWB4UAt9o9rbr3BDr
2v6OBqtSt8oVw41aig==
-----END CERTIFICATE-----

View File

@ -0,0 +1,67 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha1WithRSAEncryption
Issuer: CN=Westpoint Certificate Test CA, ST=Lancashire, C=UK/emailAddress=ca@example.com, O=Westpoint Certificate Test Root Certification Authority
Validity
Not Before: Jun 26 19:36:39 2011 GMT
Not After : Jun 23 19:36:39 2021 GMT
Subject: CN=example.com, ST=Lancashire, C=UK/emailAddress=test@example.com, O=Some organisation
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (1024 bit)
Modulus:
00:c7:d8:d4:a7:c0:a0:e7:82:b4:ec:67:52:bf:50:
bf:b9:a6:f2:10:19:67:53:8c:99:5e:c8:fc:03:07:
71:24:a3:a9:c4:49:f8:15:34:4a:45:ee:92:81:aa:
3c:5a:1a:42:2b:db:d7:30:9e:85:e6:b8:74:bc:ae:
f0:ae:7d:05:4e:c9:0f:00:33:b2:86:ba:b6:49:9a:
07:18:92:f9:35:69:d2:ac:39:b9:85:ac:78:99:81:
06:f5:fa:2e:5b:18:f7:6a:16:d0:e6:f9:71:0f:b0:
05:c4:f0:5f:ed:90:81:3c:96:f5:e3:45:73:72:5f:
ce:dc:ce:0b:56:2e:be:d2:eb
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Authority Information Access:
OCSP - URI:http://ocsp.example.com:8888/
Signature Algorithm: sha1WithRSAEncryption
76:84:40:52:b8:1d:6c:64:58:f1:10:30:03:db:16:91:da:b1:
70:28:54:6f:0f:32:1c:84:65:b3:14:99:c6:59:f9:ec:f9:3f:
46:1f:12:77:4e:f1:26:ad:46:4b:ee:48:78:bd:bf:2a:11:01:
5b:02:cd:d2:6e:2d:8c:08:ea:a7:5a:18:16:71:e8:5d:c8:e7:
7d:f2:4f:23:6c:59:3c:17:93:02:60:c0:d0:62:09:d2:a3:7d:
90:77:6c:f7:0c:b2:e4:9e:73:d2:f8:dd:a3:0c:70:36:2f:5a:
58:2b:2d:3e:0e:71:43:b2:14:00:e2:eb:2d:0e:09:91:47:83:
e8:02:d4:7d:5c:1f:ce:d8:f5:ad:1f:ee:82:4f:23:47:db:f4:
71:48:1b:e1:82:f1:d1:86:db:0f:b6:bb:3a:8f:40:05:48:b7:
f2:a8:c7:c9:46:e1:ea:28:b2:02:00:90:04:00:19:32:6f:8d:
3e:c2:67:ca:b0:80:3a:32:e3:35:92:18:a2:62:30:9d:7a:f5:
13:3b:c7:00:3f:4e:17:a9:01:5d:a1:2c:71:76:d7:37:c8:16:
92:f8:82:69:15:5f:7d:5e:b0:ba:0b:9f:bd:53:ad:e5:a6:b3:
bc:6b:e4:1a:79:29:31:ff:ff:a1:2d:0b:30:46:d3:a5:2d:62:
e6:be:68:df
-----BEGIN CERTIFICATE-----
MIIDYDCCAkigAwIBAgIBATANBgkqhkiG9w0BAQUFADCBqzEmMCQGA1UEAxMdV2Vz
dHBvaW50IENlcnRpZmljYXRlIFRlc3QgQ0ExEzARBgNVBAgTCkxhbmNhc2hpcmUx
CzAJBgNVBAYTAlVLMR0wGwYJKoZIhvcNAQkBFg5jYUBleGFtcGxlLmNvbTFAMD4G
A1UEChM3V2VzdHBvaW50IENlcnRpZmljYXRlIFRlc3QgUm9vdCBDZXJ0aWZpY2F0
aW9uIEF1dGhvcml0eTAeFw0xMTA2MjYxOTM2MzlaFw0yMTA2MjMxOTM2MzlaMHUx
FDASBgNVBAMTC2V4YW1wbGUuY29tMRMwEQYDVQQIEwpMYW5jYXNoaXJlMQswCQYD
VQQGEwJVSzEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbTEaMBgGA1UE
ChMRU29tZSBvcmdhbmlzYXRpb24wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGB
AMfY1KfAoOeCtOxnUr9Qv7mm8hAZZ1OMmV7I/AMHcSSjqcRJ+BU0SkXukoGqPFoa
Qivb1zCehea4dLyu8K59BU7JDwAzsoa6tkmaBxiS+TVp0qw5uYWseJmBBvX6LlsY
92oW0Ob5cQ+wBcTwX+2QgTyW9eNFc3JfztzOC1YuvtLrAgMBAAGjSDBGMAkGA1Ud
EwQCMAAwOQYIKwYBBQUHAQEELTArMCkGCCsGAQUFBzABhh1odHRwOi8vb2NzcC5l
eGFtcGxlLmNvbTo4ODg4LzANBgkqhkiG9w0BAQUFAAOCAQEAdoRAUrgdbGRY8RAw
A9sWkdqxcChUbw8yHIRlsxSZxln57Pk/Rh8Sd07xJq1GS+5IeL2/KhEBWwLN0m4t
jAjqp1oYFnHoXcjnffJPI2xZPBeTAmDA0GIJ0qN9kHds9wyy5J5z0vjdowxwNi9a
WCstPg5xQ7IUAOLrLQ4JkUeD6ALUfVwfztj1rR/ugk8jR9v0cUgb4YLx0YbbD7a7
Oo9ABUi38qjHyUbh6iiyAgCQBAAZMm+NPsJnyrCAOjLjNZIYomIwnXr1EzvHAD9O
F6kBXaEscXbXN8gWkviCaRVffV6wugufvVOt5aazvGvkGnkpMf//oS0LMEbTpS1i
5r5o3w==
-----END CERTIFICATE-----