mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-11-23 17:22:16 -05:00
Reuse signature creation timestamp for synchronous signing
This commit is contained in:
parent
afd6851e5b
commit
99af2c33d3
@ -18,10 +18,8 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.pgp;
|
||||
|
||||
import org.openkeychain.nfc.NfcHandler;
|
||||
import org.spongycastle.bcpg.ArmoredOutputStream;
|
||||
import org.spongycastle.bcpg.BCPGOutputStream;
|
||||
import org.spongycastle.bcpg.S2K;
|
||||
import org.spongycastle.openpgp.PGPCompressedDataGenerator;
|
||||
import org.spongycastle.openpgp.PGPEncryptedDataGenerator;
|
||||
import org.spongycastle.openpgp.PGPException;
|
||||
@ -41,17 +39,14 @@ import org.sufficientlysecure.keychain.util.InputData;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.SignatureException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
@ -77,7 +72,9 @@ public class PgpSignEncrypt {
|
||||
private String mSignaturePassphrase;
|
||||
private boolean mEncryptToSigner;
|
||||
private boolean mCleartextInput;
|
||||
private byte[] mNfcData;
|
||||
|
||||
private byte[] mNfcSignedHash = null;
|
||||
private Date mNfcCreationTimestamp = null;
|
||||
|
||||
private static byte[] NEW_LINE;
|
||||
|
||||
@ -108,7 +105,8 @@ public class PgpSignEncrypt {
|
||||
this.mSignaturePassphrase = builder.mSignaturePassphrase;
|
||||
this.mEncryptToSigner = builder.mEncryptToSigner;
|
||||
this.mCleartextInput = builder.mCleartextInput;
|
||||
this.mNfcData = builder.mNfcData;
|
||||
this.mNfcSignedHash = builder.mNfcSignedHash;
|
||||
this.mNfcCreationTimestamp = builder.mNfcCreationTimestamp;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
@ -131,7 +129,9 @@ public class PgpSignEncrypt {
|
||||
private String mSignaturePassphrase = null;
|
||||
private boolean mEncryptToSigner = false;
|
||||
private boolean mCleartextInput = false;
|
||||
private byte[] mNfcData = null;
|
||||
|
||||
private byte[] mNfcSignedHash = null;
|
||||
private Date mNfcCreationTimestamp = null;
|
||||
|
||||
public Builder(ProviderHelper providerHelper, String versionHeader, InputData data, OutputStream outStream) {
|
||||
this.mProviderHelper = providerHelper;
|
||||
@ -216,8 +216,9 @@ public class PgpSignEncrypt {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setNfcData(byte[] nfcData) {
|
||||
mNfcData = nfcData;
|
||||
public Builder setNfcState(byte[] signedHash, Date creationTimestamp) {
|
||||
mNfcSignedHash = signedHash;
|
||||
mNfcCreationTimestamp = creationTimestamp;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -259,19 +260,15 @@ public class PgpSignEncrypt {
|
||||
}
|
||||
|
||||
public static class NeedNfcDataException extends Exception {
|
||||
public byte[] mData;
|
||||
public byte[] mHashToSign;
|
||||
public Date mCreationTimestamp;
|
||||
|
||||
public NeedNfcDataException(byte[] data) {
|
||||
mData = data;
|
||||
public NeedNfcDataException(byte[] hashToSign, Date creationTimestamp) {
|
||||
mHashToSign = hashToSign;
|
||||
mCreationTimestamp = creationTimestamp;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove later
|
||||
static String convertStreamToString(java.io.InputStream is) {
|
||||
java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
|
||||
return s.hasNext() ? s.next() : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Signs and/or encrypts data based on parameters of class
|
||||
*/
|
||||
@ -381,7 +378,7 @@ public class PgpSignEncrypt {
|
||||
mSignatureHashAlgorithm, cleartext);
|
||||
} else {
|
||||
signatureGenerator = signingKey.getSignatureGenerator(
|
||||
mSignatureHashAlgorithm, cleartext, mNfcData);
|
||||
mSignatureHashAlgorithm, cleartext, mNfcSignedHash, mNfcCreationTimestamp);
|
||||
}
|
||||
} catch (PgpGeneralException e) {
|
||||
// TODO throw correct type of exception (which shouldn't be PGPException)
|
||||
@ -546,8 +543,8 @@ public class PgpSignEncrypt {
|
||||
try {
|
||||
signatureGenerator.generate().encode(pOut);
|
||||
} catch (NfcSyncPGPContentSignerBuilder.NfcInteractionNeeded e) {
|
||||
// this secret key diverts to a OpenPGP card, throw exception with to-be-signed hash
|
||||
throw new NeedNfcDataException(e.hashToSign);
|
||||
// this secret key diverts to a OpenPGP card, throw exception with hash that will be signed
|
||||
throw new NeedNfcDataException(e.hashToSign, e.creationTimestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.sufficientlysecure.keychain.pgp;
|
||||
|
||||
import org.spongycastle.bcpg.HashAlgorithmTags;
|
||||
import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
|
||||
import org.spongycastle.bcpg.S2K;
|
||||
import org.spongycastle.openpgp.PGPException;
|
||||
import org.spongycastle.openpgp.PGPPrivateKey;
|
||||
@ -30,11 +29,9 @@ import org.sufficientlysecure.keychain.util.Log;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.SignatureException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/** Wrapper for a PGPSecretKey.
|
||||
*
|
||||
@ -121,7 +118,7 @@ public class WrappedSecretKey extends WrappedPublicKey {
|
||||
}
|
||||
|
||||
public PGPSignatureGenerator getSignatureGenerator(int hashAlgo, boolean cleartext,
|
||||
byte[] nfcSignedHash)
|
||||
byte[] nfcSignedHash, Date nfcCreationTimestamp)
|
||||
throws PgpGeneralException {
|
||||
if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) {
|
||||
throw new PrivateKeyNotUnlockedException();
|
||||
@ -129,11 +126,21 @@ public class WrappedSecretKey extends WrappedPublicKey {
|
||||
|
||||
PGPContentSignerBuilder contentSignerBuilder;
|
||||
if (mPrivateKeyState == PRIVATE_KEY_STATE_DIVERT_TO_CARD) {
|
||||
// to sign using nfc PgpSignEncrypt is executed two times.
|
||||
// the first time it stops to return the PendingIntent for nfc connection and signing the hash
|
||||
// the second time the signed hash is used.
|
||||
// to get the same hash we cache the timestamp for the second round!
|
||||
if (nfcCreationTimestamp == null) {
|
||||
nfcCreationTimestamp = new Date();
|
||||
}
|
||||
|
||||
// use synchronous "NFC based" SignerBuilder
|
||||
contentSignerBuilder = new NfcSyncPGPContentSignerBuilder(
|
||||
mSecretKey.getPublicKey().getAlgorithm(), hashAlgo,
|
||||
mSecretKey.getKeyID(), nfcSignedHash)
|
||||
mSecretKey.getKeyID(), nfcSignedHash, nfcCreationTimestamp)
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||
|
||||
Log.d(Constants.TAG, "mSecretKey.getKeyID() "+ PgpKeyHelper.convertKeyIdToHex(mSecretKey.getKeyID()));
|
||||
} else {
|
||||
// content signer based on signing key algorithm and chosen hash algorithm
|
||||
contentSignerBuilder = new JcaPGPContentSignerBuilder(
|
||||
@ -155,6 +162,10 @@ public class WrappedSecretKey extends WrappedPublicKey {
|
||||
|
||||
PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
|
||||
spGen.setSignerUserID(false, mRing.getPrimaryUserIdWithFallback());
|
||||
if (nfcCreationTimestamp != null) {
|
||||
spGen.setSignatureCreationTime(false, nfcCreationTimestamp);
|
||||
Log.d(Constants.TAG, "For NFC: set sig creation time to " + nfcCreationTimestamp);
|
||||
}
|
||||
signatureGenerator.setHashedSubpackets(spGen.generate());
|
||||
return signatureGenerator;
|
||||
} catch(PGPException e) {
|
||||
|
@ -50,6 +50,7 @@ import org.sufficientlysecure.keychain.util.Log;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
|
||||
public class OpenPgpService extends RemoteService {
|
||||
@ -136,11 +137,11 @@ public class OpenPgpService extends RemoteService {
|
||||
return result;
|
||||
}
|
||||
|
||||
private Intent getNfcIntent(Intent data, byte[] in) {
|
||||
private Intent getNfcIntent(Intent data, byte[] hashToSign) {
|
||||
// build PendingIntent for Yubikey NFC operations
|
||||
Intent intent = new Intent(getBaseContext(), NfcActivity.class);
|
||||
intent.setAction(NfcActivity.ACTION_SIGN_HASH);
|
||||
intent.putExtra(NfcActivity.EXTRA_NFC_DATA, in);
|
||||
intent.putExtra(NfcActivity.EXTRA_NFC_HASH_TO_SIGN, hashToSign);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
// pass params through to activity that it can be returned again later to repeat pgp operation
|
||||
intent.putExtra(NfcActivity.EXTRA_DATA, data);
|
||||
@ -191,7 +192,8 @@ public class OpenPgpService extends RemoteService {
|
||||
return passphraseBundle;
|
||||
}
|
||||
|
||||
byte[] nfcData = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_DATA);
|
||||
byte[] nfcSignedHash = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_SIGNED_HASH);
|
||||
Date nfcCreationTimestamp = new Date(data.getLongExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, 0));
|
||||
|
||||
// Get Input- and OutputStream from ParcelFileDescriptor
|
||||
InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input);
|
||||
@ -210,7 +212,7 @@ public class OpenPgpService extends RemoteService {
|
||||
.setSignatureForceV3(false)
|
||||
.setSignatureMasterKeyId(accSettings.getKeyId())
|
||||
.setSignaturePassphrase(passphrase)
|
||||
.setNfcData(nfcData);
|
||||
.setNfcState(nfcSignedHash, nfcCreationTimestamp);
|
||||
|
||||
// TODO: currently always assume cleartext input, no sign-only of binary currently!
|
||||
builder.setCleartextInput(true);
|
||||
@ -229,7 +231,8 @@ public class OpenPgpService extends RemoteService {
|
||||
throw new Exception(getString(R.string.error_no_signature_key));
|
||||
} catch (PgpSignEncrypt.NeedNfcDataException e) {
|
||||
// return PendingIntent to execute NFC activity
|
||||
Intent nfcIntent = getNfcIntent(data, e.mData);
|
||||
data.putExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, e.mCreationTimestamp.getTime());
|
||||
Intent nfcIntent = getNfcIntent(data, e.mHashToSign);
|
||||
return nfcIntent;
|
||||
}
|
||||
} finally {
|
||||
|
2
extern/openpgp-card-nfc-lib
vendored
2
extern/openpgp-card-nfc-lib
vendored
@ -1 +1 @@
|
||||
Subproject commit bedea7f2734451e7990d4971cb7f9f4e3cbe2fee
|
||||
Subproject commit 6402aa9232d6de01c696dc6ba23ca86355474d4e
|
Loading…
Reference in New Issue
Block a user