Bug 1114816 - Implement TLS intolerance fallback whitelist. r=keeler, a=lmandel
authorMasatoshi Kimura <VYV03354@nifty.ne.jp>
Thu, 29 Jan 2015 03:52:42 +0900
changeset 249673 1e9694bbffaa4179d7163c3f42ff6b430760e0e7
parent 249672 874b03be37f26a0b89a621b3df746a32df0f5eff
child 249674 10d1df99ba8e2ca1386cc7a555bee7ad85a25b9a
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskeeler, lmandel
bugs1114816, 1128763, 1128227
milestone37.0a2
Bug 1114816 - Implement TLS intolerance fallback whitelist. r=keeler, a=lmandel * * * Bug 1128763 - Do insecure fallback after PR_CONNECT_RESET_ERROR for whitelisted sites only. r=keeler * * * Bug 1128227 - Add a static TLS insecure fallback whitelist. r=keeler
browser/devtools/webconsole/test/browser_webconsole_certificate_messages.js
netwerk/base/public/security-prefs.js
security/manager/ssl/src/IntolerantFallbackList.inc
security/manager/ssl/src/nsNSSIOLayer.cpp
security/manager/ssl/src/nsNSSIOLayer.h
security/manager/ssl/tests/gtest/TLSIntoleranceTest.cpp
security/manager/tools/genIntolerantFallbackList.js
--- a/browser/devtools/webconsole/test/browser_webconsole_certificate_messages.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_certificate_messages.js
@@ -12,20 +12,22 @@ let gWebconsoleTests = [
    name: "SHA1 warning displayed successfully",
    warning: ["SHA-1"], nowarning: ["SSL 3.0", "RC4"]},
   {url: "https://ssl3.example.com" + TEST_URI_PATH,
    name: "SSL3 warning displayed successfully",
    pref: [["security.tls.version.min", 0]],
    warning: ["SSL 3.0"], nowarning: ["SHA-1", "RC4"]},
   {url: "https://rc4.example.com" + TEST_URI_PATH,
    name: "RC4 warning displayed successfully",
+   pref: [["security.tls.insecure_fallback_hosts", "rc4.example.com"]],
    warning: ["RC4"], nowarning: ["SHA-1", "SSL 3.0"]},
   {url: "https://ssl3rc4.example.com" + TEST_URI_PATH,
    name: "SSL3 and RC4 warning displayed successfully",
-   pref: [["security.tls.version.min", 0]],
+   pref: [["security.tls.version.min", 0],
+          ["security.tls.insecure_fallback_hosts", "ssl3rc4.example.com"]],
    warning: ["SSL 3.0", "RC4"], nowarning: ["SHA-1"]},
   {url: "https://sha256ee.example.com" + TEST_URI_PATH,
    name: "SSL warnings appropriately not present",
    warning: [], nowarning: ["SHA-1", "SSL 3.0", "RC4"]},
 ];
 const TRIGGER_MSG = "If you haven't seen ssl warnings yet, you won't";
 
 let gHud = undefined, gContentBrowser;
--- a/netwerk/base/public/security-prefs.js
+++ b/netwerk/base/public/security-prefs.js
@@ -1,15 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 pref("security.tls.version.min", 1);
 pref("security.tls.version.max", 3);
 pref("security.tls.version.fallback-limit", 3);
