Fix some runtime bugs

This commit is contained in:
Paul Schaub 2018-06-14 16:02:53 +02:00
parent 422baa6d2e
commit 800955d5a8
6 changed files with 105 additions and 18 deletions

View File

@ -66,6 +66,9 @@ public abstract class AbstractPainlessOpenPgpStore implements PainlessOpenPgpSto
} }
byte[] bytes = loadPublicKeyRingBytes(owner); byte[] bytes = loadPublicKeyRingBytes(owner);
if (bytes == null) {
return null;
}
keyRing = new PGPPublicKeyRingCollection(bytes, fingerprintCalculator); keyRing = new PGPPublicKeyRingCollection(bytes, fingerprintCalculator);
publicKeyRings.put(owner, keyRing); publicKeyRings.put(owner, keyRing);
@ -81,6 +84,9 @@ public abstract class AbstractPainlessOpenPgpStore implements PainlessOpenPgpSto
} }
byte[] bytes = loadSecretKeyRingBytes(owner); byte[] bytes = loadSecretKeyRingBytes(owner);
if (bytes == null) {
return null;
}
keyRing = new PGPSecretKeyRingCollection(bytes, fingerprintCalculator); keyRing = new PGPSecretKeyRingCollection(bytes, fingerprintCalculator);
secretKeyRings.put(owner, keyRing); secretKeyRings.put(owner, keyRing);

View File

