Index: net/socket/nss_ssl_util.cc |
diff --git a/net/socket/nss_ssl_util.cc b/net/socket/nss_ssl_util.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..80268d987d486e856296582478c30e4f3a4658da |
--- /dev/null |
+++ b/net/socket/nss_ssl_util.cc |
@@ -0,0 +1,240 @@ |
+// Copyright (c) 2010 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "net/socket/nss_ssl_util.h" |
+ |
+#include <nss.h> |
+#include <secerr.h> |
+#include <ssl.h> |
+#include <sslerr.h> |
+ |
+#include "base/lazy_instance.h" |
+#include "base/logging.h" |
+#include "base/nss_util.h" |
+#include "base/singleton.h" |
+#include "base/thread_restrictions.h" |
+#include "base/values.h" |
+#include "net/base/net_errors.h" |
+#include "net/base/net_log.h" |
+ |
+namespace net { |
+ |
+class NSSSSLInitSingleton { |
+ public: |
+ NSSSSLInitSingleton() { |
+ base::EnsureNSSInit(); |
+ |
+ NSS_SetDomesticPolicy(); |
+ |
+#if defined(USE_SYSTEM_SSL) |
+ // Use late binding to avoid scary but benign warning |
+ // "Symbol `SSL_ImplementedCiphers' has different size in shared object, |
+ // consider re-linking" |
+ // TODO(wtc): Use the new SSL_GetImplementedCiphers and |
+ // SSL_GetNumImplementedCiphers functions when we require NSS 3.12.6. |
+ // See https://bugzilla.mozilla.org/show_bug.cgi?id=496993. |
+ const PRUint16* pSSL_ImplementedCiphers = static_cast<const PRUint16*>( |
+ dlsym(RTLD_DEFAULT, "SSL_ImplementedCiphers")); |
+ if (pSSL_ImplementedCiphers == NULL) { |
+ NOTREACHED() << "Can't get list of supported ciphers"; |
+ return; |
+ } |
+#else |
+#define pSSL_ImplementedCiphers SSL_ImplementedCiphers |
+#endif |
+ |
+ // Explicitly enable exactly those ciphers with keys of at least 80 bits |
+ for (int i = 0; i < SSL_NumImplementedCiphers; i++) { |
+ SSLCipherSuiteInfo info; |
+ if (SSL_GetCipherSuiteInfo(pSSL_ImplementedCiphers[i], &info, |
+ sizeof(info)) == SECSuccess) { |
+ SSL_CipherPrefSetDefault(pSSL_ImplementedCiphers[i], |
+ (info.effectiveKeyBits >= 80)); |
+ } |
+ } |
+ |
+ // Enable SSL. |
+ SSL_OptionSetDefault(SSL_SECURITY, PR_TRUE); |
+ |
+ // All other SSL options are set per-session by SSLClientSocket and |
+ // SSLServerSocket. |
+ } |
+ |
+ ~NSSSSLInitSingleton() { |
+ // Have to clear the cache, or NSS_Shutdown fails with SEC_ERROR_BUSY. |
+ SSL_ClearSessionCache(); |
+ } |
+}; |
+ |
+static base::LazyInstance<NSSSSLInitSingleton> g_nss_ssl_init_singleton( |
+ base::LINKER_INITIALIZED); |
+ |
+// Initialize the NSS SSL library if it isn't already initialized. This must |
+// be called before any other NSS SSL functions. This function is |
+// thread-safe, and the NSS SSL library will only ever be initialized once. |
+// The NSS SSL library will be properly shut down on program exit. |
+void EnsureNSSSSLInit() { |
+ // Initializing SSL causes us to do blocking IO. |
+ // Temporarily allow it until we fix |
+ // http://code.google.com/p/chromium/issues/detail?id=59847 |
+ base::ThreadRestrictions::ScopedAllowIO allow_io; |
+ |
+ g_nss_ssl_init_singleton.Get(); |
+} |
+ |
+// Map a Chromium net error code to an NSS error code. |
+// See _MD_unix_map_default_error in the NSS source |
+// tree for inspiration. |
+PRErrorCode MapErrorToNSS(int result) { |
+ if (result >=0) |
+ return result; |
+ |
+ switch (result) { |
+ case ERR_IO_PENDING: |
+ return PR_WOULD_BLOCK_ERROR; |
+ case ERR_ACCESS_DENIED: |
+ case ERR_NETWORK_ACCESS_DENIED: |
+ // For connect, this could be mapped to PR_ADDRESS_NOT_SUPPORTED_ERROR. |
+ return PR_NO_ACCESS_RIGHTS_ERROR; |
+ case ERR_NOT_IMPLEMENTED: |
+ return PR_NOT_IMPLEMENTED_ERROR; |
+ case ERR_INTERNET_DISCONNECTED: // Equivalent to ENETDOWN. |
+ return PR_NETWORK_UNREACHABLE_ERROR; // Best approximation. |
+ case ERR_CONNECTION_TIMED_OUT: |
+ case ERR_TIMED_OUT: |
+ return PR_IO_TIMEOUT_ERROR; |
+ case ERR_CONNECTION_RESET: |
+ return PR_CONNECT_RESET_ERROR; |
+ case ERR_CONNECTION_ABORTED: |
+ return PR_CONNECT_ABORTED_ERROR; |
+ case ERR_CONNECTION_REFUSED: |
+ return PR_CONNECT_REFUSED_ERROR; |
+ case ERR_ADDRESS_UNREACHABLE: |
+ return PR_HOST_UNREACHABLE_ERROR; // Also PR_NETWORK_UNREACHABLE_ERROR. |
+ case ERR_ADDRESS_INVALID: |
+ return PR_ADDRESS_NOT_AVAILABLE_ERROR; |
+ case ERR_NAME_NOT_RESOLVED: |
+ return PR_DIRECTORY_LOOKUP_ERROR; |
+ default: |
+ LOG(WARNING) << "MapErrorToNSS " << result |
+ << " mapped to PR_UNKNOWN_ERROR"; |
+ return PR_UNKNOWN_ERROR; |
+ } |
+} |
+ |
+// The default error mapping function. |
+// Maps an NSS error code to a network error code. |
+int MapNSSError(PRErrorCode err) { |
+ // TODO(port): fill this out as we learn what's important |
+ switch (err) { |
+ case PR_WOULD_BLOCK_ERROR: |
+ return ERR_IO_PENDING; |
+ case PR_ADDRESS_NOT_SUPPORTED_ERROR: // For connect. |
+ case PR_NO_ACCESS_RIGHTS_ERROR: |
+ return ERR_ACCESS_DENIED; |
+ case PR_IO_TIMEOUT_ERROR: |
+ return ERR_TIMED_OUT; |
+ case PR_CONNECT_RESET_ERROR: |
+ return ERR_CONNECTION_RESET; |
+ case PR_CONNECT_ABORTED_ERROR: |
+ return ERR_CONNECTION_ABORTED; |
+ case PR_CONNECT_REFUSED_ERROR: |
+ return ERR_CONNECTION_REFUSED; |
+ case PR_HOST_UNREACHABLE_ERROR: |
+ case PR_NETWORK_UNREACHABLE_ERROR: |
+ return ERR_ADDRESS_UNREACHABLE; |
+ case PR_ADDRESS_NOT_AVAILABLE_ERROR: |
+ return ERR_ADDRESS_INVALID; |
+ case PR_INVALID_ARGUMENT_ERROR: |
+ return ERR_INVALID_ARGUMENT; |
+ case PR_END_OF_FILE_ERROR: |
+ return ERR_CONNECTION_CLOSED; |
+ case PR_NOT_IMPLEMENTED_ERROR: |
+ return ERR_NOT_IMPLEMENTED; |
+ |
+ case SEC_ERROR_INVALID_ARGS: |
+ return ERR_INVALID_ARGUMENT; |
+ |
+ case SSL_ERROR_SSL_DISABLED: |
+ return ERR_NO_SSL_VERSIONS_ENABLED; |
+ case SSL_ERROR_NO_CYPHER_OVERLAP: |
+ case SSL_ERROR_UNSUPPORTED_VERSION: |
+ return ERR_SSL_VERSION_OR_CIPHER_MISMATCH; |
+ case SSL_ERROR_HANDSHAKE_FAILURE_ALERT: |
+ case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT: |
+ case SSL_ERROR_ILLEGAL_PARAMETER_ALERT: |
+ return ERR_SSL_PROTOCOL_ERROR; |
+ case SSL_ERROR_DECOMPRESSION_FAILURE_ALERT: |
+ return ERR_SSL_DECOMPRESSION_FAILURE_ALERT; |
+ case SSL_ERROR_BAD_MAC_ALERT: |
+ return ERR_SSL_BAD_RECORD_MAC_ALERT; |
+ case SSL_ERROR_UNSAFE_NEGOTIATION: |
+ return ERR_SSL_UNSAFE_NEGOTIATION; |
+ case SSL_ERROR_WEAK_SERVER_KEY: |
+ return ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY; |
+ |
+ default: { |
+ if (IS_SSL_ERROR(err)) { |
+ LOG(WARNING) << "Unknown SSL error " << err << |
+ " mapped to net::ERR_SSL_PROTOCOL_ERROR"; |
+ return ERR_SSL_PROTOCOL_ERROR; |
+ } |
+ LOG(WARNING) << "Unknown error " << err << |
+ " mapped to net::ERR_FAILED"; |
+ return ERR_FAILED; |
+ } |
+ } |
+} |
+ |
+// Context-sensitive error mapping functions. |
+int MapHandshakeError(PRErrorCode err) { |
+ switch (err) { |
+ // If the server closed on us, it is a protocol error. |
+ // Some TLS-intolerant servers do this when we request TLS. |
+ case PR_END_OF_FILE_ERROR: |
+ // The handshake may fail because some signature (for example, the |
+ // signature in the ServerKeyExchange message for an ephemeral |
+ // Diffie-Hellman cipher suite) is invalid. |
+ case SEC_ERROR_BAD_SIGNATURE: |
+ return ERR_SSL_PROTOCOL_ERROR; |
+ default: |
+ return MapNSSError(err); |
+ } |
+} |
+ |
+// Extra parameters to attach to the NetLog when we receive an error in response |
+// to a call to an NSS function. Used instead of SSLErrorParams with |
+// events of type TYPE_SSL_NSS_ERROR. Automatically looks up last PR error. |
+class SSLFailedNSSFunctionParams : public NetLog::EventParameters { |
+ public: |
+ // |param| is ignored if it has a length of 0. |
+ SSLFailedNSSFunctionParams(const std::string& function, |
+ const std::string& param) |
+ : function_(function), param_(param), ssl_lib_error_(PR_GetError()) { |
+ } |
+ |
+ virtual Value* ToValue() const { |
+ DictionaryValue* dict = new DictionaryValue(); |
+ dict->SetString("function", function_); |
+ if (!param_.empty()) |
+ dict->SetString("param", param_); |
+ dict->SetInteger("ssl_lib_error", ssl_lib_error_); |
+ return dict; |
+ } |
+ |
+ private: |
+ const std::string function_; |
+ const std::string param_; |
+ const PRErrorCode ssl_lib_error_; |
+}; |
+ |
+void LogFailedNSSFunction(const BoundNetLog& net_log, |
+ const char* function, |
+ const char* param) { |
+ net_log.AddEvent( |
+ NetLog::TYPE_SSL_NSS_ERROR, |
+ make_scoped_refptr(new SSLFailedNSSFunctionParams(function, param))); |
+} |
+ |
+} // namespace net |