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