Reuse signature creation timestamp for synchronous signing

This commit is contained in:
Dominik Schürmann 2014-07-22 18:09:12 +02:00
parent afd6851e5b
commit 99af2c33d3
4 changed files with 45 additions and 34 deletions

View File

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

View File

@ -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) {

View File

@ -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 {

@ -1 +1 @@
Subproject commit bedea7f2734451e7990d4971cb7f9f4e3cbe2fee
Subproject commit 6402aa9232d6de01c696dc6ba23ca86355474d4e