Close FileDescriptors and input, output streams when possible
This commit is contained in:
@@ -55,6 +55,7 @@ import org.sufficientlysecure.keychain.ui.ViewKeyActivity;
|
|||||||
import org.sufficientlysecure.keychain.util.InputData;
|
import org.sufficientlysecure.keychain.util.InputData;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -224,6 +225,8 @@ public class OpenPgpService extends RemoteService {
|
|||||||
private Intent signImpl(Intent data, ParcelFileDescriptor input,
|
private Intent signImpl(Intent data, ParcelFileDescriptor input,
|
||||||
ParcelFileDescriptor output, AccountSettings accSettings,
|
ParcelFileDescriptor output, AccountSettings accSettings,
|
||||||
boolean cleartextSign) {
|
boolean cleartextSign) {
|
||||||
|
InputStream is = null;
|
||||||
|
OutputStream os = null;
|
||||||
try {
|
try {
|
||||||
boolean asciiArmor = cleartextSign || data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
|
boolean asciiArmor = cleartextSign || data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
|
||||||
|
|
||||||
@@ -243,96 +246,88 @@ public class OpenPgpService extends RemoteService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get Input- and OutputStream from ParcelFileDescriptor
|
// Get Input- and OutputStream from ParcelFileDescriptor
|
||||||
InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input);
|
is = new ParcelFileDescriptor.AutoCloseInputStream(input);
|
||||||
OutputStream os = null;
|
|
||||||
if (cleartextSign) {
|
if (cleartextSign) {
|
||||||
// output stream only needed for cleartext signatures,
|
// output stream only needed for cleartext signatures,
|
||||||
// detached signatures are returned as extra
|
// detached signatures are returned as extra
|
||||||
os = new ParcelFileDescriptor.AutoCloseOutputStream(output);
|
os = new ParcelFileDescriptor.AutoCloseOutputStream(output);
|
||||||
}
|
}
|
||||||
try {
|
long inputLength = is.available();
|
||||||
long inputLength = is.available();
|
InputData inputData = new InputData(is, inputLength);
|
||||||
InputData inputData = new InputData(is, inputLength);
|
|
||||||
|
|
||||||
// Find the appropriate subkey to sign with
|
// Find the appropriate subkey to sign with
|
||||||
long sigSubKeyId;
|
long sigSubKeyId;
|
||||||
|
try {
|
||||||
|
CachedPublicKeyRing signingRing =
|
||||||
|
new ProviderHelper(this).getCachedPublicKeyRing(accSettings.getKeyId());
|
||||||
|
sigSubKeyId = signingRing.getSecretSignId();
|
||||||
|
} catch (PgpKeyNotFoundException e) {
|
||||||
|
// secret key that is set for this account is deleted?
|
||||||
|
// show account config again!
|
||||||
|
return getCreateAccountIntent(data, getAccountName(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
// get passphrase from cache, if key has "no" passphrase, this returns an empty String
|
||||||
|
String passphrase;
|
||||||
|
if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) {
|
||||||
|
passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
|
||||||
|
} else {
|
||||||
try {
|
try {
|
||||||
CachedPublicKeyRing signingRing =
|
passphrase = PassphraseCacheService.getCachedPassphrase(getContext(),
|
||||||
new ProviderHelper(this).getCachedPublicKeyRing(accSettings.getKeyId());
|
accSettings.getKeyId(), sigSubKeyId);
|
||||||
sigSubKeyId = signingRing.getSecretSignId();
|
} catch (PassphraseCacheService.KeyNotFoundException e) {
|
||||||
} catch (PgpKeyNotFoundException e) {
|
// should happen earlier, but return again here if it happens
|
||||||
// secret key that is set for this account is deleted?
|
|
||||||
// show account config again!
|
|
||||||
return getCreateAccountIntent(data, getAccountName(data));
|
return getCreateAccountIntent(data, getAccountName(data));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (passphrase == null) {
|
||||||
|
// get PendingIntent for passphrase input, add it to given params and return to client
|
||||||
|
return getPassphraseIntent(data, sigSubKeyId);
|
||||||
|
}
|
||||||
|
|
||||||
// get passphrase from cache, if key has "no" passphrase, this returns an empty String
|
// sign-only
|
||||||
String passphrase;
|
PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(
|
||||||
if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) {
|
this, new ProviderHelper(getContext()), null,
|
||||||
passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
|
inputData, os
|
||||||
|
);
|
||||||
|
builder.setEnableAsciiArmorOutput(asciiArmor)
|
||||||
|
.setCleartextSignature(cleartextSign)
|
||||||
|
.setDetachedSignature(!cleartextSign)
|
||||||
|
.setVersionHeader(PgpHelper.getVersionForHeader(this))
|
||||||
|
.setSignatureHashAlgorithm(accSettings.getHashAlgorithm())
|
||||||
|
.setSignatureMasterKeyId(accSettings.getKeyId())
|
||||||
|
.setSignatureSubKeyId(sigSubKeyId)
|
||||||
|
.setSignaturePassphrase(passphrase)
|
||||||
|
.setNfcState(nfcSignedHash, nfcCreationDate);
|
||||||
|
|
||||||
|
// execute PGP operation!
|
||||||
|
SignEncryptResult pgpResult = builder.build().execute();
|
||||||
|
|
||||||
|
if (pgpResult.isPending()) {
|
||||||
|
if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_PASSPHRASE) ==
|
||||||
|
SignEncryptResult.RESULT_PENDING_PASSPHRASE) {
|
||||||
|
return getPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded());
|
||||||
|
} else if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_NFC) ==
|
||||||
|
SignEncryptResult.RESULT_PENDING_NFC) {
|
||||||
|
// return PendingIntent to execute NFC activity
|
||||||
|
// pass through the signature creation timestamp to be used again on second execution
|
||||||
|
// of PgpSignEncrypt when we have the signed hash!
|
||||||
|
data.putExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, pgpResult.getNfcTimestamp().getTime());
|
||||||
|
return getNfcSignIntent(data, pgpResult.getNfcKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcHash(), pgpResult.getNfcAlgo());
|
||||||
} else {
|
} else {
|
||||||
try {
|
throw new PgpGeneralException(
|
||||||
passphrase = PassphraseCacheService.getCachedPassphrase(getContext(),
|
"Encountered unhandled type of pending action not supported by API!");
|
||||||
accSettings.getKeyId(), sigSubKeyId);
|
|
||||||
} catch (PassphraseCacheService.KeyNotFoundException e) {
|
|
||||||
// should happen earlier, but return again here if it happens
|
|
||||||
return getCreateAccountIntent(data, getAccountName(data));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (passphrase == null) {
|
} else if (pgpResult.success()) {
|
||||||
// get PendingIntent for passphrase input, add it to given params and return to client
|
Intent result = new Intent();
|
||||||
return getPassphraseIntent(data, sigSubKeyId);
|
if (!cleartextSign) {
|
||||||
}
|
result.putExtra(OpenPgpApi.RESULT_DETACHED_SIGNATURE, pgpResult.getDetachedSignature());
|
||||||
|
|
||||||
// sign-only
|
|
||||||
PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(
|
|
||||||
this, new ProviderHelper(getContext()), null,
|
|
||||||
inputData, os
|
|
||||||
);
|
|
||||||
builder.setEnableAsciiArmorOutput(asciiArmor)
|
|
||||||
.setCleartextSignature(cleartextSign)
|
|
||||||
.setDetachedSignature(!cleartextSign)
|
|
||||||
.setVersionHeader(PgpHelper.getVersionForHeader(this))
|
|
||||||
.setSignatureHashAlgorithm(accSettings.getHashAlgorithm())
|
|
||||||
.setSignatureMasterKeyId(accSettings.getKeyId())
|
|
||||||
.setSignatureSubKeyId(sigSubKeyId)
|
|
||||||
.setSignaturePassphrase(passphrase)
|
|
||||||
.setNfcState(nfcSignedHash, nfcCreationDate);
|
|
||||||
|
|
||||||
// execute PGP operation!
|
|
||||||
SignEncryptResult pgpResult = builder.build().execute();
|
|
||||||
|
|
||||||
if (pgpResult.isPending()) {
|
|
||||||
if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_PASSPHRASE) ==
|
|
||||||
SignEncryptResult.RESULT_PENDING_PASSPHRASE) {
|
|
||||||
return getPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded());
|
|
||||||
} else if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_NFC) ==
|
|
||||||
SignEncryptResult.RESULT_PENDING_NFC) {
|
|
||||||
// return PendingIntent to execute NFC activity
|
|
||||||
// pass through the signature creation timestamp to be used again on second execution
|
|
||||||
// of PgpSignEncrypt when we have the signed hash!
|
|
||||||
data.putExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, pgpResult.getNfcTimestamp().getTime());
|
|
||||||
return getNfcSignIntent(data, pgpResult.getNfcKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcHash(), pgpResult.getNfcAlgo());
|
|
||||||
} else {
|
|
||||||
throw new PgpGeneralException(
|
|
||||||
"Encountered unhandled type of pending action not supported by API!");
|
|
||||||
}
|
|
||||||
} else if (pgpResult.success()) {
|
|
||||||
Intent result = new Intent();
|
|
||||||
if (!cleartextSign) {
|
|
||||||
result.putExtra(OpenPgpApi.RESULT_DETACHED_SIGNATURE, pgpResult.getDetachedSignature());
|
|
||||||
}
|
|
||||||
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
|
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
LogEntryParcel errorMsg = pgpResult.getLog().getLast();
|
|
||||||
throw new Exception(getString(errorMsg.mType.getMsgId()));
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
is.close();
|
|
||||||
if (os != null) {
|
|
||||||
os.close();
|
|
||||||
}
|
}
|
||||||
|
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
LogEntryParcel errorMsg = pgpResult.getLog().getLast();
|
||||||
|
throw new Exception(getString(errorMsg.mType.getMsgId()));
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.d(Constants.TAG, "signImpl", e);
|
Log.d(Constants.TAG, "signImpl", e);
|
||||||
@@ -341,12 +336,29 @@ public class OpenPgpService extends RemoteService {
|
|||||||
new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
|
new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
|
||||||
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
|
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
|
||||||
return result;
|
return result;
|
||||||
|
} finally {
|
||||||
|
if (is != null) {
|
||||||
|
try {
|
||||||
|
is.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(Constants.TAG, "IOException when closing InputStream", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (os != null) {
|
||||||
|
try {
|
||||||
|
os.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(Constants.TAG, "IOException when closing OutputStream", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Intent encryptAndSignImpl(Intent data, ParcelFileDescriptor input,
|
private Intent encryptAndSignImpl(Intent data, ParcelFileDescriptor input,
|
||||||
ParcelFileDescriptor output, AccountSettings accSettings,
|
ParcelFileDescriptor output, AccountSettings accSettings,
|
||||||
boolean sign) {
|
boolean sign) {
|
||||||
|
InputStream is = null;
|
||||||
|
OutputStream os = null;
|
||||||
try {
|
try {
|
||||||
boolean asciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
|
boolean asciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
|
||||||
String originalFilename = data.getStringExtra(OpenPgpApi.EXTRA_ORIGINAL_FILENAME);
|
String originalFilename = data.getStringExtra(OpenPgpApi.EXTRA_ORIGINAL_FILENAME);
|
||||||
@@ -372,96 +384,91 @@ public class OpenPgpService extends RemoteService {
|
|||||||
|
|
||||||
// build InputData and write into OutputStream
|
// build InputData and write into OutputStream
|
||||||
// Get Input- and OutputStream from ParcelFileDescriptor
|
// Get Input- and OutputStream from ParcelFileDescriptor
|
||||||
InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input);
|
is = new ParcelFileDescriptor.AutoCloseInputStream(input);
|
||||||
OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output);
|
os = new ParcelFileDescriptor.AutoCloseOutputStream(output);
|
||||||
try {
|
|
||||||
long inputLength = is.available();
|
|
||||||
InputData inputData = new InputData(is, inputLength);
|
|
||||||
|
|
||||||
PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(
|
long inputLength = is.available();
|
||||||
this, new ProviderHelper(getContext()), null, inputData, os
|
InputData inputData = new InputData(is, inputLength);
|
||||||
);
|
|
||||||
builder.setEnableAsciiArmorOutput(asciiArmor)
|
|
||||||
.setVersionHeader(PgpHelper.getVersionForHeader(this))
|
|
||||||
.setCompressionId(accSettings.getCompression())
|
|
||||||
.setSymmetricEncryptionAlgorithm(accSettings.getEncryptionAlgorithm())
|
|
||||||
.setEncryptionMasterKeyIds(keyIds)
|
|
||||||
.setFailOnMissingEncryptionKeyIds(true)
|
|
||||||
.setOriginalFilename(originalFilename)
|
|
||||||
.setAdditionalEncryptId(accSettings.getKeyId()); // add acc key for encryption
|
|
||||||
|
|
||||||
if (sign) {
|
PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(
|
||||||
|
this, new ProviderHelper(getContext()), null, inputData, os
|
||||||
|
);
|
||||||
|
builder.setEnableAsciiArmorOutput(asciiArmor)
|
||||||
|
.setVersionHeader(PgpHelper.getVersionForHeader(this))
|
||||||
|
.setCompressionId(accSettings.getCompression())
|
||||||
|
.setSymmetricEncryptionAlgorithm(accSettings.getEncryptionAlgorithm())
|
||||||
|
.setEncryptionMasterKeyIds(keyIds)
|
||||||
|
.setFailOnMissingEncryptionKeyIds(true)
|
||||||
|
.setOriginalFilename(originalFilename)
|
||||||
|
.setAdditionalEncryptId(accSettings.getKeyId()); // add acc key for encryption
|
||||||
|
|
||||||
// Find the appropriate subkey to sign with
|
if (sign) {
|
||||||
long sigSubKeyId;
|
|
||||||
try {
|
|
||||||
CachedPublicKeyRing signingRing =
|
|
||||||
new ProviderHelper(this).getCachedPublicKeyRing(accSettings.getKeyId());
|
|
||||||
sigSubKeyId = signingRing.getSecretSignId();
|
|
||||||
} catch (PgpKeyNotFoundException e) {
|
|
||||||
// secret key that is set for this account is deleted?
|
|
||||||
// show account config again!
|
|
||||||
return getCreateAccountIntent(data, getAccountName(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
String passphrase;
|
// Find the appropriate subkey to sign with
|
||||||
if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) {
|
long sigSubKeyId;
|
||||||
passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
|
try {
|
||||||
} else {
|
CachedPublicKeyRing signingRing =
|
||||||
passphrase = PassphraseCacheService.getCachedPassphrase(getContext(),
|
new ProviderHelper(this).getCachedPublicKeyRing(accSettings.getKeyId());
|
||||||
accSettings.getKeyId(), sigSubKeyId);
|
sigSubKeyId = signingRing.getSecretSignId();
|
||||||
}
|
} catch (PgpKeyNotFoundException e) {
|
||||||
if (passphrase == null) {
|
// secret key that is set for this account is deleted?
|
||||||
// get PendingIntent for passphrase input, add it to given params and return to client
|
// show account config again!
|
||||||
return getPassphraseIntent(data, sigSubKeyId);
|
return getCreateAccountIntent(data, getAccountName(data));
|
||||||
}
|
|
||||||
|
|
||||||
byte[] nfcSignedHash = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_SIGNED_HASH);
|
|
||||||
// carefully: only set if timestamp exists
|
|
||||||
Date nfcCreationDate = null;
|
|
||||||
long nfcCreationTimestamp = data.getLongExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, -1);
|
|
||||||
if (nfcCreationTimestamp != -1) {
|
|
||||||
nfcCreationDate = new Date(nfcCreationTimestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// sign and encrypt
|
|
||||||
builder.setSignatureHashAlgorithm(accSettings.getHashAlgorithm())
|
|
||||||
.setSignatureMasterKeyId(accSettings.getKeyId())
|
|
||||||
.setSignatureSubKeyId(sigSubKeyId)
|
|
||||||
.setSignaturePassphrase(passphrase)
|
|
||||||
.setNfcState(nfcSignedHash, nfcCreationDate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// execute PGP operation!
|
String passphrase;
|
||||||
SignEncryptResult pgpResult = builder.build().execute();
|
if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) {
|
||||||
|
passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
|
||||||
if (pgpResult.isPending()) {
|
|
||||||
if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_PASSPHRASE) ==
|
|
||||||
SignEncryptResult.RESULT_PENDING_PASSPHRASE) {
|
|
||||||
return getPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded());
|
|
||||||
} else if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_NFC) ==
|
|
||||||
SignEncryptResult.RESULT_PENDING_NFC) {
|
|
||||||
// return PendingIntent to execute NFC activity
|
|
||||||
// pass through the signature creation timestamp to be used again on second execution
|
|
||||||
// of PgpSignEncrypt when we have the signed hash!
|
|
||||||
data.putExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, pgpResult.getNfcTimestamp().getTime());
|
|
||||||
return getNfcSignIntent(data, pgpResult.getNfcKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcHash(), pgpResult.getNfcAlgo());
|
|
||||||
} else {
|
|
||||||
throw new PgpGeneralException(
|
|
||||||
"Encountered unhandled type of pending action not supported by API!");
|
|
||||||
}
|
|
||||||
} else if (pgpResult.success()) {
|
|
||||||
Intent result = new Intent();
|
|
||||||
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
|
|
||||||
return result;
|
|
||||||
} else {
|
} else {
|
||||||
LogEntryParcel errorMsg = pgpResult.getLog().getLast();
|
passphrase = PassphraseCacheService.getCachedPassphrase(getContext(),
|
||||||
throw new Exception(getString(errorMsg.mType.getMsgId()));
|
accSettings.getKeyId(), sigSubKeyId);
|
||||||
|
}
|
||||||
|
if (passphrase == null) {
|
||||||
|
// get PendingIntent for passphrase input, add it to given params and return to client
|
||||||
|
return getPassphraseIntent(data, sigSubKeyId);
|
||||||
}
|
}
|
||||||
|
|
||||||
} finally {
|
byte[] nfcSignedHash = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_SIGNED_HASH);
|
||||||
is.close();
|
// carefully: only set if timestamp exists
|
||||||
os.close();
|
Date nfcCreationDate = null;
|
||||||
|
long nfcCreationTimestamp = data.getLongExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, -1);
|
||||||
|
if (nfcCreationTimestamp != -1) {
|
||||||
|
nfcCreationDate = new Date(nfcCreationTimestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sign and encrypt
|
||||||
|
builder.setSignatureHashAlgorithm(accSettings.getHashAlgorithm())
|
||||||
|
.setSignatureMasterKeyId(accSettings.getKeyId())
|
||||||
|
.setSignatureSubKeyId(sigSubKeyId)
|
||||||
|
.setSignaturePassphrase(passphrase)
|
||||||
|
.setNfcState(nfcSignedHash, nfcCreationDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// execute PGP operation!
|
||||||
|
SignEncryptResult pgpResult = builder.build().execute();
|
||||||
|
|
||||||
|
if (pgpResult.isPending()) {
|
||||||
|
if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_PASSPHRASE) ==
|
||||||
|
SignEncryptResult.RESULT_PENDING_PASSPHRASE) {
|
||||||
|
return getPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded());
|
||||||
|
} else if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_NFC) ==
|
||||||
|
SignEncryptResult.RESULT_PENDING_NFC) {
|
||||||
|
// return PendingIntent to execute NFC activity
|
||||||
|
// pass through the signature creation timestamp to be used again on second execution
|
||||||
|
// of PgpSignEncrypt when we have the signed hash!
|
||||||
|
data.putExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, pgpResult.getNfcTimestamp().getTime());
|
||||||
|
return getNfcSignIntent(data, pgpResult.getNfcKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcHash(), pgpResult.getNfcAlgo());
|
||||||
|
} else {
|
||||||
|
throw new PgpGeneralException(
|
||||||
|
"Encountered unhandled type of pending action not supported by API!");
|
||||||
|
}
|
||||||
|
} else if (pgpResult.success()) {
|
||||||
|
Intent result = new Intent();
|
||||||
|
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
LogEntryParcel errorMsg = pgpResult.getLog().getLast();
|
||||||
|
throw new Exception(getString(errorMsg.mType.getMsgId()));
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.d(Constants.TAG, "encryptAndSignImpl", e);
|
Log.d(Constants.TAG, "encryptAndSignImpl", e);
|
||||||
@@ -470,17 +477,33 @@ public class OpenPgpService extends RemoteService {
|
|||||||
new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
|
new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
|
||||||
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
|
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
|
||||||
return result;
|
return result;
|
||||||
|
} finally {
|
||||||
|
if (is != null) {
|
||||||
|
try {
|
||||||
|
is.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(Constants.TAG, "IOException when closing InputStream", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (os != null) {
|
||||||
|
try {
|
||||||
|
os.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(Constants.TAG, "IOException when closing OutputStream", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Intent decryptAndVerifyImpl(Intent data, ParcelFileDescriptor input,
|
private Intent decryptAndVerifyImpl(Intent data, ParcelFileDescriptor input,
|
||||||
ParcelFileDescriptor output, Set<Long> allowedKeyIds,
|
ParcelFileDescriptor output, Set<Long> allowedKeyIds,
|
||||||
boolean decryptMetadataOnly) {
|
boolean decryptMetadataOnly) {
|
||||||
|
InputStream is = null;
|
||||||
|
OutputStream os = null;
|
||||||
try {
|
try {
|
||||||
// Get Input- and OutputStream from ParcelFileDescriptor
|
// Get Input- and OutputStream from ParcelFileDescriptor
|
||||||
InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input);
|
is = new ParcelFileDescriptor.AutoCloseInputStream(input);
|
||||||
|
|
||||||
OutputStream os;
|
|
||||||
// output is optional, e.g., for verifying detached signatures
|
// output is optional, e.g., for verifying detached signatures
|
||||||
if (decryptMetadataOnly || output == null) {
|
if (decryptMetadataOnly || output == null) {
|
||||||
os = null;
|
os = null;
|
||||||
@@ -488,101 +511,95 @@ public class OpenPgpService extends RemoteService {
|
|||||||
os = new ParcelFileDescriptor.AutoCloseOutputStream(output);
|
os = new ParcelFileDescriptor.AutoCloseOutputStream(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
String passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
|
||||||
String passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
|
long inputLength = is.available();
|
||||||
long inputLength = is.available();
|
InputData inputData = new InputData(is, inputLength);
|
||||||
InputData inputData = new InputData(is, inputLength);
|
|
||||||
|
|
||||||
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(
|
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(
|
||||||
this, new ProviderHelper(getContext()), null, inputData, os
|
this, new ProviderHelper(getContext()), null, inputData, os
|
||||||
);
|
);
|
||||||
|
|
||||||
byte[] nfcDecryptedSessionKey = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_DECRYPTED_SESSION_KEY);
|
byte[] nfcDecryptedSessionKey = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_DECRYPTED_SESSION_KEY);
|
||||||
|
|
||||||
byte[] detachedSignature = data.getByteArrayExtra(OpenPgpApi.EXTRA_DETACHED_SIGNATURE);
|
byte[] detachedSignature = data.getByteArrayExtra(OpenPgpApi.EXTRA_DETACHED_SIGNATURE);
|
||||||
|
|
||||||
// allow only private keys associated with accounts of this app
|
// allow only private keys associated with accounts of this app
|
||||||
// no support for symmetric encryption
|
// no support for symmetric encryption
|
||||||
builder.setPassphrase(passphrase)
|
builder.setPassphrase(passphrase)
|
||||||
.setAllowSymmetricDecryption(false)
|
.setAllowSymmetricDecryption(false)
|
||||||
.setAllowedKeyIds(allowedKeyIds)
|
.setAllowedKeyIds(allowedKeyIds)
|
||||||
.setDecryptMetadataOnly(decryptMetadataOnly)
|
.setDecryptMetadataOnly(decryptMetadataOnly)
|
||||||
.setNfcState(nfcDecryptedSessionKey)
|
.setNfcState(nfcDecryptedSessionKey)
|
||||||
.setDetachedSignature(detachedSignature);
|
.setDetachedSignature(detachedSignature);
|
||||||
|
|
||||||
DecryptVerifyResult pgpResult = builder.build().execute();
|
DecryptVerifyResult pgpResult = builder.build().execute();
|
||||||
|
|
||||||
if (pgpResult.isPending()) {
|
if (pgpResult.isPending()) {
|
||||||
if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) ==
|
if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) ==
|
||||||
DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) {
|
DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) {
|
||||||
return getPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded());
|
return getPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded());
|
||||||
} else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) ==
|
} else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) ==
|
||||||
DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) {
|
DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) {
|
||||||
throw new PgpGeneralException(
|
throw new PgpGeneralException(
|
||||||
"Decryption of symmetric content not supported by API!");
|
"Decryption of symmetric content not supported by API!");
|
||||||
} else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_NFC) ==
|
} else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_NFC) ==
|
||||||
DecryptVerifyResult.RESULT_PENDING_NFC) {
|
DecryptVerifyResult.RESULT_PENDING_NFC) {
|
||||||
return getNfcDecryptIntent(
|
return getNfcDecryptIntent(
|
||||||
data, pgpResult.getNfcSubKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcEncryptedSessionKey());
|
data, pgpResult.getNfcSubKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcEncryptedSessionKey());
|
||||||
} else {
|
|
||||||
throw new PgpGeneralException(
|
|
||||||
"Encountered unhandled type of pending action not supported by API!");
|
|
||||||
}
|
|
||||||
} else if (pgpResult.success()) {
|
|
||||||
Intent result = new Intent();
|
|
||||||
|
|
||||||
OpenPgpSignatureResult signatureResult = pgpResult.getSignatureResult();
|
|
||||||
if (signatureResult != null) {
|
|
||||||
result.putExtra(OpenPgpApi.RESULT_SIGNATURE, signatureResult);
|
|
||||||
|
|
||||||
if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) < 5) {
|
|
||||||
// SIGNATURE_KEY_REVOKED and SIGNATURE_KEY_EXPIRED have been added in version 5
|
|
||||||
if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_REVOKED
|
|
||||||
|| signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_EXPIRED) {
|
|
||||||
signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_MISSING) {
|
|
||||||
// If signature is unknown we return an _additional_ PendingIntent
|
|
||||||
// to retrieve the missing key
|
|
||||||
Intent intent = new Intent(getBaseContext(), ImportKeysActivity.class);
|
|
||||||
intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE);
|
|
||||||
intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, signatureResult.getKeyId());
|
|
||||||
intent.putExtra(ImportKeysActivity.EXTRA_PENDING_INTENT_DATA, data);
|
|
||||||
|
|
||||||
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,
|
|
||||||
intent,
|
|
||||||
PendingIntent.FLAG_CANCEL_CURRENT);
|
|
||||||
|
|
||||||
result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) >= 4) {
|
|
||||||
OpenPgpMetadata metadata = pgpResult.getDecryptMetadata();
|
|
||||||
if (metadata != null) {
|
|
||||||
result.putExtra(OpenPgpApi.RESULT_METADATA, metadata);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String charset = pgpResult.getCharset();
|
|
||||||
if (charset != null) {
|
|
||||||
result.putExtra(OpenPgpApi.RESULT_CHARSET, charset);
|
|
||||||
}
|
|
||||||
|
|
||||||
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
|
|
||||||
return result;
|
|
||||||
} else {
|
} else {
|
||||||
LogEntryParcel errorMsg = pgpResult.getLog().getLast();
|
throw new PgpGeneralException(
|
||||||
throw new Exception(getString(errorMsg.mType.getMsgId()));
|
"Encountered unhandled type of pending action not supported by API!");
|
||||||
}
|
}
|
||||||
} finally {
|
} else if (pgpResult.success()) {
|
||||||
is.close();
|
Intent result = new Intent();
|
||||||
if (os != null) {
|
|
||||||
os.close();
|
OpenPgpSignatureResult signatureResult = pgpResult.getSignatureResult();
|
||||||
|
if (signatureResult != null) {
|
||||||
|
result.putExtra(OpenPgpApi.RESULT_SIGNATURE, signatureResult);
|
||||||
|
|
||||||
|
if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) < 5) {
|
||||||
|
// SIGNATURE_KEY_REVOKED and SIGNATURE_KEY_EXPIRED have been added in version 5
|
||||||
|
if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_REVOKED
|
||||||
|
|| signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_EXPIRED) {
|
||||||
|
signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_MISSING) {
|
||||||
|
// If signature is unknown we return an _additional_ PendingIntent
|
||||||
|
// to retrieve the missing key
|
||||||
|
Intent intent = new Intent(getBaseContext(), ImportKeysActivity.class);
|
||||||
|
intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE);
|
||||||
|
intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, signatureResult.getKeyId());
|
||||||
|
intent.putExtra(ImportKeysActivity.EXTRA_PENDING_INTENT_DATA, data);
|
||||||
|
|
||||||
|
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,
|
||||||
|
intent,
|
||||||
|
PendingIntent.FLAG_CANCEL_CURRENT);
|
||||||
|
|
||||||
|
result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) >= 4) {
|
||||||
|
OpenPgpMetadata metadata = pgpResult.getDecryptMetadata();
|
||||||
|
if (metadata != null) {
|
||||||
|
result.putExtra(OpenPgpApi.RESULT_METADATA, metadata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String charset = pgpResult.getCharset();
|
||||||
|
if (charset != null) {
|
||||||
|
result.putExtra(OpenPgpApi.RESULT_CHARSET, charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
LogEntryParcel errorMsg = pgpResult.getLog().getLast();
|
||||||
|
throw new Exception(getString(errorMsg.mType.getMsgId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.d(Constants.TAG, "decryptAndVerifyImpl", e);
|
Log.d(Constants.TAG, "decryptAndVerifyImpl", e);
|
||||||
Intent result = new Intent();
|
Intent result = new Intent();
|
||||||
@@ -590,6 +607,21 @@ public class OpenPgpService extends RemoteService {
|
|||||||
new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
|
new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
|
||||||
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
|
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
|
||||||
return result;
|
return result;
|
||||||
|
} finally {
|
||||||
|
if (is != null) {
|
||||||
|
try {
|
||||||
|
is.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(Constants.TAG, "IOException when closing InputStream", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (os != null) {
|
||||||
|
try {
|
||||||
|
os.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(Constants.TAG, "IOException when closing OutputStream", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -720,48 +752,66 @@ public class OpenPgpService extends RemoteService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Intent execute(Intent data, ParcelFileDescriptor input, ParcelFileDescriptor output) {
|
public Intent execute(Intent data, ParcelFileDescriptor input, ParcelFileDescriptor output) {
|
||||||
Intent errorResult = checkRequirements(data);
|
try {
|
||||||
if (errorResult != null) {
|
Intent errorResult = checkRequirements(data);
|
||||||
return errorResult;
|
if (errorResult != null) {
|
||||||
}
|
return errorResult;
|
||||||
|
}
|
||||||
|
|
||||||
String accName = getAccountName(data);
|
String accName = getAccountName(data);
|
||||||
final AccountSettings accSettings = getAccSettings(accName);
|
final AccountSettings accSettings = getAccSettings(accName);
|
||||||
if (accSettings == null) {
|
if (accSettings == null) {
|
||||||
return getCreateAccountIntent(data, accName);
|
return getCreateAccountIntent(data, accName);
|
||||||
}
|
}
|
||||||
|
|
||||||
String action = data.getAction();
|
String action = data.getAction();
|
||||||
if (OpenPgpApi.ACTION_CLEARTEXT_SIGN.equals(action)) {
|
if (OpenPgpApi.ACTION_CLEARTEXT_SIGN.equals(action)) {
|
||||||
return signImpl(data, input, output, accSettings, true);
|
return signImpl(data, input, output, accSettings, true);
|
||||||
} else if (OpenPgpApi.ACTION_SIGN.equals(action)) {
|
} else if (OpenPgpApi.ACTION_SIGN.equals(action)) {
|
||||||
// DEPRECATED: same as ACTION_CLEARTEXT_SIGN
|
// DEPRECATED: same as ACTION_CLEARTEXT_SIGN
|
||||||
Log.w(Constants.TAG, "You are using a deprecated API call, please use ACTION_CLEARTEXT_SIGN instead of ACTION_SIGN!");
|
Log.w(Constants.TAG, "You are using a deprecated API call, please use ACTION_CLEARTEXT_SIGN instead of ACTION_SIGN!");
|
||||||
return signImpl(data, input, output, accSettings, true);
|
return signImpl(data, input, output, accSettings, true);
|
||||||
} else if (OpenPgpApi.ACTION_DETACHED_SIGN.equals(action)) {
|
} else if (OpenPgpApi.ACTION_DETACHED_SIGN.equals(action)) {
|
||||||
return signImpl(data, input, output, accSettings, false);
|
return signImpl(data, input, output, accSettings, false);
|
||||||
} else if (OpenPgpApi.ACTION_ENCRYPT.equals(action)) {
|
} else if (OpenPgpApi.ACTION_ENCRYPT.equals(action)) {
|
||||||
return encryptAndSignImpl(data, input, output, accSettings, false);
|
return encryptAndSignImpl(data, input, output, accSettings, false);
|
||||||
} else if (OpenPgpApi.ACTION_SIGN_AND_ENCRYPT.equals(action)) {
|
} else if (OpenPgpApi.ACTION_SIGN_AND_ENCRYPT.equals(action)) {
|
||||||
return encryptAndSignImpl(data, input, output, accSettings, true);
|
return encryptAndSignImpl(data, input, output, accSettings, true);
|
||||||
} else if (OpenPgpApi.ACTION_DECRYPT_VERIFY.equals(action)) {
|
} else if (OpenPgpApi.ACTION_DECRYPT_VERIFY.equals(action)) {
|
||||||
String currentPkg = getCurrentCallingPackage();
|
String currentPkg = getCurrentCallingPackage();
|
||||||
Set<Long> allowedKeyIds =
|
Set<Long> allowedKeyIds =
|
||||||
mProviderHelper.getAllKeyIdsForApp(
|
mProviderHelper.getAllKeyIdsForApp(
|
||||||
ApiAccounts.buildBaseUri(currentPkg));
|
ApiAccounts.buildBaseUri(currentPkg));
|
||||||
return decryptAndVerifyImpl(data, input, output, allowedKeyIds, false);
|
return decryptAndVerifyImpl(data, input, output, allowedKeyIds, false);
|
||||||
} else if (OpenPgpApi.ACTION_DECRYPT_METADATA.equals(action)) {
|
} else if (OpenPgpApi.ACTION_DECRYPT_METADATA.equals(action)) {
|
||||||
String currentPkg = getCurrentCallingPackage();
|
String currentPkg = getCurrentCallingPackage();
|
||||||
Set<Long> allowedKeyIds =
|
Set<Long> allowedKeyIds =
|
||||||
mProviderHelper.getAllKeyIdsForApp(
|
mProviderHelper.getAllKeyIdsForApp(
|
||||||
ApiAccounts.buildBaseUri(currentPkg));
|
ApiAccounts.buildBaseUri(currentPkg));
|
||||||
return decryptAndVerifyImpl(data, input, output, allowedKeyIds, true);
|
return decryptAndVerifyImpl(data, input, output, allowedKeyIds, true);
|
||||||
} else if (OpenPgpApi.ACTION_GET_KEY.equals(action)) {
|
} else if (OpenPgpApi.ACTION_GET_KEY.equals(action)) {
|
||||||
return getKeyImpl(data);
|
return getKeyImpl(data);
|
||||||
} else if (OpenPgpApi.ACTION_GET_KEY_IDS.equals(action)) {
|
} else if (OpenPgpApi.ACTION_GET_KEY_IDS.equals(action)) {
|
||||||
return getKeyIdsImpl(data);
|
return getKeyIdsImpl(data);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
// always close input and output file descriptors even in error cases
|
||||||
|
if (input != null) {
|
||||||
|
try {
|
||||||
|
input.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(Constants.TAG, "IOException when closing input ParcelFileDescriptor", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (output != null) {
|
||||||
|
try {
|
||||||
|
output.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(Constants.TAG, "IOException when closing output ParcelFileDescriptor", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user