[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-devel
Subject:    KSSL* enhancements for openssl SMIME plugin
From:       Stefan Rompf <srompf () isg ! de>
Date:       2003-04-04 19:42:16
[Download RAW message or body]

Hi,

I've started a project to write an openssl based SMIME plugin for kmail.
Main reason is that Aegypten, while providing SMIME support and some
very interesting smartcard features, does not have any KDE integration
by design, making it not so interesting for broad usage with kmail.

I plan to use the peer ssl certificates of kssld to store the email
certificates. However, retrieving them for encryption requires
functionality to get certificates by email address. So I've implemented
some additions to KSSLD, KSSLCertificate, KOpenSSLProxy and
KSSLCertificateCache.

KSSLCertificate:
-a method to get a list of email addresses associated with a certificate
-a method to get a "KDEKey" of a certificate. The KDEKey is a string
that should be both unique and human readable enough to allow
identifying and selecting a certificate. Currently, this is subject +
MD5 digest

KSSLCertificateCache / KSSLD:
-get a KDECertificate for a KDEKey. I'm aware that internal error
handling is quite raw at the moment
-get a list of KDEKeys for an email address

I've attached two patches against KDE 3.1 for review. Currently, they
are only slightly tested (and I've just spotted a memory leak ;-), but
since they will be the base of my further work, I'd like to know whether
I chose the right way and if the changes would be acceptable once they
are more elaborated.

Comments?

Cheers, Stefan

PS: If anybody wonders why I use Netscrap for this mail, kmail on this
machine is currently not configured for external mailing ;-)
["kssl.diff" (text/plain)]

diff -ur -x .deps -x .libs kssl.old/kopenssl.cc kssl/kopenssl.cc
--- kssl.old/kopenssl.cc	2003-01-03 05:58:50.000000000 +0100
+++ kssl/kopenssl.cc	2003-03-20 21:49:27.000000000 +0100
@@ -157,7 +157,9 @@
 static void (*K_ERR_clear_error)() = NULL;
 static void (*K_ERR_print_errors_fp)(FILE*) = NULL;
 static int (*K_PKCS7_verify)(PKCS7*,STACK_OF(X509)*,X509_STORE*,BIO*,BIO*,int) = NULL;
-
+static STACK *(*K_X509_get1_email)(X509 *x) = NULL;
+static void (*K_X509_email_free)(STACK *sk) = NULL;
+   
 #endif
 };
 
@@ -410,6 +412,9 @@
       K_i2d_X509_REQ_fp = (int (*)(FILE *, X509_REQ *)) _cryptoLib->symbol("i2d_X509_REQ_fp");
       K_ERR_clear_error = (void (*)()) _cryptoLib->symbol("ERR_clear_error");
       K_ERR_print_errors_fp = (void (*)(FILE*)) _cryptoLib->symbol("ERR_print_errors_fp");
+      K_X509_get1_email = (STACK *(*)(X509 *x)) _cryptoLib->symbol("X509_get1_email");
+      K_X509_email_free = (void (*)(STACK *sk)) _cryptoLib->symbol("X509_email_free");
+
 #endif
    }
 
@@ -1243,6 +1248,14 @@
 }
 
 
+STACK *KOpenSSLProxy::X509_get1_email(X509 *x) {
+   return (K_X509_get1_email)(x);
+}
+
+
+void KOpenSSLProxy::X509_email_free(STACK *sk) {
+   (K_X509_email_free)(sk);
+}
 
 #endif
 
diff -ur -x .deps -x .libs kssl.old/kopenssl.h kssl/kopenssl.h
--- kssl.old/kopenssl.h	2003-01-03 05:58:50.000000000 +0100
+++ kssl/kopenssl.h	2003-03-20 21:48:34.000000000 +0100
@@ -756,6 +756,10 @@
    /* Print the errors to this stream */
    void ERR_print_errors_fp(FILE *fp);
 
+   /* SMime support */
+   STACK *X509_get1_email(X509 *x);
+   void X509_email_free(STACK *sk);
+
 
 #endif
 
