diff --git a/app/src/main/java/eu/faircode/email/FragmentCompose.java b/app/src/main/java/eu/faircode/email/FragmentCompose.java index 43ed7be1dd..a5a4b67aac 100644 --- a/app/src/main/java/eu/faircode/email/FragmentCompose.java +++ b/app/src/main/java/eu/faircode/email/FragmentCompose.java @@ -4388,6 +4388,7 @@ public class FragmentCompose extends FragmentBase { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); boolean check_certificate = prefs.getBoolean("check_certificate", true); + boolean check_key_usage = prefs.getBoolean("check_key_usage", false); File tmp = Helper.ensureExists(context, "encryption"); @@ -4455,8 +4456,30 @@ public class FragmentCompose extends FragmentBase { // Check public key validity try { chain[0].checkValidity(); - // TODO: check digitalSignature/nonRepudiation key usage - // https://datatracker.ietf.org/doc/html/rfc3850#section-4.4.2 + + if (check_key_usage) { + // Signing Key: Key Usage: Digital Signature, Non-Repudiation + // Encrypting Key: Key Usage: Key Encipherment, Data Encipherment + + boolean[] usage = chain[0].getKeyUsage(); + if (usage != null && usage.length > 3) { + // https://datatracker.ietf.org/doc/html/rfc3280#section-4.2.1.3 + // https://datatracker.ietf.org/doc/html/rfc3850#section-4.4.2 + boolean digitalSignature = usage[0]; + boolean keyEncipherment = usage[2]; + + if (EntityMessage.SMIME_SIGNONLY.equals(type)) { + if (!digitalSignature) + throw new IllegalAccessException("Invalid key usage:" + + " digitalSignature=" + digitalSignature); + } else if (EntityMessage.SMIME_SIGNENCRYPT.equals(type)) { + if (!digitalSignature || !keyEncipherment) + throw new IllegalAccessException("Invalid key usage:" + + " digitalSignature=" + digitalSignature + + " keyEncipherment=" + keyEncipherment); + } + } + } } catch (CertificateException ex) { String msg = ex.getMessage(); throw new IllegalArgumentException( diff --git a/app/src/main/java/eu/faircode/email/FragmentOptionsEncryption.java b/app/src/main/java/eu/faircode/email/FragmentOptionsEncryption.java index 9a0d0053c0..54852983de 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptionsEncryption.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptionsEncryption.java @@ -105,6 +105,7 @@ public class FragmentOptionsEncryption extends FragmentBase private Spinner spSignAlgoSmime; private Spinner spEncryptAlgoSmime; private SwitchCompat swCheckCertificate; + private SwitchCompat swCheckKeyUsage; private Button btnManageCertificates; private Button btnImportKey; private Button btnManageKeys; @@ -123,7 +124,7 @@ public class FragmentOptionsEncryption extends FragmentBase "sign_default", "encrypt_default", "encrypt_auto", "encrypt_reply", "auto_verify", "auto_decrypt", "auto_undecrypt", "openpgp_provider", "autocrypt", "autocrypt_mutual", "encrypt_subject", - "sign_algo_smime", "encrypt_algo_smime", "check_certificate" + "sign_algo_smime", "encrypt_algo_smime", "check_certificate", "check_key_usage" )); @Override @@ -159,6 +160,7 @@ public class FragmentOptionsEncryption extends FragmentBase spSignAlgoSmime = view.findViewById(R.id.spSignAlgoSmime); spEncryptAlgoSmime = view.findViewById(R.id.spEncryptAlgoSmime); swCheckCertificate = view.findViewById(R.id.swCheckCertificate); + swCheckKeyUsage = view.findViewById(R.id.swCheckKeyUsage); btnManageCertificates = view.findViewById(R.id.btnManageCertificates); btnImportKey = view.findViewById(R.id.btnImportKey); btnManageKeys = view.findViewById(R.id.btnManageKeys); @@ -395,6 +397,14 @@ public class FragmentOptionsEncryption extends FragmentBase @Override public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { prefs.edit().putBoolean("check_certificate", checked).apply(); + swCheckKeyUsage.setEnabled(checked); + } + }); + + swCheckKeyUsage.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { + prefs.edit().putBoolean("check_key_usage", checked).apply(); } }); @@ -709,6 +719,8 @@ public class FragmentOptionsEncryption extends FragmentBase } swCheckCertificate.setChecked(prefs.getBoolean("check_certificate", true)); + swCheckKeyUsage.setChecked(prefs.getBoolean("check_key_usage", false)); + swCheckKeyUsage.setEnabled(swCheckCertificate.isChecked()); } catch (Throwable ex) { Log.e(ex); } diff --git a/app/src/main/res/layout/fragment_options_encryption.xml b/app/src/main/res/layout/fragment_options_encryption.xml index 4378a65bb3..f9037588f2 100644 --- a/app/src/main/res/layout/fragment_options_encryption.xml +++ b/app/src/main/res/layout/fragment_options_encryption.xml @@ -421,6 +421,19 @@ app:layout_constraintTop_toBottomOf="@id/tvAlgoHint" app:switchPadding="12dp" /> + +