1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/manager/ssl/src/nsSDR.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,327 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "stdlib.h" 1.11 +#include "plstr.h" 1.12 +#include "plbase64.h" 1.13 + 1.14 +#include "mozilla/Services.h" 1.15 +#include "nsMemory.h" 1.16 +#include "nsString.h" 1.17 +#include "nsCOMPtr.h" 1.18 +#include "nsThreadUtils.h" 1.19 +#include "nsIInterfaceRequestor.h" 1.20 +#include "nsIInterfaceRequestorUtils.h" 1.21 +#include "nsIServiceManager.h" 1.22 +#include "nsITokenPasswordDialogs.h" 1.23 + 1.24 +#include "nsISecretDecoderRing.h" 1.25 +#include "nsCRT.h" 1.26 +#include "nsSDR.h" 1.27 +#include "nsNSSComponent.h" 1.28 +#include "nsNSSShutDown.h" 1.29 +#include "ScopedNSSTypes.h" 1.30 + 1.31 +#include "pk11func.h" 1.32 +#include "pk11sdr.h" // For PK11SDR_Encrypt, PK11SDR_Decrypt 1.33 + 1.34 +#include "ssl.h" // For SSL_ClearSessionCache 1.35 + 1.36 +using namespace mozilla; 1.37 + 1.38 +// Standard ISupports implementation 1.39 +// NOTE: Should these be the thread-safe versions? 1.40 +NS_IMPL_ISUPPORTS(nsSecretDecoderRing, nsISecretDecoderRing, nsISecretDecoderRingConfig) 1.41 + 1.42 +// nsSecretDecoderRing constructor 1.43 +nsSecretDecoderRing::nsSecretDecoderRing() 1.44 +{ 1.45 + // initialize superclass 1.46 +} 1.47 + 1.48 +// nsSecretDecoderRing destructor 1.49 +nsSecretDecoderRing::~nsSecretDecoderRing() 1.50 +{ 1.51 +} 1.52 + 1.53 +/* [noscript] long encrypt (in buffer data, in long dataLen, out buffer result); */ 1.54 +NS_IMETHODIMP nsSecretDecoderRing:: 1.55 +Encrypt(unsigned char * data, int32_t dataLen, unsigned char * *result, int32_t *_retval) 1.56 +{ 1.57 + nsNSSShutDownPreventionLock locker; 1.58 + nsresult rv = NS_OK; 1.59 + ScopedPK11SlotInfo slot; 1.60 + SECItem keyid; 1.61 + SECItem request; 1.62 + SECItem reply; 1.63 + SECStatus s; 1.64 + nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext(); 1.65 + 1.66 + slot = PK11_GetInternalKeySlot(); 1.67 + if (!slot) { rv = NS_ERROR_NOT_AVAILABLE; goto loser; } 1.68 + 1.69 + /* Make sure token is initialized. */ 1.70 + rv = setPassword(slot, ctx); 1.71 + if (NS_FAILED(rv)) 1.72 + goto loser; 1.73 + 1.74 + /* Force authentication */ 1.75 + s = PK11_Authenticate(slot, true, ctx); 1.76 + if (s != SECSuccess) { rv = NS_ERROR_FAILURE; goto loser; } 1.77 + 1.78 + /* Use default key id */ 1.79 + keyid.data = 0; 1.80 + keyid.len = 0; 1.81 + request.data = data; 1.82 + request.len = dataLen; 1.83 + reply.data = 0; 1.84 + reply.len = 0; 1.85 + s= PK11SDR_Encrypt(&keyid, &request, &reply, ctx); 1.86 + if (s != SECSuccess) { rv = NS_ERROR_FAILURE; goto loser; } 1.87 + 1.88 + *result = reply.data; 1.89 + *_retval = reply.len; 1.90 + 1.91 +loser: 1.92 + return rv; 1.93 +} 1.94 + 1.95 +/* [noscript] long decrypt (in buffer data, in long dataLen, out buffer result); */ 1.96 +NS_IMETHODIMP nsSecretDecoderRing:: 1.97 +Decrypt(unsigned char * data, int32_t dataLen, unsigned char * *result, int32_t *_retval) 1.98 +{ 1.99 + nsNSSShutDownPreventionLock locker; 1.100 + nsresult rv = NS_OK; 1.101 + ScopedPK11SlotInfo slot; 1.102 + SECStatus s; 1.103 + SECItem request; 1.104 + SECItem reply; 1.105 + nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext(); 1.106 + 1.107 + *result = 0; 1.108 + *_retval = 0; 1.109 + 1.110 + /* Find token with SDR key */ 1.111 + slot = PK11_GetInternalKeySlot(); 1.112 + if (!slot) { rv = NS_ERROR_NOT_AVAILABLE; goto loser; } 1.113 + 1.114 + /* Force authentication */ 1.115 + if (PK11_Authenticate(slot, true, ctx) != SECSuccess) 1.116 + { 1.117 + rv = NS_ERROR_NOT_AVAILABLE; 1.118 + goto loser; 1.119 + } 1.120 + 1.121 + request.data = data; 1.122 + request.len = dataLen; 1.123 + reply.data = 0; 1.124 + reply.len = 0; 1.125 + s = PK11SDR_Decrypt(&request, &reply, ctx); 1.126 + if (s != SECSuccess) { rv = NS_ERROR_FAILURE; goto loser; } 1.127 + 1.128 + *result = reply.data; 1.129 + *_retval = reply.len; 1.130 + 1.131 +loser: 1.132 + return rv; 1.133 +} 1.134 + 1.135 +/* string encryptString (in string text); */ 1.136 +NS_IMETHODIMP nsSecretDecoderRing:: 1.137 +EncryptString(const char *text, char **_retval) 1.138 +{ 1.139 + nsNSSShutDownPreventionLock locker; 1.140 + nsresult rv = NS_OK; 1.141 + unsigned char *encrypted = 0; 1.142 + int32_t eLen; 1.143 + 1.144 + if (!text || !_retval) { 1.145 + rv = NS_ERROR_INVALID_POINTER; 1.146 + goto loser; 1.147 + } 1.148 + 1.149 + rv = Encrypt((unsigned char *)text, strlen(text), &encrypted, &eLen); 1.150 + if (rv != NS_OK) { goto loser; } 1.151 + 1.152 + rv = encode(encrypted, eLen, _retval); 1.153 + 1.154 +loser: 1.155 + if (encrypted) PORT_Free(encrypted); 1.156 + 1.157 + return rv; 1.158 +} 1.159 + 1.160 +/* string decryptString (in string crypt); */ 1.161 +NS_IMETHODIMP nsSecretDecoderRing:: 1.162 +DecryptString(const char *crypt, char **_retval) 1.163 +{ 1.164 + nsNSSShutDownPreventionLock locker; 1.165 + nsresult rv = NS_OK; 1.166 + char *r = 0; 1.167 + unsigned char *decoded = 0; 1.168 + int32_t decodedLen; 1.169 + unsigned char *decrypted = 0; 1.170 + int32_t decryptedLen; 1.171 + 1.172 + if (!crypt || !_retval) { 1.173 + rv = NS_ERROR_INVALID_POINTER; 1.174 + goto loser; 1.175 + } 1.176 + 1.177 + rv = decode(crypt, &decoded, &decodedLen); 1.178 + if (rv != NS_OK) goto loser; 1.179 + 1.180 + rv = Decrypt(decoded, decodedLen, &decrypted, &decryptedLen); 1.181 + if (rv != NS_OK) goto loser; 1.182 + 1.183 + // Convert to NUL-terminated string 1.184 + r = (char *)nsMemory::Alloc(decryptedLen+1); 1.185 + if (!r) { rv = NS_ERROR_OUT_OF_MEMORY; goto loser; } 1.186 + 1.187 + memcpy(r, decrypted, decryptedLen); 1.188 + r[decryptedLen] = 0; 1.189 + 1.190 + *_retval = r; 1.191 + r = 0; 1.192 + 1.193 +loser: 1.194 + if (decrypted) PORT_Free(decrypted); 1.195 + if (decoded) PR_DELETE(decoded); 1.196 + 1.197 + return rv; 1.198 +} 1.199 + 1.200 +/* void changePassword(); */ 1.201 +NS_IMETHODIMP nsSecretDecoderRing:: 1.202 +ChangePassword() 1.203 +{ 1.204 + nsNSSShutDownPreventionLock locker; 1.205 + nsresult rv; 1.206 + ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); 1.207 + if (!slot) return NS_ERROR_NOT_AVAILABLE; 1.208 + 1.209 + /* Convert UTF8 token name to UCS2 */ 1.210 + NS_ConvertUTF8toUTF16 tokenName(PK11_GetTokenName(slot)); 1.211 + 1.212 + /* Get the set password dialog handler imlementation */ 1.213 + nsCOMPtr<nsITokenPasswordDialogs> dialogs; 1.214 + 1.215 + rv = getNSSDialogs(getter_AddRefs(dialogs), 1.216 + NS_GET_IID(nsITokenPasswordDialogs), 1.217 + NS_TOKENPASSWORDSDIALOG_CONTRACTID); 1.218 + if (NS_FAILED(rv)) return rv; 1.219 + 1.220 + nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext(); 1.221 + bool canceled; 1.222 + 1.223 + { 1.224 + nsPSMUITracker tracker; 1.225 + if (tracker.isUIForbidden()) { 1.226 + rv = NS_ERROR_NOT_AVAILABLE; 1.227 + } 1.228 + else { 1.229 + rv = dialogs->SetPassword(ctx, tokenName.get(), &canceled); 1.230 + } 1.231 + } 1.232 + 1.233 + /* canceled is ignored */ 1.234 + 1.235 + return rv; 1.236 +} 1.237 + 1.238 +NS_IMETHODIMP nsSecretDecoderRing:: 1.239 +Logout() 1.240 +{ 1.241 + static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); 1.242 + 1.243 + nsresult rv; 1.244 + nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv)); 1.245 + if (NS_FAILED(rv)) 1.246 + return rv; 1.247 + 1.248 + { 1.249 + nsNSSShutDownPreventionLock locker; 1.250 + PK11_LogoutAll(); 1.251 + SSL_ClearSessionCache(); 1.252 + } 1.253 + 1.254 + return NS_OK; 1.255 +} 1.256 + 1.257 +NS_IMETHODIMP nsSecretDecoderRing:: 1.258 +LogoutAndTeardown() 1.259 +{ 1.260 + static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); 1.261 + 1.262 + nsresult rv; 1.263 + nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv)); 1.264 + if (NS_FAILED(rv)) 1.265 + return rv; 1.266 + 1.267 + { 1.268 + nsNSSShutDownPreventionLock locker; 1.269 + PK11_LogoutAll(); 1.270 + SSL_ClearSessionCache(); 1.271 + } 1.272 + 1.273 + rv = nssComponent->LogoutAuthenticatedPK11(); 1.274 + 1.275 + // After we just logged out, we need to prune dead connections to make 1.276 + // sure that all connections that should be stopped, are stopped. See 1.277 + // bug 517584. 1.278 + nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); 1.279 + if (os) 1.280 + os->NotifyObservers(nullptr, "net:prune-dead-connections", nullptr); 1.281 + 1.282 + return rv; 1.283 +} 1.284 + 1.285 +/* void setWindow(in nsISupports w); */ 1.286 +NS_IMETHODIMP nsSecretDecoderRing:: 1.287 +SetWindow(nsISupports *w) 1.288 +{ 1.289 + return NS_OK; 1.290 +} 1.291 + 1.292 +// Support routines 1.293 + 1.294 +nsresult nsSecretDecoderRing:: 1.295 +encode(const unsigned char *data, int32_t dataLen, char **_retval) 1.296 +{ 1.297 + nsresult rv = NS_OK; 1.298 + 1.299 + char *result = PL_Base64Encode((const char *)data, dataLen, nullptr); 1.300 + if (!result) { rv = NS_ERROR_OUT_OF_MEMORY; goto loser; } 1.301 + 1.302 + *_retval = NS_strdup(result); 1.303 + PR_DELETE(result); 1.304 + if (!*_retval) { rv = NS_ERROR_OUT_OF_MEMORY; goto loser; } 1.305 + 1.306 +loser: 1.307 + return rv; 1.308 +} 1.309 + 1.310 +nsresult nsSecretDecoderRing:: 1.311 +decode(const char *data, unsigned char **result, int32_t * _retval) 1.312 +{ 1.313 + nsresult rv = NS_OK; 1.314 + uint32_t len = strlen(data); 1.315 + int adjust = 0; 1.316 + 1.317 + /* Compute length adjustment */ 1.318 + if (data[len-1] == '=') { 1.319 + adjust++; 1.320 + if (data[len-2] == '=') adjust++; 1.321 + } 1.322 + 1.323 + *result = (unsigned char *)PL_Base64Decode(data, len, nullptr); 1.324 + if (!*result) { rv = NS_ERROR_ILLEGAL_VALUE; goto loser; } 1.325 + 1.326 + *_retval = (len*3)/4 - adjust; 1.327 + 1.328 +loser: 1.329 + return rv; 1.330 +}