S/MIME Skip checking sign time

The certificate chain will be checked separately
This commit is contained in:
M66B 2020-01-29 19:01:39 +01:00
parent a36c6b3684
commit 34a3b88b49
2 changed files with 56 additions and 12 deletions

View File

@ -93,7 +93,13 @@ public class EntityCertificate {
}
boolean isExpired() {
long now = new Date().getTime();
return isExpired(null);
}
boolean isExpired(Date date) {
if (date == null)
date = new Date();
long now = date.getTime();
return ((this.after != null && now <= this.after) || (this.before != null && now > this.before));
}

View File

@ -116,6 +116,10 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import com.sun.mail.util.FolderClosedIOException;
import org.bouncycastle.asn1.cms.Attribute;
import org.bouncycastle.asn1.cms.AttributeTable;
import org.bouncycastle.asn1.cms.CMSAttributes;
import org.bouncycastle.asn1.cms.Time;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cms.CMSEnvelopedData;
@ -128,6 +132,7 @@ import org.bouncycastle.cms.KeyTransRecipientId;
import org.bouncycastle.cms.RecipientInformation;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.cms.SignerInformationStore;
import org.bouncycastle.cms.SignerInformationVerifier;
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
import org.bouncycastle.cms.jcajce.JceKeyTransEnvelopedRecipient;
import org.bouncycastle.cms.jcajce.JceKeyTransRecipient;
@ -159,6 +164,7 @@ import java.security.cert.CertPathValidator;
import java.security.cert.CertStore;
import java.security.cert.CertStoreParameters;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.PKIXBuilderParameters;
@ -4774,7 +4780,26 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
X509Certificate cert = new JcaX509CertificateConverter()
.getCertificate(certHolder);
try {
if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().build(cert))) {
Date signingTime;
Attribute attr = signer.getSignedAttributes().get(CMSAttributes.signingTime);
if (attr != null && attr.getAttrValues().size() == 1)
signingTime = Time.getInstance(attr.getAttrValues()
.getObjectAt(0).toASN1Primitive()).getDate();
else
signingTime = new Date(message.received);
args.putSerializable("time", signingTime);
SignerInformationVerifier verifier = new JcaSimpleSignerInfoVerifierBuilder()
.build(cert);
SignerInformation s = new SignerInformation(signer) {
@Override
public AttributeTable getSignedAttributes() {
// The certificate validity will be check below
return super.getSignedAttributes().remove(CMSAttributes.signingTime);
}
};
if (s.verify(verifier)) {
boolean known = true;
String fingerprint = EntityCertificate.getFingerprint(cert);
List<String> emails = EntityCertificate.getAltSubjectName(cert);
@ -4813,7 +4838,7 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
CertStoreParameters intermediates = new CollectionCertStoreParameters(certs);
params.addCertStore(CertStore.getInstance("Collection", intermediates));
params.setRevocationEnabled(false);
params.setDate(new Date(message.received));
params.setDate(signingTime);
CertPathBuilder builder = CertPathBuilder.getInstance("PKIX");
CertPathBuilderResult path = builder.build(params);
@ -4821,8 +4846,6 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
CertPathValidator cpv = CertPathValidator.getInstance("PKIX");
cpv.validate(path.getCertPath(), params);
args.putBoolean("valid", true);
List<Certificate> pcerts = new ArrayList<>();
pcerts.addAll(path.getCertPath().getCertificates());
if (path instanceof PKIXCertPathValidatorResult) {
@ -4842,6 +4865,18 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
}
args.putStringArrayList("trace", trace);
boolean valid = true;
for (Certificate pcert : pcerts)
try {
((X509Certificate) pcert).checkValidity(signingTime);
} catch (CertificateException ex) {
Log.w(ex);
valid = false;
break;
}
args.putBoolean("valid", valid);
} catch (Throwable ex) {
Log.w(ex);
@ -4990,11 +5025,6 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
protected void onExecuted(final Bundle args, X509Certificate cert) {
int type = args.getInt("type");
if (EntityMessage.SMIME_SIGNONLY.equals(type)) {
String sender = args.getString("sender");
boolean known = args.getBoolean("known");
boolean valid = args.getBoolean("valid");
final ArrayList<String> trace = args.getStringArrayList("trace");
if (cert == null) {
String message;
String reason = args.getString("reason");
@ -5005,8 +5035,16 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
Snackbar.make(view, message, Snackbar.LENGTH_LONG).show();
} else
try {
String sender = args.getString("sender");
Date time = (Date) args.getSerializable("time");
boolean known = args.getBoolean("known");
boolean valid = args.getBoolean("valid");
final ArrayList<String> trace = args.getStringArrayList("trace");
EntityCertificate record = EntityCertificate.from(cert, null);
if (time == null)
time = new Date();
boolean match = false;
List<String> emails = EntityCertificate.getAltSubjectName(cert);
for (String email : emails)
@ -5015,7 +5053,7 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
break;
}
if (known && !record.isExpired() && match && valid)
if (known && !record.isExpired(time) && match && valid)
Snackbar.make(view, R.string.title_signature_valid, Snackbar.LENGTH_LONG).show();
else {
LayoutInflater inflator = LayoutInflater.from(getContext());
@ -5038,7 +5076,7 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
DateFormat TF = Helper.getDateTimeInstance(getContext(), SimpleDateFormat.SHORT, SimpleDateFormat.SHORT);
tvAfter.setText(record.after == null ? null : TF.format(record.after));
tvBefore.setText(record.before == null ? null : TF.format(record.before));
tvExpired.setVisibility(record.isExpired() ? View.VISIBLE : View.GONE);
tvExpired.setVisibility(record.isExpired(time) ? View.VISIBLE : View.GONE);
if (trace != null && trace.size() > 0)
tvSubject.setOnClickListener(new View.OnClickListener() {