mirror of https://github.com/M66B/FairEmail.git
Store intermediate certificates
This commit is contained in:
parent
ff08ec5667
commit
8fb2409e36
File diff suppressed because it is too large
Load Diff
|
@ -30,6 +30,7 @@ import android.view.Menu;
|
|||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
@ -57,6 +58,7 @@ public class AdapterCertificate extends RecyclerView.Adapter<AdapterCertificate.
|
|||
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnLongClickListener {
|
||||
private View view;
|
||||
private TextView tvEmail;
|
||||
private ImageView ivIntermediate;
|
||||
private TextView tvSubject;
|
||||
private TextView tvAfter;
|
||||
private TextView tvBefore;
|
||||
|
@ -69,6 +71,7 @@ public class AdapterCertificate extends RecyclerView.Adapter<AdapterCertificate.
|
|||
|
||||
view = itemView.findViewById(R.id.clItem);
|
||||
tvEmail = itemView.findViewById(R.id.tvEmail);
|
||||
ivIntermediate = itemView.findViewById(R.id.ivIntermediate);
|
||||
tvSubject = itemView.findViewById(R.id.tvSubject);
|
||||
tvAfter = itemView.findViewById(R.id.tvAfter);
|
||||
tvBefore = itemView.findViewById(R.id.tvBefore);
|
||||
|
@ -143,6 +146,7 @@ public class AdapterCertificate extends RecyclerView.Adapter<AdapterCertificate.
|
|||
|
||||
private void bindTo(EntityCertificate certificate) {
|
||||
tvEmail.setText(certificate.email);
|
||||
ivIntermediate.setVisibility(certificate.intermediate ? View.VISIBLE : View.INVISIBLE);
|
||||
tvSubject.setText(certificate.subject);
|
||||
tvAfter.setText(certificate.after == null ? null : TF.format(certificate.after));
|
||||
tvBefore.setText(certificate.before == null ? null : TF.format(certificate.before));
|
||||
|
|
|
@ -60,7 +60,7 @@ import io.requery.android.database.sqlite.SQLiteDatabase;
|
|||
// https://developer.android.com/topic/libraries/architecture/room.html
|
||||
|
||||
@Database(
|
||||
version = 135,
|
||||
version = 136,
|
||||
entities = {
|
||||
EntityIdentity.class,
|
||||
EntityAccount.class,
|
||||
|
@ -1321,6 +1321,13 @@ public abstract class DB extends RoomDatabase {
|
|||
db.execSQL("CREATE VIEW IF NOT EXISTS `identity_view` AS " + TupleIdentityView.query);
|
||||
db.execSQL("CREATE VIEW IF NOT EXISTS `folder_view` AS " + TupleFolderView.query);
|
||||
}
|
||||
})
|
||||
.addMigrations(new Migration(135, 136) {
|
||||
@Override
|
||||
public void migrate(@NonNull SupportSQLiteDatabase db) {
|
||||
Log.i("DB migration from version " + startVersion + " to " + endVersion);
|
||||
db.execSQL("ALTER TABLE `certificate` ADD COLUMN `intermediate` INTEGER NOT NULL DEFAULT 0");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ public interface DaoCertificate {
|
|||
List<EntityCertificate> getCertificates();
|
||||
|
||||
@Query("SELECT * FROM certificate" +
|
||||
" ORDER BY email, subject")
|
||||
" ORDER BY intermediate, email, subject")
|
||||
LiveData<List<EntityCertificate>> liveCertificates();
|
||||
|
||||
@Query("SELECT * FROM certificate" +
|
||||
|
@ -44,6 +44,10 @@ public interface DaoCertificate {
|
|||
" WHERE email = :email COLLATE NOCASE")
|
||||
List<EntityCertificate> getCertificateByEmail(String email);
|
||||
|
||||
@Query("SELECT * FROM certificate" +
|
||||
" WHERE intermediate")
|
||||
List<EntityCertificate> getIntermediateCertificate();
|
||||
|
||||
@Insert
|
||||
long insertCertificate(EntityCertificate certificate);
|
||||
|
||||
|
|
|
@ -62,6 +62,8 @@ public class EntityCertificate {
|
|||
@NonNull
|
||||
public String fingerprint;
|
||||
@NonNull
|
||||
public boolean intermediate;
|
||||
@NonNull
|
||||
public String email;
|
||||
public String subject;
|
||||
public Long after;
|
||||
|
@ -70,8 +72,13 @@ public class EntityCertificate {
|
|||
public String data;
|
||||
|
||||
static EntityCertificate from(X509Certificate certificate, String email) throws CertificateEncodingException, NoSuchAlgorithmException {
|
||||
return from(certificate, false, email);
|
||||
}
|
||||
|
||||
static EntityCertificate from(X509Certificate certificate, boolean intermediate, String email) throws CertificateEncodingException, NoSuchAlgorithmException {
|
||||
EntityCertificate record = new EntityCertificate();
|
||||
record.fingerprint = getFingerprint(certificate);
|
||||
record.intermediate = intermediate;
|
||||
record.email = email;
|
||||
record.subject = getSubject(certificate);
|
||||
|
||||
|
@ -131,6 +138,7 @@ public class EntityCertificate {
|
|||
public JSONObject toJSON() throws JSONException {
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("id", id);
|
||||
json.put("intermediate", intermediate);
|
||||
json.put("email", email);
|
||||
json.put("data", data);
|
||||
return json;
|
||||
|
@ -139,6 +147,7 @@ public class EntityCertificate {
|
|||
public static EntityCertificate fromJSON(JSONObject json) throws JSONException, CertificateException, NoSuchAlgorithmException {
|
||||
EntityCertificate certificate = new EntityCertificate();
|
||||
certificate.id = json.getLong("id");
|
||||
certificate.intermediate = json.optBoolean("intermediate");
|
||||
certificate.email = json.getString("email");
|
||||
certificate.data = json.getString("data");
|
||||
|
||||
|
@ -160,9 +169,9 @@ public class EntityCertificate {
|
|||
if (obj instanceof EntityCertificate) {
|
||||
EntityCertificate other = (EntityCertificate) obj;
|
||||
return (this.fingerprint.equals(other.fingerprint) &&
|
||||
this.intermediate == other.intermediate &&
|
||||
Objects.equals(this.email, other.email) &&
|
||||
Objects.equals(this.subject, other.subject) &&
|
||||
this.data.equals(other.data));
|
||||
Objects.equals(this.subject, other.subject));
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -4835,8 +4835,43 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
|
|||
X509CertSelector target = new X509CertSelector();
|
||||
target.setCertificate(cert);
|
||||
|
||||
// Load/store intermediate certificates
|
||||
List<X509Certificate> local = new ArrayList<>();
|
||||
|
||||
try {
|
||||
List<EntityCertificate> ecs = db.certificate().getIntermediateCertificate();
|
||||
for (EntityCertificate ec : ecs)
|
||||
local.add(ec.getCertificate());
|
||||
|
||||
for (X509Certificate c : certs) {
|
||||
boolean[] usage = c.getKeyUsage();
|
||||
boolean root = (usage != null && usage[5]);
|
||||
if (root) {
|
||||
boolean found = false;
|
||||
String issuer = (c.getIssuerDN() == null ? "" : c.getIssuerDN().getName());
|
||||
EntityCertificate record = EntityCertificate.from(c, true, issuer);
|
||||
for (EntityCertificate ec : ecs)
|
||||
if (ec.fingerprint.equals(record.fingerprint)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
Log.i("Storing certificate subject=" + record.subject);
|
||||
local.add(record.getCertificate());
|
||||
db.certificate().insertCertificate(record);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
Log.e(ex);
|
||||
local = certs;
|
||||
}
|
||||
|
||||
// Intermediate certificates
|
||||
Log.i("Intermediate certificates=" + local.size());
|
||||
PKIXBuilderParameters params = new PKIXBuilderParameters(ks, target);
|
||||
CertStoreParameters intermediates = new CollectionCertStoreParameters(certs);
|
||||
CertStoreParameters intermediates = new CollectionCertStoreParameters(local);
|
||||
params.addCertStore(CertStore.getInstance("Collection", intermediates));
|
||||
params.setRevocationEnabled(false);
|
||||
params.setDate(signingTime);
|
||||
|
|
|
@ -18,10 +18,25 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:text="test@example.com"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/ivIntermediate"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivIntermediate"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/baseline_security_24" />
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/barrier"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:barrierDirection="bottom"
|
||||
app:constraint_referenced_ids="tvEmail,ivIntermediate" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvSubject"
|
||||
android:layout_width="0dp"
|
||||
|
@ -30,7 +45,7 @@
|
|||
android:textAppearance="@android:style/TextAppearance.Small"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tvEmail" />
|
||||
app:layout_constraintTop_toBottomOf="@+id/barrier" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvAfter"
|
||||
|
|
Loading…
Reference in New Issue