• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
NSSSSLInitSingleton()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 
~NSSSSLInitSingleton()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.
EnsureNSSSSLInit()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.
MapErrorToNSS(int result)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.
MapNSSError(PRErrorCode err)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.
MapNSSHandshakeError(PRErrorCode err)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.
SSLFailedNSSFunctionParams(const std::string & function,const std::string & param)219   SSLFailedNSSFunctionParams(const std::string& function,
220                              const std::string& param)
221       : function_(function), param_(param), ssl_lib_error_(PR_GetError()) {
222   }
223 
ToValue() const224   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 
LogFailedNSSFunction(const BoundNetLog & net_log,const char * function,const char * param)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