bug 1549249 - hard-code new add-on signing intermediate so it's always available r=jcj,kmag a=ryanvm
authorDana Keeler <dkeeler@mozilla.com>
Mon, 06 May 2019 10:42:52 -0700
changeset 531478 c52835481c084fecff479ddf35e06054c5e0ba32
parent 531477 df3eadfa74a8061f4c88496404d51baf47e21070
child 531479 d5a6ca2d0e9d4b68fc1d316ab07d9f4e38a8f11e
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjcj, kmag, ryanvm
bugs1549249
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 1549249 - hard-code new add-on signing intermediate so it's always available r=jcj,kmag a=ryanvm Summary: Our previous approach to making this intermediate available relied on being able to add it to the user's NSS cert DB. This does work in the majority of cases, but there are some situations where it doesn't work (e.g. if the user's DB is set to read only, if they've configured Firefox to run in "nocertdb" mode, if they have a master password but forgot it, and so on). This patch compiles the intermediate in to Firefox in the same way we incorporate the root, so it should always be available. At the same time, this patch reverts the changes from 023dd959512e2cfa685187616560f91efa91183c and 1d35f8d88bdd007e01d42c4ff76c6d10d7c01a98 (the patches that implemented the original approach) because they should no longer be necessary. Reviewers: jcj!, kmag! Tags: #secure-revision Bug #: 1549249 Differential Revision: https://phabricator.services.mozilla.com/D30090
security/apps/AppTrustDomain.cpp
security/apps/AppTrustDomain.h
security/apps/addons-public-intermediate.crt
security/apps/gen_cert_header.py
security/apps/moz.build
toolkit/mozapps/extensions/internal/XPIInstall.jsm
toolkit/mozapps/extensions/internal/XPIProvider.jsm
--- a/security/apps/AppTrustDomain.cpp
+++ b/security/apps/AppTrustDomain.cpp
@@ -19,16 +19,17 @@
 #include "nsNetUtil.h"
 #include "mozpkix/pkixnss.h"
 #include "prerror.h"
 
 // Generated by gen_cert_header.py, which gets called by the build system.
 #include "xpcshell.inc"
 // Add-on signing Certificates
 #include "addons-public.inc"
+#include "addons-public-intermediate.inc"
 #include "addons-stage.inc"
 // Privileged Package Certificates
 #include "privileged-package-root.inc"
 
 using namespace mozilla::pkix;
 
 extern mozilla::LazyLogModule gPIPNSSLog;
 
@@ -120,16 +121,33 @@ nsresult AppTrustDomain::SetTrustedRoot(
   }
 
   mTrustedRoot.reset(CERT_NewTempCertificate(
       CERT_GetDefaultCertDB(), &trustedDER, nullptr, false, true));
   if (!mTrustedRoot) {
     return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
   }
 
+  // If we're verifying add-ons signed by our production root, we want to make
+  // sure a valid intermediate certificate is available for path building.
+  // Merely holding this alive in memory makes it available for NSS to find in
+  // AppTrustDomain::FindIssuer.
+  if (trustedRoot == nsIX509CertDB::AddonsPublicRoot) {
+    SECItem intermediateDER = {
+        siBuffer,
+        const_cast<uint8_t*>(addonsPublicIntermediate),
+        mozilla::ArrayLength(addonsPublicIntermediate),
+    };
+    mAddonsIntermediate.reset(CERT_NewTempCertificate(
+        CERT_GetDefaultCertDB(), &intermediateDER, nullptr, false, true));
+    if (!mAddonsIntermediate) {
+      return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
+    }
+  }
+
   return NS_OK;
 }
 
 Result AppTrustDomain::FindIssuer(Input encodedIssuerName,
                                   IssuerChecker& checker, Time)
 
 {
   MOZ_ASSERT(mTrustedRoot);
--- a/security/apps/AppTrustDomain.h
+++ b/security/apps/AppTrustDomain.h
@@ -72,16 +72,17 @@ class AppTrustDomain final : public mozi
                            mozilla::pkix::DigestAlgorithm digestAlg,
                            /*out*/ uint8_t* digestBuf,
                            size_t digestBufLen) override;
 
  private:
   /*out*/ UniqueCERTCertList& mCertChain;
   void* mPinArg;  // non-owning!
   UniqueCERTCertificate mTrustedRoot;
