r3352 - in trunk/libmcrypto: include/libmcrypto source

mikaelsv at minisip.org mikaelsv at minisip.org
Wed Aug 8 10:38:19 CEST 2007


Author: mikaelsv
Date: 2007-08-08 10:38:19 +0200 (Wed, 08 Aug 2007)
New Revision: 3352

Added:
   trunk/libmcrypto/include/libmcrypto/CacheManager.h
   trunk/libmcrypto/include/libmcrypto/CertificateFinder.h
   trunk/libmcrypto/include/libmcrypto/CertificatePathFinderUcd.h
   trunk/libmcrypto/source/CacheManager.cxx
   trunk/libmcrypto/source/CertificateFinder.cxx
   trunk/libmcrypto/source/CertificatePathFinderUcd.cxx
Modified:
   trunk/libmcrypto/include/libmcrypto/Makefile.am
   trunk/libmcrypto/include/libmcrypto/cert.h
   trunk/libmcrypto/source/Makefile.am
   trunk/libmcrypto/source/cert.cxx
Log:
This is the first of several updates today. The purpose of today's work
is to add support for Up-Cross-Down Certificate Retrieval.

This revision will probably not compile...



Added: trunk/libmcrypto/include/libmcrypto/CacheManager.h
===================================================================
--- trunk/libmcrypto/include/libmcrypto/CacheManager.h	                        (rev 0)
+++ trunk/libmcrypto/include/libmcrypto/CacheManager.h	2007-08-08 08:38:19 UTC (rev 3352)
@@ -0,0 +1,105 @@
+/*
+ Copyright (C) 2004-2007 The Minisip Team
+
+ 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
+ */
+
+/* Copyright (C) 2007
+ *
+ * Authors: Mikael Svensson
+ */
+
+#ifndef _CACHEMANAGER_H_
+#define _CACHEMANAGER_H_
+
+#include <libminisip/libminisip_config.h>
+
+#include <libmutil/MemObject.h>
+#include <libmutil/CacheItem.h>
+#include <libmnetutil/DirectorySet.h>
+#include <libmnetutil/DirectorySetItem.h>
+#include <libmcrypto/cert.h>
+
+#include <string>
+#include <map>
+
+#define CACHEMANAGER_CERTSET_ROOTCAS "rootcas"
+#define CACHEMANAGER_DIRSET_MAIN "main"
+
+class LIBMINISIP_API CacheManager : public MObject {
+	public:
+		CacheManager();
+
+		//MRef<CertificateSetItem*> findCertificate();
+
+		/**
+		 * Returns a directory set item responsible for a particular domain.
+		 *
+		 * Note that even though several cached directories may match the given domain name only
+		 * the first directory will be returned. Use DirectorySet directly if you need a list
+		 * of all matching directories and not just any matching.
+		 *
+		 * @param	defaultSet	Specifies which set to scan. All sets are scanned if this
+		 * 				parameter is left out or set to an empty string.
+		 */
+		MRef<DirectorySetItem*> findDirectory(const std::string domain, const std::string defaultSet = "");
+		//MRef<CrlSetItem*> findCrl();
+
+		MRef<DirectorySet*> getDirectorySet(std::string key);
+
+		/**
+		 * Adds a directory item to a directory set in the cache.
+		 *
+		 * @param	dirItem		The item to add.
+		 * @param	setKey		The name of the directory set to which the item should be added.
+		 * 				If the string is empty the item will be added to a new directory
+		 * 				set with a random name.
+		 * @returns	The name of the directory set to which the item was added.
+		 */
+		std::string addDirectory(MRef<DirectorySetItem*> dirItem, std::string setKey);
+
+		/**
+		 * Wrapper for addDirectory() that automatically creates an LDAP directory set item
+		 * and adds it to a directory set in the cache.
+		 *
+		 * @param	url		URL speciying the location of the LDAP directory
+		 * @param	subTree		Specifies which part of the DNS tree that the directory
+		 * 				is responsible for.
+		 * @param	setKey		The name of the directory set to which the item should be added.
+		 * 				If the string is empty the item will be added to a new directory
+		 * 				set with a random name.
+		 * @returns	The name of the directory set to which the item was added.
+		 */
+		std::string addDirectoryLdap(std::string url, std::string subTree, const std::string setKey);
+
+		//void purgeCache();
+		//void removeFromCache(MRef<CacheItem*> item);
+
+		/**
+		 * @param	searchText	Can be either a SIP URI or an X.509 DN. If the parameter is a SIP URI then
+		 * 				the function will match the URI against the certificate's subjectAltNames.
+		 * 				Otherwise (if the parameter is not a SIP URI) the subject field is matched.
+		 */
+		std::vector<MRef<Certificate*> > findCertificate(const std::string searchText, const std::string issuer);
+	private:
+		std::string getNewDirectoryKey() const;
+
+		std::map<std::string, MRef<DirectorySet*> > directorySets;
+
+		std::vector<MRef<Certificate*> > fakeCache;
+
+};
+
+#endif

Added: trunk/libmcrypto/include/libmcrypto/CertificateFinder.h
===================================================================
--- trunk/libmcrypto/include/libmcrypto/CertificateFinder.h	                        (rev 0)
+++ trunk/libmcrypto/include/libmcrypto/CertificateFinder.h	2007-08-08 08:38:19 UTC (rev 3352)
@@ -0,0 +1,111 @@
+/*
+ Copyright (C) 2004-2007 The Minisip Team
+
+ 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
+ */
+
+/* Copyright (C) 2007
+ *
+ * Authors: Mikael Svensson
+ */
+
+#ifndef _CERTIFICATEFINDER_H_
+#define _CERTIFICATEFINDER_H_
+
+#include <libminisip/libminisip_config.h>
+
+#include <libmutil/MemObject.h>
+#include <libmutil/Timestamp.h>
+#include <libmcrypto/cert.h>
+#include <libmnetutil/Downloader.h>
+#include <libmnetutil/LdapDownloader.h>
+#include <libminisip/config/CacheManager.h>
+
+#include <string>
+#include <vector>
+
+#ifndef MAX_EFFORT
+#define MAX_EFFORT -1
+#endif
+
+class LIBMINISIP_API CertificateFinderStats : public MObject {
+	public:
+
+		CertificateFinderStats() : ldapQueries (0), ldapQueriesNoResult (0), ldapQueriesNoDirectory (0), ldapCertsDownloaded (0), dnsQueries (0), dnsQueriesNoResult (0), dnsSrvQueries (0), dnsSrvQueriesNoResult (0), certsProcessed (0), certsUseful (0), cacheQueries (0), cacheQueriesNoResult (0) { }
+
+		int ldapQueries;
+		int ldapQueriesNoResult;
+		int ldapQueriesNoDirectory;
+		int ldapCertsDownloaded;
+		int dnsQueries;
+		int dnsQueriesNoResult;
+		int dnsSrvQueries;
+		int dnsSrvQueriesNoResult;
+		int cacheQueries;
+		int cacheQueriesNoResult;
+		int certsProcessed;
+		int certsUseful;
+		Timestamp ts;
+};
+
+/**
+ * Finds certificates mathching certain subjects and issuers.
+ */
+class LIBMINISIP_API CertificateFinder : public MObject {
+
+	public:
+		CertificateFinder();
+		CertificateFinder(MRef<CacheManager*> cm);
+
+		void setStatsObject(CertificateFinderStats * stats) {
+			this->stats = stats;
+		}
+
+		/**
+		* Using all the other functions of this class
+		*/
+		std::vector<MRef<Certificate*> > find(const std::string subjectUri, MRef<Certificate*> curCert, int & effort, const bool typeCrossCert);
+
+		/**
+		* Using local certificate cache
+		*/
+		//std::vector<MRef<Certificate*> > findCache(const std::string subjectUri, const std::string issuerUri);
+
+		/**
+		* Using LDAP
+		*/
+		//std::vector<MRef<Certificate*> > findSubjectInfoAccess(const std::string subjectUri, const std::string issuer, const std::string siaUrl, const bool typeCrossCert);
+
+		/**
+		* Using LDAP
+		*/
+		//std::vector<MRef<Certificate*> > findDnsSrv(const std::string subjectUri);
+
+		/**
+		* Using LDAP
+		*/
+		//std::vector<MRef<Certificate*> > findDnsGuessing(const std::string subjectUri);
+
+		void setAutoCacheCerts(const bool value);
+		bool getAutoCacheCerts() const;
+	private:
+		std::vector<MRef<Certificate*> > downloadFromLdap(const LdapUrl & url, const std::string sipUri, const std::string issuer, const bool typeCrossCert);
+
+		MRef<CacheManager*> cacheManager;
+		bool autoAddToCache;
+
+		CertificateFinderStats * stats;
+};
+#endif

