1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "net/socket/nss_ssl_util.h" 6 7 #include <nss.h> 8 #include <secerr.h> 9 #include <ssl.h> 10 #include <sslerr.h> 11 12 #include <string> 13 14 #include "base/lazy_instance.h" 15 #include "base/logging.h" 16 #include "base/memory/singleton.h" 17 #include "base/threading/thread_restrictions.h" 18 #include "base/values.h" 19 #include "crypto/nss_util.h" 20 #include "net/base/net_errors.h" 21 #include "net/base/net_log.h" 22 23 namespace net { 24 25 class NSSSSLInitSingleton { 26 public: 27 NSSSSLInitSingleton() { 28 crypto::EnsureNSSInit(); 29 30 NSS_SetDomesticPolicy(); 31 32 #if defined(USE_SYSTEM_SSL) 33 // Use late binding to avoid scary but benign warning 34 // "Symbol `SSL_ImplementedCiphers' has different size in shared object, 35 // consider re-linking" 36 // TODO(wtc): Use the new SSL_GetImplementedCiphers and 37 // SSL_GetNumImplementedCiphers functions when we require NSS 3.12.6. 38 // See https://bugzilla.mozilla.org/show_bug.cgi?id=496993. 39 const PRUint16* pSSL_ImplementedCiphers = static_cast<const PRUint16*>( 40 dlsym(RTLD_DEFAULT, "SSL_ImplementedCiphers")); 41 if (pSSL_ImplementedCiphers == NULL) { 42 NOTREACHED() << "Can't get list of supported ciphers"; 43 return; 44 } 45 #else 46 #define pSSL_ImplementedCiphers SSL_ImplementedCiphers 47 #endif 48 49 // Explicitly enable exactly those ciphers with keys of at least 80 bits 50 for (int i = 0; i < SSL_NumImplementedCiphers; i++) { 51 SSLCipherSuiteInfo info; 52 if (SSL_GetCipherSuiteInfo(pSSL_ImplementedCiphers[i], &info, 53 sizeof(info)) == SECSuccess) { 54 SSL_CipherPrefSetDefault(pSSL_ImplementedCiphers[i], 55 (info.effectiveKeyBits >= 80)); 56 } 57 } 58 59 // Enable SSL. 60 SSL_OptionSetDefault(SSL_SECURITY, PR_TRUE); 61 62 // All other SSL options are set per-session by SSLClientSocket and 63 // SSLServerSocket. 64 } 65 66 ~NSSSSLInitSingleton() { 67 // Have to clear the cache, or NSS_Shutdown fails with SEC_ERROR_BUSY. 68 SSL_ClearSessionCache(); 69 } 70 }; 71 72 static base::LazyInstance<NSSSSLInitSingleton> g_nss_ssl_init_singleton( 73 base::LINKER_INITIALIZED); 74 75 // Initialize the NSS SSL library if it isn't already initialized. This must 76 // be called before any other NSS SSL functions. This function is 77 // thread-safe, and the NSS SSL library will only ever be initialized once. 78 // The NSS SSL library will be properly shut down on program exit. 79 void EnsureNSSSSLInit() { 80 // Initializing SSL causes us to do blocking IO. 81 // Temporarily allow it until we fix 82 // http://code.google.com/p/chromium/issues/detail?id=59847 83 base::ThreadRestrictions::ScopedAllowIO allow_io; 84 85 g_nss_ssl_init_singleton.Get(); 86 } 87 88 // Map a Chromium net error code to an NSS error code. 89 // See _MD_unix_map_default_error in the NSS source 90 // tree for inspiration. 91 PRErrorCode MapErrorToNSS(int result) { 92 if (result >=0) 93 return result; 94 95 switch (result) { 96 case ERR_IO_PENDING: 97 return PR_WOULD_BLOCK_ERROR; 98 case ERR_ACCESS_DENIED: 99 case ERR_NETWORK_ACCESS_DENIED: 100 // For connect, this could be mapped to PR_ADDRESS_NOT_SUPPORTED_ERROR. 101 return PR_NO_ACCESS_RIGHTS_ERROR; 102 case ERR_NOT_IMPLEMENTED: 103 return PR_NOT_IMPLEMENTED_ERROR; 104 case ERR_INTERNET_DISCONNECTED: // Equivalent to ENETDOWN. 105 return PR_NETWORK_UNREACHABLE_ERROR; // Best approximation. 106 case ERR_CONNECTION_TIMED_OUT: 107 case ERR_TIMED_OUT: 108 return PR_IO_TIMEOUT_ERROR; 109 case ERR_CONNECTION_RESET: 110 return PR_CONNECT_RESET_ERROR; 111 case ERR_CONNECTION_ABORTED: 112 return PR_CONNECT_ABORTED_ERROR; 113 case ERR_CONNECTION_REFUSED: 114 return PR_CONNECT_REFUSED_ERROR; 115 case ERR_ADDRESS_UNREACHABLE: 116 return PR_HOST_UNREACHABLE_ERROR; // Also PR_NETWORK_UNREACHABLE_ERROR. 117 case ERR_ADDRESS_INVALID: 118 return PR_ADDRESS_NOT_AVAILABLE_ERROR; 119 case ERR_NAME_NOT_RESOLVED: 120 return PR_DIRECTORY_LOOKUP_ERROR; 121 default: 122 LOG(WARNING) << "MapErrorToNSS " << result 123 << " mapped to PR_UNKNOWN_ERROR"; 124 return PR_UNKNOWN_ERROR; 125 } 126 } 127 128 // The default error mapping function. 129 // Maps an NSS error code to a network error code. 130 int MapNSSError(PRErrorCode err) { 131 // TODO(port): fill this out as we learn what's important 132 switch (err) { 133 case PR_WOULD_BLOCK_ERROR: 134 return ERR_IO_PENDING; 135 case PR_ADDRESS_NOT_SUPPORTED_ERROR: // For connect. 136 case PR_NO_ACCESS_RIGHTS_ERROR: 137 return ERR_ACCESS_DENIED; 138 case PR_IO_TIMEOUT_ERROR: 139 return ERR_TIMED_OUT; 140 case PR_CONNECT_RESET_ERROR: 141 return ERR_CONNECTION_RESET; 142 case PR_CONNECT_ABORTED_ERROR: 143 return ERR_CONNECTION_ABORTED; 144 case PR_CONNECT_REFUSED_ERROR: 145 return ERR_CONNECTION_REFUSED; 146 case PR_HOST_UNREACHABLE_ERROR: 147 case PR_NETWORK_UNREACHABLE_ERROR: 148 return ERR_ADDRESS_UNREACHABLE; 149 case PR_ADDRESS_NOT_AVAILABLE_ERROR: 150 return ERR_ADDRESS_INVALID; 151 case PR_INVALID_ARGUMENT_ERROR: 152 return ERR_INVALID_ARGUMENT; 153 case PR_END_OF_FILE_ERROR: 154 return ERR_CONNECTION_CLOSED; 155 case PR_NOT_IMPLEMENTED_ERROR: 156 return ERR_NOT_IMPLEMENTED; 157 158 case SEC_ERROR_INVALID_ARGS: 159 return ERR_INVALID_ARGUMENT; 160 case SEC_ERROR_NO_KEY: 161 return ERR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY; 162 case SEC_ERROR_INVALID_KEY: 163 case SSL_ERROR_SIGN_HASHES_FAILURE: 164 return ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED; 165 // A handshake (initial or renegotiation) may fail because some signature 166 // (for example, the signature in the ServerKeyExchange message for an 167 // ephemeral Diffie-Hellman cipher suite) is invalid. 168 case SEC_ERROR_BAD_SIGNATURE: 169 return ERR_SSL_PROTOCOL_ERROR; 170 171 case SSL_ERROR_SSL_DISABLED: 172 return ERR_NO_SSL_VERSIONS_ENABLED; 173 case SSL_ERROR_NO_CYPHER_OVERLAP: 174 case SSL_ERROR_UNSUPPORTED_VERSION: 175 return ERR_SSL_VERSION_OR_CIPHER_MISMATCH; 176 case SSL_ERROR_HANDSHAKE_FAILURE_ALERT: 177 case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT: 178 case SSL_ERROR_ILLEGAL_PARAMETER_ALERT: 179 return ERR_SSL_PROTOCOL_ERROR; 180 case SSL_ERROR_DECOMPRESSION_FAILURE_ALERT: 181 return ERR_SSL_DECOMPRESSION_FAILURE_ALERT; 182 case SSL_ERROR_BAD_MAC_ALERT: 183 return ERR_SSL_BAD_RECORD_MAC_ALERT; 184 case SSL_ERROR_UNSAFE_NEGOTIATION: 185 return ERR_SSL_UNSAFE_NEGOTIATION; 186 case SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY: 187 return ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY; 188 189 default: { 190 if (IS_SSL_ERROR(err)) { 191 LOG(WARNING) << "Unknown SSL error " << err 192 << " mapped to net::ERR_SSL_PROTOCOL_ERROR"; 193 return ERR_SSL_PROTOCOL_ERROR; 194 } 195 LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED"; 196 return ERR_FAILED; 197 } 198 } 199 } 200 201 // Context-sensitive error mapping functions. 202 int MapNSSHandshakeError(PRErrorCode err) { 203 switch (err) { 204 // If the server closed on us, it is a protocol error. 205 // Some TLS-intolerant servers do this when we request TLS. 206 case PR_END_OF_FILE_ERROR: 207 return ERR_SSL_PROTOCOL_ERROR; 208 default: 209 return MapNSSError(err); 210 } 211 } 212 213 // Extra parameters to attach to the NetLog when we receive an error in response 214 // to a call to an NSS function. Used instead of SSLErrorParams with 215 // events of type TYPE_SSL_NSS_ERROR. Automatically looks up last PR error. 216 class SSLFailedNSSFunctionParams : public NetLog::EventParameters { 217 public: 218 // |param| is ignored if it has a length of 0. 219 SSLFailedNSSFunctionParams(const std::string& function, 220 const std::string& param) 221 : function_(function), param_(param), ssl_lib_error_(PR_GetError()) { 222 } 223 224 virtual Value* ToValue() const { 225 DictionaryValue* dict = new DictionaryValue(); 226 dict->SetString("function", function_); 227 if (!param_.empty()) 228 dict->SetString("param", param_); 229 dict->SetInteger("ssl_lib_error", ssl_lib_error_); 230 return dict; 231 } 232 233 private: 234 const std::string function_; 235 const std::string param_; 236 const PRErrorCode ssl_lib_error_; 237 }; 238 239 void LogFailedNSSFunction(const BoundNetLog& net_log, 240 const char* function, 241 const char* param) { 242 net_log.AddEvent( 243 NetLog::TYPE_SSL_NSS_ERROR, 244 make_scoped_refptr(new SSLFailedNSSFunctionParams(function, param))); 245 } 246 247 } // namespace net 248