diff options
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure')
4 files changed, 83 insertions, 31 deletions
| diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java index 833e1ad3d..f0ce2ea78 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java @@ -36,6 +36,7 @@ import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory;  import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;  import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;  import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder; +import org.spongycastle.openpgp.operator.jcajce.NfcPublicKeyDataDecryptorFactoryBuilder;  import org.spongycastle.openpgp.operator.jcajce.NfcSyncPGPContentSignerBuilder;  import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; @@ -189,14 +190,8 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {          return supported;      } -    public PGPSignatureGenerator getSignatureGenerator(int hashAlgo, boolean cleartext, -                                                       byte[] nfcSignedHash, Date nfcCreationTimestamp) -            throws PgpGeneralException { -        if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) { -            throw new PrivateKeyNotUnlockedException(); -        } - -        PGPContentSignerBuilder contentSignerBuilder; +    private PGPContentSignerBuilder getContentSignerBuilder(int hashAlgo, byte[] nfcSignedHash, +                                                            Date nfcCreationTimestamp) {          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 @@ -207,18 +202,27 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {              }              // use synchronous "NFC based" SignerBuilder -            contentSignerBuilder = new NfcSyncPGPContentSignerBuilder( +            return new NfcSyncPGPContentSignerBuilder(                      mSecretKey.getPublicKey().getAlgorithm(), hashAlgo,                      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( +            return new JcaPGPContentSignerBuilder(                      mSecretKey.getPublicKey().getAlgorithm(), hashAlgo)                      .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);          } +    } + +    public PGPSignatureGenerator getSignatureGenerator(int hashAlgo, boolean cleartext, +                                                       byte[] nfcSignedHash, Date nfcCreationTimestamp) +            throws PgpGeneralException { +        if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) { +            throw new PrivateKeyNotUnlockedException(); +        } + +        PGPContentSignerBuilder contentSignerBuilder = getContentSignerBuilder(hashAlgo, +                nfcSignedHash, nfcCreationTimestamp);          int signatureType;          if (cleartext) { @@ -247,12 +251,17 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {      }      public PublicKeyDataDecryptorFactory getDecryptorFactory() { -        // TODO: divert to card missing -        if (mPrivateKeyState != PRIVATE_KEY_STATE_UNLOCKED) { +        if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) {              throw new PrivateKeyNotUnlockedException();          } -        return new JcePublicKeyDataDecryptorFactoryBuilder() -                .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mPrivateKey); + +        if (mPrivateKeyState == PRIVATE_KEY_STATE_DIVERT_TO_CARD) { +            return new NfcPublicKeyDataDecryptorFactoryBuilder() +                    .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mPrivateKey); +        } else { +            return new JcePublicKeyDataDecryptorFactoryBuilder() +                    .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mPrivateKey); +        }      }      /** @@ -262,12 +271,11 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {       * @param userIds       User IDs to certify, must not be null or empty       * @return A keyring with added certifications       */ -    public UncachedKeyRing certifyUserIds(CanonicalizedPublicKeyRing publicKeyRing, List<String> userIds) +    public UncachedKeyRing certifyUserIds(CanonicalizedPublicKeyRing publicKeyRing, List<String> userIds, +                                          byte[] nfcSignedHash, Date nfcCreationTimestamp)              throws PgpGeneralMsgIdException, NoSuchAlgorithmException, NoSuchProviderException,              PGPException, SignatureException { - -        // TODO: divert to card missing -        if (mPrivateKeyState != PRIVATE_KEY_STATE_UNLOCKED) { +        if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) {              throw new PrivateKeyNotUnlockedException();          } @@ -275,9 +283,8 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {          PGPSignatureGenerator signatureGenerator;          {              // TODO: SHA256 fixed? -            JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder( -                    mSecretKey.getPublicKey().getAlgorithm(), PGPUtil.SHA256) -                    .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); +            PGPContentSignerBuilder contentSignerBuilder = getContentSignerBuilder(PGPUtil.SHA256, +                    nfcSignedHash, nfcCreationTimestamp);              signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);              signatureGenerator.init(PGPSignature.DEFAULT_CERTIFICATION, mPrivateKey); @@ -285,6 +292,10 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {          { // supply signatureGenerator with a SubpacketVector              PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); +            if (nfcCreationTimestamp != null) { +                spGen.setSignatureCreationTime(false, nfcCreationTimestamp); +                Log.d(Constants.TAG, "For NFC: set sig creation time to " + nfcCreationTimestamp); +            }              PGPSignatureSubpacketVector packetVector = spGen.generate();              signatureGenerator.setHashedSubpackets(packetVector);          } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java index cb077c55c..6abef1ad2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -42,6 +42,7 @@ import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;  import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;  import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;  import org.spongycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder; +import org.spongycastle.openpgp.operator.jcajce.NfcPublicKeyDataDecryptorFactoryBuilder;  import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.R;  import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; @@ -59,6 +60,7 @@ import java.io.InputStream;  import java.io.OutputStream;  import java.net.URLConnection;  import java.security.SignatureException; +import java.util.Date;  import java.util.Iterator;  import java.util.Set; @@ -193,13 +195,21 @@ public class PgpDecryptVerify {          }      } +    public static class NeedNfcDataException extends Exception { +        public byte[] mDec; + +        public NeedNfcDataException(byte[] dec) { +            mDec = dec; +        } +    } +      /**       * Decrypts and/or verifies data based on parameters of class       */      public PgpDecryptVerifyResult execute()              throws IOException, PGPException, SignatureException,              WrongPassphraseException, NoSecretKeyException, KeyExtractionException, -            InvalidDataException, IntegrityCheckFailedException { +            InvalidDataException, IntegrityCheckFailedException, NeedNfcDataException {          // automatically works with ascii armor input and binary          InputStream in = PGPUtil.getDecoderStream(mData.getInputStream());          if (in instanceof ArmoredInputStream) { @@ -223,7 +233,7 @@ public class PgpDecryptVerify {      private PgpDecryptVerifyResult decryptVerify(InputStream in)              throws IOException, PGPException, SignatureException,              WrongPassphraseException, KeyExtractionException, NoSecretKeyException, -            InvalidDataException, IntegrityCheckFailedException { +            InvalidDataException, IntegrityCheckFailedException, NeedNfcDataException {          PgpDecryptVerifyResult result = new PgpDecryptVerifyResult();          PGPObjectFactory pgpF = new PGPObjectFactory(in, new JcaKeyFingerprintCalculator()); @@ -370,7 +380,11 @@ public class PgpDecryptVerify {              updateProgress(R.string.progress_preparing_streams, currentProgress, 100);              PublicKeyDataDecryptorFactory decryptorFactory = secretEncryptionKey.getDecryptorFactory(); -            clear = encryptedDataAsymmetric.getDataStream(decryptorFactory); +            try { +                clear = encryptedDataAsymmetric.getDataStream(decryptorFactory); +            } catch (NfcPublicKeyDataDecryptorFactoryBuilder.NfcInteractionNeeded e) { +                throw new NeedNfcDataException(e.dec); +            }              encryptedData = encryptedDataAsymmetric;          } else {              // no packet has been found where we have the corresponding secret key in our db 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 00a9dc8f1..3b4559cf2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -155,15 +155,38 @@ public class OpenPgpService extends RemoteService {          }      } -    private Intent getNfcIntent(Intent data, byte[] hashToSign, int hashAlgo) { +    private Intent getNfcSignIntent(Intent data, String pin, byte[] hashToSign, int hashAlgo) {          // build PendingIntent for Yubikey NFC operations          Intent intent = new Intent(getBaseContext(), NfcActivity.class);          intent.setAction(NfcActivity.ACTION_SIGN_HASH); +        // pass params through to activity that it can be returned again later to repeat pgp operation +        intent.putExtra(NfcActivity.EXTRA_DATA, data); +        intent.putExtra(NfcActivity.EXTRA_PIN, pin); +          intent.putExtra(NfcActivity.EXTRA_NFC_HASH_TO_SIGN, hashToSign);          intent.putExtra(NfcActivity.EXTRA_NFC_HASH_ALGO, hashAlgo);          intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); +        PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0, +                intent, +                PendingIntent.FLAG_CANCEL_CURRENT); + +        // return PendingIntent to be executed by client +        Intent result = new Intent(); +        result.putExtra(OpenPgpApi.RESULT_INTENT, pi); +        result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); +        return result; +    } + +    private Intent getNfcDecryptIntent(Intent data, String pin, byte[] dec) { +        // build PendingIntent for Yubikey NFC operations +        Intent intent = new Intent(getBaseContext(), NfcActivity.class); +        intent.setAction(NfcActivity.ACTION_DECRYPT_SESSION_KEY);          // pass params through to activity that it can be returned again later to repeat pgp operation          intent.putExtra(NfcActivity.EXTRA_DATA, data); +        intent.putExtra(NfcActivity.EXTRA_PIN, pin); + +        intent.putExtra(NfcActivity.EXTRA_NFC_DEC, dec); +        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);          PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,                  intent,                  PendingIntent.FLAG_CANCEL_CURRENT); @@ -257,7 +280,7 @@ public class OpenPgpService extends RemoteService {                      // 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, e.mCreationTimestamp.getTime()); -                    return getNfcIntent(data, e.mHashToSign, e.mHashAlgo); +                    return getNfcSignIntent(data, passphrase, e.mHashToSign, e.mHashAlgo);                  }              } finally {                  is.close(); @@ -322,8 +345,8 @@ public class OpenPgpService extends RemoteService {                          .setOriginalFilename(originalFilename)                          .setAdditionalEncryptId(accSettings.getKeyId()); // add acc key for encryption +                String passphrase = null;                  if (sign) { -                    String passphrase;                      if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) {                          passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);                      } else { @@ -359,7 +382,7 @@ public class OpenPgpService extends RemoteService {                      // 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, e.mCreationTimestamp.getTime()); -                    return getNfcIntent(data, e.mHashToSign, e.mHashAlgo); +                    return getNfcSignIntent(data, passphrase, e.mHashToSign, e.mHashAlgo);                  }              } finally {                  is.close(); @@ -439,6 +462,9 @@ public class OpenPgpService extends RemoteService {                      throw new Exception(getString(R.string.error_no_secret_key_found));                  } catch (PgpDecryptVerify.IntegrityCheckFailedException e) {                      throw new Exception(getString(R.string.error_integrity_check_failed)); +                } catch (PgpDecryptVerify.NeedNfcDataException e) { +                    // return PendingIntent to execute NFC activity +                    return getNfcDecryptIntent(data, passphrase, e.mDec);                  }                  if (PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index a5b672e7e..b9746aee5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -697,7 +697,8 @@ public class KeychainIntentService extends IntentService implements Progressable                  if (!certificationKey.unlock(signaturePassphrase)) {                      throw new PgpGeneralException("Error extracting key (bad passphrase?)");                  } -                UncachedKeyRing newRing = certificationKey.certifyUserIds(publicRing, userIds); +                // TODO: supply nfc stuff +                UncachedKeyRing newRing = certificationKey.certifyUserIds(publicRing, userIds, null, null);                  // store the signed key in our local cache                  providerHelper.savePublicKeyRing(newRing); | 
