S/MIME Skip checking sign time

The certificate chain will be checked separately
pull/172/head
M66B 6 years ago
parent a36c6b3684
commit 34a3b88b49

@ -93,7 +93,13 @@ public class EntityCertificate {
} }
boolean isExpired() { 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)); return ((this.after != null && now <= this.after) || (this.before != null && now > this.before));
} }

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

Loading…
Cancel
Save