Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
ASN1.cs
1using System;
3using System.Diagnostics.CodeAnalysis;
4using System.Formats.Asn1;
5using System.Globalization;
6using System.Reflection;
7using System.Text;
9using Waher.Events;
14
16{
21 public static class ASN1
22 {
23 private static readonly SortedDictionary<string, int> oidsNotRecognized = [];
24 private static readonly SortedDictionary<string, int> oidsNotConfigured = [];
25 private static readonly SortedDictionary<string, int> algorithmsUsed = [];
26 private static readonly SortedDictionary<string, int> unrecognizedCurves = [];
27 private static Dictionary<string, ConstructorInfo>? objectConstructors = null;
28
37 public static bool TryDecodeDerAs(UniversalTagNumber TagNumber, byte[] Data, out object? Value)
38 {
39 return TryDecodeDerAs(null, TagNumber, Data, out Value);
40 }
41
51 public static bool TryDecodeDerAs(ICommunicationLayer? Client, UniversalTagNumber TagNumber,
52 byte[] Data, out object? Value)
53 {
54 if (Data.Length == 0)
55 {
56 Value = null;
57 return false;
58 }
59
60 byte Tag = (byte)TagNumber;
61 if (TagNumber == UniversalTagNumber.Sequence || TagNumber == UniversalTagNumber.Set)
62 Tag |= 0x20;
63
64 Data = (byte[])Data.Clone();
65 Data[0] = Tag;
66
67 AsnReader Reader = new(Data, AsnEncodingRules.DER);
68 return TryDecodeAsn1(Client, Reader, out Value);
69 }
70
77 public static bool TryDecodeDer(byte[] Data, out object? Value)
78 {
79 return TryDecodeDer(null, Data, out Value);
80 }
81
89 public static bool TryDecodeDer(ICommunicationLayer? Client, byte[] Data, out object? Value)
90 {
91 AsnReader Reader = new(Data, AsnEncodingRules.DER);
92 if (!TryDecodeAsn1(Client, Reader, out Value))
93 return false;
94
95 if (Reader.HasData)
96 {
97 Value = null;
98 return false;
99 }
100
101 return true;
102 }
103
110 public static bool TryDecodeAsn1(AsnReader Reader, out object? Value)
111 {
112 return TryDecodeAsn1(null, Reader, out Value);
113 }
114
122 public static bool TryDecodeAsn1(ICommunicationLayer? Client, AsnReader Reader, out object? Value)
123 {
124 if (!Reader.HasData)
125 {
126 Value = null;
127 return false;
128 }
129
130 Asn1Tag Tag = Reader.PeekTag();
131
132 if (Tag.TagClass == TagClass.Universal)
133 {
134 switch (Tag.TagValue)
135 {
136 case (int)UniversalTagNumber.EndOfContents:
137 Value = null;
138 return false;
139
140 case (int)UniversalTagNumber.Boolean:
141 // Some certificates have been observed to encode Boolean values incorrectly,
142 // for instance encoding TRUE as 01 01 01 instead of 01 01 FF.
143 // Trying to read a Boolean using normal method would in these cases result in
144 // an exception.
145
146 ReadOnlyMemory<byte> Section = Reader.ReadEncodedValue();
147
148 if (Section.Length == 3)
149 Value = Section.Span[^1] != 0;
150 else
151 Value = Reader.ReadBoolean();
152
153 return true;
154
155 case (int)UniversalTagNumber.Integer:
156 case (int)UniversalTagNumber.Enumerated:
157 Value = Reader.ReadInteger();
158 return true;
159
160 case (int)UniversalTagNumber.BitString:
161 Value = Reader.ReadBitString(out _);
162 return true;
163
164 case (int)UniversalTagNumber.OctetString:
165 byte[] Bin = Reader.ReadOctetString();
166
167 if (Tag.IsConstructed)
168 {
169 try
170 {
171 if (TryDecodeDer(Client, Bin, out object? Embedded))
172 Value = Embedded;
173 else
174 Value = Bin;
175 }
176 catch (Exception)
177 {
178 Value = Bin;
179 }
180 }
181 else
182 Value = Bin;
183
184 return true;
185
186 case (int)UniversalTagNumber.Null:
187 Reader.ReadNull();
188 Value = null;
189 return true;
190
191 case (int)UniversalTagNumber.ObjectIdentifier:
192 string Oid = Reader.ReadObjectIdentifier();
193
195 Value = SecurityObject;
196 else
197 {
198 Client?.Warning("OID not recognized: " + Oid);
200 Value = Oid;
201 }
202 return true;
203
204 case (int)UniversalTagNumber.ObjectDescriptor: // Obsolete
205 case (int)UniversalTagNumber.UTF8String:
206 case (int)UniversalTagNumber.NumericString:
207 case (int)UniversalTagNumber.PrintableString:
208 case (int)UniversalTagNumber.TeletexString: // Same as UniversalTagNumber.T61String:
209 case (int)UniversalTagNumber.VideotexString:
210 case (int)UniversalTagNumber.IA5String:
211 case (int)UniversalTagNumber.GraphicString:
212 case (int)UniversalTagNumber.VisibleString: // Same as UniversalTagNumber.ISO646String:
213 case (int)UniversalTagNumber.GeneralString:
214 case (int)UniversalTagNumber.UniversalString:
215 case (int)UniversalTagNumber.UnrestrictedCharacterString:
216 case (int)UniversalTagNumber.BMPString:
217 Value = Reader.ReadCharacterString((UniversalTagNumber)Tag.TagValue);
218 return true;
219
220 case (int)UniversalTagNumber.Real:
221 case (int)UniversalTagNumber.RelativeObjectIdentifier:
222 case (int)UniversalTagNumber.Time:
223 case (int)UniversalTagNumber.Date:
224 case (int)UniversalTagNumber.TimeOfDay:
225 case (int)UniversalTagNumber.DateTime:
226 case (int)UniversalTagNumber.Duration:
227 case (int)UniversalTagNumber.ObjectIdentifierIRI:
228 case (int)UniversalTagNumber.RelativeObjectIdentifierIRI:
229 Value = Reader.ReadEncodedValue();
230 return true;
231
232 case (int)UniversalTagNumber.Sequence: // Same as UniversalTagNumber.SequenceOf:
233 case (int)UniversalTagNumber.External: // Same as UniversalTagNumber.InstanceOf:
234 case (int)UniversalTagNumber.Set: // Same as UniversalTagNumber.SetOf:
235 case (int)UniversalTagNumber.Embedded:
236
237 Section = Reader.ReadEncodedValue();
238 AsnReader Inner = new(Section, Reader.RuleSet,
239 new AsnReaderOptions()
240 {
241 SkipSetSortOrderVerification = true
242 });
243
244 if (Tag.TagValue == (int)UniversalTagNumber.Sequence)
245 Inner = Inner.ReadSequence();
246 else
247 Inner = Inner.ReadSetOf(Tag);
248
249 if (!TryDecodeAsn1(Client, Inner, out object? FirstElement))
250 {
251 Value = Array.Empty<object?>();
252 return true;
253 }
254
255 if (!TryDecodeAsn1(Client, Inner, out object? Element))
256 {
257 if (Tag.TagValue == (int)UniversalTagNumber.Sequence)
258 Value = new Sequence(new object?[] { FirstElement }, Section.ToArray());
259 else
260 Value = new Set(new object?[] { FirstElement }, Section.ToArray());
261
262 return true;
263 }
264
265 ChunkedList<object?> Elements = [FirstElement, Element];
266
267 while (TryDecodeAsn1(Client, Inner, out Element))
268 Elements.Add(Element);
269
270 object?[] Elements2 = [.. Elements];
271 byte[] SubSection = Section.ToArray();
272
273 if (FirstElement is ISecurityObject SecurityObject2 &&
274 !SecurityObject2.IsConfigured)
275 {
276 if (SecurityObject2.Configure(new Vector(Elements2, SubSection)))
277 {
278 Value = SecurityObject2;
279 return true;
280 }
281 else
282 ReportOidNotConfigured(SecurityObject2.Oid);
283 }
284
285 if (Tag.TagValue == (int)UniversalTagNumber.Sequence)
286 Value = new Sequence(Elements2, SubSection);
287 else
288 Value = new Set(Elements2, SubSection);
289
290 return true;
291
292 case (int)UniversalTagNumber.UtcTime:
293 Value = Reader.ReadUtcTime();
294 return true;
295
296 case (int)UniversalTagNumber.GeneralizedTime:
297 Value = Reader.ReadGeneralizedTime();
298 return true;
299
300 default:
301 Value = null;
302 return false;
303 }
304 }
305 else if (Tag.TagClass == TagClass.ContextSpecific)
306 {
307 ReadOnlyMemory<byte> Section = Reader.ReadEncodedValue();
308
309 if (Tag.IsConstructed)
310 {
311 AsnReader Inner = new(Section, Reader.RuleSet);
312
313 try
314 {
315 Inner = Inner.ReadSequence(Tag);
316
317 if (!TryDecodeAsn1(Client, Inner, out object? FirstElement))
318 {
319 Value = Array.Empty<object?>();
320 return true;
321 }
322
323 if (!TryDecodeAsn1(Client, Inner, out object? Element))
324 {
325 Value = new ContextSpecific(Tag.TagValue, new object?[] { FirstElement }, Section.ToArray());
326 return true;
327 }
328
329 ChunkedList<object?> Elements = [FirstElement, Element];
330
331 while (TryDecodeAsn1(Client, Inner, out Element))
332 Elements.Add(Element);
333
334 object?[] Elements2 = [.. Elements];
335 byte[] SubSection = Section.ToArray();
336
337 if (FirstElement is ISecurityObject SecurityObject2 &&
338 !SecurityObject2.IsConfigured)
339 {
340 if (SecurityObject2.Configure(new Vector(Elements2, SubSection)))
341 {
342 Value = new ContextSpecific(Tag.TagValue,
343 new object[] { SecurityObject2 }, SubSection);
344
345 return true;
346 }
347 else
348 ReportOidNotConfigured(SecurityObject2.Oid);
349 }
350
351 Value = new ContextSpecific(Tag.TagValue, Elements2, SubSection);
352 return true;
353 }
354 catch (Exception)
355 {
356 Value = Section.ToArray();
357 return true;
358 }
359 }
360 else
361 {
362 Value = Section.ToArray();
363 return true;
364 }
365 }
366 else
367 {
368 Value = null;
369 return false;
370 }
371 }
372
378 public static int ReportOidNotRecognized(string Oid)
379 {
380 return Inc(Oid, oidsNotRecognized);
381 }
382
389 public static KeyValuePair<string, int>[] GetOidsNotRecognized(bool Clear)
390 {
391 return GetCounts(oidsNotRecognized, Clear);
392 }
393
399 public static int ReportOidNotConfigured(string Oid)
400 {
401 return Inc(Oid, oidsNotConfigured);
402 }
403
410 public static KeyValuePair<string, int>[] GetOidsNotConfigured(bool Clear)
411 {
412 return GetCounts(oidsNotConfigured, Clear);
413 }
414
420 public static int ReportAlgorithmUse(string Name)
421 {
422 return Inc(Name, algorithmsUsed);
423 }
424
430 public static int ReportAlgorithmUse(EllipticCurve Curve)
431 {
432 string Name = Curve.CurveName;
433 int Result = ReportAlgorithmUse(Name);
434
435 if (Name == "Custom")
436 {
437 StringBuilder sb = new();
438
439 sb.Append("Order: ");
440 sb.AppendLine(Curve.Order.ToString(CultureInfo.InvariantCulture));
441 sb.Append("Cofactor: ");
442 sb.AppendLine(Curve.Cofactor.ToString(CultureInfo.InvariantCulture));
443 sb.Append("BasePoint.X: ");
444 sb.AppendLine(Curve.BasePoint.X.ToString(CultureInfo.InvariantCulture));
445 sb.Append("BasePoint.Y: ");
446 sb.AppendLine(Curve.BasePoint.Y.ToString(CultureInfo.InvariantCulture));
447
448 if (Curve is PrimeFieldCurve PrimeFieldCurve)
449 {
450 sb.Append("Prime: ");
451 sb.AppendLine(PrimeFieldCurve.Prime.ToString(CultureInfo.InvariantCulture));
452
453
455 {
456 sb.Append("A: ");
457 sb.AppendLine(WeierstrassCurve.A.ToString(CultureInfo.InvariantCulture));
458 sb.Append("B: ");
459 sb.AppendLine(WeierstrassCurve.B.ToString(CultureInfo.InvariantCulture));
460 }
462 {
463 sb.Append("A: ");
464 sb.AppendLine(MontgomeryCurve.A.ToString(CultureInfo.InvariantCulture));
465 }
467 {
468 sb.Append("D: ");
469 sb.AppendLine(EdwardsCurve.D.ToString(CultureInfo.InvariantCulture));
470 }
472 {
473 sb.Append("D: ");
474 sb.AppendLine(EdwardsTwistedCurve.D.ToString(CultureInfo.InvariantCulture));
475 }
476 else
477 {
478 sb.Append("Type: ");
479 sb.AppendLine(Curve.GetType().FullName);
480 }
481 }
482
483 Inc(sb.ToString(), unrecognizedCurves);
484 }
485
486 return Result;
487 }
488
494 public static KeyValuePair<string, int>[] GetAlgorithmsUsed(bool Clear)
495 {
496 return GetCounts(algorithmsUsed, Clear);
497 }
498
504 public static KeyValuePair<string, int>[] GetUnrecognizedEllipticCurvesUsed(bool Clear)
505 {
506 return GetCounts(unrecognizedCurves, Clear);
507 }
508
515 public static int Inc(string Key, SortedDictionary<string, int> Counts)
516 {
517 lock (Counts)
518 {
519 if (!Counts.TryGetValue(Key, out int i))
520 {
521 Counts[Key] = 1;
522 return 1;
523 }
524 else
525 {
526 if (i < int.MaxValue)
527 Counts[Key] = ++i;
528
529 return i;
530 }
531 }
532 }
533
540 public static KeyValuePair<string, int>[] GetCounts(SortedDictionary<string, int> Counts, bool Clear)
541 {
542 lock (Counts)
543 {
544 KeyValuePair<string, int>[] Result = new KeyValuePair<string, int>[Counts.Count];
545 Counts.CopyTo(Result, 0);
546
547 if (Clear)
548 Counts.Clear();
549
550 return Result;
551 }
552 }
553
560 public static bool TryInstantiate(string Oid, [NotNullWhen(true)] out ISecurityObject? Object)
561 {
562 if (objectConstructors is null)
563 {
564 Dictionary<string, ConstructorInfo> Constructors = [];
565
566 foreach (Type T in Types.GetTypesImplementingInterface(typeof(ISecurityObject)))
567 {
568 try
569 {
570 ConstructorInfo? CI = Types.GetDefaultConstructor(T);
571 if (CI is null)
572 continue;
573
575
576 Constructors[Obj.Oid] = CI;
577 }
578 catch (Exception ex)
579 {
580 Log.Exception(ex);
581 }
582 }
583
584 objectConstructors = Constructors;
585 }
586
587 if (objectConstructors.TryGetValue(Oid, out ConstructorInfo? CI2))
588 {
589 Object = (ISecurityObject)CI2.Invoke(Types.NoParameters);
590 return true;
591 }
592 else
593 {
594 Object = null;
595 return false;
596 }
597 }
598 }
599}
Static class for parsing and decoding security objects encoded using Abstract Syntax Notation 1 (ASN....
Definition: ASN1.cs:22
static bool TryDecodeDer(ICommunicationLayer? Client, byte[] Data, out object? Value)
Decodes a DER-encoded object.
Definition: ASN1.cs:89
static KeyValuePair< string, int >[] GetOidsNotConfigured(bool Clear)
Gets an array of OIDs that has not been configured properly.
Definition: ASN1.cs:410
static bool TryDecodeAsn1(AsnReader Reader, out object? Value)
Decodes the next ASN.1-encoded object.
Definition: ASN1.cs:110
static bool TryInstantiate(string Oid, [NotNullWhen(true)] out ISecurityObject? Object)
Tries to instantiate a new object of a given OID.
Definition: ASN1.cs:560
static bool TryDecodeAsn1(ICommunicationLayer? Client, AsnReader Reader, out object? Value)
Decodes the next ASN.1-encoded object.
Definition: ASN1.cs:122
static KeyValuePair< string, int >[] GetUnrecognizedEllipticCurvesUsed(bool Clear)
Gets an array of unrecognized Elliptic Curves that has been used.
Definition: ASN1.cs:504
static int Inc(string Key, SortedDictionary< string, int > Counts)
Increments a named counter
Definition: ASN1.cs:515
static int ReportOidNotRecognized(string Oid)
Records an OID as not recognized.
Definition: ASN1.cs:378
static bool TryDecodeDerAs(UniversalTagNumber TagNumber, byte[] Data, out object? Value)
Decodes a DER-encoded object.
Definition: ASN1.cs:37
static bool TryDecodeDerAs(ICommunicationLayer? Client, UniversalTagNumber TagNumber, byte[] Data, out object? Value)
Decodes a DER-encoded object.
Definition: ASN1.cs:51
static int ReportAlgorithmUse(EllipticCurve Curve)
Records an Elliptic Curve has been used.
Definition: ASN1.cs:430
static KeyValuePair< string, int >[] GetCounts(SortedDictionary< string, int > Counts, bool Clear)
Gets an array of counts
Definition: ASN1.cs:540
static KeyValuePair< string, int >[] GetOidsNotRecognized(bool Clear)
Gets an array of OIDs that has not been recognized.
Definition: ASN1.cs:389
static int ReportOidNotConfigured(string Oid)
Records an OID as not configured properly.
Definition: ASN1.cs:399
static bool TryDecodeDer(byte[] Data, out object? Value)
Decodes a DER-encoded object.
Definition: ASN1.cs:77
static KeyValuePair< string, int >[] GetAlgorithmsUsed(bool Clear)
Gets an array of algorithms that has been used.
Definition: ASN1.cs:494
static int ReportAlgorithmUse(string Name)
Records an Elliptic Curve has been used.
Definition: ASN1.cs:420
Abstract base class for security objects.
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:14
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:1657
A chunked list is a linked list of chunks of objects of type T .
Definition: ChunkedList.cs:54
void Add(T Item)
Adds an item to the collection.
Definition: ChunkedList.cs:272
Static class that dynamically manages types and interfaces available in the runtime environment.
Definition: Types.cs:15
static object[] NoParameters
Contains an empty array of parameter values.
Definition: Types.cs:572
static Type[] GetTypesImplementingInterface(string InterfaceFullName)
Gets all types implementing a given interface.
Definition: Types.cs:85
static ConstructorInfo GetDefaultConstructor(Type Type)
Gets the default constructor of a type, if one exists.
Definition: Types.cs:1742
BigInteger D
d coefficient of Edwards curve.
Base class of Edwards curves (x²+y²=1+dx²y²) over a prime field.
Definition: EdwardsCurve.cs:10
Base class of Twisted Edwards curves (-x²+y²=1+dx²y²) over a prime field.
Abstract base class for elliptic curves.
abstract string CurveName
Name of curve.
PointOnCurve BasePoint
Base-point of curve.
Base class of Montgomery curves (y²=x³+Ax²+x), with birational Edwards equivalent over a prime field.
Base class of Elliptic curves over a prime field.
Base class of Weierstrass curves (y²=x³+ax+b) over a prime field.
bool IsConfigured
If the object has been configured.
void Warning(string Warning)
Called to inform the viewer of a warning state.
Interface for observable classes implementing communication protocols.
Definition: ImplTypes.g.cs:58
class ContextSpecific(int Tag, Array Elements, byte[] SubSection)
A context-specific object (or set of objects).
class Sequence(Array Elements, byte[] SubSection)
A generic sequence class used if dedicated security objects cannot be found.
Definition: Sequence.cs:10
class Set(Array Elements, byte[] SubSection)
A generic set class used if dedicated security objects cannot be found.
Definition: Set.cs:10