Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
EndpointSecurity.cs
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Reflection;
5using System.Text;
6using System.Threading.Tasks;
7using System.Xml;
9using Waher.Events;
16
18{
23 {
27 public const string IoTHarmonizationE2EIeeeV1 = "urn:ieee:iot:e2e:1.0";
28
32 public const string IoTHarmonizationE2ENeuroFoundationV1 = "urn:nf:iot:e2e:1.0";
33
38
42 public static readonly string[] NamespacesIoTHarmonizationE2E = new string[]
43 {
46 };
47
51 public const string IoTHarmonizationP2PIeeeV1 = "urn:ieee:iot:p2p:1.0";
52
56 public const string IoTHarmonizationP2PNeuroFoundationV1 = "urn:nf:iot:p2p:1.0";
57
62
66 public static readonly string[] NamespacesIoTHarmonizationP2P = new string[]
67 {
70 };
71
72 private static Dictionary<string, IE2eEndpoint> endpointTypes = new Dictionary<string, IE2eEndpoint>();
73 private static bool initialized = false;
74 private static Type[] e2eTypes = null;
75 private static bool e2eTypesLocked = false;
76
77 private readonly Dictionary<string, IE2eEndpoint[]> contacts;
78 private XmppClient client;
79 private readonly XmppServerlessMessaging serverlessMessaging;
80 private IE2eEndpoint[] oldKeys = null;
81 private IE2eEndpoint[] keys = null;
82 private readonly UTF8Encoding encoding = new UTF8Encoding(false, false);
83 private readonly object synchObject = new object();
84 private readonly int securityStrength;
85 private readonly bool ephemeralKeys;
86 private Aes256 aes = new Aes256();
88 private ChaCha20 cha = new ChaCha20();
89
95 public EndpointSecurity(XmppClient Client, int SecurityStrength)
96 : this(Client, null, SecurityStrength)
97 {
98 }
99
106 public EndpointSecurity(XmppClient Client, XmppServerlessMessaging ServerlessMessaging, int SecurityStrength)
107 : this(Client, ServerlessMessaging, SecurityStrength, null)
108 {
109 }
110
117 public EndpointSecurity(XmppClient Client, int SecurityStrength, params IE2eEndpoint[] LocalEndpoints)
118 : this(Client, null, SecurityStrength, LocalEndpoints)
119 {
120 }
121
129 public EndpointSecurity(XmppClient Client, XmppServerlessMessaging ServerlessMessaging, int SecurityStrength,
130 params IE2eEndpoint[] LocalEndpoints)
131 : base()
132 {
133 this.securityStrength = SecurityStrength;
134 this.client = Client;
135 this.serverlessMessaging = ServerlessMessaging;
136 this.contacts = new Dictionary<string, IE2eEndpoint[]>(StringComparer.CurrentCultureIgnoreCase);
137
138 if (!(LocalEndpoints is null))
139 {
140 this.keys = LocalEndpoints;
141 this.ephemeralKeys = false;
142 }
143 else
144 {
145 this.keys = CreateEndpoints(SecurityStrength, 0, int.MaxValue);
146 this.ephemeralKeys = true;
147 }
148
149 if (!(this.client is null))
150 {
151 this.RegisterHandlers(this.client);
152
153 this.client.OnStateChanged += this.Client_OnStateChanged;
154 this.client.OnPresence += this.Client_OnPresence;
155 this.client.CustomPresenceXml += this.Client_CustomPresenceXml;
156 }
157 }
158
159 private Task Client_CustomPresenceXml(object Sender, CustomPresenceEventArgs e)
160 {
161 this.AppendE2eInfo(e.Stanza);
162 this.serverlessMessaging?.AppendP2pInfo(e.Stanza);
163
164 return Task.CompletedTask;
165 }
166
174 public static IE2eEndpoint[] CreateEndpoints(int DesiredSecurityStrength, int MinSecurityStrength, int MaxSecurityStrength)
175 {
176 return CreateEndpoints(DesiredSecurityStrength, MinSecurityStrength, MaxSecurityStrength, null);
177 }
178
187 public static IE2eEndpoint[] CreateEndpoints(int DesiredSecurityStrength, int MinSecurityStrength, int MaxSecurityStrength,
188 Type OnlyIfDerivedFrom)
189 {
190 return CreateEndpoints(DesiredSecurityStrength, MinSecurityStrength, MaxSecurityStrength, OnlyIfDerivedFrom, null);
191 }
192
202 public static IE2eEndpoint[] CreateEndpoints(int DesiredSecurityStrength, int MinSecurityStrength, int MaxSecurityStrength,
203 Type OnlyIfDerivedFrom, ProfilerThread Thread)
204 {
205 Thread = Thread?.CreateSubThread("Endpoints", ProfilerThreadType.Sequential);
206 try
207 {
208 Thread?.Start();
209 Thread?.NewState("Init");
210
211 List<IE2eEndpoint> Result = new List<IE2eEndpoint>();
212 TypeInfo OnlyIfDerivedFromType = OnlyIfDerivedFrom?.GetTypeInfo();
213 IEnumerable<IE2eEndpoint> Templates;
214 bool CheckHeritance = true;
215
216 lock (endpointTypes)
217 {
218 if (initialized)
219 Templates = endpointTypes.Values;
220 else
221 {
222 Dictionary<string, IE2eEndpoint> E2eTypes = new Dictionary<string, IE2eEndpoint>();
223 Dictionary<string, bool> TypeNames = new Dictionary<string, bool>();
224 TypeInfo E2eTypeInfo = typeof(IE2eEndpoint).GetTypeInfo();
225
226 foreach (KeyValuePair<string, IE2eEndpoint> P in endpointTypes)
227 {
228 E2eTypes[P.Key] = P.Value;
229 TypeNames[P.Value.GetType().FullName] = true;
230 }
231
232 foreach (Type T in e2eTypes ?? Types.GetTypesImplementingInterface(typeof(IE2eEndpoint)))
233 {
234 if (TypeNames.ContainsKey(T.FullName))
235 continue;
236
237 TypeInfo TI = T.GetTypeInfo();
238 if (!(e2eTypes is null) && !E2eTypeInfo.IsAssignableFrom(TI))
239 continue;
240
241 if (!(OnlyIfDerivedFromType?.IsAssignableFrom(TI) ?? true))
242 continue;
243
244 ConstructorInfo CI = Types.GetDefaultConstructor(T);
245 if (CI is null)
246 continue;
247
248 try
249 {
250 IE2eEndpoint Endpoint = (IE2eEndpoint)CI.Invoke(Types.NoParameters);
251 E2eTypes[Endpoint.Namespace + "#" + Endpoint.LocalName] = Endpoint;
252 }
253 catch (Exception ex)
254 {
255 Log.Exception(ex);
256 continue;
257 }
258 }
259
260 endpointTypes = E2eTypes;
261 Templates = E2eTypes.Values;
262
263 if (OnlyIfDerivedFromType is null)
264 initialized = true;
265 else
266 CheckHeritance = false;
267 }
268 }
269
270 foreach (IE2eEndpoint Endpoint in Templates)
271 {
272 if (CheckHeritance && !(OnlyIfDerivedFromType?.IsAssignableFrom(Endpoint.GetType().GetTypeInfo()) ?? true))
273 continue;
274
275 Thread?.NewState(Endpoint.LocalName);
276
277 IE2eEndpoint Endpoint2 = Endpoint.Create(DesiredSecurityStrength);
278 int i = Endpoint2.SecurityStrength;
279 if (i >= MinSecurityStrength && i <= MaxSecurityStrength)
280 Result.Add(Endpoint2);
281 else
282 Endpoint2.Dispose();
283 }
284
285 return Result.ToArray();
286 }
287 finally
288 {
289 Thread?.Stop();
290 }
291 }
292
298 public static void SetCiphers(Type[] CipherTypes, bool Lock)
299 {
300 if (e2eTypesLocked)
301 throw new InvalidOperationException("Ciphers locked.");
302
303 e2eTypes = CipherTypes;
304 e2eTypesLocked = Lock;
305 }
306
314 public static bool TryGetEndpoint(string LocalName, string Namespace, out IE2eEndpoint Endpoint)
315 {
316 if (Namespace.StartsWith("urn:ieee:"))
317 Namespace = Namespace.Replace("urn:ieee:", "urn:nf:");
318
319 string Key = Namespace + "#" + LocalName;
320
321 if (endpointTypes.TryGetValue(Key, out Endpoint))
322 return true;
323 else if (initialized || endpointTypes.Count > 0)
324 return false;
325
326 CreateEndpoints(128, 0, int.MaxValue);
327
328 return endpointTypes.TryGetValue(Key, out Endpoint);
329 }
330
338 public static bool TryCreateEndpoint(string LocalName, string Namespace, out IE2eEndpoint Endpoint)
339 {
340 if (TryGetEndpoint(LocalName, Namespace, out Endpoint))
341 {
342 Endpoint = Endpoint.Create(Endpoint.SecurityStrength);
343 return true;
344 }
345 else
346 return false;
347 }
348
352 public virtual void Dispose()
353 {
354 if (!(this.client is null))
355 {
356 this.client.OnStateChanged -= this.Client_OnStateChanged;
357 this.client.OnPresence -= this.Client_OnPresence;
358 this.client.CustomPresenceXml -= this.Client_CustomPresenceXml;
359
360 this.UnregisterHandlers(this.client);
361 this.client = null;
362 }
363
364 if (!(this.oldKeys is null))
365 {
366 foreach (IE2eEndpoint E2e in this.oldKeys)
367 E2e.Dispose();
368 }
369
370 if (!(this.keys is null))
371 {
372 foreach (IE2eEndpoint E2e in this.keys)
373 E2e.Dispose();
374
375 }
376
377 lock (this.contacts)
378 {
379 foreach (IE2eEndpoint[] Endpoints in this.contacts.Values)
380 {
381 foreach (IE2eEndpoint Endpoint in Endpoints)
382 Endpoint.Dispose();
383 }
384
385 this.contacts.Clear();
386 }
387
388 this.aes?.Dispose();
389 this.aes = null;
390
391 this.acp?.Dispose();
392 this.acp = null;
393
394 this.cha?.Dispose();
395 this.cha = null;
396 }
397
398 private Task Client_OnStateChanged(object Sender, XmppState NewState)
399 {
400 if (NewState == XmppState.RequestingSession && this.ephemeralKeys)
401 this.GenerateNewKey();
402
403 return Task.CompletedTask;
404 }
405
409 public void GenerateNewKey()
410 {
411 lock (this.synchObject)
412 {
413 IE2eEndpoint[] Keys = this.oldKeys;
414
415 this.oldKeys = this.keys;
416
417 if (!(Keys is null))
418 {
419 foreach (IE2eEndpoint E2e in Keys)
420 E2e.Dispose();
421 }
422
423 int i, c = this.keys.Length;
424 Keys = new IE2eEndpoint[c];
425
426 for (i = 0; i < c; i++)
427 {
428 Keys[i] = this.keys[i].Create(this.securityStrength);
429 Keys[i].Previous = this.keys[i];
430 this.keys[i].Previous = null;
431 }
432
433 this.keys = Keys;
434 }
435 }
436
441 public virtual void RegisterHandlers(XmppClient Client)
442 {
443 #region Neuro-Foundation V1
444
445 Client?.RegisterMessageHandler("aes", IoTHarmonizationE2ENeuroFoundationV1, this.AesMessageHandler, false);
446 Client?.RegisterIqGetHandler("aes", IoTHarmonizationE2ENeuroFoundationV1, this.AesIqGetHandler, false);
447 Client?.RegisterIqSetHandler("aes", IoTHarmonizationE2ENeuroFoundationV1, this.AesIqSetHandler, false);
448 Client?.RegisterMessageHandler("acp", IoTHarmonizationE2ENeuroFoundationV1, this.AcpMessageHandler, false);
449 Client?.RegisterIqGetHandler("acp", IoTHarmonizationE2ENeuroFoundationV1, this.AcpIqGetHandler, false);
450 Client?.RegisterIqSetHandler("acp", IoTHarmonizationE2ENeuroFoundationV1, this.AcpIqSetHandler, false);
451 Client?.RegisterMessageHandler("cha", IoTHarmonizationE2ENeuroFoundationV1, this.ChaMessageHandler, false);
452 Client?.RegisterIqGetHandler("cha", IoTHarmonizationE2ENeuroFoundationV1, this.ChaIqGetHandler, false);
453 Client?.RegisterIqSetHandler("cha", IoTHarmonizationE2ENeuroFoundationV1, this.ChaIqSetHandler, false);
454 Client?.RegisterIqSetHandler("synchE2e", IoTHarmonizationE2ENeuroFoundationV1, this.SynchE2eHandler, false);
455
456 #endregion
457
458 #region IEEE v1
459
460 Client?.RegisterMessageHandler("aes", IoTHarmonizationE2EIeeeV1, this.AesMessageHandler, false);
461 Client?.RegisterIqGetHandler("aes", IoTHarmonizationE2EIeeeV1, this.AesIqGetHandler, false);
462 Client?.RegisterIqSetHandler("aes", IoTHarmonizationE2EIeeeV1, this.AesIqSetHandler, false);
463 Client?.RegisterMessageHandler("acp", IoTHarmonizationE2EIeeeV1, this.AcpMessageHandler, false);
464 Client?.RegisterIqGetHandler("acp", IoTHarmonizationE2EIeeeV1, this.AcpIqGetHandler, false);
465 Client?.RegisterIqSetHandler("acp", IoTHarmonizationE2EIeeeV1, this.AcpIqSetHandler, false);
466 Client?.RegisterMessageHandler("cha", IoTHarmonizationE2EIeeeV1, this.ChaMessageHandler, false);
467 Client?.RegisterIqGetHandler("cha", IoTHarmonizationE2EIeeeV1, this.ChaIqGetHandler, false);
468 Client?.RegisterIqSetHandler("cha", IoTHarmonizationE2EIeeeV1, this.ChaIqSetHandler, false);
469 Client?.RegisterIqSetHandler("synchE2e", IoTHarmonizationE2EIeeeV1, this.SynchE2eHandler, false);
470
471 #endregion
472 }
473
478 public virtual void UnregisterHandlers(XmppClient Client)
479 {
480 #region Neuro-Foundation V1
481
482 Client?.UnregisterMessageHandler("aes", IoTHarmonizationE2ENeuroFoundationV1, this.AesMessageHandler, false);
483 Client?.UnregisterIqGetHandler("aes", IoTHarmonizationE2ENeuroFoundationV1, this.AesIqGetHandler, false);
484 Client?.UnregisterIqSetHandler("aes", IoTHarmonizationE2ENeuroFoundationV1, this.AesIqSetHandler, false);
485 Client?.UnregisterMessageHandler("acp", IoTHarmonizationE2ENeuroFoundationV1, this.AcpMessageHandler, false);
486 Client?.UnregisterIqGetHandler("acp", IoTHarmonizationE2ENeuroFoundationV1, this.AcpIqGetHandler, false);
487 Client?.UnregisterIqSetHandler("acp", IoTHarmonizationE2ENeuroFoundationV1, this.AcpIqSetHandler, false);
488 Client?.UnregisterMessageHandler("cha", IoTHarmonizationE2ENeuroFoundationV1, this.ChaMessageHandler, false);
489 Client?.UnregisterIqGetHandler("cha", IoTHarmonizationE2ENeuroFoundationV1, this.ChaIqGetHandler, false);
490 Client?.UnregisterIqSetHandler("cha", IoTHarmonizationE2ENeuroFoundationV1, this.ChaIqSetHandler, false);
491 Client?.UnregisterIqSetHandler("synchE2e", IoTHarmonizationE2ENeuroFoundationV1, this.SynchE2eHandler, false);
492
493 #endregion
494
495 #region IEEE v1
496
497 Client?.UnregisterMessageHandler("aes", IoTHarmonizationE2EIeeeV1, this.AesMessageHandler, false);
498 Client?.UnregisterIqGetHandler("aes", IoTHarmonizationE2EIeeeV1, this.AesIqGetHandler, false);
499 Client?.UnregisterIqSetHandler("aes", IoTHarmonizationE2EIeeeV1, this.AesIqSetHandler, false);
500 Client?.UnregisterMessageHandler("acp", IoTHarmonizationE2EIeeeV1, this.AcpMessageHandler, false);
501 Client?.UnregisterIqGetHandler("acp", IoTHarmonizationE2EIeeeV1, this.AcpIqGetHandler, false);
502 Client?.UnregisterIqSetHandler("acp", IoTHarmonizationE2EIeeeV1, this.AcpIqSetHandler, false);
503 Client?.UnregisterMessageHandler("cha", IoTHarmonizationE2EIeeeV1, this.ChaMessageHandler, false);
504 Client?.UnregisterIqGetHandler("cha", IoTHarmonizationE2EIeeeV1, this.ChaIqGetHandler, false);
505 Client?.UnregisterIqSetHandler("cha", IoTHarmonizationE2EIeeeV1, this.ChaIqSetHandler, false);
506 Client?.UnregisterIqSetHandler("synchE2e", IoTHarmonizationE2EIeeeV1, this.SynchE2eHandler, false);
507
508 #endregion
509 }
510
516 public static List<IE2eEndpoint> ParseE2eKeys(XmlElement E2E)
517 {
518 List<IE2eEndpoint> Endpoints = null;
519
520 foreach (XmlNode N in E2E.ChildNodes)
521 {
522 if (N is XmlElement E)
523 {
524 IE2eEndpoint Endpoint = ParseE2eKey(E);
525
526 if (!(Endpoint is null))
527 {
528 if (Endpoints is null)
529 Endpoints = new List<IE2eEndpoint>();
530
531 Endpoints.Add(Endpoint);
532 }
533 }
534 }
535
536 return Endpoints;
537 }
538
544 public static IE2eEndpoint ParseE2eKey(XmlElement E)
545 {
546 if (TryGetEndpoint(E.LocalName, E.NamespaceURI, out IE2eEndpoint Endpoint))
547 return Endpoint.Parse(E);
548 else
549 return null;
550 }
551
558 public bool AddPeerPkiInfo(string FullJID, XmlElement E2E)
559 {
560 try
561 {
562 List<IE2eEndpoint> Endpoints = null;
563 IE2eEndpoint[] OldEndpoints = null;
564 int i;
565
566 if (!(E2E is null))
567 Endpoints = ParseE2eKeys(E2E);
568
569 if (Endpoints is null)
570 {
571 this.RemovePeerPkiInfo(FullJID);
572 return false;
573 }
574
575 Endpoints.Sort((e1, e2) =>
576 {
577 int Diff = e2.SecurityStrength - e1.SecurityStrength;
578 if (Diff != 0)
579 return Diff;
580
581 return e1.Score - e2.Score;
582 });
583
584 i = 0;
585 int j, c = Endpoints.Count;
586
587 for (j = 1; j < c; j++)
588 {
589 if (Endpoints[j].SecurityStrength >= this.securityStrength)
590 i = j;
591 }
592
593 if (i != 0)
594 {
595 IE2eEndpoint Temp = Endpoints[i];
596 Endpoints.RemoveAt(i);
597 Endpoints.Insert(0, Temp);
598 }
599
600 lock (this.contacts)
601 {
602 if (!this.contacts.TryGetValue(FullJID, out OldEndpoints))
603 OldEndpoints = null;
604
605 this.contacts[FullJID] = Endpoints.ToArray();
606 }
607
608 if (!(OldEndpoints is null))
609 {
610 foreach (IE2eEndpoint Endpoint in OldEndpoints)
611 Endpoint.Dispose();
612 }
613
614 return true;
615 }
616 catch (Exception)
617 {
618 this.RemovePeerPkiInfo(FullJID);
619 return false;
620 }
621 }
622
628 public bool RemovePeerPkiInfo(string FullJID)
629 {
630 IE2eEndpoint[] List;
631
632 lock (this.contacts)
633 {
634 if (!this.contacts.TryGetValue(FullJID, out List))
635 return false;
636 else
637 this.contacts.Remove(FullJID);
638 }
639
640 foreach (IE2eEndpoint Endpoint in List)
641 Endpoint.Dispose();
642
643 return true;
644 }
645
651 public bool ContainsKey(string FullJid)
652 {
653 lock (this.contacts)
654 {
655 return this.contacts.ContainsKey(FullJid);
656 }
657 }
658
664 public IE2eEndpoint[] GetE2eEndpoints(string FullJid)
665 {
666 lock (this.contacts)
667 {
668 if (this.contacts.TryGetValue(FullJid, out IE2eEndpoint[] Endpoints))
669 return Endpoints;
670 }
671
672 if (string.Compare(FullJid, this.client.BareJID) == 0)
673 {
674 StringBuilder Xml = new StringBuilder();
675
676 this.AppendE2eInfo(Xml);
677
678 XmlDocument Doc = new XmlDocument()
679 {
680 PreserveWhitespace = true
681 };
682 Doc.LoadXml(Xml.ToString());
683
684 return ParseE2eKeys(Doc.DocumentElement)?.ToArray() ?? new IE2eEndpoint[0];
685 }
686
687 return new E2eEndpoint[0];
688 }
689
700 public virtual Task<byte[]> Encrypt(string Id, string Type, string From, string To, byte[] Data, out IE2eEndpoint EndpointReference)
701 {
702 IE2eEndpoint RemoteEndpoint = this.FindRemoteEndpoint(To, null);
703 if (RemoteEndpoint is null)
704 {
705 EndpointReference = null;
706 return null;
707 }
708
709 EndpointReference = this.FindLocalEndpoint(RemoteEndpoint);
710 if (EndpointReference is null)
711 return null;
712
713 uint Counter = EndpointReference.GetNextCounter();
714 byte[] Encrypted = EndpointReference.DefaultSymmetricCipher.Encrypt(Id, Type, From, To, Counter, Data, EndpointReference, RemoteEndpoint);
715
716 return Task.FromResult(Encrypted);
717 }
718
730 public virtual Task<byte[]> Decrypt(string EndpointReference, string Id, string Type, string From, string To, byte[] Data,
731 IE2eSymmetricCipher SymmetricCipher)
732 {
733 IE2eEndpoint RemoteEndpoint = this.FindRemoteEndpoint(From, EndpointReference);
734 if (RemoteEndpoint is null)
735 return null;
736
737 IE2eEndpoint LocalEndpoint = this.FindLocalEndpoint(RemoteEndpoint);
738 if (LocalEndpoint is null)
739 return null;
740
741 IE2eSymmetricCipher Cipher = LocalEndpoint.DefaultSymmetricCipher;
742 if (!(SymmetricCipher is null) && Cipher.GetType() != SymmetricCipher.GetType())
743 Cipher = SymmetricCipher;
744
745 byte[] Decrypted = Cipher.Decrypt(Id, Type, From, To, Data, RemoteEndpoint, LocalEndpoint);
746
747 return Task.FromResult(Decrypted);
748 }
749
750 private IE2eEndpoint FindRemoteEndpoint(string RemoteJid, string EndpointReference)
751 {
752 IE2eEndpoint[] Endpoints;
753
754 lock (this.contacts)
755 {
756 if (!this.contacts.TryGetValue(RemoteJid, out Endpoints))
757 return null;
758 }
759
760 if (EndpointReference is null)
761 return Endpoints[0];
762
763 string Namespace;
764 string LocalName;
765 int i;
766
767 i = EndpointReference.IndexOf('#');
768 if (i < 0)
769 {
770 LocalName = EndpointReference;
771 Namespace = IoTHarmonizationE2ECurrent;
772 }
773 else
774 {
775 Namespace = EndpointReference.Substring(0, i).Replace("urn:ieee:", "urn:nf:");
776 LocalName = EndpointReference.Substring(i + 1);
777 }
778
779 foreach (IE2eEndpoint Endpoint in Endpoints)
780 {
781 if (Endpoint.LocalName == LocalName && Endpoint.Namespace == Namespace)
782 return Endpoint;
783 }
784
785 return null;
786 }
787
798 public virtual async Task<IE2eEndpoint> Encrypt(string Id, string Type, string From, string To, Stream Data, Stream Encrypted)
799 {
800 IE2eEndpoint RemoteEndpoint = this.FindRemoteEndpoint(To, null);
801 if (RemoteEndpoint is null)
802 return null;
803
804 IE2eEndpoint LocalEndpoint = this.FindLocalEndpoint(RemoteEndpoint);
805 if (LocalEndpoint is null)
806 return null;
807
808 uint Counter = LocalEndpoint.GetNextCounter();
809 await LocalEndpoint.DefaultSymmetricCipher.Encrypt(Id, Type, From, To, Counter, Data, Encrypted, LocalEndpoint, RemoteEndpoint);
810
811 return LocalEndpoint;
812 }
813
825 public virtual async Task<Stream> Decrypt(string EndpointReference, string Id, string Type, string From, string To, Stream Data,
826 IE2eSymmetricCipher SymmetricCipher)
827 {
828 IE2eEndpoint RemoteEndpoint = this.FindRemoteEndpoint(From, EndpointReference);
829 if (RemoteEndpoint is null)
830 return null;
831
832 IE2eEndpoint LocalEndpoint = this.FindLocalEndpoint(RemoteEndpoint);
833 if (LocalEndpoint is null)
834 return null;
835
836 IE2eSymmetricCipher Cipher = LocalEndpoint.DefaultSymmetricCipher;
837 if (!(SymmetricCipher is null) && Cipher.GetType() != SymmetricCipher.GetType())
838 Cipher = SymmetricCipher;
839
840 return await Cipher.Decrypt(Id, Type, From, To, Data, RemoteEndpoint, LocalEndpoint);
841 }
842
854 public virtual async Task<bool> Encrypt(XmppClient Client, string Id, string Type, string From, string To, string DataXml, StringBuilder Xml)
855 {
856 bool SniffE2eInfo = Client.HasSniffers && Client.TryGetTag("ShowE2E", out object Obj) && Obj is bool b && b;
857 IE2eEndpoint RemoteEndpoint = this.FindRemoteEndpoint(To, null);
858 if (RemoteEndpoint is null)
859 {
860 if (SniffE2eInfo)
861 await Client.Warning("Remote E2E endpoint not found. Unable to encrypt message.");
862
863 return false;
864 }
865
866 IE2eEndpoint LocalEndpoint = this.FindLocalEndpoint(RemoteEndpoint);
867 if (LocalEndpoint is null)
868 {
869 if (SniffE2eInfo)
870 await Client.Warning("Local E2E endpoint matching remote endpoint not found. Unable to encrypt message.");
871
872 return false;
873 }
874
875 byte[] Data = this.encoding.GetBytes(DataXml);
876 uint Counter = LocalEndpoint.GetNextCounter();
877 bool Result = LocalEndpoint.DefaultSymmetricCipher.Encrypt(Id, Type, From, To, Counter, Data, Xml, LocalEndpoint, RemoteEndpoint);
878
879 if (SniffE2eInfo)
880 await Client.Information(DataXml);
881
882 return Result;
883 }
884
885 private IE2eEndpoint FindLocalEndpoint(IE2eEndpoint RemoteEndpoint)
886 {
887 IE2eEndpoint[] Endpoints = this.keys;
888 int c = Endpoints.Length;
889 int i;
890 Type T = RemoteEndpoint.GetType();
891
892 for (i = 0; i < c; i++)
893 {
894 if (Endpoints[i].GetType() == T)
895 return Endpoints[i];
896 }
897
898 return null;
899 }
900
906 public IE2eEndpoint FindLocalEndpoint(string KeyName)
907 {
908 return this.FindLocalEndpoint(KeyName, string.Empty);
909 }
910
917 public IE2eEndpoint FindLocalEndpoint(string KeyName, string KeyNamespace)
918 {
919 IE2eEndpoint[] Endpoints = this.keys;
920 int c = Endpoints.Length;
921 int i;
922
923 for (i = 0; i < c; i++)
924 {
925 if (Endpoints[i].LocalName == KeyName &&
926 (Endpoints[i].Namespace == KeyNamespace || string.IsNullOrEmpty(KeyNamespace)))
927 {
928 return Endpoints[i];
929 }
930 }
931
932 return null;
933 }
934
946 public virtual async Task<Tuple<string, string>> Decrypt(XmppClient Client, string Id, string Type, string From, string To, XmlElement E2eElement,
947 IE2eSymmetricCipher SymmetricCipher)
948 {
949 bool SniffE2eInfo = Client.HasSniffers && Client.TryGetTag("ShowE2E", out object Obj) && Obj is bool b && b;
950 string EndpointReference = XML.Attribute(E2eElement, "r");
951 IE2eEndpoint RemoteEndpoint = this.FindRemoteEndpoint(From, EndpointReference);
952 if (RemoteEndpoint is null)
953 {
954 if (SniffE2eInfo)
955 await Client.Error("Remote E2E endpoint not found. Unable to decrypt message.");
956
957 return null;
958 }
959
960 IE2eEndpoint LocalEndpoint = this.FindLocalEndpoint(RemoteEndpoint);
961 if (LocalEndpoint is null)
962 {
963 if (SniffE2eInfo)
964 await Client.Error("Local E2E endpoint matching remote endpoint not found. Unable to decrypt message.");
965
966 return null;
967 }
968
969 IE2eSymmetricCipher Cipher = LocalEndpoint.DefaultSymmetricCipher;
970 if (!(SymmetricCipher is null) && Cipher.GetType() != SymmetricCipher.GetType())
971 Cipher = SymmetricCipher;
972
973 string Xml = Cipher.Decrypt(Id, Type, From, To, E2eElement, RemoteEndpoint, LocalEndpoint);
974 if (Xml is null)
975 {
976 if (SniffE2eInfo)
977 await Client.Error("Unable to decrypt message.");
978
979 return null;
980 }
981
982 if (SniffE2eInfo)
983 await Client.Information(Xml);
984
985 return new Tuple<string, string>(Xml, EndpointReference);
986 }
987
988 private Task AesMessageHandler(object Sender, MessageEventArgs e)
989 {
990 return this.E2eMessageHandler(Sender, e, this.aes);
991 }
992
993 private Task AcpMessageHandler(object Sender, MessageEventArgs e)
994 {
995 return this.E2eMessageHandler(Sender, e, this.acp);
996 }
997
998 private Task ChaMessageHandler(object Sender, MessageEventArgs e)
999 {
1000 return this.E2eMessageHandler(Sender, e, this.cha);
1001 }
1002
1003 private async Task E2eMessageHandler(object Sender, MessageEventArgs e, IE2eSymmetricCipher Cipher)
1004 {
1005 XmppClient Client = Sender as XmppClient;
1006 Tuple<string, string> T = await this.Decrypt(Client, e.Id, e.Message.GetAttribute("type"), e.From, e.To, e.Content, Cipher);
1007 if (T is null)
1008 {
1009 await Client.Error("Unable to decrypt or verify message.");
1010 return;
1011 }
1012
1013 string Xml = T.Item1;
1014 string EndpointReference = T.Item2;
1015
1016 XmlDocument Doc = new XmlDocument()
1017 {
1018 PreserveWhitespace = true
1019 };
1020 Doc.LoadXml(Xml);
1021
1022 MessageEventArgs e2 = new MessageEventArgs(Client, Doc.DocumentElement)
1023 {
1024 From = e.From,
1025 To = e.To,
1026 Id = e.Id,
1027 E2eEncryption = this,
1028 E2eReference = EndpointReference
1029 };
1030
1031 Client.ProcessMessage(e2);
1032 }
1033
1041 public virtual bool TryGetSymmetricCipher(string LocalName, string Namespace, out IE2eSymmetricCipher Cipher)
1042 {
1043 switch (LocalName)
1044 {
1045 case "aes": Cipher = this.aes; return true;
1046 case "acp": Cipher = this.acp; return true;
1047 case "cha": Cipher = this.cha; return true;
1048 }
1049
1050 Cipher = null;
1051 return false;
1052 }
1053
1059 protected virtual async Task IqResult(object Sender, IqResultEventArgs e)
1060 {
1061 XmppClient Client = Sender as XmppClient;
1062 XmlElement E = e.FirstElement;
1063 object[] P = (object[])e.State;
1064 EventHandlerAsync<IqResultEventArgs> Callback = (EventHandlerAsync<IqResultEventArgs>)P[0];
1065 object State = P[1];
1066
1067 if (!this.TryGetSymmetricCipher(E.LocalName, E.NamespaceURI, out IE2eSymmetricCipher Cipher))
1068 Cipher = null;
1069
1070 if (!(Cipher is null))
1071 {
1072 Tuple<string, string> T = await this.Decrypt(Client, e.Id, e.Response.GetAttribute("type"), e.From, e.To, E, Cipher);
1073 if (T is null)
1074 {
1075 await Client.Error("Unable to decrypt or verify response.");
1076 return;
1077 }
1078
1079 string Content = T.Item1;
1080 string EndpointReference = T.Item2;
1081 StringBuilder Xml = new StringBuilder();
1082
1083 Xml.Append("<iq xmlns=\"jabber:client\" id=\"");
1084 Xml.Append(e.Id);
1085 Xml.Append("\" from=\"");
1086 Xml.Append(XML.Encode(e.From));
1087 Xml.Append("\" to=\"");
1088 Xml.Append(XML.Encode(e.To));
1089
1090 if (e.Ok)
1091 Xml.Append("\" type=\"result\">");
1092 else
1093 Xml.Append("\" type=\"error\">");
1094
1095 Xml.Append(Content);
1096 Xml.Append("</iq>");
1097
1098 XmlDocument Doc = new XmlDocument()
1099 {
1100 PreserveWhitespace = true
1101 };
1102 Doc.LoadXml(Xml.ToString());
1103
1104 IqResultEventArgs e2 = new IqResultEventArgs(this, EndpointReference, Cipher,
1105 Doc.DocumentElement, e.Id, e.To, e.From, e.Ok, State);
1106 await Callback.Raise(Sender, e2);
1107 }
1108 else if (!e.Ok && this.IsForbidden(e.ErrorElement))
1109 {
1111 string Id = (string)P[3];
1112 string To = (string)P[4];
1113 string Xml = (string)P[5];
1114 string Type = (string)P[6];
1115 int RetryTimeout = (int)P[7];
1116 int NrRetries = (int)P[8];
1117 bool DropOff = (bool)P[9];
1118 int MaxRetryTimeout = (int)P[10];
1119 bool PkiSynchronized = (bool)P[11];
1120
1121 if (PkiSynchronized)
1122 {
1123 e.State = State;
1124 await Callback.Raise(Sender, e);
1125 }
1126 else
1127 {
1128 await this.SynchronizeE2e(To, async (Sender2, e2) =>
1129 {
1130 if (e2.Ok)
1131 {
1132 await this.SendIq(Client, E2ETransmission, Id, To, Xml, Type, Callback, State,
1133 RetryTimeout, NrRetries, DropOff, MaxRetryTimeout, true);
1134 }
1135 else
1136 {
1137 e.State = State;
1138 await Callback.Raise(Sender, e);
1139 }
1140 });
1141 };
1142 }
1143 else
1144 {
1145 e.State = State;
1146 await Callback.Raise(Sender, e);
1147 }
1148 }
1149
1150 private bool IsForbidden(XmlElement E)
1151 {
1152 if (E is null)
1153 return false;
1154
1155 XmlElement E2;
1156
1157 foreach (XmlNode N in E.ChildNodes)
1158 {
1159 E2 = N as XmlElement;
1160 if (E2 is null)
1161 continue;
1162
1163 if (E2.LocalName == "forbidden" && E2.NamespaceURI == XmppClient.NamespaceXmppStanzas)
1164 return true;
1165 }
1166
1167 return false;
1168 }
1169
1170 private string EmbedIq(IqEventArgs e, string Type, string Content)
1171 {
1172 StringBuilder Xml = new StringBuilder();
1173
1174 Xml.Append("<iq xmlns=\"jabber:client\" id=\"");
1175 Xml.Append(e.Id);
1176 Xml.Append("\" from=\"");
1177 Xml.Append(XML.Encode(e.From));
1178 Xml.Append("\" to=\"");
1179 Xml.Append(XML.Encode(e.To));
1180 Xml.Append("\" type=\"");
1181 Xml.Append(Type);
1182 Xml.Append("\">");
1183 Xml.Append(Content);
1184 Xml.Append("</iq>");
1185
1186 return Xml.ToString();
1187 }
1188
1189 private Task AesIqGetHandler(object Sender, IqEventArgs e)
1190 {
1191 return this.E2eIqGetHandler(Sender, e, this.aes);
1192 }
1193
1194 private Task AcpIqGetHandler(object Sender, IqEventArgs e)
1195 {
1196 return this.E2eIqGetHandler(Sender, e, this.acp);
1197 }
1198
1199 private Task ChaIqGetHandler(object Sender, IqEventArgs e)
1200 {
1201 return this.E2eIqGetHandler(Sender, e, this.cha);
1202 }
1203
1204 private async Task E2eIqGetHandler(object Sender, IqEventArgs e, IE2eSymmetricCipher Cipher)
1205 {
1206 XmppClient Client = Sender as XmppClient;
1207 Tuple<string, string> T = await this.Decrypt(Client, e.Id, e.IQ.GetAttribute("type"), e.From, e.To, e.Query, Cipher);
1208 if (T is null)
1209 {
1210 await Client.Error("Unable to decrypt or verify request.");
1211 await e.IqError(new ForbiddenException("Unable to decrypt or verify message.", e.IQ));
1212 return;
1213 }
1214
1215 string Content = T.Item1;
1216 string EndpointReference = T.Item2;
1217
1218 XmlDocument Doc = new XmlDocument()
1219 {
1220 PreserveWhitespace = true
1221 };
1222 Doc.LoadXml(this.EmbedIq(e, "get", Content));
1223
1224 IqEventArgs e2 = new IqEventArgs(Client, this, EndpointReference, Cipher, Doc.DocumentElement, e.Id, e.To, e.From);
1225 await Client.ProcessIqGet(e2);
1226 }
1227
1228 private Task AesIqSetHandler(object Sender, IqEventArgs e)
1229 {
1230 return this.E2eIqSetHandler(Sender, e, this.aes);
1231 }
1232
1233 private Task AcpIqSetHandler(object Sender, IqEventArgs e)
1234 {
1235 return this.E2eIqSetHandler(Sender, e, this.acp);
1236 }
1237
1238 private Task ChaIqSetHandler(object Sender, IqEventArgs e)
1239 {
1240 return this.E2eIqSetHandler(Sender, e, this.cha);
1241 }
1242
1243 private async Task E2eIqSetHandler(object Sender, IqEventArgs e, IE2eSymmetricCipher Cipher)
1244 {
1245 XmppClient Client = Sender as XmppClient;
1246 Tuple<string, string> T = await this.Decrypt(Client, e.Id, e.IQ.GetAttribute("type"), e.From, e.To, e.Query, Cipher);
1247 if (T is null)
1248 {
1249 await Client.Error("Unable to decrypt or verify request.");
1250 await e.IqError(new ForbiddenException("Unable to decrypt or verify message.", e.IQ));
1251 return;
1252 }
1253
1254 string Content = T.Item1;
1255 string EndpointReference = T.Item2;
1256
1257 XmlDocument Doc = new XmlDocument()
1258 {
1259 PreserveWhitespace = true
1260 };
1261 Doc.LoadXml(this.EmbedIq(e, "set", Content));
1262
1263 IqEventArgs e2 = new IqEventArgs(Client, this, EndpointReference, Cipher, Doc.DocumentElement, e.Id, e.To, e.From);
1264 await Client.ProcessIqSet(e2);
1265 }
1266
1285 MessageType Type, string Id, string To, string CustomXml, string Body, string Subject,
1286 string Language, string ThreadId, string ParentThreadId, EventHandlerAsync<DeliveryEventArgs> DeliveryCallback,
1287 object State)
1288 {
1289 return this.SendMessage(Client, E2ETransmission, QoS, Type, Id, To, CustomXml, Body, Subject,
1290 Language, ThreadId, ParentThreadId, DeliveryCallback, State, false);
1291 }
1292
1311 private async Task SendMessage(XmppClient Client, E2ETransmission E2ETransmission, QoSLevel QoS,
1312 MessageType Type, string Id, string To, string CustomXml, string Body, string Subject,
1313 string Language, string ThreadId, string ParentThreadId, EventHandlerAsync<DeliveryEventArgs> DeliveryCallback,
1314 object State, bool PkiSynchronized)
1315 {
1316 if (this.client is null)
1317 throw new ObjectDisposedException("Endpoint security object disposed.");
1318
1319 if (string.IsNullOrEmpty(Id))
1320 Id = Client.NextId();
1321
1322 StringBuilder Xml = new StringBuilder();
1323
1324 Xml.Append("<message");
1325
1326 switch (Type)
1327 {
1328 case MessageType.Chat:
1329 Xml.Append(" type=\"chat\"");
1330 break;
1331
1332 case MessageType.Error:
1333 Xml.Append(" type=\"error\"");
1334 break;
1335
1336 case MessageType.GroupChat:
1337 Xml.Append(" type=\"groupchat\"");
1338 break;
1339
1340 case MessageType.Headline:
1341 Xml.Append(" type=\"headline\"");
1342 break;
1343 }
1344
1345 if (!string.IsNullOrEmpty(Language))
1346 {
1347 Xml.Append(" xml:lang=\"");
1348 Xml.Append(XML.Encode(Language));
1349 Xml.Append('"');
1350 }
1351
1352 Xml.Append('>');
1353
1354 if (!string.IsNullOrEmpty(Subject))
1355 {
1356 Xml.Append("<subject>");
1357 Xml.Append(XML.Encode(Subject));
1358 Xml.Append("</subject>");
1359 }
1360
1361 Xml.Append("<body>");
1362 Xml.Append(XML.Encode(Body));
1363 Xml.Append("</body>");
1364
1365 if (!string.IsNullOrEmpty(ThreadId))
1366 {
1367 Xml.Append("<thread");
1368
1369 if (!string.IsNullOrEmpty(ParentThreadId))
1370 {
1371 Xml.Append(" parent=\"");
1372 Xml.Append(XML.Encode(ParentThreadId));
1373 Xml.Append('"');
1374 }
1375
1376 Xml.Append(">");
1377 Xml.Append(XML.Encode(ThreadId));
1378 Xml.Append("</thread>");
1379 }
1380
1381 if (!string.IsNullOrEmpty(CustomXml))
1382 Xml.Append(CustomXml);
1383
1384 Xml.Append("</message>");
1385
1386 string MessageXml = Xml.ToString();
1387 StringBuilder Encrypted = new StringBuilder();
1388
1389 if (await this.Encrypt(Client, Id, string.Empty, this.client.FullJID, To, MessageXml, Encrypted))
1390 {
1391 MessageXml = Encrypted.ToString();
1392
1393 await Client.SendMessage(QoS, MessageType.Normal, Id, To, MessageXml, string.Empty,
1394 string.Empty, string.Empty, string.Empty, string.Empty, DeliveryCallback, State);
1395
1396 return;
1397 }
1398 else if (XmppClient.GetBareJID(To) == To)
1399 {
1400 RosterItem Item = Client.GetRosterItem(To);
1401 bool Found = false;
1402
1403 if (!(Item is null))
1404 {
1405 foreach (PresenceEventArgs e in Item.Resources)
1406 {
1407 Encrypted.Clear();
1408
1409 if (await this.Encrypt(Client, Id, string.Empty, this.client.FullJID, e.From, MessageXml, Encrypted))
1410 {
1411 await Client.SendMessage(QoS, MessageType.Normal, Id, e.From, Encrypted.ToString(), string.Empty,
1412 string.Empty, string.Empty, string.Empty, string.Empty, DeliveryCallback, State);
1413
1414 Found = true;
1415 }
1416 }
1417 }
1418
1419 if (Found)
1420 return;
1421 }
1422
1423 if (E2ETransmission == E2ETransmission.IgnoreIfNotE2E)
1424 return;
1425
1426 if (!PkiSynchronized)
1427 {
1428 await this.SynchronizeE2e(To, async (Sender, e) =>
1429 {
1430 if (e.Ok)
1431 {
1432 await this.SendMessage(Client, E2ETransmission, QoS, Type, Id, To, CustomXml, Body, Subject,
1433 Language, ThreadId, ParentThreadId, DeliveryCallback, State, true);
1434 }
1435 else if (E2ETransmission == E2ETransmission.NormalIfNotE2E)
1436 {
1437 await Client.SendMessage(QoS, Type, Id, To, CustomXml, Body, Subject, Language,
1438 ThreadId, ParentThreadId, DeliveryCallback, State);
1439 }
1440 else if (!(DeliveryCallback is null)) // null Callbacks are common, and should not result in a warning in sniffers.
1441 await DeliveryCallback.Raise(Sender, new DeliveryEventArgs(State, false));
1442
1443 }, State);
1444 }
1445 else if (E2ETransmission == E2ETransmission.NormalIfNotE2E)
1446 {
1447 await Client.SendMessage(QoS, Type, Id, To, CustomXml, Body, Subject, Language,
1448 ThreadId, ParentThreadId, DeliveryCallback, State);
1449 }
1450 else
1451 throw new InvalidOperationException("End-to-End Encryption not available between " + Client.FullJID + " and " + To + ".");
1452 }
1453
1464 public Task<uint> SendIqGet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml,
1465 EventHandlerAsync<IqResultEventArgs> Callback, object State)
1466 {
1467 return this.SendIq(Client, E2ETransmission, null, To, Xml, "get", Callback, State, Client.DefaultRetryTimeout,
1468 Client.DefaultNrRetries, Client.DefaultDropOff, Client.DefaultMaxRetryTimeout, false);
1469 }
1470
1483 public Task<uint> SendIqGet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml,
1484 EventHandlerAsync<IqResultEventArgs> Callback, object State, int RetryTimeout, int NrRetries)
1485 {
1486 return this.SendIq(Client, E2ETransmission, null, To, Xml, "get", Callback, State, RetryTimeout, NrRetries, false,
1487 RetryTimeout, false);
1488 }
1489
1505 public Task<uint> SendIqGet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml,
1506 EventHandlerAsync<IqResultEventArgs> Callback, object State, int RetryTimeout, int NrRetries, bool DropOff,
1507 int MaxRetryTimeout)
1508 {
1509 return this.SendIq(Client, E2ETransmission, null, To, Xml, "get", Callback, State, RetryTimeout,
1510 NrRetries, DropOff, MaxRetryTimeout, false);
1511 }
1512
1523 public Task<uint> SendIqSet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml,
1524 EventHandlerAsync<IqResultEventArgs> Callback, object State)
1525 {
1526 return this.SendIq(Client, E2ETransmission, null, To, Xml, "set", Callback, State,
1528 Client.DefaultMaxRetryTimeout, false);
1529 }
1530
1543 public Task<uint> SendIqSet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml,
1544 EventHandlerAsync<IqResultEventArgs> Callback, object State, int RetryTimeout, int NrRetries)
1545 {
1546 return this.SendIq(Client, E2ETransmission, null, To, Xml, "set", Callback, State, RetryTimeout,
1547 NrRetries, false, RetryTimeout, false);
1548 }
1549
1565 public Task<uint> SendIqSet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml,
1566 EventHandlerAsync<IqResultEventArgs> Callback, object State, int RetryTimeout, int NrRetries, bool DropOff,
1567 int MaxRetryTimeout)
1568 {
1569 return this.SendIq(Client, E2ETransmission, null, To, Xml, "set", Callback, State, RetryTimeout,
1570 NrRetries, DropOff, MaxRetryTimeout, false);
1571 }
1572
1584 public Task<uint> SendIqGet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml,
1585 EventHandlerAsync<IqResultEventArgs> Callback, object State, EventHandlerAsync<DeliveryEventArgs> DeliveryCallback)
1586 {
1587 return this.SendIq(Client, E2ETransmission, null, To, Xml, "get", Callback, State, Client.DefaultRetryTimeout,
1588 Client.DefaultNrRetries, Client.DefaultDropOff, Client.DefaultMaxRetryTimeout, false, DeliveryCallback);
1589 }
1590
1604 public Task<uint> SendIqGet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml,
1605 EventHandlerAsync<IqResultEventArgs> Callback, object State, int RetryTimeout, int NrRetries,
1606 EventHandlerAsync<DeliveryEventArgs> DeliveryCallback)
1607 {
1608 return this.SendIq(Client, E2ETransmission, null, To, Xml, "get", Callback, State, RetryTimeout, NrRetries, false,
1609 RetryTimeout, false, DeliveryCallback);
1610 }
1611
1628 public Task<uint> SendIqGet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml,
1629 EventHandlerAsync<IqResultEventArgs> Callback, object State, int RetryTimeout, int NrRetries, bool DropOff,
1630 int MaxRetryTimeout, EventHandlerAsync<DeliveryEventArgs> DeliveryCallback)
1631 {
1632 return this.SendIq(Client, E2ETransmission, null, To, Xml, "get", Callback, State, RetryTimeout,
1633 NrRetries, DropOff, MaxRetryTimeout, false, DeliveryCallback);
1634 }
1635
1647 public Task<uint> SendIqSet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml,
1648 EventHandlerAsync<IqResultEventArgs> Callback, object State, EventHandlerAsync<DeliveryEventArgs> DeliveryCallback)
1649 {
1650 return this.SendIq(Client, E2ETransmission, null, To, Xml, "set", Callback, State,
1652 Client.DefaultMaxRetryTimeout, false, DeliveryCallback);
1653 }
1654
1668 public Task<uint> SendIqSet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml,
1669 EventHandlerAsync<IqResultEventArgs> Callback, object State, int RetryTimeout, int NrRetries,
1670 EventHandlerAsync<DeliveryEventArgs> DeliveryCallback)
1671 {
1672 return this.SendIq(Client, E2ETransmission, null, To, Xml, "set", Callback, State, RetryTimeout,
1673 NrRetries, false, RetryTimeout, false, DeliveryCallback);
1674 }
1675
1692 public Task<uint> SendIqSet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml,
1693 EventHandlerAsync<IqResultEventArgs> Callback, object State, int RetryTimeout, int NrRetries, bool DropOff,
1694 int MaxRetryTimeout, EventHandlerAsync<DeliveryEventArgs> DeliveryCallback)
1695 {
1696 return this.SendIq(Client, E2ETransmission, null, To, Xml, "set", Callback, State, RetryTimeout,
1697 NrRetries, DropOff, MaxRetryTimeout, false, DeliveryCallback);
1698 }
1699
1708 public Task SendIqResult(XmppClient Client, E2ETransmission E2ETransmission, string Id, string To, string Xml)
1709 {
1710 return this.SendIq(Client, E2ETransmission, Id, To, Xml, "result", null, null, 0, 0, false, 0, false);
1711 }
1712
1721 public Task SendIqError(XmppClient Client, E2ETransmission E2ETransmission, string Id, string To, string Xml)
1722 {
1723 return this.SendIq(Client, E2ETransmission, Id, To, Xml, "error", null, null, 0, 0, false, 0, false);
1724 }
1725
1734 public async Task SendIqError(XmppClient Client, E2ETransmission E2ETransmission, string Id, string To,
1735 Exception ex)
1736 {
1737 await this.SendIqError(Client, E2ETransmission, Id, To, await Client.ExceptionToXmppXml(ex));
1738 }
1739
1761 protected Task<uint> SendIq(XmppClient Client, E2ETransmission E2ETransmission, string Id, string To, string Xml,
1762 string Type, EventHandlerAsync<IqResultEventArgs> Callback, object State, int RetryTimeout, int NrRetries, bool DropOff,
1763 int MaxRetryTimeout, bool PkiSynchronized)
1764 {
1765 return this.SendIq(Client, E2ETransmission, Id, To, Xml, Type, Callback, State, RetryTimeout, NrRetries, DropOff,
1766 MaxRetryTimeout, PkiSynchronized, null);
1767 }
1768
1791 protected async Task<uint> SendIq(XmppClient Client, E2ETransmission E2ETransmission, string Id, string To, string Xml,
1792 string Type, EventHandlerAsync<IqResultEventArgs> Callback, object State, int RetryTimeout, int NrRetries, bool DropOff,
1793 int MaxRetryTimeout, bool PkiSynchronized, EventHandlerAsync<DeliveryEventArgs> DeliveryCallback)
1794 {
1795 if (this.client is null)
1796 throw new ObjectDisposedException("Endpoint security object disposed.");
1797
1798 if (string.IsNullOrEmpty(Id))
1799 Id = Client.NextId();
1800
1801 StringBuilder Encrypted = new StringBuilder();
1802
1803 if (await this.Encrypt(Client, Id, Type, this.client.FullJID, To, Xml, Encrypted))
1804 {
1805 string XmlEnc = Encrypted.ToString();
1806
1807 return await Client.SendIq(Id, To, XmlEnc, Type, this.IqResult,
1808 new object[] { Callback, State, E2ETransmission, Id, To, Xml, Type, RetryTimeout, NrRetries, DropOff, MaxRetryTimeout, PkiSynchronized },
1809 RetryTimeout, NrRetries, DropOff, MaxRetryTimeout, DeliveryCallback);
1810 }
1811
1812 if (E2ETransmission == E2ETransmission.IgnoreIfNotE2E)
1813 {
1814 if (uint.TryParse(Id, out uint SeqNr))
1815 return SeqNr;
1816 else
1817 return 0;
1818 }
1819
1820 if (!PkiSynchronized)
1821 {
1822 if (!uint.TryParse(Id, out uint SeqNr))
1823 {
1824 Id = Client.NextId();
1825 SeqNr = uint.Parse(Id);
1826 }
1827
1828 await this.SynchronizeE2e(To, async (Sender, e) =>
1829 {
1830 if (e.Ok)
1831 {
1832 await this.SendIq(Client, E2ETransmission, Id, To, Xml, Type, Callback, State,
1833 RetryTimeout, NrRetries, DropOff, MaxRetryTimeout, true, DeliveryCallback);
1834 }
1835 else if (E2ETransmission == E2ETransmission.NormalIfNotE2E)
1836 {
1837 await Client.SendIq(Id, To, Xml, Type, Callback, State, RetryTimeout,
1838 NrRetries, DropOff, MaxRetryTimeout, DeliveryCallback);
1839 }
1840 else
1841 {
1842 if (!(DeliveryCallback is null))
1843 await DeliveryCallback.Raise(Sender, new DeliveryEventArgs(Sender, true));
1844
1845 await Callback.Raise(Sender, e);
1846 }
1847 }, State);
1848
1849 return SeqNr;
1850 }
1851 else if (E2ETransmission == E2ETransmission.NormalIfNotE2E)
1852 {
1853 return await Client.SendIq(Id, To, Xml, Type, Callback, State, RetryTimeout,
1854 NrRetries, DropOff, MaxRetryTimeout, DeliveryCallback);
1855 }
1856 else
1857 throw new InvalidOperationException("End-to-End Encryption not available between " + Client.FullJID + " and " + To + ".");
1858 }
1859
1871 public XmlElement IqGet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml, int Timeout)
1872 {
1873 Task<XmlElement> Result = this.IqGetAsync(Client, E2ETransmission, To, Xml);
1874
1875 if (!Result.Wait(Timeout))
1876 throw new TimeoutException();
1877
1878 return Result.Result;
1879 }
1880
1891 public async Task<XmlElement> IqGetAsync(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml)
1892 {
1893 TaskCompletionSource<XmlElement> Result = new TaskCompletionSource<XmlElement>();
1894
1895 await this.SendIqGet(Client, E2ETransmission, To, Xml, (Sender, e) =>
1896 {
1897 if (e.Ok)
1898 Result.TrySetResult(e.Response);
1899 else
1900 Result.TrySetException(e.StanzaError ?? new XmppException("Unable to perform IQ Get."));
1901
1902 return Task.CompletedTask;
1903
1904 }, null);
1905
1906 return await Result.Task;
1907 }
1908
1920 public XmlElement IqSet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml, int Timeout)
1921 {
1922 Task<XmlElement> Result = this.IqSetAsync(Client, E2ETransmission, To, Xml);
1923
1924 if (!Result.Wait(Timeout))
1925 throw new TimeoutException();
1926
1927 return Result.Result;
1928 }
1929
1940 public async Task<XmlElement> IqSetAsync(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml)
1941 {
1942 TaskCompletionSource<XmlElement> Result = new TaskCompletionSource<XmlElement>();
1943
1944 await this.SendIqSet(Client, E2ETransmission, To, Xml, (Sender, e) =>
1945 {
1946 if (e.Ok)
1947 Result.TrySetResult(e.Response);
1948 else
1949 Result.TrySetException(e.StanzaError ?? new XmppException("Unable to perform IQ Set."));
1950
1951 return Task.CompletedTask;
1952
1953 }, null);
1954
1955 return await Result.Task;
1956 }
1957
1962 public void AppendE2eInfo(StringBuilder Xml)
1963 {
1964 Xml.Append("<e2e xmlns=\"");
1965 Xml.Append(IoTHarmonizationE2ECurrent);
1966 Xml.Append("\">");
1967
1968 foreach (IE2eEndpoint E2e in this.keys)
1970
1971 Xml.Append("</e2e>");
1972 }
1973
1979 public Task SynchronizeE2e(string FullJID, EventHandlerAsync<IqResultEventArgs> Callback)
1980 {
1981 return this.SynchronizeE2e(FullJID, Callback, null);
1982 }
1983
1990 public async Task SynchronizeE2e(string FullJID, EventHandlerAsync<IqResultEventArgs> Callback, object State)
1991 {
1992 LinkedList<SynchRec> CallbackList;
1993
1994 lock (this.synchronizationTasks)
1995 {
1996 SynchRec Rec = new SynchRec()
1997 {
1998 Callback = Callback,
1999 State = State
2000 };
2001
2002 if (this.synchronizationTasks.TryGetValue(FullJID, out CallbackList))
2003 {
2004 CallbackList.AddLast(Rec);
2005 return;
2006 }
2007
2008 CallbackList = new LinkedList<SynchRec>();
2009 CallbackList.AddLast(Rec);
2010
2011 this.synchronizationTasks[FullJID] = CallbackList;
2012 }
2013
2014 await this.client.SendIqSet(FullJID, this.GetE2eXml(), async (Sender, e) =>
2015 {
2016 lock (this.synchronizationTasks)
2017 {
2018 if (!this.synchronizationTasks.TryGetValue(FullJID, out CallbackList))
2019 return;
2020
2021 this.synchronizationTasks.Remove(FullJID);
2022 }
2023
2024 if (e.Ok && !(e.FirstElement is null))
2025 await this.ParseE2e(e.FirstElement, FullJID);
2026
2027 foreach (SynchRec Rec in CallbackList)
2028 {
2029 e.State = Rec.State;
2030 await Rec.Callback.Raise(Sender, e);
2031 }
2032 }, State);
2033 }
2034
2035 private readonly Dictionary<string, LinkedList<SynchRec>> synchronizationTasks = new Dictionary<string, LinkedList<SynchRec>>();
2036
2037 private class SynchRec
2038 {
2039 public EventHandlerAsync<IqResultEventArgs> Callback;
2040 public object State;
2041 }
2042
2043 private string GetE2eXml()
2044 {
2045 StringBuilder Xml = new StringBuilder();
2046
2047 Xml.Append("<synchE2e xmlns=\"");
2048 Xml.Append(IoTHarmonizationE2ECurrent);
2049 Xml.Append("\">");
2050
2051 this.AppendE2eInfo(Xml);
2052 this.serverlessMessaging?.AppendP2pInfo(Xml);
2053
2054 Xml.Append("</synchE2e>");
2055
2056 return Xml.ToString();
2057 }
2058
2059 private async Task ParseE2e(XmlElement E, string RemoteFullJID)
2060 {
2061 XmlElement E2E = null;
2062 XmlElement P2P = null;
2063
2064 if (!(E is null) && E.LocalName == "synchE2e")
2065 {
2066 foreach (XmlNode N in E.ChildNodes)
2067 {
2068 if (N is XmlElement E2)
2069 {
2070 switch (E2.LocalName)
2071 {
2072 case "e2e":
2073 if (Array.IndexOf(NamespacesIoTHarmonizationE2E, E.NamespaceURI) >= 0)
2074 E2E = E2;
2075 break;
2076
2077 case "p2p":
2078 if (Array.IndexOf(NamespacesIoTHarmonizationP2P, E.NamespaceURI) >= 0)
2079 P2P = E2;
2080 break;
2081 }
2082 }
2083 }
2084 }
2085
2086 bool HasE2E = this.AddPeerPkiInfo(RemoteFullJID, E2E);
2087 bool HasP2P = !(this.serverlessMessaging is null) && await this.serverlessMessaging.AddPeerAddressInfo(RemoteFullJID, P2P);
2088
2089 await this.PeerUpdated.Raise(this, new PeerSynchronizedEventArgs(RemoteFullJID, HasE2E, HasP2P));
2090 }
2091
2092 private async Task SynchE2eHandler(object Sender, IqEventArgs e)
2093 {
2094 RosterItem Item;
2095
2096 if (e.FromBareJid != this.client.BareJID &&
2097 ((Item = this.client.GetRosterItem(e.FromBareJid)) is null ||
2098 Item.State == SubscriptionState.None ||
2099 Item.State == SubscriptionState.Remove ||
2100 Item.State == SubscriptionState.Unknown))
2101 {
2102 throw new ForbiddenException("Access denied. Unable to synchronize E2EE.", e.IQ);
2103 }
2104
2105 await this.ParseE2e(e.Query, e.From);
2106 await e.IqResult(this.GetE2eXml());
2107 }
2108
2109 private async Task Client_OnPresence(object Sender, PresenceEventArgs e)
2110 {
2111 switch (e.Type)
2112 {
2113 case PresenceType.Available:
2114 XmlElement E2E = null;
2115 XmlElement P2P = null;
2116
2117 foreach (XmlNode N in e.Presence.ChildNodes)
2118 {
2119 if (N is XmlElement E)
2120 {
2121 switch (E.LocalName)
2122 {
2123 case "e2e":
2124 if (Array.IndexOf(NamespacesIoTHarmonizationE2E, E.NamespaceURI) >= 0)
2125 E2E = E;
2126 break;
2127
2128 case "p2p":
2129 if (Array.IndexOf(NamespacesIoTHarmonizationP2P, E.NamespaceURI) >= 0)
2130 P2P = E;
2131 break;
2132 }
2133 }
2134 }
2135
2136 bool HasE2E = this.AddPeerPkiInfo(e.From, E2E);
2137 bool HasP2P = !(this.serverlessMessaging is null) && await this.serverlessMessaging.AddPeerAddressInfo(e.From, P2P);
2138
2139 await this.PeerAvailable.Raise(this, new AvailableEventArgs(e, HasE2E, HasP2P));
2140 break;
2141
2142 case PresenceType.Unavailable:
2143 await this.PeerUnavailable.Raise(this, e);
2144 break;
2145 }
2146 }
2147
2151 public event EventHandlerAsync<AvailableEventArgs> PeerAvailable = null;
2152
2156 public event EventHandlerAsync<PresenceEventArgs> PeerUnavailable = null;
2157
2161 public event EventHandlerAsync<PeerSynchronizedEventArgs> PeerUpdated = null;
2162
2169 {
2170 return this.GetLocalKey(Key.GetType());
2171 }
2172
2178 public IE2eEndpoint GetLocalKey(Type KeyType)
2179 {
2180 foreach (IE2eEndpoint Endpoint in this.keys)
2181 {
2182 if (Endpoint.GetType() == KeyType)
2183 return Endpoint;
2184 }
2185
2186 if (!typeof(IE2eEndpoint).GetTypeInfo().IsAssignableFrom(KeyType.GetTypeInfo()))
2187 throw new ArgumentException("Not assignable from " + typeof(IE2eEndpoint).FullName, nameof(KeyType));
2188
2189 return null;
2190 }
2191
2197 public IE2eEndpoint GetLocalKey(byte[] PublicKey)
2198 {
2199 if (PublicKey is null)
2200 return null;
2201
2202 string s = Convert.ToBase64String(PublicKey);
2203
2204 foreach (IE2eEndpoint Endpoint in this.keys)
2205 {
2206 if (Endpoint.PublicKeyBase64 == s)
2207 return Endpoint;
2208 }
2209
2210 return null;
2211 }
2212
2213 }
2214}
Helps with common XML-related tasks.
Definition: XML.cs:19
static string Attribute(XmlElement E, string Name)
Gets the value of an XML attribute.
Definition: XML.cs:914
static string Encode(string s)
Encodes a string for use in XML.
Definition: XML.cs:27
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:13
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
Definition: Log.cs:1647
Task Information(string Comment)
Called to inform the viewer of something.
Task Warning(string Warning)
Called to inform the viewer of a warning state.
Event arguments for delivery events.
Event Argument for custom presence XML events.
Event arguments for IQ queries.
Definition: IqEventArgs.cs:12
async Task IqError(string Xml)
Returns an error response to the current request.
Definition: IqEventArgs.cs:208
async Task IqResult(string Xml)
Returns a response to the current request.
Definition: IqEventArgs.cs:194
XmlElement Query
Query element, if found, null otherwise.
Definition: IqEventArgs.cs:119
string From
From address attribute
Definition: IqEventArgs.cs:137
string To
To address attribute
Definition: IqEventArgs.cs:132
string FromBareJid
Bare version of the "from" JID.
Definition: IqEventArgs.cs:157
Event arguments for responses to IQ queries.
bool Ok
If the response is an OK result response (true), or an error response (false).
object State
State object passed to the original request.
XmlElement FirstElement
First child element of the Response element.
Event arguments for message events.
string Id
ID attribute of message stanza.
string From
From where the message was received.
bool Ok
If the response is an OK result response (true), or an error response (false).
string To
To whom the message was sent.
XmlElement Content
Content of the message. For messages that are processed by registered message handlers,...
Event arguments for presence events.
bool Ok
If the response is an OK result response (true), or an error response (false).
XmppException StanzaError
Any stanza error returned.
string From
From where the presence was received.
PresenceType Type
Type of presence received.
Event arguments for Availability events.
Abstract base class for End-to-End encryption schemes.
Definition: E2eEndpoint.cs:12
Class managing end-to-end encryption.
EventHandlerAsync< AvailableEventArgs > PeerAvailable
Event raised whenever a peer has become available.
Task< uint > SendIqSet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml, EventHandlerAsync< IqResultEventArgs > Callback, object State, int RetryTimeout, int NrRetries, bool DropOff, int MaxRetryTimeout)
Sends an IQ Set stanza
EndpointSecurity(XmppClient Client, XmppServerlessMessaging ServerlessMessaging, int SecurityStrength, params IE2eEndpoint[] LocalEndpoints)
Class managing end-to-end encryption.
Task< uint > SendIqSet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml, EventHandlerAsync< IqResultEventArgs > Callback, object State, int RetryTimeout, int NrRetries, bool DropOff, int MaxRetryTimeout, EventHandlerAsync< DeliveryEventArgs > DeliveryCallback)
Sends an IQ Set stanza
async Task SendIqError(XmppClient Client, E2ETransmission E2ETransmission, string Id, string To, Exception ex)
Sends an IQ Error stanza
virtual bool TryGetSymmetricCipher(string LocalName, string Namespace, out IE2eSymmetricCipher Cipher)
Tries to get a symmetric cipher from a reference.
const string IoTHarmonizationE2ENeuroFoundationV1
urn:nf:iot:e2e:1.0
IE2eEndpoint[] GetE2eEndpoints(string FullJid)
Gets available E2E options for a given endpoint.
XmlElement IqGet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml, int Timeout)
Sends an IQ Get stanza
const string IoTHarmonizationP2PIeeeV1
urn:ieee:iot:p2p:1.0
Task< uint > SendIqGet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends an IQ Get stanza
static readonly string[] NamespacesIoTHarmonizationE2E
Namespaces supported for End-to-end encryption.
virtual void RegisterHandlers(XmppClient Client)
Registers XMPP stanza handlers
virtual async Task< Stream > Decrypt(string EndpointReference, string Id, string Type, string From, string To, Stream Data, IE2eSymmetricCipher SymmetricCipher)
Decrypts binary data received from an XMPP client out of band.
Task< uint > SendIqGet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml, EventHandlerAsync< IqResultEventArgs > Callback, object State, EventHandlerAsync< DeliveryEventArgs > DeliveryCallback)
Sends an IQ Get stanza
static List< IE2eEndpoint > ParseE2eKeys(XmlElement E2E)
Parses a set of E2E keys from XML.
static bool TryCreateEndpoint(string LocalName, string Namespace, out IE2eEndpoint Endpoint)
Tries to create a new endpoint, given its qualified name.
IE2eEndpoint GetLocalKey(IE2eEndpoint Key)
Gets the local key of a given type.
virtual Task< byte[]> Decrypt(string EndpointReference, string Id, string Type, string From, string To, byte[] Data, IE2eSymmetricCipher SymmetricCipher)
Decrypts binary data from an endpoint.
Task< uint > SendIqGet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml, EventHandlerAsync< IqResultEventArgs > Callback, object State, int RetryTimeout, int NrRetries, bool DropOff, int MaxRetryTimeout)
Sends an IQ Get stanza
virtual Task< byte[]> Encrypt(string Id, string Type, string From, string To, byte[] Data, out IE2eEndpoint EndpointReference)
Encrypts binary data for transmission to an endpoint.
const string IoTHarmonizationP2PCurrent
Current namespace for peer-to-peer communication
IE2eEndpoint GetLocalKey(Type KeyType)
Gets the local key of a given type.
IE2eEndpoint GetLocalKey(byte[] PublicKey)
Gets the local key with a given public key.
Task< uint > SendIqSet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml, EventHandlerAsync< IqResultEventArgs > Callback, object State, int RetryTimeout, int NrRetries, EventHandlerAsync< DeliveryEventArgs > DeliveryCallback)
Sends an IQ Set stanza
static IE2eEndpoint[] CreateEndpoints(int DesiredSecurityStrength, int MinSecurityStrength, int MaxSecurityStrength, Type OnlyIfDerivedFrom)
Creates a set of endpoints within a range of security strengths.
static IE2eEndpoint ParseE2eKey(XmlElement E)
Parses a single E2E key from XML.
Task< uint > SendIqGet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml, EventHandlerAsync< IqResultEventArgs > Callback, object State, int RetryTimeout, int NrRetries, bool DropOff, int MaxRetryTimeout, EventHandlerAsync< DeliveryEventArgs > DeliveryCallback)
Sends an IQ Get stanza
Task< uint > SendIqGet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml, EventHandlerAsync< IqResultEventArgs > Callback, object State, int RetryTimeout, int NrRetries)
Sends an IQ Get stanza
virtual void UnregisterHandlers(XmppClient Client)
Unregisters XMPP stanza handlers
Task< uint > SendIqSet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends an IQ Set stanza
EndpointSecurity(XmppClient Client, int SecurityStrength, params IE2eEndpoint[] LocalEndpoints)
Class managing end-to-end encryption.
async Task SynchronizeE2e(string FullJID, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Synchronizes End-to-End Encryption and Peer-to-Peer connectivity parameters with a remote entity.
EndpointSecurity(XmppClient Client, XmppServerlessMessaging ServerlessMessaging, int SecurityStrength)
Class managing end-to-end encryption.
Task< uint > SendIq(XmppClient Client, E2ETransmission E2ETransmission, string Id, string To, string Xml, string Type, EventHandlerAsync< IqResultEventArgs > Callback, object State, int RetryTimeout, int NrRetries, bool DropOff, int MaxRetryTimeout, bool PkiSynchronized)
Sends an IQ stanza
virtual async Task IqResult(object Sender, IqResultEventArgs e)
Response handler for E2E encrypted iq stanzas
void AppendE2eInfo(StringBuilder Xml)
Appends E2E information to XML.
static bool TryGetEndpoint(string LocalName, string Namespace, out IE2eEndpoint Endpoint)
Tries to get an existing endpoint, given its qualified name.
Task< uint > SendIqSet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml, EventHandlerAsync< IqResultEventArgs > Callback, object State, int RetryTimeout, int NrRetries)
Sends an IQ Set stanza
static readonly string[] NamespacesIoTHarmonizationP2P
Namespaces supported for Peer-to-peer communication.
async Task< XmlElement > IqSetAsync(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml)
Sends an IQ Set stanza
Task SendIqResult(XmppClient Client, E2ETransmission E2ETransmission, string Id, string To, string Xml)
Sends an IQ Result stanza
EndpointSecurity(XmppClient Client, int SecurityStrength)
Class managing end-to-end encryption.
const string IoTHarmonizationP2PNeuroFoundationV1
urn:nf:iot:p2p:1.0
IE2eEndpoint FindLocalEndpoint(string KeyName)
Returns the local endpoint that matches a given key name.
IE2eEndpoint FindLocalEndpoint(string KeyName, string KeyNamespace)
Returns the local endpoint that matches a given key name and namespace.
Task< uint > SendIqGet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml, EventHandlerAsync< IqResultEventArgs > Callback, object State, int RetryTimeout, int NrRetries, EventHandlerAsync< DeliveryEventArgs > DeliveryCallback)
Sends an IQ Get stanza
EventHandlerAsync< PeerSynchronizedEventArgs > PeerUpdated
Event raised whenever information about a peer has been updated.
virtual async Task< IE2eEndpoint > Encrypt(string Id, string Type, string From, string To, Stream Data, Stream Encrypted)
Encrypts binary data that can be sent to an XMPP client out of band.
Task SynchronizeE2e(string FullJID, EventHandlerAsync< IqResultEventArgs > Callback)
Synchronizes End-to-End Encryption and Peer-to-Peer connectivity parameters with a remote entity.
static void SetCiphers(Type[] CipherTypes, bool Lock)
Sets allowed cipers in endpoint security.
static IE2eEndpoint[] CreateEndpoints(int DesiredSecurityStrength, int MinSecurityStrength, int MaxSecurityStrength, Type OnlyIfDerivedFrom, ProfilerThread Thread)
Creates a set of endpoints within a range of security strengths.
static IE2eEndpoint[] CreateEndpoints(int DesiredSecurityStrength, int MinSecurityStrength, int MaxSecurityStrength)
Creates a set of endpoints within a range of security strengths.
virtual async Task< Tuple< string, string > > Decrypt(XmppClient Client, string Id, string Type, string From, string To, XmlElement E2eElement, IE2eSymmetricCipher SymmetricCipher)
Decrypts XML data from an endpoint.
async Task< uint > SendIq(XmppClient Client, E2ETransmission E2ETransmission, string Id, string To, string Xml, string Type, EventHandlerAsync< IqResultEventArgs > Callback, object State, int RetryTimeout, int NrRetries, bool DropOff, int MaxRetryTimeout, bool PkiSynchronized, EventHandlerAsync< DeliveryEventArgs > DeliveryCallback)
Sends an IQ stanza
XmlElement IqSet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml, int Timeout)
Sends an IQ Set stanza
virtual async Task< bool > Encrypt(XmppClient Client, string Id, string Type, string From, string To, string DataXml, StringBuilder Xml)
Encrypts XML data for transmission to an endpoint.
bool AddPeerPkiInfo(string FullJID, XmlElement E2E)
Adds E2E information about a peer.
const string IoTHarmonizationE2ECurrent
Current namespace for End-to-End encryption.
const string IoTHarmonizationE2EIeeeV1
urn:ieee:iot:e2e:1.0
bool ContainsKey(string FullJid)
If infomation is available for a given endpoint.
Task SendMessage(XmppClient Client, E2ETransmission E2ETransmission, QoSLevel QoS, MessageType Type, string Id, string To, string CustomXml, string Body, string Subject, string Language, string ThreadId, string ParentThreadId, EventHandlerAsync< DeliveryEventArgs > DeliveryCallback, object State)
Sends an XMPP message to an endpoint.
bool RemovePeerPkiInfo(string FullJID)
Removes E2E information about a peer.
Task< uint > SendIqSet(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml, EventHandlerAsync< IqResultEventArgs > Callback, object State, EventHandlerAsync< DeliveryEventArgs > DeliveryCallback)
Sends an IQ Set stanza
void GenerateNewKey()
Generates new local keys.
Task SendIqError(XmppClient Client, E2ETransmission E2ETransmission, string Id, string To, string Xml)
Sends an IQ Error stanza
EventHandlerAsync< PresenceEventArgs > PeerUnavailable
Event raised whenever a peer has become unavailable.
async Task< XmlElement > IqGetAsync(XmppClient Client, E2ETransmission E2ETransmission, string To, string Xml)
Sends an IQ Get stanza
virtual void Dispose()
IDisposable.Dispose
Event arguments for peer synchronization events.
Implements support for the AEAD-ChaCha20-Poly1305 cipher in hybrid End-to-End encryption schemes.
Implements support for the AES-256 cipher in hybrid End-to-End encryption schemes.
Definition: Aes256.cs:15
override void Dispose()
IDisposable.Dispose
Definition: Aes256.cs:48
Implements support for the ChaCha20 cipher in hybrid End-to-End encryption schemes.
Definition: ChaCha20.cs:15
Class managing peer-to-peer serveless XMPP communication.
Maintains information about an item in the roster.
Definition: RosterItem.cs:75
SubscriptionState State
roup Current subscription state.
Definition: RosterItem.cs:268
PresenceEventArgs[] Resources
Active resources utilized by contact.
Definition: RosterItem.cs:300
The requesting entity does not possess the necessary permissions to perform an action that only certa...
Manages an XMPP client connection. Implements XMPP, as defined in https://tools.ietf....
Definition: XmppClient.cs:59
async void ProcessMessage(MessageEventArgs e)
Processes an incoming message.
Definition: XmppClient.cs:2253
bool UnregisterMessageHandler(string LocalName, string Namespace, EventHandlerAsync< MessageEventArgs > Handler, bool RemoveNamespaceAsClientFeature)
Unregisters a Message handler.
Definition: XmppClient.cs:2855
bool UnregisterIqGetHandler(string LocalName, string Namespace, EventHandlerAsync< IqEventArgs > Handler, bool RemoveNamespaceAsClientFeature)
Unregisters an IQ-Get handler.
Definition: XmppClient.cs:2778
int DefaultRetryTimeout
Default retry timeout, in milliseconds. This value is used when sending IQ requests wihtout specifyin...
Definition: XmppClient.cs:6778
Task SendMessage(MessageType Type, string To, string CustomXml, string Body, string Subject, string Language, string ThreadId, string ParentThreadId)
Sends a simple chat message
Definition: XmppClient.cs:5395
bool DefaultDropOff
Default Drop-off value. If drop-off is used, the retry timeout is doubled for each retry,...
Definition: XmppClient.cs:6827
int DefaultNrRetries
Default number of retries if results or errors are not returned. This value is used when sending IQ r...
Definition: XmppClient.cs:6795
static string GetBareJID(string JID)
Gets the Bare JID from a JID, which may be a Full JID.
Definition: XmppClient.cs:6901
void RegisterIqSetHandler(string LocalName, string Namespace, EventHandlerAsync< IqEventArgs > Handler, bool PublishNamespaceAsClientFeature)
Registers an IQ-Set handler.
Definition: XmppClient.cs:2729
int DefaultMaxRetryTimeout
Default maximum retry timeout, in milliseconds. This value is used when sending IQ requests wihtout s...
Definition: XmppClient.cs:6811
void RegisterIqGetHandler(string LocalName, string Namespace, EventHandlerAsync< IqEventArgs > Handler, bool PublishNamespaceAsClientFeature)
Registers an IQ-Get handler.
Definition: XmppClient.cs:2717
Task ProcessIqSet(IqEventArgs e)
Processes an incoming IQ SET stanza.
Definition: XmppClient.cs:2497
Task ProcessIqGet(IqEventArgs e)
Processes an incoming IQ GET stanza.
Definition: XmppClient.cs:2488
const string NamespaceXmppStanzas
urn:ietf:params:xml:ns:xmpp-stanzas
Definition: XmppClient.cs:78
void RegisterMessageHandler(string LocalName, string Namespace, EventHandlerAsync< MessageEventArgs > Handler, bool PublishNamespaceAsClientFeature)
Registers a Message handler.
Definition: XmppClient.cs:2828
bool UnregisterIqSetHandler(string LocalName, string Namespace, EventHandlerAsync< IqEventArgs > Handler, bool RemoveNamespaceAsClientFeature)
Unregisters an IQ-Set handler.
Definition: XmppClient.cs:2791
Task< uint > SendIq(string Id, string To, string Xml, string Type, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends an IQ stanza.
Definition: XmppClient.cs:3855
Task< uint > SendIqSet(string To, string Xml, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends an IQ Set request.
Definition: XmppClient.cs:3607
bool TryGetTag(string TagName, out object Tag)
Tries to get a tag from the client. Tags can be used to attached application specific objects to the ...
Definition: XmppClient.cs:7207
async Task< string > ExceptionToXmppXml(Exception ex)
Converts an exception object to an XMPP XML error element.
Definition: XmppClient.cs:3794
string NextId()
Generates a new id attribute value.
Definition: XmppClient.cs:3829
RosterItem GetRosterItem(string BareJID)
Gets a roster item.
Definition: XmppClient.cs:4522
Base class of XMPP exceptions
Static class that dynamically manages types and interfaces available in the runtime environment.
Definition: Types.cs:14
static object[] NoParameters
Contains an empty array of parameter values.
Definition: Types.cs:548
static Type[] GetTypesImplementingInterface(string InterfaceFullName)
Gets all types implementing a given interface.
Definition: Types.cs:84
static ConstructorInfo GetDefaultConstructor(Type Type)
Gets the default constructor of a type, if one exists.
Definition: Types.cs:1630
Class that keeps track of events and timing for one thread.
ProfilerThread CreateSubThread(string Name, ProfilerThreadType Type)
Creates a new profiler thread.
void NewState(string State)
Thread changes state.
Abstract base class for End-to-End encryption schemes.
Definition: IE2eEndpoint.cs:12
void ToXml(StringBuilder Xml, string ParentNamespace)
Exports the public key information to XML.
int SecurityStrength
Security strength of End-to-End encryption scheme.
Definition: IE2eEndpoint.cs:17
IE2eEndpoint Create(int SecurityStrength)
Creates a new key.
uint GetNextCounter()
Gets the next counter value.
IE2eEndpoint Parse(XmlElement Xml)
Parses endpoint information from an XML element.
string PublicKeyBase64
Remote public key, as a Base64 string.
Definition: IE2eEndpoint.cs:58
string Namespace
Namespace of the E2E endpoint
Definition: IE2eEndpoint.cs:33
IE2eSymmetricCipher DefaultSymmetricCipher
Default symmetric cipher.
string LocalName
Local name of the E2E endpoint
Definition: IE2eEndpoint.cs:25
IE2eEndpoint Previous
Previous keys.
Definition: IE2eEndpoint.cs:41
Interface for symmetric ciphers.
byte[] Encrypt(string Id, string Type, string From, string To, uint Counter, byte[] Data, IE2eEndpoint Sender, IE2eEndpoint Receiver)
Encrypts binary data
byte[] Decrypt(string Id, string Type, string From, string To, byte[] Data, IE2eEndpoint Sender, IE2eEndpoint Receiver)
Decrypts binary data
End-to-end encryption interface.
PresenceType
Type of presence received.
Definition: PresenceType.cs:7
QoSLevel
Quality of Service Level for asynchronous messages. Support for QoS Levels must be supported by the r...
Definition: QoSLevel.cs:8
SubscriptionState
State of a presence subscription.
Definition: RosterItem.cs:16
MessageType
Type of message received.
Definition: MessageType.cs:7
XmppState
State of XMPP connection.
Definition: XmppState.cs:7
E2ETransmission
End-to-end encryption mode.
ProfilerThreadType
Type of profiler thread.