in core/src/main/java/jenkins/util/JSONSignatureValidator.java [58:141]
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<>();
{// load and verify certificates
CertificateFactory cf = CertificateFactory.getInstance("X509");
for (Object cert : signature.getJSONArray("certificates")) {
try {
X509Certificate c = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(Base64.getDecoder().decode(cert.toString().getBytes(StandardCharsets.UTF_8))));
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));
}
LOGGER.log(Level.FINE, "Add certificate found in JSON document:\n\tsubjectDN: {0}\n\tissuer: {1}\n\tnotBefore: {2}\n\tnotAfter: {3}",
new Object[] { c.getSubjectDN(), c.getIssuerDN(), c.getNotBefore(), c.getNotAfter() });
LOGGER.log(Level.FINEST, () -> "Certificate from JSON document: " + c);
certs.add(c);
} catch (IllegalArgumentException ex) {
throw new IOException("Could not decode certificate", ex);
}
}
CertificateUtil.validatePath(certs, loadTrustAnchors(cf));
}
if (certs.isEmpty()) {
return FormValidation.error("No certificate found in %s. Cannot verify the signature", name);
}
// check the better digest first
FormValidation resultSha512 = null;
try {
MessageDigest digest = MessageDigest.getInstance("SHA-512");
Signature sig = Signature.getInstance("SHA512withRSA");
sig.initVerify(certs.get(0));
resultSha512 = checkSpecificSignature(o, signature, digest, "correct_digest512", sig, "correct_signature512", "SHA-512");
switch (resultSha512.kind) {
case ERROR:
return resultSha512;
case WARNING:
LOGGER.log(Level.INFO, "JSON data source '" + name + "' does not provide a SHA-512 content checksum or signature. Looking for SHA-1.");
break;
case OK:
// fall through
}
} catch (NoSuchAlgorithmException nsa) {
LOGGER.log(Level.WARNING, "Failed to verify potential SHA-512 digest/signature, falling back to SHA-1", nsa);
}
// if we get here, SHA-512 passed, wasn't provided, or the JRE is terrible.
MessageDigest digest = MessageDigest.getInstance("SHA1");
Signature sig = Signature.getInstance("SHA1withRSA");
sig.initVerify(certs.get(0));
FormValidation resultSha1 = checkSpecificSignature(o, signature, digest, "correct_digest", sig, "correct_signature", "SHA-1");
switch (resultSha1.kind) {
case ERROR:
return resultSha1;
case WARNING:
if (resultSha512.kind == FormValidation.Kind.WARNING) {
// neither signature provided
return FormValidation.error("No correct_signature or correct_signature512 entry found in '" + name + "'.");
}
case OK:
// fall through
}
if (warning!=null) return warning;
return FormValidation.ok();
} catch (GeneralSecurityException e) {
return FormValidation.error(e, "Signature verification failed in "+name);
}
}