From d46fc3740bbfc3bac0b1133a3e9d47c7ce3e06e2 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 18 Mar 2015 21:12:31 +0100 Subject: yubikey certifications! --- .../keychain/pgp/CanonicalizedSecretKey.java | 151 +++------------------ .../keychain/pgp/PgpCertifyOperation.java | 149 ++++++++++++++++++++ .../keychain/pgp/PgpSignEncryptOperation.java | 4 +- 3 files changed, 170 insertions(+), 134 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpCertifyOperation.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') 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 df409902f..c4d0d488e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java @@ -202,8 +202,26 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey { } } - public PGPSignatureGenerator getSignatureGenerator(int hashAlgo, boolean cleartext, - Map signedHashes, Date creationTimestamp) + public PGPSignatureGenerator getCertSignatureGenerator(Map signedHashes) { + PGPContentSignerBuilder contentSignerBuilder = getContentSignerBuilder( + PgpConstants.CERTIFY_HASH_ALGO, signedHashes); + + if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) { + throw new PrivateKeyNotUnlockedException(); + } + + PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder); + try { + signatureGenerator.init(PGPSignature.DEFAULT_CERTIFICATION, mPrivateKey); + return signatureGenerator; + } catch (PGPException e) { + Log.e(Constants.TAG, "signing error", e); + return null; + } + } + + public PGPSignatureGenerator getDataSignatureGenerator(int hashAlgo, boolean cleartext, + Map signedHashes, Date creationTimestamp) throws PgpGeneralException { if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) { throw new PrivateKeyNotUnlockedException(); @@ -259,135 +277,6 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey { } } - /** - * Certify the given pubkeyid with the given masterkeyid. - * - * @param publicKeyRing Keyring to add certification to. - * @param userIds User IDs to certify - * @return A keyring with added certifications - */ - public UncachedKeyRing certifyUserIds(CanonicalizedPublicKeyRing publicKeyRing, - List userIds, - HashMap signedHashes, Date creationTimestamp) { - if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) { - throw new PrivateKeyNotUnlockedException(); - } - if (!isMasterKey()) { - throw new AssertionError("tried to certify with non-master key, this is a programming error!"); - } - if (publicKeyRing.getMasterKeyId() == getKeyId()) { - throw new AssertionError("key tried to self-certify, this is a programming error!"); - } - - // create a signatureGenerator from the supplied masterKeyId and passphrase - PGPSignatureGenerator signatureGenerator; - { - PGPContentSignerBuilder contentSignerBuilder = getContentSignerBuilder( - PgpConstants.CERTIFY_HASH_ALGO, signedHashes); - - signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder); - try { - signatureGenerator.init(PGPSignature.DEFAULT_CERTIFICATION, mPrivateKey); - } catch (PGPException e) { - Log.e(Constants.TAG, "signing error", e); - return null; - } - } - - { // supply signatureGenerator with a SubpacketVector - PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); - if (creationTimestamp != null) { - spGen.setSignatureCreationTime(false, creationTimestamp); - Log.d(Constants.TAG, "For NFC: set sig creation time to " + creationTimestamp); - } - PGPSignatureSubpacketVector packetVector = spGen.generate(); - signatureGenerator.setHashedSubpackets(packetVector); - } - - // get the master subkey (which we certify for) - PGPPublicKey publicKey = publicKeyRing.getPublicKey().getPublicKey(); - - // fetch public key ring, add the certification and return it - try { - for (String userId : userIds) { - PGPSignature sig = signatureGenerator.generateCertification(userId, publicKey); - publicKey = PGPPublicKey.addCertification(publicKey, userId, sig); - } - } catch (PGPException e) { - Log.e(Constants.TAG, "signing error", e); - return null; - } - - PGPPublicKeyRing ring = PGPPublicKeyRing.insertPublicKey(publicKeyRing.getRing(), publicKey); - - return new UncachedKeyRing(ring); - } - - /** - * Certify the given user attributes with the given masterkeyid. - * - * @param publicKeyRing Keyring to add certification to. - * @param userAttributes User IDs to certify, or all if null - * @return A keyring with added certifications - */ - public UncachedKeyRing certifyUserAttributes(CanonicalizedPublicKeyRing publicKeyRing, - List userAttributes, - HashMap signedHashes, Date creationTimestamp) { - if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) { - throw new PrivateKeyNotUnlockedException(); - } - if (!isMasterKey()) { - throw new AssertionError("tried to certify with non-master key, this is a programming error!"); - } - if (publicKeyRing.getMasterKeyId() == getKeyId()) { - throw new AssertionError("key tried to self-certify, this is a programming error!"); - } - - // create a signatureGenerator from the supplied masterKeyId and passphrase - PGPSignatureGenerator signatureGenerator; - { - PGPContentSignerBuilder contentSignerBuilder = getContentSignerBuilder( - PgpConstants.CERTIFY_HASH_ALGO, signedHashes); - - signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder); - try { - signatureGenerator.init(PGPSignature.DEFAULT_CERTIFICATION, mPrivateKey); - } catch (PGPException e) { - Log.e(Constants.TAG, "signing error", e); - return null; - } - } - - { // supply signatureGenerator with a SubpacketVector - PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); - if (creationTimestamp != null) { - spGen.setSignatureCreationTime(false, creationTimestamp); - Log.d(Constants.TAG, "For NFC: set sig creation time to " + creationTimestamp); - } - PGPSignatureSubpacketVector packetVector = spGen.generate(); - signatureGenerator.setHashedSubpackets(packetVector); - } - - // get the master subkey (which we certify for) - PGPPublicKey publicKey = publicKeyRing.getPublicKey().getPublicKey(); - - // fetch public key ring, add the certification and return it - try { - for (WrappedUserAttribute userAttribute : userAttributes) { - PGPUserAttributeSubpacketVector vector = userAttribute.getVector(); - PGPSignature sig = signatureGenerator.generateCertification(vector, publicKey); - publicKey = PGPPublicKey.addCertification(publicKey, vector, sig); - } - } catch (PGPException e) { - Log.e(Constants.TAG, "signing error", e); - return null; - } - - PGPPublicKeyRing ring = PGPPublicKeyRing.insertPublicKey(publicKeyRing.getRing(), publicKey); - - return new UncachedKeyRing(ring); - } - static class PrivateKeyNotUnlockedException extends RuntimeException { // this exception is a programming error which happens when an operation which requires // the private key is called without a previous call to unlock() diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpCertifyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpCertifyOperation.java new file mode 100644 index 000000000..3c9daadbb --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpCertifyOperation.java @@ -0,0 +1,149 @@ +package org.sufficientlysecure.keychain.pgp; + + +import java.nio.ByteBuffer; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPSignature; +import org.spongycastle.openpgp.PGPSignatureGenerator; +import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator; +import org.spongycastle.openpgp.PGPSignatureSubpacketVector; +import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector; +import org.spongycastle.openpgp.operator.jcajce.NfcSyncPGPContentSignerBuilder.NfcInteractionNeeded; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; +import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction; +import org.sufficientlysecure.keychain.service.input.NfcOperationsParcel; +import org.sufficientlysecure.keychain.service.input.NfcOperationsParcel.NfcSignOperationsBuilder; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.Log; + + +public class PgpCertifyOperation { + + public PgpCertifyResult certify( + CanonicalizedSecretKey secretKey, + CanonicalizedPublicKeyRing publicRing, + OperationLog log, + int indent, + CertifyAction action, + Map signedHashes, + Date creationTimestamp) { + + if (!secretKey.isMasterKey()) { + throw new AssertionError("tried to certify with non-master key, this is a programming error!"); + } + if (publicRing.getMasterKeyId() == secretKey.getKeyId()) { + throw new AssertionError("key tried to self-certify, this is a programming error!"); + } + + // create a signatureGenerator from the supplied masterKeyId and passphrase + PGPSignatureGenerator signatureGenerator = secretKey.getCertSignatureGenerator(signedHashes); + + { // supply signatureGenerator with a SubpacketVector + PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); + if (creationTimestamp != null) { + spGen.setSignatureCreationTime(false, creationTimestamp); + Log.d(Constants.TAG, "For NFC: set sig creation time to " + creationTimestamp); + } + PGPSignatureSubpacketVector packetVector = spGen.generate(); + signatureGenerator.setHashedSubpackets(packetVector); + } + + // get the master subkey (which we certify for) + PGPPublicKey publicKey = publicRing.getPublicKey().getPublicKey(); + + NfcSignOperationsBuilder requiredInput = new NfcSignOperationsBuilder(creationTimestamp); + + try { + if (action.mUserIds != null) { + log.add(LogType.MSG_CRT_CERTIFY_UIDS, 2, action.mUserIds.size(), + KeyFormattingUtils.convertKeyIdToHex(action.mMasterKeyId)); + + // fetch public key ring, add the certification and return it + for (String userId : action.mUserIds) { + try { + PGPSignature sig = signatureGenerator.generateCertification(userId, publicKey); + publicKey = PGPPublicKey.addCertification(publicKey, userId, sig); + } catch (NfcInteractionNeeded e) { + requiredInput.addHash(e.hashToSign, e.hashAlgo); + } + } + + } + + if (action.mUserAttributes != null) { + log.add(LogType.MSG_CRT_CERTIFY_UATS, 2, action.mUserAttributes.size(), + KeyFormattingUtils.convertKeyIdToHex(action.mMasterKeyId)); + + // fetch public key ring, add the certification and return it + for (WrappedUserAttribute userAttribute : action.mUserAttributes) { + PGPUserAttributeSubpacketVector vector = userAttribute.getVector(); + try { + PGPSignature sig = signatureGenerator.generateCertification(vector, publicKey); + publicKey = PGPPublicKey.addCertification(publicKey, vector, sig); + } catch (NfcInteractionNeeded e) { + requiredInput.addHash(e.hashToSign, e.hashAlgo); + } + } + + } + } catch (PGPException e) { + Log.e(Constants.TAG, "signing error", e); + return new PgpCertifyResult(); + } + + if (!requiredInput.isEmpty()) { + return new PgpCertifyResult(requiredInput.build()); + } + + PGPPublicKeyRing ring = PGPPublicKeyRing.insertPublicKey(publicRing.getRing(), publicKey); + return new PgpCertifyResult(new UncachedKeyRing(ring)); + + } + + public static class PgpCertifyResult { + + final NfcOperationsParcel mRequiredInput; + final UncachedKeyRing mCertifiedRing; + + PgpCertifyResult() { + mRequiredInput = null; + mCertifiedRing = null; + } + + PgpCertifyResult(NfcOperationsParcel requiredInput) { + mRequiredInput = requiredInput; + mCertifiedRing = null; + } + + PgpCertifyResult(UncachedKeyRing certifiedRing) { + mRequiredInput = null; + mCertifiedRing = certifiedRing; + } + + public boolean success() { + return mCertifiedRing != null || mRequiredInput != null; + } + + public boolean nfcInputRequired() { + return mRequiredInput != null; + } + + public UncachedKeyRing getCertifiedRing() { + return mCertifiedRing; + } + + public NfcOperationsParcel getRequiredInput() { + return mRequiredInput; + } + + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java index 2e515137a..7253d9b18 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java @@ -44,8 +44,6 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; -import org.sufficientlysecure.keychain.service.input.NfcOperationsParcel; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; @@ -283,7 +281,7 @@ public class PgpSignEncryptOperation extends BaseOperation { try { boolean cleartext = input.isCleartextSignature() && input.isEnableAsciiArmorOutput() && !enableEncryption; - signatureGenerator = signingKey.getSignatureGenerator( + signatureGenerator = signingKey.getDataSignatureGenerator( input.getSignatureHashAlgorithm(), cleartext, input.getCryptoData(), input.getSignatureTime()); } catch (PgpGeneralException e) { -- cgit v1.2.3