bug 1549249 - hard-code new add-on signing intermediate so it's always available r=jcj,kmag a=tomprince
authorDana Keeler <dkeeler@mozilla.com>
Mon, 06 May 2019 23:12:36 +0000
changeset 516455 5b264ffa56e752df9a66c8a781e06fde51ada9e8
parent 516454 0e3d04885173d7b2cf9c920f5372b815f0e4b6a5
child 516456 96d2576eae4baf0aa961b4f5a1dadd26bb8ee823
push id2025
push usermozilla@hocat.ca
push dateMon, 06 May 2019 23:34:21 +0000
treeherdermozilla-release@5b264ffa56e7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjcj, kmag, tomprince
bugs1549249
milestone66.0.5
bug 1549249 - hard-code new add-on signing intermediate so it's always available r=jcj,kmag a=tomprince 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 848b15028562c6757748070f637e0e4f0bbb5f65 (the patch that implemented the original approach) because it should no longer be necessary. This also bumps the add-on DB schema to trigger add-on revalidation. Differential Revision: https://phabricator.services.mozilla.com/D30140
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/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/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -99,17 +99,17 @@ const STARTUP_MTIME_SCOPES = [KEY_APP_GL
                               KEY_APP_SYSTEM_SHARE,
                               KEY_APP_SYSTEM_USER];
 
 const NOTIFICATION_FLUSH_PERMISSIONS  = "flush-pending-permissions";
 const XPI_PERMISSION                  = "install";
 
 const XPI_SIGNATURE_CHECK_PERIOD      = 24 * 60 * 60;
 
-const DB_SCHEMA = 29;
+const DB_SCHEMA = 30;
 
 function encoded(strings, ...values) {
   let result = [];
 
   for (let [i, string] of strings.entries()) {
     result.push(string);
     if (i < values.length)
       result.push(encodeURIComponent(values[i]));
@@ -1875,39 +1875,16 @@ class BootstrapScope {
       await updateCallback();
     }
 
     this.addon = newAddon;
     return this._install(reason, callUpdate, startup, extraArgs);
   }
 }
 
-// https://bugzilla.mozilla.org/show_bug.cgi?id=1548973
-const MISSING_INTERMEDIATE_CERTIFICATE = "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";
-
-function addMissingIntermediateCertificate() {
-  const PREF_SIGNER_HOTFIXED = "extensions.signer.hotfixed";
-  let hotfixApplied = Services.prefs.getBoolPref(PREF_SIGNER_HOTFIXED, false);
-  if (hotfixApplied) {
-    return;
-  }
-  logger.debug("hotfix for addon signing cert has not been applied; applying");
-
-  try {
-    let certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(Ci.nsIX509CertDB);
-    certDB.addCertFromBase64(MISSING_INTERMEDIATE_CERTIFICATE, ",,");
-    logger.debug("new intermediate certificate added");
-  } catch (e) {
-    logger.error("failed to add new intermediate certificate:", e);
-    return;
-  }
-
-  Services.prefs.setBoolPref(PREF_SIGNER_HOTFIXED, true);
-}
-
 var XPIProvider = {
   get name() {
     return "XPIProvider";
   },
 
   BOOTSTRAP_REASONS: Object.freeze(BOOTSTRAP_REASONS),
 
   // A Map of active addons to their bootstrapScope by ID
@@ -2133,20 +2110,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);