From 99af2c33d35f9557c2f23e1abddd82d770e763d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 22 Jul 2014 18:09:12 +0200 Subject: Reuse signature creation timestamp for synchronous signing --- .../keychain/pgp/PgpSignEncrypt.java | 41 ++++++++++------------ .../keychain/pgp/WrappedSecretKey.java | 23 ++++++++---- .../keychain/remote/OpenPgpService.java | 13 ++++--- extern/openpgp-card-nfc-lib | 2 +- 4 files changed, 45 insertions(+), 34 deletions(-) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java index cc34e8737..41b81bf1c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java @@ -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); } } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java index 141f2d5eb..ea919b683 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKey.java @@ -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) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java index a00759180..e18af2eda 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -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 { diff --git a/extern/openpgp-card-nfc-lib b/extern/openpgp-card-nfc-lib index bedea7f27..6402aa923 160000 --- a/extern/openpgp-card-nfc-lib +++ b/extern/openpgp-card-nfc-lib @@ -1 +1 @@ -Subproject commit bedea7f2734451e7990d4971cb7f9f4e3cbe2fee +Subproject commit 6402aa9232d6de01c696dc6ba23ca86355474d4e -- cgit v1.2.3