yubikey certifications!

This commit is contained in:
Vincent Breitmoser
2015-03-18 21:12:31 +01:00
parent aca54e31ea
commit d46fc3740b
15 changed files with 476 additions and 241 deletions

View File

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

View File

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

View File

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