[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#688764: unblock: jenkins/1.447.2+dfsg-2



Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Please unblock package jenkins

The version I have just uploaded to unstable fixes two security issues
as outlined in http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=688298.

One is classified as 'Critical' and the other is classified as 'High'.

The fix was cherry picked from the latest upstream LTS release under
guidance from the project leader, Kohsuke Kawaguchi.

Debdiff attached.

unblock jenkins/1.447.2+dfsg-2

- -- System Information:
Debian Release: wheezy/sid
  APT prefers unstable
  APT policy: (500, 'unstable')
Architecture: amd64 (x86_64)

Kernel: Linux 3.5.0-15-generic (SMP w/8 CPU cores)
Locale: LANG=C, LC_CTYPE=C (charmap=ANSI_X3.4-1968)
Shell: /bin/sh linked to /bin/dash

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.12 (GNU/Linux)

iQIcBAEBCAAGBQJQYbS2AAoJEL/srsug59jDYLsQAMYWKYTkCG7Y4E8TEtHAv4xu
ETxn6ZTBje9MPGa5ldNEpM032ZzcO1AOpDzrdZ39VYw4f+iAQpj4e1AvO2TvJccJ
cUPxvMGuPAbuB8ZD/cawQoD+6svcrqdHtwdRig91yEk2imXy7w6DIMu2YfxK8In8
+lg+uRlOFJSLEXKQd1hhb6pYRmJtj6FPX8ZIn3VPSpZhfvkw5Wk1yi37r8z248tY
3zzwMz9T2eNR2YbYhC/H8IcImruXx6gOSDzpDPQ1ZydivjGoPOHWshKefTn/dqPV
I1+Yv3kFGtkhllZlRaI8IKFsRbFA+B7TmiK2lmvz1CZR1EdZ8uzwARPjF/JtzV6m
m01XbAfCEylwJu/1edJ9M17sfc83iDBM6v3+83WXvix64yZoeaZt3THD275XJzIV
UASNGucjQ8bk7cTNAsCt73VYzsOhD5IT7XGApFjXswbn00huauwu7NrJjNOy2jzF
4qncAJ02scs+ZD9c0D0ZgtSfKsDBYwyjCABSObkY0E/av6PJyfGkjOD4C9FCCpcH
c9BpdhZMa+fXy5Iq4DV1zsjmGzJW4c3ZyLPXw3IxsY4keK1f/RPBeFfG1yPiQzsH
n9xdQ2NCsCKAJv9kC55a0rowh3vgJ7irMUiRwze+uoMOzfHZxkGiCT2hDj88njy+
qWZH8txRw7Dd0o8KhRc3
=5s7y
-----END PGP SIGNATURE-----
diff -Nru jenkins-1.447.2+dfsg/debian/changelog jenkins-1.447.2+dfsg/debian/changelog
--- jenkins-1.447.2+dfsg/debian/changelog	2012-06-21 10:18:11.000000000 +0100
+++ jenkins-1.447.2+dfsg/debian/changelog	2012-09-25 12:21:13.000000000 +0100
@@ -1,3 +1,15 @@
+jenkins (1.447.2+dfsg-2) unstable; urgency=low
+
+  * Fix multiple security issues in Jenkins core (Closes: #688298):
+    - d/p/security/CVE-2012-4438_CVE-2012-4439.patch: Cherry picked
+      fixes from 1.466.2 release to resolve remote code execution
+      and XSS security vulnerabilities.
+    - d/rules: Tweaked handling of groovy -> java source file copy to
+      accommodate the file created by the above patch.
+    - Fixes: CVE-2012-4438, CVE-2012-4439
+
+ -- James Page <james.page@ubuntu.com>  Tue, 25 Sep 2012 11:01:53 +0100
+
 jenkins (1.447.2+dfsg-1) unstable; urgency=low
 
   * New upstream release. 
diff -Nru jenkins-1.447.2+dfsg/debian/patches/security/CVE-2012-4438_CVE-2012-4439.patch jenkins-1.447.2+dfsg/debian/patches/security/CVE-2012-4438_CVE-2012-4439.patch
--- jenkins-1.447.2+dfsg/debian/patches/security/CVE-2012-4438_CVE-2012-4439.patch	1970-01-01 01:00:00.000000000 +0100
+++ jenkins-1.447.2+dfsg/debian/patches/security/CVE-2012-4438_CVE-2012-4439.patch	2012-09-25 12:21:13.000000000 +0100
@@ -0,0 +1,559 @@
+Decription: Cherry picked fixes from 1.466.2 to resolve
+ two security issues:
+    - CVE-2012-4438 jenkins remote code execution
+    - CVE-2012-4439 jenkins XSS
+Origin: Upstream, commits fb73bac50f22526a3d3b...43ff1688eee6ea
+Bug: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=688298
+
+diff --git a/core/src/main/java/hudson/model/DownloadService.java b/core/src/main/java/hudson/model/DownloadService.java
+index 7f8d86d..820a44a 100644
+--- a/core/src/main/java/hudson/model/DownloadService.java
++++ b/core/src/main/java/hudson/model/DownloadService.java
+@@ -26,18 +26,20 @@ package hudson.model;
+ import hudson.Extension;
+ import hudson.ExtensionList;
+ import hudson.ExtensionPoint;
++import hudson.util.FormValidation;
++import hudson.util.FormValidation.Kind;
+ import hudson.util.IOException2;
+ import hudson.util.IOUtils;
+ import hudson.util.QuotedStringTokenizer;
+ import hudson.util.TextFile;
+ import hudson.util.TimeUnit2;
+ import jenkins.model.Jenkins;
++import jenkins.util.JSONSignatureValidator;
+ import net.sf.json.JSONException;
+ import org.kohsuke.stapler.Stapler;
+ 
+ import java.io.File;
+ import java.io.IOException;
+-import java.util.logging.Level;
+ import java.util.logging.Logger;
+ 
+ import net.sf.json.JSONObject;
+@@ -61,7 +63,8 @@ public class DownloadService extends PageDecorator {
+      */
+     public String generateFragment() {
+     	if (neverUpdate) return "";
+-    	
++        if (doesNotSupportPostMessage())  return "";
++
+         StringBuilder buf = new StringBuilder();
+         if(Jenkins.getInstance().hasPermission(Jenkins.READ)) {
+             long now = System.currentTimeMillis();
+@@ -88,6 +91,23 @@ public class DownloadService extends PageDecorator {
+         return buf.toString();
+     }
+ 
++    private boolean doesNotSupportPostMessage() {
++        StaplerRequest req = Stapler.getCurrentRequest();
++        if (req==null)      return false;
++
++        String ua = req.getHeader("User-Agent");
++        if (ua==null)       return false;
++
++        // according to http://caniuse.com/#feat=x-doc-messaging, IE <=7 doesn't support pstMessage
++        // see http://www.useragentstring.com/pages/Internet%20Explorer/ for user agents
++
++        // we want to err on the cautious side here.
++        // Because of JENKINS-15105, we can't serve signed metadata from JSON, which means we need to be
++        // using a modern browser as a vehicle to request these data. This check is here to prevent Jenkins
++        // from using older browsers that are known not to support postMessage as the vehicle.
++        return ua.contains("Windows") && (ua.contains(" MSIE 5.") || ua.contains(" MSIE 6.") || ua.contains(" MSIE 7."));
++    }
++
+     private String mapHttps(String url) {
+         /*
+             HACKISH:
+@@ -223,11 +243,24 @@ public class DownloadService extends PageDecorator {
+          */
+         public void doPostBack(StaplerRequest req, StaplerResponse rsp) throws IOException {
+             long dataTimestamp = System.currentTimeMillis();
++            due = dataTimestamp+getInterval();  // success or fail, don't try too often
++
++            String json = IOUtils.toString(req.getInputStream(),"UTF-8");
++            JSONObject o = JSONObject.fromObject(json);
++
++            if (signatureCheck) {
++                FormValidation e = new JSONSignatureValidator("downloadable '"+id+"'").verifySignature(o);
++                if (e.kind!= Kind.OK) {
++                    LOGGER.severe(e.renderHtml());
++                    throw e;
++                }
++            }
++
+             TextFile df = getDataFile();
+-            df.write(IOUtils.toString(req.getInputStream(),"UTF-8"));
++            df.write(json);
+             df.file.setLastModified(dataTimestamp);
+-            due = dataTimestamp+getInterval();
+             LOGGER.info("Obtained the updated data file for "+id);
++
+             rsp.setContentType("text/plain");  // So browser won't try to parse response
+         }
+ 
+@@ -253,5 +286,10 @@ public class DownloadService extends PageDecorator {
+     }
+ 
+     public static boolean neverUpdate = Boolean.getBoolean(DownloadService.class.getName()+".never");
++
++    /**
++     * Off by default until we know this is reasonably working.
++     */
++    public static boolean signatureCheck = !Boolean.getBoolean(DownloadService.class.getName()+".noSignatureCheck");
+ }
+ 
+diff --git a/core/src/main/java/hudson/model/UpdateSite.java b/core/src/main/java/hudson/model/UpdateSite.java
+index 74bccfb..578237e 100644
+--- a/core/src/main/java/hudson/model/UpdateSite.java
++++ b/core/src/main/java/hudson/model/UpdateSite.java
+@@ -25,7 +25,6 @@
+ 
+ package hudson.model;
+ 
+-import com.trilead.ssh2.crypto.Base64;
+ import hudson.PluginManager;
+ import hudson.PluginWrapper;
+ import hudson.lifecycle.Lifecycle;
+@@ -37,12 +36,9 @@ import hudson.util.IOUtils;
+ import hudson.util.TextFile;
+ import hudson.util.VersionNumber;
+ import jenkins.model.Jenkins;
++import jenkins.util.JSONSignatureValidator;
+ import net.sf.json.JSONException;
+ import net.sf.json.JSONObject;
+-import org.apache.commons.io.output.NullOutputStream;
+-import org.apache.commons.io.output.TeeOutputStream;
+-import org.jvnet.hudson.crypto.CertificateUtil;
+-import org.jvnet.hudson.crypto.SignatureOutputStream;
+ import org.kohsuke.stapler.DataBoundConstructor;
+ import org.kohsuke.stapler.HttpResponse;
+ import org.kohsuke.stapler.QueryParameter;
+@@ -52,23 +48,14 @@ import org.kohsuke.stapler.StaplerResponse;
+ import javax.servlet.ServletContext;
+ import java.io.ByteArrayInputStream;
+ import java.io.File;
+-import java.io.FileInputStream;
+ import java.io.IOException;
+ import java.io.OutputStreamWriter;
+ import java.io.Writer;
+ import java.security.DigestOutputStream;
+ import java.security.GeneralSecurityException;
+-import java.security.MessageDigest;
+-import java.security.Signature;
+-import java.security.cert.CertificateExpiredException;
+-import java.security.cert.CertificateFactory;
+-import java.security.cert.CertificateNotYetValidException;
+-import java.security.cert.TrustAnchor;
+-import java.security.cert.X509Certificate;
+ import java.util.ArrayList;
+ import java.util.Collections;
+ import java.util.HashMap;
+-import java.util.HashSet;
+ import java.util.List;
+ import java.util.Map;
+ import java.util.Set;
+@@ -174,100 +161,7 @@ public class UpdateSite {
+      * Verifies the signature in the update center data file.
+      */
+     private FormValidation verifySignature(JSONObject o) throws IOException {
+-        try {
+-            FormValidation warning = null;
+-
+-            JSONObject signature = o.getJSONObject("signature");
+-            if (signature.isNullObject()) {
+-                return FormValidation.error("No signature block found in update center '"+id+"'");
+-            }
+-            o.remove("signature");
+-
+-            List<X509Certificate> certs = new ArrayList<X509Certificate>();
+-            {// load and verify certificates
+-                CertificateFactory cf = CertificateFactory.getInstance("X509");
+-                for (Object cert : signature.getJSONArray("certificates")) {
+-                    X509Certificate c = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(Base64.decode(cert.toString().toCharArray())));
+-                    try {
+-                        c.checkValidity();
+-                    } catch (CertificateExpiredException e) { // even if the certificate isn't valid yet, we'll proceed it anyway
+-                        warning = FormValidation.warning(e,String.format("Certificate %s has expired in update center '%s'",cert.toString(),id));
+-                    } catch (CertificateNotYetValidException e) {
+-                        warning = FormValidation.warning(e,String.format("Certificate %s is not yet valid in update center '%s'",cert.toString(),id));
+-                    }
+-                    certs.add(c);
+-                }
+-
+-                // if we trust default root CAs, we end up trusting anyone who has a valid certificate,
+-                // which isn't useful at all
+-                Set<TrustAnchor> anchors = new HashSet<TrustAnchor>(); // CertificateUtil.getDefaultRootCAs();
+-                Jenkins j = Jenkins.getInstance();
+-                for (String cert : (Set<String>) j.servletContext.getResourcePaths("/WEB-INF/update-center-rootCAs")) {
+-                    if (cert.endsWith(".txt"))  continue;       // skip text files that are meant to be documentation
+-                    anchors.add(new TrustAnchor((X509Certificate)cf.generateCertificate(j.servletContext.getResourceAsStream(cert)),null));
+-                }
+-                File[] cas = new File(j.root, "update-center-rootCAs").listFiles();
+-                if (cas!=null) {
+-                    for (File cert : cas) {
+-                        if (cert.getName().endsWith(".txt"))  continue;       // skip text files that are meant to be documentation
+-                        FileInputStream in = new FileInputStream(cert);
+-                        try {
+-                            anchors.add(new TrustAnchor((X509Certificate)cf.generateCertificate(in),null));
+-                        } finally {
+-                            in.close();
+-                        }
+-                    }
+-                }
+-                CertificateUtil.validatePath(certs,anchors);
+-            }
+-
+-            // this is for computing a digest to check sanity
+-            MessageDigest sha1 = MessageDigest.getInstance("SHA1");
+-            DigestOutputStream dos = new DigestOutputStream(new NullOutputStream(),sha1);
+-
+-            // this is for computing a signature
+-            Signature sig = Signature.getInstance("SHA1withRSA");
+-            sig.initVerify(certs.get(0));
+-            SignatureOutputStream sos = new SignatureOutputStream(sig);
+-
+-            // until JENKINS-11110 fix, UC used to serve invalid digest (and therefore unverifiable signature)
+-            // that only covers the earlier portion of the file. This was caused by the lack of close() call
+-            // in the canonical writing, which apparently leave some bytes somewhere that's not flushed to
+-            // the digest output stream. This affects Jenkins [1.424,1,431].
+-            // Jenkins 1.432 shipped with the "fix" (1eb0c64abb3794edce29cbb1de50c93fa03a8229) that made it
+-            // compute the correct digest, but it breaks all the existing UC json metadata out there. We then
+-            // quickly discovered ourselves in the catch-22 situation. If we generate UC with the correct signature,
+-            // it'll cut off [1.424,1.431] from the UC. But if we don't, we'll cut off [1.432,*).
+-            //
+-            // In 1.433, we revisited 1eb0c64abb3794edce29cbb1de50c93fa03a8229 so that the original "digest"/"signature"
+-            // pair continues to be generated in a buggy form, while "correct_digest"/"correct_signature" are generated
+-            // correctly.
+-            //
+-            // Jenkins should ignore "digest"/"signature" pair. Accepting it creates a vulnerability that allows
+-            // the attacker to inject a fragment at the end of the json.
+-            o.writeCanonical(new OutputStreamWriter(new TeeOutputStream(dos,sos),"UTF-8")).close();
+-
+-            // did the digest match? this is not a part of the signature validation, but if we have a bug in the c14n
+-            // (which is more likely than someone tampering with update center), we can tell
+-            String computedDigest = new String(Base64.encode(sha1.digest()));
+-            String providedDigest = signature.optString("correct_digest");
+-            if (providedDigest==null) {
+-                return FormValidation.error("No correct_digest parameter in update center '"+id+"'. This metadata appears to be old.");
+-            }
+-            if (!computedDigest.equalsIgnoreCase(providedDigest)) {
+-                return FormValidation.error("Digest mismatch: "+computedDigest+" vs "+providedDigest+" in update center '"+id+"'");
+-            }
+-
+-            String providedSignature = signature.getString("correct_signature");
+-            if (!sig.verify(Base64.decode(providedSignature.toCharArray()))) {
+-                return FormValidation.error("Signature in the update center doesn't match with the certificate in update center '"+id+"'");
+-            }
+-
+-            if (warning!=null)  return warning;
+-            return FormValidation.ok();
+-        } catch (GeneralSecurityException e) {
+-            return FormValidation.error(e,"Signature verification failed in the update center '"+id+"'");
+-        }
++        return new JSONSignatureValidator("update site '"+id+"'").verifySignature(o);
+     }
+ 
+     /**
+diff --git a/core/src/main/java/hudson/search/Search.java b/core/src/main/java/hudson/search/Search.java
+index 55737b8..f439d8a 100644
+--- a/core/src/main/java/hudson/search/Search.java
++++ b/core/src/main/java/hudson/search/Search.java
+@@ -84,6 +84,7 @@ public class Search {
+      * See http://developer.mozilla.org/en/docs/Supporting_search_suggestions_in_search_plugins
+      */
+     public void doSuggestOpenSearch(StaplerRequest req, StaplerResponse rsp, @QueryParameter String q) throws IOException, ServletException {
++        rsp.setContentType(Flavor.JSON.contentType);
+         DataWriter w = Flavor.JSON.createDataWriter(null, rsp);
+         w.startArray();
+         w.value(q);
+diff --git a/core/src/main/java/hudson/tasks/junit/History.java b/core/src/main/java/hudson/tasks/junit/History.java
+index 6d5333c..7a46b60 100644
+--- a/core/src/main/java/hudson/tasks/junit/History.java
++++ b/core/src/main/java/hudson/tasks/junit/History.java
+@@ -293,4 +293,12 @@ public class History {
+ 
+     }
+ 
++    public static int asInt(String s, int defalutValue) {
++        if (s==null)    return defalutValue;
++        try {
++            return Integer.parseInt(s);
++        } catch (NumberFormatException e) {
++            return defalutValue;
++        }
++    }
+ }
+diff --git a/core/src/main/java/jenkins/util/JSONSignatureValidator.java b/core/src/main/java/jenkins/util/JSONSignatureValidator.java
+new file mode 100644
+index 0000000..69c6144
+--- /dev/null
++++ b/core/src/main/java/jenkins/util/JSONSignatureValidator.java
+@@ -0,0 +1,140 @@
++package jenkins.util;
++
++import com.trilead.ssh2.crypto.Base64;
++import hudson.util.FormValidation;
++import jenkins.model.Jenkins;
++import net.sf.json.JSONObject;
++import org.apache.commons.io.output.NullOutputStream;
++import org.apache.commons.io.output.TeeOutputStream;
++import org.jvnet.hudson.crypto.CertificateUtil;
++import org.jvnet.hudson.crypto.SignatureOutputStream;
++
++import java.io.ByteArrayInputStream;
++import java.io.File;
++import java.io.FileInputStream;
++import java.io.IOException;
++import java.io.OutputStreamWriter;
++import java.security.DigestOutputStream;
++import java.security.GeneralSecurityException;
++import java.security.MessageDigest;
++import java.security.Signature;
++import java.security.cert.CertificateExpiredException;
++import java.security.cert.CertificateFactory;
++import java.security.cert.CertificateNotYetValidException;
++import java.security.cert.TrustAnchor;
++import java.security.cert.X509Certificate;
++import java.util.ArrayList;
++import java.util.HashSet;
++import java.util.List;
++import java.util.Set;
++
++/**
++ * @author Kohsuke Kawaguchi
++ */
++public class JSONSignatureValidator {
++    private final String name;
++
++    public JSONSignatureValidator(String name) {
++        this.name = name;
++    }
++
++    /**
++     * Verifies the signature in the update center data file.
++     */
++    public FormValidation verifySignature(JSONObject o) throws IOException {
++        try {
++            FormValidation warning = null;
++
++            JSONObject signature = o.getJSONObject("signature");
++            if (signature.isNullObject()) {
++                return FormValidation.error("No signature block found in "+name);
++            }
++            o.remove("signature");
++
++            List<X509Certificate> certs = new ArrayList<X509Certificate>();
++            {// load and verify certificates
++                CertificateFactory cf = CertificateFactory.getInstance("X509");
++                for (Object cert : signature.getJSONArray("certificates")) {
++                    X509Certificate c = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(Base64.decode(cert.toString().toCharArray())));
++                    try {
++                        c.checkValidity();
++                    } catch (CertificateExpiredException e) { // even if the certificate isn't valid yet, we'll proceed it anyway
++                        warning = FormValidation.warning(e,String.format("Certificate %s has expired in %s",cert.toString(),name));
++                    } catch (CertificateNotYetValidException e) {
++                        warning = FormValidation.warning(e,String.format("Certificate %s is not yet valid in %s",cert.toString(),name));
++                    }
++                    certs.add(c);
++                }
++
++                // if we trust default root CAs, we end up trusting anyone who has a valid certificate,
++                // which isn't useful at all
++                Set<TrustAnchor> anchors = new HashSet<TrustAnchor>(); // CertificateUtil.getDefaultRootCAs();
++                Jenkins j = Jenkins.getInstance();
++                for (String cert : (Set<String>) j.servletContext.getResourcePaths("/WEB-INF/update-center-rootCAs")) {
++                    if (cert.endsWith(".txt"))  continue;       // skip text files that are meant to be documentation
++                    anchors.add(new TrustAnchor((X509Certificate)cf.generateCertificate(j.servletContext.getResourceAsStream(cert)),null));
++                }
++                File[] cas = new File(j.root, "update-center-rootCAs").listFiles();
++                if (cas!=null) {
++                    for (File cert : cas) {
++                        if (cert.getName().endsWith(".txt"))  continue;       // skip text files that are meant to be documentation
++                        FileInputStream in = new FileInputStream(cert);
++                        try {
++                            anchors.add(new TrustAnchor((X509Certificate)cf.generateCertificate(in),null));
++                        } finally {
++                            in.close();
++                        }
++                    }
++                }
++                CertificateUtil.validatePath(certs, anchors);
++            }
++
++            // this is for computing a digest to check sanity
++            MessageDigest sha1 = MessageDigest.getInstance("SHA1");
++            DigestOutputStream dos = new DigestOutputStream(new NullOutputStream(),sha1);
++
++            // this is for computing a signature
++            Signature sig = Signature.getInstance("SHA1withRSA");
++            sig.initVerify(certs.get(0));
++            SignatureOutputStream sos = new SignatureOutputStream(sig);
++
++            // until JENKINS-11110 fix, UC used to serve invalid digest (and therefore unverifiable signature)
++            // that only covers the earlier portion of the file. This was caused by the lack of close() call
++            // in the canonical writing, which apparently leave some bytes somewhere that's not flushed to
++            // the digest output stream. This affects Jenkins [1.424,1,431].
++            // Jenkins 1.432 shipped with the "fix" (1eb0c64abb3794edce29cbb1de50c93fa03a8229) that made it
++            // compute the correct digest, but it breaks all the existing UC json metadata out there. We then
++            // quickly discovered ourselves in the catch-22 situation. If we generate UC with the correct signature,
++            // it'll cut off [1.424,1.431] from the UC. But if we don't, we'll cut off [1.432,*).
++            //
++            // In 1.433, we revisited 1eb0c64abb3794edce29cbb1de50c93fa03a8229 so that the original "digest"/"signature"
++            // pair continues to be generated in a buggy form, while "correct_digest"/"correct_signature" are generated
++            // correctly.
++            //
++            // Jenkins should ignore "digest"/"signature" pair. Accepting it creates a vulnerability that allows
++            // the attacker to inject a fragment at the end of the json.
++            o.writeCanonical(new OutputStreamWriter(new TeeOutputStream(dos,sos),"UTF-8")).close();
++
++            // did the digest match? this is not a part of the signature validation, but if we have a bug in the c14n
++            // (which is more likely than someone tampering with update center), we can tell
++            String computedDigest = new String(Base64.encode(sha1.digest()));
++            String providedDigest = signature.optString("correct_digest");
++            if (providedDigest==null) {
++                return FormValidation.error("No correct_digest parameter in "+name+". This metadata appears to be old.");
++            }
++            if (!computedDigest.equalsIgnoreCase(providedDigest)) {
++                return FormValidation.error("Digest mismatch: "+computedDigest+" vs "+providedDigest+" in "+name);
++            }
++
++            String providedSignature = signature.getString("correct_signature");
++            if (!sig.verify(Base64.decode(providedSignature.toCharArray()))) {
++                return FormValidation.error("Signature in the update center doesn't match with the certificate in "+name);
++            }
++
++            if (warning!=null)  return warning;
++            return FormValidation.ok();
++        } catch (GeneralSecurityException e) {
++            return FormValidation.error(e,"Signature verification failed in "+name);
++        }
++    }
++}
+diff --git a/core/src/main/resources/hudson/tasks/junit/History/index.jelly b/core/src/main/resources/hudson/tasks/junit/History/index.jelly
+index 8ad7ee4..cda7a24 100644
+--- a/core/src/main/resources/hudson/tasks/junit/History/index.jelly
++++ b/core/src/main/resources/hudson/tasks/junit/History/index.jelly
+@@ -26,8 +26,8 @@ THE SOFTWARE.
+ <?jelly escape-by-default='true'?>
+ <j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt">
+   <l:layout title="${%title(it.testObject.displayName)}">
+-		<j:set var="start" value="${request.getParameter('start')?:0}"/>
+-		<j:set var="end" value="${request.getParameter('end')?:start+24}"/>
++		<j:set var="start" value="${it.asInt(request.getParameter('start'),0)}"/>
++		<j:set var="end" value="${it.asInt(request.getParameter('end'),start+24)}"/>
+ 		<j:set var="rangeParameters" value="start=${start}&amp;end=${end+1}"/>
+ 		<script type="text/javascript">
+ 			function setCount() {
+diff --git a/war/src/main/webapp/scripts/hudson-behavior.js b/war/src/main/webapp/scripts/hudson-behavior.js
+index f4abe0b..7b74dda 100644
+--- a/war/src/main/webapp/scripts/hudson-behavior.js
++++ b/war/src/main/webapp/scripts/hudson-behavior.js
+@@ -2308,12 +2308,69 @@ function loadScript(href,callback) {
+     head.insertBefore( script, head.firstChild );
+ }
+ 
++/**
++ * Loads a dynamically created invisible IFRAME.
++ */
++function createIframe(src,callback) {
++    var iframe = document.createElement("iframe");
++    iframe.src = src;
++    iframe.style.display = "none";
++
++    var done = false;
++    iframe.onload = iframe.onreadystatechange = function() {
++        if ( !done && (!this.readyState ||
++                this.readyState === "loaded" || this.readyState === "complete") ) {
++            done = true;
++            callback();
++        }
++    };
++
++    document.body.appendChild(iframe);
++    return iframe;
++}
++
+ var downloadService = {
+     continuations: {},
+ 
+     download : function(id,url,info, postBack,completionHandler) {
+-        this.continuations[id] = {postBack:postBack,completionHandler:completionHandler};
+-        loadScript(url+"?"+Hash.toQueryString(info));
++        var tag = {id:id,postBack:postBack,completionHandler:completionHandler,received:false};
++        this.continuations[id] = tag;
++
++        // use JSONP to download the data
++        function fallback() {
++            loadScript(url+"?id="+id+'&'+Hash.toQueryString(info));
++        }
++
++        if (window.postMessage) {
++            // try downloading the postMessage version of the data,
++            // if we don't receive postMessage (which probably means the server isn't ready with these new datasets),
++            // fallback to JSONP
++            tag.iframe = createIframe(url+".html?id="+id+'&'+Hash.toQueryString(info),function() {
++                window.setTimeout(function() {
++                    if (!tag.received)
++                        fallback();
++                },100); // bit of delay in case onload on our side fires first
++            });
++        } else {
++            // this browser doesn't support postMessage
++            fallback();
++        }
++
++        // NOTE:
++        //   the only reason we even try fallback() is in case our server accepts the submission without a signature
++        //   (which it really shouldn't)
++    },
++
++    /**
++     * Call back to postMessage
++     */
++    receiveMessage : function(ev) {
++        var self = this;
++        Object.values(this.continuations).each(function(tag) {
++            if (tag.iframe.contentWindow==ev.source) {
++                self.post(tag.id,JSON.parse(ev.data));
++            }
++        })
+     },
+ 
+     post : function(id,data) {
+@@ -2322,15 +2379,22 @@ var downloadService = {
+             data = id;
+             id = data.id;
+         }
+-        var o = this.continuations[id];
++        var tag = this.continuations[id];
++        if (tag==undefined) {
++            console.log("Submission from update center that we don't know: "+id);
++            console.log("Likely mismatch between the registered ID vs ID in JSON");
++            return;
++        }
++        tag.received = true;
++
+         // send the payload back in the body. We used to send this in as a form submission, but that hits the form size check in Jetty.
+-        new Ajax.Request(o.postBack, {
++        new Ajax.Request(tag.postBack, {
+             contentType:"application/json",
+             encoding:"UTF-8",
+             postBody:Object.toJSON(data),
+             onSuccess: function() {
+-                if(o.completionHandler!=null)
+-                    o.completionHandler();
++                if(tag.completionHandler!=null)
++                    tag.completionHandler();
+                 else if(downloadService.completionHandler!=null)
+                     downloadService.completionHandler();
+             }
+@@ -2341,6 +2405,8 @@ var downloadService = {
+ // update center service. to remain compatible with earlier version of Hudson, aliased.
+ var updateCenter = downloadService;
+ 
++YAHOO.util.Event.addListener(window, "message", function(ev) { downloadService.receiveMessage(ev); })
++
+ /*
+ redirects to a page once the page is ready.
+ 
diff -Nru jenkins-1.447.2+dfsg/debian/patches/series jenkins-1.447.2+dfsg/debian/patches/series
--- jenkins-1.447.2+dfsg/debian/patches/series	2012-06-21 10:18:11.000000000 +0100
+++ jenkins-1.447.2+dfsg/debian/patches/series	2012-09-25 12:21:13.000000000 +0100
@@ -16,3 +16,4 @@
 dependency-upgrades/animal-sniffer-upgrade.patch
 build/use-stock-jmdns.patch
 ubuntu/ubuntu-font.patch
+security/CVE-2012-4438_CVE-2012-4439.patch
diff -Nru jenkins-1.447.2+dfsg/debian/rules jenkins-1.447.2+dfsg/debian/rules
--- jenkins-1.447.2+dfsg/debian/rules	2012-06-21 10:18:11.000000000 +0100
+++ jenkins-1.447.2+dfsg/debian/rules	2012-09-25 12:21:13.000000000 +0100
@@ -57,7 +57,7 @@
 	[ ! -f dummy.keystore ] || rm dummy.keystore
 	rm -rf debian/*.upstart
 	rm -rf debian/plugin-debian.pom
-	rm -rf core/src/main/java/jenkins/util
+	rm -rf core/src/main/java/jenkins/util/ServerTcpPort.java
 
 get-orig-source:
 	uscan --download-version $(DEB_UPSTREAM_VERSION) --force-download --rename
@@ -73,7 +73,6 @@
 	done
 	# Hack in java files from groovy source folder - no idea why they are there
 	# might be maven3 related.
-	mkdir -p core/src/main/java/jenkins/util
 	cp core/src/main/groovy/jenkins/util/ServerTcpPort.java core/src/main/java/jenkins/util
 
 dummy.keystore:

Reply to: