yubikey certifications!
This commit is contained in:
@@ -202,8 +202,26 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
|
||||
}
|
||||
}
|
||||
|
||||
public PGPSignatureGenerator getSignatureGenerator(int hashAlgo, boolean cleartext,
|
||||
Map<ByteBuffer,byte[]> signedHashes, Date creationTimestamp)
|
||||
public PGPSignatureGenerator getCertSignatureGenerator(Map<ByteBuffer, byte[]> 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<ByteBuffer, byte[]> 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<String> userIds,
|
||||
HashMap<ByteBuffer,byte[]> 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<WrappedUserAttribute> userAttributes,
|
||||
HashMap<ByteBuffer,byte[]> 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()
|
||||
|
||||
@@ -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<ByteBuffer,byte[]> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user