Merge pull request #2011 from rhari991/restrict-sign-keys
API: Restrict secret keys for sign operation
This commit is contained in:
@@ -731,6 +731,7 @@ public abstract class OperationResult implements Parcelable {
|
||||
MSG_PSE_ERROR_PGP (LogLevel.ERROR, R.string.msg_pse_error_pgp),
|
||||
MSG_PSE_ERROR_SIG (LogLevel.ERROR, R.string.msg_pse_error_sig),
|
||||
MSG_PSE_ERROR_UNLOCK (LogLevel.ERROR, R.string.msg_pse_error_unlock),
|
||||
MSG_PSE_ERROR_KEY_NOT_ALLOWED(LogLevel.ERROR, R.string.msg_pse_error_key_not_allowed),
|
||||
MSG_PSE_ERROR_REVOKED_OR_EXPIRED (LogLevel.ERROR, R.string.msg_pse_error_revoked_or_expired),
|
||||
MSG_PSE_KEY_OK (LogLevel.OK, R.string.msg_pse_key_ok),
|
||||
MSG_PSE_KEY_UNKNOWN (LogLevel.DEBUG, R.string.msg_pse_key_unknown),
|
||||
|
||||
@@ -25,6 +25,8 @@ import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
|
||||
|
||||
public class PgpSignEncryptResult extends InputPendingResult {
|
||||
|
||||
public static final int RESULT_KEY_DISALLOWED = RESULT_ERROR + 32;
|
||||
|
||||
byte[] mOutputBytes;
|
||||
|
||||
byte[] mDetachedSignature;
|
||||
|
||||
@@ -22,6 +22,8 @@ import android.net.Uri;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
|
||||
public class PgpSignEncryptInputParcel implements Parcelable {
|
||||
|
||||
@@ -31,6 +33,8 @@ public class PgpSignEncryptInputParcel implements Parcelable {
|
||||
private Uri mOutputUri;
|
||||
private byte[] mInputBytes;
|
||||
|
||||
private HashSet<Long> mAllowedKeyIds;
|
||||
|
||||
public PgpSignEncryptInputParcel(PgpSignEncryptData data) {
|
||||
this.data = data;
|
||||
}
|
||||
@@ -41,6 +45,8 @@ public class PgpSignEncryptInputParcel implements Parcelable {
|
||||
mInputBytes = source.createByteArray();
|
||||
|
||||
data = source.readParcelable(getClass().getClassLoader());
|
||||
|
||||
mAllowedKeyIds = (HashSet<Long>) source.readSerializable();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -55,6 +61,8 @@ public class PgpSignEncryptInputParcel implements Parcelable {
|
||||
dest.writeByteArray(mInputBytes);
|
||||
|
||||
data.writeToParcel(dest, 0);
|
||||
|
||||
dest.writeSerializable(mAllowedKeyIds);
|
||||
}
|
||||
|
||||
public void setInputBytes(byte[] inputBytes) {
|
||||
@@ -91,6 +99,14 @@ public class PgpSignEncryptInputParcel implements Parcelable {
|
||||
return data;
|
||||
}
|
||||
|
||||
HashSet<Long> getAllowedKeyIds() {
|
||||
return mAllowedKeyIds;
|
||||
}
|
||||
|
||||
public void setAllowedKeyIds(HashSet<Long> allowedKeyIds) {
|
||||
mAllowedKeyIds = allowedKeyIds;
|
||||
}
|
||||
|
||||
public static final Creator<PgpSignEncryptInputParcel> CREATOR = new Creator<PgpSignEncryptInputParcel>() {
|
||||
public PgpSignEncryptInputParcel createFromParcel(final Parcel source) {
|
||||
return new PgpSignEncryptInputParcel(source);
|
||||
|
||||
@@ -21,7 +21,6 @@ package org.sufficientlysecure.keychain.pgp;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.bouncycastle.bcpg.ArmoredOutputStream;
|
||||
@@ -40,8 +39,6 @@ import org.bouncycastle.openpgp.operator.jcajce.PGPUtil;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.operations.BaseOperation;
|
||||
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
|
||||
import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult;
|
||||
@@ -229,6 +226,14 @@ public class PgpSignEncryptOperation extends BaseOperation<PgpSignEncryptInputPa
|
||||
mProviderHelper.getCanonicalizedSecretKeyRing(signingMasterKeyId);
|
||||
signingKey = signingKeyRing.getSecretKey(data.getSignatureSubKeyId());
|
||||
|
||||
if (input.getAllowedKeyIds() != null) {
|
||||
if (!input.getAllowedKeyIds().contains(signingMasterKeyId)) {
|
||||
// this key is in our db, but NOT allowed!
|
||||
log.add(LogType.MSG_PSE_ERROR_KEY_NOT_ALLOWED, indent + 1);
|
||||
return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_KEY_DISALLOWED, log);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Make sure key is not expired or revoked
|
||||
if (signingKeyRing.isExpired() || signingKeyRing.isRevoked()
|
||||
|
||||
@@ -19,15 +19,6 @@
|
||||
package org.sufficientlysecure.keychain.remote;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
@@ -75,6 +66,15 @@ import org.sufficientlysecure.keychain.util.InputData;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
public class OpenPgpService extends Service {
|
||||
public static final int API_VERSION_WITH_RESULT_METADATA = 4;
|
||||
public static final int API_VERSION_WITH_KEY_REVOKED_EXPIRED = 5;
|
||||
@@ -109,6 +109,8 @@ public class OpenPgpService extends Service {
|
||||
try {
|
||||
boolean asciiArmor = cleartextSign || data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
|
||||
|
||||
int targetApiVersion = data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1);
|
||||
|
||||
// sign-only
|
||||
PgpSignEncryptData pgpData = new PgpSignEncryptData();
|
||||
pgpData.setEnableAsciiArmorOutput(asciiArmor)
|
||||
@@ -143,6 +145,7 @@ public class OpenPgpService extends Service {
|
||||
|
||||
|
||||
PgpSignEncryptInputParcel pseInput = new PgpSignEncryptInputParcel(pgpData);
|
||||
pseInput.setAllowedKeyIds(getAllowedKeyIds(targetApiVersion));
|
||||
|
||||
// Get Input- and OutputStream from ParcelFileDescriptor
|
||||
if (!cleartextSign) {
|
||||
@@ -204,6 +207,7 @@ public class OpenPgpService extends Service {
|
||||
OutputStream outputStream, boolean sign) {
|
||||
try {
|
||||
boolean asciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
|
||||
int targetApiVersion = data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1);
|
||||
String originalFilename = data.getStringExtra(OpenPgpApi.EXTRA_ORIGINAL_FILENAME);
|
||||
if (originalFilename == null) {
|
||||
originalFilename = "";
|
||||
@@ -278,6 +282,7 @@ public class OpenPgpService extends Service {
|
||||
}
|
||||
|
||||
PgpSignEncryptInputParcel pseInput = new PgpSignEncryptInputParcel(pgpData);
|
||||
pseInput.setAllowedKeyIds(getAllowedKeyIds(targetApiVersion));
|
||||
|
||||
CryptoInputParcel inputParcel = CryptoInputParcelCacheService.getCryptoInputParcel(this, data);
|
||||
if (inputParcel == null) {
|
||||
@@ -330,15 +335,7 @@ public class OpenPgpService extends Service {
|
||||
outputStream = null;
|
||||
}
|
||||
|
||||
String currentPkg = mApiPermissionHelper.getCurrentCallingPackage();
|
||||
HashSet<Long> allowedKeyIds = mApiDao.getAllowedKeyIdsForApp(
|
||||
KeychainContract.ApiAllowedKeys.buildBaseUri(currentPkg));
|
||||
|
||||
int targetApiVersion = data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1);
|
||||
if (targetApiVersion <= API_VERSION_HIGHEST_WITH_ACCOUNTS) {
|
||||
allowedKeyIds.addAll(mApiDao.getAllKeyIdsForApp(
|
||||
ApiAccounts.buildBaseUri(currentPkg)));
|
||||
}
|
||||
|
||||
CryptoInputParcel cryptoInput = CryptoInputParcelCacheService.getCryptoInputParcel(this, data);
|
||||
if (cryptoInput == null) {
|
||||
@@ -368,7 +365,7 @@ public class OpenPgpService extends Service {
|
||||
// no support for symmetric encryption
|
||||
PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel()
|
||||
.setAllowSymmetricDecryption(false)
|
||||
.setAllowedKeyIds(allowedKeyIds)
|
||||
.setAllowedKeyIds(getAllowedKeyIds(targetApiVersion))
|
||||
.setDecryptMetadataOnly(decryptMetadataOnly)
|
||||
.setDetachedSignature(detachedSignature)
|
||||
.setSenderAddress(senderAddress);
|
||||
@@ -694,6 +691,19 @@ public class OpenPgpService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
private HashSet<Long> getAllowedKeyIds(int targetApiVersion) {
|
||||
String currentPkg = mApiPermissionHelper.getCurrentCallingPackage();
|
||||
HashSet<Long> allowedKeyIds = mApiDao.getAllowedKeyIdsForApp(
|
||||
KeychainContract.ApiAllowedKeys.buildBaseUri(currentPkg));
|
||||
|
||||
if (targetApiVersion <= API_VERSION_HIGHEST_WITH_ACCOUNTS) {
|
||||
allowedKeyIds.addAll(mApiDao.getAllKeyIdsForApp(
|
||||
ApiAccounts.buildBaseUri(currentPkg)));
|
||||
}
|
||||
|
||||
return allowedKeyIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check requirements:
|
||||
* - params != null
|
||||
|
||||
@@ -1297,6 +1297,7 @@
|
||||
<string name="msg_pse_error_pgp">"Internal OpenPGP error!"</string>
|
||||
<string name="msg_pse_error_sig">"Encountered OpenPGP signature exception!"</string>
|
||||
<string name="msg_pse_error_unlock">"Unknown error unlocking key!"</string>
|
||||
<string name="msg_pse_error_key_not_allowed">"Key selected for encryption is not allowed"</string>
|
||||
<string name="msg_pse_error_revoked_or_expired">"Revoked/Expired key cannot be used for sign or encryption"</string>
|
||||
<string name="msg_pse_key_ok">"Encrypting for key: %s"</string>
|
||||
<string name="msg_pse_key_unknown">"Missing key for encryption: %s"</string>
|
||||
|
||||
Reference in New Issue
Block a user