/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. #include "nsCRLManager.h"
  37. #include "nsCRLInfo.h"
  38. #include "nsCOMPtr.h"
  39. #include "nsIDateTimeFormat.h"
  40. #include "nsDateTimeFormatCID.h"
  41. #include "nsComponentManagerUtils.h"
  42. #include "nsReadableUtils.h"
  43. #include "nsNSSComponent.h"
  44. #include "nsCOMPtr.h"
  45. #include "nsICertificateDialogs.h"
  46. #include "nsIMutableArray.h"
  47. #include "nsIPrefService.h"
  48. #include "nsIPrefBranch.h"
  49. #include "nsNSSShutDown.h"
  50. #include "nsThreadUtils.h"
  51. #include "nsNSSCertHeader.h"
  52. #include "nspr.h"
  53. extern "C" {
  54. #include "pk11func.h"
  55. #include "certdb.h"
  56. #include "cert.h"
  57. #include "secerr.h"
  58. #include "nssb64.h"
  59. #include "secasn1.h"
  60. #include "secder.h"
  61. }
  62. #include "ssl.h"
  63. #include "ocsp.h"
  64. #include "plbase64.h"
  65. static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
  66. NS_IMPL_ISUPPORTS1(nsCRLManager, nsICRLManager)
  67. nsCRLManager::nsCRLManager()
  68. {
  69. }
  70. nsCRLManager::~nsCRLManager()
  71. {
  72. }
  73. NS_IMETHODIMP
  74. nsCRLManager::ImportCrl (PRUint8 *aData, PRUint32 aLength, nsIURI * aURI, PRUint32 aType, bool doSilentDownload, const PRUnichar* crlKey)
  75. {
  76. if (!NS_IsMainThread()) {
  77. NS_ERROR("nsCRLManager::ImportCrl called off the main thread");
  78. return NS_ERROR_NOT_SAME_THREAD;
  79. }
  80. nsNSSShutDownPreventionLock locker;
  81. nsresult rv;
  82. PRArenaPool *arena = NULL;
  83. CERTCertificate *caCert;
  84. SECItem derName = { siBuffer, NULL, 0 };
  85. SECItem derCrl;
  86. CERTSignedData sd;
  87. SECStatus sec_rv;
  88. CERTSignedCrl *crl;
  89. nsCAutoString url;
  90. nsCOMPtr<nsICRLInfo> crlData;
  91. bool importSuccessful;
  92. PRInt32 errorCode;
  93. nsString errorMessage;
  94. nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
  95. if (NS_FAILED(rv)) return rv;
  96. aURI->GetSpec(url);
  97. arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  98. if (!arena) {
  99. goto loser;
  100. }
  101. memset(&sd, 0, sizeof(sd));
  102. derCrl.data = (unsigned char*)aData;
  103. derCrl.len = aLength;
  104. sec_rv = CERT_KeyFromDERCrl(arena, &derCrl, &derName);
  105. if (sec_rv != SECSuccess) {
  106. goto loser;
  107. }
  108. caCert = CERT_FindCertByName(CERT_GetDefaultCertDB(), &derName);
  109. if (!caCert) {
  110. if (aType == SEC_KRL_TYPE){
  111. goto loser;
  112. }
  113. } else {
  114. sec_rv = SEC_ASN1DecodeItem(arena,
  115. &sd, SEC_ASN1_GET(CERT_SignedDataTemplate),
  116. &derCrl);
  117. if (sec_rv != SECSuccess) {
  118. goto loser;
  119. }
  120. sec_rv = CERT_VerifySignedData(&sd, caCert, PR_Now(),
  121. nsnull);
  122. if (sec_rv != SECSuccess) {
  123. goto loser;
  124. }
  125. }
  126. crl = SEC_NewCrl(CERT_GetDefaultCertDB(), const_cast<char*>(url.get()), &derCrl,
  127. aType);
  128. if (!crl) {
  129. goto loser;
  130. }
  131. crlData = new nsCRLInfo(crl);
  132. SSL_ClearSessionCache();
  133. SEC_DestroyCrl(crl);
  134. importSuccessful = true;
  135. goto done;
  136. loser:
  137. importSuccessful = false;
  138. errorCode = PR_GetError();
  139. switch (errorCode) {
  140. case SEC_ERROR_CRL_EXPIRED:
  141. nssComponent->GetPIPNSSBundleString("CrlImportFailureExpired", errorMessage);
  142. break;
  143. case SEC_ERROR_CRL_BAD_SIGNATURE:
  144. nssComponent->GetPIPNSSBundleString("CrlImportFailureBadSignature", errorMessage);
  145. break;
  146. case SEC_ERROR_CRL_INVALID:
  147. nssComponent->GetPIPNSSBundleString("CrlImportFailureInvalid", errorMessage);
  148. break;
  149. case SEC_ERROR_OLD_CRL:
  150. nssComponent->GetPIPNSSBundleString("CrlImportFailureOld", errorMessage);
  151. break;
  152. case SEC_ERROR_CRL_NOT_YET_VALID:
  153. nssComponent->GetPIPNSSBundleString("CrlImportFailureNotYetValid", errorMessage);
  154. break;
  155. default:
  156. nssComponent->GetPIPNSSBundleString("CrlImportFailureReasonUnknown", errorMessage);
  157. errorMessage.AppendInt(errorCode,16);
  158. break;
  159. }
  160. done:
  161. if(!doSilentDownload){
  162. if (!importSuccessful){
  163. nsString message;
  164. nsString temp;
  165. nssComponent->GetPIPNSSBundleString("CrlImportFailure1x", message);
  166. message.Append(NS_LITERAL_STRING("\n").get());
  167. message.Append(errorMessage);
  168. nssComponent->GetPIPNSSBundleString("CrlImportFailure2", temp);
  169. message.Append(NS_LITERAL_STRING("\n").get());
  170. message.Append(temp);
  171. nsNSSComponent::ShowAlertWithConstructedString(message);
  172. } else {
  173. nsCOMPtr<nsICertificateDialogs> certDialogs;
  174. // Not being able to display the success dialog should not
  175. // be a fatal error, so don't return a failure code.
  176. {
  177. nsPSMUITracker tracker;
  178. if (tracker.isUIForbidden()) {
  179. rv = NS_ERROR_NOT_AVAILABLE;
  180. }
  181. else {
  182. rv = ::getNSSDialogs(getter_AddRefs(certDialogs),
  183. NS_GET_IID(nsICertificateDialogs), NS_CERTIFICATEDIALOGS_CONTRACTID);
  184. }
  185. }
  186. if (NS_SUCCEEDED(rv)) {
  187. nsCOMPtr<nsIInterfaceRequestor> cxt = new PipUIContext();
  188. certDialogs->CrlImportStatusDialog(cxt, crlData);
  189. }
  190. }
  191. } else {
  192. if(crlKey == nsnull){
  193. return NS_ERROR_FAILURE;
  194. }
  195. nsCOMPtr<nsIPrefService> prefSvc = do_GetService(NS_PREFSERVICE_CONTRACTID,&rv);
  196. nsCOMPtr<nsIPrefBranch> pref = do_GetService(NS_PREFSERVICE_CONTRACTID,&rv);
  197. if (NS_FAILED(rv)){
  198. return rv;
  199. }
  200. nsCAutoString updateErrCntPrefStr(CRL_AUTOUPDATE_ERRCNT_PREF);
  201. updateErrCntPrefStr.AppendWithConversion(crlKey);
  202. if(importSuccessful){
  203. PRUnichar *updateTime;
  204. nsCAutoString updateTimeStr;
  205. nsCString updateURL;
  206. PRInt32 timingTypePref;
  207. double dayCnt;
  208. char *dayCntStr;
  209. nsCAutoString updateTypePrefStr(CRL_AUTOUPDATE_TIMIINGTYPE_PREF);
  210. nsCAutoString updateTimePrefStr(CRL_AUTOUPDATE_TIME_PREF);
  211. nsCAutoString updateUrlPrefStr(CRL_AUTOUPDATE_URL_PREF);
  212. nsCAutoString updateDayCntPrefStr(CRL_AUTOUPDATE_DAYCNT_PREF);
  213. nsCAutoString updateFreqCntPrefStr(CRL_AUTOUPDATE_FREQCNT_PREF);
  214. updateTypePrefStr.AppendWithConversion(crlKey);
  215. updateTimePrefStr.AppendWithConversion(crlKey);
  216. updateUrlPrefStr.AppendWithConversion(crlKey);
  217. updateDayCntPrefStr.AppendWithConversion(crlKey);
  218. updateFreqCntPrefStr.AppendWithConversion(crlKey);
  219. pref->GetIntPref(updateTypePrefStr.get(),&timingTypePref);
  220. //Compute and update the next download instant
  221. if(timingTypePref == TYPE_AUTOUPDATE_TIME_BASED){
  222. pref->GetCharPref(updateDayCntPrefStr.get(),&dayCntStr);
  223. }else{
  224. pref->GetCharPref(updateFreqCntPrefStr.get(),&dayCntStr);
  225. }
  226. dayCnt = atof(dayCntStr);
  227. nsMemory::Free(dayCntStr);
  228. bool toBeRescheduled = false;
  229. if(NS_SUCCEEDED(ComputeNextAutoUpdateTime(crlData, timingTypePref, dayCnt, &updateTime))){
  230. updateTimeStr.AssignWithConversion(updateTime);
  231. nsMemory::Free(updateTime);
  232. pref->SetCharPref(updateTimePrefStr.get(),updateTimeStr.get());
  233. //Now, check if this update time is already in the past. This would
  234. //imply we have downloaded the same crl, or there is something wrong
  235. //with the next update date. We will not reschedule this crl in this
  236. //session anymore - or else, we land into a loop. It would anyway be
  237. //imported once the browser is restarted.
  238. PRTime nextTime;
  239. PR_ParseTimeString(updateTimeStr.get(),true, &nextTime);
  240. if(LL_CMP(nextTime, > , PR_Now())){
  241. toBeRescheduled = true;
  242. }
  243. }
  244. //Update the url to download from, next time
  245. crlData->GetLastFetchURL(updateURL);
  246. pref->SetCharPref(updateUrlPrefStr.get(),updateURL.get());
  247. pref->SetIntPref(updateErrCntPrefStr.get(),0);
  248. if (toBeRescheduled) {
  249. nsAutoString hashKey(crlKey);
  250. nssComponent->RemoveCrlFromList(hashKey);
  251. nssComponent->DefineNextTimer();
  252. }
  253. } else{
  254. PRInt32 errCnt;
  255. nsCAutoString errMsg;
  256. nsCAutoString updateErrDetailPrefStr(CRL_AUTOUPDATE_ERRDETAIL_PREF);
  257. updateErrDetailPrefStr.AppendWithConversion(crlKey);
  258. errMsg.AssignWithConversion(errorMessage.get());
  259. rv = pref->GetIntPref(updateErrCntPrefStr.get(),&errCnt);
  260. if(NS_FAILED(rv))
  261. errCnt = 0;
  262. pref->SetIntPref(updateErrCntPrefStr.get(),errCnt+1);
  263. pref->SetCharPref(updateErrDetailPrefStr.get(),errMsg.get());
  264. }
  265. prefSvc->SavePrefFile(nsnull);
  266. }
  267. return rv;
  268. }
  269. NS_IMETHODIMP
  270. nsCRLManager::UpdateCRLFromURL( const PRUnichar *url, const PRUnichar* key, bool *res)
  271. {
  272. nsresult rv;
  273. nsAutoString downloadUrl(url);
  274. nsAutoString dbKey(key);
  275. nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
  276. if(NS_FAILED(rv)){
  277. *res = false;
  278. return rv;
  279. }
  280. rv = nssComponent->DownloadCRLDirectly(downloadUrl, dbKey);
  281. if(NS_FAILED(rv)){
  282. *res = false;
  283. } else {
  284. *res = true;
  285. }
  286. return NS_OK;
  287. }
  288. NS_IMETHODIMP
  289. nsCRLManager::RescheduleCRLAutoUpdate(void)
  290. {
  291. nsresult rv;
  292. nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
  293. if(NS_FAILED(rv)){
  294. return rv;
  295. }
  296. rv = nssComponent->DefineNextTimer();
  297. return rv;
  298. }
  299. /**
  300. * getCRLs
  301. *
  302. * Export a set of certs and keys from the database to a PKCS#12 file.
  303. */
  304. NS_IMETHODIMP
  305. nsCRLManager::GetCrls(nsIArray ** aCrls)
  306. {
  307. nsNSSShutDownPreventionLock locker;
  308. SECStatus sec_rv;
  309. CERTCrlHeadNode *head = nsnull;
  310. CERTCrlNode *node = nsnull;
  311. nsresult rv;
  312. nsCOMPtr<nsIMutableArray> crlsArray =
  313. do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
  314. if (NS_FAILED(rv)) {
  315. return rv;
  316. }
  317. // Get the list of certs //
  318. sec_rv = SEC_LookupCrls(CERT_GetDefaultCertDB(), &head, -1);
  319. if (sec_rv != SECSuccess) {
  320. return NS_ERROR_FAILURE;
  321. }
  322. if (head) {
  323. for (node=head->first; node != nsnull; node = node->next) {
  324. nsCOMPtr<nsICRLInfo> entry = new nsCRLInfo((node->crl));
  325. crlsArray->AppendElement(entry, false);
  326. }
  327. PORT_FreeArena(head->arena, false);
  328. }
  329. *aCrls = crlsArray;
  330. NS_IF_ADDREF(*aCrls);
  331. return NS_OK;
  332. }
  333. /**
  334. * deleteCrl
  335. *
  336. * Delete a Crl entry from the cert db.
  337. */
  338. NS_IMETHODIMP
  339. nsCRLManager::DeleteCrl(PRUint32 aCrlIndex)
  340. {
  341. nsNSSShutDownPreventionLock locker;
  342. CERTSignedCrl *realCrl = nsnull;
  343. CERTCrlHeadNode *head = nsnull;
  344. CERTCrlNode *node = nsnull;
  345. SECStatus sec_rv;
  346. PRUint32 i;
  347. // Get the list of certs //
  348. sec_rv = SEC_LookupCrls(CERT_GetDefaultCertDB(), &head, -1);
  349. if (sec_rv != SECSuccess) {
  350. return NS_ERROR_FAILURE;
  351. }
  352. if (head) {
  353. for (i = 0, node=head->first; node != nsnull; i++, node = node->next) {
  354. if (i != aCrlIndex) {
  355. continue;
  356. }
  357. realCrl = SEC_FindCrlByName(CERT_GetDefaultCertDB(), &(node->crl->crl.derName), node->type);
  358. SEC_DeletePermCRL(realCrl);
  359. SEC_DestroyCrl(realCrl);
  360. SSL_ClearSessionCache();
  361. }
  362. PORT_FreeArena(head->arena, false);
  363. }
  364. return NS_OK;
  365. }
  366. NS_IMETHODIMP
  367. nsCRLManager::ComputeNextAutoUpdateTime(nsICRLInfo *info,
  368. PRUint32 autoUpdateType, double dayCnt, PRUnichar **nextAutoUpdate)
  369. {
  370. if (!info)
  371. return NS_ERROR_FAILURE;
  372. PRTime microsecInDayCnt;
  373. PRTime now = PR_Now();
  374. PRTime tempTime;
  375. PRInt64 diff = 0;
  376. PRInt64 secsInDay = 86400UL;
  377. PRInt64 temp;
  378. PRInt64 cycleCnt = 0;
  379. PRInt64 secsInDayCnt;
  380. PRFloat64 tmpData;
  381. LL_L2F(tmpData,secsInDay);
  382. LL_MUL(tmpData,dayCnt,tmpData);
  383. LL_F2L(secsInDayCnt,tmpData);
  384. LL_MUL(microsecInDayCnt, secsInDayCnt, PR_USEC_PER_SEC);
  385. PRTime lastUpdate;
  386. PRTime nextUpdate;
  387. nsresult rv;
  388. rv = info->GetLastUpdate(&lastUpdate);
  389. if (NS_FAILED(rv))
  390. return rv;
  391. rv = info->GetNextUpdate(&nextUpdate);
  392. if (NS_FAILED(rv))
  393. return rv;
  394. switch (autoUpdateType) {
  395. case TYPE_AUTOUPDATE_FREQ_BASED:
  396. LL_SUB(diff, now, lastUpdate); //diff is the no of micro sec between now and last update
  397. LL_DIV(cycleCnt, diff, microsecInDayCnt); //temp is the number of full cycles from lst update
  398. LL_MOD(temp, diff, microsecInDayCnt);
  399. if(!(LL_IS_ZERO(temp))) {
  400. LL_ADD(cycleCnt,cycleCnt,1); //no of complete cycles till next autoupdate instant
  401. }
  402. LL_MUL(temp,cycleCnt,microsecInDayCnt); //micro secs from last update
  403. LL_ADD(tempTime, lastUpdate, temp);
  404. break;
  405. case TYPE_AUTOUPDATE_TIME_BASED:
  406. LL_SUB(tempTime, nextUpdate, microsecInDayCnt);
  407. break;
  408. default:
  409. return NS_ERROR_NOT_IMPLEMENTED;
  410. }
  411. //Now, a basic constraing is that the next auto update date can never be after
  412. //next update, if one is defined
  413. if(LL_CMP(nextUpdate , > , 0 )) {
  414. if(LL_CMP(tempTime , > , nextUpdate)) {
  415. tempTime = nextUpdate;
  416. }
  417. }
  418. nsAutoString nextAutoUpdateDate;
  419. PRExplodedTime explodedTime;
  420. nsCOMPtr<nsIDateTimeFormat> dateFormatter = do_CreateInstance(NS_DATETIMEFORMAT_CONTRACTID, &rv);
  421. if (NS_FAILED(rv))
  422. return rv;
  423. PR_ExplodeTime(tempTime, PR_GMTParameters, &explodedTime);
  424. dateFormatter->FormatPRExplodedTime(nsnull, kDateFormatShort, kTimeFormatSeconds,
  425. &explodedTime, nextAutoUpdateDate);
  426. *nextAutoUpdate = ToNewUnicode(nextAutoUpdateDate);
  427. return NS_OK;
  428. }