From cdba5bdda99c4c09d84b434241d9771be1002184 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Wed, 20 Jun 2018 12:45:05 +0200 Subject: [PATCH] improve tests --- .../FileBasedPainlessOpenPgpStore.java | 9 +-- .../ox/bouncycastle/DryOxEncryptionTest.java | 24 +++--- .../FileBasedPainlessOpenPgpStoreTest.java | 31 +++----- .../smackx/ox/bouncycastle/UserIdTest.java | 75 +++++++++++++++++++ .../smackx/ox/OXInstantMessagingManager.java | 2 +- .../smackx/ox/OpenPgpManager.java | 3 +- .../smackx/ox/chat/OpenPgpContact.java | 64 ++++++++++++---- 7 files changed, 152 insertions(+), 56 deletions(-) create mode 100644 smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/UserIdTest.java diff --git a/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/FileBasedPainlessOpenPgpStore.java b/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/FileBasedPainlessOpenPgpStore.java index 862b13272..ab1eff36a 100644 --- a/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/FileBasedPainlessOpenPgpStore.java +++ b/smack-openpgp-bouncycastle/src/main/java/org/jivesoftware/smackx/ox/bouncycastle/FileBasedPainlessOpenPgpStore.java @@ -75,7 +75,7 @@ public class FileBasedPainlessOpenPgpStore extends AbstractPainlessOpenPgpStore inputStream.close(); bytes = buffer.toByteArray(); } catch (FileNotFoundException e) { - LOGGER.log(Level.INFO, "Pubring of user " + owner.toString() + " does not exist."); + LOGGER.log(Level.FINE, "Pubring of user " + owner.toString() + " does not exist."); return null; } catch (IOException e) { if (inputStream != null) { @@ -101,7 +101,7 @@ public class FileBasedPainlessOpenPgpStore extends AbstractPainlessOpenPgpStore inputStream.close(); bytes = buffer.toByteArray(); } catch (FileNotFoundException e) { - LOGGER.log(Level.INFO, "Secring of user " + owner.toString() + " does not exist."); + LOGGER.log(Level.FINE, "Secring of user " + owner.toString() + " does not exist."); return null; } catch (IOException e) { if (inputStream != null) { @@ -190,7 +190,7 @@ public class FileBasedPainlessOpenPgpStore extends AbstractPainlessOpenPgpStore } } catch (PGPException | IOException e) { - LOGGER.log(Level.WARNING, "Could not read public keys of contact " + contact.toString(), e); + throw new SmackOpenPgpException("Could not read public keys of contact " + contact.toString(), e); } return availableFingerprints; } @@ -298,7 +298,7 @@ public class FileBasedPainlessOpenPgpStore extends AbstractPainlessOpenPgpStore try { File contactsDir = getContactsPath(false); if (!contactsDir.exists()) { - LOGGER.log(Level.INFO, "Contacts directory does not exists yet."); + LOGGER.log(Level.FINE, "Contacts directory does not exists yet."); return trustedFingerprints; } @@ -419,7 +419,6 @@ public class FileBasedPainlessOpenPgpStore extends AbstractPainlessOpenPgpStore return file; } - private static void createDirectoryOrThrow(File dir) throws IOException { if (!dir.mkdirs()) { throw new IOException("Could not create directory \"" + dir.getAbsolutePath() + "\""); diff --git a/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/DryOxEncryptionTest.java b/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/DryOxEncryptionTest.java index 9a20cef9a..9b4d811de 100644 --- a/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/DryOxEncryptionTest.java +++ b/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/DryOxEncryptionTest.java @@ -24,6 +24,7 @@ import java.security.NoSuchProviderException; import java.util.Collections; import java.util.Date; +import org.jivesoftware.smack.util.FileUtils; import org.jivesoftware.smack.util.stringencoder.Base64; import org.jivesoftware.smackx.ox.element.PubkeyElement; import org.jivesoftware.smackx.ox.exception.MissingOpenPgpPublicKeyException; @@ -33,23 +34,22 @@ import org.jivesoftware.smackx.ox.util.KeyBytesAndFingerprint; import de.vanitasvitae.crypto.pgpainless.key.UnprotectedKeysProtector; import org.bouncycastle.openpgp.PGPException; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.jxmpp.jid.BareJid; import org.jxmpp.jid.JidTestUtil; public class DryOxEncryptionTest extends OxTestSuite { - private static File getTempDir(String suffix) { - String temp = System.getProperty("java.io.tmpdir"); - if (temp == null) { - temp = "tmp"; - } + private final File alicePath = FileUtils.getTempDir("ox-alice"); + private final File bobPath = FileUtils.getTempDir("ox-bob"); - if (suffix == null) { - return new File(temp); - } else { - return new File(temp, suffix); - } + @Before + @After + public void deletePath() { + FileUtils.deleteDirectory(alicePath); + FileUtils.deleteDirectory(bobPath); } @Test @@ -59,8 +59,6 @@ public class DryOxEncryptionTest extends OxTestSuite { BareJid alice = JidTestUtil.BARE_JID_1; BareJid bob = JidTestUtil.BARE_JID_2; - File alicePath = getTempDir("ox-alice"); - File bobPath = getTempDir("ox-bob"); FileBasedPainlessOpenPgpStore aliceStore = new FileBasedPainlessOpenPgpStore(alicePath, new UnprotectedKeysProtector()); FileBasedPainlessOpenPgpStore bobStore = new FileBasedPainlessOpenPgpStore(bobPath, new UnprotectedKeysProtector()); @@ -85,7 +83,5 @@ public class DryOxEncryptionTest extends OxTestSuite { aliceStore.setAnnouncedKeysFingerprints(bob, Collections.singletonMap(bobKey.getFingerprint(), new Date())); bobStore.setAnnouncedKeysFingerprints(alice, Collections.singletonMap(aliceKey.getFingerprint(), new Date())); - - } } diff --git a/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/FileBasedPainlessOpenPgpStoreTest.java b/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/FileBasedPainlessOpenPgpStoreTest.java index cb4c938fb..a829ef896 100644 --- a/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/FileBasedPainlessOpenPgpStoreTest.java +++ b/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/FileBasedPainlessOpenPgpStoreTest.java @@ -39,37 +39,28 @@ import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.jxmpp.jid.BareJid; -import org.jxmpp.jid.impl.JidCreate; -import org.jxmpp.stringprep.XmppStringprepException; +import org.jxmpp.jid.JidTestUtil; public class FileBasedPainlessOpenPgpStoreTest extends OxTestSuite { - private static final File basePath; - private static final BareJid alice; - private static final BareJid bob; + private final File basePath; + private final BareJid alice; + private final BareJid bob; private FileBasedPainlessOpenPgpStore store; - static { - String userHome = System.getProperty("user.home"); - if (userHome != null) { - File f = new File(userHome); - basePath = new File(f, ".config/smack-integration-test/ox/painless_ox_store"); - } else { - basePath = new File("painless_ox_store"); - } - - try { - alice = JidCreate.bareFrom("alice@wonderland.lit"); - bob = JidCreate.bareFrom("bob@builder.tv"); - } catch (XmppStringprepException e) { - throw new AssertionError(e); - } + public FileBasedPainlessOpenPgpStoreTest() { + super(); + this.basePath = FileUtils.getTempDir("ox-filebased-store-test"); + this.alice = JidTestUtil.BARE_JID_1; + this.bob = JidTestUtil.BARE_JID_2; } + @After @Before public void deleteStore() { FileUtils.deleteDirectory(basePath); diff --git a/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/UserIdTest.java b/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/UserIdTest.java new file mode 100644 index 000000000..e24e65986 --- /dev/null +++ b/smack-openpgp-bouncycastle/src/test/java/org/jivesoftware/smackx/ox/bouncycastle/UserIdTest.java @@ -0,0 +1,75 @@ +/** + * + * Copyright 2018 Paul Schaub. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jivesoftware.smackx.ox.bouncycastle; + +import java.io.File; +import java.io.IOException; +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; + +import org.jivesoftware.smack.util.FileUtils; +import org.jivesoftware.smackx.ox.exception.MissingUserIdOnKeyException; +import org.jivesoftware.smackx.ox.exception.SmackOpenPgpException; + +import de.vanitasvitae.crypto.pgpainless.PGPainless; +import de.vanitasvitae.crypto.pgpainless.key.UnprotectedKeysProtector; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPSecretKeyRing; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.jxmpp.jid.BareJid; +import org.jxmpp.jid.JidTestUtil; + +public class UserIdTest extends OxTestSuite { + + private final File path; + + public UserIdTest() { + this.path = FileUtils.getTempDir("ox-user-id-test"); + } + + @After + @Before + public void deleteDir() { + FileUtils.deleteDirectory(path); + } + + @Test + public void requireUserIdOnImportTest() + throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, + IOException, SmackOpenPgpException, MissingUserIdOnKeyException { + BareJid owner = JidTestUtil.BARE_JID_1; + FileBasedPainlessOpenPgpStore store = new FileBasedPainlessOpenPgpStore(path, new UnprotectedKeysProtector()); + PainlessOpenPgpProvider provider = new PainlessOpenPgpProvider(owner, store); + PGPSecretKeyRing ownerKey = PGPainless.generateKeyRing().simpleEcKeyRing("xmpp:" + owner.toString()); + provider.importSecretKey(owner, ownerKey.getEncoded()); + } + + @Test(expected = MissingUserIdOnKeyException.class) + public void throwOnMissingUserIdTest() + throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, + IOException, SmackOpenPgpException, MissingUserIdOnKeyException { + BareJid owner = JidTestUtil.BARE_JID_1; + BareJid stranger = JidTestUtil.BARE_JID_2; + FileBasedPainlessOpenPgpStore store = new FileBasedPainlessOpenPgpStore(path, new UnprotectedKeysProtector()); + PainlessOpenPgpProvider provider = new PainlessOpenPgpProvider(owner, store); + PGPSecretKeyRing strangerKey = PGPainless.generateKeyRing().simpleEcKeyRing("xmpp:" + stranger.toString()); + provider.importSecretKey(owner, strangerKey.getEncoded()); + } +} diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OXInstantMessagingManager.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OXInstantMessagingManager.java index 0e47ed191..954a452f1 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OXInstantMessagingManager.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OXInstantMessagingManager.java @@ -99,7 +99,7 @@ public final class OXInstantMessagingManager extends Manager implements Signcryp public boolean contactSupportsOxInstantMessaging(OpenPgpContact contact) throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException { - return contactSupportsOxInstantMessaging(contact.getJidOfChatPartner().asBareJid()); + return contactSupportsOxInstantMessaging(contact.getJid()); } public boolean addOxMessageListener(OxMessageListener listener) { diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpManager.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpManager.java index cefbfc578..8d80c0327 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpManager.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/OpenPgpManager.java @@ -244,8 +244,7 @@ public final class OpenPgpManager extends Manager { if (openPgpContact == null) { OpenPgpFingerprints theirKeys = determineContactsKeys(jid); OpenPgpFingerprints ourKeys = determineContactsKeys(connection().getUser().asBareJid()); - Chat chat = ChatManager.getInstanceFor(connection()).chatWith(jid); - openPgpContact = new OpenPgpContact(getOpenPgpProvider(), chat, ourKeys, theirKeys); + openPgpContact = new OpenPgpContact(getOpenPgpProvider(), jid, ourKeys, theirKeys); openPgpCapableContacts.put(jid, openPgpContact); } diff --git a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/chat/OpenPgpContact.java b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/chat/OpenPgpContact.java index 1489410e9..c07e63fd1 100644 --- a/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/chat/OpenPgpContact.java +++ b/smack-openpgp/src/main/java/org/jivesoftware/smackx/ox/chat/OpenPgpContact.java @@ -22,7 +22,8 @@ import java.util.Collections; import java.util.List; import org.jivesoftware.smack.SmackException; -import org.jivesoftware.smack.chat2.Chat; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.chat2.ChatManager; import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.util.MultiMap; @@ -40,44 +41,79 @@ import org.jivesoftware.smackx.ox.exception.SmackOpenPgpException; import org.jivesoftware.smackx.ox.util.DecryptedBytesAndMetadata; import org.jxmpp.jid.BareJid; -import org.jxmpp.jid.EntityBareJid; import org.jxmpp.jid.Jid; import org.xmlpull.v1.XmlPullParserException; public class OpenPgpContact { - private final Chat chat; + private final BareJid jid; private final OpenPgpFingerprints contactsFingerprints; private final OpenPgpFingerprints ourFingerprints; private final OpenPgpProvider cryptoProvider; private final OpenPgpV4Fingerprint singingKey; public OpenPgpContact(OpenPgpProvider cryptoProvider, - Chat chat, + BareJid jid, OpenPgpFingerprints ourFingerprints, OpenPgpFingerprints contactsFingerprints) { this.cryptoProvider = cryptoProvider; - this.chat = chat; + this.jid = jid; this.singingKey = cryptoProvider.getStore().getPrimaryOpenPgpKeyPairFingerprint(); this.ourFingerprints = ourFingerprints; this.contactsFingerprints = contactsFingerprints; } - public EntityBareJid getJidOfChatPartner() { - return chat.getXmppAddressOfChatPartner(); + public BareJid getJid() { + return jid; } - public OpenPgpFingerprints getContactsFingerprints() { + public OpenPgpFingerprints getFingerprints() { return contactsFingerprints; } - public void send(Message message, List payload) + public void addSignedEncryptedPayloadTo(Message message, List payload) + throws IOException, SmackOpenPgpException, MissingOpenPgpKeyPairException { + MultiMap fingerprints = oursAndRecipientFingerprints(); + + SigncryptElement preparedPayload = new SigncryptElement( + Collections.singleton(getJid()), + payload); + + OpenPgpElement encryptedPayload; + byte[] encryptedBytes; + + // Encrypt the payload + try { + encryptedBytes = cryptoProvider.signAndEncrypt( + preparedPayload, + singingKey, + fingerprints); + } catch (MissingOpenPgpPublicKeyException e) { + throw new AssertionError("Missing OpenPGP public key, even though this should not happen here.", e); + } + + encryptedPayload = new OpenPgpElement(Base64.encodeToString(encryptedBytes)); + + // Add encrypted payload to message + message.addExtension(encryptedPayload); + + // Add additional information to the message + // STOPSHIP: 20.06.18 BELOW + // TODO: Check if message already contains EME element. + message.addExtension(new ExplicitMessageEncryptionElement( + ExplicitMessageEncryptionElement.ExplicitMessageEncryptionProtocol.openpgpV0)); + StoreHint.set(message); + message.setBody("This message is encrypted using XEP-0374: OpenPGP for XMPP: Instant Messaging."); + + } + + public void send(XMPPConnection connection, Message message, List payload) throws MissingOpenPgpKeyPairException, SmackException.NotConnectedException, InterruptedException, SmackOpenPgpException, IOException { MultiMap fingerprints = oursAndRecipientFingerprints(); SigncryptElement preparedPayload = new SigncryptElement( - Collections.singleton(chat.getXmppAddressOfChatPartner()), + Collections.singleton(getJid()), payload); OpenPgpElement encryptedPayload; @@ -104,22 +140,22 @@ public class OpenPgpContact { StoreHint.set(message); message.setBody("This message is encrypted using XEP-0374: OpenPGP for XMPP: Instant Messaging."); - chat.send(message); + ChatManager.getInstanceFor(connection).chatWith(getJid().asEntityBareJidIfPossible()).send(message); } - public void send(Message message, CharSequence body) + public void send(XMPPConnection connection, Message message, CharSequence body) throws MissingOpenPgpKeyPairException, SmackException.NotConnectedException, InterruptedException, SmackOpenPgpException, IOException { List payload = new ArrayList<>(); payload.add(new Message.Body(null, body.toString())); - send(message, payload); + send(connection, message, payload); } public OpenPgpContentElement receive(OpenPgpElement element) throws XmlPullParserException, MissingOpenPgpKeyPairException, SmackOpenPgpException, IOException { byte[] decoded = Base64.decode(element.getEncryptedBase64MessageContent()); - DecryptedBytesAndMetadata decryptedBytes = cryptoProvider.decrypt(decoded, getJidOfChatPartner(), null); + DecryptedBytesAndMetadata decryptedBytes = cryptoProvider.decrypt(decoded, getJid(), null); OpenPgpMessage openPgpMessage = new OpenPgpMessage(decryptedBytes.getBytes(), new OpenPgpMessage.Metadata(decryptedBytes.getDecryptionKey(),