More ikey progress

This commit is contained in:
Paul Schaub 2020-09-02 16:40:36 +02:00
parent d9c9eff602
commit 1d4e729f4c
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
24 changed files with 401 additions and 57 deletions

View file

@ -23,20 +23,20 @@ public class MappingModule {
@Provides
@Singleton
static PeerMapping providePeerMapping() {
return new PeerMapping(provideAccountMapping());
static PeerMapping providePeerMapping(AccountMapping accountMapping) {
return new PeerMapping(accountMapping);
}
@Provides
@Singleton
static DirectChatMapping provideDirectChatMapping() {
return new DirectChatMapping(providePeerMapping());
static DirectChatMapping provideDirectChatMapping(PeerMapping peerMapping) {
return new DirectChatMapping(peerMapping);
}
@Provides
@Singleton
static GroupChatMapping provideGroupChatMapping() {
return new GroupChatMapping(provideAccountMapping());
static GroupChatMapping provideGroupChatMapping(AccountMapping accountMapping) {
return new GroupChatMapping(accountMapping);
}
@Provides

View file

@ -1,10 +1,166 @@
package org.jivesoftware.smackx.ikey;
import org.apache.xml.security.c14n.CanonicalizationException;
import org.apache.xml.security.c14n.Canonicalizer;
import org.apache.xml.security.c14n.InvalidCanonicalizerException;
import org.apache.xml.security.parser.XMLParserException;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.util.Async;
import org.jivesoftware.smackx.ikey.element.IkeyElement;
import org.jivesoftware.smackx.ikey.mechanism.IkeySignatureVerificationMechanism;
import org.jivesoftware.smackx.ikey.util.IkeyConstants;
import org.jivesoftware.smackx.ikey.util.UnsupportedSignatureAlgorithmException;
import org.jivesoftware.smackx.ikey.util.canonicalization.ElementCanonicalizer;
import org.jivesoftware.smackx.ikey.util.canonicalization.XmlSecElementCanonicalizer;
import org.jivesoftware.smackx.ikey_ox.OxIkeySignatureVerificationMechanism;
import org.jivesoftware.smackx.pep.PepEventListener;
import org.jivesoftware.smackx.pep.PepManager;
import org.jivesoftware.smackx.pubsub.LeafNode;
import org.jivesoftware.smackx.pubsub.PayloadItem;
import org.jivesoftware.smackx.pubsub.PubSubException;
import org.jivesoftware.smackx.pubsub.PubSubManager;
import org.jxmpp.jid.EntityBareJid;
import org.pgpainless.PGPainless;
public class IkeyManager {
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
private IkeySignatureVerificationMechanism getSignatureMechanismFor(EntityBareJid contactJid) {
return null;
public final class IkeyManager extends Manager {
private static final Map<XMPPConnection, IkeyManager> INSTANCES = new WeakHashMap<>();
private IkeyStore store;
private final ElementCanonicalizer canonicalizer;
private IkeyManager(XMPPConnection connection) {
super(connection);
try {
this.canonicalizer = new XmlSecElementCanonicalizer(Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N11_OMIT_COMMENTS));
} catch (InvalidCanonicalizerException e) {
throw new AssertionError(e);
}
}
public static synchronized IkeyManager getInstanceFor(XMPPConnection connection) {
IkeyManager manager = INSTANCES.get(connection);
if (manager == null) {
manager = new IkeyManager(connection);
INSTANCES.put(connection, manager);
}
return manager;
}
public void startListeners() {
PepManager.getInstanceFor(connection())
.addPepEventListener(IkeyConstants.IKEY_NODE, IkeyElement.class, pepEventListener);
}
public void stopListeners() {
PepManager.getInstanceFor(connection())
.removePepEventListener(pepEventListener);
}
public void publishIkeyElement(IkeyElement ikeyElement)
throws InterruptedException, PubSubException.NotALeafNodeException, XMPPException.XMPPErrorException,
SmackException.NotConnectedException, SmackException.NoResponseException {
PepManager.getInstanceFor(connection())
.publish(IkeyConstants.IKEY_NODE, new PayloadItem<>(ikeyElement));
}
public IkeyElement fetchIkeyElementOf(EntityBareJid jid)
throws InterruptedException, PubSubException.NotALeafNodeException, SmackException.NoResponseException,
SmackException.NotConnectedException, XMPPException.XMPPErrorException, PubSubException.NotAPubSubNodeException {
PubSubManager pubSubManager = PubSubManager.getInstanceFor(connection(), jid);
return fetchIkeyElementFrom(pubSubManager);
}
public IkeyElement fetchOwnIkeyElement()
throws InterruptedException, PubSubException.NotALeafNodeException, SmackException.NoResponseException,
SmackException.NotConnectedException, XMPPException.XMPPErrorException, PubSubException.NotAPubSubNodeException {
PubSubManager pubSubManager = PubSubManager.getInstanceFor(connection());
return fetchIkeyElementFrom(pubSubManager);
}
private IkeyElement fetchIkeyElementFrom(PubSubManager pubSubManager) throws PubSubException.NotALeafNodeException, SmackException.NoResponseException, SmackException.NotConnectedException, InterruptedException, XMPPException.XMPPErrorException, PubSubException.NotAPubSubNodeException {
LeafNode node = pubSubManager.getLeafNode(IkeyConstants.IKEY_NODE);
List<PayloadItem<IkeyElement>> items = node.getItems(1);
if (items.isEmpty()) {
return null;
} else {
return items.get(0).getPayload();
}
}
private void processIkeyElement(EntityBareJid from, IkeyElement element)
throws XMLParserException, IOException, CanonicalizationException, UnsupportedSignatureAlgorithmException {
if (isFromTheFuture(element) || existsSameOrNewerRecord(element)) {
return;
}
if (!verifyIkeyElement(from, element)) {
return;
}
//store.setLatestTimestamp(from, element.getSubordinates().getTimestamp());
//store.setIkeySubkeys(from, element.getSubordinates().getSubordinates());
}
private boolean verifyIkeyElement(EntityBareJid from, IkeyElement element)
throws XMLParserException, IOException, CanonicalizationException, UnsupportedSignatureAlgorithmException {
IkeySignatureVerificationMechanism verificationMechanism = getSignatureVerificationMechanismFor(element);
IkeySignatureVerifier verifier = new IkeySignatureVerifier(verificationMechanism, canonicalizer);
return verifier.verify(element, from);
}
private IkeySignatureVerificationMechanism getSignatureVerificationMechanismFor(IkeyElement ikeyElement)
throws IOException, UnsupportedSignatureAlgorithmException {
switch (ikeyElement.getType()) {
case OX:
PGPPublicKeyRing ikey = PGPainless.readKeyRing().publicKeyRing(ikeyElement.getSuperordinate().getPubKeyBytes());
return new OxIkeySignatureVerificationMechanism(ikey);
case X509:
throw new UnsupportedSignatureAlgorithmException("X.509");
}
throw new AssertionError("Unknown verification algorithm encountered: " + ikeyElement.getType());
}
private static boolean isFromTheFuture(IkeyElement element) {
Date elementTimestamp = element.getSubordinates().getTimestamp();
Date now = new Date();
return elementTimestamp.after(now);
}
private boolean existsSameOrNewerRecord(IkeyElement ikeyElement) {
Date latestTimestamp = store.getLatestTimestamp(ikeyElement.getSubordinates().getJid());
Date eventTimestamp = ikeyElement.getSubordinates().getTimestamp();
if (latestTimestamp == null) {
// No record at all found.
return false;
}
return latestTimestamp.equals(eventTimestamp) // same
|| latestTimestamp.after(eventTimestamp); // newer
}
private final PepEventListener<IkeyElement> pepEventListener =
(from, event, id, carrierMessage) -> Async.go(() -> {
try {
processIkeyElement(from, event);
} catch (XMLParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (CanonicalizationException e) {
e.printStackTrace();
} catch (UnsupportedSignatureAlgorithmException e) {
e.printStackTrace();
}
});
}

View file

@ -5,6 +5,8 @@ import org.apache.xml.security.parser.XMLParserException;
import org.bouncycastle.util.encoders.Base64;
import org.jivesoftware.smackx.ikey.element.ProofElement;
import org.jivesoftware.smackx.ikey.element.SubordinateListElement;
import org.jivesoftware.smackx.ikey.mechanism.IkeySignatureCreationMechanism;
import org.jivesoftware.smackx.ikey.util.canonicalization.XmlSecElementCanonicalizer;
import java.io.IOException;

View file

@ -4,6 +4,8 @@ import org.apache.xml.security.c14n.CanonicalizationException;
import org.apache.xml.security.parser.XMLParserException;
import org.bouncycastle.util.encoders.Base64;
import org.jivesoftware.smackx.ikey.element.IkeyElement;
import org.jivesoftware.smackx.ikey.mechanism.IkeySignatureVerificationMechanism;
import org.jivesoftware.smackx.ikey.util.canonicalization.ElementCanonicalizer;
import org.jxmpp.jid.EntityBareJid;
import java.io.IOException;
@ -11,9 +13,9 @@ import java.io.IOException;
public class IkeySignatureVerifier {
private final IkeySignatureVerificationMechanism signatureVerificationMechanism;
private final XmlSecElementCanonicalizer elementCanonicalizer;
private final ElementCanonicalizer elementCanonicalizer;
public IkeySignatureVerifier(IkeySignatureVerificationMechanism signatureVerificationMechanism, XmlSecElementCanonicalizer elementCanonicalizer) {
public IkeySignatureVerifier(IkeySignatureVerificationMechanism signatureVerificationMechanism, ElementCanonicalizer elementCanonicalizer) {
this.signatureVerificationMechanism = signatureVerificationMechanism;
this.elementCanonicalizer = elementCanonicalizer;
}

View file

@ -0,0 +1,12 @@
package org.jivesoftware.smackx.ikey;
import org.jxmpp.jid.EntityBareJid;
import java.util.Date;
public interface IkeyStore {
Date getLatestTimestamp(EntityBareJid jid);
}

View file

@ -1,6 +0,0 @@
package org.jivesoftware.smackx.ikey;
public enum IkeyType {
OX,
X509
}

View file

@ -3,8 +3,8 @@ package org.jivesoftware.smackx.ikey.element;
import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.packet.XmlEnvironment;
import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jivesoftware.smackx.ikey.IkeyConstants;
import org.jivesoftware.smackx.ikey.IkeyType;
import org.jivesoftware.smackx.ikey.util.IkeyConstants;
import org.jivesoftware.smackx.ikey.mechanism.IkeyType;
import javax.xml.namespace.QName;
@ -17,11 +17,13 @@ public class IkeyElement implements ExtensionElement {
private static final QName QNAME = new QName(IkeyConstants.NAMESPACE, ELEMENT);
private final IkeyType type;
private final SuperordinateElement superordinate;
private final SubordinateListElement subordinates;
private final ProofElement proof;
public IkeyElement(IkeyType type, SubordinateListElement subordinates, ProofElement proof) {
public IkeyElement(IkeyType type, SuperordinateElement superordinate, SubordinateListElement subordinates, ProofElement proof) {
this.type = type;
this.superordinate = superordinate;
this.subordinates = subordinates;
this.proof = proof;
}
@ -30,6 +32,10 @@ public class IkeyElement implements ExtensionElement {
return type;
}
public SuperordinateElement getSuperordinate() {
return superordinate;
}
public SubordinateListElement getSubordinates() {
return subordinates;
}
@ -53,6 +59,7 @@ public class IkeyElement implements ExtensionElement {
return new XmlStringBuilder(this, xmlEnvironment)
.attribute(ATTR_IKEY_TYPE, getType())
.rightAngleBracket()
.append(getSuperordinate())
.append(getSubordinates())
.append(getProof())
.closeElement(this);

View file

@ -4,22 +4,26 @@ import org.jivesoftware.smack.packet.NamedElement;
import org.jivesoftware.smack.packet.XmlEnvironment;
import org.jivesoftware.smack.util.Objects;
import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jivesoftware.smackx.ikey.IkeyConstants;
import org.jivesoftware.smackx.ikey.util.IkeyConstants;
import org.jxmpp.jid.EntityBareJid;
import java.util.Date;
import java.util.List;
public class SubordinateListElement implements NamedElement {
public static final String NAMESPACE = IkeyConstants.NAMESPACE;
public static final String ELEMENT = "subordinates";
public static final String ATTR_STAMP = "stamp";
public static final String ATTR_JID = "jid";
private final List<SubordinateElement> subordinates;
private final EntityBareJid jid;
private final Date timestamp;
public SubordinateListElement(EntityBareJid jid, List<SubordinateElement> subordinates) {
public SubordinateListElement(EntityBareJid jid, Date timestamp, List<SubordinateElement> subordinates) {
this.jid = jid;
this.timestamp = timestamp;
this.subordinates = Objects.requireNonNullNorEmpty(subordinates, "List of subordinates MUST NOT be null nor empty.");
}
@ -27,6 +31,10 @@ public class SubordinateListElement implements NamedElement {
return jid;
}
public Date getTimestamp() {
return timestamp;
}
public List<SubordinateElement> getSubordinates() {
return subordinates;
}
@ -40,6 +48,7 @@ public class SubordinateListElement implements NamedElement {
public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) {
return new XmlStringBuilder(this)
.attribute(ATTR_JID, getJid())
.attribute(ATTR_STAMP, getTimestamp())
.rightAngleBracket()
.append(getSubordinates())
.closeElement(this);

View file

@ -0,0 +1,42 @@
package org.jivesoftware.smackx.ikey.element;
import org.jivesoftware.smack.packet.NamedElement;
import org.jivesoftware.smack.packet.XmlEnvironment;
import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jivesoftware.smack.util.stringencoder.Base64;
public class SuperordinateElement implements NamedElement {
public static final String ELEMENT = "superordinate";
private final byte[] pubKeyBytes;
public SuperordinateElement(byte[] bytes) {
this.pubKeyBytes = bytes;
}
public SuperordinateElement(String base64) {
this.pubKeyBytes = Base64.decode(base64);
}
@Override
public String getElementName() {
return ELEMENT;
}
public byte[] getPubKeyBytes() {
return pubKeyBytes.clone();
}
public String getBase64PubKey() {
return Base64.encodeToString(getPubKeyBytes());
}
@Override
public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) {
return new XmlStringBuilder(this)
.rightAngleBracket()
.append(getBase64PubKey())
.closeElement(this);
}
}

View file

@ -1,4 +1,4 @@
package org.jivesoftware.smackx.ikey;
package org.jivesoftware.smackx.ikey.mechanism;
import java.io.IOException;

View file

@ -1,4 +1,4 @@
package org.jivesoftware.smackx.ikey;
package org.jivesoftware.smackx.ikey.mechanism;
import java.io.IOException;

View file

@ -0,0 +1,6 @@
package org.jivesoftware.smackx.ikey.mechanism;
public enum IkeyType {
OX,
X509
}

View file

@ -1,4 +1,4 @@
package org.jivesoftware.smackx.ikey;
package org.jivesoftware.smackx.ikey.util;
public class IkeyConstants {

View file

@ -0,0 +1,17 @@
package org.jivesoftware.smackx.ikey.util;
import org.jivesoftware.smack.util.StringUtils;
public class UnsupportedSignatureAlgorithmException extends Exception {
private static final long serialVersionUID = 1L;
private final String algorithmName;
public UnsupportedSignatureAlgorithmException(String algorithmName) {
this.algorithmName = StringUtils.requireNotNullNorEmpty(algorithmName, "Algorithm name MUST NOT be null NOR empty.");
}
public String getAlgorithmName() {
return algorithmName;
}
}

View file

@ -1,4 +1,4 @@
package org.jivesoftware.smackx.ikey;
package org.jivesoftware.smackx.ikey.util.canonicalization;
import org.apache.xml.security.c14n.CanonicalizationException;
import org.apache.xml.security.parser.XMLParserException;
@ -18,4 +18,8 @@ public interface ElementCanonicalizer {
}
byte[] canonicalize(byte[] xml) throws XMLParserException, IOException, CanonicalizationException;
default String removeInterElementWhitespace(String xml) {
return xml.replaceAll(">\\s*<", "><");
}
}

View file

@ -1,4 +1,4 @@
package org.jivesoftware.smackx.ikey;
package org.jivesoftware.smackx.ikey.util.canonicalization;
import org.apache.xml.security.c14n.CanonicalizationException;
import org.apache.xml.security.c14n.Canonicalizer;

View file

@ -1,12 +1,11 @@
package org.jivesoftware.smackx.ikey_ox;
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.util.io.Streams;
import org.jivesoftware.smackx.ikey.IkeySignatureCreationMechanism;
import org.jivesoftware.smackx.ikey.IkeyType;
import org.jivesoftware.smackx.ikey.mechanism.IkeySignatureCreationMechanism;
import org.jivesoftware.smackx.ikey.mechanism.IkeyType;
import org.pgpainless.PGPainless;
import org.pgpainless.encryption_signing.EncryptionStream;
import org.pgpainless.key.protection.SecretKeyRingProtector;

View file

@ -3,8 +3,8 @@ package org.jivesoftware.smackx.ikey_ox;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.util.io.Streams;
import org.jivesoftware.smackx.ikey.IkeySignatureVerificationMechanism;
import org.jivesoftware.smackx.ikey.IkeyType;
import org.jivesoftware.smackx.ikey.mechanism.IkeySignatureVerificationMechanism;
import org.jivesoftware.smackx.ikey.mechanism.IkeyType;
import org.pgpainless.PGPainless;
import org.pgpainless.decryption_verification.DecryptionStream;
import org.pgpainless.decryption_verification.OpenPgpMetadata;

View file

@ -0,0 +1,5 @@
package org.mercury_im.messenger.core.crypto.ikey;
public class IkeySignatureProvider {
}

View file

@ -0,0 +1,35 @@
package org.mercury_im.messenger.core.di.module;
import org.apache.xml.security.Init;
import org.apache.xml.security.c14n.Canonicalizer;
import org.apache.xml.security.c14n.InvalidCanonicalizerException;
import org.jivesoftware.smackx.ikey.util.canonicalization.ElementCanonicalizer;
import org.jivesoftware.smackx.ikey.util.canonicalization.XmlSecElementCanonicalizer;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class IkeyModule {
@Singleton
@Provides
static Canonicalizer provideCanonicalizer() {
if (!Init.isInitialized()) {
Init.init();
}
try {
return Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N11_OMIT_COMMENTS);
} catch (InvalidCanonicalizerException e) {
throw new AssertionError(e);
}
}
@Singleton
@Provides
static ElementCanonicalizer provideElementCanonicalizer(Canonicalizer canonicalizer) {
return new XmlSecElementCanonicalizer(canonicalizer);
}
}

View file

@ -1,6 +1,6 @@
package org.jivesoftware.smackx.ikey.element;
import org.jivesoftware.smackx.ikey.IkeyType;
import org.jivesoftware.smackx.ikey.mechanism.IkeyType;
import org.junit.Test;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.impl.JidCreate;
@ -8,14 +8,21 @@ import org.jxmpp.jid.impl.JidCreate;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Date;
public class IkeyElementTest {
@Test
public void elementTest() throws URISyntaxException {
IkeyType type = IkeyType.OX;
Date date = new Date();
SuperordinateElement superordinate = new SuperordinateElement("" +
"VGhpcyBpcyBvbmx5IGEgdGVzdCwgbm90IGEgcmVhbCBrZXkuIFdoeSB3b3VsZCB5b3UgdGhpbmsg" +
"dGhpcyBpcyBhIHJlYWwga2V5PyBCZWNhdXNlIGl0IGlzICdiYXNlNjQtZW5jcnlwdGVkJz8gRHVt" +
"bXkgZHVtYiBkdW1iLg==");
SubordinateListElement subordinates = buildSubListElement(
JidCreate.entityBareFromOrThrowUnchecked("hamlet@denmark.lit"),
date,
new SubordinateElement(
new URI("xmpp:hamlet@denmark.lit?;node=urn:xmpp:openpgp:0:public-keys:1357B01865B2503C18453D208CAC2A9678548E35;item=2020-01-21T10:46:21Z"),
"1357B01865B2503C18453D208CAC2A9678548E35"),
@ -25,12 +32,12 @@ public class IkeyElementTest {
);
ProofElement proof = new ProofElement("d2hpbGUgdGhpcyBpcyBub3QgYSB2YWxpZCBwcm9vZiwgaXQgaXMgc3VmZmljaWVudCBmb3IgdGVzdGluZy4=");
IkeyElement ikeyElement = new IkeyElement(type, subordinates, proof);
IkeyElement ikeyElement = new IkeyElement(type, superordinate, subordinates, proof);
System.out.println(ikeyElement.toXML().toString());
}
private SubordinateListElement buildSubListElement(EntityBareJid jid, SubordinateElement... subordinateElements) {
return new SubordinateListElement(jid, Arrays.asList(subordinateElements));
private SubordinateListElement buildSubListElement(EntityBareJid jid, Date date, SubordinateElement... subordinateElements) {
return new SubordinateListElement(jid, date, Arrays.asList(subordinateElements));
}
}

View file

@ -6,12 +6,13 @@ import org.apache.xml.security.c14n.Canonicalizer;
import org.apache.xml.security.c14n.InvalidCanonicalizerException;
import org.apache.xml.security.parser.XMLParserException;
import org.bouncycastle.openpgp.PGPException;
import org.jivesoftware.smackx.ikey.XmlSecElementCanonicalizer;
import org.jivesoftware.smackx.ikey.IkeySignatureCreationMechanism;
import org.jivesoftware.smack.util.stringencoder.Base64;
import org.jivesoftware.smackx.ikey.util.canonicalization.XmlSecElementCanonicalizer;
import org.jivesoftware.smackx.ikey.mechanism.IkeySignatureCreationMechanism;
import org.jivesoftware.smackx.ikey.IkeySignatureCreator;
import org.jivesoftware.smackx.ikey.IkeySignatureVerificationMechanism;
import org.jivesoftware.smackx.ikey.mechanism.IkeySignatureVerificationMechanism;
import org.jivesoftware.smackx.ikey.IkeySignatureVerifier;
import org.jivesoftware.smackx.ikey.IkeyType;
import org.jivesoftware.smackx.ikey.mechanism.IkeyType;
import org.jivesoftware.smackx.ikey_ox.OxIkeySignatureCreationMechanism;
import org.jivesoftware.smackx.ikey_ox.OxIkeySignatureVerificationMechanism;
import org.junit.BeforeClass;
@ -19,8 +20,12 @@ import org.junit.Test;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.impl.JidCreate;
import org.pgpainless.PGPainless;
import org.pgpainless.algorithm.KeyFlag;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import org.pgpainless.key.collection.PGPKeyRing;
import org.pgpainless.key.generation.KeySpec;
import org.pgpainless.key.generation.type.ECDSA;
import org.pgpainless.key.generation.type.curve.EllipticCurve;
import org.pgpainless.key.protection.UnprotectedKeysProtector;
import java.io.IOException;
@ -29,11 +34,12 @@ import java.net.URISyntaxException;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import static junit.framework.TestCase.assertTrue;
public class IkeySignatureCreatorAndVerifierTest {
public class IkeySignatureCreatorAndVerifierTest extends MercurySmackTestSuite {
@BeforeClass
public static void initialize() {
@ -45,7 +51,13 @@ public class IkeySignatureCreatorAndVerifierTest {
@Test
public void createIkeyElementAndVerifySignature() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException, URISyntaxException, XMLParserException, IOException, CanonicalizationException, InvalidCanonicalizerException {
EntityBareJid jid = JidCreate.entityBareFromOrThrowUnchecked("alice@wonderland.lit");
PGPKeyRing keyRing = PGPainless.generateKeyRing().simpleEcKeyRing("xmpp:" + jid);
PGPKeyRing keyRing = PGPainless.generateKeyRing()
.withMasterKey(KeySpec.getBuilder(ECDSA.fromCurve(EllipticCurve._P256))
.withKeyFlags(KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA)
.withDefaultAlgorithms())
.withPrimaryUserId("xmpp:" + jid)
.withoutPassphrase()
.build();
XmlSecElementCanonicalizer elementCanonicalizer = new XmlSecElementCanonicalizer(Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N11_OMIT_COMMENTS));
IkeySignatureCreationMechanism signingMechanism = new OxIkeySignatureCreationMechanism(
@ -55,14 +67,15 @@ public class IkeySignatureCreatorAndVerifierTest {
IkeySignatureVerifier verifier = new IkeySignatureVerifier(verificationMechanism, elementCanonicalizer);
OpenPgpV4Fingerprint fingerprint = new OpenPgpV4Fingerprint(keyRing.getMasterKey());
SuperordinateElement superordinate = new SuperordinateElement(Base64.encodeToString(keyRing.getMasterKey().getEncoded()));
List<SubordinateElement> subList = new ArrayList<>();
subList.add(new SubordinateElement(
new URI("xmpp:" + jid + "?;node=urn:xmpp:openpgp:0:public-keys:" + fingerprint + ";item=2020-01-21T10:46:21Z"),
fingerprint.toString()));
SubordinateListElement subs = new SubordinateListElement(jid, subList);
SubordinateListElement subs = new SubordinateListElement(jid, new Date(), subList);
ProofElement proofElement = creator.createProofFor(subs);
IkeyElement ikeyElement = new IkeyElement(IkeyType.OX, subs, proofElement);
IkeyElement ikeyElement = new IkeyElement(IkeyType.OX, superordinate, subs, proofElement);
System.out.println(ikeyElement.toXML().toString());

View file

@ -0,0 +1,38 @@
package org.jivesoftware.smackx.ikey.element;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.util.stringencoder.Base64;
import java.security.Security;
public class MercurySmackTestSuite {
static {
SmackConfiguration.getVersion();
org.jivesoftware.smack.util.stringencoder.Base64.setEncoder(new Base64.Encoder() {
@Override
public byte[] decode(String string) {
return java.util.Base64.getDecoder().decode(string);
}
@Override
public String encodeToString(byte[] input) {
return java.util.Base64.getEncoder().encodeToString(input);
}
@Override
public String encodeToStringWithoutPadding(byte[] input) {
return java.util.Base64.getEncoder().withoutPadding().encodeToString(input);
}
@Override
public byte[] encode(byte[] input) {
return java.util.Base64.getEncoder().encode(input);
}
});
Security.addProvider(new BouncyCastleProvider());
}
}

View file

@ -5,9 +5,8 @@ import org.apache.xml.security.c14n.CanonicalizationException;
import org.apache.xml.security.c14n.Canonicalizer;
import org.apache.xml.security.c14n.InvalidCanonicalizerException;
import org.apache.xml.security.parser.XMLParserException;
import org.jivesoftware.smackx.ikey.XmlSecElementCanonicalizer;
import org.jivesoftware.smackx.ikey.util.canonicalization.XmlSecElementCanonicalizer;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import java.io.IOException;
@ -24,7 +23,6 @@ public class XmlSecElementCanonicalizerTest {
}
@Test
@Ignore
public void test() throws InvalidCanonicalizerException, XMLParserException, IOException, CanonicalizationException {
XmlSecElementCanonicalizer canonicalizer = new XmlSecElementCanonicalizer(Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N11_OMIT_COMMENTS));
String element = "<ikey xmlns='urn:xmpp:ikey:0' type='OX'><subordinates jid='alice@wonderland.lit'>" +
@ -33,18 +31,16 @@ public class XmlSecElementCanonicalizerTest {
"<proof>iF4EABMIAAYFAl9I3esACgkQNZFg0LCGhWntNAD+LDO/Q+WQ5TrQOt4vBcqnUarCOZ6Ev4Wp4QgsIjs2BHcA/2BOIC6FBqkx80zB8NZsZu4H1fvn+gWgrscXhgf9+f+h</proof>" +
"</ikey>";
String elementWithInsignificantWhitespace = "" +
"<ikey xmlns='urn:xmpp:ikey:0'" +
" type='OX'>" +
" <subordinates jid='alice@wonderland.lit'>" +
"<ikey xmlns='urn:xmpp:ikey:0'\n" +
" type='OX'>\n" +
" <subordinates jid='alice@wonderland.lit'>\n" +
" <sub uri=\"xmpp:alice@wonderland.lit?;node=urn:xmpp:openpgp:0:public-keys:34669E842617A0D38A96016B359160D0B0868569;item=2020-01-21T10:46:21Z\"\n" +
" fpr='34669E842617A0D38A96016B359160D0B0868569'/>" +
" </subordinates>" +
" <proof>" +
" iF4EABMIAAYFAl9I3esACgkQNZFg0LCGhWntNAD+LDO/Q+WQ5TrQOt4vBcqnUarCOZ6Ev4Wp4QgsIjs2BHcA/2BOIC6FBqkx80zB8NZsZu4H1fvn+gWgrscXhgf9+f+h" +
" </proof>" +
" fpr='34669E842617A0D38A96016B359160D0B0868569'/>\n" +
" </subordinates>\n" +
" <proof>iF4EABMIAAYFAl9I3esACgkQNZFg0LCGhWntNAD+LDO/Q+WQ5TrQOt4vBcqnUarCOZ6Ev4Wp4QgsIjs2BHcA/2BOIC6FBqkx80zB8NZsZu4H1fvn+gWgrscXhgf9+f+h</proof>\n" +
"</ikey>";
String can1 = new String(canonicalizer.canonicalize(element));
String can2 = new String(canonicalizer.canonicalize(elementWithInsignificantWhitespace));
String can1 = canonicalizer.removeInterElementWhitespace(new String(canonicalizer.canonicalize(element)));
String can2 = canonicalizer.removeInterElementWhitespace(new String(canonicalizer.canonicalize(elementWithInsignificantWhitespace)));
assertEquals(can1, can2);
}
}