Skip to content

Commit

Permalink
Do not finalize forms with bad public keys (getodk#340)
Browse files Browse the repository at this point in the history
  • Loading branch information
grzesiek2010 authored and lognaturel committed Jan 26, 2017
1 parent c581d28 commit bf738af
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2588,6 +2588,11 @@ public void savingComplete(SaveResult saveResult) {
Toast.makeText(this, message,
Toast.LENGTH_LONG).show();
break;
case SaveToDiskTask.ENCRYPTION_ERROR:
Toast.makeText(this, String.format(getString(R.string.encryption_error_message),
saveResult.getSaveErrorMessage()), Toast.LENGTH_LONG).show();
finishReturnInstance();
break;
case FormEntryController.ANSWER_CONSTRAINT_VIOLATED:
case FormEntryController.ANSWER_REQUIRED_BUT_EMPTY:
refreshCurrentView();
Expand Down Expand Up @@ -2874,4 +2879,4 @@ public EmptyView(Context context) {
super(context);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public class SaveToDiskTask extends AsyncTask<Void, String, SaveResult> {
public static final int VALIDATE_ERROR = 502;
public static final int VALIDATED = 503;
public static final int SAVED_AND_EXIT = 504;
public static final int ENCRYPTION_ERROR = 505;


public SaveToDiskTask(Uri uri, Boolean saveAndExit, Boolean markCompleted, String updatedName) {
Expand Down Expand Up @@ -133,6 +134,9 @@ protected SaveResult doInBackground(Void... nothing) {
}

saveResult.setSaveResult(mSave ? SAVED_AND_EXIT : SAVED);
} catch (EncryptionException e) {
saveResult.setSaveErrorMessage(e.getMessage());
saveResult.setSaveResult(ENCRYPTION_ERROR);
} catch (Exception e) {
Log.e(t, e.getMessage(), e);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.kxml2.kdom.Document;
import org.kxml2.kdom.Element;
import org.kxml2.kdom.Node;
import org.odk.collect.android.R;
import org.odk.collect.android.application.Collect;
import org.odk.collect.android.exception.EncryptionException;
import org.odk.collect.android.logic.FormController.InstanceMetadata;
Expand Down Expand Up @@ -295,7 +296,7 @@ public boolean isNotBouncyCastle() {
* @param mUri either an instance URI (if previously saved) or a form URI
*/
public static EncryptedFormInformation getEncryptedFormInformation(Uri mUri,
InstanceMetadata instanceMetadata) {
InstanceMetadata instanceMetadata) throws EncryptionException {

ContentResolver cr = Collect.getInstance().getContentResolver();

Expand All @@ -315,8 +316,9 @@ public static EncryptedFormInformation getEncryptedFormInformation(Uri mUri,
try {
instanceCursor = cr.query(mUri, null, null, null, null);
if (instanceCursor.getCount() != 1) {
Log.e(t, "Not exactly one record for this instance!");
return null; // save unencrypted.
String msg = Collect.getInstance().getString(R.string.not_exactly_one_record_for_this_instance);
Log.e(t, msg);
throw new EncryptionException(msg, null);
}
instanceCursor.moveToFirst();
String jrFormId = instanceCursor.getString(
Expand All @@ -342,23 +344,26 @@ public static EncryptedFormInformation getEncryptedFormInformation(Uri mUri,
null);

if (formCursor.getCount() != 1) {
Log.e(t, "Not exactly one blank form matches this jr_form_id");
return null; // save unencrypted
String msg = Collect.getInstance().getString(R.string.not_exactly_one_blank_form_for_this_form_id);
Log.e(t, msg);
throw new EncryptionException(msg, null);
}
formCursor.moveToFirst();
} else if (cr.getType(mUri) == FormsColumns.CONTENT_ITEM_TYPE) {
formCursor = cr.query(mUri, null, null, null, null);
if (formCursor.getCount() != 1) {
Log.e(t, "Not exactly one blank form!");
return null; // save unencrypted.
String msg = Collect.getInstance().getString(R.string.not_exactly_one_blank_form_for_this_form_id);
Log.e(t, msg);
throw new EncryptionException(msg, null);
}
formCursor.moveToFirst();
}

formId = formCursor.getString(formCursor.getColumnIndex(FormsColumns.JR_FORM_ID));
if (formId == null || formId.length() == 0) {
Log.e(t, "No FormId specified???");
return null;
String msg = Collect.getInstance().getString(R.string.no_form_id_specified);
Log.e(t, msg);
throw new EncryptionException(msg, null);
}
int idxVersion = formCursor.getColumnIndex(FormsColumns.JR_VERSION);
int idxBase64RsaPublicKey = formCursor.getColumnIndex(
Expand All @@ -373,19 +378,21 @@ public static EncryptedFormInformation getEncryptedFormInformation(Uri mUri,

int version = android.os.Build.VERSION.SDK_INT;
if (version < 8) {
Log.e(t, "Phone does not support encryption.");
return null; // save unencrypted
String msg = Collect.getInstance().getString(R.string.phone_does_not_support_encryption);
Log.e(t, msg);
throw new EncryptionException(msg, null);
}

// this constructor will throw an exception if we are not
// running on version 8 or above (if Base64 is not found).
try {
wrapper = new Base64Wrapper();
} catch (ClassNotFoundException e) {
Log.e(t, "Phone does not have Base64 class but API level is "
+ version);
String msg = String.format(Collect.getInstance()
.getString(R.string.phone_does_not_have_base64_class), String.valueOf(version));
Log.e(t, msg);
e.printStackTrace();
return null; // save unencrypted
throw new EncryptionException(msg, e);
}

// OK -- Base64 decode (requires API Version 8 or higher)
Expand All @@ -395,16 +402,18 @@ public static EncryptedFormInformation getEncryptedFormInformation(Uri mUri,
try {
kf = KeyFactory.getInstance(RSA_ALGORITHM);
} catch (NoSuchAlgorithmException e) {
Log.e(t, "Phone does not support RSA encryption.");
String msg = Collect.getInstance().getString(R.string.phone_does_not_support_rsa);
Log.e(t, msg);
e.printStackTrace();
return null;
throw new EncryptionException(msg, e);
}
try {
pk = kf.generatePublic(publicKeySpec);
} catch (InvalidKeySpecException e) {
e.printStackTrace();
Log.e(t, "Invalid RSA public key.");
return null;
String msg = Collect.getInstance().getString(R.string.invalid_rsa_public_key);
Log.e(t, msg);
throw new EncryptionException(msg, e);
}
} finally {
if (formCursor != null) {
Expand Down
8 changes: 8 additions & 0 deletions collect_app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -434,4 +434,12 @@
<!-- %1$s represents degrees, %2$s represents minutes and %3$s represents seconds as in N 18°48'8" -->
<string name="north">N %1$s%2$s%3$s</string>
<string name="gdrive_connection_exception">This image is stored on Google Drive and cannot be accessed while you are offline.</string>
<string name="not_exactly_one_record_for_this_instance">Not exactly one record for this instance!</string>
<string name="not_exactly_one_blank_form_for_this_form_id">Not exactly one blank form matches this jr_form_id.</string>
<string name="no_form_id_specified">No FormId specified???</string>
<string name="phone_does_not_support_encryption">Phone does not support encryption.</string>
<string name="phone_does_not_have_base64_class">Phone does not have Base64 class but API level is %s.</string>
<string name="phone_does_not_support_rsa">Phone does not support RSA encryption.</string>
<string name="invalid_rsa_public_key">Invalid RSA public key.</string>
<string name="encryption_error_message">%s Form has not been saved as finalized.</string>
</resources>

0 comments on commit bf738af

Please sign in to comment.