+  UniqueCERTCertificate mAddonsIntermediate;
 
   static StaticMutex sMutex;
   static UniquePtr<unsigned char[]> sDevImportedDERData;
   static unsigned int sDevImportedDERLen;
 };
 
 }  // namespace psm
 }  // namespace mozilla
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d37979bf3839dd41bb175a3887cc8023507bdde2
GIT binary patch
literal 1841
zc$_n6V%IfjVijG$%*4pV#4NzTVZh7AsnzDu_MMlJk%yJRpw^JvfRl|ml!Z;0DKywn
z#y|?h;Sv`1&9BPL$w^dj&Mzv+FG?)Q%+E8_H_!#iato`$WF39|6#|O#Q%aLT3KW7f
z)AKU((iMVJi^?*SQw`+}WI-C3g~f{U^GkG-6LkyViggon^9|(0c@0esOn?v!qQrTP
zkhunp%W3L9H3Joh`(%qDGRcXCdWk71`FX{9xez1t@{7_96%FL!!N$obCX|+6QJk9W
z08^5jpKH*>q=X!{jI0dIO-%d@KyfanCMHIP{i~uEb@XqrUe(6jef;gg_fcP8mRavr
ztG<1x>UL62;#RMC@AcfdH;zf&{_XOw^=gH?f3wKFe{4HWFO_$+i2Sy6_VM)__r7JB
z;-m73NwqG7W5=$Ld7Za@tc+D{tUnW7@Sx7N&uj9ce}XfnWxh%>&OKDREZO9d6NB6a
zkxIAfH&-T~`_MM&)|;%iYbq}1pWf@MvTruW!+q@MKQ!H3n^BxU@&CykYWzEHWK8Vf
z?Z3vCwY4#P%iS*vkJ#E8#rnUg{j+$cw8+led8@LxSN`$*%5gtfNrm-*dHSw3%sn4G
zR}`?B2<UkQb%|?AOYEt6c$o3YfwtS#OEi5wJy!iOHTW4|ckbry&x~^;H%XeTQkRZc
z<e7cpSW8@yZ*qmXi1}A{=atLz4+{2&wim{H`L%0hlA=_zQRMA;3)Q54qzbMud$Y6i
z$=jJmn}znBlwwtTXL#3?amJyZ>m3&~b{Ot^WE>g!YZc#|!+YlaG2`9&-HuoJlCRnl
zucMt`nm=~1S|6F;#&PCWdaT6Vz`m0kyLbF?o~mA@!E|83an)}ej<>S!vpbg``nN8s
z?9^_Fg{yxxFFW7b7ty<K-=WtlJ3{LBuJdVE)@y5MRXw!t$mb(kho4NSxW2M|u}AVb
zfBmkK<U@=0EdHT>ch9z2rJtGJ$y_@j{Y)yzFD$^U>VMw0YcsZfbqn~U(SGFqbxkH_
zMh3>kO^lreO^mGuJiufpE6l=bz|6?_-+&Lq;|H=>Sb!Oo%|HyqR|WBT47k`hwAmP0
zS=pJH!I?>xk420{M9l8D%zqy3$v<X`Ue{fG=vhVLowo*!D?swfER72c8s|2MY~J%K
zqGa{Myb7&NtLG@otw`3HzI|b1<C6LT&h$-;j0VPRoC$3njBP)h7+F}<#8fg$N(!v>
z^)a)aesZFIa#4<6L29mnAIN)hEba!b3!M!Vn&g1_F0UjtuS6G=c@s-Yi&Bww8pt=v
z;#YuL6f%QyX?*b6Y5Jdq_Ly&3d+CexpUWkok1jr0b8P2v>%w!Pi?dxF0w%RM%iX`O
zY_l(2K>dcLi@%uYIdjFwAI@&j*p=t{K;+E3TRs2(&wISD^=hjE`<CSsOs*~wULHRC
zqP}fVcSq-6U-qESB6}{m9DMp-i~q3c)^}XnC+#(4$mX1=EY+LTwy2Te&+!hYGwGsR
zI(EkS&N5I6yRrV4+DhK%Ug<i*DfV)$Rcbsc%74x~dYmtR|Gdz>>FtXOi=<m`ua-Pc
z)-IbRn(|cRMq7oc$-k&Co1V^h*v)%tMzG;Fu9H?15^BN|X1@6HySID$*6+UO_nfn?
zSx}i1IZ0pV;5C8LgjVl<{~Igp)X!Hs@EFuyV`gOEeesrDw3}g;&YL`|*S@BQ1Lys_
zVz)Y!>(bF%rqPc-sFh5${$v%;cfPT)|Lx74$5;a$cXLg;v3lwDze~2sNf>SV$+uNd
z;k-s{YJiK-#&i2E?khZ#>$khLYolIS%*-sg&ngzzPThRaP#0cf=F=eih$oUkRy=#r
z{JC<>A0=3xoltA!;(FWvu<Uy+lk}DdH;)e<b~DVIsyeO}YaIP~yQ(;g#ZBdzs1a*W
zm$HyifxeQK%<8%dE|;W<)m>@Rie9#wM_l}+sw~_V6x3QMb**0Y=9BuPp$;dKSojyc
f+vmUW*YVXavwRKvnjdaXmOD4Ay_3<_cyT)bbL!^r
--- a/security/apps/gen_cert_header.py
+++ b/security/apps/gen_cert_header.py
@@ -27,16 +27,17 @@ def _create_header(array_name, cert_byte
 # Create functions named the same as the data arrays that we're going to
 # write to the headers, so we don't have to duplicate the names like so:
 #
 #   def arrayName(header, cert_filename):
 #     header.write(_create_header("arrayName", cert_filename))
 array_names = [
     'xpcshellRoot',
     'addonsPublicRoot',
+    'addonsPublicIntermediate',
     'addonsStageRoot',
     'privilegedPackageRoot',
 ]
 
 for n in array_names:
     # Make sure the lambda captures the right string.
     globals()[n] = lambda header, cert_filename, name=n: header.write(
         _create_header(name, _file_byte_generator(cert_filename)))
--- a/security/apps/moz.build
+++ b/security/apps/moz.build
@@ -34,16 +34,17 @@ if CONFIG['CC_TYPE'] in ('clang', 'gcc')
         '-Wno-unused-parameter',
     ]
 
 test_ssl_path = '/security/manager/ssl/tests/unit'
 
 headers_arrays_certs = [
     ('xpcshell.inc', 'xpcshellRoot', test_ssl_path + '/test_signed_apps/xpcshellTestRoot.der'),
     ('addons-public.inc', 'addonsPublicRoot', 'addons-public.crt'),
+    ('addons-public-intermediate.inc', 'addonsPublicIntermediate', 'addons-public-intermediate.crt'),
     ('addons-stage.inc', 'addonsStageRoot', 'addons-stage.crt'),
     ('privileged-package-root.inc', 'privilegedPackageRoot', 'privileged-package-root.der'),
 ]
 
 for header, array_name, cert in headers_arrays_certs:
     GENERATED_FILES += [header]
     h = GENERATED_FILES[header]
     h.script = 'gen_cert_header.py:' + array_name
--- a/toolkit/mozapps/extensions/internal/XPIInstall.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIInstall.jsm
@@ -3258,51 +3258,16 @@ class SystemAddonInstaller extends Direc
 
     return newFile;
   }
 
   // old system add-on upgrade dirs get automatically removed
   uninstallAddon(aAddon) {}
 }
 
-// https://bugzilla.mozilla.org/show_bug.cgi?id=1548973
-const MISSING_INTERMEDIATE_CERTIFICATE = "\
-MIIHLTCCBRWgAwIBAgIDEAAIMA0GCSqGSIb3DQEBDAUAMH0xCzAJBgNVBAYTAlVTMRwwGgYDVQQKEx\
-NNb3ppbGxhIENvcnBvcmF0aW9uMS8wLQYDVQQLEyZNb3ppbGxhIEFNTyBQcm9kdWN0aW9uIFNpZ25p\
-bmcgU2VydmljZTEfMB0GA1UEAxMWcm9vdC1jYS1wcm9kdWN0aW9uLWFtbzAeFw0xNTA0MDQwMDAwMD\
-BaFw0yNTA0MDQwMDAwMDBaMIGnMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTTW96aWxsYSBDb3Jwb3Jh\
-dGlvbjEvMC0GA1UECxMmTW96aWxsYSBBTU8gUHJvZHVjdGlvbiBTaWduaW5nIFNlcnZpY2UxJjAkBg\
-NVBAMTHXNpZ25pbmdjYTEuYWRkb25zLm1vemlsbGEub3JnMSEwHwYJKoZIhvcNAQkBFhJmb3hzZWNA\
-bW96aWxsYS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/qluiiI+wO6qGA4vH7c\
-HvWvXpdju9JnvbwnrbYmxhtUpfS68LbdjGGtv7RP6F1XhHT4MU3v4GuMulH0E4Wfalm8evsb3tBJRM\
-JPICJX5UCLi6VJ6J2vipXSWBf8xbcOB+PY5Kk6L+EZiWaepiM23CdaZjNOJCAB6wFHlGe+zUk87whp\
-La7GrtrHjTb8u9TSS+mwjhvgfP8ILZrWhzb5H/ybgmD7jYaJGIDY/WDmq1gVe03fShxD09Ml1P7H38\
-o5kbFLnbbqpqC6n8SfUI31MiJAXAN2e6rAOM8EmocAY0EC5KUooXKRsYvHzhwwHkwIbbe6QpTUlIqv\
-w1MPlQPs7Zu/MBnVmyGTSqJxtYoklr0MaEXnJNY3g3FDf1R0Opp2/BEY9Vh3Fc9Pq6qWIhGoMyWdue\
-oSYa+GURqDbsuYnk7ZkysxK+yRoFJu4x3TUBmMKM14jQKLgxvuIzWVn6qg6cw7ye/DYNufc+DSPSTS\
-akSsWJ9IPxiAU7xJ+GCMzaZ10Y3VGOybGLuPxDlSd6KALAoMcl9ghB2mvfB0N3wv6uWnbKuxihq/qD\
-ps+FjliNvr7C66mIVH+9rkyHIy6GgIUlwr7E88Qqw+SQeNeph6NIY85PL4p0Y8KivKP4J928tpp18w\
-LuHNbIG+YaUk5WUDZ6/2621pi19UZQ8iiHxN/XKQIDAQABo4IBiTCCAYUwDAYDVR0TBAUwAwEB/zAO\
-BgNVHQ8BAf8EBAMCAQYwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwMwHQYDVR0OBBYEFBY++xz/DCuT+J\
-sV1y2jwuZ4YdztMIGoBgNVHSMEgaAwgZ2AFLO86lh0q+FueCqyq5wjHqhjLJe3oYGBpH8wfTELMAkG\
-A1UEBhMCVVMxHDAaBgNVBAoTE01vemlsbGEgQ29ycG9yYXRpb24xLzAtBgNVBAsTJk1vemlsbGEgQU\
-1PIFByb2R1Y3Rpb24gU2lnbmluZyBTZXJ2aWNlMR8wHQYDVQQDExZyb290LWNhLXByb2R1Y3Rpb24t\
-YW1vggEBMDMGCWCGSAGG+EIBBAQmFiRodHRwOi8vYWRkb25zLm1vemlsbGEub3JnL2NhL2NybC5wZW\
-0wTgYDVR0eBEcwRaFDMCCCHi5jb250ZW50LXNpZ25hdHVyZS5tb3ppbGxhLm9yZzAfgh1jb250ZW50\
-LXNpZ25hdHVyZS5tb3ppbGxhLm9yZzANBgkqhkiG9w0BAQwFAAOCAgEAX1PNli/zErw3tK3S9Bv803\
-RV4tHkrMa5xztxzlWja0VAUJKEQx7f1yM8vmcQJ9g5RE8WFc43IePwzbAoum5F4BTM7tqM//+e476F\
-1YUgB7SnkDTVpBOnV5vRLz1Si4iJ/U0HUvMUvNJEweXvKg/DNbXuCreSvTEAawmRIxqNYoaigQD8x4\
-hCzGcVtIi5Xk2aMCJW2K/6JqkN50pnLBNkPx6FeiYMJCP8z0FIz3fv53FHgu3oeDhi2u3VdONjK3aa\
-FWTlKNiGeDU0/lr0suWfQLsNyphTMbYKyTqQYHxXYJno9PuNi7e1903PvM47fKB5bFmSLyzB1hB1YI\
-VLj0/YqD4nz3lADDB91gMBB7vR2h5bRjFqLOxuOutNNcNRnv7UPqtVCtLF2jVb4/AmdJU78jpfDs+B\
-gY/t2bnGBVFBuwqS2Kult/2kth4YMrL5DrURIM8oXWVQRBKxzr843yDmHo8+2rqxLnZcmWoe8yQ41s\
-rZ4IB+V3w2TIAd4gxZAB0Xa6KfnR4D8RgE5sgmgQoK7Y/hdvd9Ahu0WEZI8Eg+mDeCeojWcyjF+dt6\
-c2oERiTmFTIFUoojEjJwLyIqHKt+eApEYpF7imaWcumFN1jR+iUjE4ZSUoVxGtZ/Jdnkf8VVQMhiBA\
-+i7r5PsfrHq+lqTTGOg+GzYx7OmoeJAT0zo4c=";
-
 var XPIInstall = {
   // An array of currently active AddonInstalls
   installs: new Set(),
 
   createLocalInstall,
   flushJarCache,
   newVersionReason,
   recursiveRemove,
@@ -3331,24 +3296,16 @@ var XPIInstall = {
       try {
         c.cancel();
       } catch (e) {
         logger.warn("Cancel failed", e);
       }
     }
   },
 
-  addMissingIntermediateCertificate() {
-    logger.debug("hotfix for addon signing cert has not been applied; applying");
-
-    let certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(Ci.nsIX509CertDB);
-    certDB.addCertFromBase64(MISSING_INTERMEDIATE_CERTIFICATE, ",,");
-    logger.debug("new intermediate certificate added");
-  },
-
   /**
    * @param {string} id
    *        The expected ID of the add-on.
    * @param {nsIFile} file
    *        The XPI file to install the add-on from.
    * @param {XPIStateLocation} location
    *        The install location to install the add-on to.
    * @returns {AddonInternal}
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -1982,28 +1982,16 @@ class BootstrapScope {
       await updateCallback();
     }
 
     this.addon = newAddon;
     return this._install(reason, callUpdate, startup, extraArgs);
   }
 }
 
-function addMissingIntermediateCertificate() {
-  const PREF_SIGNER_HOTFIXED = "extensions.signer.hotfixed";
-  if (!Services.prefs.getBoolPref(PREF_SIGNER_HOTFIXED, false)) {
-    try {
-      XPIInstall.addMissingIntermediateCertificate();
-      Services.prefs.setBoolPref(PREF_SIGNER_HOTFIXED, true);
-    } catch (e) {
-      logger.error("failed to add new intermediate certificate:", e);
-    }
-  }
-}
-
 let resolveDBReady;
 let dbReadyPromise = new Promise(resolve => {
   resolveDBReady = resolve;
 });
 let resolveProviderReady;
 let providerReadyPromise = new Promise(resolve => {
   resolveProviderReady = resolve;
 });
@@ -2239,21 +2227,16 @@ var XPIProvider = {
    * @param {string?} [aOldAppVersion]
    *        The version of the application last run with this profile or null
    *        if it is a new profile or the version is unknown
    * @param {string?} [aOldPlatformVersion]
    *        The version of the platform last run with this profile or null
    *        if it is a new profile or the version is unknown
    */
   startup(aAppChanged, aOldAppVersion, aOldPlatformVersion) {
-    // Add missing certificate (bug 1548973). Mistakenly disabled add-ons are
-    // going to be re-enabled because the schema version bump forces a new
-    // signature verification check.
-    addMissingIntermediateCertificate();
-
     try {
       AddonManagerPrivate.recordTimestamp("XPI_startup_begin");
 
       logger.debug("startup");
 
       this.builtInAddons = {};
       try {
         let url = Services.io.newURI(BUILT_IN_ADDONS_URI);