tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

NSSErrorsService.cpp (9067B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "NSSErrorsService.h"
      6 
      7 #include "nsIStringBundle.h"
      8 #include "nsNSSComponent.h"
      9 #include "nsServiceManagerUtils.h"
     10 #include "mozpkix/pkixnss.h"
     11 #include "secerr.h"
     12 #include "sslerr.h"
     13 
     14 #define PIPNSS_STRBUNDLE_URL "chrome://pipnss/locale/pipnss.properties"
     15 #define NSSERR_STRBUNDLE_URL "chrome://pipnss/locale/nsserrors.properties"
     16 
     17 namespace mozilla {
     18 namespace psm {
     19 
     20 static_assert(mozilla::pkix::ERROR_BASE ==
     21                  nsINSSErrorsService::MOZILLA_PKIX_ERROR_BASE,
     22              "MOZILLA_PKIX_ERROR_BASE and "
     23              "nsINSSErrorsService::MOZILLA_PKIX_ERROR_BASE do not match.");
     24 static_assert(mozilla::pkix::ERROR_LIMIT ==
     25                  nsINSSErrorsService::MOZILLA_PKIX_ERROR_LIMIT,
     26              "MOZILLA_PKIX_ERROR_LIMIT and "
     27              "nsINSSErrorsService::MOZILLA_PKIX_ERROR_LIMIT do not match.");
     28 
     29 static bool IsPSMError(PRErrorCode error) {
     30  return (error >= mozilla::pkix::ERROR_BASE &&
     31          error < mozilla::pkix::ERROR_LIMIT);
     32 }
     33 
     34 NS_IMPL_ISUPPORTS(NSSErrorsService, nsINSSErrorsService)
     35 
     36 NSSErrorsService::~NSSErrorsService() = default;
     37 
     38 nsresult NSSErrorsService::Init() {
     39  nsresult rv;
     40  nsCOMPtr<nsIStringBundleService> bundleService(
     41      do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
     42  if (NS_FAILED(rv) || !bundleService) return NS_ERROR_FAILURE;
     43 
     44  bundleService->CreateBundle(PIPNSS_STRBUNDLE_URL,
     45                              getter_AddRefs(mPIPNSSBundle));
     46  if (!mPIPNSSBundle) rv = NS_ERROR_FAILURE;
     47 
     48  bundleService->CreateBundle(NSSERR_STRBUNDLE_URL,
     49                              getter_AddRefs(mNSSErrorsBundle));
     50  if (!mNSSErrorsBundle) rv = NS_ERROR_FAILURE;
     51 
     52  return rv;
     53 }
     54 
     55 #define EXPECTED_SEC_ERROR_BASE (-0x2000)
     56 #define EXPECTED_SSL_ERROR_BASE (-0x3000)
     57 
     58 #if SEC_ERROR_BASE != EXPECTED_SEC_ERROR_BASE || \
     59    SSL_ERROR_BASE != EXPECTED_SSL_ERROR_BASE
     60 #  error \
     61      "Unexpected change of error code numbers in lib NSS, please adjust the mapping code"
     62 /*
     63 * Please ensure the NSS error codes are mapped into the positive range 0x1000
     64 * to 0xf000 Search for NS_ERROR_MODULE_SECURITY to ensure there are no
     65 * conflicts. The current code also assumes that NSS library error codes are
     66 * negative.
     67 */
     68 #endif
     69 
     70 bool IsNSSErrorCode(PRErrorCode code) {
     71  return IS_SEC_ERROR(code) || IS_SSL_ERROR(code) || IsPSMError(code);
     72 }
     73 
     74 nsresult GetXPCOMFromNSSError(PRErrorCode code) {
     75  if (!code) {
     76    MOZ_CRASH("Function failed without calling PR_GetError");
     77  }
     78 
     79  // The error codes within each module must be a 16 bit value.
     80  // For simplicity we use the positive value of the NSS code.
     81  return (nsresult)NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_SECURITY,
     82                                             -1 * code);
     83 }
     84 
     85 NS_IMETHODIMP
     86 NSSErrorsService::IsNSSErrorCode(int32_t aNSPRCode, bool* _retval) {
     87  if (!_retval) {
     88    return NS_ERROR_INVALID_ARG;
     89  }
     90 
     91  *_retval = mozilla::psm::IsNSSErrorCode(aNSPRCode);
     92  return NS_OK;
     93 }
     94 
     95 NS_IMETHODIMP
     96 NSSErrorsService::GetXPCOMFromNSSError(int32_t aNSPRCode,
     97                                       nsresult* aXPCOMErrorCode) {
     98  if (!aXPCOMErrorCode) {
     99    return NS_ERROR_INVALID_ARG;
    100  }
    101 
    102  if (!mozilla::psm::IsNSSErrorCode(aNSPRCode)) {
    103    return NS_ERROR_INVALID_ARG;
    104  }
    105 
    106  *aXPCOMErrorCode = mozilla::psm::GetXPCOMFromNSSError(aNSPRCode);
    107 
    108  return NS_OK;
    109 }
    110 
    111 NS_IMETHODIMP
    112 NSSErrorsService::GetErrorClass(nsresult aXPCOMErrorCode,
    113                                uint32_t* aErrorClass) {
    114  NS_ENSURE_ARG(aErrorClass);
    115 
    116  if (NS_ERROR_GET_MODULE(aXPCOMErrorCode) != NS_ERROR_MODULE_SECURITY ||
    117      NS_ERROR_GET_SEVERITY(aXPCOMErrorCode) != NS_ERROR_SEVERITY_ERROR) {
    118    return NS_ERROR_FAILURE;
    119  }
    120 
    121  int32_t aNSPRCode = -1 * NS_ERROR_GET_CODE(aXPCOMErrorCode);
    122 
    123  if (!mozilla::psm::IsNSSErrorCode(aNSPRCode)) {
    124    return NS_ERROR_FAILURE;
    125  }
    126 
    127  // All overridable errors are certificate errors.
    128  if (mozilla::psm::ErrorIsOverridable(aNSPRCode)) {
    129    *aErrorClass = ERROR_CLASS_BAD_CERT;
    130    return NS_OK;
    131  }
    132  // Some non-overridable errors are certificate errors.
    133  switch (aNSPRCode) {
    134    case SEC_ERROR_BAD_DER:
    135    case SEC_ERROR_BAD_SIGNATURE:
    136    case SEC_ERROR_CERT_NOT_IN_NAME_SPACE:
    137    case SEC_ERROR_EXTENSION_VALUE_INVALID:
    138    case SEC_ERROR_INADEQUATE_CERT_TYPE:
    139    case SEC_ERROR_INADEQUATE_KEY_USAGE:
    140    case SEC_ERROR_INVALID_KEY:
    141    case SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID:
    142    case SEC_ERROR_REVOKED_CERTIFICATE:
    143    case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION:
    144    case SEC_ERROR_UNSUPPORTED_EC_POINT_FORM:
    145    case SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE:
    146    case SEC_ERROR_UNSUPPORTED_KEYALG:
    147    case SEC_ERROR_UNTRUSTED_CERT:
    148    case SEC_ERROR_UNTRUSTED_ISSUER:
    149    case mozilla::pkix::MOZILLA_PKIX_ERROR_INVALID_INTEGER_ENCODING:
    150    case mozilla::pkix::MOZILLA_PKIX_ERROR_ISSUER_NO_LONGER_TRUSTED:
    151    case mozilla::pkix::MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE:
    152    case mozilla::pkix::MOZILLA_PKIX_ERROR_SIGNATURE_ALGORITHM_MISMATCH:
    153      *aErrorClass = ERROR_CLASS_BAD_CERT;
    154      return NS_OK;
    155    default:
    156      break;
    157  }
    158 
    159  // Otherwise, this must be a TLS error.
    160  *aErrorClass = ERROR_CLASS_SSL_PROTOCOL;
    161  return NS_OK;
    162 }
    163 
    164 NS_IMETHODIMP
    165 NSSErrorsService::IsErrorOverridable(nsresult aXPCOMErrorCode, bool* _retval) {
    166  if (!_retval) {
    167    return NS_ERROR_INVALID_ARG;
    168  }
    169 
    170  if (NS_ERROR_GET_MODULE(aXPCOMErrorCode) != NS_ERROR_MODULE_SECURITY ||
    171      NS_ERROR_GET_SEVERITY(aXPCOMErrorCode) != NS_ERROR_SEVERITY_ERROR) {
    172    return NS_ERROR_FAILURE;
    173  }
    174 
    175  int32_t aNSPRCode = -1 * NS_ERROR_GET_CODE(aXPCOMErrorCode);
    176 
    177  if (!mozilla::psm::IsNSSErrorCode(aNSPRCode)) {
    178    return NS_ERROR_FAILURE;
    179  }
    180 
    181  *_retval = ErrorIsOverridable(aNSPRCode);
    182  return NS_OK;
    183 }
    184 
    185 bool ErrorIsOverridable(PRErrorCode code) {
    186  switch (code) {
    187    // Overridable errors.
    188    case SEC_ERROR_CA_CERT_INVALID:
    189    case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
    190    case SEC_ERROR_EXPIRED_CERTIFICATE:
    191    case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
    192    case SEC_ERROR_INVALID_TIME:
    193    case SEC_ERROR_UNKNOWN_ISSUER:
    194    case SSL_ERROR_BAD_CERT_DOMAIN:
    195    case mozilla::pkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY:
    196    case mozilla::pkix::MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME:
    197    case mozilla::pkix::MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE:
    198    case mozilla::pkix::
    199        MOZILLA_PKIX_ERROR_INSUFFICIENT_CERTIFICATE_TRANSPARENCY:
    200    case mozilla::pkix::MOZILLA_PKIX_ERROR_MITM_DETECTED:
    201    case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE:
    202    case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE:
    203    case mozilla::pkix::MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT:
    204    case mozilla::pkix::MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA:
    205      return true;
    206    // Non-overridable errors.
    207    default:
    208      return false;
    209  }
    210 }
    211 
    212 static const char* getOverrideErrorStringName(PRErrorCode aErrorCode) {
    213  switch (aErrorCode) {
    214    case SSL_ERROR_SSL_DISABLED:
    215      return "PSMERR_SSL_Disabled";
    216    case SSL_ERROR_SSL2_DISABLED:
    217      return "PSMERR_SSL2_Disabled";
    218    case SEC_ERROR_REUSED_ISSUER_AND_SERIAL:
    219      return "PSMERR_HostReusedIssuerSerial";
    220    case mozilla::pkix::MOZILLA_PKIX_ERROR_MITM_DETECTED:
    221      return "certErrorTrust_MitM";
    222    default:
    223      return nullptr;
    224  }
    225 }
    226 
    227 mozilla::Result<PRErrorCode, nsresult> NSResultToPRErrorCode(
    228    nsresult aXPCOMErrorCode) {
    229  if (NS_ERROR_GET_MODULE(aXPCOMErrorCode) != NS_ERROR_MODULE_SECURITY ||
    230      NS_ERROR_GET_SEVERITY(aXPCOMErrorCode) != NS_ERROR_SEVERITY_ERROR) {
    231    return Err(NS_ERROR_FAILURE);
    232  }
    233 
    234  PRErrorCode nsprCode = -1 * NS_ERROR_GET_CODE(aXPCOMErrorCode);
    235 
    236  if (!mozilla::psm::IsNSSErrorCode(nsprCode)) {
    237    return Err(NS_ERROR_FAILURE);
    238  }
    239 
    240  return nsprCode;
    241 }
    242 
    243 NS_IMETHODIMP
    244 NSSErrorsService::GetErrorMessage(nsresult aXPCOMErrorCode,
    245                                  nsAString& aErrorMessage) {
    246  auto prErrorCode = NSResultToPRErrorCode(aXPCOMErrorCode);
    247  if (!prErrorCode.isOk()) {
    248    return prErrorCode.unwrapErr();
    249  }
    250 
    251  nsCOMPtr<nsIStringBundle> theBundle;
    252  const char* idStr = getOverrideErrorStringName(prErrorCode.unwrap());
    253  if (idStr) {
    254    theBundle = mPIPNSSBundle;
    255  } else {
    256    idStr = PR_ErrorToName(prErrorCode.unwrap());
    257    theBundle = mNSSErrorsBundle;
    258  }
    259 
    260  if (!idStr || !theBundle) {
    261    return NS_ERROR_FAILURE;
    262  }
    263 
    264  nsAutoString msg;
    265  nsresult rv = theBundle->GetStringFromName(idStr, msg);
    266  if (NS_SUCCEEDED(rv)) {
    267    aErrorMessage = msg;
    268  }
    269  return rv;
    270 }
    271 
    272 NS_IMETHODIMP
    273 NSSErrorsService::GetErrorName(nsresult aXPCOMErrorCode,
    274                               nsAString& aErrorName) {
    275  auto prErrorCode = NSResultToPRErrorCode(aXPCOMErrorCode);
    276  if (!prErrorCode.isOk()) {
    277    return prErrorCode.unwrapErr();
    278  }
    279 
    280  const char* idStr = PR_ErrorToName(prErrorCode.unwrap());
    281  if (!idStr) {
    282    return NS_ERROR_FAILURE;
    283  }
    284 
    285  aErrorName = NS_ConvertASCIItoUTF16(idStr);
    286  return NS_OK;
    287 }
    288 
    289 }  // namespace psm
    290 }  // namespace mozilla