diff --git a/netwerk/base/nsIPackagedAppUtils.idl b/netwerk/base/nsIPackagedAppUtils.idl index ca78e9a3ec2..cc4c05d6f97 100644 --- a/netwerk/base/nsIPackagedAppUtils.idl +++ b/netwerk/base/nsIPackagedAppUtils.idl @@ -24,7 +24,7 @@ interface nsIVerificationCallback; * https://wiki.mozilla.org/FirefoxOS/New_security_model/Packaging */ -[scriptable, uuid(cc245638-6a38-4f70-8d77-21c55aabd636)] +[scriptable, uuid(edf91fee-ef4a-4479-9136-27eb3b7a6312)] interface nsIPackagedAppUtils : nsISupports { /** @@ -37,7 +37,8 @@ interface nsIPackagedAppUtils : nsISupports */ void verifyManifest(in ACString aHeader, in ACString aManifest, - in nsIVerificationCallback aVerifier); + in nsIVerificationCallback aVerifier, + in boolean aDeveloperMode); /** * @aFileName is the name of a resource in the package diff --git a/netwerk/protocol/http/PackagedAppUtils.js b/netwerk/protocol/http/PackagedAppUtils.js index d09354c3e0d..0c3ce10023c 100644 --- a/netwerk/protocol/http/PackagedAppUtils.js +++ b/netwerk/protocol/http/PackagedAppUtils.js @@ -29,7 +29,7 @@ PackagedAppUtils.prototype = { classDescription: "Packaged App Utils", QueryInterface: XPCOMUtils.generateQI([Ci.nsIPackagedAppUtils]), - verifyManifest: function(aHeader, aManifest, aCallback) { + verifyManifest: function(aHeader, aManifest, aCallback, aDeveloperMode) { debug("Manifest: " + aManifest); // parse signature from header @@ -83,8 +83,10 @@ PackagedAppUtils.prototype = { throw "CERTDB_ERROR"; } - certDb.verifySignedManifestAsync( - Ci.nsIX509CertDB.PrivilegedPackageRoot, manifestStream, signatureStream, + let trustedRoot = aDeveloperMode ? Ci.nsIX509CertDB.DeveloperImportedRoot + : Ci.nsIX509CertDB.PrivilegedPackageRoot; + + certDb.verifySignedManifestAsync(trustedRoot, manifestStream, signatureStream, function(aRv, aCert) { aCallback.fireVerifiedEvent(true, Components.isSuccessCode(aRv)); }); diff --git a/netwerk/protocol/http/PackagedAppVerifier.cpp b/netwerk/protocol/http/PackagedAppVerifier.cpp index a455f64b4d0..4a314454696 100644 --- a/netwerk/protocol/http/PackagedAppVerifier.cpp +++ b/netwerk/protocol/http/PackagedAppVerifier.cpp @@ -128,7 +128,7 @@ PackagedAppVerifier::WriteManifest(nsIInputStream* aStream, uint32_t* aWriteCount) { LOG(("WriteManifest: length %u", aCount)); - LOG(("%s", aFromRawSegment)); + LOG(("%s", nsCString(aFromRawSegment, aCount).get())); nsCString* manifest = static_cast(aManifest); manifest->AppendASCII(aFromRawSegment, aCount); *aWriteCount = aCount; @@ -277,7 +277,8 @@ PackagedAppVerifier::VerifyManifest(const ResourceCacheInfo* aInfo) LOG(("Signature: length = %u\n%s", mSignature.Length(), mSignature.get())); LOG(("Manifest: length = %u\n%s", mManifest.Length(), mManifest.get())); - nsresult rv = mPackagedAppUtils->VerifyManifest(mSignature, mManifest, this); + nsresult rv = mPackagedAppUtils->VerifyManifest(mSignature, mManifest, + this, gDeveloperMode); if (NS_FAILED(rv)) { LOG(("VerifyManifest FAILED rv = %u", (unsigned)rv)); } @@ -304,12 +305,6 @@ PackagedAppVerifier::VerifyResource(const ResourceCacheInfo* aInfo) MOZ_CRASH(); } - if (gDeveloperMode) { - LOG(("Developer mode! Bypass integrity check.")); - FireVerifiedEvent(false, true); - return; - } - if (mSignature.IsEmpty()) { LOG(("No signature. No need to do resource integrity check.")); FireVerifiedEvent(false, true); diff --git a/netwerk/test/mochitests/signed_web_packaged_app.sjs b/netwerk/test/mochitests/signed_web_packaged_app.sjs index 1b7256be3ac..eac3bfe5033 100644 --- a/netwerk/test/mochitests/signed_web_packaged_app.sjs +++ b/netwerk/test/mochitests/signed_web_packaged_app.sjs @@ -5,33 +5,79 @@ var Cu = Components.utils; function handleRequest(request, response) { response.setHeader("Content-Type", "application/package", false); - response.write(octetStreamData.packageHeader + octetStreamData.getData()); + response.write(signedPackage); return; } // The package content // getData formats it as described at http://www.w3.org/TR/web-packaging/#streamable-package-format -var octetStreamData = { - packageHeader: 'manifest-signature: dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk\r\n', - - content: [ - { headers: ["Content-Location: /index.html", "Content-Type: text/html"], data: "\r\n \r\n \r\n\r\n Web Packaged App Index\r\n\r\n", type: "text/html" }, - { headers: ["Content-Location: /scripts/app.js", "Content-Type: text/javascript"], data: "module Math from '/scripts/helpers/math.js';\r\n...\r\n", type: "text/javascript" }, - { headers: ["Content-Location: /scripts/helpers/math.js", "Content-Type: text/javascript"], data: "export function sum(nums) { ... }\r\n...\r\n", type: "text/javascript" } - ], - token : "gc0pJq0M:08jU534c0p", - getData: function() { - var str = ""; - for (var i in this.content) { - str += "--" + this.token + "\r\n"; - for (var j in this.content[i].headers) { - str += this.content[i].headers[j] + "\r\n"; - } - str += "\r\n"; - str += this.content[i].data + "\r\n"; - } - - str += "--" + this.token + "--"; - return str; - } -} +var signedPackage = [ + "manifest-signature: MIIF1AYJKoZIhvcNAQcCoIIFxTCCBcECAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHAaCCA54wggOaMIICgqADAgECAgECMA0GCSqGSIb3DQEBCwUAMHMxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEkMCIGA1UEChMbRXhhbXBsZSBUcnVzdGVkIENvcnBvcmF0aW9uMRkwFwYDVQQDExBUcnVzdGVkIFZhbGlkIENBMB4XDTE1MDkxMDA4MDQzNVoXDTM1MDkxMDA4MDQzNVowdDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MSQwIgYDVQQKExtFeGFtcGxlIFRydXN0ZWQgQ29ycG9yYXRpb24xGjAYBgNVBAMTEVRydXN0ZWQgQ29ycCBDZXJ0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAts8whjOzEbn/w1xkFJ67af7F/JPujBK91oyJekh2schIMzFau9pY8S1AiJQoJCulOJCJfUc8hBLKBZiGAkii+4Gpx6cVqMLe6C22MdD806Soxn8Dg4dQqbIvPuI4eeVKu5CEk80PW/BaFMmRvRHO62C7PILuH6yZeGHC4P7dTKpsk4CLxh/jRGXLC8jV2BCW0X+3BMbHBg53NoI9s1Gs7KGYnfOHbBP5wEFAa00RjHnubUaCdEBlC8Kl4X7p0S4RGb3rsB08wgFe9EmSZHIgcIm+SuVo7N4qqbI85qo2ulU6J8NN7ZtgMPHzrMhzgAgf/KnqPqwDIxnNmRNJmHTUYwIDAQABozgwNjAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMDMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAQEAukH6cJUUj5faa8CuPCqrEa0PoLY4SYNnff9NI+TTAHkB9l+kOcFl5eo2EQOcWmZKYi7QLlWC4jy/KQYattO9FMaxiOQL4FAc6ZIbNyfwWBzZWyr5syYJTTTnkLq8A9pCKarN49+FqhJseycU+8EhJEJyP5pv5hLvDNTTHOQ6SXhASsiX8cjo3AY4bxA5pWeXuTZ459qDxOnQd+GrOe4dIeqflk0hA2xYKe3SfF+QlK8EO370B8Dj8RX230OATM1E3OtYyALe34KW3wM9Qm9rb0eViDnVyDiCWkhhQnw5yPg/XQfloug2itRYuCnfUoRt8xfeHgwz2Ymz8cUADn3KpTGCAf4wggH6AgEBMHgwczELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MSQwIgYDVQQKExtFeGFtcGxlIFRydXN0ZWQgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFRydXN0ZWQgVmFsaWQgQ0ECAQIwCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTE1MTAwMTIxMTEwNlowIwYJKoZIhvcNAQkEMRYEFHAisUYrrt+gBxYFhZ5KQQusOmN3MA0GCSqGSIb3DQEBAQUABIIBACHW4V0BsPWOvWrGOTRj6mPpNbH/JI1bN2oyqQZrpUQoaBY+BbYxO7TY4Uwe+aeIR/TTPJznOMF/dl3Bna6TPabezU4ylg7TVFI6W7zC5f5DZKp+Xv6uTX6knUzbbW1fkJqMtE8hGUzYXc3/C++Ci6kuOzrpWOhk6DpJHeUO/ioV56H0+QK/oMAjYpEsOohaPqvTPNOBhMQ0OQP3bmuJ6HcjZ/oz96PpzXUPKT1tDe6VykIYkV5NvtC8Tu2lDbYvp9ug3gyDgdyNSV47y5i/iWkzEhsAJB+9Z50wKhplnkxxVHEXkB/6tmfvExvQ28gLd/VbaEGDX2ljCaTSUjhD0o0=\r", + "--7B0MKBI3UH\r", + "Content-Location: manifest.webapp\r", + "Content-Type: application/x-web-app-manifest+json\r", + "\r", + "{", + " \"name\": \"My App\",", + " \"moz-resources\": [", + " {", + " \"src\": \"page2.html\",", + " \"integrity\": \"JREF3JbXGvZ+I1KHtoz3f46ZkeIPrvXtG4VyFQrJ7II=\"", + " },", + " {", + " \"src\": \"index.html\",", + " \"integrity\": \"zEubR310nePwd30NThIuoCxKJdnz7Mf5z+dZHUbH1SE=\"", + " },", + " {", + " \"src\": \"scripts/script.js\",", + " \"integrity\": \"6TqtNArQKrrsXEQWu3D9ZD8xvDRIkhyV6zVdTcmsT5Q=\"", + " },", + " {", + " \"src\": \"scripts/library.js\",", + " \"integrity\": \"TN2ByXZiaBiBCvS4MeZ02UyNi44vED+KjdjLInUl4o8=\"", + " }", + " ],", + " \"moz-permissions\": [", + " {", + " \"systemXHR\": {", + " \"description\": \"Needed to download stuff\"", + " },", + " \"devicestorage:pictures\": {", + " \"description\": \"Need to load pictures\"", + " }", + " }", + " ],", + " \"package-identifier\": \"611FC2FE-491D-4A47-B3B3-43FBDF6F404F\",", + " \"moz-package-location\": \"https://example.com/myapp/app.pak\",", + " \"description\": \"A great app!\"", + "}\r", + "--7B0MKBI3UH\r", + "Content-Location: page2.html\r", + "Content-Type: text/html\r", + "\r", + "", + " page2.html", + "", + "\r", + "--7B0MKBI3UH\r", + "Content-Location: index.html\r", + "Content-Type: text/html\r", + "\r", + "", + " Last updated: 2015/10/01 14:10 PST", + "", + "\r", + "--7B0MKBI3UH\r", + "Content-Location: scripts/script.js\r", + "Content-Type: text/javascript\r", + "\r", + "// script.js", + "\r", + "--7B0MKBI3UH\r", + "Content-Location: scripts/library.js\r", + "Content-Type: text/javascript\r", + "\r", + "// library.js", + "\r", + "--7B0MKBI3UH--" +].join("\n"); diff --git a/netwerk/test/mochitests/test_signed_web_packaged_app.html b/netwerk/test/mochitests/test_signed_web_packaged_app.html index b1d0b6eda2c..28d3e3f4087 100644 --- a/netwerk/test/mochitests/test_signed_web_packaged_app.html +++ b/netwerk/test/mochitests/test_signed_web_packaged_app.html @@ -21,7 +21,6 @@ var Cr = SpecialPowers.Cr; SpecialPowers.pushPrefEnv( { "set": [["network.http.enable-packaged-apps", true], - ["network.http.packaged-apps-developer-mode", true], ["network.http.packaged-signed-apps-enabled", true], ["dom.ipc.processPriorityManager.testMode", true], ["dom.ipc.processPriorityManager.enabled", true], diff --git a/netwerk/test/unit/test_packaged_app_channel.js b/netwerk/test/unit/test_packaged_app_channel.js index 6c361f06ec6..16f9f1aa9ac 100644 --- a/netwerk/test/unit/test_packaged_app_channel.js +++ b/netwerk/test/unit/test_packaged_app_channel.js @@ -51,7 +51,7 @@ Listener.prototype = { do_check_eq(this.available, count); // Need to consume stream to avoid assertion var str = new nsIBinaryInputStream(stream).readBytes(count); - equal(str, "\r\n \r\n \r\n ...\r\n \r\n ...\r\n\r\n", "check proper content"); + equal(str, "\n Last updated: 2015/10/01 14:10 PST\n\n", "check proper content"); } catch (ex) { do_throw(ex); @@ -74,7 +74,7 @@ Listener.prototype = { var testData = { packageHeader: "manifest-signature: dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk\r\n", content: [ - { headers: ["Content-Location: /index.html", "Content-Type: text/html"], data: "\r\n \r\n \r\n ...\r\n \r\n ...\r\n\r\n", type: "text/html" }, + { headers: ["Content-Location: /index.html", "Content-Type: text/html"], data: "\n Last updated: 2015/10/01 14:10 PST\n\n", type: "text/html" }, { headers: ["Content-Location: /scripts/app.js", "Content-Type: text/javascript"], data: "module Math from '/scripts/helpers/math.js';\r\n...\r\n", type: "text/javascript" }, { headers: ["Content-Location: /scripts/helpers/math.js", "Content-Type: text/javascript"], data: "export function sum(nums) { ... }\r\n...\r\n", type: "text/javascript" } ], @@ -95,6 +95,79 @@ var testData = { } } +var badSignature = "manifest-signature: dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk\r\n"; +var goodSignature = "manifest-signature: MIIF1AYJKoZIhvcNAQcCoIIFxTCCBcECAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHAaCCA54wggOaMIICgqADAgECAgECMA0GCSqGSIb3DQEBCwUAMHMxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEkMCIGA1UEChMbRXhhbXBsZSBUcnVzdGVkIENvcnBvcmF0aW9uMRkwFwYDVQQDExBUcnVzdGVkIFZhbGlkIENBMB4XDTE1MDkxMDA4MDQzNVoXDTM1MDkxMDA4MDQzNVowdDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MSQwIgYDVQQKExtFeGFtcGxlIFRydXN0ZWQgQ29ycG9yYXRpb24xGjAYBgNVBAMTEVRydXN0ZWQgQ29ycCBDZXJ0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAts8whjOzEbn/w1xkFJ67af7F/JPujBK91oyJekh2schIMzFau9pY8S1AiJQoJCulOJCJfUc8hBLKBZiGAkii+4Gpx6cVqMLe6C22MdD806Soxn8Dg4dQqbIvPuI4eeVKu5CEk80PW/BaFMmRvRHO62C7PILuH6yZeGHC4P7dTKpsk4CLxh/jRGXLC8jV2BCW0X+3BMbHBg53NoI9s1Gs7KGYnfOHbBP5wEFAa00RjHnubUaCdEBlC8Kl4X7p0S4RGb3rsB08wgFe9EmSZHIgcIm+SuVo7N4qqbI85qo2ulU6J8NN7ZtgMPHzrMhzgAgf/KnqPqwDIxnNmRNJmHTUYwIDAQABozgwNjAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMDMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAQEAukH6cJUUj5faa8CuPCqrEa0PoLY4SYNnff9NI+TTAHkB9l+kOcFl5eo2EQOcWmZKYi7QLlWC4jy/KQYattO9FMaxiOQL4FAc6ZIbNyfwWBzZWyr5syYJTTTnkLq8A9pCKarN49+FqhJseycU+8EhJEJyP5pv5hLvDNTTHOQ6SXhASsiX8cjo3AY4bxA5pWeXuTZ459qDxOnQd+GrOe4dIeqflk0hA2xYKe3SfF+QlK8EO370B8Dj8RX230OATM1E3OtYyALe34KW3wM9Qm9rb0eViDnVyDiCWkhhQnw5yPg/XQfloug2itRYuCnfUoRt8xfeHgwz2Ymz8cUADn3KpTGCAf4wggH6AgEBMHgwczELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MSQwIgYDVQQKExtFeGFtcGxlIFRydXN0ZWQgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFRydXN0ZWQgVmFsaWQgQ0ECAQIwCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTE1MTAwMTIxMTEwNlowIwYJKoZIhvcNAQkEMRYEFHAisUYrrt+gBxYFhZ5KQQusOmN3MA0GCSqGSIb3DQEBAQUABIIBACHW4V0BsPWOvWrGOTRj6mPpNbH/JI1bN2oyqQZrpUQoaBY+BbYxO7TY4Uwe+aeIR/TTPJznOMF/dl3Bna6TPabezU4ylg7TVFI6W7zC5f5DZKp+Xv6uTX6knUzbbW1fkJqMtE8hGUzYXc3/C++Ci6kuOzrpWOhk6DpJHeUO/ioV56H0+QK/oMAjYpEsOohaPqvTPNOBhMQ0OQP3bmuJ6HcjZ/oz96PpzXUPKT1tDe6VykIYkV5NvtC8Tu2lDbYvp9ug3gyDgdyNSV47y5i/iWkzEhsAJB+9Z50wKhplnkxxVHEXkB/6tmfvExvQ28gLd/VbaEGDX2ljCaTSUjhD0o0=\r\n"; + +var packageContent = [ + "--7B0MKBI3UH\r", + "Content-Location: manifest.webapp\r", + "Content-Type: application/x-web-app-manifest+json\r", + "\r", + "{", + " \"name\": \"My App\",", + " \"moz-resources\": [", + " {", + " \"src\": \"page2.html\",", + " \"integrity\": \"JREF3JbXGvZ+I1KHtoz3f46ZkeIPrvXtG4VyFQrJ7II=\"", + " },", + " {", + " \"src\": \"index.html\",", + " \"integrity\": \"zEubR310nePwd30NThIuoCxKJdnz7Mf5z+dZHUbH1SE=\"", + " },", + " {", + " \"src\": \"scripts/script.js\",", + " \"integrity\": \"6TqtNArQKrrsXEQWu3D9ZD8xvDRIkhyV6zVdTcmsT5Q=\"", + " },", + " {", + " \"src\": \"scripts/library.js\",", + " \"integrity\": \"TN2ByXZiaBiBCvS4MeZ02UyNi44vED+KjdjLInUl4o8=\"", + " }", + " ],", + " \"moz-permissions\": [", + " {", + " \"systemXHR\": {", + " \"description\": \"Needed to download stuff\"", + " },", + " \"devicestorage:pictures\": {", + " \"description\": \"Need to load pictures\"", + " }", + " }", + " ],", + " \"package-identifier\": \"611FC2FE-491D-4A47-B3B3-43FBDF6F404F\",", + " \"moz-package-location\": \"https://example.com/myapp/app.pak\",", + " \"description\": \"A great app!\"", + "}\r", + "--7B0MKBI3UH\r", + "Content-Location: page2.html\r", + "Content-Type: text/html\r", + "\r", + "", + " page2.html", + "", + "\r", + "--7B0MKBI3UH\r", + "Content-Location: index.html\r", + "Content-Type: text/html\r", + "\r", + "", + " Last updated: 2015/10/01 14:10 PST", + "", + "\r", + "--7B0MKBI3UH\r", + "Content-Location: scripts/script.js\r", + "Content-Type: text/javascript\r", + "\r", + "// script.js", + "\r", + "--7B0MKBI3UH\r", + "Content-Location: scripts/library.js\r", + "Content-Type: text/javascript\r", + "\r", + "// library.js", + "\r", + "--7B0MKBI3UH--" +].join("\n"); + function contentHandler(metadata, response) { response.setHeader("Content-Type", 'application/package'); @@ -108,16 +181,22 @@ function regularContentHandler(metadata, response) response.bodyOutputStream.write(body, body.length); } -function contentHandlerWithSignature(metadata, response) +function contentHandlerWithBadSignature(metadata, response) { response.setHeader("Content-Type", 'application/package'); - var body = testData.packageHeader + testData.getData(); + var body = badSignature + packageContent; + response.bodyOutputStream.write(body, body.length); +} + +function contentHandlerWithGoodSignature(metadata, response) +{ + response.setHeader("Content-Type", 'application/package'); + var body = goodSignature + packageContent; response.bodyOutputStream.write(body, body.length); } var httpserver = null; var originalPref = false; -var originalDevMode = false; var originalSignedAppEnabled = false; function run_test() @@ -126,15 +205,14 @@ function run_test() httpserver = new HttpServer(); httpserver.registerPathHandler("/package", contentHandler); httpserver.registerPathHandler("/regular", regularContentHandler); - httpserver.registerPathHandler("/package_with_signature", contentHandlerWithSignature); + httpserver.registerPathHandler("/package_with_good_signature", contentHandlerWithGoodSignature); + httpserver.registerPathHandler("/package_with_bad_signature", contentHandlerWithBadSignature); httpserver.start(-1); // Enable the feature and save the original pref value originalPref = Services.prefs.getBoolPref("network.http.enable-packaged-apps"); - originalDevMode = Services.prefs.getBoolPref("network.http.packaged-apps-developer-mode"); originalSignedAppEnabled = Services.prefs.getBoolPref("network.http.packaged-signed-apps-enabled"); Services.prefs.setBoolPref("network.http.enable-packaged-apps", true); - Services.prefs.setBoolPref("network.http.packaged-apps-developer-mode", false); Services.prefs.setBoolPref("network.http.packaged-signed-apps-enabled", true); do_register_cleanup(reset_pref); @@ -142,32 +220,27 @@ function run_test() add_test(test_channel_no_notificationCallbacks); add_test(test_channel_uris); - add_test(test_channel_with_signature); - add_test(test_channel_with_signature_dev_mode); + add_test(test_channel_with_bad_signature); + add_test(test_channel_with_good_signature); // run tests run_next_test(); } -function test_channel_with_signature() { - var channel = make_channel(uri+"/package_with_signature!//index.html"); +function test_channel_with_bad_signature() { + var channel = make_channel(uri+"/package_with_bad_signature!//index.html"); channel.notificationCallbacks = new LoadContextCallback(1024, false, false, false); channel.asyncOpen(new Listener(function(l) { - // Since the manifest verification is not implemented yet, we should - // get NS_ERROR_FILE_NOT_FOUND if the package has a signature while - // not in developer mode. do_check_true(l.gotFileNotFound); run_next_test(); }), null); } -function test_channel_with_signature_dev_mode() { - Services.prefs.setBoolPref("network.http.packaged-apps-developer-mode", true); - var channel = make_channel(uri+"/package_with_signature!//index.html"); +function test_channel_with_good_signature() { + var channel = make_channel(uri+"/package_with_good_signature!//index.html"); channel.notificationCallbacks = new LoadContextCallback(1024, false, false, false); channel.asyncOpen(new Listener(function(l) { do_check_true(l.gotStopRequestOK); - Services.prefs.setBoolPref("network.http.packaged-apps-developer-mode", false); run_next_test(); }), null); } @@ -208,6 +281,5 @@ function check_regular_response(request, buffer) { function reset_pref() { // Set the pref to its original value Services.prefs.setBoolPref("network.http.enable-packaged-apps", originalPref); - Services.prefs.setBoolPref("network.http.packaged-apps-developer-mode", originalDevMode); Services.prefs.setBoolPref("network.http.packaged-signed-apps-enabled", originalSignedAppEnabled); } diff --git a/netwerk/test/unit/test_packaged_app_service.js b/netwerk/test/unit/test_packaged_app_service.js index 3014ff9dd2c..2d44bf1e340 100644 --- a/netwerk/test/unit/test_packaged_app_service.js +++ b/netwerk/test/unit/test_packaged_app_service.js @@ -120,6 +120,77 @@ var testData = { } } +var signedPackage = [ + "manifest-signature: MIIF1AYJKoZIhvcNAQcCoIIFxTCCBcECAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHAaCCA54wggOaMIICgqADAgECAgECMA0GCSqGSIb3DQEBCwUAMHMxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEkMCIGA1UEChMbRXhhbXBsZSBUcnVzdGVkIENvcnBvcmF0aW9uMRkwFwYDVQQDExBUcnVzdGVkIFZhbGlkIENBMB4XDTE1MDkxMDA4MDQzNVoXDTM1MDkxMDA4MDQzNVowdDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MSQwIgYDVQQKExtFeGFtcGxlIFRydXN0ZWQgQ29ycG9yYXRpb24xGjAYBgNVBAMTEVRydXN0ZWQgQ29ycCBDZXJ0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAts8whjOzEbn/w1xkFJ67af7F/JPujBK91oyJekh2schIMzFau9pY8S1AiJQoJCulOJCJfUc8hBLKBZiGAkii+4Gpx6cVqMLe6C22MdD806Soxn8Dg4dQqbIvPuI4eeVKu5CEk80PW/BaFMmRvRHO62C7PILuH6yZeGHC4P7dTKpsk4CLxh/jRGXLC8jV2BCW0X+3BMbHBg53NoI9s1Gs7KGYnfOHbBP5wEFAa00RjHnubUaCdEBlC8Kl4X7p0S4RGb3rsB08wgFe9EmSZHIgcIm+SuVo7N4qqbI85qo2ulU6J8NN7ZtgMPHzrMhzgAgf/KnqPqwDIxnNmRNJmHTUYwIDAQABozgwNjAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMDMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAQEAukH6cJUUj5faa8CuPCqrEa0PoLY4SYNnff9NI+TTAHkB9l+kOcFl5eo2EQOcWmZKYi7QLlWC4jy/KQYattO9FMaxiOQL4FAc6ZIbNyfwWBzZWyr5syYJTTTnkLq8A9pCKarN49+FqhJseycU+8EhJEJyP5pv5hLvDNTTHOQ6SXhASsiX8cjo3AY4bxA5pWeXuTZ459qDxOnQd+GrOe4dIeqflk0hA2xYKe3SfF+QlK8EO370B8Dj8RX230OATM1E3OtYyALe34KW3wM9Qm9rb0eViDnVyDiCWkhhQnw5yPg/XQfloug2itRYuCnfUoRt8xfeHgwz2Ymz8cUADn3KpTGCAf4wggH6AgEBMHgwczELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MSQwIgYDVQQKExtFeGFtcGxlIFRydXN0ZWQgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFRydXN0ZWQgVmFsaWQgQ0ECAQIwCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTE1MTAwMTIxMTEwNlowIwYJKoZIhvcNAQkEMRYEFHAisUYrrt+gBxYFhZ5KQQusOmN3MA0GCSqGSIb3DQEBAQUABIIBACHW4V0BsPWOvWrGOTRj6mPpNbH/JI1bN2oyqQZrpUQoaBY+BbYxO7TY4Uwe+aeIR/TTPJznOMF/dl3Bna6TPabezU4ylg7TVFI6W7zC5f5DZKp+Xv6uTX6knUzbbW1fkJqMtE8hGUzYXc3/C++Ci6kuOzrpWOhk6DpJHeUO/ioV56H0+QK/oMAjYpEsOohaPqvTPNOBhMQ0OQP3bmuJ6HcjZ/oz96PpzXUPKT1tDe6VykIYkV5NvtC8Tu2lDbYvp9ug3gyDgdyNSV47y5i/iWkzEhsAJB+9Z50wKhplnkxxVHEXkB/6tmfvExvQ28gLd/VbaEGDX2ljCaTSUjhD0o0=\r", + "--7B0MKBI3UH\r", + "Content-Location: manifest.webapp\r", + "Content-Type: application/x-web-app-manifest+json\r", + "\r", + "{", + " \"name\": \"My App\",", + " \"moz-resources\": [", + " {", + " \"src\": \"page2.html\",", + " \"integrity\": \"JREF3JbXGvZ+I1KHtoz3f46ZkeIPrvXtG4VyFQrJ7II=\"", + " },", + " {", + " \"src\": \"index.html\",", + " \"integrity\": \"zEubR310nePwd30NThIuoCxKJdnz7Mf5z+dZHUbH1SE=\"", + " },", + " {", + " \"src\": \"scripts/script.js\",", + " \"integrity\": \"6TqtNArQKrrsXEQWu3D9ZD8xvDRIkhyV6zVdTcmsT5Q=\"", + " },", + " {", + " \"src\": \"scripts/library.js\",", + " \"integrity\": \"TN2ByXZiaBiBCvS4MeZ02UyNi44vED+KjdjLInUl4o8=\"", + " }", + " ],", + " \"moz-permissions\": [", + " {", + " \"systemXHR\": {", + " \"description\": \"Needed to download stuff\"", + " },", + " \"devicestorage:pictures\": {", + " \"description\": \"Need to load pictures\"", + " }", + " }", + " ],", + " \"package-identifier\": \"611FC2FE-491D-4A47-B3B3-43FBDF6F404F\",", + " \"moz-package-location\": \"https://example.com/myapp/app.pak\",", + " \"description\": \"A great app!\"", + "}\r", + "--7B0MKBI3UH\r", + "Content-Location: page2.html\r", + "Content-Type: text/html\r", + "\r", + "", + " page2.html", + "", + "\r", + "--7B0MKBI3UH\r", + "Content-Location: index.html\r", + "Content-Type: text/html\r", + "\r", + "", + " Last updated: 2015/10/01 14:10 PST", + "", + "\r", + "--7B0MKBI3UH\r", + "Content-Location: scripts/script.js\r", + "Content-Type: text/javascript\r", + "\r", + "// script.js", + "\r", + "--7B0MKBI3UH\r", + "Content-Location: scripts/library.js\r", + "Content-Type: text/javascript\r", + "\r", + "// library.js", + "\r", + "--7B0MKBI3UH--" +].join("\n"); + XPCOMUtils.defineLazyGetter(this, "uri", function() { return "http://localhost:" + httpserver.identity.primaryPort; }); @@ -505,7 +576,7 @@ function test_worse_package_5() { function signedPackagedAppContentHandler(metadata, response) { response.setHeader("Content-Type", 'application/package'); - var body = testData.packageHeader + testData.getData(); + var body = signedPackage; response.bodyOutputStream.write(body, body.length); } @@ -523,9 +594,6 @@ var dummyCacheListener = { function test_signed_package_callback() { - // TODO: To be removed in Bug 1178518. - gPrefs.setBoolPref("network.http.packaged-apps-developer-mode", true); - packagePath = "/signedPackage"; let url = uri + packagePath + "!//index.html"; let channel = getChannelForURL(url, { @@ -544,6 +612,9 @@ function test_signed_package_callback() iid.equals(Ci.nsIPackagedAppChannelListener)) { return this; } + if (iid.equals(Ci.nsILoadContext)) { + return new LoadContextCallback(1024, false, false, false); + } throw Cr.NS_ERROR_NO_INTERFACE; }, }); @@ -570,6 +641,9 @@ function test_unsigned_package_callback() iid.equals(Ci.nsIPackagedAppChannelListener)) { return this; } + if (iid.equals(Ci.nsILoadContext)) { + return new LoadContextCallback(1024, false, false, false); + } throw Cr.NS_ERROR_NO_INTERFACE; }, }); diff --git a/netwerk/test/unit/test_packaged_app_utils.js b/netwerk/test/unit/test_packaged_app_utils.js index d49b53307f4..2f304d5af99 100644 --- a/netwerk/test/unit/test_packaged_app_utils.js +++ b/netwerk/test/unit/test_packaged_app_utils.js @@ -98,7 +98,7 @@ function test_verify_manifest(aHeader, aManifest, aShouldSucceed) { run_next_test(); } }; - packagedAppUtils.verifyManifest(aHeader, aManifest, fakeVerifier); + packagedAppUtils.verifyManifest(aHeader, aManifest, fakeVerifier, false); } } diff --git a/netwerk/test/unit/test_packaged_app_verifier.js b/netwerk/test/unit/test_packaged_app_verifier.js index 1667dc2506b..b11d85a6b91 100644 --- a/netwerk/test/unit/test_packaged_app_verifier.js +++ b/netwerk/test/unit/test_packaged_app_verifier.js @@ -215,18 +215,6 @@ function test_invalid_signature(aDeveloperMode) { feedResources(expectedCallbacks, signature); } -function test_no_signature_developer_mode() -{ - enable_developer_mode() - test_no_signature(true); -} - -function test_invalid_signature_developer_mode() -{ - enable_developer_mode() - test_invalid_signature(true); -} - function run_test() { ok(!!gVerifier); @@ -235,10 +223,6 @@ function run_test() add_test(test_no_signature); add_test(test_invalid_signature); - // Test cases in developer mode. - add_test(test_no_signature_developer_mode); - add_test(test_invalid_signature_developer_mode); - // run tests run_next_test(); -} \ No newline at end of file +} diff --git a/security/apps/AppTrustDomain.cpp b/security/apps/AppTrustDomain.cpp index a74b6da8eb0..a3b65b73819 100644 --- a/security/apps/AppTrustDomain.cpp +++ b/security/apps/AppTrustDomain.cpp @@ -8,7 +8,13 @@ #include "certdb.h" #include "pkix/pkixnss.h" #include "mozilla/ArrayUtils.h" +#include "MainThreadUtils.h" +#include "mozilla/Preferences.h" +#include "nsComponentManagerUtils.h" +#include "nsIFile.h" +#include "nsIFileStreams.h" #include "nsIX509CertDB.h" +#include "nsNetUtil.h" #include "nsNSSCertificate.h" #include "prerror.h" #include "secerr.h" @@ -34,9 +40,15 @@ using namespace mozilla::pkix; extern PRLogModuleInfo* gPIPNSSLog; static const unsigned int DEFAULT_MIN_RSA_BITS = 2048; +static char kDevImportedDER[] = + "network.http.packaged-apps-developer-trusted-root"; namespace mozilla { namespace psm { +StaticMutex AppTrustDomain::sMutex; +nsAutoArrayPtr AppTrustDomain::sDevImportedDERData(nullptr); +unsigned int AppTrustDomain::sDevImportedDERLen = 0; + AppTrustDomain::AppTrustDomain(ScopedCERTCertList& certChain, void* pinArg) : mCertChain(certChain) , mPinArg(pinArg) @@ -101,6 +113,53 @@ AppTrustDomain::SetTrustedRoot(AppTrustedRoot trustedRoot) trustedDER.len = mozilla::ArrayLength(privilegedPackageRoot); break; + case nsIX509CertDB::DeveloperImportedRoot: { + StaticMutexAutoLock lock(sMutex); + if (!sDevImportedDERData) { + MOZ_ASSERT(!NS_IsMainThread()); + nsCOMPtr file(do_CreateInstance("@mozilla.org/file/local;1")); + if (!file) { + PR_SetError(SEC_ERROR_IO, 0); + return SECFailure; + } + nsresult rv = file->InitWithNativePath( + Preferences::GetCString(kDevImportedDER)); + if (NS_FAILED(rv)) { + PR_SetError(SEC_ERROR_IO, 0); + return SECFailure; + } + + nsCOMPtr inputStream; + NS_NewLocalFileInputStream(getter_AddRefs(inputStream), file, -1, -1, + nsIFileInputStream::CLOSE_ON_EOF); + if (!inputStream) { + PR_SetError(SEC_ERROR_IO, 0); + return SECFailure; + } + + uint64_t length; + rv = inputStream->Available(&length); + if (NS_FAILED(rv)) { + PR_SetError(SEC_ERROR_IO, 0); + return SECFailure; + } + + char* data = new char[length]; + rv = inputStream->Read(data, length, &sDevImportedDERLen); + if (NS_FAILED(rv)) { + PR_SetError(SEC_ERROR_IO, 0); + return SECFailure; + } + + MOZ_ASSERT(length == sDevImportedDERLen); + sDevImportedDERData = reinterpret_cast(data); + } + + trustedDER.data = sDevImportedDERData; + trustedDER.len = sDevImportedDERLen; + break; + } + default: PR_SetError(SEC_ERROR_INVALID_ARGS, 0); return SECFailure; diff --git a/security/apps/AppTrustDomain.h b/security/apps/AppTrustDomain.h index e494874101d..fb742a8b170 100644 --- a/security/apps/AppTrustDomain.h +++ b/security/apps/AppTrustDomain.h @@ -8,6 +8,8 @@ #define mozilla_psm_AppsTrustDomain_h #include "pkix/pkixtypes.h" +#include "mozilla/StaticMutex.h" +#include "nsAutoPtr.h" #include "nsDebug.h" #include "nsIX509CertDB.h" #include "ScopedNSSTypes.h" @@ -69,6 +71,10 @@ private: void* mPinArg; // non-owning! ScopedCERTCertificate mTrustedRoot; unsigned int mMinRSABits; + + static StaticMutex sMutex; + static nsAutoArrayPtr sDevImportedDERData; + static unsigned int sDevImportedDERLen; }; } } // namespace mozilla::psm diff --git a/security/manager/ssl/nsIX509CertDB.idl b/security/manager/ssl/nsIX509CertDB.idl index d1ba93edeb8..345290433e6 100644 --- a/security/manager/ssl/nsIX509CertDB.idl +++ b/security/manager/ssl/nsIX509CertDB.idl @@ -46,7 +46,7 @@ interface nsIVerifySignedManifestCallback : nsISupports * This represents a service to access and manipulate * X.509 certificates stored in a database. */ -[scriptable, uuid(0a47571d-602c-4b21-9f52-c3d0e681d83a)] +[scriptable, uuid(a36c45fb-f7b5-423e-a0f7-ea1eb4fd60b5)] interface nsIX509CertDB : nsISupports { /** @@ -319,6 +319,14 @@ interface nsIX509CertDB : nsISupports { const AppTrustedRoot AddonsPublicRoot = 7; const AppTrustedRoot AddonsStageRoot = 8; const AppTrustedRoot PrivilegedPackageRoot = 9; + /* + * If DeveloperImportedRoot is set as trusted root, a CA from local file + * system will be imported. Only used when preference + * "network.http.packaged-apps-developer-mode" is set. + * The path of the CA is specified by preference + * "network.http.packaged-apps-developer-trusted-root". + */ + const AppTrustedRoot DeveloperImportedRoot = 10; void openSignedAppFileAsync(in AppTrustedRoot trustedRoot, in nsIFile aJarFile, in nsIOpenSignedAppFileCallback callback);