@ -27,6 +27,7 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.file.Files; import java.nio.file.Files;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@ -160,7 +161,7 @@ public class FileBasedPainlessOpenPgpStore extends AbstractPainlessOpenPgpStore
Set<OpenPgpV4Fingerprint> fingerprints = new HashSet<>(); Set<OpenPgpV4Fingerprint> fingerprints = new HashSet<>();
try { try {
PGPSecretKeyRingCollection secretKeys = getSecretKeyRings(owner); PGPSecretKeyRingCollection secretKeys = getSecretKeyRings(owner);
for (PGPSecretKeyRing s : secretKeys) { for (PGPSecretKeyRing s : secretKeys != null ? secretKeys : Collections.<PGPSecretKeyRing>emptySet()) {
fingerprints.add(PainlessOpenPgpProvider.getFingerprint(s.getPublicKey())); fingerprints.add(PainlessOpenPgpProvider.getFingerprint(s.getPublicKey()));
} }
} catch (IOException | PGPException e) { } catch (IOException | PGPException e) {
@ -176,7 +177,7 @@ public class FileBasedPainlessOpenPgpStore extends AbstractPainlessOpenPgpStore
try { try {
PGPPublicKeyRingCollection publicKeys = getPublicKeyRings(contact); PGPPublicKeyRingCollection publicKeys = getPublicKeyRings(contact);
Set<OpenPgpV4Fingerprint> fingerprints = new HashSet<>(); Set<OpenPgpV4Fingerprint> fingerprints = new HashSet<>();
for (PGPPublicKeyRing ring : publicKeys) { for (PGPPublicKeyRing ring : publicKeys != null ? publicKeys : Collections.<PGPPublicKeyRing>emptySet()) {
OpenPgpV4Fingerprint fingerprint = PainlessOpenPgpProvider.getFingerprint(ring.getPublicKey()); OpenPgpV4Fingerprint fingerprint = PainlessOpenPgpProvider.getFingerprint(ring.getPublicKey());
fingerprints.add(fingerprint); fingerprints.add(fingerprint);
} }
@ -252,8 +253,8 @@ public class FileBasedPainlessOpenPgpStore extends AbstractPainlessOpenPgpStore
LOGGER.log(Level.WARNING, "Encountered illegal line in file " + LOGGER.log(Level.WARNING, "Encountered illegal line in file " +
file.getAbsolutePath() + ": " + lineNr, e); file.getAbsolutePath() + ": " + lineNr, e);
} }
reader.close();
} }
reader.close();
} catch (IOException e) { } catch (IOException e) {
LOGGER.log(Level.WARNING, "Could not read fingerprints and dates from file " + file.getAbsolutePath(), e); LOGGER.log(Level.WARNING, "Could not read fingerprints and dates from file " + file.getAbsolutePath(), e);
if (reader != null) { if (reader != null) {
@ -379,7 +380,7 @@ public class FileBasedPainlessOpenPgpStore extends AbstractPainlessOpenPgpStore
} }
private File getContactsPath(BareJid owner, boolean create) throws IOException { private File getContactsPath(BareJid owner, boolean create) throws IOException {
File path = new File(getContactsPath(create) + owner.toString()); File path = new File(getContactsPath(create), owner.toString());
if (create && !path.exists()) { if (create && !path.exists()) {
createDirectoryOrThrow(path); createDirectoryOrThrow(path);
} }

View File

@ -24,12 +24,15 @@ import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException; import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException; import java.security.NoSuchProviderException;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
import java.util.Set; import java.util.Set;
import org.jivesoftware.smack.util.MultiMap; import org.jivesoftware.smack.util.MultiMap;
import org.jivesoftware.smackx.ox.OpenPgpProvider; import org.jivesoftware.smackx.ox.OpenPgpProvider;
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
import org.jivesoftware.smackx.ox.bouncycastle.selection_strategy.BareJidUserId;
import org.jivesoftware.smackx.ox.callback.SmackMissingOpenPgpPublicKeyCallback; import org.jivesoftware.smackx.ox.callback.SmackMissingOpenPgpPublicKeyCallback;
import org.jivesoftware.smackx.ox.element.CryptElement; import org.jivesoftware.smackx.ox.element.CryptElement;
import org.jivesoftware.smackx.ox.element.SignElement; import org.jivesoftware.smackx.ox.element.SignElement;
@ -46,11 +49,14 @@ import de.vanitasvitae.crypto.pgpainless.decryption_verification.DecryptionStrea
import de.vanitasvitae.crypto.pgpainless.decryption_verification.MissingPublicKeyCallback; import de.vanitasvitae.crypto.pgpainless.decryption_verification.MissingPublicKeyCallback;
import de.vanitasvitae.crypto.pgpainless.decryption_verification.PainlessResult; import de.vanitasvitae.crypto.pgpainless.decryption_verification.PainlessResult;
import de.vanitasvitae.crypto.pgpainless.key.generation.type.length.RsaLength; import de.vanitasvitae.crypto.pgpainless.key.generation.type.length.RsaLength;
import de.vanitasvitae.crypto.pgpainless.util.BCUtil;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyRing; import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator;
import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.io.Streams; import org.bouncycastle.util.io.Streams;
import org.jxmpp.jid.BareJid; import org.jxmpp.jid.BareJid;
@ -72,7 +78,7 @@ public class PainlessOpenPgpProvider implements OpenPgpProvider {
throws MissingOpenPgpKeyPairException, MissingOpenPgpPublicKeyException, SmackOpenPgpException, throws MissingOpenPgpKeyPairException, MissingOpenPgpPublicKeyException, SmackOpenPgpException,
IOException { IOException {
Set<PGPPublicKeyRing> allRecipientsKeys = getEncryptionKeys(encryptionKeys); PGPPublicKeyRing[] validEncryptionKeys = getEncryptionKeys(encryptionKeys);
PGPSecretKeyRing signingKeyRing = getSigningKey(signingKey); PGPSecretKeyRing signingKeyRing = getSigningKey(signingKey);
InputStream fromPlain = element.toInputStream(); InputStream fromPlain = element.toInputStream();
@ -81,7 +87,7 @@ public class PainlessOpenPgpProvider implements OpenPgpProvider {
try { try {
encryptor = PGPainless.createEncryptor() encryptor = PGPainless.createEncryptor()
.onOutputStream(encrypted) .onOutputStream(encrypted)
.toRecipients((PGPPublicKeyRing[]) allRecipientsKeys.toArray()) .toRecipients(validEncryptionKeys)
.usingSecureAlgorithms() .usingSecureAlgorithms()
.signWith(store.getSecretKeyProtector(), signingKeyRing) .signWith(store.getSecretKeyProtector(), signingKeyRing)
.noArmor(); .noArmor();
@ -129,7 +135,7 @@ public class PainlessOpenPgpProvider implements OpenPgpProvider {
@Override @Override
public byte[] encrypt(CryptElement element, MultiMap<BareJid, OpenPgpV4Fingerprint> encryptionKeyFingerprints) public byte[] encrypt(CryptElement element, MultiMap<BareJid, OpenPgpV4Fingerprint> encryptionKeyFingerprints)
throws MissingOpenPgpPublicKeyException, IOException, SmackOpenPgpException { throws MissingOpenPgpPublicKeyException, IOException, SmackOpenPgpException {
Set<PGPPublicKeyRing> allRecipientsKeys = getEncryptionKeys(encryptionKeyFingerprints); PGPPublicKeyRing[] allRecipientsKeys = getEncryptionKeys(encryptionKeyFingerprints);
InputStream fromPlain = element.toInputStream(); InputStream fromPlain = element.toInputStream();
ByteArrayOutputStream encrypted = new ByteArrayOutputStream(); ByteArrayOutputStream encrypted = new ByteArrayOutputStream();
@ -137,7 +143,7 @@ public class PainlessOpenPgpProvider implements OpenPgpProvider {
try { try {
encryptor = PGPainless.createEncryptor() encryptor = PGPainless.createEncryptor()
.onOutputStream(encrypted) .onOutputStream(encrypted)
.toRecipients((PGPPublicKeyRing[]) allRecipientsKeys.toArray()) .toRecipients(allRecipientsKeys)
.usingSecureAlgorithms() .usingSecureAlgorithms()
.doNotSign() .doNotSign()
.noArmor(); .noArmor();
@ -210,7 +216,7 @@ public class PainlessOpenPgpProvider implements OpenPgpProvider {
return store; return store;
} }
private Set<PGPPublicKeyRing> getEncryptionKeys(MultiMap<BareJid, OpenPgpV4Fingerprint> encryptionKeys) private PGPPublicKeyRing[] getEncryptionKeys(MultiMap<BareJid, OpenPgpV4Fingerprint> encryptionKeys)
throws IOException, SmackOpenPgpException { throws IOException, SmackOpenPgpException {
Set<PGPPublicKeyRing> allRecipientsKeys = new HashSet<>(); Set<PGPPublicKeyRing> allRecipientsKeys = new HashSet<>();
@ -227,7 +233,13 @@ public class PainlessOpenPgpProvider implements OpenPgpProvider {
} }
} }
return allRecipientsKeys; PGPPublicKeyRing[] allEncryptionKeys = new PGPPublicKeyRing[allRecipientsKeys.size()];
Iterator<PGPPublicKeyRing> iterator = allRecipientsKeys.iterator();
for (int i = 0; i < allEncryptionKeys.length; i++) {
allEncryptionKeys[i] = iterator.next();
}
return allEncryptionKeys;
} }
private PGPSecretKeyRing getSigningKey(OpenPgpV4Fingerprint signingKey) private PGPSecretKeyRing getSigningKey(OpenPgpV4Fingerprint signingKey)
@ -256,13 +268,66 @@ public class PainlessOpenPgpProvider implements OpenPgpProvider {
} }
@Override @Override
public OpenPgpV4Fingerprint importPublicKey(BareJid owner, byte[] bytes) throws MissingUserIdOnKeyException { public OpenPgpV4Fingerprint importPublicKey(BareJid owner, byte[] bytes)
return null; throws MissingUserIdOnKeyException, IOException, SmackOpenPgpException {
PGPPublicKeyRing publicKeys = new PGPPublicKeyRing(bytes, new BcKeyFingerprintCalculator());
return importPublicKey(owner, publicKeys);
}
public OpenPgpV4Fingerprint importPublicKey(BareJid owner, PGPPublicKeyRing ring)
throws SmackOpenPgpException, IOException, MissingUserIdOnKeyException {
if (!new BareJidUserId.PubRingSelectionStrategy().accept(owner, ring)) {
throw new MissingUserIdOnKeyException(owner, ring.getPublicKey().getKeyID());
}
try {
PGPPublicKeyRingCollection publicKeyRings = getStore().getPublicKeyRings(owner);
if (publicKeyRings == null) {
publicKeyRings = new PGPPublicKeyRingCollection(Collections.singleton(ring));
} else {
publicKeyRings = PGPPublicKeyRingCollection.addPublicKeyRing(publicKeyRings, ring);
}
getStore().storePublicKeyRing(owner, publicKeyRings);
} catch (PGPException e) {
throw new SmackOpenPgpException(e);
}
return getFingerprint(ring.getPublicKey());
} }
@Override @Override
public OpenPgpV4Fingerprint importSecretKey(BareJid owner, byte[] bytes) throws MissingUserIdOnKeyException { public OpenPgpV4Fingerprint importSecretKey(BareJid owner, byte[] bytes)
return null; throws MissingUserIdOnKeyException, SmackOpenPgpException, IOException {
PGPSecretKeyRing secretKeys;
try {
secretKeys = new PGPSecretKeyRing(bytes, new BcKeyFingerprintCalculator());
} catch (PGPException | IOException e) {
throw new SmackOpenPgpException("Could not deserialize PGP secret key of " + owner.toString(), e);
}
if (!new BareJidUserId.SecRingSelectionStrategy().accept(owner, secretKeys)) {
throw new MissingUserIdOnKeyException(owner, secretKeys.getPublicKey().getKeyID());
}
PGPSecretKeyRingCollection secretKeyRings;
try {
secretKeyRings = getStore().getSecretKeyRings(owner);
} catch (PGPException | IOException e) {
throw new SmackOpenPgpException("Could not load secret key ring of " + owner.toString(), e);
}
if (secretKeyRings == null) {
try {
secretKeyRings = new PGPSecretKeyRingCollection(Collections.singleton(secretKeys));
} catch (IOException | PGPException e) {
throw new SmackOpenPgpException("Could not create SecretKeyRingCollection from SecretKeyRing.", e);
}
} else {
secretKeyRings = PGPSecretKeyRingCollection.addSecretKeyRing(secretKeyRings, secretKeys);
}
getStore().storeSecretKeyRing(owner, secretKeyRings);
PGPPublicKeyRing publicKeys = BCUtil.publicKeyRingFromSecretKeyRing(secretKeys);
importPublicKey(owner, publicKeys);
return getFingerprint(publicKeys.getPublicKey());
} }
public static OpenPgpV4Fingerprint getFingerprint(PGPPublicKey publicKey) { public static OpenPgpV4Fingerprint getFingerprint(PGPPublicKey publicKey) {

View File

@ -317,14 +317,18 @@ public final class OpenPgpManager extends Manager {
if (pubkeyElement == null) { if (pubkeyElement == null) {
continue; continue;
} }
processPublicKey(pubkeyElement, jid); processPublicKey(pubkeyElement, jid);
available.add(f); available.add(f);
} catch (PubSubException.NotAPubSubNodeException | PubSubException.NotALeafNodeException e) { } catch (PubSubException.NotAPubSubNodeException | PubSubException.NotALeafNodeException e) {
LOGGER.log(Level.WARNING, "Could not fetch public key " + f.toString() + " of user " + jid.toString(), e); LOGGER.log(Level.WARNING, "Could not fetch public key " + f.toString() + " of user " + jid.toString(), e);
unfetched.put(f, e); unfetched.put(f, e);
} catch (MissingUserIdOnKeyException e) { } catch (MissingUserIdOnKeyException e) {
LOGGER.log(Level.WARNING, "Key does not contain user-id of " + jid + ". Ignoring the key.", e); LOGGER.log(Level.WARNING, "Key does not contain user-id of " + jid + ". Ignoring the key.", e);
unfetched.put(f, e); unfetched.put(f, e);
} catch (IOException e) {
LOGGER.log(Level.WARNING, "Could not import key " + f.toString() + " of user " + jid.toString(), e);
} }
} }
} }
@ -382,7 +386,7 @@ public final class OpenPgpManager extends Manager {
*/ */
private void processPublicKey(PubkeyElement pubkeyElement, BareJid owner) private void processPublicKey(PubkeyElement pubkeyElement, BareJid owner)
throws MissingUserIdOnKeyException { throws MissingUserIdOnKeyException, IOException, SmackOpenPgpException {
byte[] base64 = pubkeyElement.getDataElement().getB64Data(); byte[] base64 = pubkeyElement.getDataElement().getB64Data();
provider.importPublicKey(owner, Base64.decode(base64)); provider.importPublicKey(owner, Base64.decode(base64));
} }

View File

@ -133,9 +133,11 @@ public interface OpenPgpProvider {
throws SmackOpenPgpException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, throws SmackOpenPgpException, InvalidAlgorithmParameterException, NoSuchAlgorithmException,
NoSuchProviderException, IOException; NoSuchProviderException, IOException;
OpenPgpV4Fingerprint importPublicKey(BareJid owner, byte[] bytes) throws MissingUserIdOnKeyException; OpenPgpV4Fingerprint importPublicKey(BareJid owner, byte[] bytes)
throws MissingUserIdOnKeyException, IOException, SmackOpenPgpException;
OpenPgpV4Fingerprint importSecretKey(BareJid owner, byte[] bytes) throws MissingUserIdOnKeyException; OpenPgpV4Fingerprint importSecretKey(BareJid owner, byte[] bytes)
throws MissingUserIdOnKeyException, SmackOpenPgpException, IOException;
OpenPgpStore getStore(); OpenPgpStore getStore();
} }

View File

@ -24,6 +24,7 @@ import java.util.logging.Logger;
import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.StanzaError;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint; import org.jivesoftware.smackx.ox.OpenPgpV4Fingerprint;
import org.jivesoftware.smackx.ox.element.PubkeyElement; import org.jivesoftware.smackx.ox.element.PubkeyElement;
@ -205,7 +206,15 @@ public class PubSubDelegate {
throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException,
SmackException.NoResponseException { SmackException.NoResponseException {
PubSubManager pm = PubSubManager.getInstance(connection, connection.getUser().asBareJid()); PubSubManager pm = PubSubManager.getInstance(connection, connection.getUser().asBareJid());
pm.deleteNode(PEP_NODE_PUBLIC_KEYS); try {
pm.deleteNode(PEP_NODE_PUBLIC_KEYS);
} catch (XMPPException.XMPPErrorException e) {
if (e.getXMPPError().getCondition() == StanzaError.Condition.item_not_found) {
LOGGER.log(Level.FINE, "Node does not exist. No need to delete it.");
} else {
throw e;
}
}
} }
/** /**