+pref("security.tls.insecure_fallback_hosts", "");
+pref("security.tls.insecure_fallback_hosts.use_static_list", true);
 
 pref("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref", false);
 pref("security.ssl.renego_unrestricted_hosts", "");
 pref("security.ssl.treat_unsafe_negotiation_as_broken", false);
 pref("security.ssl.require_safe_negotiation",  false);
 pref("security.ssl.warn_missing_rfc5746",  1);
 pref("security.ssl.enable_ocsp_stapling", true);
 pref("security.ssl.enable_false_start", true);
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/src/IntolerantFallbackList.inc
@@ -0,0 +1,675 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+///////////////////////////////////////////////////////////////////////////////
+// This is an automatically generated file. If you're not
+// nsNSSIOLayer.cpp, you shouldn't be #including it.
+///////////////////////////////////////////////////////////////////////////////
+
+static const char* const kIntolerantFallbackList[] =
+{
+  "aacoprod.aacounty.org",
+  "access.uwstout.edu",
+  "account.61.com.tw",
+  "acs.sia.eu", // RC4
+  "actiononline.stpete.org",
+  "actu.reunion.fr",
+  "ad401k.sbisec.co.jp",
+  "adman.you.gr",
+  "affiliatewalla.com",
+  "airportwifi.com", // bug 1116891
+  "allyours.virginmedia.com",
+  "amss.mobilicity.ca",
+  "ap.meitetsuunyu.co.jp",
+  "apps.amerch.com",
+  "apps.fpcu.org",
+  "apps.sasken.com",
+  "appsrv.restat.com",
+  "arts.ac.uk",
+  "ascii.jp",
+  "asiaenglish.visitkorea.or.kr",
+  "asiointi.hel.fi",
+  "asknow.com",
+  "auction.kuronekoyamato.co.jp", // bug 1128366
+  "b2b.feib.com.tw",
+  "bcccbookstore.bccc.edu",
+  "bedrijfsprofiel.graydon.nl",
+  "beehive.miit.ru",
+  "bettertrades.com",
+  "bianmin.chinapay.com",
+  "big5chinese.visitkorea.or.kr",
+  "bigflix.com",
+  "blackboard.tru.ca",
+  "blogwatcher.co.jp",
+  "blueportal.vanmarcke.be",
+  "bmypage.kuronekoyamato.co.jp", // bug 1128366
+  "books.spec.whatwg.org", // RC4
+  "books.wwnorton.com", // bug 1116891
+  "bookstore.alma.edu",
+  "bookstore.assumption.edu",
+  "bookstore.bsc.edu",
+  "bookstore.calbaptist.edu",
+  "bookstore.cleary.edu",
+  "bookstore.doane.edu",
+  "bookstore.drury.edu",
+  "bookstore.grinnell.edu",
+  "bookstore.hacc.edu",
+  "bookstore.hancockcollege.edu",
+  "bookstore.icc.edu",
+  "bookstore.northern.edu",
+  "bookstore.ntc.edu",
+  "bookstore.palmer.edu",
+  "bookstore.phcc.edu",
+  "bookstore.reed.edu",
+  "bookstore.smc.edu",
+  "bookstore.snu.edu",
+  "bookstore.sunyjefferson.edu",
+  "bookstore.tridenttech.edu",
+  "bookstore.wbu.edu",
+  "bookstore.wscc.edu",
+  "bursar.ou.edu",
+  "buttons.verticalresponse.com",
+  "buy.liker.com.tw",
+  "c2.kuronekoyamato.co.jp", // bug 1128366
+  "c2g.jupiter.fl.us",
+  "carcraft.co.uk",
+  "cart.pcpitstop.com", // bug 1116891
+  "cbsfilms.epk.tv",
+  "cbsfnotes1.blood.org.tw",
+  "central.acadiau.ca",
+  "chinese.visitkorea.or.kr",
+  "chintai.mibucorp.co.jp",
+  "click2gov.alpharetta.ga.us",
+  "click2gov.sanangelotexas.us",
+  "clientes.chilectra.cl",
+  "club.guosen.com.cn",
+  "cmypage.kuronekoyamato.co.jp", // bug 1112110
+  "coagov.aurora-il.org",
+  "codem.codemasters.com",
+  "collegestore.hfcc.edu",
+  "comune.milano.it",
+  "contact-us.kuronekoyamato.co.jp", // bug 1128366
+  "corporate.webfg.com",
+  "corporbank.nbcb.com.cn",
+  "coursecatalog.harvard.edu",
+  "courtapps.utcourts.gov",
+  "crm.et2008.com",
+  "crossroads.schneider.com",
+  "crypticstudios.com",
+  "cs.tokai-tv.com",
+  "cualerts.dupaco.com", // bug 1116892
+  "cwu.edu",
+  "dbank.hxb.com.cn",
+  "dealer.autobytel.com",
+  "dealer.autoc-one.jp",
+  "developer.fsmoffice.net",
+  "developer.palm.com",
+  "developers.whatwg.org", // RC4
+  "dheb.delavska-hranilnica.si",
+  "digibet.com",
+  "dinsmore.fsmoffice.net",
+  "direct-teleshop.jp",
+  "direct.graydon.nl",
+  "dream-prize.com",
+  "dwwsyw.bjgjj.gov.cn",
+  "e-mediador.fiatc.es",
+  "e-profesional.fiatc.es",
+  "eagleslanding.lamission.edu",
+  "eatm.scsb.com.tw",
+  "ebank-public.hzbank.com.cn",
+  "ebank.accessbankplc.com",
+  "ebank.hxb.com.cn",
+  "ebank.hzbank.com.cn",
+  "ebpp.airtel.lk",
+  "ec-line.cn",
+  "ec.kotoha.co.jp",
+  "echo.com",
+  "echotrak.com",
+  "ecourses.uthscsa.edu",
+  "egov.leaguecity.com",
+  "emaildvla.direct.gov.uk", // bug 1116891
+  "encoding.spec.whatwg.org", // RC4
+  "english.visitkorea.or.kr",
+  "epk.tv",
+  "epolicija.lt",
+  "eservices.palomar.edu",
+  "etimebanker.bankofthewest.com", // bug 1127204
+  "etrade.ftft.com.tw",
+  "event.kasite.net",
+  "extra.ytk.fi",
+  "extranet.eurocontrol.int",
+  "ez.cityofchesapeake.net",
+  "ezpay.com.tw",
+  "fallback.test", // Used by gtest
+  "fastlane.echo.com",
+  "fetch.spec.whatwg.org", // RC4
+  "fhbonline.fhb.com",
+  "figures.spec.whatwg.org", // RC4
+  "finance.car.com",
+  "followupfactory.fsmoffice.net",
+  "form.kuronekoyamato.co.jp", // bug 1128366
+  "french.visitkorea.or.kr",
+  "friends.freshandeasy.com",
+  "fsmoffice.net",
+  "ftisystem.fsmoffice.net",
+  "fubar.com",
+  "fullscreen.spec.whatwg.org", // RC4
+  "gateway.halton.gov.uk",
+  "gbe-bund.de",
+  "german.visitkorea.or.kr",
+  "gestion.urjc.es",
+  "giftcertificates.com",
+  "gosignmeup.com", // bug 1116891
+  "gotimeforce.com",
+  "hb.posted.co.rs",
+  "helpdesk.attask.com",
+  "hercle.com",
+  "hikkoshi.homes.co.jp",
+  "hollowayusa.com",
+  "home.hi-ho.ne.jp",
+  "hoosierlottery.com",
+  "household.endsleigh.co.uk",
+  "hpshop.gr",
+  "hr.templehealth.org",
+  "html.spec.whatwg.org", // RC4
+  "identity.virginmedia.com", // bug 1129887
+  "iezukuri.homes.co.jp",
+  "ifueltech.fsmoffice.net",
+  "ifund.allianzglobalinvestors.com.tw",
+  "ihr.suburbanpropane.com",
+  "images.bankofthewest.com", // bug 1127204
+  "inquire.homes.co.jp",
+  "inside.i-med.ac.at",
+  "its.bocmacau.com",
+  "ividmail.fsmoffice.net",
+  "japanese.visitkorea.or.kr",
+  "javascript.spec.whatwg.org", // RC4
+  "jhct.co.jp",
+  "jifenpay.com",
+  "jizen.kuronekoyamato.co.jp", // bug 1128366
+  "jookey.jp",
+  "juror.fairfaxcounty.gov",
+  "kaigo.homes.co.jp",
+  "kc.uthscsa.edu",
+  "keirin.jp",
+  "kfeducation.com",
+  "kjp.keinet.ne.jp",
+  "kjp.oo.kawai-juku.ac.jp",
+  "kmis.brookes.ac.uk",
+  "kodate.homes.co.jp",
+  "korea.neways.com",
+  "korean.visitkorea.or.kr",
+  "learn.ou.edu",
+  "learn.swosu.edu",
+  "library.indigo.ca",
+  "lm-order.de",
+  "login.chicagopolice.org",
+  "login.ermis.gov.gr",
+  "lsc.okb.co.jp",
+  "ltr.kotoha.co.jp",
+  "m.cacu.com",
+  "m.e-hon.ne.jp",
+  "m.getawaytoday.com", // bug 1116891
+  "maakoalifestyle.fsmoffice.net",
+  "mail.izhnet.ru",
+  "mailoffer.merrickbank.com",
+  "map.infonavit.org.mx",
+  "marketday.com", // bug 1092998
+  "mbrapp.fpcu.org",
+  "mccbookstore.mchenry.edu",
+  "mecsumai.com",
+  "meiji-jisho.com",
+  "member.edenredticket.com",
+  "membres.fdj.fr",
+  "merchant.edenredticket.com",
+  "merrickbank.com",
+  "meta-ehealth.com",
+  "mijn.graydon.nl",
+  "mimesniff.spec.whatwg.org", // RC4
+  "miportal.urjc.es",
+  "mobile.dream-prize.com",
+  "mon-ulb.ulb.ac.be",
+  "mwed.jp",
+  "my.arts.ac.uk",
+  "my.csmd.edu",
+  "my.csudh.edu",
+  "my.kyivstar.ua",
+  "my.miit.ru",
+  "my.officef5.com",
+  "mybank.nbcb.com.cn",
+  "mybanner.gvsu.edu",
+  "myhancock.hancockcollege.edu",
+  "myhomest.co.jp",
+  "myntc.ntc.edu",
+  "mypage.homes.co.jp",
+  "mytoi.kuronekoyamato.co.jp", // bug 1128366
+  "myucd.ucd.ie",
+  "myuws.uws.edu.au",
+  "nbank.hxb.com.cn",
+  "nbc.epk.tv",
+  "niche.endsleigh.co.uk",
+  "nmsmp.alsok.co.jp",
+  "no1.nipponrentacar.co.jp",
+  "notifications.spec.whatwg.org", // RC4
+  "obos1.obos.no",
+  "officevp.fsmoffice.net",
+  "okurijyoinji.kuronekoyamato.co.jp", // bug 1128366
+  "online.informs.org",
+  "online.nawbo.org",
+  "online.newindia.co.in",
+  "online.sainsburysbank.co.uk",
+  "opi.emersonclimate.com",
+  "opus.pinellascounty.org",
+  "orix-realestate.co.jp",
+  "otodoke.kuronekoyamato.co.jp", // bug 1128366
+  "ow2.orderwave.com",
+  "owa.byui.edu",
+  "ozone.ou.edu",
+  "parents.ou.edu",
+  "parionsweb.fdj.fr",
+  "parionsweb.fr",
+  "pay3.chinabank.com.cn",
+  "payment.safepass.cn",
+  "paymentshq.achfederal.com",
+  "paysys.gooooal.com",
+  "peoples.com",
+  "poezd.rw.by",
+  "portal.eztec.com.br",
+  "portal.questonline.gr",
+  "portal.uem.es",
+  "products.geotrust.com",
+  "products.thawte.com",
+  "profiles.uthscsa.edu",
+  "pts.club-g-po.jp",
+  "publicacionesoficiales.boe.es",
+  "publicjobs.ie",
+  "publicrecords.com",
+  "quirks.spec.whatwg.org", // RC4
+  "r.kaipoke.biz",
+  "rakuraku-market.com",
+  "rcp.kotoha.co.jp",
+  "realestate.homes.co.jp",
+  "recruit.nurse-senka.com",
+  "reform.homes.co.jp",
+  "registration.o2.co.uk",
+  "relativitymedia.epk.tv",
+  "renewals.cipd.co.uk",
+  "repair.kuroneko-kadendr.jp", // bug 1128366
+  "reputation.com",
+  "research-report.uws.edu.au",
+  "reserve.opas.jp",
+  "resources.whatwg.org", // RC4
+  "rpg.kotoha.co.jp",
+  "rr.com",
+  "russian.visitkorea.or.kr",
+  "s.aiasahi.jp",
+  "sales.mibucorp.co.jp",
+  "sales.newchinalife.com",
+  "sbank.hxb.com.cn",
+  "sboseweb.mcpsweb.org",
+  "school.keystoneschoolonline.com",
+  "schweser.com",
+  "secure.bg-mania.jp",
+  "secure.fortisbc.com",
+  "secure.missouristate.edu",
+  "secure.smartcart.com",
+  "securedcard.merrickbank.com",
+  "secureonline.dwp.gov.uk",
+  "selfcare.rr.com",
+  "sems.hrd.ccsd.net",
+  "service.autoc-one.jp",
+  "services.apvma.gov.au",
+  "servizionline.infogroup.it",
+  "sgp.kotoha.co.jp",
+  "shinchiku.homes.co.jp",
+  "shop.autoc-one.jp",
+  "shop.kagome.co.jp",
+  "shop.lococom.jp",
+  "shop.maxim-ic.com",
+  "shop.nanairo.coop", // bug 1128318
+  "showcase-tv.com",
+  "sigeduweb.udesa.edu.ar",
+  "sirius.ws.ryukoku.ac.jp",
+  "sisweb.ucd.ie",
+  "slovanet.sk",
+  "smartcart.com",
+  "smarticon.geotrust.com",
+  "sony.epk.tv",
+  "spanish.visitkorea.or.kr",
+  "spp.kotoha.co.jp",
+  "ss2.sfcollege.edu",
+  "ss5.sfcollege.edu",
+  "ssl.0634.co.jp",
+  "ssl.taisho-direct.jp",
+  "startrekonline.com",
+  "store.closetmaid.com",
+  "store.morningside.edu",
+  "store.moxa.com",
+  "streams.spec.whatwg.org", // RC4
+  "stub.com",
+  "stubpass.com",
+  "sumai.homes.co.jp",
+  "support.crypticstudios.com",
+  "support.ticketseating.com",
+  "support.ticketsupply.com",
+  "svrch13.sugarlandtx.gov",
+  "syuhai.kuronekoyamato.co.jp", // bug 1128366
+  "syzygy.co.uk",
+  "takuhai-locker.kuronekoyamato.co.jp", // bug 1128366
+  "taxbill365.com",
+  "tele2.hr",
+  "tenkyo-tenso.kuronekoyamato.co.jp", // bug 1128366
+  "thebookstore.tru.ca",
+  "ticketseating.com",
+  "ticketsupply.com",
+  "tienda.boe.es",
+  "timewarnercable.com", // bug 1115883
+  "todentaminen.posti.fi",
+  "toushi.homes.co.jp",
+  "trade.hsfund.com",
+  "trueblue.jetblue.com",
+  "tsuhanshokai.kuronekoyamato.co.jp", // bug 1128366
+  "twcbc.com",
+  "universal.epk.tv",
+  "url.spec.whatwg.org", // RC4
+  "userdoor.com",
+  "uslugi.beeline.am",
+  "uslugi.beeline.kz",
+  "utahbar.org", // bug 1127611
+  "utradehub.or.kr",
+  "uxxiportal.upct.es",
+  "verkkokauppa.posti.fi",
+  "vod.skyperfectv.co.jp",
+  "wayfarer.timewarnercable.com", // bug 1115883
+  "web3.secureinternetbank.com", // bug 1111354
+  "webapps.ou.edu",
+  "webatm.landbank.com.tw",
+  "webctmt.lau.edu.lb",
+  "webmail.iyte.edu.tr",
+  "websiti.cnbv.gob.mx",
+  "webtv.tv2.no",
+  "whataburger.com",
+  "whatwg.org", // RC4
+  "wiki.whatwg.org", // RC4
+  "wis.ntu.edu.sg",
+  "world-family.co.jp",
+  "wszg.nbcs.gov.cn",
+  "www.3zai.com",
+  "www.accessingram.com",
+  "www.acgov.org",
+  "www.affiliatewalla.com",
+  "www.allinpay.com",
+  "www.alphashirt.com",
+  "www.ancelutil.com.uy",
+  "www.animate-onlineshop.jp", // bug 1126652
+  "www.apeasternpower.com",
+  "www.apita.co.jp",
+  "www.applied.com",
+  "www.araggroup.com",
+  "www.araglegalcenter.com",
+  "www.arts.ac.uk",
+  "www.asknow.com",
+  "www.attask-ondemand.com",
+  "www.attask.com",
+  "www.augustasportswear.com",
+  "www.auroragov.org",
+  "www.bancocredichile.cl",
+  "www.bancofrances.com.ar",
+  "www.bankofthewest.com", // bug 1127204
+  "www.bauschonline.com",
+  "www.bbsfonline.com",
+  "www.bettertrades.com",
+  "www.bigflix.com",
+  "www.blogwatcher.co.jp",
+  "www.blueprintonline.co.za",
+  "www.bm-sms.co.jp",
+  "www.bmfsfj.de",
+  "www.boe.es",
+  "www.bookstore.ccbcmd.edu",
+  "www.bookstore.csi.edu",
+  "www.bookstore.irsc.edu",
+  "www.bookstore.mtu.edu",
+  "www.bookstore.westga.edu",
+  "www.borsaitaliana.it",
+  "www.bottegaverde.es",
+  "www.bottegaverde.it",
+  "www.bottegaverde.pt",
+  "www.bpionline.pt",
+  "www.brb.com.br",
+  "www.bundespruefstelle.de",
+  "www.businessdirect.bt.com",
+  "www.cafedumonde.jp",
+  "www.carcraft.co.uk",
+  "www.care-mane.com",
+  "www.careers.asio.gov.au",
+  "www.chinapay.com",
+  "www.cihi.ca",
+  "www.cipd.co.uk",
+  "www.club-animate.jp",
+  "www.cngcorp.com",
+  "www.codan.dk",
+  "www.comune.milano.it",
+  "www.credem.it",
+  "www.crediscotia.com.mx",
+  "www.creditagricole.info",
+  "www.crocs.com.tw",
+  "www.crypticstudios.com",
+  "www.css-club.net",
+  "www.ctfeshop.com.cn",
+  "www.cwu.edu",
+  "www.dabs.com",
+  "www.dabs.ie",
+  "www.dabs4work.ie",
+  "www.derayah.com",
+  "www.dgii.gov.do",
+  "www.digibet.com",
+  "www.drcsurveys.com",
+  "www.dream-prize.com",
+  "www.duskin.co.jp",
+  "www.duskin.jp",
+  "www.ec-line.cn",
+  "www.echo.com",
+  "www.echotrak.com",
+  "www.eckeroline.fi",
+  "www.econ.ne.jp",
+  "www.econda-monitor.de",
+  "www.emihub.com",
+  "www.epk.tv",
+  "www.epolicija.lt",
+  "www.ermis.gov.gr",
+  "www.erneuerbare-energien.de",
+  "www.esadealumni.net",
+  "www.esavingsaccount.co.uk",
+  "www.everyd.com",
+  "www.expogrupo.com",
+  "www.expohotelbarcelona.com",
+  "www.ezpay.com.tw",
+  "www.familien-wegweiser.de",
+  "www.fdj.fr",
+  "www.fj96336.com",
+  "www.fn-neon.de",
+  "www.foerderdatenbank.de",
+  "www.fontainebleau.com",
+  "www.fora.se",
+  "www.foundersc.com",
+  "www.fsmoffice.net",
+  "www.fubar.com",
+  "www.fundsupermart.co.in",
+  "www.gamers-onlineshop.jp", // bug 1126654
+  "www.gbe-bund.de",
+  "www.gestion.urjc.es",
+  "www.giftcertificates.com",
+  "www.golfersland.net",
+  "www.gosignmeup.com", // bug 1116891
+  "www.gotimeforce.com",
+  "www.gtja.com",
+  "www.hankyu-club.com",
+  "www.haynes.co.uk",
+  "www.hctmall.com.tw",
+  "www.hercle.com",
+  "www.hitachi-ies.co.jp",
+  "www.hollowayusa.com",
+  "www.hoosierlottery.com",
+  "www.hotel-story.ne.jp",
+  "www.hpshop.gr",
+  "www.hsbank.cc",
+  "www.htsec.com",
+  "www.hx168.com.cn",
+  "www.i-misdo.com",
+  "www.iezukuri-net.com",
+  "www.illori.com.tw",
+  "www.ingramentertainment.com",
+  "www.interpark.com",
+  "www.jaf.or.jp",
+  "www.jhct.co.jp",
+  "www.jifenpay.com",
+  "www.kaigojob.com",
+  "www.kaipoke.biz",
+  "www.kasite.net",
+  "www.kfeducation.com",
+  "www.khan.co.kr",
+  "www.komatsu-kenki.co.jp",
+  "www.komatsu.co.jp",
+  "www.komatsu.com",
+  "www.kotoha.co.jp",
+  "www.kracie.co.jp",
+  "www.kredodirect.com.ua", // bug 1095507
+  "www.kyusai.co.jp",
+  "www.law888.com.tw",
+  "www.learndoj.gov",
+  "www.lib.cwu.edu",
+  "www.libraryvideo.com",
+  "www.lm-order.de",
+  "www.lococom.jp",
+  "www.londonstockexchange.com",
+  "www.marenostrumresort.com",
+  "www.marketday.com", // bug 1092998
+  "www.matkahuolto.info",
+  "www.matrics.or.jp",
+  "www.mecsumai.com",
+  "www.meiji-jisho.com",
+  "www.mercatoneuno.com",
+  "www.merrickbank.com",
+  "www.meta-ehealth.com",
+  "www.miracle-ear.com",
+  "www.misterdonut.jp",
+  "www.mizuno.jp",
+  "www.mizunoshop.net",
+  "www.monclick.fr",
+  "www.monclick.it",
+  "www.mopera.net",
+  "www.mp2.aeroport.fr",
+  "www.mpay.co.th",
+  "www.mtsindia.in", // RC4
+  "www.mwed.jp",
+  "www.my.airdo.jp",
+  "www.mydress.com.tw",
+  "www.myhomest.co.jp",
+  "www.mynpcdata.net",
+  "www.nec-nexs.com",
+  "www.nekonet-ios.jp",
+  "www.neways.com",
+  "www.newaysonline.com",
+  "www.newchinalife.com",
+  "www.nishi.or.jp",
+  "www.nursejinzaibank.com",
+  "www.orix-realestate.co.jp",
+  "www.orix-sumai.jp",
+  "www.ou.edu",
+  "www.oursinn-hankyu.co.jp",
+  "www.outlet01.com.tw",
+  "www.oxendales.co.uk",
+  "www.parionsweb.fr",
+  "www.partnerandaffinitycards.co.uk", // RC4
+  "www.pen-kanagawa.ed.jp",
+  "www.peoples.com",
+  "www.point-tactix.jp",
+  "www.polla.cl",
+  "www.priate.jp",
+  "www.publicjobs.ie",
+  "www.publicrecords.com",
+  "www.purenurse.com",
+  "www.pwcrecruiting.com",
+  "www.razorgator.com",
+  "www.renaultcredit.com.ar",
+  "www.reputation.com",
+  "www.riversendtrading.com",
+  "www.rr.com",
+  "www.rubriquefidelite.com",
+  "www.ruskfrance.net",
+  "www.s-book.net",
+  "www.safepass.cn",
+  "www.sandiegoimmunizationregistry.org",
+  "www.schweser.com",
+  "www.secure.missouristate.edu",
+  "www.sendwordnow.com",
+  "www.session.ne.jp",
+  "www.shanghaigm.com",
+  "www.shiki.jp",
+  "www.shinsei.e-aichi.jp",
+  "www.shop.bt.com",
+  "www.showcase-tv.com",
+  "www.sihd-bk.jp",
+  "www.sikatoru.com",
+  "www.slovanet.sk",
+  "www.smartcart.com",
+  "www.smartoffice.jp",
+  "www.soconngas.com",
+  "www.sogehomebank.com",
+  "www.sogo-seibu.jp", // bug 1128602
+  "www.sokamocka.com",
+  "www.sports-nakama.com",
+  "www.startrekonline.com",
+  "www.strade.com.vn",
+  "www.stub.com",
+  "www.stubpass.com",
+  "www.sunderland.gov.uk",
+  "www.syzygy.co.uk",
+  "www.taxbill365.com",
+  "www.tealife.co.jp",
+  "www.tele2.hr",
+  "www.tetsudo.com",
+  "www.thecopia.com",
+  "www.ticketseating.com",
+  "www.ticketsupply.com",
+  "www.timewarnercable.com", // bug 1115883
+  "www.torrecatalunya.com",
+  "www.transunion.ca",
+  "www.twcbc.com",
+  "www.u-gakugei.ac.jp",
+  "www.ubao.com",
+  "www.uccard.co.jp",
+  "www.uinet.com",
+  "www.unodc.org",
+  "www.ur-net.go.jp",
+  "www.userdoor.com",
+  "www.utahbar.org", // bug 1127611
+  "www.utradehub.or.kr",
+  "www.virgin.net",
+  "www.visitkorea.or.kr",
+  "www.wavecable.com",
+  "www.whataburger.com",
+  "www.whatwg.org", // RC4
+  "www.wingarc.com",
+  "www.world-family.co.jp",
+  "www.xm-l-tax.gov.cn",
+  "www.yakult.co.kr",
+  "www.youmeshop.jp",
+  "www.yuuka.co.jp",
+  "www.zenfolio.com",
+  "www.zoominfo.com",
+  "www1.ibercajadirecto.com",
+  "www10.sim.edu.sg",
+  "www2.seibu.jp",
+  "www2.shueisha.co.jp",
+  "www2.sogo-gogo.com",
+  "www2.wou.edu",
+  "www3.ibac.co.jp",
+  "www3.taiheiyo-ferry.co.jp",
+  "wwws.kadokawa.co.jp",
+  "xhr.spec.whatwg.org", // RC4
+  "yeswellnesspro.fsmoffice.net",
+  "zenfolio.com",
+  "zoominfo.com",
+};
--- a/security/manager/ssl/src/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/src/nsNSSIOLayer.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsNSSIOLayer.h"
 
 #include "pkix/ScopedPtr.h"
 #include "pkix/pkixtypes.h"
 #include "nsNSSComponent.h"
