Back to index

lightning-sunbird  0.9+nobinonly
nsSDR.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 2001
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Terry Hayes <thayes@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "stdlib.h"
00041 #include "plstr.h"
00042 #include "plbase64.h"
00043 
00044 #include "nsMemory.h"
00045 #include "nsString.h"
00046 #include "nsCOMPtr.h"
00047 #include "nsISupports.h"
00048 #include "nsIInterfaceRequestor.h"
00049 #include "nsIInterfaceRequestorUtils.h"
00050 #include "nsIServiceManager.h"
00051 #include "nsIWindowWatcher.h"
00052 #include "nsIPrompt.h"
00053 #include "nsProxiedService.h"
00054 #include "nsITokenPasswordDialogs.h"
00055 
00056 #include "nsISecretDecoderRing.h"
00057 #include "nsSDR.h"
00058 #include "nsNSSComponent.h"
00059 #include "nsNSSShutDown.h"
00060 
00061 #include "pk11func.h"
00062 #include "pk11sdr.h" // For PK11SDR_Encrypt, PK11SDR_Decrypt
00063 
00064 #include "ssl.h" // For SSL_ClearSessionCache
00065 
00066 #include "nsNSSCleaner.h"
00067 NSSCleanupAutoPtrClass(PK11SlotInfo, PK11_FreeSlot)
00068 
00069 //
00070 // Implementation of an nsIInterfaceRequestor for use
00071 // as context for NSS calls
00072 //
00073 class nsSDRContext : public nsIInterfaceRequestor
00074 {
00075 public:
00076   NS_DECL_ISUPPORTS
00077   NS_DECL_NSIINTERFACEREQUESTOR
00078 
00079   nsSDRContext();
00080   virtual ~nsSDRContext();
00081 
00082 };
00083 
00084 NS_IMPL_ISUPPORTS1(nsSDRContext, nsIInterfaceRequestor)
00085 
00086 nsSDRContext::nsSDRContext()
00087 {
00088 }
00089 
00090 nsSDRContext::~nsSDRContext()
00091 {
00092 }
00093 
00094 /* void getInterface (in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */
00095 NS_IMETHODIMP nsSDRContext::GetInterface(const nsIID & uuid, void * *result)
00096 {
00097   if (uuid.Equals(NS_GET_IID(nsIPrompt))) {
00098     nsCOMPtr<nsIProxyObjectManager> proxyman(do_GetService(NS_XPCOMPROXY_CONTRACTID));
00099     if (!proxyman) return NS_ERROR_FAILURE;
00100 
00101     nsCOMPtr<nsIPrompt> prompter;
00102     nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
00103     if (wwatch) {
00104       wwatch->GetNewPrompter(0, getter_AddRefs(prompter));
00105       if (prompter) {
00106         nsCOMPtr<nsIPrompt> proxyPrompt;
00107         proxyman->GetProxyForObject(NS_UI_THREAD_EVENTQ, NS_GET_IID(nsIPrompt),
00108                                     prompter, PROXY_SYNC, getter_AddRefs(proxyPrompt));
00109         if (!proxyPrompt) return NS_ERROR_FAILURE;
00110         *result = proxyPrompt;
00111         NS_ADDREF((nsIPrompt*)*result);
00112       }
00113     }
00114   } else {
00115     return NS_ERROR_NO_INTERFACE;
00116   }
00117 
00118   return NS_OK;
00119 }
00120 
00121 // Standard ISupports implementation
00122 // NOTE: Should these be the thread-safe versions?
00123 NS_IMPL_ISUPPORTS2(nsSecretDecoderRing, nsISecretDecoderRing, nsISecretDecoderRingConfig)
00124 
00125 // nsSecretDecoderRing constructor
00126 nsSecretDecoderRing::nsSecretDecoderRing()
00127 {
00128   // initialize superclass
00129 }
00130 
00131 // nsSecretDecoderRing destructor
00132 nsSecretDecoderRing::~nsSecretDecoderRing()
00133 {
00134 }
00135 
00136 /* [noscript] long encrypt (in buffer data, in long dataLen, out buffer result); */
00137 NS_IMETHODIMP nsSecretDecoderRing::
00138 Encrypt(unsigned char * data, PRInt32 dataLen, unsigned char * *result, PRInt32 *_retval)
00139 {
00140   nsNSSShutDownPreventionLock locker;
00141   nsresult rv = NS_OK;
00142   PK11SlotInfo *slot = 0;
00143   PK11SlotInfoCleaner tmpSlotCleaner(slot);
00144   SECItem keyid;
00145   SECItem request;
00146   SECItem reply;
00147   SECStatus s;
00148   nsCOMPtr<nsIInterfaceRequestor> ctx = new nsSDRContext();
00149 
00150   slot = PK11_GetInternalKeySlot();
00151   if (!slot) { rv = NS_ERROR_NOT_AVAILABLE; goto loser; }
00152 
00153   /* Make sure token is initialized. */
00154   rv = setPassword(slot, ctx);
00155   if (NS_FAILED(rv))
00156     goto loser;
00157 
00158   s = PK11_Authenticate(slot, PR_TRUE, ctx);
00159   if (s != SECSuccess) { rv = NS_ERROR_FAILURE; goto loser; }
00160 
00161   /* Use default key id */
00162   keyid.data = 0;
00163   keyid.len = 0;
00164   request.data = data;
00165   request.len = dataLen;
00166   reply.data = 0;
00167   reply.len = 0;
00168   s= PK11SDR_Encrypt(&keyid, &request, &reply, ctx);
00169   if (s != SECSuccess) { rv = NS_ERROR_FAILURE; goto loser; }
00170 
00171   *result = reply.data;
00172   *_retval = reply.len;
00173 
00174 loser:
00175   return rv;
00176 }
00177 
00178 /* [noscript] long decrypt (in buffer data, in long dataLen, out buffer result); */
00179 NS_IMETHODIMP nsSecretDecoderRing::
00180 Decrypt(unsigned char * data, PRInt32 dataLen, unsigned char * *result, PRInt32 *_retval)
00181 {
00182   nsNSSShutDownPreventionLock locker;
00183   nsresult rv = NS_OK;
00184   PK11SlotInfo *slot = 0;
00185   PK11SlotInfoCleaner tmpSlotCleaner(slot);
00186   SECStatus s;
00187   SECItem request;
00188   SECItem reply;
00189   nsCOMPtr<nsIInterfaceRequestor> ctx = new nsSDRContext();
00190 
00191   *result = 0;
00192   *_retval = 0;
00193 
00194   /* Find token with SDR key */
00195   slot = PK11_GetInternalKeySlot();
00196   if (!slot) { rv = NS_ERROR_NOT_AVAILABLE; goto loser; }
00197 
00198   /* Force authentication */
00199   if (PK11_Authenticate(slot, PR_TRUE, ctx) != SECSuccess)
00200   {
00201     rv = NS_ERROR_NOT_AVAILABLE;
00202     goto loser;
00203   }
00204 
00205   request.data = data;
00206   request.len = dataLen;
00207   reply.data = 0;
00208   reply.len = 0;
00209   s = PK11SDR_Decrypt(&request, &reply, ctx);
00210   if (s != SECSuccess) { rv = NS_ERROR_FAILURE; goto loser; }
00211 
00212   *result = reply.data;
00213   *_retval = reply.len;
00214 
00215 loser:
00216   return rv;
00217 }
00218 
00219 /* string encryptString (in string text); */
00220 NS_IMETHODIMP nsSecretDecoderRing::
00221 EncryptString(const char *text, char **_retval)
00222 {
00223     nsNSSShutDownPreventionLock locker;
00224     nsresult rv = NS_OK;
00225     unsigned char *encrypted = 0;
00226     PRInt32 eLen;
00227 
00228     if (text == nsnull || _retval == nsnull) {
00229         rv = NS_ERROR_INVALID_POINTER;
00230         goto loser;
00231     }
00232 
00233     rv = Encrypt((unsigned char *)text, PL_strlen(text), &encrypted, &eLen);
00234     if (rv != NS_OK) { goto loser; }
00235 
00236     rv = encode(encrypted, eLen, _retval);
00237 
00238 loser:
00239     if (encrypted) nsMemory::Free(encrypted);
00240 
00241     return rv;
00242 }
00243 
00244 /* string decryptString (in string crypt); */
00245 NS_IMETHODIMP nsSecretDecoderRing::
00246 DecryptString(const char *crypt, char **_retval)
00247 {
00248     nsNSSShutDownPreventionLock locker;
00249     nsresult rv = NS_OK;
00250     char *r = 0;
00251     unsigned char *decoded = 0;
00252     PRInt32 decodedLen;
00253     unsigned char *decrypted = 0;
00254     PRInt32 decryptedLen;
00255 
00256     if (crypt == nsnull || _retval == nsnull) {
00257       rv = NS_ERROR_INVALID_POINTER;
00258       goto loser;
00259     }
00260 
00261     rv = decode(crypt, &decoded, &decodedLen);
00262     if (rv != NS_OK) goto loser;
00263 
00264     rv = Decrypt(decoded, decodedLen, &decrypted, &decryptedLen);
00265     if (rv != NS_OK) goto loser;
00266 
00267     // Convert to NUL-terminated string
00268     r = (char *)nsMemory::Alloc(decryptedLen+1);
00269     if (!r) { rv = NS_ERROR_OUT_OF_MEMORY; goto loser; }
00270 
00271     memcpy(r, decrypted, decryptedLen);
00272     r[decryptedLen] = 0;
00273 
00274     *_retval = r;
00275     r = 0;
00276 
00277 loser:
00278     if (r) nsMemory::Free(r);
00279     if (decrypted) nsMemory::Free(decrypted);
00280     if (decoded) nsMemory::Free(decoded);
00281  
00282     return rv;
00283 }
00284 
00285 /* void changePassword(); */
00286 NS_IMETHODIMP nsSecretDecoderRing::
00287 ChangePassword()
00288 {
00289   nsNSSShutDownPreventionLock locker;
00290   nsresult rv;
00291   PK11SlotInfo *slot;
00292 
00293   slot = PK11_GetInternalKeySlot();
00294   if (!slot) return NS_ERROR_NOT_AVAILABLE;
00295 
00296   /* Convert UTF8 token name to UCS2 */
00297   NS_ConvertUTF8toUCS2 tokenName(PK11_GetTokenName(slot));
00298 
00299   PK11_FreeSlot(slot);
00300 
00301   /* Get the set password dialog handler imlementation */
00302   nsCOMPtr<nsITokenPasswordDialogs> dialogs;
00303 
00304   rv = getNSSDialogs(getter_AddRefs(dialogs),
00305            NS_GET_IID(nsITokenPasswordDialogs),
00306            NS_TOKENPASSWORDSDIALOG_CONTRACTID);
00307   if (NS_FAILED(rv)) return rv;
00308 
00309   nsCOMPtr<nsIInterfaceRequestor> ctx = new nsSDRContext();
00310   PRBool canceled;
00311 
00312   {
00313     nsPSMUITracker tracker;
00314     if (tracker.isUIForbidden()) {
00315       rv = NS_ERROR_NOT_AVAILABLE;
00316     }
00317     else {
00318       rv = dialogs->SetPassword(ctx, tokenName.get(), &canceled);
00319     }
00320   }
00321 
00322   /* canceled is ignored */
00323 
00324 
00325   return rv;
00326 }
00327 
00328 static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
00329 
00330 NS_IMETHODIMP nsSecretDecoderRing::
00331 Logout()
00332 {
00333   nsresult rv;
00334   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
00335   if (NS_FAILED(rv))
00336     return rv;
00337 
00338   {
00339     nsNSSShutDownPreventionLock locker;
00340     PK11_LogoutAll();
00341     SSL_ClearSessionCache();
00342   }
00343 
00344   return NS_OK;
00345 }
00346 
00347 NS_IMETHODIMP nsSecretDecoderRing::
00348 LogoutAndTeardown()
00349 {
00350   nsresult rv;
00351   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
00352   if (NS_FAILED(rv))
00353     return rv;
00354 
00355   {
00356     nsNSSShutDownPreventionLock locker;
00357     PK11_LogoutAll();
00358     SSL_ClearSessionCache();
00359   }
00360 
00361   return nssComponent->LogoutAuthenticatedPK11();
00362 }
00363 
00364 /* void setWindow(in nsISupports w); */
00365 NS_IMETHODIMP nsSecretDecoderRing::
00366 SetWindow(nsISupports *w)
00367 {
00368   return NS_OK;
00369 }
00370 
00371 // Support routines
00372 
00373 nsresult nsSecretDecoderRing::
00374 encode(const unsigned char *data, PRInt32 dataLen, char **_retval)
00375 {
00376     nsresult rv = NS_OK;
00377 
00378     *_retval = PL_Base64Encode((const char *)data, dataLen, NULL);
00379     if (!*_retval) { rv = NS_ERROR_OUT_OF_MEMORY; goto loser; }
00380 
00381 loser:
00382     return rv;
00383 }
00384 
00385 nsresult nsSecretDecoderRing::
00386 decode(const char *data, unsigned char **result, PRInt32 * _retval)
00387 {
00388     nsresult rv = NS_OK;
00389     PRUint32 len = PL_strlen(data);
00390     int adjust = 0;
00391 
00392     /* Compute length adjustment */
00393     if (data[len-1] == '=') {
00394       adjust++;
00395       if (data[len-2] == '=') adjust++;
00396     }
00397 
00398     *result = (unsigned char *)PL_Base64Decode(data, len, NULL);
00399     if (!*result) { rv = NS_ERROR_ILLEGAL_VALUE; goto loser; }
00400 
00401     *_retval = (len*3)/4 - adjust;
00402 
00403 loser:
00404     return rv;
00405 }