in main/src/main/java/org/apache/james/jdkim/DKIMVerifier.java [236:316]
public BodyHasher newBodyHasher(Headers messageHeaders) throws FailException {
List<String> fields = messageHeaders.getFields("DKIM-Signature");
if (fields == null || fields.isEmpty()) {
return null;
}
// For each DKIM-signature we prepare an hashjob.
// We calculate all hashes concurrently so to read
// the inputstream only once.
Map<String, BodyHasherImpl> bodyHashJobs = new HashMap<>();
Hashtable<String, FailException> signatureExceptions = new Hashtable<>();
for (String signatureField : fields) {
try {
int pos = signatureField.indexOf(':');
if (pos > 0) {
String v = signatureField.substring(pos + 1);
SignatureRecord signatureRecord = null;
try {
signatureRecord = newSignatureRecord(v);
} catch (IllegalStateException e) {
throw new PermFailException("Invalid signature record: " + e.getMessage(), signatureRecord, e);
}
// Specification say we MAY refuse to verify the signature.
if (signatureRecord.getSignatureTimestamp() != null) {
long signedTime = signatureRecord.getSignatureTimestamp();
long elapsed = (System.currentTimeMillis() / 1000 - signedTime);
if (elapsed < -3600 * 24 * 365 * 3) {
throw new PermFailException("Signature date is more than "
+ -elapsed / (3600 * 24 * 365) + " years in the future.", signatureRecord);
} else if (elapsed < -3600 * 24 * 30 * 3) {
throw new PermFailException("Signature date is more than "
+ -elapsed / (3600 * 24 * 30) + " months in the future.", signatureRecord);
} else if (elapsed < -3600 * 24 * 3) {
throw new PermFailException("Signature date is more than "
+ -elapsed / (3600 * 24) + " days in the future.", signatureRecord);
} else if (elapsed < -3600 * 3) {
throw new PermFailException("Signature date is more than "
+ -elapsed / 3600 + " hours in the future.", signatureRecord);
} else if (elapsed < -60 * 3) {
throw new PermFailException("Signature date is more than "
+ -elapsed / 60 + " minutes in the future.", signatureRecord);
} else if (elapsed < 0) {
throw new PermFailException("Signature date is "
+ elapsed + " seconds in the future.", signatureRecord);
}
}
// TODO here we could check more parameters for
// validation before running a network operation like the
// dns lookup.
// e.g: the canonicalization method could be checked now.
PublicKeyRecord publicKeyRecord = publicRecordLookup(signatureRecord);
List<CharSequence> signedHeadersList = signatureRecord.getHeaders();
byte[] decoded = signatureRecord.getSignature();
signatureVerify(messageHeaders, signatureRecord, decoded,
publicKeyRecord, signedHeadersList);
// we track all canonicalizations+limit+bodyHash we
// see so to be able to check all of them in a single
// stream run.
BodyHasherImpl bhj = newBodyHasher(signatureRecord);
bodyHashJobs.put(signatureField, bhj);
} else {
throw new PermFailException(
"unexpected bad signature field");
}
} catch (TempFailException | PermFailException e) {
signatureExceptions.put(signatureField, e);
} catch (RuntimeException e) {
signatureExceptions.put(signatureField, new PermFailException(
"Unexpected exception processing signature", e));
}
}
return new CompoundBodyHasher(bodyHashJobs, signatureExceptions);
}