mirror of
https://codeberg.org/Mercury-IM/Mercury-IM
synced 2024-11-10 18:15:57 +01:00
More ikey progress
This commit is contained in:
parent
d9c9eff602
commit
1d4e729f4c
24 changed files with 401 additions and 57 deletions
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
package org.jivesoftware.smackx.ikey;
|
||||
|
||||
public enum IkeyType {
|
||||
OX,
|
||||
X509
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package org.jivesoftware.smackx.ikey;
|
||||
package org.jivesoftware.smackx.ikey.mechanism;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package org.jivesoftware.smackx.ikey;
|
||||
package org.jivesoftware.smackx.ikey.mechanism;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package org.jivesoftware.smackx.ikey.mechanism;
|
||||
|
||||
public enum IkeyType {
|
||||
OX,
|
||||
X509
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package org.jivesoftware.smackx.ikey;
|
||||
package org.jivesoftware.smackx.ikey.util;
|
||||
|
||||
public class IkeyConstants {
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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*<", "><");
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
package org.mercury_im.messenger.core.crypto.ikey;
|
||||
|
||||
public class IkeySignatureProvider {
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue