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