]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/modules/extra/m_ssl_gnutls.cpp
Merge branch 'master+gnutlsprio'
[user/henk/code/inspircd.git] / src / modules / extra / m_ssl_gnutls.cpp
index df676a2522b979d2e1391eb6095e379873e6a638..716a736f87868f3304adfc7b79a8f697673fe5d2 100644 (file)
@@ -37,6 +37,7 @@
 
 #ifndef GNUTLS_VERSION_NUMBER
 #define GNUTLS_VERSION_NUMBER LIBGNUTLS_VERSION_NUMBER
+#define GNUTLS_VERSION LIBGNUTLS_VERSION
 #endif
 
 // Check if the GnuTLS library is at least version major.minor.patch
@@ -208,14 +209,6 @@ namespace GnuTLS
                        return dh;
                }
 
-               /** Generate */
-               static std::auto_ptr<DHParams> Generate(unsigned int bits)
-               {
-                       std::auto_ptr<DHParams> dh(new DHParams);
-                       ThrowOnError(gnutls_dh_params_generate2(dh->dh_params, bits), "Unable to generate DH params");
-                       return dh;
-               }
-
                ~DHParams()
                {
                        gnutls_dh_params_deinit(dh_params);
@@ -352,6 +345,40 @@ namespace GnuTLS
                {
                        gnutls_priority_set(sess, priority);
                }
+
+               static const char* GetDefault()
+               {
+                       return "NORMAL:%SERVER_PRECEDENCE:-VERS-SSL3.0";
+               }
+
+               static std::string RemoveUnknownTokens(const std::string& prio)
+               {
+                       std::string ret;
+                       irc::sepstream ss(prio, ':');
+                       for (std::string token; ss.GetToken(token); )
+                       {
+                               // Save current position so we can revert later if needed
+                               const std::string::size_type prevpos = ret.length();
+                               // Append next token
+                               if (!ret.empty())
+                                       ret.push_back(':');
+                               ret.append(token);
+
+                               gnutls_priority_t test;
+                               if (gnutls_priority_init(&test, ret.c_str(), NULL) < 0)
+                               {
+                                       // The new token broke the priority string, revert to the previously working one
+                                       ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Priority string token not recognized: \"%s\"", token.c_str());
+                                       ret.erase(prevpos);
+                               }
+                               else
+                               {
+                                       // Worked
+                                       gnutls_priority_deinit(test);
+                               }
+                       }
+                       return ret;
+               }
        };
 #else
        /** Dummy class, used when gnutls_priority_set() is not available
@@ -361,7 +388,7 @@ namespace GnuTLS
         public:
                Priority(const std::string& priorities)
                {
-                       if (priorities != "NORMAL")
+                       if (priorities != GetDefault())
                                throw Exception("You've set a non-default priority string, but GnuTLS lacks support for it");
                }
 
@@ -370,6 +397,17 @@ namespace GnuTLS
                        // Always set the default priorities
                        gnutls_set_default_priority(sess);
                }
+
+               static const char* GetDefault()
+               {
+                       return "NORMAL";
+               }
+
+               static std::string RemoveUnknownTokens(const std::string& prio)
+               {
+                       // We don't do anything here because only NORMAL is accepted
+                       return prio;
+               }
        };
 #endif
 
@@ -563,24 +601,40 @@ namespace GnuTLS
                        return ret;
                }
 
+               static std::string GetPrioStr(const std::string& profilename, ConfigTag* tag)
+               {
+                       // Use default priority string if this tag does not specify one
+                       std::string priostr = GnuTLS::Priority::GetDefault();
+                       bool found = tag->readString("priority", priostr);
+                       // If the prio string isn't set in the config don't be strict about the default one because it doesn't work on all versions of GnuTLS
+                       if (!tag->getBool("strictpriority", found))
+                       {
+                               std::string stripped = GnuTLS::Priority::RemoveUnknownTokens(priostr);
+                               if (stripped.empty())
+                               {
+                                       // Stripping failed, act as if a prio string wasn't set
+                                       stripped = GnuTLS::Priority::RemoveUnknownTokens(GnuTLS::Priority::GetDefault());
+                                       ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Priority string for profile \"%s\" contains unknown tokens and stripping it didn't yield a working one either, falling back to \"%s\"", profilename.c_str(), stripped.c_str());
+                               }
+                               else if ((found) && (stripped != priostr))
+                               {
+                                       // Prio string was set in the config and we ended up with something that works but different
+                                       ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Priority string for profile \"%s\" contains unknown tokens, stripped to \"%s\"", profilename.c_str(), stripped.c_str());
+                               }
+                               priostr.swap(stripped);
+                       }
+                       return priostr;
+               }
+
         public:
                static reference<Profile> Create(const std::string& profilename, ConfigTag* tag)
                {
                        std::string certstr = ReadFile(tag->getString("certfile", "cert.pem"));
                        std::string keystr = ReadFile(tag->getString("keyfile", "key.pem"));
 
-                       std::auto_ptr<DHParams> dh;
-                       int gendh = tag->getInt("gendh");
-                       if (gendh)
-                       {
-                               gendh = (gendh < 1024 ? 1024 : gendh);
-                               dh = DHParams::Generate(gendh);
-                       }
-                       else
-                               dh = DHParams::Import(ReadFile(tag->getString("dhfile", "dhparams.pem")));
+                       std::auto_ptr<DHParams> dh = DHParams::Import(ReadFile(tag->getString("dhfile", "dhparams.pem")));
 
-                       // Use default priority string if this tag does not specify one
-                       std::string priostr = tag->getString("priority", "NORMAL");
+                       std::string priostr = GetPrioStr(profilename, tag);
                        unsigned int mindh = tag->getInt("mindhbits", 1024);
                        std::string hashstr = tag->getString("hash", "md5");
 
@@ -1241,6 +1295,7 @@ class ModuleSSLGnuTLS : public Module
 
        void init() CXX11_OVERRIDE
        {
+               ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "GnuTLS lib version %s module was compiled for " GNUTLS_VERSION, gnutls_check_version(NULL));
                ReadProfiles();
                ServerInstance->GenRandom = &randhandler;
        }