PageRenderTime 45ms CodeModel.GetById 14ms app.highlight 27ms RepoModel.GetById 1ms app.codeStats 0ms

/security/manager/ssl/src/nsCRLManager.cpp

http://github.com/zpao/v8monkey
C++ | 489 lines | 370 code | 61 blank | 58 comment | 57 complexity | 3d8aed325ca566576c6dd99feb2f34e1 MD5 | raw file
  1/* ***** BEGIN LICENSE BLOCK *****
  2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3 *
  4 * The contents of this file are subject to the Mozilla Public License Version
  5 * 1.1 (the "License"); you may not use this file except in compliance with
  6 * the License. You may obtain a copy of the License at
  7 * http://www.mozilla.org/MPL/
  8 *
  9 * Software distributed under the License is distributed on an "AS IS" basis,
 10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 11 * for the specific language governing rights and limitations under the
 12 * License.
 13 *
 14 * The Original Code is the Netscape security libraries.
 15 *
 16 * The Initial Developer of the Original Code is
 17 * Netscape Communications Corporation.
 18 * Portions created by the Initial Developer are Copyright (C) 2000
 19 * the Initial Developer. All Rights Reserved.
 20 *
 21 * Contributor(s):
 22 *
 23 * Alternatively, the contents of this file may be used under the terms of
 24 * either the GNU General Public License Version 2 or later (the "GPL"), or
 25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 26 * in which case the provisions of the GPL or the LGPL are applicable instead
 27 * of those above. If you wish to allow use of your version of this file only
 28 * under the terms of either the GPL or the LGPL, and not to allow others to
 29 * use your version of this file under the terms of the MPL, indicate your
 30 * decision by deleting the provisions above and replace them with the notice
 31 * and other provisions required by the GPL or the LGPL. If you do not delete
 32 * the provisions above, a recipient may use your version of this file under
 33 * the terms of any one of the MPL, the GPL or the LGPL.
 34 *
 35 * ***** END LICENSE BLOCK ***** */
 36
 37#include "nsCRLManager.h"
 38#include "nsCRLInfo.h"
 39
 40#include "nsCOMPtr.h"
 41#include "nsIDateTimeFormat.h"
 42#include "nsDateTimeFormatCID.h"
 43#include "nsComponentManagerUtils.h"
 44#include "nsReadableUtils.h"
 45#include "nsNSSComponent.h"
 46#include "nsCOMPtr.h"
 47#include "nsICertificateDialogs.h"
 48#include "nsIMutableArray.h"
 49#include "nsIPrefService.h"
 50#include "nsIPrefBranch.h"
 51#include "nsNSSShutDown.h"
 52#include "nsThreadUtils.h"
 53
 54#include "nsNSSCertHeader.h"
 55
 56#include "nspr.h"
 57extern "C" {
 58#include "pk11func.h"
 59#include "certdb.h"
 60#include "cert.h"
 61#include "secerr.h"
 62#include "nssb64.h"
 63#include "secasn1.h"
 64#include "secder.h"
 65}
 66#include "ssl.h"
 67#include "ocsp.h"
 68#include "plbase64.h"
 69
 70static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
 71
 72NS_IMPL_ISUPPORTS1(nsCRLManager, nsICRLManager)
 73
 74nsCRLManager::nsCRLManager()
 75{
 76}
 77
 78nsCRLManager::~nsCRLManager()
 79{
 80}
 81
 82NS_IMETHODIMP 
 83nsCRLManager::ImportCrl (PRUint8 *aData, PRUint32 aLength, nsIURI * aURI, PRUint32 aType, bool doSilentDownload, const PRUnichar* crlKey)
 84{
 85  if (!NS_IsMainThread()) {
 86    NS_ERROR("nsCRLManager::ImportCrl called off the main thread");
 87    return NS_ERROR_NOT_SAME_THREAD;
 88  }
 89  
 90  nsNSSShutDownPreventionLock locker;
 91  nsresult rv;
 92  PRArenaPool *arena = NULL;
 93  CERTCertificate *caCert;
 94  SECItem derName = { siBuffer, NULL, 0 };
 95  SECItem derCrl;
 96  CERTSignedData sd;
 97  SECStatus sec_rv;
 98  CERTSignedCrl *crl;
 99  nsCAutoString url;
100  nsCOMPtr<nsICRLInfo> crlData;
101  bool importSuccessful;
102  PRInt32 errorCode;
103  nsString errorMessage;
104  
105  nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
106  if (NS_FAILED(rv)) return rv;
107	         
108  aURI->GetSpec(url);
109  arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
110  if (!arena) {
111    goto loser;
112  }
113  memset(&sd, 0, sizeof(sd));
114
115  derCrl.data = (unsigned char*)aData;
116  derCrl.len = aLength;
117  sec_rv = CERT_KeyFromDERCrl(arena, &derCrl, &derName);
118  if (sec_rv != SECSuccess) {
119    goto loser;
120  }
121
122  caCert = CERT_FindCertByName(CERT_GetDefaultCertDB(), &derName);
123  if (!caCert) {
124    if (aType == SEC_KRL_TYPE){
125      goto loser;
126    }
127  } else {
128    sec_rv = SEC_ASN1DecodeItem(arena,
129                            &sd, SEC_ASN1_GET(CERT_SignedDataTemplate), 
130                            &derCrl);
131    if (sec_rv != SECSuccess) {
132      goto loser;
133    }
134    sec_rv = CERT_VerifySignedData(&sd, caCert, PR_Now(),
135                               nsnull);
136    if (sec_rv != SECSuccess) {
137      goto loser;
138    }
139  }
140  
141  crl = SEC_NewCrl(CERT_GetDefaultCertDB(), const_cast<char*>(url.get()), &derCrl,
142                   aType);
143  
144  if (!crl) {
145    goto loser;
146  }
147
148  crlData = new nsCRLInfo(crl);
149  SSL_ClearSessionCache();
150  SEC_DestroyCrl(crl);
151  
152  importSuccessful = true;
153  goto done;
154
155loser:
156  importSuccessful = false;
157  errorCode = PR_GetError();
158  switch (errorCode) {
159    case SEC_ERROR_CRL_EXPIRED:
160      nssComponent->GetPIPNSSBundleString("CrlImportFailureExpired", errorMessage);
161      break;
162
163	case SEC_ERROR_CRL_BAD_SIGNATURE:
164      nssComponent->GetPIPNSSBundleString("CrlImportFailureBadSignature", errorMessage);
165      break;
166
167	case SEC_ERROR_CRL_INVALID:
168      nssComponent->GetPIPNSSBundleString("CrlImportFailureInvalid", errorMessage);
169      break;
170
171	case SEC_ERROR_OLD_CRL:
172      nssComponent->GetPIPNSSBundleString("CrlImportFailureOld", errorMessage);
173      break;
174
175	case SEC_ERROR_CRL_NOT_YET_VALID:
176      nssComponent->GetPIPNSSBundleString("CrlImportFailureNotYetValid", errorMessage);
177      break;
178
179    default:
180      nssComponent->GetPIPNSSBundleString("CrlImportFailureReasonUnknown", errorMessage);
181      errorMessage.AppendInt(errorCode,16);
182      break;
183  }
184
185done:
186          
187  if(!doSilentDownload){
188    if (!importSuccessful){
189      nsString message;
190      nsString temp;
191      nssComponent->GetPIPNSSBundleString("CrlImportFailure1x", message);
192      message.Append(NS_LITERAL_STRING("\n").get());
193      message.Append(errorMessage);
194      nssComponent->GetPIPNSSBundleString("CrlImportFailure2", temp);
195      message.Append(NS_LITERAL_STRING("\n").get());
196      message.Append(temp);
197
198      nsNSSComponent::ShowAlertWithConstructedString(message);
199    } else {
200      nsCOMPtr<nsICertificateDialogs> certDialogs;
201      // Not being able to display the success dialog should not
202      // be a fatal error, so don't return a failure code.
203      {
204        nsPSMUITracker tracker;
205        if (tracker.isUIForbidden()) {
206          rv = NS_ERROR_NOT_AVAILABLE;
207        }
208        else {
209          rv = ::getNSSDialogs(getter_AddRefs(certDialogs),
210            NS_GET_IID(nsICertificateDialogs), NS_CERTIFICATEDIALOGS_CONTRACTID);
211        }
212      }
213      if (NS_SUCCEEDED(rv)) {
214        nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
215        certDialogs->CrlImportStatusDialog(cxt, crlData);
216      }
217    }
218  } else {
219    if(crlKey == nsnull){
220      return NS_ERROR_FAILURE;
221    }
222    nsCOMPtr<nsIPrefService> prefSvc = do_GetService(NS_PREFSERVICE_CONTRACTID,&rv);
223    nsCOMPtr<nsIPrefBranch> pref = do_GetService(NS_PREFSERVICE_CONTRACTID,&rv);
224    if (NS_FAILED(rv)){
225      return rv;
226    }
227    
228    nsCAutoString updateErrCntPrefStr(CRL_AUTOUPDATE_ERRCNT_PREF);
229    updateErrCntPrefStr.AppendWithConversion(crlKey);
230    if(importSuccessful){
231      PRUnichar *updateTime;
232      nsCAutoString updateTimeStr;
233      nsCString updateURL;
234      PRInt32 timingTypePref;
235      double dayCnt;
236      char *dayCntStr;
237      nsCAutoString updateTypePrefStr(CRL_AUTOUPDATE_TIMIINGTYPE_PREF);
238      nsCAutoString updateTimePrefStr(CRL_AUTOUPDATE_TIME_PREF);
239      nsCAutoString updateUrlPrefStr(CRL_AUTOUPDATE_URL_PREF);
240      nsCAutoString updateDayCntPrefStr(CRL_AUTOUPDATE_DAYCNT_PREF);
241      nsCAutoString updateFreqCntPrefStr(CRL_AUTOUPDATE_FREQCNT_PREF);
242      updateTypePrefStr.AppendWithConversion(crlKey);
243      updateTimePrefStr.AppendWithConversion(crlKey);
244      updateUrlPrefStr.AppendWithConversion(crlKey);
245      updateDayCntPrefStr.AppendWithConversion(crlKey);
246      updateFreqCntPrefStr.AppendWithConversion(crlKey);
247
248      pref->GetIntPref(updateTypePrefStr.get(),&timingTypePref);
249      
250      //Compute and update the next download instant
251      if(timingTypePref == TYPE_AUTOUPDATE_TIME_BASED){
252        pref->GetCharPref(updateDayCntPrefStr.get(),&dayCntStr);
253      }else{
254        pref->GetCharPref(updateFreqCntPrefStr.get(),&dayCntStr);
255      }
256      dayCnt = atof(dayCntStr);
257      nsMemory::Free(dayCntStr);
258
259      bool toBeRescheduled = false;
260      if(NS_SUCCEEDED(ComputeNextAutoUpdateTime(crlData, timingTypePref, dayCnt, &updateTime))){
261        updateTimeStr.AssignWithConversion(updateTime);
262        nsMemory::Free(updateTime);
263        pref->SetCharPref(updateTimePrefStr.get(),updateTimeStr.get());
264        //Now, check if this update time is already in the past. This would
265        //imply we have downloaded the same crl, or there is something wrong
266        //with the next update date. We will not reschedule this crl in this
267        //session anymore - or else, we land into a loop. It would anyway be
268        //imported once the browser is restarted.
269        PRTime nextTime;
270        PR_ParseTimeString(updateTimeStr.get(),true, &nextTime);
271        if(LL_CMP(nextTime, > , PR_Now())){
272          toBeRescheduled = true;
273        }
274      }
275      
276      //Update the url to download from, next time
277      crlData->GetLastFetchURL(updateURL);
278      pref->SetCharPref(updateUrlPrefStr.get(),updateURL.get());
279      
280      pref->SetIntPref(updateErrCntPrefStr.get(),0);
281      
282      if (toBeRescheduled) {
283        nsAutoString hashKey(crlKey);
284        nssComponent->RemoveCrlFromList(hashKey);
285        nssComponent->DefineNextTimer();
286      }
287
288    } else{
289      PRInt32 errCnt;
290      nsCAutoString errMsg;
291      nsCAutoString updateErrDetailPrefStr(CRL_AUTOUPDATE_ERRDETAIL_PREF);
292      updateErrDetailPrefStr.AppendWithConversion(crlKey);
293      errMsg.AssignWithConversion(errorMessage.get());
294      rv = pref->GetIntPref(updateErrCntPrefStr.get(),&errCnt);
295      if(NS_FAILED(rv))
296        errCnt = 0;
297
298      pref->SetIntPref(updateErrCntPrefStr.get(),errCnt+1);
299      pref->SetCharPref(updateErrDetailPrefStr.get(),errMsg.get());
300    }
301    prefSvc->SavePrefFile(nsnull);
302  }
303
304  return rv;
305}
306
307NS_IMETHODIMP 
308nsCRLManager::UpdateCRLFromURL( const PRUnichar *url, const PRUnichar* key, bool *res)
309{
310  nsresult rv;
311  nsAutoString downloadUrl(url);
312  nsAutoString dbKey(key);
313  nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
314  if(NS_FAILED(rv)){
315    *res = false;
316    return rv;
317  }
318
319  rv = nssComponent->DownloadCRLDirectly(downloadUrl, dbKey);
320  if(NS_FAILED(rv)){
321    *res = false;
322  } else {
323    *res = true;
324  }
325  return NS_OK;
326
327}
328
329NS_IMETHODIMP 
330nsCRLManager::RescheduleCRLAutoUpdate(void)
331{
332  nsresult rv;
333  nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
334  if(NS_FAILED(rv)){
335    return rv;
336  }
337  rv = nssComponent->DefineNextTimer();
338  return rv;
339}
340
341/**
342 * getCRLs
343 *
344 * Export a set of certs and keys from the database to a PKCS#12 file.
345 */
346NS_IMETHODIMP 
347nsCRLManager::GetCrls(nsIArray ** aCrls)
348{
349  nsNSSShutDownPreventionLock locker;
350  SECStatus sec_rv;
351  CERTCrlHeadNode *head = nsnull;
352  CERTCrlNode *node = nsnull;
353  nsresult rv;
354  nsCOMPtr<nsIMutableArray> crlsArray =
355    do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
356  if (NS_FAILED(rv)) {
357    return rv;
358  }
359
360  // Get the list of certs //
361  sec_rv = SEC_LookupCrls(CERT_GetDefaultCertDB(), &head, -1);
362  if (sec_rv != SECSuccess) {
363    return NS_ERROR_FAILURE;
364  }
365
366  if (head) {
367    for (node=head->first; node != nsnull; node = node->next) {
368
369      nsCOMPtr<nsICRLInfo> entry = new nsCRLInfo((node->crl));
370      crlsArray->AppendElement(entry, false);
371    }
372    PORT_FreeArena(head->arena, false);
373  }
374
375  *aCrls = crlsArray;
376  NS_IF_ADDREF(*aCrls);
377  return NS_OK;
378}
379
380/**
381 * deleteCrl
382 *
383 * Delete a Crl entry from the cert db.
384 */
385NS_IMETHODIMP 
386nsCRLManager::DeleteCrl(PRUint32 aCrlIndex)
387{
388  nsNSSShutDownPreventionLock locker;
389  CERTSignedCrl *realCrl = nsnull;
390  CERTCrlHeadNode *head = nsnull;
391  CERTCrlNode *node = nsnull;
392  SECStatus sec_rv;
393  PRUint32 i;
394
395  // Get the list of certs //
396  sec_rv = SEC_LookupCrls(CERT_GetDefaultCertDB(), &head, -1);
397  if (sec_rv != SECSuccess) {
398    return NS_ERROR_FAILURE;
399  }
400
401  if (head) {
402    for (i = 0, node=head->first; node != nsnull; i++, node = node->next) {
403      if (i != aCrlIndex) {
404        continue;
405      }
406      realCrl = SEC_FindCrlByName(CERT_GetDefaultCertDB(), &(node->crl->crl.derName), node->type);
407      SEC_DeletePermCRL(realCrl);
408      SEC_DestroyCrl(realCrl);
409      SSL_ClearSessionCache();
410    }
411    PORT_FreeArena(head->arena, false);
412  }
413  return NS_OK;
414}
415
416NS_IMETHODIMP
417nsCRLManager::ComputeNextAutoUpdateTime(nsICRLInfo *info, 
418  PRUint32 autoUpdateType, double dayCnt, PRUnichar **nextAutoUpdate)
419{
420  if (!info)
421    return NS_ERROR_FAILURE;
422
423  PRTime microsecInDayCnt;
424  PRTime now = PR_Now();
425  PRTime tempTime;
426  PRInt64 diff = 0;
427  PRInt64 secsInDay = 86400UL;
428  PRInt64 temp;
429  PRInt64 cycleCnt = 0;
430  PRInt64 secsInDayCnt;
431  PRFloat64 tmpData;
432  
433  LL_L2F(tmpData,secsInDay);
434  LL_MUL(tmpData,dayCnt,tmpData);
435  LL_F2L(secsInDayCnt,tmpData);
436  LL_MUL(microsecInDayCnt, secsInDayCnt, PR_USEC_PER_SEC);
437    
438  PRTime lastUpdate;
439  PRTime nextUpdate;
440  
441  nsresult rv;
442
443  rv = info->GetLastUpdate(&lastUpdate);
444  if (NS_FAILED(rv))
445    return rv;
446
447  rv = info->GetNextUpdate(&nextUpdate);
448  if (NS_FAILED(rv))
449    return rv;
450
451  switch (autoUpdateType) {
452  case TYPE_AUTOUPDATE_FREQ_BASED:
453    LL_SUB(diff, now, lastUpdate);             //diff is the no of micro sec between now and last update
454    LL_DIV(cycleCnt, diff, microsecInDayCnt);   //temp is the number of full cycles from lst update
455    LL_MOD(temp, diff, microsecInDayCnt);
456    if(!(LL_IS_ZERO(temp))) {
457      LL_ADD(cycleCnt,cycleCnt,1);            //no of complete cycles till next autoupdate instant
458    }
459    LL_MUL(temp,cycleCnt,microsecInDayCnt);    //micro secs from last update
460    LL_ADD(tempTime, lastUpdate, temp);
461    break;  
462  case TYPE_AUTOUPDATE_TIME_BASED:
463    LL_SUB(tempTime, nextUpdate, microsecInDayCnt);
464    break;
465  default:
466    return NS_ERROR_NOT_IMPLEMENTED;
467  }
468
469  //Now, a basic constraing is that the next auto update date can never be after
470  //next update, if one is defined
471  if(LL_CMP(nextUpdate , > , 0 )) {
472    if(LL_CMP(tempTime , > , nextUpdate)) {
473      tempTime = nextUpdate;
474    }
475  }
476
477  nsAutoString nextAutoUpdateDate;
478  PRExplodedTime explodedTime;
479  nsCOMPtr<nsIDateTimeFormat> dateFormatter = do_CreateInstance(NS_DATETIMEFORMAT_CONTRACTID, &rv);
480  if (NS_FAILED(rv))
481    return rv;
482  PR_ExplodeTime(tempTime, PR_GMTParameters, &explodedTime);
483  dateFormatter->FormatPRExplodedTime(nsnull, kDateFormatShort, kTimeFormatSeconds,
484                                      &explodedTime, nextAutoUpdateDate);
485  *nextAutoUpdate = ToNewUnicode(nextAutoUpdateDate);
486
487  return NS_OK;
488}
489