yubikey certifications!

This commit is contained in:
Vincent Breitmoser
2015-03-18 21:12:31 +01:00
parent aca54e31ea
commit d46fc3740b
15 changed files with 476 additions and 241 deletions

View File

@@ -56,7 +56,7 @@ import org.sufficientlysecure.keychain.service.CertifyActionsParcel;
import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.ui.adapter.MultiUserIdsAdapter;
import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.ui.widget.CertifyKeySpinner;
@@ -66,14 +66,11 @@ import org.sufficientlysecure.keychain.util.Preferences;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
public class CertifyKeyFragment extends LoaderFragment
public class CertifyKeyFragment extends CryptoOperationFragment
implements LoaderManager.LoaderCallbacks<Cursor> {
public static final int REQUEST_CODE_PASSPHRASE = 0x00008001;
private CheckBox mUploadKeyCheckbox;
ListView mUserIds;
@@ -102,9 +99,6 @@ public class CertifyKeyFragment extends LoaderFragment
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Start out with a progress indicator.
setContentShown(false);
mPubMasterKeyIds = getActivity().getIntent().getLongArrayExtra(CertifyKeyActivity.EXTRA_KEY_IDS);
if (mPubMasterKeyIds == null) {
Log.e(Constants.TAG, "List of key ids to certify missing!");
@@ -114,6 +108,7 @@ public class CertifyKeyFragment extends LoaderFragment
mPassthroughMessenger = getActivity().getIntent().getParcelableExtra(
KeychainIntentService.EXTRA_MESSENGER);
mPassthroughMessenger = null; // TODO remove, development hack
// preselect certify key id if given
long certifyKeyId = getActivity().getIntent().getLongExtra(CertifyKeyActivity.EXTRA_CERTIFY_KEY_ID, Constants.key.none);
@@ -143,9 +138,7 @@ public class CertifyKeyFragment extends LoaderFragment
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) {
View root = super.onCreateView(inflater, superContainer, savedInstanceState);
View view = inflater.inflate(R.layout.certify_key_fragment, getContainer());
View view = inflater.inflate(R.layout.certify_key_fragment, null);
mCertifyKeySpinner = (CertifyKeySpinner) view.findViewById(R.id.certify_key_spinner);
mUploadKeyCheckbox = (CheckBox) view.findViewById(R.id.sign_key_upload_checkbox);
@@ -173,7 +166,7 @@ public class CertifyKeyFragment extends LoaderFragment
Notify.showNotify(getActivity(), getString(R.string.select_key_to_certify),
Notify.Style.ERROR);
} else {
initiateCertifying();
cryptoOperation();
}
}
});
@@ -183,7 +176,7 @@ public class CertifyKeyFragment extends LoaderFragment
mUploadKeyCheckbox.setChecked(false);
}
return root;
return view;
}
@Override
@@ -307,7 +300,6 @@ public class CertifyKeyFragment extends LoaderFragment
}
mUserIdsAdapter.swapCursor(matrix);
setContentShown(true, isResumed());
}
@Override
@@ -315,50 +307,17 @@ public class CertifyKeyFragment extends LoaderFragment
mUserIdsAdapter.swapCursor(null);
}
/**
* handles the UI bits of the signing process on the UI thread
*/
private void initiateCertifying() {
// get the user's passphrase for this key (if required)
String passphrase;
try {
passphrase = PassphraseCacheService.getCachedPassphrase(getActivity(), mSignMasterKeyId, mSignMasterKeyId);
} catch (PassphraseCacheService.KeyNotFoundException e) {
Log.e(Constants.TAG, "Key not found!", e);
getActivity().finish();
return;
}
if (passphrase == null) {
Intent intent = new Intent(getActivity(), PassphraseDialogActivity.class);
intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, mSignMasterKeyId);
startActivityForResult(intent, REQUEST_CODE_PASSPHRASE);
// bail out; need to wait until the user has entered the passphrase before trying again
} else {
startCertifying();
}
protected void cryptoOperation() {
cryptoOperation((CryptoInputParcel) null);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CODE_PASSPHRASE: {
if (resultCode == Activity.RESULT_OK && data != null) {
String passphrase = data.getStringExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE);
startCertifying();
}
return;
}
default: {
super.onActivityResult(requestCode, resultCode, data);
}
}
protected void cryptoOperation(String passphrase) {
cryptoOperation((CryptoInputParcel) null);
}
/**
* kicks off the actual signing process on a background thread
*/
private void startCertifying() {
@Override
protected void cryptoOperation(CryptoInputParcel cryptoInput) {
// Bail out if there is not at least one user id selected
ArrayList<CertifyAction> certifyActions = mUserIdsAdapter.getSelectedCertifyActions();
if (certifyActions.isEmpty()) {
@@ -370,7 +329,7 @@ public class CertifyKeyFragment extends LoaderFragment
Bundle data = new Bundle();
{
// fill values for this action
CertifyActionsParcel parcel = new CertifyActionsParcel(new Date(), mSignMasterKeyId);
CertifyActionsParcel parcel = new CertifyActionsParcel(cryptoInput, mSignMasterKeyId);
parcel.mCertifyActions.addAll(certifyActions);
data.putParcelable(KeychainIntentService.CERTIFY_PARCEL, parcel);
@@ -390,14 +349,21 @@ public class CertifyKeyFragment extends LoaderFragment
} else {
// Message is received after signing is done in KeychainIntentService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity(),
getString(R.string.progress_certifying), ProgressDialog.STYLE_SPINNER, true) {
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
getActivity(), getString(R.string.progress_certifying),
ProgressDialog.STYLE_SPINNER, true) {
public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first
// handle messages by KeychainIntentCryptoServiceHandler first
super.handleMessage(message);
// handle pending messages
if (handlePendingMessage(message)) {
return;
}
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
Bundle data = message.getData();
CertifyResult result = data.getParcelable(CertifyResult.EXTRA_RESULT);
Intent intent = new Intent();

View File

@@ -0,0 +1,89 @@
package org.sufficientlysecure.keychain.ui;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Message;
import android.support.v4.app.Fragment;
import org.sufficientlysecure.keychain.operations.results.CertifyResult;
import org.sufficientlysecure.keychain.operations.results.InputPendingResult;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler.MessageStatus;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.NfcOperationsParcel;
public abstract class CryptoOperationFragment extends Fragment {
public static final int REQUEST_CODE_PASSPHRASE = 0x00008001;
public static final int REQUEST_CODE_NFC = 0x00008002;
private void startPassphraseDialog(long subkeyId) {
Intent intent = new Intent(getActivity(), PassphraseDialogActivity.class);
intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, subkeyId);
startActivityForResult(intent, REQUEST_CODE_PASSPHRASE);
}
private void initiateNfcInput(NfcOperationsParcel nfcOps) {
Intent intent = new Intent(getActivity(), NfcOperationActivity.class);
intent.putExtra(NfcOperationActivity.EXTRA_PIN, "123456");
intent.putExtra(NfcOperationActivity.EXTRA_NFC_OPS, nfcOps);
startActivityForResult(intent, REQUEST_CODE_NFC);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CODE_PASSPHRASE: {
if (resultCode == Activity.RESULT_OK && data != null) {
String passphrase = data.getStringExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE);
cryptoOperation(passphrase);
}
return;
}
case REQUEST_CODE_NFC: {
if (resultCode == Activity.RESULT_OK && data != null) {
CryptoInputParcel cryptoInput =
data.getParcelableExtra(NfcOperationActivity.RESULT_DATA);
cryptoOperation(cryptoInput);
return;
}
break;
}
default: {
super.onActivityResult(requestCode, resultCode, data);
}
}
}
public boolean handlePendingMessage(Message message) {
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
Bundle data = message.getData();
InputPendingResult result = data.getParcelable(CertifyResult.EXTRA_RESULT);
if (result != null && result.isPending()) {
if (result.isPassphrasePending()) {
startPassphraseDialog(result.getPassphraseKeyId());
return true;
} else if (result.isNfcPending()) {
NfcOperationsParcel requiredInput = result.getNfcOperationsParcel();
initiateNfcInput(requiredInput);
return true;
} else {
throw new RuntimeException("Unhandled pending result!");
}
}
}
return false;
}
protected abstract void cryptoOperation(CryptoInputParcel cryptoInput);
protected abstract void cryptoOperation(String passphrase);
}

View File

@@ -182,17 +182,17 @@ public class NfcOperationActivity extends BaseActivity {
case NFC_DECRYPT:
for (int i = 0; i < mNfcOperations.mInputHash.length; i++) {
byte[] hash = mNfcOperations.mInputHash[i];
for (int i = 0; i < mNfcOperations.mInputHashes.length; i++) {
byte[] hash = mNfcOperations.mInputHashes[i];
byte[] decryptedSessionKey = nfcDecryptSessionKey(hash);
resultData.addCryptoData(hash, decryptedSessionKey);
}
break;
case NFC_SIGN:
for (int i = 0; i < mNfcOperations.mInputHash.length; i++) {
byte[] hash = mNfcOperations.mInputHash[i];
int algo = mNfcOperations.mSignAlgo[i];
for (int i = 0; i < mNfcOperations.mInputHashes.length; i++) {
byte[] hash = mNfcOperations.mInputHashes[i];
int algo = mNfcOperations.mSignAlgos[i];
byte[] signedHash = nfcCalculateSignature(hash, algo);
resultData.addCryptoData(hash, signedHash);
}