head 1.3; access; symbols PSI_0_8_7:1.1; locks; strict; comment @// @; 1.3 date 2003.06.17.15.40.12; author swiergot; state dead; branches; next 1.2; 1.2 date 2003.06.06.18.40.21; author swiergot; state Exp; branches; next 1.1; 1.1 date 2003.04.08.11.37.59; author swiergot; state Exp; branches; next ; desc @@ 1.3 log @- Use official source distribution. - Added optflags patch. @ text @/* * qssl.cpp - Qt OpenSSL plugin * Copyright (C) 2001-2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include"qssl_p.h" #include #include #include #include #include //! \brief plugin hook QSSL *createQSSL() { return new _QSSL; } int version() { return 2; } //! \class QSSL qssl.h //! \brief QT OpenSSL plug-in //---------------------------------------------------------------------------- // QSSL //---------------------------------------------------------------------------- //! \brief Creates QSSL object _QSSL::_QSSL() { SSL_library_init(); SSL_load_error_strings(); } //! \brief Destroys QSSL object _QSSL::~_QSSL() { ERR_free_strings(); ERR_remove_state(0); } QSSLCert *_QSSL::createCert() { return new _QSSLCert; } //! \brief gives you access to QSSLFilter QSSLFilter *_QSSL::createFilter() { return new _QSSLFilter; } //---------------------------------------------------------------------------- // QSSLCert //---------------------------------------------------------------------------- static QByteArray base64encode(const QByteArray &s) { int i; int len = s.size(); char tbl[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; int a, b, c; QByteArray p((len+2)/3*4); int at = 0; for( i = 0; i < len; i += 3 ) { a = ((unsigned char)s[i] & 3) << 4; if(i + 1 < len) { a += (unsigned char)s[i + 1] >> 4; b = ((unsigned char)s[i + 1] & 0xF) << 2; if(i + 2 < len) { b += (unsigned char)s[i + 2] >> 6; c = (unsigned char)s[i + 2] & 0x3F; } else c = 64; } else b = c = 64; p[at++] = tbl[(unsigned char)s[i] >> 2]; p[at++] = tbl[a]; p[at++] = tbl[b]; p[at++] = tbl[c]; } return p; } QByteArray base64decode(const QByteArray &s) { // return value QByteArray p; // -1 specifies invalid // 64 specifies eof // everything else specifies data char tbl[] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,64,-1,-1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, }; // this should be a multiple of 4 int len = s.size(); if(len % 4) return p; p.resize(len / 4 * 3); int i; int at = 0; int a, b, c, d; c = d = 0; for( i = 0; i < len; i += 4 ) { a = tbl[s[i]]; b = tbl[s[i + 1]]; c = tbl[s[i + 2]]; d = tbl[s[i + 3]]; if((a == 64 || b == 64) || (a < 0 || b < 0 || c < 0 || d < 0)) { p.resize(0); return p; } p[at++] = ((a & 0x3F) << 2) | ((b >> 4) & 0x03); p[at++] = ((b & 0x0F) << 4) | ((c >> 2) & 0x0F); p[at++] = ((c & 0x03) << 6) | ((d >> 0) & 0x3F); } if(c & 64) p.resize(at - 2); else if(d & 64) p.resize(at - 1); return p; } static QValueList nameToProperties(X509_NAME *name) { QValueList list; for(int n = 0; n < X509_NAME_entry_count(name); ++n) { X509_NAME_ENTRY *ne = X509_NAME_get_entry(name, n); QSSLCertProperty p; ASN1_OBJECT *ao = X509_NAME_ENTRY_get_object(ne); int nid = OBJ_obj2nid(ao); if(nid == NID_undef) continue; p.var = OBJ_nid2sn(nid); ASN1_STRING *as = X509_NAME_ENTRY_get_data(ne); QCString c; c.resize(as->length+1); strncpy(c.data(), (char *)as->data, as->length); p.val = QString::fromLatin1(c); list += p; } return list; } // (taken from kdelibs) -- Justin // // This code is mostly taken from OpenSSL v0.9.5a // by Eric Young QDateTime ASN1_UTCTIME_QDateTime(ASN1_UTCTIME *tm, int *isGmt) { QDateTime qdt; char *v; int gmt=0; int i; int y=0,M=0,d=0,h=0,m=0,s=0; QDate qdate; QTime qtime; i = tm->length; v = (char *)tm->data; if (i < 10) goto auq_err; if (v[i-1] == 'Z') gmt=1; for (i=0; i<10; i++) if ((v[i] > '9') || (v[i] < '0')) goto auq_err; y = (v[0]-'0')*10+(v[1]-'0'); if (y < 50) y+=100; M = (v[2]-'0')*10+(v[3]-'0'); if ((M > 12) || (M < 1)) goto auq_err; d = (v[4]-'0')*10+(v[5]-'0'); h = (v[6]-'0')*10+(v[7]-'0'); m = (v[8]-'0')*10+(v[9]-'0'); if ( (v[10] >= '0') && (v[10] <= '9') && (v[11] >= '0') && (v[11] <= '9')) s = (v[10]-'0')*10+(v[11]-'0'); // localize the date and display it. qdate.setYMD(y+1900, M, d); qtime.setHMS(h,m,s); qdt.setDate(qdate); qdt.setTime(qtime); auq_err: if (isGmt) *isGmt = gmt; return qdt; } // (adapted from kdelibs) -- Justin static bool cnMatchesAddress(const QString &_cn, const QString &peerHost) { QString cn = _cn; QRegExp rx; // Check for invalid characters if(QRegExp("[^a-zA-Z0-9\\.\\*\\-]").search(cn) >= 0) return false; // Domains can legally end with '.'s. We don't need them though. while(cn.endsWith(".")) cn.truncate(cn.length()-1); // Do not let empty CN's get by!! if(cn.isEmpty()) return false; // Check for IPv4 address rx.setPattern("[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}"); if(rx.exactMatch(peerHost)) return peerHost == cn; // Check for IPv6 address here... rx.setPattern("^\\[.*\\]$"); if(rx.exactMatch(peerHost)) return peerHost == cn; if(cn.contains('*')) { // First make sure that there are at least two valid parts // after the wildcard (*). QStringList parts = QStringList::split('.', cn, false); while(parts.count() > 2) parts.remove(parts.begin()); if(parts.count() != 2) { return false; // we don't allow *.root - that's bad } if(parts[0].contains('*') || parts[1].contains('*')) { return false; } // RFC2818 says that *.example.com should match against // foo.example.com but not bar.foo.example.com // (ie. they must have the same number of parts) if(QRegExp(cn, false, true).exactMatch(peerHost) && parts.count() == QStringList::split('.', peerHost, false).count()) return true; return false; } // We must have an exact match in this case (insensitive though) // (note we already did .lower()) if(cn == peerHost) return true; return false; } class _QSSLCert::Private { public: Private() {} X509 *x; // openssl internal representation QByteArray dat; QString serial; QDateTime notBefore, notAfter; QString subjectString, issuerString; QValueList subject, issuer; int validityResult; }; _QSSLCert::_QSSLCert() { d = new Private; d->x = 0; d->validityResult = NoCert; } _QSSLCert::_QSSLCert(const _QSSLCert &from) :QSSLCert() { d = new Private; d->x = 0; d->validityResult = NoCert; *this = from; } _QSSLCert & _QSSLCert::operator=(const _QSSLCert &from) { reset(); *d = *from.d; if(d->x) ++d->x->references; // bump the reference count d->dat.detach(); // dup the QByteArray return *this; } _QSSLCert::~_QSSLCert() { reset(); delete d; } void _QSSLCert::reset() { if(d->x) { X509_free(d->x); d->x = 0; } d->validityResult = NoCert; } X509 *_QSSLCert::toX509() const { return d->x; } void _QSSLCert::fromX509(X509 *x) { reset(); // extract the raw data d->x = x; ++d->x->references; // bump the reference count int len = i2d_X509(x, NULL); QByteArray dat(len); unsigned char *p = (unsigned char *)dat.data(); i2d_X509(x, &p); d->dat = dat; // serial number ASN1_INTEGER *ai = X509_get_serialNumber(x); if(ai) { char *rep = i2s_ASN1_INTEGER(NULL, ai); d->serial = rep; OPENSSL_free(rep); } // validity dates d->notBefore = ASN1_UTCTIME_QDateTime(X509_get_notBefore(x), NULL); d->notAfter = ASN1_UTCTIME_QDateTime(X509_get_notAfter(x), NULL); // extract the subject/issuer strings X509_NAME *sn = X509_get_subject_name(x); X509_NAME *in = X509_get_issuer_name(x); char buf[1024]; X509_NAME_oneline(sn, buf, 1024); d->subjectString = buf; X509_NAME_oneline(in, buf, 1024); d->issuerString = buf; // extract the subject/issuer contents d->subject = nameToProperties(sn); d->issuer = nameToProperties(in); } void _QSSLCert::setValidityResult(int r) { d->validityResult = r; } bool _QSSLCert::isNull() const { return (d->x ? false: true); } bool _QSSLCert::isValid() const { return (validityResult() == Valid ? true: false); } int _QSSLCert::validityResult() const { return d->validityResult; } QString _QSSLCert::serialNumber() const { return d->serial; } QDateTime _QSSLCert::notBefore() const { return d->notBefore; } QDateTime _QSSLCert::notAfter() const { return d->notAfter; } QValueList _QSSLCert::subject() const { return d->subject; } QValueList _QSSLCert::issuer() const { return d->issuer; } QString _QSSLCert::subjectString() const { return d->subjectString; } QString _QSSLCert::issuerString() const { return d->issuerString; } QString _QSSLCert::toString() const { QByteArray enc = base64encode(d->dat); QCString c; c.resize(enc.size()+1); memcpy(c.data(), enc.data(), enc.size()); return QString::fromLatin1(c); } bool _QSSLCert::fromString(const QString &str) { QCString cs = str.latin1(); QByteArray enc(cs.length()); memcpy(enc.data(), cs.data(), enc.size()); QByteArray dat = base64decode(enc); unsigned char *p = (unsigned char *)dat.data(); X509 *x = d2i_X509(NULL, &p, dat.size()); if(!x) return false; fromX509(x); return true; } QByteArray _QSSLCert::toPEM() const { QString str = toString(); unsigned int len = str.length() - 1; for(unsigned int i = 0; i < len/64; i++) str.insert(64*(i+1)+i, '\n'); QString out; out += "-----BEGIN CERTIFICATE-----\n"; out += str + '\n'; out += "-----END CERTIFICATE-----\n"; QCString cs = out.latin1(); QByteArray buf(cs.length()); memcpy(buf.data(), cs.data(), buf.size()); return buf; } bool _QSSLCert::matchesAddress(const QString &realHost) const { QString peerHost = realHost.stripWhiteSpace(); while(peerHost.endsWith(".")) peerHost.truncate(peerHost.length()-1); peerHost = peerHost.lower(); for(QValueList::ConstIterator it = d->subject.begin(); it != d->subject.end(); ++it) { if((*it).var == "CN") { if(cnMatchesAddress((*it).val.stripWhiteSpace().lower(), peerHost)) return true; } } return false; } //---------------------------------------------------------------------------- // QSSLFilter //---------------------------------------------------------------------------- //! \if _hide_doc_ class QSSLFilterPrivate { public: QSSLFilterPrivate() {} int mode; QByteArray sendQueue, recvQueue; SSL *ssl; SSL_METHOD *method; SSL_CTX *context; BIO *rbio, *wbio; _QSSLCert cert; QString host; }; //! \endif //! \class QSSLFilter qssl.h //! \brief QSSLFilter - Main SSL wrapper //! //! This class should be used if you want basic ssl support. //! //! \fn void QSSLFilter::handshaken() //! \brief Signals letting you know the initialization has finished //! //! This is when you put those pad locks at the corner of your application ;D //! \fn void QSSLFilter::readyRead() //! \brief Signals non-encrypted data is ready for read //! \fn void QSSLFilter::outgoingSSLDataReady() //! \brief Singals encrypted data is ready for read //! \fn void QSSLFilter::error(bool isWarning, const QString &) //! \brief Signals any error //! //! the isWarning = 1 if this is a warning information. You may choose to //! procede with the process if a warning is signaled. //! //! \param bool - 1 if warning and 0 if error //! \param QString - warning/error message //! //! \sa continueAfterWarning() //! \brief Creates QSSLFilter object _QSSLFilter::_QSSLFilter() { d = new QSSLFilterPrivate; d->ssl = 0; d->context = 0; } //! \brief Destroys Object _QSSLFilter::~_QSSLFilter() { reset(); delete d; } //! \brief Reset QSSLFilter's vars. //! //! Reset all the variable inside QSSLFilter. //! //! Use this function if you want to establish a new connection. void _QSSLFilter::reset() { if(d->ssl) { SSL_shutdown(d->ssl); SSL_free(d->ssl); d->ssl = 0; } if(d->context) { SSL_CTX_free(d->context); d->context = 0; } d->sendQueue.resize(0); d->recvQueue.resize(0); d->mode = Idle; } const QSSLCert & _QSSLFilter::peerCertificate() const { return d->cert; } //! \brief Initializes SSL filtering. //! //! Initializes SSL filtering. //! \warning Make sure you establish a socket connection before you call this //! function! //! \return true - if success\n //! false - if anything goes wrong bool _QSSLFilter::begin(const QString &host, const QPtrList &list) { reset(); d->ssl = 0; d->method = 0; d->context = 0; // get our handles d->method = TLSv1_client_method(); if(!d->method) { reset(); return false; } d->context = SSL_CTX_new(d->method); if(!d->context) { reset(); return false; } // load the certs if(!list.isEmpty()) { X509_STORE *store = SSL_CTX_get_cert_store(d->context); QPtrListIterator it(list); for(_QSSLCert *cert; (cert = (_QSSLCert *)it.current()); ++it) X509_STORE_add_cert(store, cert->toX509()); } d->ssl = SSL_new(d->context); if(!d->ssl) { reset(); return false; } SSL_set_ssl_method(d->ssl, d->method); // can this return error? // setup the memory bio // these could error out, but i don't see how d->rbio = BIO_new(BIO_s_mem()); d->wbio = BIO_new(BIO_s_mem()); // these always work SSL_set_bio(d->ssl, d->rbio, d->wbio); d->host = host; d->mode = Connect; sslUpdate(); return true; } //! \brief Send information to decode //! //! Send any information you want to decode through this method. //! \param QByteArray - data to be encrypted void _QSSLFilter::putIncomingSSLData(const QByteArray &a) { BIO_write(d->rbio, a.data(), a.size()); sslUpdate(); } //! \brief Tells you if any data is pending. bool _QSSLFilter::isOutgoingSSLData() { return (BIO_pending(d->wbio) > 0) ? true: false; } //! \brief Returns ssl encrypted data. //! //! This is what you want to send out your socket in most cases. //! \return QByteArray - ssl encrypted data QByteArray _QSSLFilter::getOutgoingSSLData() { QByteArray a; int size = BIO_pending(d->wbio); if(size <= 0) return a; a.resize(size); int r = BIO_read(d->wbio, a.data(), size); if(r <= 0) { a.resize(0); return a; } if(r != size) a.resize(r); return a; } int _QSSLFilter::doConnect() { int ret = SSL_connect(d->ssl); if(ret < 0) { int x = SSL_get_error(d->ssl, ret); if(x == SSL_ERROR_WANT_CONNECT || x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE) return TryAgain; else return Error; } else if(ret == 0) return Error; return Success; } int _QSSLFilter::doHandshake() { int ret = SSL_do_handshake(d->ssl); if(ret < 0) { int x = SSL_get_error(d->ssl, ret); if(x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE) return TryAgain; else return Error; } else if(ret == 0) return Error; return Success; } void _QSSLFilter::sslUpdate() { if(d->mode == Idle) return; if(d->mode == Connect) { int ret = doConnect(); if(ret == Success) { d->mode = Handshake; } else if(ret == Error) { reset(); handshaken(false); return; } } if(d->mode == Handshake) { int ret = doHandshake(); if(ret == Success) { // verify the certificate int code = QSSLCert::Unknown; X509 *x = SSL_get_peer_certificate(d->ssl); if(x) { d->cert.fromX509(x); X509_free(x); int ret = SSL_get_verify_result(d->ssl); if(ret == X509_V_OK) { if(d->cert.matchesAddress(d->host)) code = QSSLCert::Valid; else code = QSSLCert::HostMismatch; } else code = resultToCV(ret); } else { d->cert = _QSSLCert(); code = QSSLCert::NoCert; } d->cert.setValidityResult(code); d->mode = Active; handshaken(true); } else if(ret == Error) { reset(); handshaken(false); return; } } if(isOutgoingSSLData()) { outgoingSSLDataReady(); } // try to read incoming unencrypted data sslReadAll(); if(isRecvData()) readyRead(); } //! \brief send non-encrypted data to object //! //! \param QByteArray - non-encrypted data void _QSSLFilter::send(const QByteArray &a) { if(d->mode != Active) return; int oldsize = d->sendQueue.size(); d->sendQueue.resize(oldsize + a.size()); memcpy(d->sendQueue.data() + oldsize, a.data(), a.size()); processSendQueue(); } //! \brief Data waiting for you to take //! //! Tells you if there is any encrypted data in the queue for you to take. //! \return true - if data is queued\n //! false - if no data is queued bool _QSSLFilter::isRecvData() { return (d->recvQueue.size() > 0) ? true: false; } void _QSSLFilter::sslReadAll() { QByteArray a; while(1) { a.resize(4096); int x = SSL_read(d->ssl, a.data(), a.size()); if(x <= 0) break; if(x != (int)a.size()) a.resize(x); int oldsize = d->recvQueue.size(); d->recvQueue.resize(oldsize + a.size()); memcpy(d->recvQueue.data() + oldsize, a.data(), a.size()); } } //! \brief Get SSL decrypted data. //! //! \return QByteArray - SSL decrypted data QByteArray _QSSLFilter::recv() { QByteArray a = d->recvQueue; a.detach(); d->recvQueue.resize(0); return a; } void _QSSLFilter::processSendQueue() { if(d->sendQueue.size() > 0) { SSL_write(d->ssl, d->sendQueue.data(), d->sendQueue.size()); d->sendQueue.resize(0); sslUpdate(); } } int _QSSLFilter::resultToCV(int ret) const { int rc; switch(ret) { case X509_V_ERR_CERT_REJECTED: rc = QSSLCert::Rejected; break; case X509_V_ERR_CERT_UNTRUSTED: rc = QSSLCert::Untrusted; break; case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: case X509_V_ERR_CERT_SIGNATURE_FAILURE: case X509_V_ERR_CRL_SIGNATURE_FAILURE: case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: rc = QSSLCert::SignatureFailed; break; case X509_V_ERR_INVALID_CA: case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: rc = QSSLCert::InvalidCA; break; case X509_V_ERR_INVALID_PURPOSE: rc = QSSLCert::InvalidPurpose; break; case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: rc = QSSLCert::SelfSigned; break; case X509_V_ERR_CERT_REVOKED: rc = QSSLCert::Revoked; break; case X509_V_ERR_PATH_LENGTH_EXCEEDED: rc = QSSLCert::PathLengthExceeded; break; case X509_V_ERR_CERT_NOT_YET_VALID: case X509_V_ERR_CERT_HAS_EXPIRED: case X509_V_ERR_CRL_NOT_YET_VALID: case X509_V_ERR_CRL_HAS_EXPIRED: case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: rc = QSSLCert::Expired; break; case X509_V_ERR_APPLICATION_VERIFICATION: case X509_V_ERR_OUT_OF_MEM: case X509_V_ERR_UNABLE_TO_GET_CRL: case X509_V_ERR_CERT_CHAIN_TOO_LONG: default: rc = QSSLCert::Unknown; break; } return rc; } @ 1.2 log @- Updated for Psi 0.9. - Version 2.0. @ text @@ 1.1 log @- Commited new sources from Psi CVS. - Let's call it version 1.1 :-) @ text @a20 1 #include"qssl.h" d24 1 d26 2 a27 4 #include #include d60 5 d71 440 d515 1 a515 1 struct QSSLFilterPrivate d517 4 a520 3 int sslAction; QString errMsg; QString trustedCertStoreDir; d527 3 a566 1 d->trustedCertStoreDir = ""; a575 12 //! \brief Set the SSL certificate directory. //! //! \param QString - directory the certificate is located void _QSSLFilter::setSSLTrustedCertStoreDir(const QString &s) { QString str = s; if(str.at(str.length()-1) == '/') str.truncate(str.length()-1); d->trustedCertStoreDir = str; } d595 6 a600 2 d->errMsg = ""; d->sslAction = SSL_IDLE; d610 1 a610 1 bool _QSSLFilter::begin() d630 6 a635 7 if(!d->trustedCertStoreDir.isEmpty()) { QString certfile = d->trustedCertStoreDir + "/cacert.pem"; int ret = SSL_CTX_load_verify_locations(d->context, certfile.latin1(), NULL); if(!ret) { reset(); return false; } a651 1 SSL_set_connect_state(d->ssl); d653 2 a654 1 d->sslAction = SSL_CONNECT; d701 30 d733 1 a733 1 if(d->sslAction == SSL_IDLE) d736 6 a741 3 if(d->sslAction == SSL_CONNECT) { int ret = SSL_connect(d->ssl); if(ret == 0) { d743 1 a743 1 doError(); d746 1 a746 7 if(ret > 0) { if(SSL_do_handshake(d->ssl) < 0) { reset(); doError(); return; } d->sslAction = SSL_HANDSHAKING; d748 15 a762 8 // Added by Kiko 020621: verifies if the certificate chain // is valid. If not, raises an error and set an appropriate // diagnostic message to be retrieved by the upper layers if(!d->trustedCertStoreDir.isEmpty()) { if((ret = SSL_get_verify_result(d->ssl)) != X509_V_OK) { d->errMsg = sslErrMessage(ret); doWarning(); return; d764 6 d771 1 d773 7 a779 1 finishHandshake(); a793 21 void _QSSLFilter::finishHandshake() { d->sslAction = SSL_ACTIVE; processSendQueue(); handshaken(); } //! \brief continue after warning //! //! Tells the method to procede with the process. //! \note You should call this function after you establish a socket connection void _QSSLFilter::continueAfterWarning() { if(d->sslAction == SSL_IDLE || d->sslAction == SSL_CONNECT) sslUpdate(); else if(d->sslAction == SSL_HANDSHAKING) finishHandshake(); else sslUpdate(); } d799 3 d806 1 a806 2 if(d->sslAction == SSL_ACTIVE) processSendQueue(); d858 1 a858 1 void _QSSLFilter::doError() d860 1 a860 2 error(false, d->errMsg); } d862 3 a864 12 void _QSSLFilter::doWarning() { error(true, d->errMsg); } QString _QSSLFilter::sslErrMessage(int errcode) { QString msg; switch (errcode) { case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: msg=tr("Unable to get issuer certificate"); d866 2 a867 2 case X509_V_ERR_UNABLE_TO_GET_CRL: msg=tr("Unable to get certificate CRL"); d869 3 a872 2 msg=tr("Unable to decrypt certificate's signature"); break; d874 1 a874 1 msg=tr("Unable to decrypt CRL's signature"); d876 2 d879 9 a887 1 msg=tr("Unable to decode issuer public key"); d889 2 a890 2 case X509_V_ERR_CERT_SIGNATURE_FAILURE: msg=tr("Invalid certificate signature"); d892 2 a893 2 case X509_V_ERR_CRL_SIGNATURE_FAILURE: msg=tr("Invalid CRL signature"); a895 2 msg=tr("Certificate not yet valid"); break; a896 2 msg=tr("Certificate has expired"); break; a897 2 msg=tr("CRL not yet valid"); break; a898 2 msg=tr("CRL has expired"); break; a899 2 msg=tr("Invalid time in certifiate's notBefore field"); break; a900 2 msg=tr("Invalid time in certificate's notAfter field"); break; a901 2 msg=tr("Invalid time in CRL's lastUpdate field"); break; d903 1 a903 1 msg=tr("Invalid time in CRL's nextUpdate field"); d905 1 d907 1 a907 14 msg=tr("Out of memory while checking the certificate chain"); break; case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: msg=tr("Certificate is self-signed but isn't found in the list of trusted certificates"); break; case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: msg=tr("Certificate chain ends in a self-signed cert that isn't found in the list of trusted certificates"); break; case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: msg=tr("Unable to get issuer certificate locally"); break; case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: msg=tr("Certificate chain contains only one certificate and it's not self-signed"); break; a908 32 msg=tr("Certificate chain too long"); break; case X509_V_ERR_CERT_REVOKED: msg=tr("Certificate is revoked"); break; case X509_V_ERR_INVALID_CA: msg=tr("Invalid CA certificate"); break; case X509_V_ERR_PATH_LENGTH_EXCEEDED: msg=tr("Maximum certificate chain length exceeded"); break; case X509_V_ERR_INVALID_PURPOSE: msg=tr("Invalid certificate purpose"); break; case X509_V_ERR_CERT_UNTRUSTED: msg=tr("Certificate not trusted for the required purpose"); break; case X509_V_ERR_CERT_REJECTED: msg=tr("Root CA is marked to reject the specified purpose"); break; case X509_V_ERR_SUBJECT_ISSUER_MISMATCH: msg=tr("Subject issuer mismatch"); break; case X509_V_ERR_AKID_SKID_MISMATCH: msg=tr("Subject Key Identifier doesn't match the Authority Key Identifier"); break; case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: msg=tr("Subject Key Identifier serial number doesn't match the Authority's"); break; case X509_V_ERR_KEYUSAGE_NO_CERTSIGN: msg=tr("Key Usage doesn't include certificate signing"); break; d910 1 a910 1 msg=tr("Generic certificate validation error"); d913 1 a913 1 return msg; @ .