1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : *
3 : * ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Netscape Communications Corporation.
20 : * Portions created by the Initial Developer are Copyright (C) 2001
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Terry Hayes <thayes@netscape.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either the GNU General Public License Version 2 or later (the "GPL"), or
28 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #include "stdlib.h"
41 : #include "plstr.h"
42 : #include "plbase64.h"
43 :
44 : #include "nsMemory.h"
45 : #include "nsString.h"
46 : #include "nsCOMPtr.h"
47 : #include "nsThreadUtils.h"
48 : #include "nsIInterfaceRequestor.h"
49 : #include "nsIInterfaceRequestorUtils.h"
50 : #include "nsIServiceManager.h"
51 : #include "nsITokenPasswordDialogs.h"
52 :
53 : #include "nsISecretDecoderRing.h"
54 : #include "nsSDR.h"
55 : #include "nsNSSComponent.h"
56 : #include "nsNSSShutDown.h"
57 :
58 : #include "pk11func.h"
59 : #include "pk11sdr.h" // For PK11SDR_Encrypt, PK11SDR_Decrypt
60 :
61 : #include "ssl.h" // For SSL_ClearSessionCache
62 :
63 : #include "nsNSSCleaner.h"
64 6518 : NSSCleanupAutoPtrClass(PK11SlotInfo, PK11_FreeSlot)
65 :
66 : // Standard ISupports implementation
67 : // NOTE: Should these be the thread-safe versions?
68 2985 : NS_IMPL_ISUPPORTS2(nsSecretDecoderRing, nsISecretDecoderRing, nsISecretDecoderRingConfig)
69 :
70 : // nsSecretDecoderRing constructor
71 65 : nsSecretDecoderRing::nsSecretDecoderRing()
72 : {
73 : // initialize superclass
74 65 : }
75 :
76 : // nsSecretDecoderRing destructor
77 130 : nsSecretDecoderRing::~nsSecretDecoderRing()
78 : {
79 260 : }
80 :
81 : /* [noscript] long encrypt (in buffer data, in long dataLen, out buffer result); */
82 339 : NS_IMETHODIMP nsSecretDecoderRing::
83 : Encrypt(unsigned char * data, PRInt32 dataLen, unsigned char * *result, PRInt32 *_retval)
84 : {
85 678 : nsNSSShutDownPreventionLock locker;
86 339 : nsresult rv = NS_OK;
87 339 : PK11SlotInfo *slot = 0;
88 678 : PK11SlotInfoCleaner tmpSlotCleaner(slot);
89 : SECItem keyid;
90 : SECItem request;
91 : SECItem reply;
92 : SECStatus s;
93 678 : nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
94 339 : if (!ctx) { rv = NS_ERROR_OUT_OF_MEMORY; goto loser; }
95 :
96 339 : slot = PK11_GetInternalKeySlot();
97 339 : if (!slot) { rv = NS_ERROR_NOT_AVAILABLE; goto loser; }
98 :
99 : /* Make sure token is initialized. */
100 339 : rv = setPassword(slot, ctx);
101 339 : if (NS_FAILED(rv))
102 0 : goto loser;
103 :
104 : /* Force authentication */
105 339 : s = PK11_Authenticate(slot, true, ctx);
106 339 : if (s != SECSuccess) { rv = NS_ERROR_FAILURE; goto loser; }
107 :
108 : /* Use default key id */
109 339 : keyid.data = 0;
110 339 : keyid.len = 0;
111 339 : request.data = data;
112 339 : request.len = dataLen;
113 339 : reply.data = 0;
114 339 : reply.len = 0;
115 339 : s= PK11SDR_Encrypt(&keyid, &request, &reply, ctx);
116 339 : if (s != SECSuccess) { rv = NS_ERROR_FAILURE; goto loser; }
117 :
118 339 : *result = reply.data;
119 339 : *_retval = reply.len;
120 :
121 : loser:
122 339 : return rv;
123 : }
124 :
125 : /* [noscript] long decrypt (in buffer data, in long dataLen, out buffer result); */
126 2920 : NS_IMETHODIMP nsSecretDecoderRing::
127 : Decrypt(unsigned char * data, PRInt32 dataLen, unsigned char * *result, PRInt32 *_retval)
128 : {
129 5840 : nsNSSShutDownPreventionLock locker;
130 2920 : nsresult rv = NS_OK;
131 2920 : PK11SlotInfo *slot = 0;
132 5840 : PK11SlotInfoCleaner tmpSlotCleaner(slot);
133 : SECStatus s;
134 : SECItem request;
135 : SECItem reply;
136 5840 : nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
137 2920 : if (!ctx) { rv = NS_ERROR_OUT_OF_MEMORY; goto loser; }
138 :
139 2920 : *result = 0;
140 2920 : *_retval = 0;
141 :
142 : /* Find token with SDR key */
143 2920 : slot = PK11_GetInternalKeySlot();
144 2920 : if (!slot) { rv = NS_ERROR_NOT_AVAILABLE; goto loser; }
145 :
146 : /* Force authentication */
147 2920 : if (PK11_Authenticate(slot, true, ctx) != SECSuccess)
148 : {
149 0 : rv = NS_ERROR_NOT_AVAILABLE;
150 0 : goto loser;
151 : }
152 :
153 2920 : request.data = data;
154 2920 : request.len = dataLen;
155 2920 : reply.data = 0;
156 2920 : reply.len = 0;
157 2920 : s = PK11SDR_Decrypt(&request, &reply, ctx);
158 2920 : if (s != SECSuccess) { rv = NS_ERROR_FAILURE; goto loser; }
159 :
160 2920 : *result = reply.data;
161 2920 : *_retval = reply.len;
162 :
163 : loser:
164 2920 : return rv;
165 : }
166 :
167 : /* string encryptString (in string text); */
168 339 : NS_IMETHODIMP nsSecretDecoderRing::
169 : EncryptString(const char *text, char **_retval)
170 : {
171 678 : nsNSSShutDownPreventionLock locker;
172 339 : nsresult rv = NS_OK;
173 339 : unsigned char *encrypted = 0;
174 : PRInt32 eLen;
175 :
176 339 : if (text == nsnull || _retval == nsnull) {
177 0 : rv = NS_ERROR_INVALID_POINTER;
178 0 : goto loser;
179 : }
180 :
181 339 : rv = Encrypt((unsigned char *)text, PL_strlen(text), &encrypted, &eLen);
182 339 : if (rv != NS_OK) { goto loser; }
183 :
184 339 : rv = encode(encrypted, eLen, _retval);
185 :
186 : loser:
187 339 : if (encrypted) PORT_Free(encrypted);
188 :
189 339 : return rv;
190 : }
191 :
192 : /* string decryptString (in string crypt); */
193 2920 : NS_IMETHODIMP nsSecretDecoderRing::
194 : DecryptString(const char *crypt, char **_retval)
195 : {
196 5840 : nsNSSShutDownPreventionLock locker;
197 2920 : nsresult rv = NS_OK;
198 2920 : char *r = 0;
199 2920 : unsigned char *decoded = 0;
200 : PRInt32 decodedLen;
201 2920 : unsigned char *decrypted = 0;
202 : PRInt32 decryptedLen;
203 :
204 2920 : if (crypt == nsnull || _retval == nsnull) {
205 0 : rv = NS_ERROR_INVALID_POINTER;
206 0 : goto loser;
207 : }
208 :
209 2920 : rv = decode(crypt, &decoded, &decodedLen);
210 2920 : if (rv != NS_OK) goto loser;
211 :
212 2920 : rv = Decrypt(decoded, decodedLen, &decrypted, &decryptedLen);
213 2920 : if (rv != NS_OK) goto loser;
214 :
215 : // Convert to NUL-terminated string
216 2920 : r = (char *)nsMemory::Alloc(decryptedLen+1);
217 2920 : if (!r) { rv = NS_ERROR_OUT_OF_MEMORY; goto loser; }
218 :
219 2920 : memcpy(r, decrypted, decryptedLen);
220 2920 : r[decryptedLen] = 0;
221 :
222 2920 : *_retval = r;
223 2920 : r = 0;
224 :
225 : loser:
226 2920 : if (decrypted) PORT_Free(decrypted);
227 2920 : if (decoded) PR_DELETE(decoded);
228 :
229 2920 : return rv;
230 : }
231 :
232 : /* void changePassword(); */
233 0 : NS_IMETHODIMP nsSecretDecoderRing::
234 : ChangePassword()
235 : {
236 0 : nsNSSShutDownPreventionLock locker;
237 : nsresult rv;
238 : PK11SlotInfo *slot;
239 :
240 0 : slot = PK11_GetInternalKeySlot();
241 0 : if (!slot) return NS_ERROR_NOT_AVAILABLE;
242 :
243 : /* Convert UTF8 token name to UCS2 */
244 0 : NS_ConvertUTF8toUTF16 tokenName(PK11_GetTokenName(slot));
245 :
246 0 : PK11_FreeSlot(slot);
247 :
248 : /* Get the set password dialog handler imlementation */
249 0 : nsCOMPtr<nsITokenPasswordDialogs> dialogs;
250 :
251 0 : rv = getNSSDialogs(getter_AddRefs(dialogs),
252 : NS_GET_IID(nsITokenPasswordDialogs),
253 0 : NS_TOKENPASSWORDSDIALOG_CONTRACTID);
254 0 : if (NS_FAILED(rv)) return rv;
255 :
256 0 : nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
257 : bool canceled;
258 :
259 : {
260 0 : nsPSMUITracker tracker;
261 0 : if (tracker.isUIForbidden()) {
262 0 : rv = NS_ERROR_NOT_AVAILABLE;
263 : }
264 : else {
265 0 : rv = dialogs->SetPassword(ctx, tokenName.get(), &canceled);
266 : }
267 : }
268 :
269 : /* canceled is ignored */
270 :
271 0 : return rv;
272 : }
273 :
274 : static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
275 :
276 0 : NS_IMETHODIMP nsSecretDecoderRing::
277 : Logout()
278 : {
279 : nsresult rv;
280 0 : nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
281 0 : if (NS_FAILED(rv))
282 0 : return rv;
283 :
284 : {
285 0 : nsNSSShutDownPreventionLock locker;
286 0 : PK11_LogoutAll();
287 0 : SSL_ClearSessionCache();
288 : }
289 :
290 0 : return NS_OK;
291 : }
292 :
293 142 : NS_IMETHODIMP nsSecretDecoderRing::
294 : LogoutAndTeardown()
295 : {
296 : nsresult rv;
297 284 : nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
298 142 : if (NS_FAILED(rv))
299 0 : return rv;
300 :
301 : {
302 284 : nsNSSShutDownPreventionLock locker;
303 142 : PK11_LogoutAll();
304 142 : SSL_ClearSessionCache();
305 : }
306 :
307 142 : rv = nssComponent->LogoutAuthenticatedPK11();
308 :
309 : // After we just logged out, we need to prune dead connections to make
310 : // sure that all connections that should be stopped, are stopped. See
311 : // bug 517584.
312 284 : nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
313 142 : if (os)
314 142 : os->NotifyObservers(nsnull, "net:prune-dead-connections", nsnull);
315 :
316 142 : return rv;
317 : }
318 :
319 : /* void setWindow(in nsISupports w); */
320 0 : NS_IMETHODIMP nsSecretDecoderRing::
321 : SetWindow(nsISupports *w)
322 : {
323 0 : return NS_OK;
324 : }
325 :
326 : // Support routines
327 :
328 339 : nsresult nsSecretDecoderRing::
329 : encode(const unsigned char *data, PRInt32 dataLen, char **_retval)
330 : {
331 339 : nsresult rv = NS_OK;
332 :
333 339 : char *result = PL_Base64Encode((const char *)data, dataLen, NULL);
334 339 : if (!result) { rv = NS_ERROR_OUT_OF_MEMORY; goto loser; }
335 :
336 339 : *_retval = NS_strdup(result);
337 339 : PR_DELETE(result);
338 339 : if (!*_retval) { rv = NS_ERROR_OUT_OF_MEMORY; goto loser; }
339 :
340 : loser:
341 339 : return rv;
342 : }
343 :
344 2920 : nsresult nsSecretDecoderRing::
345 : decode(const char *data, unsigned char **result, PRInt32 * _retval)
346 : {
347 2920 : nsresult rv = NS_OK;
348 2920 : PRUint32 len = PL_strlen(data);
349 2920 : int adjust = 0;
350 :
351 : /* Compute length adjustment */
352 2920 : if (data[len-1] == '=') {
353 256 : adjust++;
354 256 : if (data[len-2] == '=') adjust++;
355 : }
356 :
357 2920 : *result = (unsigned char *)PL_Base64Decode(data, len, NULL);
358 2920 : if (!*result) { rv = NS_ERROR_ILLEGAL_VALUE; goto loser; }
359 :
360 2920 : *_retval = (len*3)/4 - adjust;
361 :
362 : loser:
363 2920 : return rv;
364 : }
|