      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 {

         DataWriter w = Flavor.JSON.createDataWriter(null, rsp);
         w.startArray();
         w.value(q);
--- 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 {

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 "";
