📄 ksslcertificate.cc
字号:
/* This file is part of the KDE project * * Copyright (C) 2000-2003 George Staikos <staikos@kde.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <unistd.h>#include <qstring.h>#include <qstringlist.h>#include <qfile.h>#include "kssldefs.h"#include "ksslcertificate.h"#include "ksslcertchain.h"#include "ksslutils.h"#include <kstandarddirs.h>#include <kmdcodec.h>#include <klocale.h>#include <qdatetime.h>#include <ktempfile.h>#include <sys/types.h>#ifdef HAVE_SYS_STAT_H#include <sys/stat.h>#endif// this hack provided by Malte Starostik to avoid glibc/openssl bug// on some systems#ifdef KSSL_HAVE_SSL#define crypt _openssl_crypt#include <openssl/ssl.h>#include <openssl/x509.h>#include <openssl/x509v3.h>#include <openssl/x509_vfy.h>#include <openssl/pem.h>#undef crypt#endif#include <kopenssl.h>#include <qcstring.h>#include <kdebug.h>#include "ksslx509v3.h"static char hv[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};class KSSLCertificatePrivate {public: KSSLCertificatePrivate() { kossl = KOSSL::self(); _lastPurpose = KSSLCertificate::None; } ~KSSLCertificatePrivate() { } KSSLCertificate::KSSLValidation m_stateCache; bool m_stateCached; #ifdef KSSL_HAVE_SSL X509 *m_cert; #endif KOSSL *kossl; KSSLCertChain _chain; KSSLX509V3 _extensions; KSSLCertificate::KSSLPurpose _lastPurpose;};KSSLCertificate::KSSLCertificate() { d = new KSSLCertificatePrivate; d->m_stateCached = false; KGlobal::dirs()->addResourceType("kssl", KStandardDirs::kde_default("data") + "kssl"); #ifdef KSSL_HAVE_SSL d->m_cert = NULL; #endif}KSSLCertificate::KSSLCertificate(const KSSLCertificate& x) { d = new KSSLCertificatePrivate; d->m_stateCached = false; KGlobal::dirs()->addResourceType("kssl", KStandardDirs::kde_default("data") + "kssl"); #ifdef KSSL_HAVE_SSL d->m_cert = NULL; setCert(KOSSL::self()->X509_dup(const_cast<KSSLCertificate&>(x).getCert())); KSSLCertChain *c = x.d->_chain.replicate(); setChain(c->rawChain()); delete c; #endif}KSSLCertificate::~KSSLCertificate() {#ifdef KSSL_HAVE_SSL if (d->m_cert) d->kossl->X509_free(d->m_cert);#endif delete d;}KSSLCertChain& KSSLCertificate::chain() { return d->_chain;}KSSLCertificate *KSSLCertificate::fromX509(X509 *x5) {KSSLCertificate *n = NULL;#ifdef KSSL_HAVE_SSL if (x5) { n = new KSSLCertificate; n->setCert(KOSSL::self()->X509_dup(x5)); }#endifreturn n;}KSSLCertificate *KSSLCertificate::fromString(QCString cert) {KSSLCertificate *n = NULL;#ifdef KSSL_HAVE_SSL if (cert.length() == 0) return NULL; QByteArray qba, qbb = cert.copy(); KCodecs::base64Decode(qbb, qba); unsigned char *qbap = reinterpret_cast<unsigned char *>(qba.data()); X509 *x5c = KOSSL::self()->d2i_X509(NULL, &qbap, qba.size()); if (!x5c) { return NULL; } n = new KSSLCertificate; n->setCert(x5c);#endifreturn n;}QString KSSLCertificate::getSubject() const {QString rc = "";#ifdef KSSL_HAVE_SSL char *t = d->kossl->X509_NAME_oneline(d->kossl->X509_get_subject_name(d->m_cert), 0, 0); if (!t) return rc; rc = t; d->kossl->OPENSSL_free(t);#endifreturn rc;}QString KSSLCertificate::getSerialNumber() const {QString rc = "";#ifdef KSSL_HAVE_SSL ASN1_INTEGER *aint = d->kossl->X509_get_serialNumber(d->m_cert); if (aint) { rc = ASN1_INTEGER_QString(aint); // d->kossl->ASN1_INTEGER_free(aint); this makes the sig test fail }#endifreturn rc;}QString KSSLCertificate::getSignatureText() const {QString rc = "";#ifdef KSSL_HAVE_SSLchar *s;int n, i; i = d->kossl->OBJ_obj2nid(d->m_cert->sig_alg->algorithm); rc = i18n("Signature Algorithm: "); rc += (i == NID_undef)?i18n("Unknown"):QString(d->kossl->OBJ_nid2ln(i)); rc += "\n"; rc += i18n("Signature Contents:"); n = d->m_cert->signature->length; s = (char *)d->m_cert->signature->data; for (i = 0; i < n; i++) { if (i%20 != 0) rc += ":"; else rc += "\n"; rc.append(hv[(s[i]&0xf0)>>4]); rc.append(hv[s[i]&0x0f]); }#endifreturn rc;}void KSSLCertificate::getEmails(QStringList &to) const { to.clear();#ifdef KSSL_HAVE_SSL if (!d->m_cert) return; STACK *s = d->kossl->X509_get1_email(d->m_cert); if (s) { for(int n=0; n < s->num; n++) { to.append(d->kossl->sk_value(s,n)); } d->kossl->X509_email_free(s); }#endif } QString KSSLCertificate::getKDEKey() const { return getSubject() + " (" + getMD5DigestText() + ")";}QString KSSLCertificate::getMD5DigestFromKDEKey(const QString &k) { QString rc; int pos = k.findRev('('); if (pos != -1) { unsigned int len = k.length(); if (k.at(len-1) == ')') { rc = k.mid(pos+1, len-pos-2); } } return rc;}QString KSSLCertificate::getMD5DigestText() const {QString rc = "";#ifdef KSSL_HAVE_SSL unsigned int n; unsigned char md[EVP_MAX_MD_SIZE]; if (!d->kossl->X509_digest(d->m_cert, d->kossl->EVP_md5(), md, &n)) { return rc; } for (unsigned int j = 0; j < n; j++) { if (j > 0) rc += ":"; rc.append(hv[(md[j]&0xf0)>>4]); rc.append(hv[md[j]&0x0f]); }#endifreturn rc;}QString KSSLCertificate::getMD5Digest() const {QString rc = "";#ifdef KSSL_HAVE_SSL unsigned int n; unsigned char md[EVP_MAX_MD_SIZE]; if (!d->kossl->X509_digest(d->m_cert, d->kossl->EVP_md5(), md, &n)) { return rc; } for (unsigned int j = 0; j < n; j++) { rc.append(hv[(md[j]&0xf0)>>4]); rc.append(hv[md[j]&0x0f]); }#endifreturn rc;}QString KSSLCertificate::getKeyType() const {QString rc = "";#ifdef KSSL_HAVE_SSL EVP_PKEY *pkey = d->kossl->X509_get_pubkey(d->m_cert); if (pkey) { #ifndef NO_RSA if (pkey->type == EVP_PKEY_RSA) rc = "RSA"; else #endif #ifndef NO_DSA if (pkey->type == EVP_PKEY_DSA) rc = "DSA"; else #endif rc = "Unknown"; d->kossl->EVP_PKEY_free(pkey); }#endifreturn rc;}QString KSSLCertificate::getPublicKeyText() const {QString rc = "";char *x = NULL;#ifdef KSSL_HAVE_SSL EVP_PKEY *pkey = d->kossl->X509_get_pubkey(d->m_cert); if (pkey) { rc = i18n("Unknown", "Unknown key algorithm"); #ifndef NO_RSA if (pkey->type == EVP_PKEY_RSA) { rc = i18n("Key type: RSA (%1 bit)") + "\n"; x = d->kossl->BN_bn2hex(pkey->pkey.rsa->n); rc += i18n("Modulus: "); rc = rc.arg(strlen(x)*4); for (unsigned int i = 0; i < strlen(x); i++) { if (i%40 != 0 && i%2 == 0) rc += ":"; else if (i%40 == 0) rc += "\n"; rc += x[i]; } rc += "\n"; d->kossl->OPENSSL_free(x); x = d->kossl->BN_bn2hex(pkey->pkey.rsa->e); rc += i18n("Exponent: 0x") + x + "\n"; d->kossl->OPENSSL_free(x); } #endif #ifndef NO_DSA if (pkey->type == EVP_PKEY_DSA) { rc = i18n("Key type: DSA (%1 bit)") + "\n"; x = d->kossl->BN_bn2hex(pkey->pkey.dsa->p); rc += i18n("Prime: "); // hack - this may not be always accurate rc = rc.arg(strlen(x)*4) ; for (unsigned int i = 0; i < strlen(x); i++) { if (i%40 != 0 && i%2 == 0) rc += ":"; else if (i%40 == 0) rc += "\n"; rc += x[i]; } rc += "\n"; d->kossl->OPENSSL_free(x); x = d->kossl->BN_bn2hex(pkey->pkey.dsa->q); rc += i18n("160 bit prime factor: "); for (unsigned int i = 0; i < strlen(x); i++) { if (i%40 != 0 && i%2 == 0) rc += ":"; else if (i%40 == 0) rc += "\n"; rc += x[i]; } rc += "\n"; d->kossl->OPENSSL_free(x); x = d->kossl->BN_bn2hex(pkey->pkey.dsa->g); rc += QString("g: "); for (unsigned int i = 0; i < strlen(x); i++) { if (i%40 != 0 && i%2 == 0) rc += ":"; else if (i%40 == 0) rc += "\n"; rc += x[i]; } rc += "\n"; d->kossl->OPENSSL_free(x); x = d->kossl->BN_bn2hex(pkey->pkey.dsa->pub_key); rc += i18n("Public key: "); for (unsigned int i = 0; i < strlen(x); i++) { if (i%40 != 0 && i%2 == 0) rc += ":"; else if (i%40 == 0) rc += "\n"; rc += x[i]; } rc += "\n"; d->kossl->OPENSSL_free(x); } #endif d->kossl->EVP_PKEY_free(pkey); }#endifreturn rc;}QString KSSLCertificate::getIssuer() const {QString rc = "";#ifdef KSSL_HAVE_SSL char *t = d->kossl->X509_NAME_oneline(d->kossl->X509_get_issuer_name(d->m_cert), 0, 0); if (!t) return rc; rc = t; d->kossl->OPENSSL_free(t);#endifreturn rc;}void KSSLCertificate::setChain(void *c) {#ifdef KSSL_HAVE_SSL d->_chain.setChain(c);#endif d->m_stateCached = false; d->m_stateCache = KSSLCertificate::Unknown;}void KSSLCertificate::setCert(X509 *c) {#ifdef KSSL_HAVE_SSLd->m_cert = c;if (c) { d->_extensions.flags = 0; d->kossl->X509_check_purpose(c, -1, 0); // setup the fields (!!)#if 0 kdDebug(7029) << "---------------- Certificate ------------------" << endl; kdDebug(7029) << getSubject() << endl;#endif for (int j = 0; j < d->kossl->X509_PURPOSE_get_count(); j++) { X509_PURPOSE *ptmp = d->kossl->X509_PURPOSE_get0(j); int id = d->kossl->X509_PURPOSE_get_id(ptmp); for (int ca = 0; ca < 2; ca++) { int idret = d->kossl->X509_check_purpose(c, id, ca); if (idret == 1 || idret == 2) { // have it// kdDebug() << "PURPOSE: " << id << (ca?" CA":"") << endl; if (!ca) d->_extensions.flags |= (1L <<(id-1)); else d->_extensions.flags |= (1L <<(16+id-1)); } else { if (!ca) d->_extensions.flags &= ~(1L <<(id-1)); else d->_extensions.flags &= ~(1L <<(16+id-1)); } } }#if 0 kdDebug(7029) << "flags: " << QString::number(c->ex_flags, 2) << "\nkeyusage: " << QString::number(c->ex_kusage, 2) << "\nxkeyusage: " << QString::number(c->ex_xkusage, 2) << "\nnscert: " << QString::number(c->ex_nscert, 2) << endl; if (c->ex_flags & EXFLAG_KUSAGE) kdDebug(7029) << " --- Key Usage extensions found" << endl; else kdDebug(7029) << " --- Key Usage extensions NOT found" << endl; if (c->ex_flags & EXFLAG_XKUSAGE) kdDebug(7029) << " --- Extended key usage extensions found" << endl; else kdDebug(7029) << " --- Extended key usage extensions NOT found" << endl; if (c->ex_flags & EXFLAG_NSCERT) kdDebug(7029) << " --- NS extensions found" << endl; else kdDebug(7029) << " --- NS extensions NOT found" << endl; if (d->_extensions.certTypeSSLCA()) kdDebug(7029) << "NOTE: this is an SSL CA file." << endl; else kdDebug(7029) << "NOTE: this is NOT an SSL CA file." << endl; if (d->_extensions.certTypeEmailCA()) kdDebug(7029) << "NOTE: this is an EMAIL CA file." << endl; else kdDebug(7029) << "NOTE: this is NOT an EMAIL CA file." << endl; if (d->_extensions.certTypeCodeCA()) kdDebug(7029) << "NOTE: this is a CODE CA file." << endl; else kdDebug(7029) << "NOTE: this is NOT a CODE CA file." << endl; if (d->_extensions.certTypeSSLClient()) kdDebug(7029) << "NOTE: this is an SSL client." << endl; else kdDebug(7029) << "NOTE: this is NOT an SSL client." << endl; if (d->_extensions.certTypeSSLServer()) kdDebug(7029) << "NOTE: this is an SSL server." << endl; else kdDebug(7029) << "NOTE: this is NOT an SSL server." << endl; if (d->_extensions.certTypeNSSSLServer()) kdDebug(7029) << "NOTE: this is a NETSCAPE SSL server." << endl; else kdDebug(7029) << "NOTE: this is NOT a NETSCAPE SSL server." << endl; if (d->_extensions.certTypeSMIME()) kdDebug(7029) << "NOTE: this is an SMIME certificate." << endl; else kdDebug(7029) << "NOTE: this is NOT an SMIME certificate." << endl; if (d->_extensions.certTypeSMIMEEncrypt()) kdDebug(7029) << "NOTE: this is an SMIME encrypt cert." << endl; else kdDebug(7029) << "NOTE: this is NOT an SMIME encrypt cert." << endl; if (d->_extensions.certTypeSMIMESign()) kdDebug(7029) << "NOTE: this is an SMIME sign cert." << endl; else kdDebug(7029) << "NOTE: this is NOT an SMIME sign cert." << endl; if (d->_extensions.certTypeCRLSign()) kdDebug(7029) << "NOTE: this is a CRL signer." << endl; else kdDebug(7029) << "NOTE: this is NOT a CRL signer." << endl; kdDebug(7029) << "-----------------------------------------------" << endl;#endif}#endifd->m_stateCached = false;d->m_stateCache = KSSLCertificate::Unknown;}X509 *KSSLCertificate::getCert() {#ifdef KSSL_HAVE_SSL return d->m_cert;#endifreturn 0;}// pull in the callback. It's common across multiple files but we want// it to be hidden.#include "ksslcallback.c"bool KSSLCertificate::isValid(KSSLCertificate::KSSLPurpose p) { return (validate(p) == KSSLCertificate::Ok);}bool KSSLCertificate::isValid() { return isValid(KSSLCertificate::SSLServer);}int KSSLCertificate::purposeToOpenSSL(KSSLCertificate::KSSLPurpose p) const {int rc = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -