2
* The contents of this file are subject to the Mozilla Public
3
* License Version 1.1 (the "License"); you may not use this file
4
* except in compliance with the License. You may obtain a copy of
5
* the License at http://www.mozilla.org/MPL/
7
* Software distributed under the License is distributed on an "AS
8
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9
* implied. See the License for the specific language governing
10
* rights and limitations under the License.
12
* The Original Code is the Netscape security libraries.
14
* The Initial Developer of the Original Code is Netscape
15
* Communications Corporation. Portions created by Netscape are
16
* Copyright (C) 2000 Netscape Communications Corporation. All
21
* Alternatively, the contents of this file may be used under the
22
* terms of the GNU General Public License Version 2 or later (the
23
* "GPL"), in which case the provisions of the GPL are applicable
24
* instead of those above. If you wish to allow use of your
25
* version of this file only under the terms of the GPL and not to
26
* allow others to use your version of this file under the MPL,
27
* indicate your decision by deleting the provisions above and
28
* replace them with the notice and other provisions required by
29
* the GPL. If you do not delete the provisions above, a recipient
30
* may use your version of this file under either the MPL or the
35
#include "nsCRLManager.h"
36
#include "nsCRLInfo.h"
39
#include "nsIDateTimeFormat.h"
40
#include "nsDateTimeFormatCID.h"
41
#include "nsComponentManagerUtils.h"
42
#include "nsReadableUtils.h"
43
#include "nsNSSComponent.h"
44
#include "nsIWindowWatcher.h"
46
#include "nsIPrompt.h"
47
#include "nsICertificateDialogs.h"
49
#include "nsNSSShutDown.h"
51
#include "nsNSSCertHeader.h"
67
static NS_DEFINE_CID(kDateTimeFormatCID, NS_DATETIMEFORMAT_CID);
68
static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
70
NS_IMPL_ISUPPORTS1(nsCRLManager, nsICRLManager)
72
nsCRLManager::nsCRLManager()
76
nsCRLManager::~nsCRLManager()
81
nsCRLManager::ImportCrl (PRUint8 *aData, PRUint32 aLength, nsIURI * aURI, PRUint32 aType, PRBool doSilentDonwload, const PRUnichar* crlKey)
83
nsNSSShutDownPreventionLock locker;
85
PRArenaPool *arena = NULL;
86
CERTCertificate *caCert;
87
SECItem derName = { siBuffer, NULL, 0 };
93
nsCOMPtr<nsICRLInfo> crlData;
94
PRBool importSuccessful;
96
nsString errorMessage;
98
nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
99
if (NS_FAILED(rv)) return rv;
102
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
106
memset(&sd, 0, sizeof(sd));
108
derCrl.data = (unsigned char*)aData;
109
derCrl.len = aLength;
110
sec_rv = CERT_KeyFromDERCrl(arena, &derCrl, &derName);
111
if (sec_rv != SECSuccess) {
115
caCert = CERT_FindCertByName(CERT_GetDefaultCertDB(), &derName);
117
if (aType == SEC_KRL_TYPE){
121
sec_rv = SEC_ASN1DecodeItem(arena,
122
&sd, SEC_ASN1_GET(CERT_SignedDataTemplate),
124
if (sec_rv != SECSuccess) {
127
sec_rv = CERT_VerifySignedData(&sd, caCert, PR_Now(),
129
if (sec_rv != SECSuccess) {
134
crl = SEC_NewCrl(CERT_GetDefaultCertDB(), NS_CONST_CAST(char*, url.get()), &derCrl,
141
crlData = new nsCRLInfo(crl);
142
SSL_ClearSessionCache();
145
importSuccessful = PR_TRUE;
149
importSuccessful = PR_FALSE;
150
errorCode = PR_GetError();
152
case SEC_ERROR_CRL_EXPIRED:
153
nssComponent->GetPIPNSSBundleString("CrlImportFailureExpired", errorMessage);
156
case SEC_ERROR_CRL_BAD_SIGNATURE:
157
nssComponent->GetPIPNSSBundleString("CrlImportFailureBadSignature", errorMessage);
160
case SEC_ERROR_CRL_INVALID:
161
nssComponent->GetPIPNSSBundleString("CrlImportFailureInvalid", errorMessage);
164
case SEC_ERROR_OLD_CRL:
165
nssComponent->GetPIPNSSBundleString("CrlImportFailureOld", errorMessage);
168
case SEC_ERROR_CRL_NOT_YET_VALID:
169
nssComponent->GetPIPNSSBundleString("CrlImportFailureNotYetValid", errorMessage);
173
nssComponent->GetPIPNSSBundleString("CrlImportFailureReasonUnknown", errorMessage);
174
errorMessage.AppendInt(errorCode,16);
180
if(!doSilentDonwload){
181
if (!importSuccessful){
184
nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
185
nsCOMPtr<nsIPrompt> prompter;
187
wwatch->GetNewPrompter(0, getter_AddRefs(prompter));
188
nssComponent->GetPIPNSSBundleString("CrlImportFailure1", message);
189
message.Append(NS_LITERAL_STRING("\n").get());
190
message.Append(errorMessage);
191
nssComponent->GetPIPNSSBundleString("CrlImportFailure2", temp);
192
message.Append(NS_LITERAL_STRING("\n").get());
193
message.Append(temp);
196
nsPSMUITracker tracker;
197
if (!tracker.isUIForbidden()) {
198
prompter->Alert(0, message.get());
203
nsCOMPtr<nsICertificateDialogs> certDialogs;
204
// Not being able to display the success dialog should not
205
// be a fatal error, so don't return a failure code.
207
nsPSMUITracker tracker;
208
if (tracker.isUIForbidden()) {
209
rv = NS_ERROR_NOT_AVAILABLE;
212
rv = ::getNSSDialogs(getter_AddRefs(certDialogs),
213
NS_GET_IID(nsICertificateDialogs), NS_CERTIFICATEDIALOGS_CONTRACTID);
216
if (NS_SUCCEEDED(rv)) {
217
nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
218
certDialogs->CrlImportStatusDialog(cxt, crlData);
222
if(crlKey == nsnull){
223
return NS_ERROR_FAILURE;
225
nsCOMPtr<nsIPref> pref = do_GetService(NS_PREF_CONTRACTID,&rv);
230
nsCAutoString updateErrCntPrefStr(CRL_AUTOUPDATE_ERRCNT_PREF);
231
updateErrCntPrefStr.AppendWithConversion(crlKey);
232
if(importSuccessful){
233
PRUnichar *updateTime;
234
nsCAutoString updateTimeStr;
236
PRInt32 timingTypePref;
239
nsCAutoString updateTypePrefStr(CRL_AUTOUPDATE_TIMIINGTYPE_PREF);
240
nsCAutoString updateTimePrefStr(CRL_AUTOUPDATE_TIME_PREF);
241
nsCAutoString updateUrlPrefStr(CRL_AUTOUPDATE_URL_PREF);
242
nsCAutoString updateDayCntPrefStr(CRL_AUTOUPDATE_DAYCNT_PREF);
243
nsCAutoString updateFreqCntPrefStr(CRL_AUTOUPDATE_FREQCNT_PREF);
244
updateTypePrefStr.AppendWithConversion(crlKey);
245
updateTimePrefStr.AppendWithConversion(crlKey);
246
updateUrlPrefStr.AppendWithConversion(crlKey);
247
updateDayCntPrefStr.AppendWithConversion(crlKey);
248
updateFreqCntPrefStr.AppendWithConversion(crlKey);
250
pref->GetIntPref(updateTypePrefStr.get(),&timingTypePref);
252
//Compute and update the next download instant
253
if(timingTypePref == TYPE_AUTOUPDATE_TIME_BASED){
254
pref->GetCharPref(updateDayCntPrefStr.get(),&dayCntStr);
256
pref->GetCharPref(updateFreqCntPrefStr.get(),&dayCntStr);
258
dayCnt = atof(dayCntStr);
259
nsMemory::Free(dayCntStr);
261
PRBool toBeRescheduled = PR_FALSE;
262
if(NS_SUCCEEDED(ComputeNextAutoUpdateTime(crlData, timingTypePref, dayCnt, &updateTime))){
263
updateTimeStr.AssignWithConversion(updateTime);
264
nsMemory::Free(updateTime);
265
pref->SetCharPref(updateTimePrefStr.get(),updateTimeStr.get());
266
//Now, check if this update time is already in the past. This would
267
//imply we have downloaded the same crl, or there is something wrong
268
//with the next update date. We will not reschedule this crl in this
269
//session anymore - or else, we land into a loop. It would anyway be
270
//imported once the browser is restarted.
272
PR_ParseTimeString(updateTimeStr.get(),PR_TRUE, &nextTime);
273
if(LL_CMP(nextTime, > , PR_Now())){
274
toBeRescheduled = PR_TRUE;
278
//Update the url to download from, next time
279
crlData->GetLastFetchURL(updateURL);
280
pref->SetCharPref(updateUrlPrefStr.get(),updateURL.get());
282
pref->SetIntPref(updateErrCntPrefStr.get(),0);
283
pref->SavePrefFile(nsnull);
285
if(toBeRescheduled == PR_TRUE){
286
nsAutoString hashKey(crlKey);
287
nssComponent->RemoveCrlFromList(hashKey);
288
nssComponent->DefineNextTimer();
293
nsCAutoString errMsg;
294
nsCAutoString updateErrDetailPrefStr(CRL_AUTOUPDATE_ERRDETAIL_PREF);
295
updateErrDetailPrefStr.AppendWithConversion(crlKey);
296
errMsg.AssignWithConversion(errorMessage.get());
297
rv = pref->GetIntPref(updateErrCntPrefStr.get(),&errCnt);
298
if( (NS_FAILED(rv)) || (errCnt ==0)){
299
pref->SetIntPref(updateErrCntPrefStr.get(),1);
301
pref->SetIntPref(updateErrCntPrefStr.get(),errCnt+1);
303
pref->SetCharPref(updateErrDetailPrefStr.get(),errMsg.get());
304
pref->SavePrefFile(nsnull);
312
nsCRLManager::UpdateCRLFromURL( const PRUnichar *url, const PRUnichar* key, PRBool *res)
315
nsAutoString downloadUrl(url);
316
nsAutoString dbKey(key);
317
nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
323
rv = nssComponent->DownloadCRLDirectly(downloadUrl, dbKey);
334
nsCRLManager::RescheduleCRLAutoUpdate(void)
337
nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
341
rv = nssComponent->DefineNextTimer();
348
* Export a set of certs and keys from the database to a PKCS#12 file.
352
nsCRLManager::GetCrls(nsIArray ** aCrls)
354
nsNSSShutDownPreventionLock locker;
356
CERTCrlHeadNode *head = nsnull;
357
CERTCrlNode *node = nsnull;
358
nsCOMPtr<nsIMutableArray> crlsArray;
360
rv = NS_NewArray(getter_AddRefs(crlsArray));
365
// Get the list of certs //
366
sec_rv = SEC_LookupCrls(CERT_GetDefaultCertDB(), &head, -1);
367
if (sec_rv != SECSuccess) {
372
for (node=head->first; node != nsnull; node = node->next) {
374
nsCOMPtr<nsICRLInfo> entry = new nsCRLInfo((node->crl));
375
crlsArray->AppendElement(entry, PR_FALSE);
377
PORT_FreeArena(head->arena, PR_FALSE);
381
NS_IF_ADDREF(*aCrls);
384
return NS_ERROR_FAILURE;;
390
* Delete a Crl entry from the cert db.
393
nsCRLManager::DeleteCrl(PRUint32 aCrlIndex)
395
nsNSSShutDownPreventionLock locker;
396
CERTSignedCrl *realCrl = nsnull;
397
CERTCrlHeadNode *head = nsnull;
398
CERTCrlNode *node = nsnull;
402
// Get the list of certs //
403
sec_rv = SEC_LookupCrls(CERT_GetDefaultCertDB(), &head, -1);
404
if (sec_rv != SECSuccess) {
409
for (i = 0, node=head->first; node != nsnull; i++, node = node->next) {
410
if (i != aCrlIndex) {
413
realCrl = SEC_FindCrlByName(CERT_GetDefaultCertDB(), &(node->crl->crl.derName), node->type);
414
SEC_DeletePermCRL(realCrl);
415
SEC_DestroyCrl(realCrl);
416
SSL_ClearSessionCache();
418
PORT_FreeArena(head->arena, PR_FALSE);
422
return NS_ERROR_FAILURE;;
426
nsCRLManager::ComputeNextAutoUpdateTime(nsICRLInfo *info,
427
PRUint32 autoUpdateType, double dayCnt, PRUnichar **nextAutoUpdate)
430
return NS_ERROR_FAILURE;
432
PRTime microsecInDayCnt;
433
PRTime now = PR_Now();
436
PRInt64 secsInDay = 86400UL;
438
PRInt64 cycleCnt = 0;
439
PRInt64 secsInDayCnt;
442
LL_L2F(tmpData,secsInDay);
443
LL_MUL(tmpData,dayCnt,tmpData);
444
LL_F2L(secsInDayCnt,tmpData);
445
LL_MUL(microsecInDayCnt, secsInDayCnt, PR_USEC_PER_SEC);
452
rv = info->GetLastUpdate(&lastUpdate);
456
rv = info->GetNextUpdate(&nextUpdate);
460
switch (autoUpdateType) {
461
case TYPE_AUTOUPDATE_FREQ_BASED:
462
LL_SUB(diff, now, lastUpdate); //diff is the no of micro sec between now and last update
463
LL_DIV(cycleCnt, diff, microsecInDayCnt); //temp is the number of full cycles from lst update
464
LL_MOD(temp, diff, microsecInDayCnt);
465
if(!(LL_IS_ZERO(temp))) {
466
LL_ADD(cycleCnt,cycleCnt,1); //no of complete cycles till next autoupdate instant
468
LL_MUL(temp,cycleCnt,microsecInDayCnt); //micro secs from last update
469
LL_ADD(tempTime, lastUpdate, temp);
471
case TYPE_AUTOUPDATE_TIME_BASED:
472
LL_SUB(tempTime, nextUpdate, microsecInDayCnt);
475
return NS_ERROR_NOT_IMPLEMENTED;
478
//Now, a basic constraing is that the next auto update date can never be after
479
//next update, if one is defined
480
if(LL_CMP(nextUpdate , > , 0 )) {
481
if(LL_CMP(tempTime , > , nextUpdate)) {
482
tempTime = nextUpdate;
486
nsAutoString nextAutoUpdateDate;
487
PRExplodedTime explodedTime;
488
nsCOMPtr<nsIDateTimeFormat> dateFormatter = do_CreateInstance(kDateTimeFormatCID, &rv);
491
PR_ExplodeTime(tempTime, PR_GMTParameters, &explodedTime);
492
dateFormatter->FormatPRExplodedTime(nsnull, kDateFormatShort, kTimeFormatSeconds,
493
&explodedTime, nextAutoUpdateDate);
494
*nextAutoUpdate = ToNewUnicode(nextAutoUpdateDate);