Home | History | Annotate | Download | only in socket
      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