+#include "mozilla/BinarySearch.h"
 #include "mozilla/Casting.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Telemetry.h"
 
 #include "prlog.h"
 #include "prmem.h"
 #include "prnetdb.h"
 #include "nsIPrefService.h"
@@ -47,16 +48,18 @@
 #include "sslproto.h"
 #include "secerr.h"
 #include "sslerr.h"
 #include "secder.h"
 #include "keyhi.h"
 
 #include <algorithm>
 
+#include "IntolerantFallbackList.inc"
+
 using namespace mozilla;
 using namespace mozilla::psm;
 
 //#define DEBUG_SSL_VERBOSE //Enable this define to get minimal
                             //reports when doing SSL read/write
 
 //#define DUMP_BUFFER  //Enable this define along with
                        //DEBUG_SSL_VERBOSE to dump SSL
@@ -671,22 +674,20 @@ nsNSSSocketInfo::SetCertVerificationResu
 SharedSSLState&
 nsNSSSocketInfo::SharedState()
 {
   return mSharedState;
 }
 
 void nsSSLIOLayerHelpers::Cleanup()
 {
+  MutexAutoLock lock(mutex);
   mTLSIntoleranceInfo.Clear();
-
-  if (mRenegoUnrestrictedSites) {
-    delete mRenegoUnrestrictedSites;
-    mRenegoUnrestrictedSites = nullptr;
-  }
+  mRenegoUnrestrictedSites.Clear();
+  mInsecureFallbackSites.Clear();
 }
 
 static void
 nsHandleSSLError(nsNSSSocketInfo* socketInfo,
                  ::mozilla::psm::SSLErrorMessageType errtype,
                  PRErrorCode err)
 {
   if (!NS_IsMainThread()) {
@@ -858,25 +859,35 @@ nsSSLIOLayerHelpers::forgetIntolerance(c
 
     entry.AssertInvariant();
     mTLSIntoleranceInfo.Put(key, entry);
   }
 
   return tolerant;
 }
 
+bool
+nsSSLIOLayerHelpers::fallbackLimitReached(const nsACString& hostName,
+                                          uint16_t intolerant)
+{
+  if (isInsecureFallbackSite(hostName)) {
+    return intolerant <= SSL_LIBRARY_VERSION_TLS_1_0;
+  }
+  return intolerant <= mVersionFallbackLimit;
+}
+
 // returns true if we should retry the handshake
 bool
 nsSSLIOLayerHelpers::rememberIntolerantAtVersion(const nsACString& hostName,
                                                  int16_t port,
                                                  uint16_t minVersion,
                                                  uint16_t intolerant,
                                                  PRErrorCode intoleranceReason)
 {
-  if (intolerant <= minVersion || intolerant <= mVersionFallbackLimit) {
+  if (intolerant <= minVersion || fallbackLimitReached(hostName, intolerant)) {
     // We can't fall back any further. Assume that intolerance isn't the issue.
     uint32_t tolerant = forgetIntolerance(hostName, port);
     // If we know the server is tolerant at the version, we don't have to
     // gather the telemetry.
     if (intolerant <= tolerant) {
       return false;
     }
 
@@ -1216,16 +1227,24 @@ retryDueToTLSIntolerance(PRErrorCode err
     Telemetry::Accumulate(Telemetry::SSL_VERSION_FALLBACK_INAPPROPRIATE,
                           tlsIntoleranceTelemetryBucket(originalReason));
 
     socketInfo->SharedState().IOLayerHelpers()
       .forgetIntolerance(socketInfo->GetHostName(), socketInfo->GetPort());
 
     return false;
   }
+
+  // Allow PR_CONNECT_RESET_ERROR only for whitelisted sites.
+  if (err == PR_CONNECT_RESET_ERROR &&
+      !socketInfo->SharedState().IOLayerHelpers()
+        .isInsecureFallbackSite(socketInfo->GetHostName())) {
+    return false;
+  }
+
   if ((err == SSL_ERROR_NO_CYPHER_OVERLAP || err == PR_END_OF_FILE_ERROR ||
        err == PR_CONNECT_RESET_ERROR) &&
       nsNSSComponent::AreAnyWeakCiphersEnabled()) {
     if (socketInfo->SharedState().IOLayerHelpers()
                   .rememberStrongCiphersFailed(socketInfo->GetHostName(),
                                                socketInfo->GetPort(), err)) {
       Telemetry::Accumulate(Telemetry::SSL_WEAK_CIPHERS_FALLBACK,
                             tlsIntoleranceTelemetryBucket(err));
@@ -1441,21 +1460,21 @@ nsSSLIOLayerPoll(PRFileDesc* fd, int16_t
   // cert validation is complete.
   int16_t result = fd->lower->methods->poll(fd->lower, in_flags, out_flags);
   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] poll SSL socket returned %d\n",
                                     (void*) fd, (int) result));
   return result;
 }
 
 nsSSLIOLayerHelpers::nsSSLIOLayerHelpers()
-  : mRenegoUnrestrictedSites(nullptr)
-  , mTreatUnsafeNegotiationAsBroken(false)
+  : mTreatUnsafeNegotiationAsBroken(false)
   , mWarnLevelMissingRFC5746(1)
   , mTLSIntoleranceInfo()
-  , mFalseStartRequireNPN(true)
+  , mFalseStartRequireNPN(false)
+  , mUseStaticFallbackList(true)
   , mVersionFallbackLimit(SSL_LIBRARY_VERSION_TLS_1_0)
   , mutex("nsSSLIOLayerHelpers.mutex")
 {
 }
 
 static int
 _PSM_InvalidInt(void)
 {
@@ -1652,35 +1671,40 @@ NS_IMPL_ISUPPORTS(PrefObserver, nsIObser
 NS_IMETHODIMP
 PrefObserver::Observe(nsISupports* aSubject, const char* aTopic,
                       const char16_t* someData)
 {
   if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
     NS_ConvertUTF16toUTF8 prefName(someData);
 
     if (prefName.EqualsLiteral("security.ssl.renego_unrestricted_hosts")) {
-      nsCString unrestricted_hosts;
-      Preferences::GetCString("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
-      if (!unrestricted_hosts.IsEmpty()) {
-        mOwner->setRenegoUnrestrictedSites(unrestricted_hosts);
-      }
+      nsCString unrestrictedHosts;
+      Preferences::GetCString("security.ssl.renego_unrestricted_hosts", &unrestrictedHosts);
+      mOwner->setSiteList(mOwner->mRenegoUnrestrictedSites, unrestrictedHosts);
     } else if (prefName.EqualsLiteral("security.ssl.treat_unsafe_negotiation_as_broken")) {
       bool enabled;
       Preferences::GetBool("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
       mOwner->setTreatUnsafeNegotiationAsBroken(enabled);
     } else if (prefName.EqualsLiteral("security.ssl.warn_missing_rfc5746")) {
       int32_t warnLevel = 1;
       Preferences::GetInt("security.ssl.warn_missing_rfc5746", &warnLevel);
       mOwner->setWarnLevelMissingRFC5746(warnLevel);
     } else if (prefName.EqualsLiteral("security.ssl.false_start.require-npn")) {
       mOwner->mFalseStartRequireNPN =
         Preferences::GetBool("security.ssl.false_start.require-npn",
                              FALSE_START_REQUIRE_NPN_DEFAULT);
     } else if (prefName.EqualsLiteral("security.tls.version.fallback-limit")) {
       mOwner->loadVersionFallbackLimit();
+    } else if (prefName.EqualsLiteral("security.tls.insecure_fallback_hosts")) {
+      nsCString insecureFallbackHosts;
+      Preferences::GetCString("security.tls.insecure_fallback_hosts", &insecureFallbackHosts);
+      mOwner->setInsecureFallbackSites(insecureFallbackHosts);
+    } else if (prefName.EqualsLiteral("security.tls.insecure_fallback_hosts.use_static_list")) {
+      mOwner->mUseStaticFallbackList =
+        Preferences::GetBool("security.tls.insecure_fallback_hosts.use_static_list", true);
     }
   }
   return NS_OK;
 }
 
 static int32_t
 PlaintextRecv(PRFileDesc* fd, void* buf, int32_t amount, int flags,
               PRIntervalTime timeout)
@@ -1707,16 +1731,20 @@ nsSSLIOLayerHelpers::~nsSSLIOLayerHelper
     Preferences::RemoveObserver(mPrefObserver,
       "security.ssl.renego_unrestricted_hosts");
     Preferences::RemoveObserver(mPrefObserver,
         "security.ssl.treat_unsafe_negotiation_as_broken");
     Preferences::RemoveObserver(mPrefObserver,
         "security.ssl.warn_missing_rfc5746");
     Preferences::RemoveObserver(mPrefObserver,
         "security.ssl.false_start.require-npn");
+    Preferences::RemoveObserver(mPrefObserver,
+        "security.tls.version.fallback-limit");
+    Preferences::RemoveObserver(mPrefObserver,
+        "security.tls.insecure_fallback_hosts");
   }
 }
 
 nsresult
 nsSSLIOLayerHelpers::Init()
 {
   if (!nsSSLIOLayerInitialized) {
     nsSSLIOLayerInitialized = true;
@@ -1755,48 +1783,51 @@ nsSSLIOLayerHelpers::Init()
     nsSSLIOLayerMethods.read = nsSSLIOLayerRead;
     nsSSLIOLayerMethods.poll = nsSSLIOLayerPoll;
 
     nsSSLPlaintextLayerIdentity = PR_GetUniqueIdentity("Plaintxext PSM layer");
     nsSSLPlaintextLayerMethods  = *PR_GetDefaultIOMethods();
     nsSSLPlaintextLayerMethods.recv = PlaintextRecv;
   }
 
-  mRenegoUnrestrictedSites = new nsTHashtable<nsCStringHashKey>();
-
-  nsCString unrestricted_hosts;
-  Preferences::GetCString("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
-  if (!unrestricted_hosts.IsEmpty()) {
-    setRenegoUnrestrictedSites(unrestricted_hosts);
-  }
+  nsCString unrestrictedHosts;
+  Preferences::GetCString("security.ssl.renego_unrestricted_hosts", &unrestrictedHosts);
+  setSiteList(mRenegoUnrestrictedSites, unrestrictedHosts);
 
   bool enabled = false;
   Preferences::GetBool("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
   setTreatUnsafeNegotiationAsBroken(enabled);
 
   int32_t warnLevel = 1;
   Preferences::GetInt("security.ssl.warn_missing_rfc5746", &warnLevel);
   setWarnLevelMissingRFC5746(warnLevel);
 
   mFalseStartRequireNPN =
     Preferences::GetBool("security.ssl.false_start.require-npn",
                          FALSE_START_REQUIRE_NPN_DEFAULT);
   loadVersionFallbackLimit();
+  nsCString insecureFallbackHosts;
+  Preferences::GetCString("security.tls.insecure_fallback_hosts", &insecureFallbackHosts);
+  setInsecureFallbackSites(insecureFallbackHosts);
+  mUseStaticFallbackList =
+    Preferences::GetBool("security.tls.insecure_fallback_hosts.use_static_list", true);
 
   mPrefObserver = new PrefObserver(this);
   Preferences::AddStrongObserver(mPrefObserver,
                                  "security.ssl.renego_unrestricted_hosts");
   Preferences::AddStrongObserver(mPrefObserver,
                                  "security.ssl.treat_unsafe_negotiation_as_broken");
   Preferences::AddStrongObserver(mPrefObserver,
                                  "security.ssl.warn_missing_rfc5746");
   Preferences::AddStrongObserver(mPrefObserver,
                                  "security.ssl.false_start.require-npn");
   Preferences::AddStrongObserver(mPrefObserver,
                                  "security.tls.version.fallback-limit");
+  Preferences::AddStrongObserver(mPrefObserver,
+                                 "security.tls.insecure_fallback_hosts");
   return NS_OK;
 }
 
 void
 nsSSLIOLayerHelpers::loadVersionFallbackLimit()
 {
   // see nsNSSComponent::setEnabledTLSVersions for pref handling rules
   uint32_t limit = Preferences::GetUint("security.tls.version.fallback-limit",
@@ -1807,49 +1838,78 @@ nsSSLIOLayerHelpers::loadVersionFallback
   nsNSSComponent::FillTLSVersionRange(filledInRange, limit, limit, defaults);
 
   mVersionFallbackLimit = filledInRange.max;
 }
 
 void
 nsSSLIOLayerHelpers::clearStoredData()
 {
-  mRenegoUnrestrictedSites->Clear();
+  MutexAutoLock lock(mutex);
+  mRenegoUnrestrictedSites.Clear();
+  mInsecureFallbackSites.Clear();
   mTLSIntoleranceInfo.Clear();
 }
 
 void
-nsSSLIOLayerHelpers::setRenegoUnrestrictedSites(const nsCString& str)
+nsSSLIOLayerHelpers::setSiteList(nsTHashtable<nsCStringHashKey>& sites,
+                                 const nsCString& str)
 {
   MutexAutoLock lock(mutex);
 
-  if (mRenegoUnrestrictedSites) {
-    delete mRenegoUnrestrictedSites;
-    mRenegoUnrestrictedSites = nullptr;
+  sites.Clear();
+
+  if (str.IsEmpty()) {
+    return;
   }
 
-  mRenegoUnrestrictedSites = new nsTHashtable<nsCStringHashKey>();
-  if (!mRenegoUnrestrictedSites)
-    return;
-
   nsCCharSeparatedTokenizer toker(str, ',');
 
   while (toker.hasMoreTokens()) {
     const nsCSubstring& host = toker.nextToken();
     if (!host.IsEmpty()) {
-      mRenegoUnrestrictedSites->PutEntry(host);
+      sites.PutEntry(host);
     }
   }
 }
 
+struct FallbackListComparator
+{
+  explicit FallbackListComparator(const char* aTarget)
+    : mTarget(aTarget)
+  {}
+
+  int operator()(const char* aVal) const {
+    return strcmp(mTarget, aVal);
+  }
+
+private:
+  const char* mTarget;
+};
+
+bool
+nsSSLIOLayerHelpers::isInsecureFallbackSite(const nsACString& hostname)
+{
+  size_t match;
+  if (mUseStaticFallbackList &&
+      BinarySearchIf(kIntolerantFallbackList, 0,
+        ArrayLength(kIntolerantFallbackList),
+        FallbackListComparator(PromiseFlatCString(hostname).get()),
+        &match)) {
+    return true;
+  }
+  MutexAutoLock lock(mutex);
+  return mInsecureFallbackSites.Contains(hostname);
+}
+
 bool
 nsSSLIOLayerHelpers::isRenegoUnrestrictedSite(const nsCString& str)
 {
   MutexAutoLock lock(mutex);
-  return mRenegoUnrestrictedSites->Contains(str);
+  return mRenegoUnrestrictedSites.Contains(str);
 }
 
 void
 nsSSLIOLayerHelpers::setTreatUnsafeNegotiationAsBroken(bool broken)
 {
   MutexAutoLock lock(mutex);
   mTreatUnsafeNegotiationAsBroken = broken;
 }
--- a/security/manager/ssl/src/nsNSSIOLayer.h
+++ b/security/manager/ssl/src/nsNSSIOLayer.h
@@ -181,17 +181,17 @@ public:
   void Cleanup();
 
   static bool nsSSLIOLayerInitialized;
   static PRDescIdentity nsSSLIOLayerIdentity;
   static PRDescIdentity nsSSLPlaintextLayerIdentity;
   static PRIOMethods nsSSLIOLayerMethods;
   static PRIOMethods nsSSLPlaintextLayerMethods;
 
-  nsTHashtable<nsCStringHashKey>* mRenegoUnrestrictedSites;
+  nsTHashtable<nsCStringHashKey> mRenegoUnrestrictedSites;
   bool mTreatUnsafeNegotiationAsBroken;
   int32_t mWarnLevelMissingRFC5746;
 
   void setTreatUnsafeNegotiationAsBroken(bool broken);
   bool treatUnsafeNegotiationAsBroken();
   void setWarnLevelMissingRFC5746(int32_t level);
   int32_t getWarnLevelMissingRFC5746();
 
@@ -204,39 +204,53 @@ private:
     StrongCipherStatus strongCipherStatus;
 
     void AssertInvariant() const
     {
       MOZ_ASSERT(intolerant == 0 || tolerant < intolerant);
     }
   };
   nsDataHashtable<nsCStringHashKey, IntoleranceEntry> mTLSIntoleranceInfo;
+  // Sites that require insecure fallback to TLS 1.0, set by the pref
+  // security.tls.insecure_fallback_hosts, which is a comma-delimited
+  // list of domain names.
+  nsTHashtable<nsCStringHashKey> mInsecureFallbackSites;
 public:
   void rememberTolerantAtVersion(const nsACString& hostname, int16_t port,
                                  uint16_t tolerant);
+  bool fallbackLimitReached(const nsACString& hostname, uint16_t intolerant);
   bool rememberIntolerantAtVersion(const nsACString& hostname, int16_t port,
                                    uint16_t intolerant, uint16_t minVersion,
                                    PRErrorCode intoleranceReason);
   bool rememberStrongCiphersFailed(const nsACString& hostName, int16_t port,
                                    PRErrorCode intoleranceReason);
   // returns the known tolerant version
   // or 0 if there is no known tolerant version
   uint16_t forgetIntolerance(const nsACString& hostname, int16_t port);
   void adjustForTLSIntolerance(const nsACString& hostname, int16_t port,
                                /*in/out*/ SSLVersionRange& range,
                                /*out*/ StrongCipherStatus& strongCipherStatus);
   PRErrorCode getIntoleranceReason(const nsACString& hostname, int16_t port);
 
-  void setRenegoUnrestrictedSites(const nsCString& str);
+  void setSiteList(nsTHashtable<nsCStringHashKey>& sites,
+                   const nsCString& str);
   bool isRenegoUnrestrictedSite(const nsCString& str);
   void clearStoredData();
   void loadVersionFallbackLimit();
+  void setInsecureFallbackSites(const nsCString& str)
+  {
+    setSiteList(mInsecureFallbackSites, str);
+  }
+  bool isInsecureFallbackSite(const nsACString& hostname);
 
   bool mFalseStartRequireNPN;
-  bool mFalseStartRequireForwardSecrecy;
+  // Use the static list of sites that require insecure fallback
+  // to TLS 1.0 if true, set by the pref
+  // security.tls.insecure_fallback_hosts.use_static_list.
+  bool mUseStaticFallbackList;
   uint16_t mVersionFallbackLimit;
 private:
   mozilla::Mutex mutex;
   nsCOMPtr<nsIObserver> mPrefObserver;
 };
 
 nsresult nsSSLIOLayerNewSocket(int32_t family,
                                const char* host,
--- a/security/manager/ssl/tests/gtest/TLSIntoleranceTest.cpp
+++ b/security/manager/ssl/tests/gtest/TLSIntoleranceTest.cpp
@@ -512,8 +512,121 @@ TEST_F(TLSIntoleranceTest, TLS_Dont_Forg
                               SSL_LIBRARY_VERSION_TLS_1_2 };
     StrongCipherStatus strongCipherStatus = StrongCipherStatusUnknown;
     helpers.adjustForTLSIntolerance(HOST, PORT, range, strongCipherStatus);
     ASSERT_EQ(SSL_LIBRARY_VERSION_3_0, range.min);
     ASSERT_EQ(SSL_LIBRARY_VERSION_TLS_1_2, range.max);
     ASSERT_EQ(StrongCiphersWorked, strongCipherStatus);
   }
 }
+
+TEST_F(TLSIntoleranceTest, TLS_Per_Site_Fallback_Limit)
+{
+  NS_NAMED_LITERAL_CSTRING(example_com, "example.com");
+  NS_NAMED_LITERAL_CSTRING(example_net, "example.net");
+  NS_NAMED_LITERAL_CSTRING(example_org, "example.org");
+
+  helpers.mVersionFallbackLimit = SSL_LIBRARY_VERSION_TLS_1_0;
+
+  ASSERT_FALSE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_2));
+  ASSERT_FALSE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_1));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_0));
+  ASSERT_FALSE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_2));
+  ASSERT_FALSE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_1));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_0));
+  ASSERT_FALSE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_2));
+  ASSERT_FALSE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_1));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_0));
+
+  helpers.mVersionFallbackLimit = SSL_LIBRARY_VERSION_TLS_1_2;
+
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_2));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_1));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_0));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_2));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_1));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_0));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_2));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_1));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_0));
+
+  helpers.setInsecureFallbackSites(example_com);
+
+  ASSERT_FALSE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_2));
+  ASSERT_FALSE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_1));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_0));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_2));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_1));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_0));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_2));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_1));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_0));
+
+  helpers.setInsecureFallbackSites(NS_LITERAL_CSTRING("example.com,example.net"));
+
+  ASSERT_FALSE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_2));
+  ASSERT_FALSE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_1));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_0));
+  ASSERT_FALSE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_2));
+  ASSERT_FALSE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_1));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_0));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_2));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_1));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_0));
+
+  helpers.setInsecureFallbackSites(example_net);
+
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_2));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_1));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_0));
+  ASSERT_FALSE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_2));
+  ASSERT_FALSE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_1));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_0));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_2));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_1));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_0));
+
+  helpers.setInsecureFallbackSites(EmptyCString());
+
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_2));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_1));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_com, SSL_LIBRARY_VERSION_TLS_1_0));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_2));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_1));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_net, SSL_LIBRARY_VERSION_TLS_1_0));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_2));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_1));
+  ASSERT_TRUE(helpers.fallbackLimitReached(example_org, SSL_LIBRARY_VERSION_TLS_1_0));
+}
+
+TEST_F(TLSIntoleranceTest, TLS_Static_Fallback_List)
+{
+  NS_NAMED_LITERAL_CSTRING(fallback_test, "fallback.test");
+  NS_NAMED_LITERAL_CSTRING(no_fallback_test, "no.fallback.test");
+
+  helpers.mVersionFallbackLimit = SSL_LIBRARY_VERSION_TLS_1_0;
+  helpers.mUseStaticFallbackList = false;
+
+  ASSERT_FALSE(helpers.fallbackLimitReached(fallback_test, SSL_LIBRARY_VERSION_TLS_1_2));
+  ASSERT_FALSE(helpers.fallbackLimitReached(fallback_test, SSL_LIBRARY_VERSION_TLS_1_1));
+  ASSERT_TRUE(helpers.fallbackLimitReached(fallback_test, SSL_LIBRARY_VERSION_TLS_1_0));
+  ASSERT_FALSE(helpers.fallbackLimitReached(no_fallback_test, SSL_LIBRARY_VERSION_TLS_1_2));
+  ASSERT_FALSE(helpers.fallbackLimitReached(no_fallback_test, SSL_LIBRARY_VERSION_TLS_1_1));
+  ASSERT_TRUE(helpers.fallbackLimitReached(no_fallback_test, SSL_LIBRARY_VERSION_TLS_1_0));
+
+  helpers.mVersionFallbackLimit = SSL_LIBRARY_VERSION_TLS_1_2;
+
+  ASSERT_TRUE(helpers.fallbackLimitReached(fallback_test, SSL_LIBRARY_VERSION_TLS_1_2));
+  ASSERT_TRUE(helpers.fallbackLimitReached(fallback_test, SSL_LIBRARY_VERSION_TLS_1_1));
+  ASSERT_TRUE(helpers.fallbackLimitReached(fallback_test, SSL_LIBRARY_VERSION_TLS_1_0));
+  ASSERT_TRUE(helpers.fallbackLimitReached(no_fallback_test, SSL_LIBRARY_VERSION_TLS_1_2));
+  ASSERT_TRUE(helpers.fallbackLimitReached(no_fallback_test, SSL_LIBRARY_VERSION_TLS_1_1));
+  ASSERT_TRUE(helpers.fallbackLimitReached(no_fallback_test, SSL_LIBRARY_VERSION_TLS_1_0));
+
+  helpers.mUseStaticFallbackList = true;
+
+  ASSERT_FALSE(helpers.fallbackLimitReached(fallback_test, SSL_LIBRARY_VERSION_TLS_1_2));
+  ASSERT_FALSE(helpers.fallbackLimitReached(fallback_test, SSL_LIBRARY_VERSION_TLS_1_1));
+  ASSERT_TRUE(helpers.fallbackLimitReached(fallback_test, SSL_LIBRARY_VERSION_TLS_1_0));
+  ASSERT_TRUE(helpers.fallbackLimitReached(no_fallback_test, SSL_LIBRARY_VERSION_TLS_1_2));
+  ASSERT_TRUE(helpers.fallbackLimitReached(no_fallback_test, SSL_LIBRARY_VERSION_TLS_1_1));
+  ASSERT_TRUE(helpers.fallbackLimitReached(no_fallback_test, SSL_LIBRARY_VERSION_TLS_1_0));
+}
new file mode 100644
--- /dev/null
+++ b/security/manager/tools/genIntolerantFallbackList.js
@@ -0,0 +1,264 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// How to run this file:
+// 1. [obtain firefox source code]
+// 2. [build/obtain firefox binaries]
+// 3. run `[path to]/run-mozilla.sh [path to]/xpcshell \
+//                                  [path to]/genIntolerantFallbackList.js \
+//                                  [absolute path to]/IntolerantFallbackList.inc
+
+const { 'classes': Cc, 'interfaces': Ci, 'utils': Cu, 'results': Cr } = Components;
+
+const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
+const { FileUtils } = Cu.import("resource://gre/modules/FileUtils.jsm", {});
+const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
+const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
+
+const SEC_ERROR_UNKNOWN_ISSUER = 0x805a1ff3;
+
+const OUTPUT = "IntolerantFallbackList.inc";
+const ERROR_OUTPUT = "IntolerantFallbackList.errors";
+const MAX_CONCURRENT_REQUESTS = 5;
+const MAX_RETRIES = 3;
+const REQUEST_TIMEOUT = 30 * 1000;
+const TEST_DOMAINS = {
+  "fallback.test": true,
+};
+
+const FILE_HEADER = `/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+///////////////////////////////////////////////////////////////////////////////
+// This is an automatically generated file. If you're not
+// nsNSSIOLayer.cpp, you shouldn't be #including it.
+///////////////////////////////////////////////////////////////////////////////
+
+static const char* const kIntolerantFallbackList[] =
+{
+`;
+
+const FILE_FOOTER = "};\n";
+
+let errorTable = {};
+let errorWithoutFallbacks = {};
+
+try {
+
+  if (arguments.length != 1) {
+    throw "Usage: genIntolerantFallbackList.js " +
+          "<absolute path to IntolerantFallbackList.inc> ";
+  }
+
+  // initialize the error message table
+  for (let name in Cr) {
+    errorTable[Cr[name]] = name;
+  }
+
+  // disable the current fallback list so it won't interfere with requests we make
+  Services.prefs.setBoolPref("security.tls.insecure_fallback_hosts.use_static_list", false);
+
+  // get the current preload list
+  let gIntolerantFallbackList = readCurrentList(arguments[0]);
+
+  // get the fallback status of each host without whitelist
+  let fallbackStatuses = [];
+  getFallbackStatuses(gIntolerantFallbackList, fallbackStatuses);
+
+  // reenable the current fallback list
+  Services.prefs.clearUserPref("security.tls.insecure_fallback_hosts.use_static_list");
+
+  // get the fallback status of each host with whitelist
+  for (let entry of fallbackStatuses) {
+    entry.errorWithoutFallback = entry.error;
+    delete entry.error;
+    entry.retries = MAX_RETRIES;
+  }
+  gIntolerantFallbackList = fallbackStatuses;
+  fallbackStatuses = [];
+  getFallbackStatuses(gIntolerantFallbackList, fallbackStatuses);
+
+  // sort the hosts alphabetically
+  fallbackStatuses.sort(function(a, b) {
+    return (a.name > b.name ? 1 : (a.name < b.name ? -1 : 0));
+  });
+
+  // write the results to a file (this is where we filter out hosts that we
+  // either could connect to without list, or couldn't connect to with list)
+  output(fallbackStatuses);
+
+} catch (e) {
+  dump([e, e.stack].join("\n"));
+  throw e;
+}
+
+function readCurrentList(filename) {
+  let currentHosts = [];
+  let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
+  file.initWithPath(filename);
+  let fis = Cc["@mozilla.org/network/file-input-stream;1"]
+              .createInstance(Ci.nsILineInputStream);
+  fis.init(file, -1, -1, Ci.nsIFileInputStream.CLOSE_ON_EOF);
+  let line = {};
+  let entryRegex = /  "([^"]*)",(?: \/\/ (.*))?/;
+  while (fis.readLine(line)) {
+    let match = entryRegex.exec(line.value);
+    if (match) {
+      currentHosts.push({
+        name: match[1],
+        comment: match[2],
+        retries: MAX_RETRIES}
+      );
+    }
+  }
+  return currentHosts;
+}
+
+function getFallbackStatuses(inHosts, outStatuses) {
+  const expectedOutputLength = inHosts.length;
+  let tmpOutput = [];
+  function handleOneHost() {
+    let host = inHosts.shift();
+    dump("spinning off request to '" + host.name + "' (remaining retries: " +
+         host.retries + ")\n");
+    getFallbackStatus(host, tmpOutput);
+  }
+
+  for (let i = 0; i < MAX_CONCURRENT_REQUESTS && inHosts.length > 0; i++) {
+    handleOneHost();
+  }
+  while (outStatuses.length != expectedOutputLength) {
+    waitForAResponse(tmpOutput);
+    let response = tmpOutput.shift();
+    dump("request to '" + response.name + "' finished: " +
+         errorToString(response.error) + "\n");
+    outStatuses.push(response);
+
+    if (inHosts.length > 0) {
+      handleOneHost();
+    }
+  }
+}
+
+function getFallbackStatus(host, resultList) {
+  if (TEST_DOMAINS[host.name]) {
+    host.error = Cr.NS_OK;
+    host.retries--;
+    resultList.push(host);
+    return;
+  }
+  let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
+            .createInstance(Ci.nsIXMLHttpRequest);
+  let inResultList = false;
+  let uri = "https://" + host.name + "/";
+  req.open("GET", uri, true);
+  req.timeout = REQUEST_TIMEOUT;
+  req.channel.notificationCallbacks = new RedirectAndAuthStopper();
+  req.onreadystatechange = function(event) {
+    if (!inResultList && req.readyState == 4) {
+      inResultList = true;
+      // If the url is changed, a redirect happened that means
+      // a successfull TLS handshake. Treat it as success rather than
+      // using a status from the redirect target.
+      host.error = uri == req.responseURL ? req.channel.status : Cr.NS_OK;
+      host.retries--;
+      resultList.push(host);
+    }
+  };
+
+  try {
+    req.send();
+  }
+  catch (e) {
+    dump("ERROR: exception making request to " + host.name + ": " + e + "\n");
+  }
+}
+
+// RedirectAndAuthStopper prevents redirects and HTTP authentication
+function RedirectAndAuthStopper() {};
+
+RedirectAndAuthStopper.prototype = {
+  // nsIChannelEventSink
+  asyncOnChannelRedirect: function(oldChannel, newChannel, flags, callback) {
+    throw Cr.NS_ERROR_ENTITY_CHANGED;
+  },
+
+  // nsIAuthPrompt2
+  promptAuth: function(channel, level, authInfo) {
+    return false;
+  },
+
+  asyncPromptAuth: function(channel, callback, context, level, authInfo) {
+    throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+  },
+
+  getInterface: function(iid) {
+    return this.QueryInterface(iid);
+  },
+
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIChannelEventSink,
+                                         Ci.nsIAuthPrompt2])
+};
+
+// Since all events are processed on the main thread, and since event
+// handlers are not preemptible, there shouldn't be any concurrency issues.
+function waitForAResponse(outputList) {
+  // From <https://developer.mozilla.org/en/XPConnect/xpcshell/HOWTO>
+  let threadManager = Cc["@mozilla.org/thread-manager;1"]
+                      .getService(Ci.nsIThreadManager);
+  let mainThread = threadManager.currentThread;
+  while (outputList.length == 0) {
+    mainThread.processNextEvent(true);
+  }
+}
+
+function errorToString(error) {
+  return error != undefined ? errorTable[error] || ("0x" + error.toString(16)) : error;
+}
+
+function formatComment(comment) {
+  return comment ? " // " + comment : "";
+}
+
+function success(error) {
+  return error == Cr.NS_OK || error == SEC_ERROR_UNKNOWN_ISSUER;
+}
+
+function output(sortedStatuses) {
+  let file = FileUtils.getFile("CurWorkD", [OUTPUT]);
+  let errorFile = FileUtils.getFile("CurWorkD", [ERROR_OUTPUT]);
+  let fos = FileUtils.openSafeFileOutputStream(file);
+  let eos = FileUtils.openSafeFileOutputStream(errorFile);
+  writeTo(FILE_HEADER, fos);
+  for (let status of sortedStatuses) {
+
+    if (!TEST_DOMAINS[status.name] &&
+        success(status.errorWithoutFallback)) {
+      dump("INFO: " + status.name + " does NOT require fallback\n");
+      writeTo(status.name + ": worked (" +
+              errorToString(status.errorWithoutFallback) + " / " +
+              errorToString(status.error) + ")" +
+              formatComment(status.comment) + "\n", eos);
+    } else {
+      if (!success(status.error)) {
+        dump("INFO: " + status.name + " is dead?\n");
+        writeTo(status.name + ": failed (" +
+                errorToString(status.errorWithoutFallback) + " / " +
+                errorToString(status.error) + ")" +
+                formatComment(status.comment) + "\n", eos);
+      }
+      dump("INFO: " + status.name + " ON the fallback list\n");
+      writeTo("  \"" + status.name + "\"," +
+              formatComment(status.comment) + "\n", fos);
+    }
+  }
+  writeTo(FILE_FOOTER, fos);
+  FileUtils.closeSafeFileOutputStream(fos);
+  FileUtils.closeSafeFileOutputStream(eos);
+}
+
+function writeTo(string, fos) {
+  fos.write(string, string.length);
+}