diff -ur -x .deps -x .libs kssl.old/ksslcertificate.cc kssl/ksslcertificate.cc
--- kssl.old/ksslcertificate.cc	2003-01-03 05:58:50.000000000 +0100
+++ kssl/ksslcertificate.cc	2003-03-20 22:34:53.000000000 +0100
@@ -27,6 +27,7 @@
 
 #include <unistd.h>
 #include <qstring.h>
+#include <qstringlist.h>
 #include <qfile.h>
 
 #include "kssldefs.h"
@@ -218,6 +219,26 @@
 }
 
 
+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));
+		}
+	}
+#endif	
+}	
+
+
+QString KSSLCertificate::getKDEKey() const {
+	return getSubject() + " " + getMD5DigestText();
+}
+
+
 QString KSSLCertificate::getMD5DigestText() const {
 QString rc = "";
 
diff -ur -x .deps -x .libs kssl.old/ksslcertificate.h kssl/ksslcertificate.h
--- kssl.old/ksslcertificate.h	2003-01-03 05:58:50.000000000 +0100
+++ kssl/ksslcertificate.h	2003-03-20 22:36:58.000000000 +0100
@@ -42,6 +42,7 @@
 #include <qcstring.h>
 
 class QString;
+class QStringList;
 class QCString;
 class KSSL;
 class KSSLCertificatePrivate;
@@ -108,6 +109,9 @@
   QString getPublicKeyText() const;
   QString getMD5DigestText() const;
   QString getSignatureText() const;
+  void getEmails(QStringList &to) const;
+  // result of getKDEKey might change and should not be used for persistant storage
+  QString getKDEKey() const;
 
   bool isValid();
   bool isValid(KSSLPurpose p);
diff -ur -x .deps -x .libs kssl.old/ksslcertificatecache.cc kssl/ksslcertificatecache.cc
--- kssl.old/ksslcertificatecache.cc	2002-02-12 05:36:06.000000000 +0100
+++ kssl/ksslcertificatecache.cc	2003-04-02 23:12:25.000000000 +0200
@@ -332,6 +332,47 @@
 }
 
 
+QStringList KSSLCertificateCache::getKDEKeybyEmail(const QString &email) {
+     QByteArray data, retval;
+     QCString rettype;
+     QDataStream arg(data, IO_WriteOnly);
+     arg << email;
+     bool rc = d->dcc->call("kded", "kssld",
+                            "getKDEKeybyEmail(QString)",
+                            data, rettype, retval);
+
+     if (rc && rettype == "QStringList") {
+        QDataStream retStream(retval, IO_ReadOnly);
+        QStringList drc;
+        retStream >> drc;
+        return drc;
+     }
+
+     return QStringList();
+}     
+
+
+KSSLCertificate *KSSLCertificateCache::getCertbyKDEKey(const QString &key) {
+     QByteArray data, retval;
+     QCString rettype;
+     QDataStream arg(data, IO_WriteOnly);
+     arg << key;
+     bool rc = d->dcc->call("kded", "kssld",
+                            "getCertbyKDEKey(QString)",
+                            data, rettype, retval);
+
+     if (rc && rettype == "KSSLCertificate") {
+        QDataStream retStream(retval, IO_ReadOnly);
+        KSSLCertificate *drc = new KSSLCertificate;
+        retStream >> *drc;
+	if (drc->getCert()) return drc; 
+	delete drc; // should not happen too often if used in conjunction with getKDEKeybyEmail
+     }
+
+     return NULL;
+}     
+
+
 QDataStream& operator<<(QDataStream& s, const KSSLCertificateCache::KSSLCertificatePolicy& p) {
   s << (Q_UINT32)p;
 return s;
diff -ur -x .deps -x .libs kssl.old/ksslcertificatecache.h kssl/ksslcertificatecache.h
--- kssl.old/ksslcertificatecache.h	2002-02-12 05:36:06.000000000 +0100
+++ kssl/ksslcertificatecache.h	2003-04-02 22:54:33.000000000 +0200
@@ -80,6 +80,10 @@
   bool addHost(KSSLCertificate& cert, QString& host);
   bool removeHost(KSSLCertificate& cert, QString& host);
 
+  // SMIME
+  QStringList getKDEKeybyEmail(const QString &email);
+  KSSLCertificate *getCertbyKDEKey(const QString &key);
+
   void reload();
 
   // You shouldn't need to call this but in some weird circumstances

["kssld.diff" (text/plain)]

diff -ur -x .deps -x .libs -x kssld.moc kssld.old/kssld.cpp kssld/kssld.cpp
--- kssld.old/kssld.cpp	2002-10-27 00:18:24.000000000 +0200
+++ kssld/kssld.cpp	2003-04-02 22:34:55.000000000 +0200
@@ -150,6 +150,8 @@
     certList.remove(node);
     delete node;
   }  
