ksslsettings.cc
00001 /* This file is part of the KDE project 00002 * 00003 * Copyright (C) 2000 George Staikos <staikos@kde.org> 00004 * 00005 * This library is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU Library General Public 00007 * License as published by the Free Software Foundation; either 00008 * version 2 of the License, or (at your option) any later version. 00009 * 00010 * This library is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Library General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Library General Public License 00016 * along with this library; see the file COPYING.LIB. If not, write to 00017 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 * Boston, MA 02110-1301, USA. 00019 */ 00020 00021 #ifdef HAVE_CONFIG_H 00022 #include <config.h> 00023 #endif 00024 00025 #include <sys/types.h> 00026 #include <sys/stat.h> 00027 00028 #include <stdlib.h> 00029 #include <pwd.h> 00030 #include <unistd.h> 00031 00032 #include <tqfile.h> 00033 #include <tqsortedlist.h> 00034 00035 #include "ksslsettings.h" 00036 #include <kglobal.h> 00037 #include <kstandarddirs.h> 00038 #include <kdebug.h> 00039 00040 // this hack provided by Malte Starostik to avoid glibc/openssl bug 00041 // on some systems 00042 #ifdef KSSL_HAVE_SSL 00043 #define crypt _openssl_crypt 00044 #include <openssl/ssl.h> 00045 #undef crypt 00046 #endif 00047 #include <kopenssl.h> 00048 00049 00050 class CipherNode { 00051 public: 00052 CipherNode(const char *_name, int _keylen) : 00053 name(_name), keylen(_keylen) {} 00054 TQString name; 00055 int keylen; 00056 inline int operator==(CipherNode &x) 00057 { return ((x.keylen == keylen) && (x.name == name)); } 00058 inline int operator< (CipherNode &x) { return keylen < x.keylen; } 00059 inline int operator<=(CipherNode &x) { return keylen <= x.keylen; } 00060 inline int operator> (CipherNode &x) { return keylen > x.keylen; } 00061 inline int operator>=(CipherNode &x) { return keylen >= x.keylen; } 00062 }; 00063 00064 00065 class KSSLSettingsPrivate { 00066 public: 00067 KSSLSettingsPrivate() { 00068 kossl = NULL; // try to delay this as long as possible 00069 } 00070 ~KSSLSettingsPrivate() { 00071 00072 } 00073 00074 KOSSL *kossl; 00075 bool m_bUseEGD; 00076 bool m_bUseEFile; 00077 TQString m_EGDPath; 00078 bool m_bSendX509; 00079 bool m_bPromptX509; 00080 }; 00081 00082 // 00083 // FIXME 00084 // Implementation note: for now, we only read cipher settings from disk, 00085 // and do not store them in memory. This should change. 00086 // 00087 00088 KSSLSettings::KSSLSettings(bool readConfig) { 00089 d = new KSSLSettingsPrivate; 00090 m_cfg = new KConfig("cryptodefaults", false, false); 00091 00092 if (!KGlobal::dirs()->addResourceType("kssl", KStandardDirs::kde_default("data") + "kssl")) { 00093 //kdDebug(7029) << "Error adding (kssl, share/apps/kssl)" << endl; 00094 } 00095 00096 if (readConfig) load(); 00097 } 00098 00099 00100 // we don't save settings incase it was a temporary object 00101 KSSLSettings::~KSSLSettings() { 00102 delete m_cfg; 00103 delete d; 00104 } 00105 00106 00107 bool KSSLSettings::sslv2() const { 00108 return m_bUseSSLv2; 00109 } 00110 00111 00112 bool KSSLSettings::sslv3() const { 00113 return m_bUseSSLv3; 00114 } 00115 00116 00117 bool KSSLSettings::tlsv1() const { 00118 return m_bUseTLSv1; 00119 } 00120 00121 00122 // FIXME: we should make a default list available if this fails 00123 // since OpenSSL seems to just choose any old thing if it's given an 00124 // empty list. This behavior is not confirmed though. 00125 TQString KSSLSettings::getCipherList() { 00126 TQString clist; 00127 #ifdef KSSL_HAVE_SSL 00128 TQString tcipher; 00129 bool firstcipher = true; 00130 SSL_METHOD *meth = 0L; 00131 TQPtrList<CipherNode> cipherList; 00132 00133 cipherList.setAutoDelete(true); 00134 00135 if (!d->kossl) 00136 d->kossl = KOSSL::self(); 00137 00138 if (m_bUseSSLv3 && m_bUseSSLv2) 00139 meth = d->kossl->TLS_client_method(); 00140 else if(m_bUseSSLv3) 00141 meth = d->kossl->SSLv3_client_method(); 00142 else if (m_bUseSSLv2) 00143 meth = d->kossl->SSLv2_client_method(); 00144 00145 SSL_CTX *ctx = d->kossl->SSL_CTX_new(meth); 00146 SSL* ssl = d->kossl->SSL_new(ctx); 00147 STACK_OF(SSL_CIPHER)* sk = d->kossl->SSL_get_ciphers(ssl); 00148 int cnt = d->kossl->OPENSSL_sk_num(sk); 00149 for (int i=0; i< cnt; i++) { 00150 SSL_CIPHER *sc = reinterpret_cast<SSL_CIPHER*>(d->kossl->OPENSSL_sk_value(sk,i)); 00151 if (!sc) 00152 break; 00153 00154 if(!strcmp("SSLv2", d->kossl->SSL_CIPHER_get_version(sc))) 00155 m_cfg->setGroup("SSLv2"); 00156 else 00157 m_cfg->setGroup("SSLv3"); 00158 00159 tcipher.sprintf("cipher_%s", d->kossl->SSL_CIPHER_get_name(sc)); 00160 int bits = d->kossl->SSL_CIPHER_get_bits(sc, NULL); 00161 if (m_cfg->readBoolEntry(tcipher, bits >= 56)) { 00162 CipherNode *xx = new CipherNode(d->kossl->SSL_CIPHER_get_name(sc),bits); 00163 if (!cipherList.contains(xx)) 00164 cipherList.prepend(xx); 00165 else 00166 delete xx; 00167 } 00168 } 00169 d->kossl->SSL_free(ssl); 00170 d->kossl->SSL_CTX_free(ctx); 00171 00172 // Remove any ADH ciphers as per RFC2246 00173 // Also remove NULL ciphers and 168bit ciphers 00174 for (unsigned int i = 0; i < cipherList.count(); i++) { 00175 CipherNode *j = 0L; 00176 while ((j = cipherList.at(i)) != 0L) { 00177 if (j->name.contains("ADH-") || j->name.contains("NULL-") || j->name.contains("DES-CBC3-SHA") || j->name.contains("FZA")) { 00178 cipherList.remove(j); 00179 } else { 00180 break; 00181 } 00182 } 00183 } 00184 00185 // now assemble the list cipher1:cipher2:cipher3:...:ciphern 00186 while (!cipherList.isEmpty()) { 00187 if (firstcipher) 00188 firstcipher = false; 00189 else clist.append(":"); 00190 clist.append(cipherList.getLast()->name); 00191 cipherList.removeLast(); 00192 } // while 00193 00194 kdDebug(7029) << "Cipher list is: " << clist << endl; 00195 00196 #endif 00197 return clist; 00198 } 00199 00200 // FIXME - sync these up so that we can use them with the control module!! 00201 void KSSLSettings::load() { 00202 m_cfg->reparseConfiguration(); 00203 00204 m_cfg->setGroup("TLS"); 00205 m_bUseTLSv1 = m_cfg->readBoolEntry("Enabled", true); 00206 00207 #if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_NO_SSL2) 00208 m_bUseSSLv2 = false; 00209 #else 00210 m_cfg->setGroup("SSLv2"); 00211 m_bUseSSLv2 = m_cfg->readBoolEntry("Enabled", false); 00212 #endif 00213 00214 #if defined(OPENSSL_NO_SSL3) 00215 m_bUseSSLv3 = false; 00216 #else 00217 m_cfg->setGroup("SSLv3"); 00218 m_bUseSSLv3 = m_cfg->readBoolEntry("Enabled", true); 00219 #endif 00220 00221 m_cfg->setGroup("Warnings"); 00222 m_bWarnOnEnter = m_cfg->readBoolEntry("OnEnter", false); 00223 m_bWarnOnLeave = m_cfg->readBoolEntry("OnLeave", true); 00224 m_bWarnOnUnencrypted = m_cfg->readBoolEntry("OnUnencrypted", true); 00225 m_bWarnOnMixed = m_cfg->readBoolEntry("OnMixed", true); 00226 00227 m_cfg->setGroup("Validation"); 00228 m_bWarnSelfSigned = m_cfg->readBoolEntry("WarnSelfSigned", true); 00229 m_bWarnExpired = m_cfg->readBoolEntry("WarnExpired", true); 00230 m_bWarnRevoked = m_cfg->readBoolEntry("WarnRevoked", true); 00231 00232 m_cfg->setGroup("EGD"); 00233 d->m_bUseEGD = m_cfg->readBoolEntry("UseEGD", false); 00234 d->m_bUseEFile = m_cfg->readBoolEntry("UseEFile", false); 00235 d->m_EGDPath = m_cfg->readPathEntry("EGDPath"); 00236 00237 m_cfg->setGroup("Auth"); 00238 d->m_bSendX509 = ("send" == m_cfg->readEntry("AuthMethod", "")); 00239 d->m_bPromptX509 = ("prompt" == m_cfg->readEntry("AuthMethod", "")); 00240 00241 #ifdef KSSL_HAVE_SSL 00242 00243 00244 00245 #endif 00246 } 00247 00248 00249 void KSSLSettings::defaults() { 00250 m_bUseTLSv1 = true; 00251 m_bUseSSLv2 = false; 00252 m_bUseSSLv3 = true; 00253 m_bWarnOnEnter = false; 00254 m_bWarnOnLeave = true; 00255 m_bWarnOnUnencrypted = true; 00256 m_bWarnOnMixed = true; 00257 m_bWarnSelfSigned = true; 00258 m_bWarnExpired = true; 00259 m_bWarnRevoked = true; 00260 d->m_bUseEGD = false; 00261 d->m_bUseEFile = false; 00262 d->m_EGDPath = ""; 00263 } 00264 00265 00266 void KSSLSettings::save() { 00267 m_cfg->setGroup("TLS"); 00268 m_cfg->writeEntry("Enabled", m_bUseTLSv1); 00269 00270 m_cfg->setGroup("SSLv2"); 00271 m_cfg->writeEntry("Enabled", m_bUseSSLv2); 00272 00273 m_cfg->setGroup("SSLv3"); 00274 m_cfg->writeEntry("Enabled", m_bUseSSLv3); 00275 00276 m_cfg->setGroup("Warnings"); 00277 m_cfg->writeEntry("OnEnter", m_bWarnOnEnter); 00278 m_cfg->writeEntry("OnLeave", m_bWarnOnLeave); 00279 m_cfg->writeEntry("OnUnencrypted", m_bWarnOnUnencrypted); 00280 m_cfg->writeEntry("OnMixed", m_bWarnOnMixed); 00281 00282 m_cfg->setGroup("Validation"); 00283 m_cfg->writeEntry("WarnSelfSigned", m_bWarnSelfSigned); 00284 m_cfg->writeEntry("WarnExpired", m_bWarnExpired); 00285 m_cfg->writeEntry("WarnRevoked", m_bWarnRevoked); 00286 00287 m_cfg->setGroup("EGD"); 00288 m_cfg->writeEntry("UseEGD", d->m_bUseEGD); 00289 m_cfg->writeEntry("UseEFile", d->m_bUseEFile); 00290 m_cfg->writePathEntry("EGDPath", d->m_EGDPath); 00291 00292 m_cfg->sync(); 00293 // FIXME - ciphers 00294 #if 0 00295 #ifdef KSSL_HAVE_SSL 00296 m_cfg->setGroup("SSLv2"); 00297 for (unsigned int i = 0; i < v2ciphers.count(); i++) { 00298 TQString ciphername; 00299 ciphername.sprintf("cipher_%s", v2ciphers[i].ascii()); 00300 if (v2selectedciphers.contains(v2ciphers[i])) { 00301 m_cfg->writeEntry(ciphername, true); 00302 } else m_cfg->writeEntry(ciphername, false); 00303 } 00304 00305 m_cfg->setGroup("SSLv3"); 00306 for (unsigned int i = 0; i < v3ciphers.count(); i++) { 00307 TQString ciphername; 00308 ciphername.sprintf("cipher_%s", v3ciphers[i].ascii()); 00309 if (v3selectedciphers.contains(v3ciphers[i])) { 00310 m_cfg->writeEntry(ciphername, true); 00311 } else m_cfg->writeEntry(ciphername, false); 00312 } 00313 #endif 00314 00315 m_cfg->sync(); 00316 00317 // insure proper permissions -- contains sensitive data 00318 TQString cfgName(KGlobal::dirs()->findResource("config", "cryptodefaults")); 00319 if (!cfgName.isEmpty()) 00320 ::chmod(TQFile::encodeName(cfgName), 0600); 00321 #endif 00322 } 00323 00324 00325 bool KSSLSettings::warnOnEnter() const { return m_bWarnOnEnter; } 00326 void KSSLSettings::setWarnOnEnter(bool x) { m_bWarnOnEnter = x; } 00327 bool KSSLSettings::warnOnUnencrypted() const { return m_bWarnOnUnencrypted; } 00328 void KSSLSettings::setWarnOnUnencrypted(bool x) { m_bWarnOnUnencrypted = x; } 00329 bool KSSLSettings::warnOnLeave() const { return m_bWarnOnLeave; } 00330 void KSSLSettings::setWarnOnLeave(bool x) { m_bWarnOnLeave = x; } 00331 bool KSSLSettings::warnOnMixed() const { return m_bWarnOnMixed; } 00332 bool KSSLSettings::warnOnSelfSigned() const { return m_bWarnSelfSigned; } 00333 bool KSSLSettings::warnOnRevoked() const { return m_bWarnRevoked; } 00334 bool KSSLSettings::warnOnExpired() const { return m_bWarnExpired; } 00335 bool KSSLSettings::useEGD() const { return d->m_bUseEGD; } 00336 bool KSSLSettings::useEFile() const { return d->m_bUseEFile; } 00337 bool KSSLSettings::autoSendX509() const { return d->m_bSendX509; } 00338 bool KSSLSettings::promptSendX509() const { return d->m_bPromptX509; } 00339 00340 void KSSLSettings::setTLSv1(bool enabled) { m_bUseTLSv1 = enabled; } 00341 void KSSLSettings::setSSLv2(bool enabled) { m_bUseSSLv2 = enabled; } 00342 void KSSLSettings::setSSLv3(bool enabled) { m_bUseSSLv3 = enabled; } 00343 00344 TQString& KSSLSettings::getEGDPath() { return d->m_EGDPath; } 00345