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 <qfile.h> 00033 #include <qsortedlist.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 #ifdef KSSL_HAVE_SSL 00050 #define sk_new d->kossl->sk_new 00051 #define sk_push d->kossl->sk_push 00052 #define sk_free d->kossl->sk_free 00053 #define sk_value d->kossl->sk_value 00054 #define sk_num d->kossl->sk_num 00055 #define sk_dup d->kossl->sk_dup 00056 #define sk_pop d->kossl->sk_pop 00057 #endif 00058 00059 class CipherNode { 00060 public: 00061 CipherNode(const char *_name, int _keylen) : 00062 name(_name), keylen(_keylen) {} 00063 QString name; 00064 int keylen; 00065 inline int operator==(CipherNode &x) 00066 { return ((x.keylen == keylen) && (x.name == name)); } 00067 inline int operator< (CipherNode &x) { return keylen < x.keylen; } 00068 inline int operator<=(CipherNode &x) { return keylen <= x.keylen; } 00069 inline int operator> (CipherNode &x) { return keylen > x.keylen; } 00070 inline int operator>=(CipherNode &x) { return keylen >= x.keylen; } 00071 }; 00072 00073 00074 class KSSLSettingsPrivate { 00075 public: 00076 KSSLSettingsPrivate() { 00077 kossl = NULL; // try to delay this as long as possible 00078 } 00079 ~KSSLSettingsPrivate() { 00080 00081 } 00082 00083 KOSSL *kossl; 00084 bool m_bUseEGD; 00085 bool m_bUseEFile; 00086 QString m_EGDPath; 00087 bool m_bSendX509; 00088 bool m_bPromptX509; 00089 }; 00090 00091 // 00092 // FIXME 00093 // Implementation note: for now, we only read cipher settings from disk, 00094 // and do not store them in memory. This should change. 00095 // 00096 00097 KSSLSettings::KSSLSettings(bool readConfig) { 00098 d = new KSSLSettingsPrivate; 00099 m_cfg = new KConfig("cryptodefaults", false, false); 00100 00101 if (!KGlobal::dirs()->addResourceType("kssl", KStandardDirs::kde_default("data") + "kssl")) { 00102 //kdDebug(7029) << "Error adding (kssl, share/apps/kssl)" << endl; 00103 } 00104 00105 if (readConfig) load(); 00106 } 00107 00108 00109 // we don't save settings incase it was a temporary object 00110 KSSLSettings::~KSSLSettings() { 00111 delete m_cfg; 00112 delete d; 00113 } 00114 00115 00116 bool KSSLSettings::sslv2() const { 00117 return m_bUseSSLv2; 00118 } 00119 00120 00121 bool KSSLSettings::sslv3() const { 00122 return m_bUseSSLv3; 00123 } 00124 00125 00126 bool KSSLSettings::tlsv1() const { 00127 return m_bUseTLSv1; 00128 } 00129 00130 00131 // FIXME: we should make a default list available if this fails 00132 // since OpenSSL seems to just choose any old thing if it's given an 00133 // empty list. This behavior is not confirmed though. 00134 QString KSSLSettings::getCipherList() { 00135 QString clist; 00136 #ifdef KSSL_HAVE_SSL 00137 QString tcipher; 00138 bool firstcipher = true; 00139 SSL_METHOD *meth = 0L; 00140 QPtrList<CipherNode> cipherList; 00141 00142 cipherList.setAutoDelete(true); 00143 00144 if (!d->kossl) 00145 d->kossl = KOSSL::self(); 00146 00147 if (m_bUseSSLv3 && m_bUseSSLv2) 00148 meth = d->kossl->SSLv23_client_method(); 00149 else if(m_bUseSSLv3) 00150 meth = d->kossl->SSLv3_client_method(); 00151 else if (m_bUseSSLv2) 00152 meth = d->kossl->SSLv2_client_method(); 00153 00154 SSL_CTX *ctx = d->kossl->SSL_CTX_new(meth); 00155 SSL* ssl = d->kossl->SSL_new(ctx); 00156 STACK_OF(SSL_CIPHER)* sk = d->kossl->SSL_get_ciphers(ssl); 00157 int cnt = sk_SSL_CIPHER_num(sk); 00158 for (int i=0; i< cnt; i++) { 00159 SSL_CIPHER *sc = sk_SSL_CIPHER_value(sk,i); 00160 if (!sc) 00161 break; 00162 00163 if(!strcmp("SSLv2", d->kossl->SSL_CIPHER_get_version(sc))) 00164 m_cfg->setGroup("SSLv2"); 00165 else 00166 m_cfg->setGroup("SSLv3"); 00167 00168 tcipher.sprintf("cipher_%s", sc->name); 00169 int bits = d->kossl->SSL_CIPHER_get_bits(sc, NULL); 00170 if (m_cfg->readBoolEntry(tcipher, bits >= 56)) { 00171 CipherNode *xx = new CipherNode(sc->name,bits); 00172 if (!cipherList.contains(xx)) 00173 cipherList.prepend(xx); 00174 else 00175 delete xx; 00176 } 00177 } 00178 d->kossl->SSL_free(ssl); 00179 d->kossl->SSL_CTX_free(ctx); 00180 00181 // Remove any ADH ciphers as per RFC2246 00182 // Also remove NULL ciphers and 168bit ciphers 00183 for (unsigned int i = 0; i < cipherList.count(); i++) { 00184 CipherNode *j = 0L; 00185 while ((j = cipherList.at(i)) != 0L) { 00186 if (j->name.contains("ADH-") || j->name.contains("NULL-") || j->name.contains("DES-CBC3-SHA") || j->name.contains("FZA")) { 00187 cipherList.remove(j); 00188 } else { 00189 break; 00190 } 00191 } 00192 } 00193 00194 // now assemble the list cipher1:cipher2:cipher3:...:ciphern 00195 while (!cipherList.isEmpty()) { 00196 if (firstcipher) 00197 firstcipher = false; 00198 else clist.append(":"); 00199 clist.append(cipherList.getLast()->name); 00200 cipherList.removeLast(); 00201 } // while 00202 00203 kdDebug(7029) << "Cipher list is: " << clist << endl; 00204 00205 #endif 00206 return clist; 00207 } 00208 00209 // FIXME - sync these up so that we can use them with the control module!! 00210 void KSSLSettings::load() { 00211 m_cfg->reparseConfiguration(); 00212 00213 m_cfg->setGroup("TLS"); 00214 m_bUseTLSv1 = m_cfg->readBoolEntry("Enabled", true); 00215 00216 m_cfg->setGroup("SSLv2"); 00217 m_bUseSSLv2 = m_cfg->readBoolEntry("Enabled", false); 00218 00219 m_cfg->setGroup("SSLv3"); 00220 m_bUseSSLv3 = m_cfg->readBoolEntry("Enabled", true); 00221 00222 m_cfg->setGroup("Warnings"); 00223 m_bWarnOnEnter = m_cfg->readBoolEntry("OnEnter", false); 00224 m_bWarnOnLeave = m_cfg->readBoolEntry("OnLeave", true); 00225 m_bWarnOnUnencrypted = m_cfg->readBoolEntry("OnUnencrypted", true); 00226 m_bWarnOnMixed = m_cfg->readBoolEntry("OnMixed", true); 00227 00228 m_cfg->setGroup("Validation"); 00229 m_bWarnSelfSigned = m_cfg->readBoolEntry("WarnSelfSigned", true); 00230 m_bWarnExpired = m_cfg->readBoolEntry("WarnExpired", true); 00231 m_bWarnRevoked = m_cfg->readBoolEntry("WarnRevoked", true); 00232 00233 m_cfg->setGroup("EGD"); 00234 d->m_bUseEGD = m_cfg->readBoolEntry("UseEGD", false); 00235 d->m_bUseEFile = m_cfg->readBoolEntry("UseEFile", false); 00236 d->m_EGDPath = m_cfg->readPathEntry("EGDPath"); 00237 00238 m_cfg->setGroup("Auth"); 00239 d->m_bSendX509 = ("send" == m_cfg->readEntry("AuthMethod", "")); 00240 d->m_bPromptX509 = ("prompt" == m_cfg->readEntry("AuthMethod", "")); 00241 00242 #ifdef KSSL_HAVE_SSL 00243 00244 00245 00246 #endif 00247 } 00248 00249 00250 void KSSLSettings::defaults() { 00251 m_bUseTLSv1 = true; 00252 m_bUseSSLv2 = false; 00253 m_bUseSSLv3 = true; 00254 m_bWarnOnEnter = false; 00255 m_bWarnOnLeave = true; 00256 m_bWarnOnUnencrypted = true; 00257 m_bWarnOnMixed = true; 00258 m_bWarnSelfSigned = true; 00259 m_bWarnExpired = true; 00260 m_bWarnRevoked = true; 00261 d->m_bUseEGD = false; 00262 d->m_bUseEFile = false; 00263 d->m_EGDPath = ""; 00264 } 00265 00266 00267 void KSSLSettings::save() { 00268 m_cfg->setGroup("TLS"); 00269 m_cfg->writeEntry("Enabled", m_bUseTLSv1); 00270 00271 m_cfg->setGroup("SSLv2"); 00272 m_cfg->writeEntry("Enabled", m_bUseSSLv2); 00273 00274 m_cfg->setGroup("SSLv3"); 00275 m_cfg->writeEntry("Enabled", m_bUseSSLv3); 00276 00277 m_cfg->setGroup("Warnings"); 00278 m_cfg->writeEntry("OnEnter", m_bWarnOnEnter); 00279 m_cfg->writeEntry("OnLeave", m_bWarnOnLeave); 00280 m_cfg->writeEntry("OnUnencrypted", m_bWarnOnUnencrypted); 00281 m_cfg->writeEntry("OnMixed", m_bWarnOnMixed); 00282 00283 m_cfg->setGroup("Validation"); 00284 m_cfg->writeEntry("WarnSelfSigned", m_bWarnSelfSigned); 00285 m_cfg->writeEntry("WarnExpired", m_bWarnExpired); 00286 m_cfg->writeEntry("WarnRevoked", m_bWarnRevoked); 00287 00288 m_cfg->setGroup("EGD"); 00289 m_cfg->writeEntry("UseEGD", d->m_bUseEGD); 00290 m_cfg->writeEntry("UseEFile", d->m_bUseEFile); 00291 m_cfg->writePathEntry("EGDPath", d->m_EGDPath); 00292 00293 m_cfg->sync(); 00294 // FIXME - ciphers 00295 #if 0 00296 #ifdef KSSL_HAVE_SSL 00297 m_cfg->setGroup("SSLv2"); 00298 for (unsigned int i = 0; i < v2ciphers.count(); i++) { 00299 QString ciphername; 00300 ciphername.sprintf("cipher_%s", v2ciphers[i].ascii()); 00301 if (v2selectedciphers.contains(v2ciphers[i])) { 00302 m_cfg->writeEntry(ciphername, true); 00303 } else m_cfg->writeEntry(ciphername, false); 00304 } 00305 00306 m_cfg->setGroup("SSLv3"); 00307 for (unsigned int i = 0; i < v3ciphers.count(); i++) { 00308 QString ciphername; 00309 ciphername.sprintf("cipher_%s", v3ciphers[i].ascii()); 00310 if (v3selectedciphers.contains(v3ciphers[i])) { 00311 m_cfg->writeEntry(ciphername, true); 00312 } else m_cfg->writeEntry(ciphername, false); 00313 } 00314 #endif 00315 00316 m_cfg->sync(); 00317 00318 // insure proper permissions -- contains sensitive data 00319 QString cfgName(KGlobal::dirs()->findResource("config", "cryptodefaults")); 00320 if (!cfgName.isEmpty()) 00321 ::chmod(QFile::encodeName(cfgName), 0600); 00322 #endif 00323 } 00324 00325 00326 bool KSSLSettings::warnOnEnter() const { return m_bWarnOnEnter; } 00327 void KSSLSettings::setWarnOnEnter(bool x) { m_bWarnOnEnter = x; } 00328 bool KSSLSettings::warnOnUnencrypted() const { return m_bWarnOnUnencrypted; } 00329 void KSSLSettings::setWarnOnUnencrypted(bool x) { m_bWarnOnUnencrypted = x; } 00330 bool KSSLSettings::warnOnLeave() const { return m_bWarnOnLeave; } 00331 void KSSLSettings::setWarnOnLeave(bool x) { m_bWarnOnLeave = x; } 00332 bool KSSLSettings::warnOnMixed() const { return m_bWarnOnMixed; } 00333 bool KSSLSettings::warnOnSelfSigned() const { return m_bWarnSelfSigned; } 00334 bool KSSLSettings::warnOnRevoked() const { return m_bWarnRevoked; } 00335 bool KSSLSettings::warnOnExpired() const { return m_bWarnExpired; } 00336 bool KSSLSettings::useEGD() const { return d->m_bUseEGD; } 00337 bool KSSLSettings::useEFile() const { return d->m_bUseEFile; } 00338 bool KSSLSettings::autoSendX509() const { return d->m_bSendX509; } 00339 bool KSSLSettings::promptSendX509() const { return d->m_bPromptX509; } 00340 00341 void KSSLSettings::setTLSv1(bool enabled) { m_bUseTLSv1 = enabled; } 00342 void KSSLSettings::setSSLv2(bool enabled) { m_bUseSSLv2 = enabled; } 00343 void KSSLSettings::setSSLv3(bool enabled) { m_bUseSSLv3 = enabled; } 00344 00345 QString& KSSLSettings::getEGDPath() { return d->m_EGDPath; } 00346 00347 #ifdef KSSL_HAVE_SSL 00348 #undef sk_new 00349 #undef sk_push 00350 #undef sk_free 00351 #undef sk_value 00352 #undef sk_num 00353 #undef sk_pop 00354 #undef sk_dup 00355 #endif 00356