+  sk_email.clear();
+  sk_kdekey.clear();
 }
 
 
@@ -180,6 +182,7 @@
     n->hosts = cfg->readListEntry("Hosts");
     newCert->chain().setChain(cfg->readListEntry("Chain"));
     certList.append(n); 
+    search_add_cert(newCert);
   }
 }
 
@@ -211,6 +214,7 @@
     n->expires = QDateTime::currentDateTime();
     n->expires = n->expires.addSecs(3600);
   }
+  search_add_cert(n->cert);
   cacheSaveToDisk();
 }
 
@@ -329,6 +333,7 @@
     if (KSSLX509Map(node->cert->getSubject()).getValue("CN") == cn) {
       certList.remove(node);
       cfg->deleteGroup(node->cert->getSubject());
+      search_rem_cert(node->cert);
       delete node;
       gotOne = true;
     }
@@ -345,6 +350,7 @@
     if (cert == *(node->cert)) {
       certList.remove(node);
       cfg->deleteGroup(node->cert->getSubject());
+      search_rem_cert(node->cert);
       delete node;
       cacheSaveToDisk();
       return true;
@@ -402,6 +408,7 @@
       if (!node->permanent && node->expires < QDateTime::currentDateTime()) {
         certList.remove(node);
         cfg->deleteGroup(node->cert->getSubject());
+	search_rem_cert(node->cert);
         delete node;
         cacheSaveToDisk();
         return QStringList();
@@ -426,6 +433,7 @@
       if (!node->permanent && node->expires < QDateTime::currentDateTime()) {
         certList.remove(node);
         cfg->deleteGroup(node->cert->getSubject());
+	search_rem_cert(node->cert);
         delete node;
         cacheSaveToDisk();
         return false;
@@ -450,6 +458,7 @@
       if (!node->permanent && node->expires < QDateTime::currentDateTime()) {
         certList.remove(node);
         cfg->deleteGroup(node->cert->getSubject());
+	search_rem_cert(node->cert);
         delete node;
         cacheSaveToDisk();
         return false;
@@ -613,6 +622,73 @@
 return true;
 }
 
+///////////////////////////////////////////////////////////////////////////
+
+void KSSLD::search_add_cert(KSSLCertificate *cert) {
+	sk_kdekey.insert(cert->getKDEKey(), cert, TRUE);
+
+	QStringList mails;
+	cert->getEmails(mails);
+	for(QStringList::const_iterator iter = mails.begin(); iter != mails.end(); iter++) \
{ +		QString email = static_cast<const QString &>(*iter).lower();
+		QMap<QString, QPtrVector<KSSLCertificate> >::iterator it = sk_email.find(email);
+		if (it == sk_email.end()) it = sk_email.insert(email, \
QPtrVector<KSSLCertificate>()); +		QPtrVector<KSSLCertificate> &elem = *it;
+		
+		if (elem.findRef(cert) == -1) {
+			unsigned int n=0;
+			for(; n<elem.size(); n++) {
+				if (!elem.at(n)) {
+					elem.insert(n, cert);
+					break;
+				}
+			}
+			if (n == elem.size()) {
+				elem.resize(n+1);
+				elem.insert(n, cert);
+			}
+		}
+	}	
+}
+
+
+void KSSLD::search_rem_cert(KSSLCertificate *cert) {
+	sk_kdekey.remove(cert->getKDEKey());
+
+	QStringList mails;
+	cert->getEmails(mails);
+	for(QStringList::const_iterator iter = mails.begin(); iter != mails.end(); iter++) \
{ +		QMap<QString, QPtrVector<KSSLCertificate> >::iterator it = \
sk_email.find(static_cast<const QString &>(*iter).lower()); +		if (it == \
sk_email.end()) break; +		QPtrVector<KSSLCertificate> &elem = *it;
+
+		int n = elem.findRef(cert);
+		if (n != -1) elem.remove(n);
+	}
+}	
+
+
+QStringList KSSLD::getKDEKeybyEmail(const QString &email) {
+	QStringList rc;
+	QMap<QString, QPtrVector<KSSLCertificate> >::iterator it = \
sk_email.find(email.lower()); +printf("GETKDEKey %s\n", email.ascii());
+	if (it == sk_email.end()) return rc;
+	QPtrVector<KSSLCertificate> &elem = *it;
+	for (unsigned int n=0; n<elem.size(); n++) if (KSSLCertificate *cert = elem.at(n)) \
rc.append(cert->getKDEKey()); +printf("ergebnisse: %d %d\n", rc.size(), elem.size());
+	return rc;
+}
+
+
+KSSLCertificate KSSLD::getCertbyKDEKey(const QString &key) {
+	QMap<QString, KSSLCertificate *>::iterator iter = sk_kdekey.find(key);
+printf("Searching cert for %s\n", key.ascii());
+	if (iter != sk_kdekey.end()) return **iter;
+	
+	KSSLCertificate rc; // FIXME: Better way to return a not found condition?
+printf("Not found: %s\n", rc.toString().ascii());	
+	return(rc);
+}	
 
 
 ///////////////////////////////////////////////////////////////////////////
diff -ur -x .deps -x .libs -x kssld.moc kssld.old/kssld.h kssld/kssld.h
--- kssld.old/kssld.h	2002-02-12 05:36:06.000000000 +0100
+++ kssld/kssld.h	2003-04-02 21:30:53.000000000 +0200
@@ -27,6 +27,9 @@
 #include <ksslcertificatecache.h>
 #include <qstring.h>
 #include <qstringlist.h>
+#include <qvaluelist.h>
+#include <qmap.h>
+#include <qptrvector.h>
 
 
 class KSimpleConfig;
@@ -100,6 +103,10 @@
 
   bool caSetUse(QString subject, bool ssl, bool email, bool code);
 
+  QStringList getKDEKeybyEmail(const QString &email);
+
+  KSSLCertificate getCertbyKDEKey(const QString &key);
+
   //
   //  Certificate Home methods
   //
@@ -116,6 +123,13 @@
 
   // Our pointer to OpenSSL
   KOpenSSLProxy *kossl;
+
+  // 
+  void search_add_cert(KSSLCertificate *cert);
+  void search_rem_cert(KSSLCertificate *cert);
+
+  QMap<QString, QPtrVector<KSSLCertificate> > sk_email;
+  QMap<QString, KSSLCertificate *> sk_kdekey;
 };
 
 
diff -ur -x .deps -x .libs -x kssld.moc kssld.old/kssld.kidl kssld/kssld.kidl
--- kssld.old/kssld.kidl	2003-02-01 23:56:31.000000000 +0100
+++ kssld/kssld.kidl	2003-04-02 22:10:18.000000000 +0200
@@ -1,5 +1,8 @@
 <!DOCTYPE DCOP-IDL><DCOP-IDL>
 <SOURCE>./kssld.h</SOURCE>
+<INCLUDE>qptrvector.h</INCLUDE>
+<INCLUDE>qmap.h</INCLUDE>
+<INCLUDE>qvaluelist.h</INCLUDE>
 <INCLUDE>qstringlist.h</INCLUDE>
 <INCLUDE>qstring.h</INCLUDE>
 <INCLUDE>ksslcertificatecache.h</INCLUDE>
@@ -136,5 +139,15 @@
         <ARG><TYPE>bool</TYPE><NAME>email</NAME></ARG>
         <ARG><TYPE>bool</TYPE><NAME>code</NAME></ARG>
      </FUNC>
+    <FUNC>
+        <TYPE>QStringList</TYPE>
+        <NAME>getKDEKeybyEmail</NAME>
+        <ARG><TYPE>QString</TYPE><NAME>email</NAME></ARG>
+     </FUNC>
+    <FUNC>
+        <TYPE>KSSLCertificate</TYPE>
+        <NAME>getCertbyKDEKey</NAME>
+        <ARG><TYPE>QString</TYPE><NAME>key</NAME></ARG>
+     </FUNC>
 </CLASS>
 </DCOP-IDL>
diff -ur -x .deps -x .libs -x kssld.moc kssld.old/kssld_skel.cpp kssld/kssld_skel.cpp
--- kssld.old/kssld_skel.cpp	2003-02-01 23:56:31.000000000 +0100
+++ kssld/kssld_skel.cpp	2003-04-02 22:10:33.000000000 +0200
@@ -13,7 +13,7 @@
 
 
 static const int KSSLD_fhash = 29;
-static const char* const KSSLD_ftable[24][3] = {
+static const char* const KSSLD_ftable[26][3] = {
     { "void", "cacheAddCertificate(KSSLCertificate,KSSLCertificateCache::KSSLCertificatePolicy,bool)", \
"cacheAddCertificate(KSSLCertificate cert,KSSLCertificateCache::KSSLCertificatePolicy \
                policy,bool permanent)" },
     { "KSSLCertificateCache::KSSLCertificatePolicy", "cacheGetPolicyByCN(QString)", \
                "cacheGetPolicyByCN(QString cn)" },
     { "KSSLCertificateCache::KSSLCertificatePolicy", \
"cacheGetPolicyByCertificate(KSSLCertificate)", \
"cacheGetPolicyByCertificate(KSSLCertificate cert)" }, @@ -37,6 +37,8 @@
     { "bool", "caRemove(QString)", "caRemove(QString subject)" },
     { "QString", "caGetCert(QString)", "caGetCert(QString subject)" },
     { "bool", "caSetUse(QString,bool,bool,bool)", "caSetUse(QString subject,bool \
ssl,bool email,bool code)" }, +    { "QStringList", "getKDEKeybyEmail(QString)", \
"getKDEKeybyEmail(QString email)" }, +    { "KSSLCertificate", \
"getCertbyKDEKey(QString)", "getCertbyKDEKey(QString key)" },  { 0, 0, 0 }
 };
 
@@ -255,6 +257,22 @@
 	QDataStream _replyStream( replyData, IO_WriteOnly );
 	_replyStream << caSetUse(arg0, arg1, arg2, arg3 );
     } break;
+    case 23: { // QStringList getKDEKeybyEmail(QString)
+	QString arg0;
+	QDataStream arg( data, IO_ReadOnly );
+	arg >> arg0;
+	replyType = KSSLD_ftable[23][0]; 
+	QDataStream _replyStream( replyData, IO_WriteOnly );
+	_replyStream << getKDEKeybyEmail(arg0 );
+    } break;
+    case 24: { // KSSLCertificate getCertbyKDEKey(QString)
+	QString arg0;
+	QDataStream arg( data, IO_ReadOnly );
+	arg >> arg0;
+	replyType = KSSLD_ftable[24][0]; 
+	QDataStream _replyStream( replyData, IO_WriteOnly );
+	_replyStream << getCertbyKDEKey(arg0 );
+    } break;
     default: 
 	return KDEDModule::process( fun, data, replyType, replyData );
     }



>> Visit http://mail.kde.org/mailman/listinfo/kde-devel#unsub to unsubscribe <<


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic