Allow multiple alt subject names

pull/168/head
M66B 6 years ago
parent 060227e574
commit 79d6efdc4d

@ -1023,18 +1023,21 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac
CertificateFactory fact = CertificateFactory.getInstance("X.509"); CertificateFactory fact = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) fact.generateCertificate(bis); X509Certificate cert = (X509Certificate) fact.generateCertificate(bis);
String fingerprint = Helper.sha256(cert.getEncoded()); String fingerprint = Helper.getFingerprint(cert);
String email = Helper.getAltSubjectName(cert); List<String> emails = Helper.getAltSubjectName(cert);
String subject = Helper.getSubject(cert);
DB db = DB.getInstance(context); DB db = DB.getInstance(context);
EntityCertificate record = db.certificate().getCertificate(fingerprint, email); for (String email : emails) {
if (record == null) { EntityCertificate record = db.certificate().getCertificate(fingerprint, email);
record = new EntityCertificate(); if (record == null) {
record.fingerprint = fingerprint; record = new EntityCertificate();
record.email = email; record.fingerprint = fingerprint;
record.subject = Helper.getSubject(cert); record.email = email;
record.setEncoded(cert.getEncoded()); record.subject = subject;
record.id = db.certificate().insertCertificate(record); record.setEncoded(cert.getEncoded());
record.id = db.certificate().insertCertificate(record);
}
} }
return null; return null;

@ -141,6 +141,7 @@ import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.text.Collator; import java.text.Collator;
import java.text.DateFormat; import java.text.DateFormat;
@ -4340,9 +4341,9 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
} }
private void onSmime(Bundle args) { private void onSmime(Bundle args) {
new SimpleTask<Boolean>() { new SimpleTask<X509Certificate>() {
@Override @Override
protected Boolean onExecute(Context context, Bundle args) throws Throwable { protected X509Certificate onExecute(Context context, Bundle args) throws Throwable {
long id = args.getLong("id"); long id = args.getLong("id");
int type = args.getInt("type"); int type = args.getInt("type");
@ -4388,22 +4389,23 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
.getCertificate(certHolder); .getCertificate(certHolder);
try { try {
if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().build(cert))) { if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().build(cert))) {
String fingerprint = Helper.sha256(cert.getEncoded()); boolean known = true;
String email = Helper.getAltSubjectName(cert); String fingerprint = Helper.getFingerprint(cert);
EntityCertificate record = db.certificate().getCertificate(fingerprint, email); List<String> emails = Helper.getAltSubjectName(cert);
for (String email : emails) {
EntityCertificate record = db.certificate().getCertificate(fingerprint, email);
if (record == null)
known = false;
}
String sender = null; String sender = null;
if (message.from != null && message.from.length == 1) if (message.from != null && message.from.length == 1)
sender = ((InternetAddress) message.from[0]).getAddress(); sender = ((InternetAddress) message.from[0]).getAddress();
args.putString("sender", sender); args.putString("sender", sender);
args.putString("fingerprint", fingerprint); args.putBoolean("known", known);
args.putString("email", email);
args.putString("subject", Helper.getSubject(cert));
args.putByteArray("encoded", cert.getEncoded());
args.putBoolean("known", record != null);
return true; return cert;
} }
} catch (CMSVerifierCertificateNotValidException ex) { } catch (CMSVerifierCertificateNotValidException ex) {
Log.w(ex); Log.w(ex);
@ -4519,18 +4521,21 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
} }
@Override @Override
protected void onExecuted(final Bundle args, Boolean valid) { 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"); String sender = args.getString("sender");
String fingerprint = args.getString("fingerprint");
String email = args.getString("email");
String subject = args.getString("subject");
byte[] encoded = args.getByteArray("encoded");
boolean known = args.getBoolean("known"); boolean known = args.getBoolean("known");
boolean match = Objects.equals(sender, email);
if (valid == null || !valid) boolean match = false;
List<String> emails = (cert == null ? Collections.emptyList() : Helper.getAltSubjectName(cert));
for (String email : emails)
if (Objects.equals(sender, email)) {
match = true;
break;
}
if (cert == null)
Snackbar.make(view, R.string.title_signature_invalid, Snackbar.LENGTH_LONG).show(); Snackbar.make(view, R.string.title_signature_invalid, Snackbar.LENGTH_LONG).show();
else if (known && match) else if (known && match)
Snackbar.make(view, R.string.title_signature_valid, Snackbar.LENGTH_LONG).show(); Snackbar.make(view, R.string.title_signature_valid, Snackbar.LENGTH_LONG).show();
@ -4543,44 +4548,58 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
TextView tvSubject = dview.findViewById(R.id.tvSubject); TextView tvSubject = dview.findViewById(R.id.tvSubject);
tvSender.setText(sender); tvSender.setText(sender);
tvEmail.setText(email); tvEmail.setText(TextUtils.join(",", emails));
tvEmailInvalid.setVisibility(match ? View.GONE : View.VISIBLE); tvEmailInvalid.setVisibility(match ? View.GONE : View.VISIBLE);
tvSubject.setText(subject); tvSubject.setText(Helper.getSubject(cert));
AlertDialog.Builder builder = new AlertDialog.Builder(getContext()) AlertDialog.Builder builder = new AlertDialog.Builder(getContext())
.setView(dview) .setView(dview)
.setNegativeButton(android.R.string.cancel, null); .setNegativeButton(android.R.string.cancel, null);
if (!TextUtils.isEmpty(sender) && !known) if (!TextUtils.isEmpty(sender) && !known && emails.size() > 0)
builder.setPositiveButton(R.string.title_signature_store, new DialogInterface.OnClickListener() { builder.setPositiveButton(R.string.title_signature_store, new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
new SimpleTask<Void>() { try {
@Override args.putByteArray("encoded", cert.getEncoded());
protected Void onExecute(Context context, Bundle args) throws Throwable {
long id = args.getLong("id"); new SimpleTask<Void>() {
@Override
DB db = DB.getInstance(context); protected Void onExecute(Context context, Bundle args) throws Throwable {
long id = args.getLong("id");
byte[] encoded = args.getByteArray("encoded");
X509Certificate cert = (X509Certificate) CertificateFactory.getInstance("X.509")
.generateCertificate(new ByteArrayInputStream(encoded));
DB db = DB.getInstance(context);
EntityMessage message = db.message().getMessage(id);
if (message == null)
return null;
String fingerprint = Helper.getFingerprint(cert);
List<String> emails = Helper.getAltSubjectName(cert);
String subject = Helper.getSubject(cert);
for (String email : emails) {
EntityCertificate record = new EntityCertificate();
record.fingerprint = fingerprint;
record.email = email;
record.subject = subject;
record.setEncoded(encoded);
record.id = db.certificate().insertCertificate(record);
}
EntityMessage message = db.message().getMessage(id);
if (message == null)
return null; return null;
}
EntityCertificate record = new EntityCertificate(); @Override
record.fingerprint = fingerprint; protected void onException(Bundle args, Throwable ex) {
record.email = email; Helper.unexpectedError(getParentFragmentManager(), ex);
record.subject = subject; }
record.setEncoded(encoded); }.execute(FragmentMessages.this, args, "certificate:store");
record.id = db.certificate().insertCertificate(record); } catch (Throwable ex) {
Helper.unexpectedError(getParentFragmentManager(), ex);
return null; }
}
@Override
protected void onException(Bundle args, Throwable ex) {
Helper.unexpectedError(getParentFragmentManager(), ex);
}
}.execute(FragmentMessages.this, args, "certificate:store");
} }
}); });

@ -102,6 +102,7 @@ import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateParsingException; import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.text.DateFormat; import java.text.DateFormat;
@ -958,24 +959,29 @@ public class Helper {
prefs.edit().remove("last_authentication").apply(); prefs.edit().remove("last_authentication").apply();
} }
static String getFingerprint(X509Certificate certificate) throws CertificateEncodingException, NoSuchAlgorithmException {
return sha256(certificate.getEncoded());
}
static String getSubject(X509Certificate certificate) { static String getSubject(X509Certificate certificate) {
return certificate.getSubjectX500Principal().getName(X500Principal.RFC2253); return certificate.getSubjectX500Principal().getName(X500Principal.RFC2253);
} }
static String getAltSubjectName(X509Certificate certificate) { static List<String> getAltSubjectName(X509Certificate certificate) {
List<String> result = new ArrayList<>();
try { try {
Collection<List<?>> altNames = certificate.getSubjectAlternativeNames(); Collection<List<?>> altNames = certificate.getSubjectAlternativeNames();
if (altNames != null) if (altNames != null)
for (List altName : altNames) for (List altName : altNames)
if (altName.get(0).equals(GeneralName.rfc822Name)) if (altName.get(0).equals(GeneralName.rfc822Name))
return (String) altName.get(1); result.add((String) altName.get(1));
else else
Log.i("Alt type=" + altName.get(0) + " data=" + altName.get(1)); Log.i("Alt type=" + altName.get(0) + " data=" + altName.get(1));
} catch (CertificateParsingException ex) { } catch (CertificateParsingException ex) {
Log.w(ex); Log.w(ex);
} }
return "?"; return result;
} }
static void selectKeyAlias(final Activity activity, final String email, final IKeyAlias intf) { static void selectKeyAlias(final Activity activity, final String email, final IKeyAlias intf) {

Loading…
Cancel
Save