Close FileDescriptors and input, output streams when possible

This commit is contained in:
Dominik Schürmann
2015-01-29 12:44:06 +01:00
parent c4ef86b38a
commit a346b58db7

View File

@@ -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);
}
}
} }
} }