Added: trunk/libmcrypto/include/libmcrypto/CertificatePathFinderUcd.h
===================================================================
--- trunk/libmcrypto/include/libmcrypto/CertificatePathFinderUcd.h	                        (rev 0)
+++ trunk/libmcrypto/include/libmcrypto/CertificatePathFinderUcd.h	2007-08-08 08:38:19 UTC (rev 3352)
@@ -0,0 +1,150 @@
+/*
+ Copyright (C) 2004-2007 The Minisip Team
+
+ 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
+ */
+
+/* Copyright (C) 2007
+ *
+ * Authors: Mikael Svensson
+ */
+
+#ifndef _CERTIFICATEPATHFINDERUCD_H_
+#define _CERTIFICATEPATHFINDERUCD_H_
+
+#include <libminisip/libminisip_config.h>
+
+#include <libmutil/MemObject.h>
+#include <libmutil/Timestamp.h>
+#include <libmcrypto/cert.h>
+#include <libminisip/config/CertificateFinder.h>
+#include <libminisip/config/CacheManager.h>
+
+#include <vector>
+#include <string>
+
+#ifndef MAX_EFFORT
+#define MAX_EFFORT -1
+#endif
+
+class LIBMINISIP_API CertificatePathFinderUcd : public MObject {
+	public:
+		CertificatePathFinderUcd(MRef<CacheManager*> cm);
+		~CertificatePathFinderUcd();
+
+		/**
+		 * Tries to find a path to certificate \p toCert.
+		 *
+		 * The function two stages:
+		 *  - Prepare/validate: Checks if all the necessary information can be derived from the function parameters
+		 *    as well as testing if \p curPath already specifies a correct path to \p toCert.
+		 *  - Find: The actual process of acquiring the missing certificates.
+		 *
+		 * The find stage should probably be described a bit better:
+		 *
+		 *  - First: check if we are looking for a down certificate or not. If not, first look for cross
+		 *    certificates and then for down certificates.
+		 *
+		 *  - Second: Then the "direction" has been determined it is time to actually find the certificates
+		 *    in "that direction". This is done by calling findCrossCerts, findUpCerts or findDownCerts and
+		 *    all those functions return lists of certificates that have "appropriate subjectAltNames".
+		 *
+		 *  - Third: Since the second step returns certificates with the correct subjects we can be pretty
+		 *    sure that they are "good and useful" certificates, but we cannot be sure. The returned
+		 *    certificate can have expired or have subjectInfoAccess values that point to non-existing
+		 *    directories. It is therefor necessary to, for each of the returned certificates, recursively
+		 *    call this function (findUcdPath) with the newest/latest certificate as the last item in
+		 *    \p curPath. This way we test each possible path in a sequential manner.
+		 *
+		 *    If a path turns out to be a dead end \c findUcdpath returns an empty list (this is done in the
+		 *    second step) and the function that called \c findUcdPath can "react to the empty list" by
+		 *    persuing a different path.
+		 *
+		 * @param	curPath		Vector containing the user's own certificates (the start of the chain).
+		 * @param	toCert		The certificate that the algorithm should find a path to.
+		 */
+		std::vector<MRef<Certificate*> > findUcdPath(std::vector<MRef<Certificate*> > curPath, MRef<Certificate*> toCert);
+
+		/**
+		 * Prints statistics for the current CertificatePathFinderUcd instance.
+		 *
+		 * Note that the statistics are accumulated from all calls to findUcdPath, not just the last one.
+		 */
+		void printStats(std::string prefix, std::string timeStampFile = "");
+	private:
+		/**
+		 * Locates cross certificate by first calling \c candidateCrossPaths and the \c findCerts.
+		 */
+		std::vector<MRef<Certificate*> > findCrossCerts	(MRef<Certificate*> curCert, MRef<Certificate*> toCert, int& crossEffort,	int& findEffort);
+		/**
+		 * Locates cross certificate by first calling \c candidateUpPaths and the \c findCerts.
+		 */
+		std::vector<MRef<Certificate*> > findUpCerts	(MRef<Certificate*> curCert, MRef<Certificate*> toCert,	int& upEffort, 		int& findEffort);
+		/**
+		 * Locates cross certificate by first calling \c candidateDownPaths and the \c findCerts.
+		 */
+		std::vector<MRef<Certificate*> > findDownCerts	(MRef<Certificate*> curCert, MRef<Certificate*> toCert, int& downEffort, 	int& findEffort);
+
+		/**
+		 * Tries to find a certificate with one of the strings in \p candidates as the subjectAltName and
+		 * the DN of \p curCert as the issuer. The items in \p candidates are tested in order (the first
+		 * item in this list should therefor specify the "best possible option", i.e. the subjectAltName
+		 * that we would like to find the most).
+		 *
+		 * @param	candidates	List of subjectAltNames that we are looking for.
+		 * @param	curCert		The certificate of the issuer (i.e. the \em subject of this certificate
+		 * 				must be the \em issuer of the certificates we are looking for.
+		 * @param	phaseEffort	The position in \p candidates where the search should begin (if this
+		 * 				parameter is \c 1 then the first item/name of \p candidates will not
+		 * 				be searched for).
+		 * @param	findEffort	???
+		 */
+		std::vector<MRef<Certificate*> > findCerts	(std::vector<std::string> candidates, MRef<Certificate*> curCert, MRef<Certificate*> toCert, int& phaseEffort, int& findEffort);
+
+		/**
+		 * Returns list with the subjectAltNames of \p toCert and the \em probable subjectAltNames of
+		 * any CA that is a parent of \p toCert.
+		 */
+		std::vector<std::string> candidateCrossPaths(MRef<Certificate*> toCert);
+
+		/**
+		 * Returns list of the \em probable subjectAltNames of the CAs that are above \p toCert in the hierarchy.
+		 */
+		std::vector<std::string> candidateUpPaths(MRef<Certificate*> curCert, MRef<Certificate*> toCert);
+
+		/**
+		 * Returns list of the \em probable subjectAltNames of the CAs between \p curCert and \p toCert. The returned
+		 * list also includes the subjectAltName of \p toCert.
+		 */
+		std::vector<std::string> candidateDownPaths(MRef<Certificate*> curCert, MRef<Certificate*> toCert);
+
+		/**
+		 * Validates whether or not the last certificate in \p certList has been issued by the owner of the
+		 * second-to-last certificate in the list.
+		 */
+		bool verifyLastPair(std::vector<MRef<Certificate*> > & certList);
+
+		/**
+		 * Get the (first found) domain name specified in the subjectAltName extensions of certificate \p cert.
+		 *
+		 * Handles both DNS names (obviously) and URIs of SIP type.
+		 */
+		std::string getSubjectDomain(MRef<Certificate*> cert);
+
+		MRef<CertificateFinder*> certFinder;
+		CertificateFinderStats* stats;
+};
+
+#endif

Modified: trunk/libmcrypto/include/libmcrypto/Makefile.am
===================================================================
--- trunk/libmcrypto/include/libmcrypto/Makefile.am	2007-07-02 17:06:08 UTC (rev 3351)
+++ trunk/libmcrypto/include/libmcrypto/Makefile.am	2007-08-08 08:38:19 UTC (rev 3352)
@@ -47,7 +47,9 @@
 		ZrtpDH.h \
 		$(OTHER_FILES)
 
-OTHER_FILES =
+OTHER_FILES = 	CacheManager.h \
+		CertificateFinder.h \
+		CertificatePathFinderUcd.h
 
 if HAVE_EVP_SHA256
 OTHER_FILES += hmac256.h sha256.h

Modified: trunk/libmcrypto/include/libmcrypto/cert.h
===================================================================
--- trunk/libmcrypto/include/libmcrypto/cert.h	2007-07-02 17:06:08 UTC (rev 3351)
+++ trunk/libmcrypto/include/libmcrypto/cert.h	2007-08-08 08:38:19 UTC (rev 3352)
@@ -34,6 +34,7 @@
 #include<libmutil/Mutex.h>
 #include<libmutil/MemObject.h>
 #include<libmutil/Exception.h>
+#include<libmutil/CacheItem.h>
 
 class Certificate;
 
@@ -41,16 +42,93 @@
 #define CERT_DB_ITEM_TYPE_FILE   1
 #define CERT_DB_ITEM_TYPE_DIR    2
 
