提交 86ea65ab 编写于 作者: S Stephen Connolly

Make it possible for sub-classes to have a sub-class specific trust anchor chain

上级 4cb7414e
...@@ -218,7 +218,16 @@ public class UpdateSite { ...@@ -218,7 +218,16 @@ public class UpdateSite {
* Verifies the signature in the update center data file. * Verifies the signature in the update center data file.
*/ */
private FormValidation verifySignature(JSONObject o) throws IOException { private FormValidation verifySignature(JSONObject o) throws IOException {
return new JSONSignatureValidator("update site '"+id+"'").verifySignature(o); return getJsonSignatureValidator().verifySignature(o);
}
/**
* Let sub-classes of UpdateSite provide their own signature validator.
* @return the signature validator.
*/
@Nonnull
protected JSONSignatureValidator getJsonSignatureValidator() {
return new JSONSignatureValidator("update site '"+id+"'");
} }
/** /**
......
...@@ -72,6 +72,64 @@ public class JSONSignatureValidator { ...@@ -72,6 +72,64 @@ public class JSONSignatureValidator {
certs.add(c); certs.add(c);
} }
CertificateUtil.validatePath(certs, loadTrustAnchors(cf));
}
// 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)) {
String msg = "Digest mismatch: computed=" + computedDigest + " vs expected=" + providedDigest + " in " + name;
if (LOGGER.isLoggable(Level.SEVERE)) {
LOGGER.severe(msg);
LOGGER.severe(o.toString(2));
}
return FormValidation.error(msg);
}
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);
}
}
protected Set<TrustAnchor> loadTrustAnchors(CertificateFactory cf) throws IOException {
// if we trust default root CAs, we end up trusting anyone who has a valid certificate, // if we trust default root CAs, we end up trusting anyone who has a valid certificate,
// which isn't useful at all // which isn't useful at all
Set<TrustAnchor> anchors = new HashSet<TrustAnchor>(); // CertificateUtil.getDefaultRootCAs(); Set<TrustAnchor> anchors = new HashSet<TrustAnchor>(); // CertificateUtil.getDefaultRootCAs();
...@@ -134,61 +192,7 @@ public class JSONSignatureValidator { ...@@ -134,61 +192,7 @@ public class JSONSignatureValidator {
} }
} }
} }
CertificateUtil.validatePath(certs, anchors); return 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)) {
String msg = "Digest mismatch: computed=" + computedDigest + " vs expected=" + providedDigest + " in " + name;
if (LOGGER.isLoggable(Level.SEVERE)) {
LOGGER.severe(msg);
LOGGER.severe(o.toString(2));
}
return FormValidation.error(msg);
}
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);
}
} }
private static final Logger LOGGER = Logger.getLogger(JSONSignatureValidator.class.getName()); private static final Logger LOGGER = Logger.getLogger(JSONSignatureValidator.class.getName());
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册