diff --git a/xpinstall/macbuild/xpinstall.xml b/xpinstall/macbuild/xpinstall.xml
index fa1609a47fa4..8d6f8437e7df 100644
--- a/xpinstall/macbuild/xpinstall.xml
+++ b/xpinstall/macbuild/xpinstall.xml
@@ -1169,6 +1169,13 @@
Text
Debug
+
+ Name
+ CertReader.cpp
+ MacOS
+ Text
+ Debug
+
@@ -1356,6 +1363,11 @@
nsXPIProxy.cpp
MacOS
+
+ Name
+ CertReader.cpp
+ MacOS
+
@@ -2474,6 +2486,13 @@
Text
Debug
+
+ Name
+ CertReader.cpp
+ MacOS
+ Text
+ Debug
+
@@ -2661,6 +2680,11 @@
nsXPIProxy.cpp
MacOS
+
+ Name
+ CertReader.cpp
+ MacOS
+
@@ -2840,6 +2864,12 @@
nsXPIProxy.cpp
MacOS
+
+ xpinstallDebug.shlb
+ Name
+ CertReader.cpp
+ MacOS
+
NS Libraries
Optimized
diff --git a/xpinstall/macbuild/xpinstallIDL.xml b/xpinstall/macbuild/xpinstallIDL.xml
index 22316d51710e..84f5ab55f0e1 100644
--- a/xpinstall/macbuild/xpinstallIDL.xml
+++ b/xpinstall/macbuild/xpinstallIDL.xml
@@ -731,6 +731,13 @@
Text
+
+ Name
+ nsPICertNotification.idl
+ MacOS
+ Text
+
+
Name
nsIXPIDialogService.idl
@@ -762,6 +769,11 @@
nsPIXPIStubHook.idl
MacOS
+
+ Name
+ nsPICertNotification.idl
+ MacOS
+
Name
nsIXPIDialogService.idl
@@ -1452,6 +1464,13 @@
Text
+
+ Name
+ nsPICertNotification.idl
+ MacOS
+ Text
+
+
Name
nsIXPIDialogService.idl
@@ -1483,6 +1502,11 @@
nsPIXPIStubHook.idl
MacOS
+
+ Name
+ nsPICertNotification.idl
+ MacOS
+
Name
nsIXPIDialogService.idl
@@ -1521,6 +1545,12 @@
nsPIXPIStubHook.idl
MacOS
+
+ headers
+ Name
+ nsPICertNotification.idl
+ MacOS
+
headers
Name
diff --git a/xpinstall/public/Makefile.in b/xpinstall/public/Makefile.in
index 317b8522e543..b3bba3ef661a 100644
--- a/xpinstall/public/Makefile.in
+++ b/xpinstall/public/Makefile.in
@@ -37,6 +37,7 @@ XPIDLSRCS = \
nsIXPINotifier.idl \
nsPIXPIProxy.idl \
nsPIXPIStubHook.idl \
+ nsPICertNotification.idl \
$(NULL)
EXPORTS = \
diff --git a/xpinstall/public/nsISoftwareUpdate.h b/xpinstall/public/nsISoftwareUpdate.h
index e571b5b3ae96..81b32003ffac 100644
--- a/xpinstall/public/nsISoftwareUpdate.h
+++ b/xpinstall/public/nsISoftwareUpdate.h
@@ -58,6 +58,7 @@
{0xbc, 0xde, 0x00, 0x80, 0x5f, 0x0e, 0x13, 0x53}\
}
+class nsIPrincipal;
class nsISoftwareUpdate : public nsISupports
{
@@ -67,6 +68,7 @@ class nsISoftwareUpdate : public nsISupports
NS_IMETHOD InstallJar(nsIFile* localFile,
const PRUnichar* URL,
const PRUnichar* arguments,
+ nsIPrincipal* aPrincipalDisplayed,
PRUint32 flags,
nsIXPIListener* aListener = 0) = 0;
diff --git a/xpinstall/public/nsIXPIDialogService.idl b/xpinstall/public/nsIXPIDialogService.idl
index ae7380451a7c..bcff53cad836 100644
--- a/xpinstall/public/nsIXPIDialogService.idl
+++ b/xpinstall/public/nsIXPIDialogService.idl
@@ -63,11 +63,19 @@ interface nsIXPIDialogService : nsISupports
*
* @param parent a window that can be used to parent the modal dialog
*
- * @param packageList For each install package there will be two strings,
- * a display name and a source URL.
+ * @param packageList For each install package there will be three strings,
+ * a display name, a source URL, and a the name of the
+ * organization that signed this install. Note that the
+ * name of the signer is not verified. Verification
+ * happens when the the install has completely downloaded.
+ * Your user interface should only suggest that the
+ * install may be signed by this organization name.
+ * Note that an unsigned archive is indicated by an
+ * empty string.
*
* @param count The number of strings in the packageList. This
- * will always be even (twice the number of packages)
+ * will always be three times the number of
+ * packages.
*
* @return true to install, false to cancel
*/
@@ -91,7 +99,7 @@ interface nsIXPIDialogService : nsISupports
* be called or nsXPInstallManager will wait forever and never clean
* itself up.
*
- * @param packageList two strings per package as in confirmInstall()
+ * @param packageList three strings per package as in confirmInstall()
* @param count the number of strings in the list
* @param observer nsIObserver to receive messages from the dialog
*/
diff --git a/xpinstall/public/nsPICertNotification.idl b/xpinstall/public/nsPICertNotification.idl
new file mode 100644
index 000000000000..8061935f224c
--- /dev/null
+++ b/xpinstall/public/nsPICertNotification.idl
@@ -0,0 +1,48 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is XPInstall Signing.
+ *
+ * The Initial Developer of the Original Code is Doug Turner.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+interface nsIURI;
+interface nsIPrincipal;
+
+[uuid(42cd7162-ea4a-4088-9888-63ea5095869e)]
+interface nsPICertNotification : nsISupports
+{
+ void onCertAvailable(in nsIURI aURI,
+ in nsISupports aContext,
+ in PRUint32 aStatus,
+ in nsIPrincipal aPrincipal);
+};
diff --git a/xpinstall/res/content/institems.js b/xpinstall/res/content/institems.js
index 39f36a7cb681..dac74bd0f397 100644
--- a/xpinstall/res/content/institems.js
+++ b/xpinstall/res/content/institems.js
@@ -21,7 +21,7 @@
// dialog param block
var gParam;
-function addTreeItem(num, aName, aUrl)
+function addTreeItem(num, aName, aUrl, aCertName)
{
// first column is the package name
var item = document.createElement("description");
@@ -29,7 +29,14 @@ function addTreeItem(num, aName, aUrl)
item.setAttribute("tooltiptext", aUrl);
item.setAttribute("class", "confirmName");
- // second column is the host serving the file
+ // second column is for the cert name
+ var certName = document.createElement("description");
+ if (aCertName == "")
+ certName.setAttribute("value", "Unsigned"); // i18n!
+ else
+ certName.setAttribute("value", aCertName);
+
+ // third column is the host serving the file
var urltext = aUrl.replace(/^([^:]*:\/*[^\/]+).*/, "$1");
var url = document.createElement('description');
url.setAttribute("value", aUrl);
@@ -40,6 +47,7 @@ function addTreeItem(num, aName, aUrl)
// create row and add it to the grid
var row = document.createElement("row");
row.appendChild(item);
+ row.appendChild(certName);
row.appendChild(url);
document.getElementById("xpirows").appendChild(row);
@@ -49,7 +57,7 @@ function addTreeItem(num, aName, aUrl)
function onLoad()
{
var row = 0;
- var moduleName, URL, numberOfDialogTreeElements;
+ var moduleName, URL, certName, numberOfDialogTreeElements;
doSetOKCancel(onOk, onCancel);
@@ -63,7 +71,9 @@ function onLoad()
{
moduleName = gParam.GetString(i);
URL = gParam.GetString(++i);
- addTreeItem(row++, moduleName, URL);
+ certName = gParam.GetString(++i);
+
+ addTreeItem(row++, moduleName, URL, certName);
}
var okText = document.getElementById("xpinstallBundle").getString("OK");
diff --git a/xpinstall/res/content/institems.xul b/xpinstall/res/content/institems.xul
index c12f8a339c03..094f11242e98 100644
--- a/xpinstall/res/content/institems.xul
+++ b/xpinstall/res/content/institems.xul
@@ -54,6 +54,7 @@ Contributor(s):
+
diff --git a/xpinstall/res/content/xpistatus.js b/xpinstall/res/content/xpistatus.js
index 60bbf880e269..9ad34f63a13e 100644
--- a/xpinstall/res/content/xpistatus.js
+++ b/xpinstall/res/content/xpistatus.js
@@ -122,6 +122,7 @@ function onLoad()
{
var moduleName = param.GetString(i++);
var URL = param.GetString(i++);
+ var certName = param.GetString(i++);
addTreeItem(row++, moduleName, URL);
}
diff --git a/xpinstall/res/locale/en-US/xpinstall.properties b/xpinstall/res/locale/en-US/xpinstall.properties
index 0d2f112c7177..8660f96aa184 100644
--- a/xpinstall/res/locale/en-US/xpinstall.properties
+++ b/xpinstall/res/locale/en-US/xpinstall.properties
@@ -102,6 +102,7 @@ error-230=Already exists
error-235=Out of space
error-239=Chrome registration failed
error-240=Unfinished install
+error-260=Signing could not be verified.
error-299=Out of memory
# there are other error codes, either rare or obsolete,
diff --git a/xpinstall/src/CertReader.cpp b/xpinstall/src/CertReader.cpp
new file mode 100644
index 000000000000..8cea98465bff
--- /dev/null
+++ b/xpinstall/src/CertReader.cpp
@@ -0,0 +1,249 @@
+/* ***** BEGIN LICENSE BLOCK *****
++ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is XPInstall Signing.
+ *
+ * The Initial Developer of the Original Code is Doug Turner.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "zlib.h"
+#include "zipstruct.h"
+
+#include "CertReader.h"
+
+#include "nsCRT.h"
+#include "nsIServiceManager.h"
+#include "nsISignatureVerifier.h"
+#include "nsIInputStream.h"
+
+#include "nsNetUtil.h"
+
+// just a guess at the max size of the cert.
+#define MAX_SIGNATURE_SIZE (32*1024)
+
+
+/*
+ * x t o i n t
+ *
+ * Converts a two byte ugly endianed integer
+ * to our platform's integer.
+ *
+ */
+
+static unsigned int xtoint (unsigned char *ii)
+{
+ return (int) (ii [0]) | ((int) ii [1] << 8);
+}
+
+/*
+ * x t o l o n g
+ *
+ * Converts a four byte ugly endianed integer
+ * to our platform's integer.
+ *
+ */
+
+static unsigned long xtolong (unsigned char *ll)
+{
+ unsigned long ret;
+
+ ret = ((((unsigned long) ll [0]) << 0) |
+ (((unsigned long) ll [1]) << 8) |
+ (((unsigned long) ll [2]) << 16) |
+ (((unsigned long) ll [3]) << 24) );
+
+ return ret;
+}
+
+static int my_inflate(unsigned char* compr, PRUint32 comprLen, unsigned char* uncompr, PRUint32 uncomprLen)
+{
+ int err;
+ z_stream d_stream; /* decompression stream */
+ memset (&d_stream, 0, sizeof (d_stream));
+
+ // buffer is way to small to even deal with.
+ if (uncomprLen < 10)
+ return -1;
+
+ *uncompr = '\0';
+
+ if (inflateInit2 (&d_stream, -MAX_WBITS) != Z_OK)
+ return -1;
+
+ d_stream.next_in = compr;
+ d_stream.avail_in = (uInt)comprLen;
+
+ d_stream.next_out = uncompr;
+ d_stream.avail_out = (uInt)uncomprLen;
+
+ err = inflate(&d_stream, Z_NO_FLUSH);
+
+ if (err != Z_OK && err != Z_STREAM_END) {
+ inflateEnd(&d_stream);
+ return -1;
+ }
+
+ err = inflateEnd(&d_stream);
+ if (err != Z_OK) {
+ return -1;
+ }
+ return 0;
+}
+
+CertReader::CertReader(nsIURI* aURI, nsISupports* aContext, nsPICertNotification* aObs)
+{
+ NS_INIT_ISUPPORTS();
+ mObserver = aObs;
+ mContext = aContext;
+ mURI = aURI;
+}
+
+CertReader::~CertReader()
+{
+}
+
+NS_IMPL_ISUPPORTS2(CertReader, nsIStreamListener, nsIRequestObserver)
+
+NS_IMETHODIMP
+CertReader::OnStartRequest(nsIRequest *request, nsISupports* context)
+{
+ mVerifier = do_GetService(SIGNATURE_VERIFIER_CONTRACTID);
+ if (!mVerifier)
+ return NS_BINDING_ABORTED;
+
+ mLeftoverBuffer.Truncate();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+CertReader::OnDataAvailable(nsIRequest *request,
+ nsISupports* context,
+ nsIInputStream *aIStream,
+ PRUint32 aSourceOffset,
+ PRUint32 aLength)
+{
+ if (!mVerifier)
+ return NS_BINDING_ABORTED;
+
+ char buf[4096];
+ PRUint32 amt, size;
+ nsresult rv;
+
+ while (aLength)
+ {
+ size = PR_MIN(aLength, sizeof(buf));
+
+ rv = aIStream->Read(buf, size, &amt);
+
+ if (NS_FAILED(rv))
+ return rv;
+
+ aLength -= amt;
+
+ mLeftoverBuffer.Append(buf, amt);
+
+ if (mLeftoverBuffer.Length() < ZIPLOCAL_SIZE)
+ continue;
+
+ const char* caret = mLeftoverBuffer.get();
+ const char* end = caret + mLeftoverBuffer.Length();
+
+ ZipLocal_* ziplocal = (ZipLocal_*) caret;
+
+ if (xtolong(ziplocal->signature) != LOCALSIG)
+ return NS_BINDING_ABORTED;
+
+ // did we read the entire file entry into memory?
+ PRUint32 fileEntryLen = (ZIPLOCAL_SIZE +
+ xtoint(ziplocal->filename_len) +
+ xtoint(ziplocal->extrafield_len) +
+ xtolong(ziplocal->size));
+
+
+ // prevent downloading a huge file on an unsigned cert
+ if (fileEntryLen > MAX_SIGNATURE_SIZE)
+ return NS_BINDING_ABORTED;
+
+ if (mLeftoverBuffer.Length() < fileEntryLen)
+ {
+ // we are just going to buffer and continue.
+ continue;
+ }
+
+ // the assumption here is that we have the fileEntry in mLeftoverBuffer
+
+ const char* data = (caret +
+ ZIPLOCAL_SIZE +
+ xtoint(ziplocal->filename_len) +
+ xtoint(ziplocal->extrafield_len));
+
+ PRUint32 orgSize = xtolong ((unsigned char *) ziplocal->orglen);
+ PRUint32 cSize = xtolong ((unsigned char *) ziplocal->size);
+
+ if (orgSize == 0)
+ return NS_ERROR_FAILURE;
+
+ unsigned char* orgData = (unsigned char*) malloc(orgSize);
+
+ if (!orgData)
+ return NS_BINDING_ABORTED;
+
+ int err = my_inflate((unsigned char*)data,
+ cSize,
+ orgData,
+ orgSize);
+
+ if (err == 0)
+ {
+ PRInt32 verifyError;
+ rv = mVerifier->VerifySignature((char*)orgData, orgSize, nsnull, 0,
+ &verifyError, getter_AddRefs(mPrincipal));
+ }
+ if (orgData)
+ free(orgData);
+
+ return NS_BINDING_ABORTED;
+ }
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+CertReader::OnStopRequest(nsIRequest *request, nsISupports* context,
+ nsresult aStatus)
+{
+ mObserver->OnCertAvailable(mURI,
+ mContext,
+ aStatus,
+ mPrincipal);
+
+ return NS_OK;
+}
+
+
diff --git a/xpinstall/src/CertReader.h b/xpinstall/src/CertReader.h
new file mode 100644
index 000000000000..22e62a750a30
--- /dev/null
+++ b/xpinstall/src/CertReader.h
@@ -0,0 +1,63 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is XPInstall Signing.
+ *
+ * The Initial Developer of the Original Code is Doug Turner.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsCOMPtr.h"
+#include "nsIStreamListener.h"
+#include "nsString.h"
+#include "nsISignatureVerifier.h"
+#include "nsICertificatePrincipal.h"
+#include "nsIPrincipal.h"
+#include "nsIURI.h"
+#include "nsPICertNotification.h"
+
+class CertReader : public nsIStreamListener
+{
+public:
+ CertReader(nsIURI* uri, nsISupports* aContext, nsPICertNotification* aObs);
+ virtual ~CertReader();
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIREQUESTOBSERVER
+ NS_DECL_NSISTREAMLISTENER
+
+private:
+ nsCString mLeftoverBuffer;
+ nsCOMPtr mPrincipal;
+ nsCOMPtr mVerifier;
+
+ nsCOMPtr mContext;
+ nsCOMPtr mURI;
+ nsCOMPtr mObserver;
+};
diff --git a/xpinstall/src/Makefile.in b/xpinstall/src/Makefile.in
index 46bbf0bea476..3582efa98ed0 100644
--- a/xpinstall/src/Makefile.in
+++ b/xpinstall/src/Makefile.in
@@ -44,6 +44,7 @@ MODULE_NAME = nsSoftwareUpdate
REQUIRES = xpcom \
string \
jar \
+ caps \
chrome \
necko \
intl \
@@ -66,6 +67,7 @@ REQUIRES = xpcom \
EXPORTS = nsXPITriggerInfo.h
CPPSRCS = \
+ CertReader.cpp \
nsInstall.cpp \
nsInstallTrigger.cpp \
nsInstallVersion.cpp \
diff --git a/xpinstall/src/nsInstall.cpp b/xpinstall/src/nsInstall.cpp
index 093d3616d00f..154019addc7c 100644
--- a/xpinstall/src/nsInstall.cpp
+++ b/xpinstall/src/nsInstall.cpp
@@ -143,6 +143,7 @@ nsInstallInfo::nsInstallInfo(PRUint32 aInstallType,
nsIFile* aFile,
const PRUnichar* aURL,
const PRUnichar* aArgs,
+ nsIPrincipal* aPrincipal,
PRUint32 flags,
nsIXPIListener* aListener,
nsIXULChromeRegistry* aChromeRegistry)
@@ -151,6 +152,7 @@ nsInstallInfo::nsInstallInfo(PRUint32 aInstallType,
mFlags(flags),
mURL(aURL),
mArgs(aArgs),
+ mPrincipal(aPrincipal),
mFile(aFile),
mListener(aListener),
mChromeRegistry(aChromeRegistry)
diff --git a/xpinstall/src/nsInstall.h b/xpinstall/src/nsInstall.h
index a4919e6a6415..b3fe6a6b5e07 100644
--- a/xpinstall/src/nsInstall.h
+++ b/xpinstall/src/nsInstall.h
@@ -58,6 +58,7 @@
#include "nsIEnumerator.h"
#include "nsIZipReader.h"
#include "nsIChromeRegistry.h"
+#include "nsIPrincipal.h"
#define XPINSTALL_BUNDLE_URL "chrome://communicator/locale/xpinstall/xpinstall.properties"
@@ -78,6 +79,7 @@ class nsInstallInfo
nsIFile* aFile,
const PRUnichar* aURL,
const PRUnichar* aArgs,
+ nsIPrincipal* mPrincipal,
PRUint32 aFlags,
nsIXPIListener* aListener,
nsIXULChromeRegistry* aChromeReg);
@@ -92,6 +94,8 @@ class nsInstallInfo
nsIXPIListener* GetListener() { return mListener.get(); }
nsIXULChromeRegistry* GetChromeRegistry() { return mChromeRegistry.get(); }
+ nsCOMPtr mPrincipal;
+
private:
nsresult mError;
@@ -180,6 +184,8 @@ class nsInstall
KEY_DOES_NOT_EXIST = -242,
VALUE_DOES_NOT_EXIST = -243,
+ INVALID_SIGNATURE = -260,
+
OUT_OF_MEMORY = -299,
GESTALT_UNKNOWN_ERR = -5550,
diff --git a/xpinstall/src/nsJSInstall.cpp b/xpinstall/src/nsJSInstall.cpp
index c7de4f1a514d..a301766bac4e 100644
--- a/xpinstall/src/nsJSInstall.cpp
+++ b/xpinstall/src/nsJSInstall.cpp
@@ -1788,6 +1788,7 @@ static JSConstDoubleSpec install_constants[] =
{ nsInstall::SUCCESS, "SUCCESS" },
{ nsInstall::REBOOT_NEEDED, "REBOOT_NEEDED" },
+ { nsInstall::INVALID_SIGNATURE, "INVALID_SIGNATURE" },
// these are bitwise values supported by addFile
{ DO_NOT_UNINSTALL, "DO_NOT_UNINSTALL" },
diff --git a/xpinstall/src/nsSoftwareUpdate.cpp b/xpinstall/src/nsSoftwareUpdate.cpp
index 19f261ca6842..aca367f6174d 100644
--- a/xpinstall/src/nsSoftwareUpdate.cpp
+++ b/xpinstall/src/nsSoftwareUpdate.cpp
@@ -299,6 +299,7 @@ NS_IMETHODIMP
nsSoftwareUpdate::InstallJar( nsIFile* aLocalFile,
const PRUnichar* aURL,
const PRUnichar* aArguments,
+ nsIPrincipal* aPrincipal,
PRUint32 flags,
nsIXPIListener* aListener)
{
@@ -316,7 +317,7 @@ nsSoftwareUpdate::InstallJar( nsIFile* aLocalFile,
chromeRegistry = tmpReg;
// we want to call this with or without a chrome registry
- nsInstallInfo *info = new nsInstallInfo( 0, aLocalFile, aURL, aArguments,
+ nsInstallInfo *info = new nsInstallInfo( 0, aLocalFile, aURL, aArguments, aPrincipal,
flags, aListener, chromeRegistry );
if (!info)
@@ -351,6 +352,7 @@ nsSoftwareUpdate::InstallChrome( PRUint32 aType,
aFile,
URL,
aName,
+ nsnull,
(PRUint32)aSelect,
aListener,
chromeRegistry);
diff --git a/xpinstall/src/nsSoftwareUpdate.h b/xpinstall/src/nsSoftwareUpdate.h
index b4988aadcae4..a10d39e42a2a 100644
--- a/xpinstall/src/nsSoftwareUpdate.h
+++ b/xpinstall/src/nsSoftwareUpdate.h
@@ -16,13 +16,13 @@
#include "nsCOMPtr.h"
class nsInstallInfo;
+class nsIPrincipal;
#include "nsIScriptExternalNameSet.h"
#include "nsIObserver.h"
#include "nsPIXPIStubHook.h"
#include "nsTopProgressNotifier.h"
-
class nsSoftwareUpdate: public nsISoftwareUpdate,
public nsPIXPIStubHook,
public nsIObserver
@@ -53,6 +53,7 @@ class nsSoftwareUpdate: public nsISoftwareUpdate,
NS_IMETHOD InstallJar( nsIFile* localFile,
const PRUnichar* URL,
const PRUnichar* arguments,
+ nsIPrincipal* principal = nsnull,
PRUint32 flags = 0,
nsIXPIListener* aListener = 0);
diff --git a/xpinstall/src/nsSoftwareUpdateRun.cpp b/xpinstall/src/nsSoftwareUpdateRun.cpp
index e8f652642069..64c04d2f87b8 100644
--- a/xpinstall/src/nsSoftwareUpdateRun.cpp
+++ b/xpinstall/src/nsSoftwareUpdateRun.cpp
@@ -55,21 +55,94 @@
#include "nsIConsoleService.h"
#include "nsIScriptError.h"
+#include "nsIJAR.h"
+#include "nsIPrincipal.h"
+#include "nsICertificatePrincipal.h"
+
static NS_DEFINE_CID(kSoftwareUpdateCID, NS_SoftwareUpdate_CID);
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
-extern JSObject *InitXPInstallObjects(JSContext *jscontext, JSObject *global, nsIFile* jarfile, const PRUnichar* url, const PRUnichar* args, PRUint32 flags, nsIXULChromeRegistry* registry, nsIZipReader* hZip);
+extern JSObject *InitXPInstallObjects(JSContext *jscontext, JSObject *global,
+ nsIFile* jarfile, const PRUnichar* url,
+ const PRUnichar* args, PRUint32 flags,
+ nsIXULChromeRegistry* registry,
+ nsIZipReader* hZip);
extern nsresult InitInstallVersionClass(JSContext *jscontext, JSObject *global, void** prototype);
extern nsresult InitInstallTriggerGlobalClass(JSContext *jscontext, JSObject *global, void** prototype);
// Defined in this file:
PR_STATIC_CALLBACK(void) XPInstallErrorReporter(JSContext *cx, const char *message, JSErrorReport *report);
-static PRInt32 GetInstallScriptFromJarfile(nsIZipReader* hZip, nsIFile* jarFile, char** scriptBuffer, PRUint32 *scriptLength);
-static nsresult SetupInstallContext(nsIZipReader* hZip, nsIFile* jarFile, const PRUnichar* url, const PRUnichar* args, PRUint32 flags, nsIXULChromeRegistry* reg, JSRuntime *jsRT, JSContext **jsCX, JSObject **jsGlob);
+static PRInt32 GetInstallScriptFromJarfile(nsIZipReader* hZip, nsIFile* jarFile, nsIPrincipal* aPrincipal, char** scriptBuffer, PRUint32 *scriptLength);
+static nsresult SetupInstallContext(nsIZipReader* hZip, nsIFile* jarFile, const PRUnichar* url, const PRUnichar* args,
+ PRUint32 flags, nsIXULChromeRegistry* reg, JSRuntime *jsRT, JSContext **jsCX, JSObject **jsGlob);
extern "C" void RunInstallOnThread(void *data);
+nsresult VerifySigning(nsIZipReader* hZip, nsIPrincipal* aPrincipal)
+{
+ if (!aPrincipal)
+ return NS_OK; // not signed, but not an error
+
+ nsCOMPtr cp(do_QueryInterface(aPrincipal));
+ if (!cp)
+ return NS_ERROR_FAILURE;
+
+ nsCOMPtr jar(do_QueryInterface(hZip));
+ if (!jar)
+ return NS_ERROR_FAILURE;
+
+ // See if the archive is signed at all first
+ nsCOMPtr principal;
+ nsresult rv = jar->GetCertificatePrincipal(nsnull, getter_AddRefs(principal));
+ if (NS_FAILED(rv) || !principal)
+ return NS_ERROR_FAILURE;
+
+ PRUint32 entryCount = 0;
+
+ // first verify all files in the jar are also in the manifest.
+ nsCOMPtr entries;
+ rv = hZip->FindEntries("*", getter_AddRefs(entries));
+ if (NS_FAILED(rv))
+ return rv;
+
+ PRBool more;
+ nsXPIDLCString name;
+ while (NS_SUCCEEDED(entries->HasMoreElements(&more)) && more)
+ {
+ nsCOMPtr file;
+ rv = entries->GetNext(getter_AddRefs(file));
+ if (NS_FAILED(rv)) return rv;
+
+ file->GetName(getter_Copies(name));
+
+ if ( PL_strncasecmp("META-INF/", name.get(), 9) == 0)
+ continue;
+
+ // we only count the entries not in the meta-inf directory
+ entryCount++;
+
+ // Each entry must be signed
+ PRBool equal;
+ rv = jar->GetCertificatePrincipal(name, getter_AddRefs(principal));
+ if (NS_FAILED(rv) || !principal) return NS_ERROR_FAILURE;
+
+ rv = principal->Equals(aPrincipal, &equal);
+ if (NS_FAILED(rv) || !equal) return NS_ERROR_FAILURE;
+ }
+
+ // next verify all files in the manifest are in the archive.
+ PRUint32 manifestEntryCount;
+ rv = jar->GetManifestEntriesCount(&manifestEntryCount);
+ if (NS_FAILED(rv))
+ return rv;
+
+ if (entryCount != manifestEntryCount)
+ return NS_ERROR_FAILURE; // some files were deleted from archive
+
+ return NS_OK;
+}
+
///////////////////////////////////////////////////////////////////////////////////////////////
// Function name : XPInstallErrorReporter
// Description : Prints error message to stdout
@@ -127,7 +200,6 @@ XPInstallErrorReporter(JSContext *cx, const char *message, JSErrorReport *report
do_GetService(kSoftwareUpdateCID, &rv);
if (NS_FAILED(rv))
-
{
NS_WARNING("shouldn't have RunInstall() if we can't get SoftwareUpdate");
return;
@@ -159,12 +231,14 @@ XPInstallErrorReporter(JSContext *cx, const char *message, JSErrorReport *report
// Description : Extracts and reads in a install.js file from a passed jar file.
// Return type : static PRInt32
// Argument : const char* jarFile - **NSPR** filepath
+// Argument : nsIPrincipal* aPrincipal - a principal, if any, displayed to the user
+// regarding the cert used to sign this install
// Argument : char** scriptBuffer - must be deleted via delete []
// Argument : PRUint32 *scriptLength
///////////////////////////////////////////////////////////////////////////////////////////////
static PRInt32
-GetInstallScriptFromJarfile(nsIZipReader* hZip, nsIFile* jarFile, char** scriptBuffer, PRUint32 *scriptLength)
+GetInstallScriptFromJarfile(nsIZipReader* hZip, nsIFile* jarFile, nsIPrincipal* aPrincipal, char** scriptBuffer, PRUint32 *scriptLength)
{
PRInt32 result = NS_OK;
@@ -192,6 +266,13 @@ GetInstallScriptFromJarfile(nsIZipReader* hZip, nsIFile* jarFile, char** scriptB
return nsInstall::CANT_READ_ARCHIVE;
}
+ rv = VerifySigning(hZip, aPrincipal);
+ if (NS_FAILED(rv))
+ {
+ NS_ASSERTION(0, "Signing check of archive failed!");
+ return nsInstall::INVALID_SIGNATURE;
+ }
+
// Extract the install.js file to the temporary directory
nsSpecialSystemDirectory installJSFileSpec(nsSpecialSystemDirectory::OS_TemporaryDirectory);
installJSFileSpec += "install.js";
@@ -200,6 +281,7 @@ GetInstallScriptFromJarfile(nsIZipReader* hZip, nsIFile* jarFile, char** scriptB
// Extract the install.js file.
nsCOMPtr iFile;
rv = NS_NewNativeLocalFile(nsDependentCString(installJSFileSpec), PR_TRUE, getter_AddRefs(iFile));
+
if (NS_SUCCEEDED(rv))
rv = hZip->Extract("install.js", iFile);
if ( NS_SUCCEEDED(rv) )
@@ -393,10 +475,12 @@ extern "C" void RunInstallOnThread(void *data)
listener->OnInstallStart( installInfo->GetURL() );
nsCOMPtr jarpath = installInfo->GetFile();
+
if (NS_SUCCEEDED(rv))
{
finalStatus = GetInstallScriptFromJarfile( hZip,
jarpath,
+ installInfo->mPrincipal,
&scriptBuffer,
&scriptLength);
@@ -587,4 +671,3 @@ extern "C" void RunChromeInstallOnThread(void *data)
delete info;
}
-
diff --git a/xpinstall/src/nsXPITriggerInfo.cpp b/xpinstall/src/nsXPITriggerInfo.cpp
index afd3e36c7cf5..d607731cea8a 100644
--- a/xpinstall/src/nsXPITriggerInfo.cpp
+++ b/xpinstall/src/nsXPITriggerInfo.cpp
@@ -27,6 +27,7 @@
#include "nsDebug.h"
#include "nsIServiceManager.h"
#include "nsIEventQueueService.h"
+#include "nsICertificatePrincipal.h"
static NS_DEFINE_IID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
@@ -38,7 +39,7 @@ MOZ_DECL_CTOR_COUNTER(nsXPITriggerItem)
nsXPITriggerItem::nsXPITriggerItem( const PRUnichar* aName,
const PRUnichar* aURL,
- PRInt32 aFlags )
+ PRInt32 aFlags)
: mName(aName), mURL(aURL), mFlags(aFlags)
{
MOZ_COUNT_CTOR(nsXPITriggerItem);
@@ -89,6 +90,18 @@ PRBool nsXPITriggerItem::IsRelativeURL()
}
+void
+nsXPITriggerItem::SetPrincipal(nsIPrincipal* aPrincipal)
+{
+ mPrincipal = aPrincipal;
+
+ nsCOMPtr cp(do_QueryInterface(aPrincipal));
+ if (cp) {
+ nsXPIDLCString cName;
+ cp->GetCommonName(getter_Copies(cName));
+ mCertName = NS_ConvertUTF8toUCS2(cName);
+ }
+}
//
// nsXPITriggerInfo
//
diff --git a/xpinstall/src/nsXPITriggerInfo.h b/xpinstall/src/nsXPITriggerInfo.h
index 7e9d6fe938a0..d9157c62697e 100644
--- a/xpinstall/src/nsXPITriggerInfo.h
+++ b/xpinstall/src/nsXPITriggerInfo.h
@@ -38,7 +38,7 @@
#include "plevent.h"
#include "nsIXPConnect.h"
-
+#include "nsIPrincipal.h"
typedef struct XPITriggerEvent {
PLEvent e;
@@ -61,14 +61,18 @@ class nsXPITriggerItem
nsString mName;
nsString mURL;
nsString mArguments;
+ nsString mCertName;
PRInt32 mFlags;
nsCOMPtr mFile;
nsCOMPtr mOutStream;
+ nsCOMPtr mPrincipal;
+
PRBool IsFileURL() { return Substring(mURL, 0, 6).Equals(NS_LITERAL_STRING("file:/")); }
PRBool IsRelativeURL();
+ void SetPrincipal(nsIPrincipal* aPrincipal);
private:
//-- prevent inadvertent copies and assignments
nsXPITriggerItem& operator=(const nsXPITriggerItem& rhs);
diff --git a/xpinstall/src/nsXPInstallManager.cpp b/xpinstall/src/nsXPInstallManager.cpp
index b1562a550dd1..a48ba02a4303 100644
--- a/xpinstall/src/nsXPInstallManager.cpp
+++ b/xpinstall/src/nsXPInstallManager.cpp
@@ -65,6 +65,8 @@
#include "nsXPCOM.h"
#include "nsISupportsPrimitives.h"
+#include "CertReader.h"
+
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
static NS_DEFINE_IID(kProxyObjectManagerCID, NS_PROXYEVENT_MANAGER_CID);
static NS_DEFINE_IID(kStringBundleServiceCID, NS_STRINGBUNDLESERVICE_CID);
@@ -134,7 +136,6 @@ nsXPInstallManager::InitManager(nsIScriptGlobalObject* aGlobalObject, nsXPITrigg
{
nsresult rv = NS_OK;
- PRBool OKtoInstall = PR_FALSE; // initialize to secure state
mTriggers = aTriggers;
mChromeType = aChromeType;
mNeedsShutdown = PR_TRUE;
@@ -146,14 +147,36 @@ nsXPInstallManager::InitManager(nsIScriptGlobalObject* aGlobalObject, nsXPITrigg
return rv;
}
+ mParentWindow = do_QueryInterface(aGlobalObject);
+ mOutstandingCertLoads = mTriggers->Size();
+
+ nsXPITriggerItem *item = mTriggers->Get(--mOutstandingCertLoads);
+
+ nsCOMPtr uri;
+ NS_NewURI(getter_AddRefs(uri), NS_ConvertUCS2toUTF8(item->mURL.get()).get());
+ nsIStreamListener* listener = new CertReader(uri, nsnull, this);
+ NS_ADDREF(listener);
+ rv = NS_OpenURI(listener, nsnull, uri);
+ NS_RELEASE(listener);
+ if (NS_FAILED(rv)) {
+ NS_RELEASE_THIS();
+ }
+ return rv;
+}
+
+
+nsresult
+nsXPInstallManager::InitManagerInternal()
+{
+ nsresult rv;
+ PRBool OKtoInstall = PR_FALSE; // initialize to secure state
+
//-----------------------------------------------------
// *** Do not return early after this point ***
//
// We have to clean up the triggers in case of error
//-----------------------------------------------------
- nsCOMPtr parentWindow(do_QueryInterface(aGlobalObject));
-
// --- use embedding dialogs if any registered
nsCOMPtr dlgSvc(do_CreateInstance(NS_XPIDIALOGSERVICE_CONTRACTID));
if ( !dlgSvc )
@@ -164,7 +187,7 @@ nsXPInstallManager::InitManager(nsIScriptGlobalObject* aGlobalObject, nsXPITrigg
// --- prepare dialog params
PRUint32 numTriggers = mTriggers->Size();
- PRUint32 numStrings = 2 * numTriggers;
+ PRUint32 numStrings = 3 * numTriggers;
const PRUnichar** packageList =
(const PRUnichar**)malloc( sizeof(PRUnichar*) * numStrings );
@@ -176,6 +199,7 @@ nsXPInstallManager::InitManager(nsIScriptGlobalObject* aGlobalObject, nsXPITrigg
nsXPITriggerItem *item = mTriggers->Get(i);
packageList[j++] = item->mName.get();
packageList[j++] = item->mURL.get();
+ packageList[j++] = item->mCertName.get();
}
//-----------------------------------------------------
@@ -186,11 +210,11 @@ nsXPInstallManager::InitManager(nsIScriptGlobalObject* aGlobalObject, nsXPITrigg
{
// skins get a simpler/friendlier dialog
// XXX currently not embeddable
- OKtoInstall = ConfirmChromeInstall( parentWindow, packageList );
+ OKtoInstall = ConfirmChromeInstall( mParentWindow, packageList );
}
else
{
- rv = dlgSvc->ConfirmInstall( parentWindow,
+ rv = dlgSvc->ConfirmInstall( mParentWindow,
packageList,
numStrings,
&OKtoInstall );
@@ -585,6 +609,7 @@ NS_IMETHODIMP nsXPInstallManager::DownloadNext()
rv = mInstallSvc->InstallJar( mItem->mFile,
mItem->mURL.get(),
mItem->mArguments.get(),
+ mItem->mPrincipal,
mItem->mFlags,
this );
}
@@ -1014,3 +1039,56 @@ nsXPInstallManager::OnLogComment(const PRUnichar* comment)
return NS_OK;
}
+
+NS_IMETHODIMP
+nsXPInstallManager::OnCertAvailable(nsIURI *aURI,
+ nsISupports* context,
+ nsresult aStatus,
+ nsIPrincipal *aPrincipal)
+{
+ if (NS_FAILED(aStatus)) {
+ // if there was a failure for whatever reason, we will treat
+ // the install as unsigned. An error here could me that the
+ // location of the install is unreachable or that the install
+ // is currupt. In either case, we want to ensure that the
+ // nsIPrincipal is nsnull (although it already should be
+ // -- we are just being paranoid here.
+ NS_ASSERTION(aPrincipal == nsnull, "There has been an error, but we have a principal!");
+ aPrincipal = nsnull;
+ }
+
+ // get the current one and assign the cert name
+ nsXPITriggerItem *item = mTriggers->Get(mOutstandingCertLoads);
+ item->SetPrincipal(aPrincipal);
+
+ if (mOutstandingCertLoads == 0) {
+ InitManagerInternal();
+ return NS_OK;
+ }
+
+ // get the next one to load. If there is any failure, we just go on to the
+ // next trigger. When all triggers items are handled, we call into InitManagerInternal
+
+ item = mTriggers->Get(--mOutstandingCertLoads);
+
+ nsCOMPtr uri;
+ NS_NewURI(getter_AddRefs(uri), NS_ConvertUCS2toUTF8(item->mURL.get()).get());
+
+ if (!uri || mChromeType != NOT_CHROME)
+ return OnCertAvailable(uri, context, NS_ERROR_FAILURE, nsnull);
+
+ nsIStreamListener* listener = new CertReader(uri, nsnull, this);
+ if (!listener)
+ return OnCertAvailable(uri, context, NS_ERROR_FAILURE, nsnull);
+
+ NS_ADDREF(listener);
+ nsresult rv = NS_OpenURI(listener, nsnull, uri);
+ NS_ASSERTION(NS_SUCCEEDED(rv), "OpenURI failed");
+ NS_RELEASE(listener);
+
+ if (NS_FAILED(rv))
+ return OnCertAvailable(uri, context, NS_ERROR_FAILURE, nsnull);
+
+ return NS_OK;
+}
+
diff --git a/xpinstall/src/nsXPInstallManager.h b/xpinstall/src/nsXPInstallManager.h
index cd8144d68ffb..80c76c2dc89b 100644
--- a/xpinstall/src/nsXPInstallManager.h
+++ b/xpinstall/src/nsXPInstallManager.h
@@ -52,6 +52,8 @@
#include "nsIDialogParamBlock.h"
+#include "nsPICertNotification.h"
+
#define NS_XPIDIALOGSERVICE_CONTRACTID "@mozilla.org/embedui/xpinstall-dialog-service;1"
#define XPI_PROGRESS_TOPIC "xpinstall-progress"
@@ -60,7 +62,8 @@ class nsXPInstallManager : public nsIXPIListener,
public nsIObserver,
public nsIStreamListener,
public nsIProgressEventSink,
- public nsIInterfaceRequestor
+ public nsIInterfaceRequestor,
+ public nsPICertNotification
{
public:
nsXPInstallManager();
@@ -74,10 +77,12 @@ class nsXPInstallManager : public nsIXPIListener,
NS_DECL_NSIPROGRESSEVENTSINK
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSIINTERFACEREQUESTOR
+ NS_DECL_NSPICERTNOTIFICATION
NS_IMETHOD InitManager(nsIScriptGlobalObject* aGlobalObject, nsXPITriggerInfo* aTrigger, PRUint32 aChromeType );
private:
+ nsresult InitManagerInternal();
NS_IMETHOD DownloadNext();
void Shutdown();
NS_IMETHOD GetDestinationFile(nsString& url, nsILocalFile* *file);
@@ -93,14 +98,17 @@ class nsXPInstallManager : public nsIXPIListener,
PRInt32 mNumJars;
PRUint32 mChromeType;
PRInt32 mContentLength;
+ PRInt32 mOutstandingCertLoads;
PRBool mDialogOpen;
PRBool mCancelled;
PRBool mSelectChrome;
PRBool mNeedsShutdown;
-
+
nsCOMPtr mDlg;
nsCOMPtr mStringBundle;
nsCOMPtr mInstallSvc;
+
+ nsCOMPtr mParentWindow;
};
#endif
diff --git a/xpinstall/stub/xpistub.cpp b/xpinstall/stub/xpistub.cpp
index 5d4377f0bf99..1b724a2a34e4 100644
--- a/xpinstall/stub/xpistub.cpp
+++ b/xpinstall/stub/xpistub.cpp
@@ -270,6 +270,7 @@ PR_PUBLIC_API(PRInt32) XPI_Install(
rv = gXPI->InstallJar( iFile,
URLstr.get(),
args.get(),
+ nsnull,
(aFlags | XPI_NO_NEW_THREAD),
gListener );