-class LIBMCRYPTO_API CertificateSetItem: public MObject{
+class LIBMCRYPTO_API CertificatePair: public MObject {
 	public:
+		CertificatePair();
+		CertificatePair(MRef<Certificate*> issuedToThisCA);
+		CertificatePair(MRef<Certificate*> issuedToThisCA, MRef<Certificate*> issuedByThisCA);
+		MRef<Certificate*> issuedToThisCA;
+		MRef<Certificate*> issuedByThisCA;
+};
+
+class LIBMCRYPTO_API CertificateSetItem: public CacheItem {
+	public:
 		std::string item;
 		int type;
 
 		virtual ~CertificateSetItem();
 
+		CertificateSetItem();
+		CertificateSetItem(std::string certUri);
+		CertificateSetItem(MRef<Certificate*> cert);
+
+		/*
+		Getters
+		*/
+		std::string getSubject();
+		std::vector<std::string> getSubjectAltNames();
+		std::string getSubjectKeyIdentifier();
+
+		std::string getIssuer();
+		std::vector<std::string> getIssuerAltNames();
+		std::string getIssuerKeyIdentifier();
+
+		bool isSelfSigned();
+
+		std::string getCertificateUri();
+		MRef<Certificate*> getCertificate();
+
+		/**
+		 * Loads certificates specified by private variables \c certificateUri or \c certificate.
+		 */
+		void loadCertAndIndex();
+
+		/**
+		 * Load certificate contained in \p cert.
+		 */
+		//void loadToMemory(MRef<Certificate*> cert);
+
+		/**
+		 * Frees memory allocated by associated certificate data. The indexed information
+		 * it still kept. This function is useful when loading an entire folder of
+		 * certificates -- it is then probably not necessary/wanted to keep all certificates
+		 * in memory. Thus, when a certificates has been loaded and indexes this function
+		 * is called and the excess memory used by the actual certificate is released.
+		 *
+		 * If the \c certificateUri property has been set the certificate data can be reloaded
+		 * later using the loadToMemory() function.
+		 */
+		void unloadCertificateFromMemory();
+
 		bool operator ==(const CertificateSetItem item2){ return (
 				item2.item == item &&
 				item2.type == type);};
+
+	private:
+		/*
+		Indexed attributes
+		*/
+		std::string subject;
+		std::vector<std::string> subjectAltNames;
+		std::string subjectKeyIdentifier;
+
+		std::string issuer;
+		std::vector<std::string> issuerAltNames;
+		std::string issuerKeyIdentifier;
+
+		/*
+		Certificate status
+		*/
+		bool selfSigned;
+
+		/*
+		Information either linking directly to a instantiated certificate or providing
+		an URI to where the certificate can be found.
+		*/
+		std::string certificateUri;
+		MRef<Certificate*> certificate;
+
+		void reindexCert();
 };
 
 
@@ -178,6 +256,14 @@
 		virtual std::string getIssuer()=0;
 		virtual std::string getIssuerCn()=0;
 
+		/**
+		 * Returns whether or not at least one of the certificate's subjectAltNames
+		 * are equal to \p uri.
+		 */
+		bool hasAltNameSipUri(std::string uri);
+		bool hasAltName(std::string uri);
+		bool hasAltName(std::string uri, SubjectAltName type);
+
 		std::string getFile();
 		std::string getPkFile();
 

Added: trunk/libmcrypto/source/CacheManager.cxx
===================================================================
--- trunk/libmcrypto/source/CacheManager.cxx	                        (rev 0)
+++ trunk/libmcrypto/source/CacheManager.cxx	2007-08-08 08:38:19 UTC (rev 3352)
@@ -0,0 +1,136 @@
+/*
+ Copyright (C) 2007 the Minisip Team
+
+ 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
+ */
+
+/* Copyright (C) 2007
+ *
+ * Authors: Mikael Svensson
+*/
+
+#include <config.h>
+#include <libminisip/config/CacheManager.h>
+#include <libmutil/stringutils.h>
+#include <libmcrypto/cert.h>
+#include <libmnetutil/FileDownloader.h>
+#include <libmsip/SipUri.h>
+
+#include <list>
+#include <stack>
+
+#include <iostream>
+
+CacheManager::CacheManager() {
+	std::cerr << "^^^ Start of " << __FUNCTION__ << std::endl;
+	Certificate* cert;
+
+	std::stack<std::string> certFiles;
+	certFiles.push("/home/mikael/thesis/environments/kth/ucd-fast.SIGNEDBY.ucd-slow.certificate.der");
+	certFiles.push("/home/mikael/thesis/environments/kth/ucd-slow.SIGNEDBY.ucd-fast.certificate.der");
+
+	while (!certFiles.empty()) {
+		FileDownloader file("file://" + certFiles.top());
+		int len = 0;
+		char* data = file.getChars(&len);
+
+		Certificate* cert = Certificate::load(reinterpret_cast<unsigned char*>(data), len);
+		fakeCache.push_back(MRef<Certificate*>(cert));
+
+		certFiles.pop();
+	}
+}
+MRef<DirectorySetItem*> CacheManager::findDirectory(const std::string domain, const std::string defaultSet) {
+	std::cerr << "^^^ Start of " << __FUNCTION__ << std::endl;
+	std::vector<MRef<DirectorySetItem*> > res;
+	if (defaultSet.length() == 0) {
+		// Scan all directory sets
+		//std::map<const std::string, MRef<DirectorySet*> >::iterator i = directorySets.begin();
+		//while (i != directorySets.end()) {
+		for (std::map<const std::string, MRef<DirectorySet*> >::iterator i = directorySets.begin(); i != directorySets.end(); i++) {
+			res = i->second->findItemsPrioritized(domain);
+			if (!res.empty())
+				return res.front();
+		}
+
+	} else {
+		// Scan only one directory set, the one mentioned in the function parameters.
+		if (directorySets.find(defaultSet) != directorySets.end()) {
+			res = directorySets[defaultSet]->findItemsPrioritized(domain);
+			if (!res.empty())
+				return res.front();
+		}
+	}
+	// Return empty item if no result found
+	return MRef<DirectorySetItem*>();
+}
+
+MRef<DirectorySet*> CacheManager::getDirectorySet(std::string key) {
+	std::cerr << "^^^ Start of " << __FUNCTION__ << std::endl;
+	if (directorySets.find(key) != directorySets.end())
+		return directorySets[key];
+	return MRef<DirectorySet*>();
+}
+
+std::string CacheManager::addDirectory(const MRef<DirectorySetItem*> dirItem, std::string setKey) {
+	std::cerr << "^^^ Start of " << __FUNCTION__ << std::endl;
+	if (0 == setKey.length()) {
+		setKey = getNewDirectoryKey();
+	}
+	if (directorySets.find(setKey) == directorySets.end()) {
+		directorySets[setKey] = MRef<DirectorySet*>(new DirectorySet());
+	}
+	directorySets[setKey]->addItem(dirItem);
+	return setKey;
+}
+
+std::string CacheManager::addDirectoryLdap(std::string url, std::string subTree, const std::string setKey) {
+	std::cerr << "^^^ Start of " << __FUNCTION__ << std::endl;
+	return addDirectory(MRef<DirectorySetItem*>(new DirectorySetItem(url, subTree)), setKey != "" ? setKey : getNewDirectoryKey());
+}
+
+//void CacheManager::purgeCache();
+//void CacheManager::removeFromCache(MRef<CacheItem*> item);
+
+std::string CacheManager::getNewDirectoryKey() const {
+	std::cerr << "^^^ Start of " << __FUNCTION__ << std::endl;
+	std::string newName = "dirset";
+	int num = 1;
+	while (directorySets.find(newName + itoa(num)) != directorySets.end())
+		num++;
+	return newName;
+}
+
+/**
+ * @todo	Subject and Issuer should NOT be used to identify certificates. Use *KeyIdentifier (?) and ??? instead.
+ */
+std::vector<MRef<Certificate*> > CacheManager::findCertificate(const std::string searchText, const std::string issuer) {
+	std::cerr << "^^^ Start of " << __FUNCTION__ << std::endl;
+
+	std::vector<MRef<Certificate*> > res;
+	SipUri uri(searchText);
+	for (std::vector<MRef<Certificate*> >::iterator i = fakeCache.begin(); i != fakeCache.end(); i++) {
+		if (uri.isValid()) {
+			if ((*i)->hasAltNameSipUri(searchText) && (*i)->getIssuer() == issuer) {
+				res.push_back(*i);
+			}
+		} else {
+			if ((*i)->getName() == searchText && (*i)->getIssuer() == issuer) {
+				res.push_back(*i);
+			}
+		}
+	}
+	return res;
+}

Added: trunk/libmcrypto/source/CertificateFinder.cxx
===================================================================
--- trunk/libmcrypto/source/CertificateFinder.cxx	                        (rev 0)
+++ trunk/libmcrypto/source/CertificateFinder.cxx	2007-08-08 08:38:19 UTC (rev 3352)
@@ -0,0 +1,350 @@
+/*
+ Copyright (C) 2007 the Minisip Team
+
+ 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
+ */
+
+/* Copyright (C) 2007
+ *
+ * Authors: Mikael Svensson
+*/
+
+#include <config.h>
+#include <libminisip/config/CertificateFinder.h>
+
+#include <libmnetutil/LdapConnection.h>
+#include <libmnetutil/LdapUrl.h>
+#include <libmnetutil/LdapEntry.h>
+#include <libmnetutil/LdapCredentials.h>
+
+#include <iostream>
+
+CertificateFinder::CertificateFinder() : stats(NULL) {
+}
+CertificateFinder::CertificateFinder(MRef<CacheManager*> cm) : cacheManager(cm), stats(NULL) {
+}
+
+/**
+ * Locates, and downloads if necessary, certificates matching the subject and issuer specified as parameters.
+ *
+ * The function first tries to find a suitable certificate in the local cache, then moves on to LDAP directories
+ * mentioned in the issuer certificates (\p curCert). The point is that the function first tries the simple
+ * stuff and then, if that fails, moves on to more advanced and more time-consuming methods.
+ *
+ * The \p effort parameter determines "the simplicity" of the first "certificate retrieval" method to try.
+ * 0 means that the search starts with the local cache.
+ *
+ * @todo	Implement the certificate cache!
+ * @todo	Add support for DNS SRV records.
+ * @param	subjectUri	The subjectAltName of the certificate that we are looking for.
+ * @param	curCert		Certificate with information about the issuer of the certificate we are looking for.
+ * 				This certificate is used to determine the issuer DN of the requested certificate,
+ * 				which LDAP server to query for the requested certificate (the subjectInfoAccess
+ * 				extension or subjectAltName extension is used for this purpose as it is assumed
+ * 				that the issuer also keeps track of its own certificates).
+ * @param	effort		Determines at what "level of difficulty" the search should start.
+ * @param	typeCrossCert	Determines if the requested certificates is a cross certificate. Note that a better
+ * 				description would be "non-user certificates" instead of "cross certificates" as this
+ * 				parameter tells other functions if the certificates should be located in some
+ * 				inetOrgPerson object or in some certificationAuthority object.
+ */
+std::vector<MRef<Certificate*> > CertificateFinder::find(const std::string subjectUri, MRef<Certificate*> curCert, int & effort, const bool typeCrossCert) {
+	std::cerr << "^^^ Start of " << __FUNCTION__ << std::endl;
+
+	std::vector<MRef<Certificate*> > ret;
+
+	std::string issuer = curCert->getName();
+
+	/*
+	Scan the local certificate cache
+	*/
+	if (effort == 0){
+		stats->cacheQueries++;
+		ret = cacheManager->findCertificate(subjectUri, issuer);
+		std::cerr << "    Found certificates in local cache: " << ret.size() << std::endl;
+		if (!ret.empty()){
+			return ret;
+		} else {
+			stats->cacheQueriesNoResult++;
+			effort = 1;
+		}
+	}
+
+	/*
+	See if the current certificate has an subjectInfoAccess extension and, if so, try to
+	connect to the LDAP server specified in this extension. Once connected we try to
+	download a suitable certificate.
+
+	Note that if the certificate should happen to have multiple subjectInfoAccess extensions
+	only the first will be used. Reason: simplicity (developer lazyness...)
+	*/
+	if (effort == 1){
+		std::string siaUrl;
+		std::vector<std::string> sias = curCert->getSubjectInfoAccess();
+		if (!sias.empty()) {
+			siaUrl = sias.at(0);
+
+			LdapUrl url(sias.at(0));
+			ret = downloadFromLdap(url, subjectUri, issuer, typeCrossCert);
+			std::cerr << "    Found certificates using SIA: " << ret.size() << std::endl;
+			if (!ret.empty()) {
+				return ret;
+			}
+		}
+		effort = 2;
+	}
+
+	/*
+	Try to find DNS SRV records specifying LDAP servers in the domain of the issuer.
+	*/
+	if (effort == 2){
+		//ret = ....
+		ret = std::vector<MRef<Certificate*> >();
+		std::cerr << "    Found certificates using SRV records: " << ret.size() << std::endl;
+		if (!ret.empty()) {
+			return ret;
+		} else {
+			effort = 3;
+		}
+	}
+
+	/*
+	If all other options fail: make a wild guesss and try to connect to "ldap.<domain of the issuer>"
+	and see if we by any chance get lucky and find ourselves a nice little server!
+	*/
+	if (effort == 3) {
+
+
+		std::string guessName = "";
+		/*
+		Note: An up-certificate is always issued to a CA, therefore the up-certificate
+		will NOT have a SIP URI as the subjectAltName. Assume that the subjectAltName
+		contains DNS addresses.
+		*/
+
+		std::vector<std::string> curAltNamesDomains = curCert->getAltName(Certificate::SAN_DNSNAME);
+		if (curAltNamesDomains.size() > 0)
+			guessName = curAltNamesDomains.at(0);
+
+		guessName = "ldap." + guessName;//subjectUri.substr(subjectUri.find('@',0)+1);
+		ret = downloadFromLdap(LdapUrl("ldap://" + guessName), subjectUri, issuer, typeCrossCert);
+		std::cerr << "    Found certificates using domain name guessing (guess:" << guessName << "): " << ret.size() << std::endl;
+		if (!ret.empty()) {
+			effort = MAX_EFFORT;
+			return ret;
+		}
+	}
+
+	effort=MAX_EFFORT;
+	return std::vector<MRef<Certificate*> >();
+}
+
+/**
+ * Using LDAP
+ */
+/*
+std::vector<MRef<Certificate*> > CertificateFinder::findSubjectInfoAccess(const std::string subjectUri, const std::string issuer, const std::string siaUrl, const bool typeCrossCert) {
+	std::cerr << "^^^ Start of " << __FUNCTION__ << std::endl;
+	std::vector<MRef<Certificate*> > temp = downloadFromLdap(LdapUrl(siaUrl), subjectUri, issuer, typeCrossCert);
+	std::cerr << "$$$ End of " << __FUNCTION__ << std::endl;
+	return temp;
+}
+*/
+/**
+ * Generic function for downloading one (or many) certificates from directory \p url. The certificates
+ * returned should have \p sipUri as an alternative name and \p issuer as the issuer DN.
+ *
+ * @param	url		LDAP directory location specifier.
+ * @param	sipUri		String that must exist in the subjectAltName extension of returned certificates.
+ * 				Note that, despite the parameter's name, it can also be a DNS name.
+ * @param	issuer		DN of issuer.
+ * @param	typeCrossCert	Set to true if the \em requested certificate is a CA certicate or false if
+ * 				it is an end-user certificates.
+ */
+std::vector<MRef<Certificate*> > CertificateFinder::downloadFromLdap(const LdapUrl & url, const std::string sipUri, const std::string issuer, const bool typeCrossCert) {
+	std::cerr << "^^^ Start of " << __FUNCTION__ << std::endl;
+
+	// Create empty result list
+	std::vector<MRef<Certificate*> > res;
+
+	// Input validation!
+	if (!url.isValid()) {
+		std::cerr << "$$$ End of " << __FUNCTION__ << std::endl;
+		return res;
+	}
+
+	std::cerr << "    Looking for " << (typeCrossCert ? "CA (cross) certificate" : "end-user certificate") << " for " << sipUri << " (directory: " << url.getHost() << ")" << std::endl;
+
+	if (stats != NULL) {
+		stats->dnsQueries++;
+		stats->ts.save("downloadFromLdap:Main:Start " + url.getHost());
+	}
+
+	// Try to connect to LDAP server
+	MRef<LdapCredentials*> creds(new LdapCredentials("", ""));
+	LdapConnection conn(url.getHost(), creds);
+	std::string base;
+
+	if (conn.isConnected(true)) {
+		try {
+			if (stats != NULL) stats->ldapQueries++;
+
+			std::cerr << "    Connected" << std::endl;
+
+			// If the supplied LDAP URL does not specify a base DN we must try to find it ourselves
+			if (url.getDn().length() == 0)
+				base = conn.getBaseDn();
+			else
+				base = url.getDn();
+
+			std::vector<MRef<LdapEntry*> > result;
+			std::vector<MRef<LdapEntry*> >::iterator iter;
+			std::vector<std::string> attrs;
+			int i=0;
+
+			std::cerr << "    Base: " << base << std::endl;
+			try {
+				/*
+				If we are looking for cross certificates we fetch crossCertifiatePairs from
+				certificationAuthority objects, otherwise we retrieve userCertificate attributes
+				from inetOrgPerson objects.
+
+				Note that we download ALL cross certificates from the LDAP server when looking
+				for CA certificates (up, cross or down certificates), but when downloading
+				certificates for end-users we only download the certifiates for the particular
+				user we are interested in.
+
+				Hence, searching for end-user certificates is much more bandwidth efficient than
+				looking for CA certificates.
+
+				Actually, the reason why searches for end-user certificates are efficient is
+				because of the labeledUri attribute: it is an attribute that can store
+				any type of URI and we use it to store the subjectAltName of the certificate
+				stored in the userCertificate attribute (or rather, we assume that one of the
+				labeledUri attributes match the subjectAltName of the userCertificate).
+				*/
+				if (stats != NULL)
+					stats->ts.save("downloadFromLdap:Search:Start");
+
+				if (typeCrossCert) {
+					attrs.push_back("crossCertificatePair;binary");
+					result = conn.find(base, "(objectClass=certificationAuthority)", attrs);
+				} else {
+					attrs.push_back("userCertificate;binary");
+					result = conn.find(base, "(&(objectClass=inetOrgPerson)(labeledUri="+sipUri+" SIPURI))", attrs);
+				}
+
+				if (stats != NULL)
+					stats->ts.save("downloadFromLdap:Search:End");
+
+			} catch (LdapException & ex) {
+				std::cerr << "    LdapException: " << ex.what() << std::endl;
+			}
+			std::cerr << "    " << result.size() << " entries found" << std::endl;
+
+			if (result.size() == 0)
+				if (stats != NULL) stats->ldapQueriesNoResult++;
+
+			for (iter = result.begin(); iter != result.end(); iter++) {
+				std::cerr << "    Found object in LDAP database" << std::endl;
+				std::vector<std::string> fileNames;
+				std::vector< MRef<LdapEntryBinaryValue*> > certs;
+
+				/*
+				Since cross certificates are stored as pairs, and not single certificates,
+				it is necessary to "extract" the two certificates from the pair.
+
+				To simplify the rest of the function the two certificates are added to
+				the "certs" vector without considering which certificate is the "forward"
+				and "reverse" certificate.
+				*/
+				if (typeCrossCert) {
+					std::vector< MRef<LdapEntryBinaryPairValue*> > certPairs;
+					std::vector< MRef<LdapEntryBinaryPairValue*> >::iterator pairIter;
+					certPairs = (*iter)->getAttrValuesBinaryPairs("crossCertificatePair;binary");
+					for (pairIter = certPairs.begin(); pairIter != certPairs.end(); pairIter++) {
+						certs.push_back((*pairIter)->first);
+						certs.push_back((*pairIter)->second);
+					}
+				} else {
+					certs = (*iter)->getAttrValuesBinary("userCertificate;binary");
+				}
+
+				Certificate* cert;
+
+				/*
+				Load/parse each retrieved certificate and test if they match the conditions.
+				*/
+				for (int x=0; x<certs.size(); x++) {
+					MRef<LdapEntryBinaryValue*> val = certs.at(x);
+					cert = Certificate::load(reinterpret_cast<unsigned char*>(val->value), val->length);
+
+					if (stats != NULL) stats->certsProcessed++;
+
+					std::cerr << "    Found binary attribute in LDAP database" << std::endl;
+					if (NULL != cert) {
+						if (stats != NULL) stats->ldapCertsDownloaded++;
+
+						std::cerr << "    Found certificate in LDAP database" << std::endl;
+						std::cerr << "    What we are looking for:" << std::endl;
+						std::cerr << "        Issuer: " << issuer << std::endl;
+						std::cerr << "        URI: " << sipUri << std::endl;
+						std::cerr << "    What we have:" << std::endl;
+						std::cerr << "        Issuer: " << cert->getIssuer() << std::endl;
+						std::cerr << "        URI in altName: " << cert->hasAltName(sipUri) << std::endl;
+						if (cert->getIssuer() == issuer && cert->hasAltName(sipUri)) {
+							/*
+							Bingo!
+
+							The current certificate has (at least) one matching subjectAltName
+							and the correct issuer name. Add the certificate to the result "set".
+							*/
+							if (stats != NULL) stats->certsUseful++;
+							std::cerr << "        Found MATCHING certificate in LDAP database" << std::endl;
+							res.push_back(MRef<Certificate*>(cert));
+						}
+					}
+				}
+			}
+		} catch (LdapException & ex) {
+			std::cerr << "LdapException: " << ex.what() << std::endl;
+		}
+	} else {
+		if (stats != NULL) stats->ldapQueriesNoDirectory++;
+	}
+
+	if (stats != NULL)
+		stats->ts.save("downloadFromLdap:Main:End");
+
+	std::cerr << "$$$ End of " << __FUNCTION__ << std::endl;
+	return res;
+}
+
+/**
+* Using LDAP
+*/
+//std::vector<MRef<Certificate*> > CertificateFinder::findDnsSrv(const std::string subjectUri);
+
+/**
+* Using LDAP
+*/
+//std::vector<MRef<Certificate*> > CertificateFinder::findDnsGuessing(const std::string subjectUri);
+
+void CertificateFinder::setAutoCacheCerts(const bool value) {
+	autoAddToCache = value;
+}
+bool CertificateFinder::getAutoCacheCerts() const {
+	return autoAddToCache;
+}

Added: trunk/libmcrypto/source/CertificatePathFinderUcd.cxx
===================================================================
--- trunk/libmcrypto/source/CertificatePathFinderUcd.cxx	                        (rev 0)
+++ trunk/libmcrypto/source/CertificatePathFinderUcd.cxx	2007-08-08 08:38:19 UTC (rev 3352)
@@ -0,0 +1,509 @@
+/*
+ Copyright (C) 2007 the Minisip Team
+
+ 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
+ */
+
+/* Copyright (C) 2007
+ *
+ * Authors: Mikael Svensson
+*/
+
+#include <config.h>
+#include <libminisip/config/CertificatePathFinderUcd.h>
+#include <libmsip/SipUri.h>
+
+#include <iostream>
+
+CertificatePathFinderUcd::CertificatePathFinderUcd(MRef<CacheManager*> cm) : stats (new CertificateFinderStats()) {
+	std::cerr << "^^^ Start of " << __FUNCTION__ << std::endl;
+	certFinder = MRef<CertificateFinder*>(new CertificateFinder(cm));
+	certFinder->setStatsObject(stats);
+	std::cerr << "$$$ End of " << __FUNCTION__ << std::endl;
+}
+CertificatePathFinderUcd::~CertificatePathFinderUcd() {
+	std::cerr << "^^^ Start of " << __FUNCTION__ << std::endl;
+	delete stats;
+	std::cerr << "$$$ End of " << __FUNCTION__ << std::endl;
+}
+std::vector<MRef<Certificate*> > CertificatePathFinderUcd::findUcdPath(std::vector<MRef<Certificate*> > curPath, MRef<Certificate*> toCert) {
+	std::cerr << "^^^ Start of " << __FUNCTION__ << std::endl;
+
+	std::vector<MRef<Certificate*> > res;
+	if (curPath.size() == 0)
+		return res;
+
+	// Choose first subjectAltName that is a valid SIP URI
+	std::cerr << "    Pick out SIP URIs (or DNS names) from subjectAltName" << std::endl;
+
+	MRef<Certificate*> curCert = curPath.back();
+
+	stats->ts.save("findUcdPath:Main:Start");
+
+	// Get list of alternative names for the last certifiate in the chain (the target of the search)
+	std::vector<std::string> toAltNames = toCert->getAltName(Certificate::SAN_URI);
+	if (toAltNames.size() == 0)
+		toAltNames = toCert->getAltName(Certificate::SAN_DNSNAME);
+
+	// Get list of alternative names for the current certificate in the chain (the certificate closest to the target)
+	std::vector<std::string> lastAltNames = curCert->getAltName(Certificate::SAN_URI);
+	if (lastAltNames.size() == 0)
+		lastAltNames = curCert->getAltName(Certificate::SAN_DNSNAME);
+
+	// Convert the alternative names to SIP URIs. The alternative names are often *not* SIP URIs but rather DNS names.
+	// This, however, does not pose a problem since the SipUri class (for some reason) accepts DNS names as valid
+	// SIP URIs. If this behaviour changes this function will have to be modified...
+
+	SipUri toUri, curUri;
+	for (std::vector<std::string>::iterator nameIter = toAltNames.begin(); nameIter != toAltNames.end(); nameIter++) {
+		SipUri uri(*nameIter);
+		if (uri.isValid()) {
+			toUri = uri;
+			break;
+		}
+	}
+	for (std::vector<std::string>::iterator nameIter = lastAltNames.begin(); nameIter != lastAltNames.end(); nameIter++) {
+		SipUri uri(*nameIter);
+		if (uri.isValid()) {
+			curUri = uri;
+			break;
+		}
+	}
+	if (!curUri.isValid() || !toUri.isValid()) {
+		std::cerr << "$$$ End of " << __FUNCTION__ << std::endl;
+		stats->ts.save("findUcdPath:Main:End");
+		return res;
+	}
+
+	std::cerr << "    Found SIP URIs:" << std::endl;
+	std::cerr << "        curUri=" << curUri << std::endl << "        toUri=" << toUri << std::endl;
+
+	// Test if the last certificate in the chain can be verified using the second-to-last certificates.
+	// If that cannot be done we abort the search as the chain is broken. An empty list is returned
+	// to signify this fact.
+
+	if (!verifyLastPair(curPath)) {
+		std::cerr << "$$$ End of " << __FUNCTION__ << std::endl;
+		stats->ts.save("findUcdPath:Main:End");
+		return res;
+	}
+
+	// Test if the subject name of the last found certificate matches the issuer name
+	// of the certificate that we are trying to get to. If so, we have found a (possible)
+	// path and we must only verify it before we can return the entire chain to the user!
+
+	if (toCert->getIssuer() == curCert->getName() ){
+		curPath.push_back(toCert);
+		if (verifyLastPair(curPath)) {
+			// Bingo!
+			std::cerr << "$$$ End of " << __FUNCTION__ << std::endl;
+			stats->ts.save("findUcdPath:Main:End");
+			return curPath;
+		} else {
+			std::cerr << "$$$ End of " << __FUNCTION__ << std::endl;
+			stats->ts.save("findUcdPath:Main:End");
+			return std::vector<MRef<Certificate*> >();
+		}
+	}
+
+
+	// List with certificates that *probably* can be in the final chain/path
+	std::vector<MRef<Certificate*> > nextCertCandidates;
+	std::vector<MRef<Certificate*> >::iterator i;
+
+	if (stringEndsWith(toUri.getIp(), curUri.getIp())) {
+        	//DOWN mode
+		int32_t downEffort = 0;
+		int32_t findEffort = 0;
+		//do {
+			/**
+			 *
+			 *
+			 *
+			 *
+			 *
+			 * Infinite-loop warning: what happens if findUcdPath() returns an empty list?
+			 * When, and where, are downEffort and findEffort increased?
+			 *
+			 *
+			 *
+			 *
+			 *
+			 */
+
+			downEffort = 0;
+			findEffort = 0;
+			nextCertCandidates = findDownCerts(curCert, toCert, downEffort, findEffort);
+			// Try each certificate that was returned from findDownCerts and recursively
+			// see if it fits the path. This means that the algorithm is a DEPTH-FIRST alg.
+
+			for (i = nextCertCandidates.begin(); i != nextCertCandidates.end(); i++) {
+
+				std::cerr << "    DOWN-mode testing with " << (*i)->getCn() << " as last node in chain." << std::endl;
+
+				std::vector<MRef<Certificate*> > testPath = curPath;
+				testPath.push_back(*i);
+				std::vector<MRef<Certificate*> > retPath = findUcdPath(testPath, toCert);
+				if (!retPath.empty()) {
+					stats->ts.save("findUcdPath:Main:End");
+					std::cerr << "$$$ End of " << __FUNCTION__ << std::endl;
+					return retPath;
+				}
+			}
+		//} while ( ! (downEffort==MAX_EFFORT && findEffort==MAX_EFFORT) );
+	} else {
+        	//UP-CROSS mode
+		int32_t crossEffort = 0;
+		int32_t findEffort = 0;
+		//do {
+			crossEffort = 0;
+			findEffort = 0;
+			nextCertCandidates = findCrossCerts(curCert, toCert, crossEffort, findEffort);
+
+			for (i = nextCertCandidates.begin(); i != nextCertCandidates.end(); i++) {
+
+				std::cerr << "    CROSS-mode testing with " << (*i)->getCn() << " as last node in chain." << std::endl;
+
+				std::vector<MRef<Certificate*> > testPath = curPath;
+				testPath.push_back(*i);
+				std::vector<MRef<Certificate*> > retPath = findUcdPath(testPath, toCert);
+				if (!retPath.empty()) {
+					std::cerr << "$$$ End of " << __FUNCTION__ << std::endl;
+					stats->ts.save("findUcdPath:Main:End");
+					return retPath;
+				}
+			}
+		//} while ( ! (crossEffort==MAX_EFFORT && findEffort==MAX_EFFORT) );
+
+		int32_t upEffort = 0;
+		//do {
+			upEffort = 0;
+			findEffort = 0;
+			nextCertCandidates = findUpCerts(curCert, toCert, upEffort, findEffort);
+			for (i = nextCertCandidates.begin(); i != nextCertCandidates.end(); i++) {
+
+				std::cerr << "    UP-mode testing with " << (*i)->getCn() << " as last node in chain." << std::endl;
+
+				std::vector<MRef<Certificate*> > testPath = curPath;
+				testPath.push_back(*i);
+				std::vector<MRef<Certificate*> > retPath = findUcdPath(testPath, toCert);
+				if (!retPath.empty()) {
+					stats->ts.save("findUcdPath:Main:End");
+					std::cerr << "$$$ End of " << __FUNCTION__ << std::endl;
+					return retPath;
+				}
+			}
+		//} while ( ! (upEffort==MAX_EFFORT && findEffort==MAX_EFFORT) );
+	}
+	std::cerr << "$$$ End of " << __FUNCTION__ << std::endl;
+	stats->ts.save("findUcdPath:Main:End");
+	return std::vector<MRef<Certificate*> >();
+}
+
+std::vector<MRef<Certificate*> > CertificatePathFinderUcd::findCrossCerts	(MRef<Certificate*> curCert, MRef<Certificate*> toCert, int& crossEffort,	int& findEffort) {
+	std::cerr << "^^^ Start of " << __FUNCTION__ << std::endl;
+
+	std::vector<std::string> candidates = candidateCrossPaths(toCert);
+	std::vector<MRef<Certificate*> > temp = findCerts(candidates, curCert, toCert, crossEffort, findEffort);
+
+	std::cerr << "$$$ End of " << __FUNCTION__ << std::endl;
+	return temp;
+}
+std::vector<MRef<Certificate*> > CertificatePathFinderUcd::findUpCerts		(MRef<Certificate*> curCert, MRef<Certificate*> toCert,	int& upEffort, 	int& findEffort) {
+	std::cerr << "^^^ Start of " << __FUNCTION__ << std::endl;
+
+	std::vector<std::string> candidates = candidateUpPaths(curCert, toCert);
+	std::vector<MRef<Certificate*> > temp = findCerts(candidates, curCert, toCert, upEffort, findEffort);
+
+	std::cerr << "$$$ End of " << __FUNCTION__ << std::endl;
+	return temp;
+}
+std::vector<MRef<Certificate*> > CertificatePathFinderUcd::findDownCerts	(MRef<Certificate*> curCert, MRef<Certificate*> toCert, int& downEffort, 	int& findEffort) {
+	std::cerr << "^^^ Start of " << __FUNCTION__ << std::endl;
+
+	std::vector<std::string> candidates = candidateDownPaths(curCert, toCert);
+	std::vector<MRef<Certificate*> > temp = findCerts(candidates, curCert, toCert, downEffort, findEffort);
+
+	std::cerr << "$$$ End of " << __FUNCTION__ << std::endl;
+	return temp;
+}
+
+std::vector<MRef<Certificate*> > CertificatePathFinderUcd::findCerts	(std::vector<std::string> candidates, MRef<Certificate*> curCert, MRef<Certificate*> toCert, int& phaseEffort, int& findEffort) {
+	std::cerr << "^^^ Start of " << __FUNCTION__ << std::endl;
+
+	stats->ts.save("findCerts:Main:Start");
+
+	do {
+		/*
+		If the list of candidates is empty or if the "effort level" (which specifies
+		which of the candidates that should be tested first) exceed the number of
+		candidates then we should abort the function because there is nothing more to be done.
+		*/
+		if (candidates.empty() || phaseEffort >= candidates.size()) {
+			phaseEffort = MAX_EFFORT;
+			findEffort = MAX_EFFORT;
+			break;
+		}
+
+		/*
+		There at least one candidate that has not yet been treid...
+		*/
+		if (phaseEffort != MAX_EFFORT) {
+			/*
+			Try to find a certificate issued TO the current candidate, issued BY the
+			"currenct certificates subject". The current certificate can be any certificate, in theory,
+			but is in actuality always the last found certificate in the chain.
+			*/
+			std::vector<MRef<Certificate*> > foundCerts = certFinder->find(candidates.at(phaseEffort), curCert, findEffort, true);
+			if (!foundCerts.empty()) {
+				// If any certificate where found we return them and feel happy about it!
+				std::cerr << "$$$ End of " << __FUNCTION__ << std::endl;
+				stats->ts.save("findCerts:Main:End");
+				return foundCerts;
+			}
+		}
+
+		/*
+		If we didn't find any certificates we must increase our efforts by advancing to
+		the next candidate in the list. Since we are changing the candidate we also reset
+		the "find effort" so that the next search start all over again by looking in the
+		local certificate cache (instead of using whatever method was successful the last
+		time).
+
+		Increasing the effort (the "phase effort", that is) usually means jumping a step
+		in the domain hierarchy.
+		*/
+		if (findEffort==MAX_EFFORT && phaseEffort!=MAX_EFFORT){
+			phaseEffort++;
+			findEffort = 0;
+		}
+
+		// Will the loop EVER break using this condition????
+	} while (! (phaseEffort==MAX_EFFORT && findEffort==MAX_EFFORT));
+
+	std::cerr << "$$$ End of " << __FUNCTION__ << std::endl;
+	stats->ts.save("findCerts:Main:End");
+	return std::vector<MRef<Certificate*> >();
+}
+
+
+std::vector<std::string> CertificatePathFinderUcd::candidateUpPaths(MRef<Certificate*> curCert, MRef<Certificate*> toCert) {
+	std::cerr << "^^^ Start of " << __FUNCTION__ << std::endl;
+	std::vector<std::string> tempCurrent = candidateCrossPaths(curCert);
+	std::vector<std::string> tempTo = candidateCrossPaths(toCert);
+
+	/*
+	candidateCrossPaths returns the parents as well as the child itself. This is useless when looking for
+	up-certificates as we are not interested if KTH.SE has an up-certificate to KTH.SE.
+
+	This is best examplified by looking at the (next) example: If curCert.domain is "ucd-fast.ssvl.kth.se"
+	then that name will be returned from candidateCrossPaths as well, but it is useless to search for
+	up-certificates to "ucd-fast.ssvl.kth.se" in the directory of "ucd-fast.ssvl.kth.se" -- we are only
+	interested in what lies *above* curCert.domain.
+	*/
+
+	std::cerr << "    tempCurrent.size()=" << tempCurrent.size() << ", tempTo.size()=" << tempTo.size() << std::endl;
+
+	if (tempCurrent.size() > 0)
+		tempCurrent.erase(tempCurrent.begin());
+	if (tempTo.size() > 0)
+		tempTo.erase(tempTo.begin());
+
+	/*
+	Remove suggested paths/URIs that both candidateCrossPath(curCert) and candidateCrossPath(toCert) have in common.
+	Perhaps an example will explain this better:
+
+	If curCert.domain is "ucd-fast.ssvl.kth.se" and toCert.domain is "ssvl.kth.se"
+	then candidateCrossPath(curCert) will return all these domains:
+	 - ucd-fast.ssvl.kth.se
+	 - ssvl.kth.se
+	 - kth.se
+
+	But looking for up-certificates for kth.se would be useless since kth.se has not been involved
+	in any of the two certificates that we are concerned about. This function should therefore remove
+	the kth.se entry from the result before returning.
+	*/
+	if (!tempCurrent.empty() && !tempTo.empty()) {
+		while (tempCurrent.back() == tempTo.back()) {
+			tempCurrent.pop_back();
+			tempTo.pop_back();
+		}
+	}
+
+	std::cerr << "$$$ End of " << __FUNCTION__ << std::endl;
+	return tempCurrent;
+}
+
+/**
+ * @note	What happens if a certificate contains multiple subjectAltNames URIs which all
+ * 		point to the same domain (this function will resturn duplicates in the result...)
+ */
+std::vector<std::string> CertificatePathFinderUcd::candidateCrossPaths(MRef<Certificate*> toCert) {
+	std::cerr << "^^^ Start of " << __FUNCTION__ << std::endl;
+
+	/*
+	Get list of alternative names of the intended target. Since the target can be both a
+	CA and end-user the alternative names can be either a DNS name or and URI.
+	*/
+	std::vector<std::string> altNames = toCert->getAltName(Certificate::SAN_URI);
+	if (altNames.size() == 0) {
+		altNames = toCert->getAltName(Certificate::SAN_DNSNAME);
+	}
+	std::vector<std::string>::iterator nameIter;
+	std::vector<std::string> resDomains;
+
+	std::cerr << "    Certificate belonging to " << toCert->getCn() << " has " << altNames.size() << " subjectAltNames" << std::endl;
+	/*
+	For each of the alt. names we calculate all possible "parent name". Note that it is
+	VERY unlikely that a CA certificate has multiple alternative names, an end-user may
+	on the other hand have several names specified. Different names for different services,
+	and one of those services might be up-cross-down certificate retrieval in SIP!
+
+	Note that duplicates are not eliminated: If a user has several alternative names, and
+	all of them belong to the same domain (e.g. "sip:mikael at kth.se" and "mail:mikael at kth.se"),
+	then the returned list will contain duplicates (e.g. {"kth.se", "kth.se"}).
+	*/
+	for (nameIter = altNames.begin(); nameIter != altNames.end(); nameIter++) {
+		SipUri uri(*nameIter);
+		std::cerr << "    Processing URI " << (*nameIter) << (uri.isValid() ? " (valid)" : " (NOT valid)") << std::endl;
+
+		/*
+		The SipUri class, for some reason, accepts DNS names as valid SIP URIs. This behavious
+		seems odd but is useful in this context: we can test for valid alternative names without
+		consideration of that type of name we are testing.
+		*/
+		if (uri.isValid()) {
+			/*
+			Since we are looking for cross-paths we should always include the target
+			itself in the list of possible cross-certifcate subjects.
+			*/
+			if (uri.getUserName().length() > 0)
+				resDomains.push_back("sip:" + uri.getUserIpString());
+
+			std::string host = uri.getIp();
+
+			if (host.length() > 0) {
+				std::string::size_type pos = 0;
+				do {
+					std::string newDomain = host.substr(pos);
+
+					resDomains.push_back(newDomain);
+
+					pos = host.find('.', pos)+1;
+				} while (pos != std::string::npos+1);
+
+				// Remove last entry if it doesn't contain a dot (as is the case with "org", "se" and "com")
+				if (resDomains.back().find('.',0) == std::string::npos)
+					resDomains.pop_back();
+			}
+		}
+	}
+	std::cerr << "$$$ End of " << __FUNCTION__ << std::endl;
+	return resDomains;
+}
+
+std::vector<std::string> CertificatePathFinderUcd::candidateDownPaths(MRef<Certificate*> curCert, MRef<Certificate*> toCert) {
+	std::cerr << "^^^ Start of " << __FUNCTION__ << std::endl;
+
+	std::vector<std::string> toAltNames = toCert->getAltName(Certificate::SAN_URI);
+
+	/*
+	When looking for down-certificates we must know where in the hierarchy
+	we are right now (so that we don't accidentally "mark" a parent as a child).
+	*/
+	std::string curDomain = getSubjectDomain(curCert);
+
+	std::vector<std::string> resDomains;
+
+	if (curDomain.length() > 0) {
+		for (std::vector<std::string>::iterator nameIter = toAltNames.begin(); nameIter != toAltNames.end(); nameIter++) {
+			SipUri uri(*nameIter);
+			std::cerr << "    Testing subjectAltName " << *nameIter << " and extracting domain names:" << std::endl;
+			std::cerr << "        uri.isValid() = " << uri.isValid() << ", stringEndsWith(uri.getIp(), curDomain) = " << stringEndsWith(uri.getIp(), curDomain) << std::endl;
+
+			/*
+			Test if the current alt. name is a proper one AND that it represents
+			an entity further down in the hierarchy. The latter is tested simply
+			by checking what text the alternative name ends with.
+			*/
+			if (uri.isValid() && stringEndsWith(uri.getIp(), curDomain)) {
+				std::string host = uri.getIp();
+				std::string::size_type pos = 0;
+				while (pos != std::string::npos) {
+					std::string newDomain = host.substr(pos);
+					if (newDomain == curDomain)
+						break;
+
+					resDomains.push_back(newDomain);
+					std::cerr << "    candidateDownPath: " << newDomain << std::endl;
+
+					pos = host.find('.', pos)+1;
+				}
+			}
+		}
+	}
+	std::cerr << "$$$ End of " << __FUNCTION__ << std::endl;
+	return resDomains;
+}
+
+/**
+ * @todo	Implement the function!
+ */
+bool CertificatePathFinderUcd::verifyLastPair(std::vector<MRef<Certificate*> > & certList) {
+	std::cerr << "^^^ Start of " << __FUNCTION__ << std::endl;
+	std::cerr << "$$$ End of " << __FUNCTION__ << std::endl;
+	return true;
+}
+
+void CertificatePathFinderUcd::printStats(std::string prefix, std::string timeStampFile) {
+	if (stats != NULL) {
+		std::cout << prefix << "cacheQueries:            " << stats->cacheQueries << std::endl;
+		std::cout << prefix << "cacheQueriesNoResult:    " << stats->cacheQueriesNoResult << std::endl;
+		std::cout << prefix << "dnsQueries:              " << stats->dnsQueries << std::endl;
+		std::cout << prefix << "ldapQueries:             " << stats->ldapQueries << std::endl;
+		std::cout << prefix << "ldapQueriesNoResult:     " << stats->ldapQueriesNoResult << std::endl;
+		std::cout << prefix << "ldapQueriesNoDirectory:  " << stats->ldapQueriesNoDirectory << std::endl;
+		std::cout << prefix << "ldapCertsDownloaded:     " << stats->ldapCertsDownloaded << std::endl;
+		//std::cout << "dnsQueriesNoResult:      " << stats->dnsQueriesNoResult << std::endl;
+		//std::cout << "dnsSrvQueries:           " << stats->dnsSrvQueries << std::endl;
+		//std::cout << "dnsSrvQueriesNoResult:   " << stats->dnsSrvQueriesNoResult << std::endl;
+		//std::cout << "certsProcessed:          " << stats->certsProcessed << std::endl;
+		//std::cout << "certsUseful:             " << stats->certsUseful << std::endl;
+		if (timeStampFile.length() > 0) {
+			stats->ts.print(timeStampFile);
+		}
+	} else {
+		std::cout << "No stats collected." << std::endl;
+	}
+}
+std::string CertificatePathFinderUcd::getSubjectDomain(MRef<Certificate*> cert) {
+	std::vector<std::string> curAltNames = cert->getAltName(Certificate::SAN_URI);
+	if (curAltNames.size() > 0) {
+		// First try to determine the "current domain" by analyzing the subjectAltNames and assuming that the "current certificate" is an end-user certificate
+		for (std::vector<std::string>::iterator nameIter = curAltNames.begin(); nameIter != curAltNames.end(); nameIter++) {
+			SipUri uri(*nameIter);
+			if (uri.isValid()) {
+				return uri.getIp();
+			}
+		}
+
+	} else {
+		// No SIP URIs were found in the subjectAltNames. Try looking for DNS names instead (i.e. assume that the current certificate is a CA certificate instead of an end-user certificate)
+		curAltNames = cert->getAltName(Certificate::SAN_DNSNAME);
+		if (curAltNames.size() > 0)
+			return curAltNames.at(0);
+	}
+	return "";
+}

Modified: trunk/libmcrypto/source/Makefile.am
===================================================================
--- trunk/libmcrypto/source/Makefile.am	2007-07-02 17:06:08 UTC (rev 3351)
+++ trunk/libmcrypto/source/Makefile.am	2007-08-08 08:38:19 UTC (rev 3352)
@@ -46,7 +46,10 @@
 		$(srp_src) \
 		TlsException.cxx \
 		uuid.cxx \
-		rijndael-alg-fst.cxx
+		rijndael-alg-fst.cxx \
+		CacheManager.cxx \
+		CertificateFinder.cxx \
+		CertificatePathFinderUcd.cxx
 
 libmcrypto_core_la_LIBADD = $(srp_libs) $(SCSIM_LIBS)
 

Modified: trunk/libmcrypto/source/cert.cxx
===================================================================
--- trunk/libmcrypto/source/cert.cxx	2007-07-02 17:06:08 UTC (rev 3351)
+++ trunk/libmcrypto/source/cert.cxx	2007-08-08 08:38:19 UTC (rev 3352)
@@ -1,7 +1,7 @@
 /*
   Copyright (C) 2005, 2004 Erik Eliasson, Johan Bilien
   Copyright (C) 2006 Mikael Magnusson
-  
+
   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
@@ -33,8 +33,23 @@
 #include<iostream>
 #include <fstream>
 
+#include <libmnetutil/Downloader.h>
+
 using namespace std;
 
+CertificatePair::CertificatePair() {
+	issuedToThisCA = MRef<Certificate*>();
+	issuedByThisCA = MRef<Certificate*>();
+}
+CertificatePair::CertificatePair(MRef<Certificate*> issuedToThisCA) {
+	this->issuedToThisCA = issuedToThisCA;
+	this->issuedByThisCA = MRef<Certificate*>();
+}
+CertificatePair::CertificatePair(MRef<Certificate*> issuedToThisCA, MRef<Certificate*> issuedByThisCA) {
+	this->issuedToThisCA = issuedToThisCA;
+	this->issuedByThisCA = issuedByThisCA;
+}
+
 PrivateKey::PrivateKey(){
 }
 
@@ -47,6 +62,26 @@
 Certificate::~Certificate(){
 }
 
+bool Certificate::hasAltNameSipUri(std::string uri) {
+	return hasAltName(uri, Certificate::SAN_URI);
+}
+bool Certificate::hasAltName(std::string uri) {
+	SubjectAltName types[] = {Certificate::SAN_DNSNAME, Certificate::SAN_RFC822NAME, Certificate::SAN_URI, Certificate::SAN_IPADDRESS};
+	for (int i=0; i<4; i++)
+		if (hasAltName(uri, types[i]))
+			return true;
+	return false;
+}
+bool Certificate::hasAltName(std::string uri, SubjectAltName type) {
+	std::vector<std::string> altNames = getAltName(type);
+	std::vector<std::string>::iterator nameIter;
+	for (nameIter = altNames.begin(); nameIter != altNames.end(); nameIter++) {
+		if ((*nameIter) == uri) {
+			return true;
+		}
+	}
+	return false;
+}
 
 string Certificate::getFile(){
 	return file;
@@ -73,7 +108,7 @@
 				     enckey, enckeylgth, iv );
 }
 
-int Certificate::signData( unsigned char * data, int data_length, 
+int Certificate::signData( unsigned char * data, int data_length,
 			    unsigned char * sign,
 			    int * sign_length ){
 	massert(m_pk);
@@ -115,10 +150,89 @@
 	setPk( PrivateKey::load( derEncPk, length, password, path ) );
 }
 
+CertificateSetItem::CertificateSetItem() : certificateUri(""), certificate(NULL) {
+}
+
+CertificateSetItem::CertificateSetItem(std::string certUri) : certificateUri(certUri), certificate(NULL) {
+	loadCertAndIndex();
+}
+
+CertificateSetItem::CertificateSetItem(MRef<Certificate*> cert) : certificateUri(""), certificate(cert) {
+	loadCertAndIndex();
+}
+
 CertificateSetItem::~CertificateSetItem(){
 }
 
+void CertificateSetItem::loadCertAndIndex() {
+	if (!certificate.isNull()) {
+		reindexCert();
+	} else if (certificateUri.length() > 0) {
+		MRef<Downloader*> loader = Downloader::create(certificateUri);
+		int certLen = 0;
+		char* certData;
+		certData = loader->getChars(&certLen);
+		if (certData != NULL && certLen > 0) {
+			certificate = Certificate::load(reinterpret_cast<unsigned char*>(certData), certLen);
+			reindexCert();
+		}
+	}
+}
 
+std::string CertificateSetItem::getSubject() {
+	return subject;
+}
+std::vector<std::string> CertificateSetItem::getSubjectAltNames() {
+	return subjectAltNames;
+}
+std::string CertificateSetItem::getSubjectKeyIdentifier() {
+	return subjectKeyIdentifier;
+}
+
+std::string CertificateSetItem::getIssuer() {
+	return issuer;
+}
+std::vector<std::string> CertificateSetItem::getIssuerAltNames() {
+	return issuerAltNames;
+}
+std::string CertificateSetItem::getIssuerKeyIdentifier() {
+	return issuerKeyIdentifier;
+}
+
+bool CertificateSetItem::isSelfSigned() {
+	return selfSigned;
+}
+
+std::string CertificateSetItem::getCertificateUri() {
+	return certificateUri;
+}
+MRef<Certificate*> CertificateSetItem::getCertificate() {
+	if (certificate.isNull())
+		loadCertAndIndex();
+	return certificate;
+}
+
+void CertificateSetItem::reindexCert() {
+	if (!certificate.isNull()) {
+		subject = certificate->getName();
+		std::vector<std::string> subjectAltNames;
+
+		Certificate::SubjectAltName altTypes[] = {Certificate::SAN_DNSNAME, Certificate::SAN_RFC822NAME, Certificate::SAN_URI, Certificate::SAN_IPADDRESS};
+		for (int i=0; i < 4; i++) {
+			std::vector<std::string> tempNames = certificate->getAltName(altTypes[i]);
+			subjectAltNames.insert(subjectAltNames.end(), tempNames.begin(), tempNames.end());
+		}
+
+		//subjectKeyIdentifier;
+
+		issuer = certificate->getIssuer();
+		//issuerAltNames;
+		//issuerKeyIdentifier;
+
+		selfSigned = (subject == issuer);
+	}
+}
+
 CertificateSet::CertificateSet(){
 	items_index = items.begin();
 }
@@ -140,7 +254,7 @@
 	for( i = items.begin(); i != last; i++ ){
 		db->addItem( *i );
 	}
-	
+
 	unlock();
 	return db;
 }
@@ -160,7 +274,7 @@
 
 MRef<CertificateSetItem*> CertificateSet::createDirItem( std::string dir ){
 	MRef<CertificateSetItem*> item = new CertificateSetItem();
-	
+
 	item->item = dir;
 	item->type = CERT_DB_ITEM_TYPE_DIR;
 	return item;
@@ -168,7 +282,7 @@
 
 MRef<CertificateSetItem*> CertificateSet::createFileItem( std::string file ){
 	MRef<CertificateSetItem*> item = new CertificateSetItem;
-	
+
 	item->item = file;
 	item->type = CERT_DB_ITEM_TYPE_FILE;
 	return item;
@@ -176,7 +290,7 @@
 
 MRef<CertificateSetItem*> CertificateSet::createCertItem( MRef<Certificate*> cert ){
 	MRef<CertificateSetItem*> item = new CertificateSetItem();
-	
+
 	item->item = "";
 	item->type = CERT_DB_ITEM_TYPE_OTHER;
 	return item;
@@ -221,7 +335,7 @@
 
 MRef<CertificateSetItem*> CertificateSet::getNext(){
 	MRef<CertificateSetItem*> tmp;
-	
+
 	if( items_index == items.end() ){
 		items_index = items.begin();
 		return NULL;
@@ -238,7 +352,7 @@
 }
 
 CertificateChain::CertificateChain( MRef<Certificate *> cert ){
-	
+
 	cert_list.push_back( cert );
 	item = cert_list.begin();
 }
@@ -256,7 +370,7 @@
 	for( i = cert_list.begin(); i != last; i++ ){
 		chain->addCertificate( *i );
 	}
-	
+
 	unlock();
 	return chain;
 }
@@ -275,7 +389,7 @@
 
 
 void CertificateChain::addCertificate( MRef<Certificate *> cert ){
-	
+
 	if( !cert_list.empty() ){
 		MRef<Certificate *> lastCert = *(--cert_list.end());
 
@@ -285,7 +399,7 @@
 				" issued by the given one" );
 		}
 	}
-	
+
 	cert_list.push_back( cert );
 	item = cert_list.begin();
 }
@@ -303,7 +417,7 @@
 
 MRef<Certificate *> CertificateChain::getNext(){
 	MRef<Certificate *> ret;
-	
+
 	if( item == cert_list.end() ){
 		item = cert_list.begin();
 		return NULL;
@@ -318,7 +432,7 @@
 	if( cert_list.size() == 0 ){
 		return NULL;
 	}
-	
+
 	return *(cert_list.begin());
 }
 



More information about the Minisip-devel mailing list