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