mirror of
https://github.com/SabreTools/SabreTools.ASN1.git
synced 2026-02-07 13:54:33 +00:00
Compare commits
75 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0bdfc5426d | ||
|
|
827913d09c | ||
|
|
2d955c8ef7 | ||
|
|
ebdab151be | ||
|
|
a664cff34c | ||
|
|
8110cdd0cb | ||
|
|
7a10aab5d1 | ||
|
|
1516a8647a | ||
|
|
4ee64a2c49 | ||
|
|
9cdf10d481 | ||
|
|
04996584b5 | ||
|
|
98b930e231 | ||
|
|
2da26d2dca | ||
|
|
32a226ede6 | ||
|
|
e9abf681c3 | ||
|
|
1c10ebf648 | ||
|
|
ea6d89d2da | ||
|
|
f457e12d85 | ||
|
|
3c561a60e7 | ||
|
|
5830e2a2fd | ||
|
|
10163eb9eb | ||
|
|
4e45de3fab | ||
|
|
ec92bb22aa | ||
|
|
6a0826e95c | ||
|
|
b7010349a0 | ||
|
|
005a447e35 | ||
|
|
ca1cb5a66e | ||
|
|
4c6ef33af2 | ||
|
|
eb519af488 | ||
|
|
402fe65e20 | ||
|
|
c22f0f2c6e | ||
|
|
92d5a097a8 | ||
|
|
d722f1fad2 | ||
|
|
a570f9a96a | ||
|
|
d4a118ba04 | ||
|
|
9ceea4f85a | ||
|
|
a0a7f23b6c | ||
|
|
bca1754d42 | ||
|
|
a6a281deb8 | ||
|
|
37bc010762 | ||
|
|
0a217e5e6b | ||
|
|
73e7b035b8 | ||
|
|
7276ab2199 | ||
|
|
fef4d30add | ||
|
|
e632f8537b | ||
|
|
ce8c4b1831 | ||
|
|
2bdb56aca2 | ||
|
|
ce6ffd3f7f | ||
|
|
c06618c66c | ||
|
|
eb356483b4 | ||
|
|
0e76552df8 | ||
|
|
070274e33f | ||
|
|
dd64d6f843 | ||
|
|
69992f64be | ||
|
|
e63921fbc2 | ||
|
|
69dc21c814 | ||
|
|
4c07f24e3c | ||
|
|
b6b43d9e1b | ||
|
|
7c972c1ea2 | ||
|
|
7c40583898 | ||
|
|
ef479c783a | ||
|
|
1ebd9f82ee | ||
|
|
774597b17c | ||
|
|
29437475fb | ||
|
|
214d4e4f9e | ||
|
|
06c742cd15 | ||
|
|
bc591f367f | ||
|
|
8c6b962bd6 | ||
|
|
306b9a49ee | ||
|
|
21ad30e65c | ||
|
|
50b8df07f1 | ||
|
|
fb33b1be85 | ||
|
|
965a8a5187 | ||
|
|
513e03c124 | ||
|
|
6d78f1f779 |
46
.github/workflows/build_and_test.yml
vendored
Normal file
46
.github/workflows/build_and_test.yml
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
name: Build and Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: |
|
||||
6.0.x
|
||||
8.0.x
|
||||
9.0.x
|
||||
|
||||
- name: Run tests
|
||||
run: dotnet test
|
||||
|
||||
- name: Run publish script
|
||||
run: ./publish-nix.sh
|
||||
|
||||
- name: Upload build
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: 'Nuget Package'
|
||||
path: "*.nupkg,*.snupkg"
|
||||
|
||||
- name: Upload to rolling
|
||||
uses: ncipollo/release-action@v1.14.0
|
||||
with:
|
||||
allowUpdates: True
|
||||
artifacts: "*.nupkg,*.snupkg"
|
||||
body: 'Last built commit: ${{ github.sha }}'
|
||||
name: 'Rolling Release'
|
||||
prerelease: True
|
||||
replacesArtifacts: True
|
||||
tag: "rolling"
|
||||
updateOnlyUnreleased: True
|
||||
23
.github/workflows/check_pr.yml
vendored
Normal file
23
.github/workflows/check_pr.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: Build PR
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: |
|
||||
6.0.x
|
||||
8.0.x
|
||||
9.0.x
|
||||
|
||||
- name: Build
|
||||
run: dotnet build
|
||||
|
||||
- name: Run tests
|
||||
run: dotnet test
|
||||
@@ -1,31 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SabreTools.ASN1
|
||||
{
|
||||
/// <summary>
|
||||
/// ASN.1 Parser
|
||||
/// </summary>
|
||||
public static class AbstractSyntaxNotationOne
|
||||
{
|
||||
/// <summary>
|
||||
/// Parse a byte array into a DER-encoded ASN.1 structure
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array representing the data</param>
|
||||
/// <param name="pointer">Current pointer into the data</param>
|
||||
/// <returns></returns>
|
||||
public static List<TypeLengthValue> Parse(byte[] data, int pointer)
|
||||
{
|
||||
// Create the output list to return
|
||||
var topLevelValues = new List<TypeLengthValue>();
|
||||
|
||||
// Loop through the data and return all top-level values
|
||||
while (pointer < data.Length)
|
||||
{
|
||||
var topLevelValue = new TypeLengthValue(data, ref pointer);
|
||||
topLevelValues.Add(topLevelValue);
|
||||
}
|
||||
|
||||
return topLevelValues;
|
||||
}
|
||||
}
|
||||
}
|
||||
7
LICENSE
Normal file
7
LICENSE
Normal file
@@ -0,0 +1,7 @@
|
||||
Copyright (c) 2018-2025 Matt Nadareski
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,866 +0,0 @@
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace SabreTools.ASN1
|
||||
{
|
||||
/// <summary>
|
||||
/// Methods related to Object Identifiers (OID) and OID-IRI formatting
|
||||
/// </summary>
|
||||
public static partial class ObjectIdentifier
|
||||
{
|
||||
/// <summary>
|
||||
/// Parse an OID in separated-value notation into OID-IRI notation
|
||||
/// </summary>
|
||||
/// <param name="values">List of values to check against</param>
|
||||
/// <param name="index">Current index into the list</param>
|
||||
/// <returns>OID-IRI formatted string, if possible</returns>
|
||||
/// <see href="http://www.oid-info.com/index.htm"/>
|
||||
public static string? ParseOIDToOIDIRINotation(ulong[]? values)
|
||||
{
|
||||
// If we have an invalid set of values, we can't do anything
|
||||
if (values == null || values.Length == 0)
|
||||
return null;
|
||||
|
||||
// Set the initial index
|
||||
int index = 0;
|
||||
|
||||
// Get a string builder for the path
|
||||
var nameBuilder = new StringBuilder();
|
||||
|
||||
// Try to parse the standard value
|
||||
string? standard = ParseOIDToOIDIRINotation(values, ref index);
|
||||
if (standard == null)
|
||||
return null;
|
||||
|
||||
// Add the standard value to the output
|
||||
nameBuilder.Append(standard);
|
||||
|
||||
// If we have no more items
|
||||
if (index == values.Length)
|
||||
return nameBuilder.ToString();
|
||||
|
||||
// Add trailing items as just values
|
||||
nameBuilder.Append("/");
|
||||
nameBuilder.Append(string.Join("/", values.Skip(index)));
|
||||
|
||||
// Create and return the string
|
||||
return nameBuilder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse an OID in separated-value notation into OID-IRI notation
|
||||
/// </summary>
|
||||
/// <param name="values">List of values to check against</param>
|
||||
/// <param name="index">Current index into the list</param>
|
||||
/// <returns>OID-IRI formatted string, if possible</returns>
|
||||
/// <see href="http://www.oid-info.com/index.htm"/>
|
||||
private static string? ParseOIDToOIDIRINotation(ulong[]? values, ref int index)
|
||||
{
|
||||
// If we have an invalid set of values, we can't do anything
|
||||
if (values == null || values.Length == 0)
|
||||
return null;
|
||||
|
||||
// If we have an invalid index, we can't do anything
|
||||
if (index < 0 || index >= values.Length)
|
||||
return null;
|
||||
|
||||
#region Start
|
||||
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: goto oid_0;
|
||||
case 1: goto oid_1;
|
||||
case 2: goto oid_2;
|
||||
default: return $"/{values[index - 1]}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// itu-t, ccitt, itu-r
|
||||
#region 0.*
|
||||
|
||||
oid_0:
|
||||
|
||||
if (index == values.Length) return "/ITU-T";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: goto oid_0_0;
|
||||
case 2: return "/ITU-T/Administration";
|
||||
case 3: return "/ITU-T/Network-Operator";
|
||||
case 4: return "/ITU-T/Identified-Organization";
|
||||
case 5: return "/ITU-R/R-Recommendation";
|
||||
case 9: return "/ITU-T/Data";
|
||||
default: return $"/ITU-T/{values[index - 1]}";
|
||||
};
|
||||
|
||||
// recommendation
|
||||
#region 0.0.*
|
||||
|
||||
oid_0_0:
|
||||
|
||||
if (index == values.Length) return "/ITU-T/Recommendation";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 1: return "/ITU-T/Recommendation/A";
|
||||
case 2: return "/ITU-T/Recommendation/B";
|
||||
case 3: return "/ITU-T/Recommendation/C";
|
||||
case 4: return "/ITU-T/Recommendation/D";
|
||||
case 5: return "/ITU-T/Recommendation/E";
|
||||
case 6: return "/ITU-T/Recommendation/F";
|
||||
case 7: return "/ITU-T/Recommendation/G";
|
||||
case 8: return "/ITU-T/Recommendation/H";
|
||||
case 9: return "/ITU-T/Recommendation/I";
|
||||
case 10: return "/ITU-T/Recommendation/J";
|
||||
case 11: return "/ITU-T/Recommendation/K";
|
||||
case 12: return "/ITU-T/Recommendation/L";
|
||||
case 13: return "/ITU-T/Recommendation/M";
|
||||
case 14: return "/ITU-T/Recommendation/N";
|
||||
case 15: return "/ITU-T/Recommendation/O";
|
||||
case 16: return "/ITU-T/Recommendation/P";
|
||||
case 17: return "/ITU-T/Recommendation/Q";
|
||||
case 18: return "/ITU-T/Recommendation/R";
|
||||
case 19: return "/ITU-T/Recommendation/S";
|
||||
case 20: return "/ITU-T/Recommendation/T";
|
||||
case 21: return "/ITU-T/Recommendation/U";
|
||||
case 22: return "/ITU-T/Recommendation/V";
|
||||
case 24: return "/ITU-T/Recommendation/X";
|
||||
case 25: return "/ITU-T/Recommendation/Y";
|
||||
case 26: return "/ITU-T/Recommendation/Z";
|
||||
default: return $"/ITU-T/Recommendation/{values[index - 1]}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
// iso
|
||||
#region 1.*
|
||||
|
||||
oid_1:
|
||||
|
||||
if (index == values.Length) return "/ISO";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: return "/ISO/Standard";
|
||||
case 1: return "/ISO/Registration-Authority";
|
||||
case 2: goto oid_1_2;
|
||||
case 3: return "/ISO/Identified-Organization";
|
||||
default: return $"/ISO/{values[index - 1]}";
|
||||
}
|
||||
|
||||
// member-body
|
||||
#region 1.2.*
|
||||
|
||||
oid_1_2:
|
||||
|
||||
if (index == values.Length) return "/ISO/Member-Body";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 36: return "/ISO/Member-Body/AU";
|
||||
case 40: return "/ISO/Member-Body/AT";
|
||||
case 56: return "/ISO/Member-Body/BE";
|
||||
case 124: return "/ISO/Member-Body/CA";
|
||||
case 156: return "/ISO/Member-Body/CN";
|
||||
case 203: return "/ISO/Member-Body/CZ";
|
||||
case 208: return "/ISO/Member-Body/DK";
|
||||
case 246: return "/ISO/Member-Body/FI";
|
||||
case 250: return "/ISO/Member-Body/FR";
|
||||
case 276: return "/ISO/Member-Body/DE";
|
||||
case 300: return "/ISO/Member-Body/GR";
|
||||
case 344: return "/ISO/Member-Body/HK";
|
||||
case 372: return "/ISO/Member-Body/IE";
|
||||
case 392: return "/ISO/Member-Body/JP";
|
||||
case 398: return "/ISO/Member-Body/KZ";
|
||||
case 410: return "/ISO/Member-Body/KR";
|
||||
case 498: return "/ISO/Member-Body/MD";
|
||||
case 528: return "/ISO/Member-Body/NL";
|
||||
case 566: return "/ISO/Member-Body/NG";
|
||||
case 578: return "/ISO/Member-Body/NO";
|
||||
case 616: return "/ISO/Member-Body/PL";
|
||||
case 643: return "/ISO/Member-Body/RU";
|
||||
case 702: return "/ISO/Member-Body/SG";
|
||||
case 752: return "/ISO/Member-Body/SE";
|
||||
case 804: return "/ISO/Member-Body/UA";
|
||||
case 826: return "/ISO/Member-Body/GB";
|
||||
case 840: return "/ISO/Member-Body/US";
|
||||
default: return $"/ISO/Member-Body/{values[index - 1]}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
// joint-iso-itu-t, joint-iso-ccitt
|
||||
#region 2.*
|
||||
|
||||
oid_2:
|
||||
|
||||
if (index == values.Length) return "/Joint-ISO-ITU-T";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 1: return "/ASN.1";
|
||||
case 16: goto oid_2_16;
|
||||
case 17: return "/Joint-ISO-ITU-T/Registration-Procedures";
|
||||
case 23: return "/Joint-ISO-ITU-T/International-Organizations";
|
||||
case 25: goto oid_2_25;
|
||||
case 27: return "/Tag-Based";
|
||||
case 28: return "/Joint-ISO-ITU-T/ITS";
|
||||
case 41: return "/BIP";
|
||||
case 42: goto oid_2_42;
|
||||
case 48: goto oid_2_48;
|
||||
case 49: goto oid_2_49;
|
||||
case 50: return "/OIDResolutionSystem";
|
||||
case 51: return "/GS1";
|
||||
case 52: return "/Joint-ISO-ITU-T/UAV";
|
||||
case 999: return "/Joint-ISO-ITU-T/Example";
|
||||
default: return $"/Joint-ISO-ITU-T/{values[index - 1]}";
|
||||
}
|
||||
|
||||
// country
|
||||
#region 2.16.*
|
||||
|
||||
oid_2_16:
|
||||
|
||||
if (index == values.Length) return "/Country";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 4: return "/Country/AF";
|
||||
case 8: return "/Country/AL";
|
||||
case 12: return "/Country/DZ";
|
||||
case 20: return "/Country/AD";
|
||||
case 24: return "/Country/AO";
|
||||
case 28: return "/Country/AG";
|
||||
case 31: return "/Country/AZ";
|
||||
case 32: return "/Country/AR";
|
||||
case 36: return "/Country/AU";
|
||||
case 40: return "/Country/AT";
|
||||
case 44: return "/Country/BS";
|
||||
case 48: return "/Country/BH";
|
||||
case 50: return "/Country/BD";
|
||||
case 51: return "/Country/AM";
|
||||
case 52: return "/Country/BB";
|
||||
case 56: return "/Country/BE";
|
||||
case 60: return "/Country/BM";
|
||||
case 64: return "/Country/BT";
|
||||
case 68: return "/Country/BO";
|
||||
case 70: return "/Country/BA";
|
||||
case 72: return "/Country/BW";
|
||||
case 76: return "/Country/BR";
|
||||
case 84: return "/Country/BZ";
|
||||
case 90: return "/Country/SB";
|
||||
case 96: return "/Country/BN";
|
||||
case 100: return "/Country/BG";
|
||||
case 104: return "/Country/MM";
|
||||
case 108: return "/Country/BI";
|
||||
case 112: return "/Country/BY";
|
||||
case 116: return "/Country/KH";
|
||||
case 120: return "/Country/CM";
|
||||
case 124: return "/Country/CA";
|
||||
case 132: return "/Country/CV";
|
||||
case 140: return "/Country/CF";
|
||||
case 144: return "/Country/LK";
|
||||
case 148: return "/Country/TD";
|
||||
case 152: return "/Country/CL";
|
||||
case 156: return "/Country/CN";
|
||||
case 158: return "/Country/TW";
|
||||
case 170: return "/Country/CO";
|
||||
case 174: return "/Country/KM";
|
||||
case 178: return "/Country/CG";
|
||||
case 180: return "/Country/CD";
|
||||
case 188: return "/Country/CR";
|
||||
case 191: return "/Country/HR";
|
||||
case 192: return "/Country/CU";
|
||||
case 196: return "/Country/CY";
|
||||
case 203: return "/Country/CZ";
|
||||
case 204: return "/Country/BJ";
|
||||
case 208: return "/Country/DK";
|
||||
case 212: return "/Country/DM";
|
||||
case 214: return "/Country/DO";
|
||||
case 218: return "/Country/EC";
|
||||
case 222: return "/Country/SV";
|
||||
case 226: return "/Country/GQ";
|
||||
case 231: return "/Country/ET";
|
||||
case 232: return "/Country/ER";
|
||||
case 233: return "/Country/EE";
|
||||
case 242: return "/Country/FJ";
|
||||
case 246: return "/Country/FI";
|
||||
case 250: return "/Country/FR";
|
||||
case 262: return "/Country/DJ";
|
||||
case 266: return "/Country/GA";
|
||||
case 268: return "/Country/GE";
|
||||
case 270: return "/Country/GM";
|
||||
case 275: return "/Country/PS";
|
||||
case 276: return "/Country/DE";
|
||||
case 288: return "/Country/GH";
|
||||
case 296: return "/Country/KI";
|
||||
case 300: return "/Country/GR";
|
||||
case 308: return "/Country/GD";
|
||||
case 320: return "/Country/GT";
|
||||
case 324: return "/Country/GN";
|
||||
case 328: return "/Country/GY";
|
||||
case 332: return "/Country/HT";
|
||||
case 336: return "/Country/VA";
|
||||
case 340: return "/Country/HN";
|
||||
case 344: return "/Country/HK";
|
||||
case 348: return "/Country/HU";
|
||||
case 352: return "/Country/IS";
|
||||
case 356: return "/Country/IN";
|
||||
case 360: return "/Country/ID";
|
||||
case 364: return "/Country/IR";
|
||||
case 368: return "/Country/IQ";
|
||||
case 372: return "/Country/IE";
|
||||
case 376: return "/Country/IL";
|
||||
case 380: return "/Country/IT";
|
||||
case 384: return "/Country/CI";
|
||||
case 388: return "/Country/JM";
|
||||
case 392: return "/Country/JP";
|
||||
case 398: return "/Country/KZ";
|
||||
case 400: return "/Country/JO";
|
||||
case 404: return "/Country/KE";
|
||||
case 408: return "/Country/KP";
|
||||
case 410: return "/Country/KR";
|
||||
case 414: return "/Country/KW";
|
||||
case 417: return "/Country/KG";
|
||||
case 418: return "/Country/LA";
|
||||
case 422: return "/Country/LB";
|
||||
case 426: return "/Country/LS";
|
||||
case 428: return "/Country/LV";
|
||||
case 430: return "/Country/LR";
|
||||
case 434: return "/Country/LY";
|
||||
case 438: return "/Country/LI";
|
||||
case 440: return "/Country/LT";
|
||||
case 442: return "/Country/LU";
|
||||
case 450: return "/Country/MG";
|
||||
case 454: return "/Country/MW";
|
||||
case 458: return "/Country/MY";
|
||||
case 462: return "/Country/MV";
|
||||
case 466: return "/Country/ML";
|
||||
case 470: return "/Country/MT";
|
||||
case 478: return "/Country/MR";
|
||||
case 480: return "/Country/MU";
|
||||
case 484: return "/Country/MX";
|
||||
case 492: return "/Country/MC";
|
||||
case 496: return "/Country/MN";
|
||||
case 498: return "/Country/MD";
|
||||
case 499: return "/Country/ME";
|
||||
case 504: return "/Country/MA";
|
||||
case 508: return "/Country/MZ";
|
||||
case 512: return "/Country/OM";
|
||||
case 516: return "/Country/NA";
|
||||
case 520: return "/Country/NR";
|
||||
case 524: return "/Country/NP";
|
||||
case 528: return "/Country/NL";
|
||||
case 530: return "/Country/AN";
|
||||
case 548: return "/Country/VU";
|
||||
case 554: return "/Country/NZ";
|
||||
case 558: return "/Country/NI";
|
||||
case 562: return "/Country/NE";
|
||||
case 566: return "/Country/NG";
|
||||
case 578: return "/Country/NO";
|
||||
case 583: return "/Country/FM";
|
||||
case 584: return "/Country/MH";
|
||||
case 585: return "/Country/PW";
|
||||
case 586: return "/Country/PK";
|
||||
case 591: return "/Country/PA";
|
||||
case 598: return "/Country/PG";
|
||||
case 600: return "/Country/PY";
|
||||
case 604: return "/Country/PE";
|
||||
case 608: return "/Country/PH";
|
||||
case 616: return "/Country/PL";
|
||||
case 620: return "/Country/PT";
|
||||
case 624: return "/Country/GW";
|
||||
case 626: return "/Country/TL";
|
||||
case 634: return "/Country/QA";
|
||||
case 642: return "/Country/RO";
|
||||
case 643: return "/Country/RU";
|
||||
case 646: return "/Country/RW";
|
||||
case 659: return "/Country/KN";
|
||||
case 662: return "/Country/LC";
|
||||
case 670: return "/Country/VC";
|
||||
case 674: return "/Country/SM";
|
||||
case 678: return "/Country/ST";
|
||||
case 682: return "/Country/SA";
|
||||
case 686: return "/Country/SN";
|
||||
case 688: return "/Country/RS";
|
||||
case 690: return "/Country/SC";
|
||||
case 694: return "/Country/SL";
|
||||
case 702: return "/Country/SG";
|
||||
case 703: return "/Country/SK";
|
||||
case 704: return "/Country/VN";
|
||||
case 705: return "/Country/SI";
|
||||
case 706: return "/Country/SO";
|
||||
case 710: return "/Country/ZA";
|
||||
case 716: return "/Country/ZW";
|
||||
case 724: return "/Country/ES";
|
||||
case 728: return "/Country/SS";
|
||||
case 729: return "/Country/SD";
|
||||
case 740: return "/Country/SR";
|
||||
case 748: return "/Country/SZ";
|
||||
case 752: return "/Country/SE";
|
||||
case 756: return "/Country/CH";
|
||||
case 760: return "/Country/SY";
|
||||
case 762: return "/Country/TJ";
|
||||
case 764: return "/Country/TH";
|
||||
case 768: return "/Country/TG";
|
||||
case 776: return "/Country/TO";
|
||||
case 780: return "/Country/TT";
|
||||
case 784: return "/Country/AE";
|
||||
case 788: return "/Country/TN";
|
||||
case 792: return "/Country/TR";
|
||||
case 795: return "/Country/TM";
|
||||
case 798: return "/Country/TV";
|
||||
case 800: return "/Country/UG";
|
||||
case 804: return "/Country/UA";
|
||||
case 807: return "/Country/MK";
|
||||
case 818: return "/Country/EG";
|
||||
case 826: return "/Country/GB";
|
||||
case 834: return "/Country/TZ";
|
||||
case 840: return "/Country/US";
|
||||
case 854: return "/Country/BF";
|
||||
case 858: return "/Country/UY";
|
||||
case 860: return "/Country/UZ";
|
||||
case 862: return "/Country/VE";
|
||||
case 882: return "/Country/WS";
|
||||
case 887: return "/Country/YE";
|
||||
case 894: return "/Country/ZM";
|
||||
default: return $"/Country/{values[index - 1]}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// uuid [TODO: Requires 128-bit values]
|
||||
#region 2.25.*
|
||||
|
||||
oid_2_25:
|
||||
|
||||
if (index == values.Length) return "/Joint-ISO-ITU-T/UUID";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: return "/Joint-ISO-ITU-T/UUID/00000000-0000-0000-0000-000000000000";
|
||||
//case 288786655511405443130567505384701230: return "/Joint-ISO-ITU-T/UUID/00379e48-0a2b-1085-b288-0002a5d5fd2e";
|
||||
//case 987895962269883002155146617097157934: return "/Joint-ISO-ITU-T/UUID/00be4308-0c89-1085-8ea0-0002a5d5fd2e";
|
||||
//case 1858228783942312576083372383319475483: return "/Joint-ISO-ITU-T/UUID/0165e1c0-a655-11e0-95b8-0002a5d5c51b";
|
||||
//case 2474299330026746002885628159579243803: return "/Joint-ISO-ITU-T/UUID/01dc8860-25fb-11da-82b2-0002a5d5c51b";
|
||||
//case 3263645701162998421821186056373271854: return "/Joint-ISO-ITU-T/UUID/02748e28-08c4-1085-b21d-0002a5d5fd2e";
|
||||
//case 3325839809379844461264382260940242222: return "/Joint-ISO-ITU-T/UUID/02808890-0ad8-1085-9bdf-0002a5d5fd2e";
|
||||
// TODO: Left off at http://www.oid-info.com/get/2.25.3664154270495270126161055518190585115
|
||||
default: return $"/Joint-ISO-ITU-T/UUID/{values[index - 1]}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// telebiometrics
|
||||
#region 2.42.*
|
||||
|
||||
oid_2_42:
|
||||
|
||||
if (index == values.Length) return "/Telebiometrics";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: goto oid_2_42_0;
|
||||
case 1: goto oid_2_42_1;
|
||||
case 2: goto oid_2_42_2;
|
||||
case 3: goto oid_2_42_3;
|
||||
default: return $"/Telebiometrics/{values[index - 1]}";
|
||||
}
|
||||
|
||||
// modules
|
||||
#region 2.42.0.*
|
||||
|
||||
oid_2_42_0:
|
||||
|
||||
if (index == values.Length) return "/Telebiometrics/Modules";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: goto oid_2_42_0_0;
|
||||
default: return $"/Telebiometrics/Modules/{values[index - 1]}";
|
||||
}
|
||||
|
||||
// main
|
||||
#region 2.42.0.0.*
|
||||
|
||||
oid_2_42_0_0:
|
||||
|
||||
if (index == values.Length) return "/Telebiometrics/Modules/Main_Module";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 1: return "/Telebiometrics/Modules/Main_Module/Version1";
|
||||
default: return $"/Telebiometrics/Modules/Main_Module/{values[index - 1]}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
// tmm
|
||||
#region 2.42.1.*
|
||||
|
||||
oid_2_42_1:
|
||||
|
||||
if (index == values.Length) return "/Telebiometrics/TMM";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: goto oid_2_42_1_0;
|
||||
case 1: goto oid_2_42_1_1;
|
||||
case 2: goto oid_2_42_1_2;
|
||||
case 3: goto oid_2_42_1_3;
|
||||
case 4: return "/Telebiometrics/TMM/Practitioners";
|
||||
default: return $"/Telebiometrics/TMM/{values[index - 1]}";
|
||||
}
|
||||
|
||||
// modules
|
||||
#region 2.42.1.0.*
|
||||
|
||||
oid_2_42_1_0:
|
||||
|
||||
if (index == values.Length) return "/Telebiometrics/TMM/Modules";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: goto oid_2_42_1_0_0;
|
||||
default: return $"/Telebiometrics/TMM/Modules/{values[index - 1]}";
|
||||
}
|
||||
|
||||
// main
|
||||
#region 2.42.1.0.0.*
|
||||
|
||||
oid_2_42_1_0_0:
|
||||
|
||||
if (index == values.Length) return "/Telebiometrics/TMM/Modules/Main";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: return "/Telebiometrics/TMM/Modules/Main/First_Version";
|
||||
default: return $"/Telebiometrics/TMM/Modules/Main/{values[index - 1]}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
// measures, metric
|
||||
#region 2.42.1.1.*
|
||||
|
||||
oid_2_42_1_1:
|
||||
|
||||
if (index == values.Length) return "/Telebiometrics/TMM/Measures";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 1: goto oid_2_42_1_1_1;
|
||||
case 2: return "/Telebiometrics/TMM/Measures/Units";
|
||||
case 3: return "/Telebiometrics/TMM/Measures/Symbols";
|
||||
case 4: return "/Telebiometrics/TMM/Measures/Conditions";
|
||||
case 5: goto oid_2_42_1_1_5;
|
||||
default: return $"/Telebiometrics/TMM/Measures/{values[index - 1]}";
|
||||
}
|
||||
|
||||
// quantities
|
||||
#region 2.42.1.1.1.*
|
||||
|
||||
oid_2_42_1_1_1:
|
||||
|
||||
if (index == values.Length) return "/Telebiometrics/TMM/Measures/Quantities";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 1: return "/Telebiometrics/TMM/Measures/Quantities/Physics";
|
||||
case 2: return "/Telebiometrics/TMM/Measures/Quantities/Chemistry";
|
||||
case 3: return "/Telebiometrics/TMM/Measures/Quantities/Biology";
|
||||
case 4: return "/Telebiometrics/TMM/Measures/Quantities/Culturology";
|
||||
case 5: return "/Telebiometrics/TMM/Measures/Quantities/Psychology";
|
||||
default: return $"/Telebiometrics/TMM/Measures/Quantities/{values[index - 1]}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// methods
|
||||
#region 2.42.1.1.5.*
|
||||
|
||||
oid_2_42_1_1_5:
|
||||
|
||||
if (index == values.Length) return "/Telebiometrics/TMM/Measures/Methods";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 1: return "/Telebiometrics/TMM/Measures/Methods/Physics";
|
||||
case 2: return "/Telebiometrics/TMM/Measures/Methods/Chemistry";
|
||||
case 3: return "/Telebiometrics/TMM/Measures/Methods/Biology";
|
||||
case 4: return "/Telebiometrics/TMM/Measures/Methods/Culturology";
|
||||
case 5: return "/Telebiometrics/TMM/Measures/Methods/Psychology";
|
||||
default: return $"/Telebiometrics/TMM/Measures/Methods/{values[index - 1]}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
// fields-of-study, scientific
|
||||
#region 2.42.1.2.*
|
||||
|
||||
oid_2_42_1_2:
|
||||
|
||||
if (index == values.Length) return "/Telebiometrics/TMM/Fields_of_Study";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 1: return "/Telebiometrics/TMM/Fields_of_Study/Physics";
|
||||
case 2: return "/Telebiometrics/TMM/Fields_of_Study/Chemistry";
|
||||
case 3: return "/Telebiometrics/TMM/Fields_of_Study/Biology";
|
||||
case 4: return "/Telebiometrics/TMM/Fields_of_Study/Culturology";
|
||||
case 5: return "/Telebiometrics/TMM/Fields_of_Study/Psychology";
|
||||
default: return $"/Telebiometrics/TMM/Fields_of_Study/{values[index - 1]}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// modalities, sensory
|
||||
#region 2.42.1.3.*
|
||||
|
||||
oid_2_42_1_3:
|
||||
|
||||
if (index == values.Length) return "/Telebiometrics/TMM/Modalities";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 1: return "/Telebiometrics/TMM/Modalities/Tango";
|
||||
case 2: return "/Telebiometrics/TMM/Modalities/Video";
|
||||
case 3: return "/Telebiometrics/TMM/Modalities/Audio";
|
||||
case 4: return "/Telebiometrics/TMM/Modalities/Chemo";
|
||||
case 5: return "/Telebiometrics/TMM/Modalities/Radio";
|
||||
case 6: return "/Telebiometrics/TMM/Modalities/Calor";
|
||||
case 7: return "/Telebiometrics/TMM/Modalities/Electro";
|
||||
default: return $"/Telebiometrics/TMM/Modalities/{values[index - 1]}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
// human-physiology
|
||||
#region 2.42.2.*
|
||||
|
||||
oid_2_42_2:
|
||||
|
||||
if (index == values.Length) return "/Telebiometrics/Human_Physiology";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: goto oid_2_42_2_0;
|
||||
case 1: goto oid_2_42_2_1;
|
||||
case 2: return "/Telebiometrics/Human_Physiology/Symbol_Combinations";
|
||||
default: return $"/Telebiometrics/Human_Physiology/{values[index - 1]}";
|
||||
}
|
||||
|
||||
// modules
|
||||
#region 2.42.2.0.*
|
||||
|
||||
oid_2_42_2_0:
|
||||
|
||||
if (index == values.Length) return "/Telebiometrics/Human_Physiology/Modules";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: goto oid_2_42_2_0_0;
|
||||
default: return $"/Telebiometrics/Human_Physiology/Modules/{values[index - 1]}";
|
||||
}
|
||||
|
||||
// main
|
||||
#region 2.42.2.0.0.*
|
||||
|
||||
oid_2_42_2_0_0:
|
||||
|
||||
if (index == values.Length) return "/Telebiometrics/Human_Physiology/Modules/Main_Module";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: return "/Telebiometrics/Human_Physiology/Modules/Main_Module/First_Version";
|
||||
default: return $"/Telebiometrics/Human_Physiology/Modules/Main_Module/{values[index - 1]}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
// symbols
|
||||
#region 2.42.2.1.*
|
||||
|
||||
oid_2_42_2_1:
|
||||
|
||||
if (index == values.Length) return "/Telebiometrics/Human_Physiology/Symbols";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 1: return "/Telebiometrics/Human_Physiology/Symbols/Tango_in";
|
||||
case 2: return "/Telebiometrics/Human_Physiology/Symbols/Video_in";
|
||||
case 3: return "/Telebiometrics/Human_Physiology/Symbols/Audio_in";
|
||||
case 4: return "/Telebiometrics/Human_Physiology/Symbols/Chemo_in";
|
||||
case 5: return "/Telebiometrics/Human_Physiology/Symbols/Radio_in";
|
||||
case 6: return "/Telebiometrics/Human_Physiology/Symbols/Calor_in";
|
||||
case 7: return "/Telebiometrics/Human_Physiology/Symbols/Tango_out";
|
||||
case 8: return "/Telebiometrics/Human_Physiology/Symbols/Video_out";
|
||||
case 9: return "/Telebiometrics/Human_Physiology/Symbols/Audio_out";
|
||||
case 10: return "/Telebiometrics/Human_Physiology/Symbols/Chemo_out";
|
||||
case 11: return "/Telebiometrics/Human_Physiology/Symbols/Radio_out";
|
||||
case 12: return "/Telebiometrics/Human_Physiology/Symbols/Calor_out";
|
||||
case 13: return "/Telebiometrics/Human_Physiology/Symbols/Safe";
|
||||
case 14: return "/Telebiometrics/Human_Physiology/Symbols/Threshold";
|
||||
default: return $"/Telebiometrics/Human_Physiology/Symbols/{values[index - 1]}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
// obj-cat, telehealth, e-health-protocol, th
|
||||
#region 2.42.3.*
|
||||
|
||||
oid_2_42_3:
|
||||
|
||||
if (index == values.Length) return "/Telebiometrics/E_Health_Protocol";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: goto oid_2_42_3_0;
|
||||
case 1: return "/Telebiometrics/E_Health_Protocol/[Patient schemes]";
|
||||
case 2: return "/Telebiometrics/E_Health_Protocol/[Medical staff schemes]";
|
||||
case 3: return "/Telebiometrics/E_Health_Protocol/[Observer schemes]";
|
||||
case 4: return "/Telebiometrics/E_Health_Protocol/[Pharmaceutical schemes]";
|
||||
case 5: return "/Telebiometrics/E_Health_Protocol/[Laboratory schemes]";
|
||||
case 6: return "/Telebiometrics/E_Health_Protocol/[Drug manufacturer schemes]";
|
||||
case 7: return "/Telebiometrics/E_Health_Protocol/[Medical device schemes]";
|
||||
case 8: return "/Telebiometrics/E_Health_Protocol/[Medical software schemes]";
|
||||
case 9: return "/Telebiometrics/E_Health_Protocol/[Medical insurance schemes]";
|
||||
case 10: return "/Telebiometrics/E_Health_Protocol/[Medical record schemes]";
|
||||
default: return $"/Telebiometrics/E_Health_Protocol/{values[index - 1]}";
|
||||
}
|
||||
|
||||
// obj-cat, telehealth, e-health-protocol, th
|
||||
#region 2.42.3.0.*
|
||||
|
||||
oid_2_42_3_0:
|
||||
|
||||
if (index == values.Length) return "/Telebiometrics/E_Health_Protocol/Modules";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: goto oid_2_42_3_0_0;
|
||||
case 1: goto oid_2_42_3_0_1;
|
||||
case 2: goto oid_2_42_3_0_2;
|
||||
case 3: goto oid_2_42_3_0_3;
|
||||
case 4: goto oid_2_42_3_0_4;
|
||||
case 5: goto oid_2_42_3_0_5;
|
||||
default: return $"/Telebiometrics/E_Health_Protocol/Modules/{values[index - 1]}";
|
||||
}
|
||||
|
||||
// identification
|
||||
#region 2.42.3.0.0.*
|
||||
|
||||
oid_2_42_3_0_0:
|
||||
|
||||
if (index == values.Length) return "/Telebiometrics/E_Health_Protocol/Modules/Identification";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 1: return "/Telebiometrics/E_Health_Protocol/Modules/Identification/Version1";
|
||||
default: return $"/Telebiometrics/E_Health_Protocol/Modules/Identification/{values[index - 1]}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// set-up
|
||||
#region 2.42.3.0.1.*
|
||||
|
||||
oid_2_42_3_0_1:
|
||||
|
||||
if (index == values.Length) return "/Telebiometrics/E_Health_Protocol/Modules/Setup";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 1: return "/Telebiometrics/E_Health_Protocol/Modules/Setup/Version1";
|
||||
default: return $"/Telebiometrics/E_Health_Protocol/Modules/Setup/{values[index - 1]}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// send-and-ack
|
||||
#region 2.42.3.0.2.*
|
||||
|
||||
oid_2_42_3_0_2:
|
||||
|
||||
if (index == values.Length) return "/Telebiometrics/E_Health_Protocol/Modules/Send-and-ack";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 1: return "/Telebiometrics/E_Health_Protocol/Modules/Send-and-ack/Version1";
|
||||
default: return $"/Telebiometrics/E_Health_Protocol/Modules/Send-and-ack/{values[index - 1]}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// command-response
|
||||
#region 2.42.3.0.3.*
|
||||
|
||||
oid_2_42_3_0_3:
|
||||
|
||||
if (index == values.Length) return "/Telebiometrics/E_Health_Protocol/Modules/Command-response";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 1: return "/Telebiometrics/E_Health_Protocol/Modules/Command-response/Version1";
|
||||
default: return $"/Telebiometrics/E_Health_Protocol/Modules/Command-response/{values[index - 1]}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// quantity-and-units
|
||||
#region 2.42.3.0.4.*
|
||||
|
||||
oid_2_42_3_0_4:
|
||||
|
||||
if (index == values.Length) return "/Telebiometrics/E_Health_Protocol/Modules/Quantities_And_Units";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 1: return "/Telebiometrics/E_Health_Protocol/Modules/Quantities_And_Units/Version1";
|
||||
default: return $"/Telebiometrics/E_Health_Protocol/Modules/Quantities_And_Units/{values[index - 1]}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// examples
|
||||
#region 2.42.3.0.5.*
|
||||
|
||||
oid_2_42_3_0_5:
|
||||
|
||||
if (index == values.Length) return "/Telebiometrics/E_Health_Protocol/Modules/Examples";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: return "/Telebiometrics/E_Health_Protocol/Modules/Examples/Command_Response";
|
||||
case 1: return "/Telebiometrics/E_Health_Protocol/Modules/Examples/Data_Message";
|
||||
default: return $"/Telebiometrics/E_Health_Protocol/Modules/Examples/{values[index - 1]}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
// cybersecurity
|
||||
#region 2.48.*
|
||||
|
||||
oid_2_48:
|
||||
|
||||
if (index == values.Length) return "/Cybersecurity";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 1: return "/Cybersecurity/Country";
|
||||
case 2: return "/Cybersecurity/International-Org";
|
||||
default: return $"/Cybersecurity/{values[index - 1]}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// alerting
|
||||
#region 2.49.*
|
||||
|
||||
oid_2_49:
|
||||
|
||||
if (index == values.Length) return "/Alerting";
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: return "/Alerting/WMO";
|
||||
default: return $"/Alerting/{values[index - 1]}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
13
README.MD
13
README.MD
@@ -1,5 +1,18 @@
|
||||
# SabreTools.ASN1
|
||||
|
||||
[](https://github.com/SabreTools/SabreTools.ASN1/actions/workflows/build_and_test.yml)
|
||||
|
||||
**NOTICE:** This library has been deprecated. All functionality formerly in this library is in [SabreTools.Serialization](https://github.com/SabreTools/SabreTools.Serialization) as of version 1.9.6.
|
||||
|
||||
This library comprises of code to parse Abstract Syntax Notation One (ASN.1) codes and output them into various formats. This also performs some rudimentary validation based on the chains that are input.
|
||||
|
||||
**Note:** This code is known to be incomplete and will be added to over time.
|
||||
|
||||
Find the link to the Nuget package [here](https://www.nuget.org/packages/SabreTools.ASN1).
|
||||
|
||||
## Releases
|
||||
|
||||
For the most recent stable build, download the latest release here: [Releases Page](https://github.com/SabreTools/SabreTools.ASN1/releases)
|
||||
|
||||
For the latest WIP build here: [Rolling Release](https://github.com/SabreTools/SabreTools.ASN1/releases/rolling)
|
||||
|
||||
|
||||
61
SabreTools.ASN1.Test/AbstractSyntaxNotationOneTests.cs
Normal file
61
SabreTools.ASN1.Test/AbstractSyntaxNotationOneTests.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.ASN1.Test
|
||||
{
|
||||
public class AbstractSyntaxNotationOneTests
|
||||
{
|
||||
[Fact]
|
||||
public void Parse_EmptyArray_Throws()
|
||||
{
|
||||
byte[] data = [];
|
||||
Assert.Throws<InvalidDataException>(() => AbstractSyntaxNotationOne.Parse(data, 0));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_ValidArrayNegativeIndex_Throws()
|
||||
{
|
||||
byte[] data = [0x00];
|
||||
Assert.Throws<IndexOutOfRangeException>(() => AbstractSyntaxNotationOne.Parse(data, -1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_ValidArrayOverIndex_Throws()
|
||||
{
|
||||
byte[] data = [0x00];
|
||||
Assert.Throws<IndexOutOfRangeException>(() => AbstractSyntaxNotationOne.Parse(data, 10));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_ValidMinimalArray()
|
||||
{
|
||||
byte[] data = [0x00];
|
||||
var tlvs = AbstractSyntaxNotationOne.Parse(data, 0);
|
||||
|
||||
var tlv = Assert.Single(tlvs);
|
||||
Assert.Equal(ASN1Type.V_ASN1_EOC, tlv.Type);
|
||||
Assert.Equal(default, tlv.Length);
|
||||
Assert.Null(tlv.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_EmptyStream_Throws()
|
||||
{
|
||||
Stream data = new MemoryStream([], 0, 0, false, false);
|
||||
Assert.Throws<InvalidDataException>(() => AbstractSyntaxNotationOne.Parse(data));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_ValidMinimalStream()
|
||||
{
|
||||
Stream data = new MemoryStream([0x00]);
|
||||
var tlvs = AbstractSyntaxNotationOne.Parse(data);
|
||||
|
||||
var tlv = Assert.Single(tlvs);
|
||||
Assert.Equal(ASN1Type.V_ASN1_EOC, tlv.Type);
|
||||
Assert.Equal(default, tlv.Length);
|
||||
Assert.Null(tlv.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
110
SabreTools.ASN1.Test/ObjectIdentifierTests.cs
Normal file
110
SabreTools.ASN1.Test/ObjectIdentifierTests.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.ASN1.Test
|
||||
{
|
||||
// These tests are known to be incomplete due to the sheer number
|
||||
// of possible OIDs that exist. The tests below are a minimal
|
||||
// representation of functionality to guarantee proper behavior
|
||||
// not necessarily absolute outputs
|
||||
public class ObjectIdentifierTests
|
||||
{
|
||||
#region ASN.1
|
||||
|
||||
[Fact]
|
||||
public void ASN1Notation_AlwaysNull()
|
||||
{
|
||||
ulong[]? values = null;
|
||||
string? actual = ObjectIdentifier.ParseOIDToASN1Notation(values);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Dot Notation
|
||||
|
||||
[Fact]
|
||||
public void DotNotation_NullValues_Null()
|
||||
{
|
||||
ulong[]? values = null;
|
||||
string? actual = ObjectIdentifier.ParseOIDToDotNotation(values);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DotNotation_EmptyValues_Null()
|
||||
{
|
||||
ulong[]? values = [];
|
||||
string? actual = ObjectIdentifier.ParseOIDToDotNotation(values);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DotNotation_Values_Formatted()
|
||||
{
|
||||
string expected = "0.1.2.3";
|
||||
ulong[]? values = [0, 1, 2, 3];
|
||||
string? actual = ObjectIdentifier.ParseOIDToDotNotation(values);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Modified OID-IRI
|
||||
|
||||
[Fact]
|
||||
public void ModifiedOIDIRI_NullValues_Null()
|
||||
{
|
||||
ulong[]? values = null;
|
||||
string? actual = ObjectIdentifier.ParseOIDToModifiedOIDIRI(values);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ModifiedOIDIRI_EmptyValues_Null()
|
||||
{
|
||||
ulong[]? values = [];
|
||||
string? actual = ObjectIdentifier.ParseOIDToModifiedOIDIRI(values);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ModifiedOIDIRI_Values_Formatted()
|
||||
{
|
||||
string expected = "/ITU-T/[question]/2/3";
|
||||
ulong[]? values = [0, 1, 2, 3];
|
||||
string? actual = ObjectIdentifier.ParseOIDToModifiedOIDIRI(values);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region OID-IRI
|
||||
|
||||
[Fact]
|
||||
public void OIDIRI_NullValues_Null()
|
||||
{
|
||||
ulong[]? values = null;
|
||||
string? actual = ObjectIdentifier.ParseOIDToOIDIRINotation(values);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OIDIRI_EmptyValues_Null()
|
||||
{
|
||||
ulong[]? values = [];
|
||||
string? actual = ObjectIdentifier.ParseOIDToOIDIRINotation(values);
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OIDIRI_Values_Formatted()
|
||||
{
|
||||
string expected = "/ITU-T/1/2/3";
|
||||
ulong[]? values = [0, 1, 2, 3];
|
||||
string? actual = ObjectIdentifier.ParseOIDToOIDIRINotation(values);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
30
SabreTools.ASN1.Test/SabreTools.ASN1.Test.csproj
Normal file
30
SabreTools.ASN1.Test/SabreTools.ASN1.Test.csproj
Normal file
@@ -0,0 +1,30 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
|
||||
<IsPackable>false</IsPackable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<NoWarn>NU1903</NoWarn>
|
||||
<Nullable>enable</Nullable>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.4">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SabreTools.ASN1\SabreTools.ASN1.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
322
SabreTools.ASN1.Test/TypeLengthValueTests.cs
Normal file
322
SabreTools.ASN1.Test/TypeLengthValueTests.cs
Normal file
@@ -0,0 +1,322 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.ASN1.Test
|
||||
{
|
||||
public class TypeLengthValueTests
|
||||
{
|
||||
#region Construction
|
||||
|
||||
[Fact]
|
||||
public void Constructor_EmptyArray_Throws()
|
||||
{
|
||||
int index = 0;
|
||||
byte[] data = [];
|
||||
Assert.Throws<InvalidDataException>(() => new TypeLengthValue(data, ref index));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_ValidArrayNegativeIndex_Throws()
|
||||
{
|
||||
int index = -1;
|
||||
byte[] data = [0x00];
|
||||
Assert.Throws<IndexOutOfRangeException>(() => new TypeLengthValue(data, ref index));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_ValidArrayOverIndex_Throws()
|
||||
{
|
||||
int index = 10;
|
||||
byte[] data = [0x00];
|
||||
Assert.Throws<IndexOutOfRangeException>(() => new TypeLengthValue(data, ref index));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_ValidMinimalArray()
|
||||
{
|
||||
int index = 0;
|
||||
byte[] data = [0x00];
|
||||
var tlv = new TypeLengthValue(data, ref index);
|
||||
|
||||
Assert.Equal(ASN1Type.V_ASN1_EOC, tlv.Type);
|
||||
Assert.Equal(default, tlv.Length);
|
||||
Assert.Null(tlv.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_EmptyStream_Throws()
|
||||
{
|
||||
Stream data = new MemoryStream([], 0, 0, false, false);
|
||||
Assert.Throws<InvalidDataException>(() => new TypeLengthValue(data));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_ValidMinimalStream()
|
||||
{
|
||||
Stream data = new MemoryStream([0x00]);
|
||||
var tlv = new TypeLengthValue(data);
|
||||
|
||||
Assert.Equal(ASN1Type.V_ASN1_EOC, tlv.Type);
|
||||
Assert.Equal(default, tlv.Length);
|
||||
Assert.Null(tlv.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_ValidBoolean()
|
||||
{
|
||||
Stream data = new MemoryStream([0x01, 0x01, 0x01]);
|
||||
var tlv = new TypeLengthValue(data);
|
||||
|
||||
Assert.Equal(ASN1Type.V_ASN1_BOOLEAN, tlv.Type);
|
||||
Assert.Equal(1UL, tlv.Length);
|
||||
Assert.NotNull(tlv.Value);
|
||||
|
||||
byte[]? valueAsArray = tlv.Value as byte[];
|
||||
Assert.NotNull(valueAsArray);
|
||||
byte actual = Assert.Single(valueAsArray);
|
||||
Assert.Equal(0x01, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new byte[] { 0x26, 0x81, 0x03, 0x01, 0x01, 0x01 })]
|
||||
[InlineData(new byte[] { 0x26, 0x82, 0x00, 0x03, 0x01, 0x01, 0x01 })]
|
||||
[InlineData(new byte[] { 0x26, 0x83, 0x00, 0x00, 0x03, 0x01, 0x01, 0x01 })]
|
||||
[InlineData(new byte[] { 0x26, 0x84, 0x00, 0x00, 0x00, 0x03, 0x01, 0x01, 0x01 })]
|
||||
[InlineData(new byte[] { 0x26, 0x85, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x01, 0x01 })]
|
||||
[InlineData(new byte[] { 0x26, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x01, 0x01 })]
|
||||
[InlineData(new byte[] { 0x26, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x01, 0x01 })]
|
||||
[InlineData(new byte[] { 0x26, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x01, 0x01 })]
|
||||
public void Constructor_ComplexValue(byte[] arr)
|
||||
{
|
||||
Stream data = new MemoryStream(arr);
|
||||
var tlv = new TypeLengthValue(data);
|
||||
|
||||
Assert.Equal(ASN1Type.V_ASN1_CONSTRUCTED | ASN1Type.V_ASN1_OBJECT, tlv.Type);
|
||||
Assert.Equal(3UL, tlv.Length);
|
||||
Assert.NotNull(tlv.Value);
|
||||
|
||||
TypeLengthValue[]? valueAsArray = tlv.Value as TypeLengthValue[];
|
||||
Assert.NotNull(valueAsArray);
|
||||
TypeLengthValue actual = Assert.Single(valueAsArray);
|
||||
|
||||
Assert.Equal(ASN1Type.V_ASN1_BOOLEAN, actual.Type);
|
||||
Assert.Equal(1UL, actual.Length);
|
||||
Assert.NotNull(actual.Value);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new byte[] { 0x26, 0x80 })]
|
||||
[InlineData(new byte[] { 0x26, 0x89 })]
|
||||
public void Constructor_ComplexValueInvalidLength_Throws(byte[] arr)
|
||||
{
|
||||
Stream data = new MemoryStream(arr);
|
||||
Assert.Throws<InvalidOperationException>(() => new TypeLengthValue(data));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Formatting
|
||||
|
||||
[Fact]
|
||||
public void Format_EOC()
|
||||
{
|
||||
string expected = "Type: V_ASN1_EOC";
|
||||
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_EOC, 0, null);
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Format_ZeroLength()
|
||||
{
|
||||
string expected = "Type: V_ASN1_NULL, Length: 0";
|
||||
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_NULL, 0, null);
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Format_InvalidConstructed()
|
||||
{
|
||||
string expected = "Type: V_ASN1_OBJECT, V_ASN1_CONSTRUCTED, Length: 1, Value: [INVALID DATA TYPE]";
|
||||
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_OBJECT | ASN1Type.V_ASN1_CONSTRUCTED, 1, (object?)false);
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Format_ValidConstructed()
|
||||
{
|
||||
string expected = "Type: V_ASN1_OBJECT, V_ASN1_CONSTRUCTED, Length: 3, Value:\n Type: V_ASN1_BOOLEAN, Length: 1, Value: True";
|
||||
var boolTlv = new TypeLengthValue(ASN1Type.V_ASN1_BOOLEAN, 1, new byte[] { 0x01 });
|
||||
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_OBJECT | ASN1Type.V_ASN1_CONSTRUCTED, 3, new TypeLengthValue[] { boolTlv });
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Format_InvalidDataType()
|
||||
{
|
||||
string expected = "Type: V_ASN1_OBJECT, Length: 1, Value: [INVALID DATA TYPE]";
|
||||
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_OBJECT, 1, (object?)false);
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Format_InvalidLength()
|
||||
{
|
||||
string expected = "Type: V_ASN1_NULL, Length: 1, Value: [NO DATA]";
|
||||
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_NULL, 1, Array.Empty<byte>());
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Format_InvalidBooleanLength()
|
||||
{
|
||||
string expected = "Type: V_ASN1_BOOLEAN, Length: 2 [Expected length of 1], Value: True";
|
||||
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_BOOLEAN, 2, new byte[] { 0x01 });
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Format_InvalidBooleanArrayLength()
|
||||
{
|
||||
string expected = "Type: V_ASN1_BOOLEAN, Length: 1 [Expected value length of 1], Value: True";
|
||||
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_BOOLEAN, 1, new byte[] { 0x01, 0x00 });
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Format_ValidBoolean()
|
||||
{
|
||||
string expected = "Type: V_ASN1_BOOLEAN, Length: 1, Value: True";
|
||||
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_BOOLEAN, 1, new byte[] { 0x01 });
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Format_ValidInteger()
|
||||
{
|
||||
string expected = "Type: V_ASN1_INTEGER, Length: 1, Value: 1";
|
||||
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_INTEGER, 1, new byte[] { 0x01 });
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Format_ValidBitString_NoBits()
|
||||
{
|
||||
string expected = "Type: V_ASN1_BIT_STRING, Length: 1, Value with 0 unused bits";
|
||||
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_BIT_STRING, 1, new byte[] { 0x00 });
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Format_ValidBitString_Bits()
|
||||
{
|
||||
string expected = "Type: V_ASN1_BIT_STRING, Length: 1, Value with 1 unused bits: 01";
|
||||
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_BIT_STRING, 1, new byte[] { 0x01, 0x01 });
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Format_ValidOctetString()
|
||||
{
|
||||
string expected = "Type: V_ASN1_OCTET_STRING, Length: 1, Value: 01";
|
||||
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_OCTET_STRING, 1, new byte[] { 0x01 });
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Format_ValidObject()
|
||||
{
|
||||
string expected = "Type: V_ASN1_OBJECT, Length: 3, Value: 0.1.2.3 (/ITU-T/1/2/3)";
|
||||
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_OBJECT, 3, new byte[] { 0x01, 0x02, 0x03 });
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Format_ValidUTF8String()
|
||||
{
|
||||
string expected = "Type: V_ASN1_UTF8STRING, Length: 3, Value: ABC";
|
||||
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_UTF8STRING, 3, new byte[] { 0x41, 0x42, 0x43 });
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Format_ValidPrintableString()
|
||||
{
|
||||
string expected = "Type: V_ASN1_PRINTABLESTRING, Length: 3, Value: ABC";
|
||||
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_PRINTABLESTRING, 3, new byte[] { 0x41, 0x42, 0x43 });
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Format_ValidTeletexString()
|
||||
{
|
||||
string expected = "Type: V_ASN1_TELETEXSTRING, Length: 3, Value: ABC";
|
||||
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_TELETEXSTRING, 3, new byte[] { 0x41, 0x42, 0x43 });
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Format_ValidIA5String()
|
||||
{
|
||||
string expected = "Type: V_ASN1_IA5STRING, Length: 3, Value: ABC";
|
||||
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_IA5STRING, 3, new byte[] { 0x41, 0x42, 0x43 });
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Format_InvalidUTCTime()
|
||||
{
|
||||
string expected = "Type: V_ASN1_UTCTIME, Length: 3, Value: ABC";
|
||||
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_UTCTIME, 3, new byte[] { 0x41, 0x42, 0x43 });
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Format_ValidUTCTime()
|
||||
{
|
||||
string expected = "Type: V_ASN1_UTCTIME, Length: 3, Value: 1980-01-01 00:00:00";
|
||||
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_UTCTIME, 3, new byte[] { 0x31, 0x39, 0x38, 0x30, 0x2D, 0x30, 0x31, 0x2D, 0x30, 0x31, 0x20, 0x30, 0x30, 0x3A, 0x30, 0x30, 0x3A, 0x30, 0x30 });
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Format_ValidBmpString()
|
||||
{
|
||||
string expected = "Type: V_ASN1_BMPSTRING, Length: 6, Value: ABC";
|
||||
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_BMPSTRING, 6, new byte[] { 0x41, 0x00, 0x42, 0x00, 0x43, 0x00 });
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Format_ValidUnformatted()
|
||||
{
|
||||
string expected = "Type: V_ASN1_OBJECT_DESCRIPTOR, Length: 1, Value: 01";
|
||||
var tlv = new TypeLengthValue(ASN1Type.V_ASN1_OBJECT_DESCRIPTOR, 1, new byte[] { 0x01 });
|
||||
string actual = tlv.Format();
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Assembly Properties -->
|
||||
<TargetFrameworks>net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64</RuntimeIdentifiers>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>1.2.0</Version>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski</Authors>
|
||||
<Description>Serialization and deserialization helpers for various types</Description>
|
||||
<Copyright>Copyright (c) Matt Nadareski 2022-2023</Copyright>
|
||||
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<RepositoryUrl>https://github.com/SabreTools/SabreTools.ASN1</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageTags>asn asn1 dot oid</PackageTags>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="README.md" Pack="true" PackagePath=""/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SabreTools.IO" Version="1.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31903.59
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SabreTools.ASN1", "SabreTools.ASN1.csproj", "{88EA40DD-E313-479C-94EA-0AB948DB4720}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SabreTools.ASN1", "SabreTools.ASN1\SabreTools.ASN1.csproj", "{88EA40DD-E313-479C-94EA-0AB948DB4720}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SabreTools.ASN1.Test", "SabreTools.ASN1.Test\SabreTools.ASN1.Test.csproj", "{5C740920-9505-4B58-AC17-2967559F6AE7}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@@ -18,5 +20,9 @@ Global
|
||||
{88EA40DD-E313-479C-94EA-0AB948DB4720}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{88EA40DD-E313-479C-94EA-0AB948DB4720}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{88EA40DD-E313-479C-94EA-0AB948DB4720}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5C740920-9505-4B58-AC17-2967559F6AE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5C740920-9505-4B58-AC17-2967559F6AE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5C740920-9505-4B58-AC17-2967559F6AE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5C740920-9505-4B58-AC17-2967559F6AE7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
55
SabreTools.ASN1/AbstractSyntaxNotationOne.cs
Normal file
55
SabreTools.ASN1/AbstractSyntaxNotationOne.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace SabreTools.ASN1
|
||||
{
|
||||
/// <summary>
|
||||
/// ASN.1 Parser
|
||||
/// </summary>
|
||||
public static class AbstractSyntaxNotationOne
|
||||
{
|
||||
/// <summary>
|
||||
/// Parse a byte array into a DER-encoded ASN.1 structure
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array representing the data</param>
|
||||
/// <param name="pointer">Current pointer into the data</param>
|
||||
public static List<TypeLengthValue> Parse(byte[] data, int pointer)
|
||||
{
|
||||
// If the data is invalid
|
||||
if (data.Length == 0)
|
||||
throw new InvalidDataException(nameof(data));
|
||||
if (pointer < 0 || pointer >= data.Length)
|
||||
throw new IndexOutOfRangeException(nameof(pointer));
|
||||
|
||||
using var stream = new MemoryStream(data);
|
||||
stream.Seek(pointer, SeekOrigin.Begin);
|
||||
return Parse(stream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a stream into a DER-encoded ASN.1 structure
|
||||
/// </summary>
|
||||
/// <param name="data">Stream representing the data</param>
|
||||
public static List<TypeLengthValue> Parse(Stream data)
|
||||
{
|
||||
// If the data is invalid
|
||||
if (data.Length == 0 || !data.CanRead)
|
||||
throw new InvalidDataException(nameof(data));
|
||||
if (data.Position < 0 || data.Position >= data.Length)
|
||||
throw new IndexOutOfRangeException(nameof(data));
|
||||
|
||||
// Create the output list to return
|
||||
var topLevelValues = new List<TypeLengthValue>();
|
||||
|
||||
// Loop through the data and return all top-level values
|
||||
while (data.Position < data.Length)
|
||||
{
|
||||
var topLevelValue = new TypeLengthValue(data);
|
||||
topLevelValues.Add(topLevelValue);
|
||||
}
|
||||
|
||||
return topLevelValues;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,17 +8,6 @@ namespace SabreTools.ASN1
|
||||
[Flags]
|
||||
public enum ASN1Type : byte
|
||||
{
|
||||
#region Modifiers
|
||||
|
||||
V_ASN1_UNIVERSAL = 0x00,
|
||||
V_ASN1_PRIMITIVE_TAG = 0x1F,
|
||||
V_ASN1_CONSTRUCTED = 0x20,
|
||||
V_ASN1_APPLICATION = 0x40,
|
||||
V_ASN1_CONTEXT_SPECIFIC = 0x80,
|
||||
V_ASN1_PRIVATE = 0xC0,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Types
|
||||
|
||||
V_ASN1_EOC = 0x00,
|
||||
@@ -51,5 +40,19 @@ namespace SabreTools.ASN1
|
||||
V_ASN1_BMPSTRING = 0x1E,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Modifiers
|
||||
|
||||
// Commented out because it is the default
|
||||
// and can interfere with V_ASN1_EOC
|
||||
// V_ASN1_UNIVERSAL = 0x00,
|
||||
|
||||
V_ASN1_PRIMITIVE_TAG = 0x1F,
|
||||
V_ASN1_CONSTRUCTED = 0x20,
|
||||
V_ASN1_APPLICATION = 0x40,
|
||||
V_ASN1_CONTEXT_SPECIFIC = 0x80,
|
||||
V_ASN1_PRIVATE = 0xC0,
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -9,13 +9,12 @@ namespace SabreTools.ASN1
|
||||
/// Parse an OID in separated-value notation into ASN.1 notation
|
||||
/// </summary>
|
||||
/// <param name="values">List of values to check against</param>
|
||||
/// <param name="index">Current index into the list</param>
|
||||
/// <returns>ASN.1 formatted string, if possible</returns>
|
||||
/// <remarks>
|
||||
public static string? ParseOIDToASN1Notation(ulong[]? values, ref int index)
|
||||
public static string? ParseOIDToASN1Notation(ulong[]? values)
|
||||
{
|
||||
// TODO: Once the modified OID-IRI formatting is done, make an ASN.1 notation version
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
18039
SabreTools.ASN1/ObjectIdentifier.ModifiedOIDIRI.cs
Normal file
18039
SabreTools.ASN1/ObjectIdentifier.ModifiedOIDIRI.cs
Normal file
File diff suppressed because it is too large
Load Diff
907
SabreTools.ASN1/ObjectIdentifier.OIDIRI.cs
Normal file
907
SabreTools.ASN1/ObjectIdentifier.OIDIRI.cs
Normal file
@@ -0,0 +1,907 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace SabreTools.ASN1
|
||||
{
|
||||
/// <summary>
|
||||
/// Methods related to Object Identifiers (OID) and OID-IRI formatting
|
||||
/// </summary>
|
||||
public static partial class ObjectIdentifier
|
||||
{
|
||||
/// <summary>
|
||||
/// Parse an OID in separated-value notation into OID-IRI notation
|
||||
/// </summary>
|
||||
/// <param name="values">List of values to check against</param>
|
||||
/// <param name="index">Current index into the list</param>
|
||||
/// <returns>OID-IRI formatted string, if possible</returns>
|
||||
/// <see href="http://www.oid-info.com/index.htm"/>
|
||||
public static string? ParseOIDToOIDIRINotation(ulong[]? values)
|
||||
{
|
||||
// If we have an invalid set of values, we can't do anything
|
||||
if (values == null || values.Length == 0)
|
||||
return null;
|
||||
|
||||
// Set the initial index
|
||||
int index = 0;
|
||||
|
||||
// Get a string builder for the path
|
||||
var nameBuilder = new StringBuilder();
|
||||
|
||||
// Try to parse the standard value
|
||||
string? standard = ParseOIDToOIDIRINotation(values, ref index);
|
||||
if (standard == null)
|
||||
return null;
|
||||
|
||||
// Add the standard value to the output
|
||||
nameBuilder.Append(standard);
|
||||
|
||||
// If we have no more items
|
||||
if (index == values.Length)
|
||||
return nameBuilder.ToString();
|
||||
|
||||
// Add trailing items as just values
|
||||
nameBuilder.Append("/");
|
||||
|
||||
// Get the remaining values in a new array
|
||||
var remainingValues = new ulong[values.Length - index];
|
||||
Array.Copy(values, index, remainingValues, 0, remainingValues.Length);
|
||||
|
||||
// Convert the values and append to the builder
|
||||
var stringValues = Array.ConvertAll(remainingValues, v => v.ToString());
|
||||
nameBuilder.Append(string.Join("/", stringValues));
|
||||
|
||||
// Create and return the string
|
||||
return nameBuilder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse an OID in separated-value notation into OID-IRI notation
|
||||
/// </summary>
|
||||
/// <param name="values">List of values to check against</param>
|
||||
/// <param name="index">Current index into the list</param>
|
||||
/// <returns>OID-IRI formatted string, if possible</returns>
|
||||
/// <see href="http://www.oid-info.com/index.htm"/>
|
||||
private static string? ParseOIDToOIDIRINotation(ulong[]? values, ref int index)
|
||||
{
|
||||
// If we have an invalid set of values, we can't do anything
|
||||
if (values == null || values.Length == 0)
|
||||
return null;
|
||||
|
||||
// If we have an invalid index, we can't do anything
|
||||
if (index < 0 || index >= values.Length)
|
||||
return null;
|
||||
|
||||
#region Start
|
||||
|
||||
var oidPath = string.Empty;
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: goto oid_0;
|
||||
case 1: goto oid_1;
|
||||
case 2: goto oid_2;
|
||||
default: return oidPath;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// itu-t, ccitt, itu-r
|
||||
#region 0.*
|
||||
|
||||
oid_0:
|
||||
|
||||
oidPath += "/ITU-T";
|
||||
if (index == values.Length) return oidPath;
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: goto oid_0_0;
|
||||
case 2: return $"{oidPath}/Administration";
|
||||
case 3: return $"{oidPath}/Network-Operator";
|
||||
case 4: return $"{oidPath}/Identified-Organization";
|
||||
case 5: return "/ITU-R/R-Recommendation";
|
||||
case 9: return $"{oidPath}/Data";
|
||||
default: return $"{oidPath}/{values[index - 1]}";
|
||||
}
|
||||
;
|
||||
|
||||
// recommendation
|
||||
#region 0.0.*
|
||||
|
||||
oid_0_0:
|
||||
|
||||
oidPath += "/Recommendation";
|
||||
if (index == values.Length) return oidPath;
|
||||
return values[index++] switch
|
||||
{
|
||||
1 => $"{oidPath}/A",
|
||||
2 => $"{oidPath}/B",
|
||||
3 => $"{oidPath}/C",
|
||||
4 => $"{oidPath}/D",
|
||||
5 => $"{oidPath}/E",
|
||||
6 => $"{oidPath}/F",
|
||||
7 => $"{oidPath}/G",
|
||||
8 => $"{oidPath}/H",
|
||||
9 => $"{oidPath}/I",
|
||||
10 => $"{oidPath}/J",
|
||||
11 => $"{oidPath}/K",
|
||||
12 => $"{oidPath}/L",
|
||||
13 => $"{oidPath}/M",
|
||||
14 => $"{oidPath}/N",
|
||||
15 => $"{oidPath}/O",
|
||||
16 => $"{oidPath}/P",
|
||||
17 => $"{oidPath}/Q",
|
||||
18 => $"{oidPath}/R",
|
||||
19 => $"{oidPath}/S",
|
||||
20 => $"{oidPath}/T",
|
||||
21 => $"{oidPath}/U",
|
||||
22 => $"{oidPath}/V",
|
||||
24 => $"{oidPath}/X",
|
||||
25 => $"{oidPath}/Y",
|
||||
26 => $"{oidPath}/Z",
|
||||
_ => $"{oidPath}/{values[index - 1]}",
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
// iso
|
||||
#region 1.*
|
||||
|
||||
oid_1:
|
||||
|
||||
oidPath += "/ISO";
|
||||
if (index == values.Length) return oidPath;
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: return $"{oidPath}/Standard";
|
||||
case 1: return $"{oidPath}/Registration-Authority";
|
||||
case 2: goto oid_1_2;
|
||||
case 3: return $"{oidPath}/Identified-Organization";
|
||||
default: return $"{oidPath}/{values[index - 1]}";
|
||||
}
|
||||
|
||||
// member-body
|
||||
#region 1.2.*
|
||||
|
||||
oid_1_2:
|
||||
|
||||
oidPath += "/Member-Body";
|
||||
if (index == values.Length) return oidPath;
|
||||
return values[index++] switch
|
||||
{
|
||||
36 => $"{oidPath}/AU",
|
||||
40 => $"{oidPath}/AT",
|
||||
56 => $"{oidPath}/BE",
|
||||
124 => $"{oidPath}/CA",
|
||||
156 => $"{oidPath}/CN",
|
||||
203 => $"{oidPath}/CZ",
|
||||
208 => $"{oidPath}/DK",
|
||||
246 => $"{oidPath}/FI",
|
||||
250 => $"{oidPath}/FR",
|
||||
276 => $"{oidPath}/DE",
|
||||
300 => $"{oidPath}/GR",
|
||||
344 => $"{oidPath}/HK",
|
||||
372 => $"{oidPath}/IE",
|
||||
392 => $"{oidPath}/JP",
|
||||
398 => $"{oidPath}/KZ",
|
||||
410 => $"{oidPath}/KR",
|
||||
498 => $"{oidPath}/MD",
|
||||
528 => $"{oidPath}/NL",
|
||||
566 => $"{oidPath}/NG",
|
||||
578 => $"{oidPath}/NO",
|
||||
616 => $"{oidPath}/PL",
|
||||
643 => $"{oidPath}/RU",
|
||||
702 => $"{oidPath}/SG",
|
||||
752 => $"{oidPath}/SE",
|
||||
804 => $"{oidPath}/UA",
|
||||
826 => $"{oidPath}/GB",
|
||||
840 => $"{oidPath}/US",
|
||||
_ => $"{oidPath}/{values[index - 1]}",
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
// joint-iso-itu-t, joint-iso-ccitt
|
||||
#region 2.*
|
||||
|
||||
oid_2:
|
||||
|
||||
oidPath += "/Joint-ISO-ITU-T";
|
||||
if (index == values.Length) return oidPath;
|
||||
switch (values[index++])
|
||||
{
|
||||
case 1: return "/ASN.1";
|
||||
case 16: oidPath = string.Empty; goto oid_2_16;
|
||||
case 17: return $"{oidPath}/Registration-Procedures";
|
||||
case 23: return $"{oidPath}/International-Organizations";
|
||||
case 25: goto oid_2_25;
|
||||
case 27: return "/Tag-Based";
|
||||
case 28: return $"{oidPath}/ITS";
|
||||
case 41: return "/BIP";
|
||||
case 42: oidPath = string.Empty; goto oid_2_42;
|
||||
case 48: oidPath = string.Empty; goto oid_2_48;
|
||||
case 49: oidPath = string.Empty; goto oid_2_49;
|
||||
case 50: return "/OIDResolutionSystem";
|
||||
case 51: return "/GS1";
|
||||
case 52: return $"{oidPath}/UAV";
|
||||
case 999: return $"{oidPath}/Example";
|
||||
default: return $"{oidPath}/{values[index - 1]}";
|
||||
}
|
||||
|
||||
// country
|
||||
#region 2.16.*
|
||||
|
||||
oid_2_16:
|
||||
|
||||
oidPath += "/Country";
|
||||
if (index == values.Length) return oidPath;
|
||||
return values[index++] switch
|
||||
{
|
||||
4 => $"{oidPath}AF",
|
||||
8 => $"{oidPath}AL",
|
||||
12 => $"{oidPath}DZ",
|
||||
20 => $"{oidPath}AD",
|
||||
24 => $"{oidPath}AO",
|
||||
28 => $"{oidPath}AG",
|
||||
31 => $"{oidPath}AZ",
|
||||
32 => $"{oidPath}AR",
|
||||
36 => $"{oidPath}AU",
|
||||
40 => $"{oidPath}AT",
|
||||
44 => $"{oidPath}BS",
|
||||
48 => $"{oidPath}BH",
|
||||
50 => $"{oidPath}BD",
|
||||
51 => $"{oidPath}AM",
|
||||
52 => $"{oidPath}BB",
|
||||
56 => $"{oidPath}BE",
|
||||
60 => $"{oidPath}BM",
|
||||
64 => $"{oidPath}BT",
|
||||
68 => $"{oidPath}BO",
|
||||
70 => $"{oidPath}BA",
|
||||
72 => $"{oidPath}BW",
|
||||
76 => $"{oidPath}BR",
|
||||
84 => $"{oidPath}BZ",
|
||||
90 => $"{oidPath}SB",
|
||||
96 => $"{oidPath}BN",
|
||||
100 => $"{oidPath}BG",
|
||||
104 => $"{oidPath}MM",
|
||||
108 => $"{oidPath}BI",
|
||||
112 => $"{oidPath}BY",
|
||||
116 => $"{oidPath}KH",
|
||||
120 => $"{oidPath}CM",
|
||||
124 => $"{oidPath}CA",
|
||||
132 => $"{oidPath}CV",
|
||||
140 => $"{oidPath}CF",
|
||||
144 => $"{oidPath}LK",
|
||||
148 => $"{oidPath}TD",
|
||||
152 => $"{oidPath}CL",
|
||||
156 => $"{oidPath}CN",
|
||||
158 => $"{oidPath}TW",
|
||||
170 => $"{oidPath}CO",
|
||||
174 => $"{oidPath}KM",
|
||||
178 => $"{oidPath}CG",
|
||||
180 => $"{oidPath}CD",
|
||||
188 => $"{oidPath}CR",
|
||||
191 => $"{oidPath}HR",
|
||||
192 => $"{oidPath}CU",
|
||||
196 => $"{oidPath}CY",
|
||||
203 => $"{oidPath}CZ",
|
||||
204 => $"{oidPath}BJ",
|
||||
208 => $"{oidPath}DK",
|
||||
212 => $"{oidPath}DM",
|
||||
214 => $"{oidPath}DO",
|
||||
218 => $"{oidPath}EC",
|
||||
222 => $"{oidPath}SV",
|
||||
226 => $"{oidPath}GQ",
|
||||
231 => $"{oidPath}ET",
|
||||
232 => $"{oidPath}ER",
|
||||
233 => $"{oidPath}EE",
|
||||
242 => $"{oidPath}FJ",
|
||||
246 => $"{oidPath}FI",
|
||||
250 => $"{oidPath}FR",
|
||||
262 => $"{oidPath}DJ",
|
||||
266 => $"{oidPath}GA",
|
||||
268 => $"{oidPath}GE",
|
||||
270 => $"{oidPath}GM",
|
||||
275 => $"{oidPath}PS",
|
||||
276 => $"{oidPath}DE",
|
||||
288 => $"{oidPath}GH",
|
||||
296 => $"{oidPath}KI",
|
||||
300 => $"{oidPath}GR",
|
||||
308 => $"{oidPath}GD",
|
||||
320 => $"{oidPath}GT",
|
||||
324 => $"{oidPath}GN",
|
||||
328 => $"{oidPath}GY",
|
||||
332 => $"{oidPath}HT",
|
||||
336 => $"{oidPath}VA",
|
||||
340 => $"{oidPath}HN",
|
||||
344 => $"{oidPath}HK",
|
||||
348 => $"{oidPath}HU",
|
||||
352 => $"{oidPath}IS",
|
||||
356 => $"{oidPath}IN",
|
||||
360 => $"{oidPath}ID",
|
||||
364 => $"{oidPath}IR",
|
||||
368 => $"{oidPath}IQ",
|
||||
372 => $"{oidPath}IE",
|
||||
376 => $"{oidPath}IL",
|
||||
380 => $"{oidPath}IT",
|
||||
384 => $"{oidPath}CI",
|
||||
388 => $"{oidPath}JM",
|
||||
392 => $"{oidPath}JP",
|
||||
398 => $"{oidPath}KZ",
|
||||
400 => $"{oidPath}JO",
|
||||
404 => $"{oidPath}KE",
|
||||
408 => $"{oidPath}KP",
|
||||
410 => $"{oidPath}KR",
|
||||
414 => $"{oidPath}KW",
|
||||
417 => $"{oidPath}KG",
|
||||
418 => $"{oidPath}LA",
|
||||
422 => $"{oidPath}LB",
|
||||
426 => $"{oidPath}LS",
|
||||
428 => $"{oidPath}LV",
|
||||
430 => $"{oidPath}LR",
|
||||
434 => $"{oidPath}LY",
|
||||
438 => $"{oidPath}LI",
|
||||
440 => $"{oidPath}LT",
|
||||
442 => $"{oidPath}LU",
|
||||
450 => $"{oidPath}MG",
|
||||
454 => $"{oidPath}MW",
|
||||
458 => $"{oidPath}MY",
|
||||
462 => $"{oidPath}MV",
|
||||
466 => $"{oidPath}ML",
|
||||
470 => $"{oidPath}MT",
|
||||
478 => $"{oidPath}MR",
|
||||
480 => $"{oidPath}MU",
|
||||
484 => $"{oidPath}MX",
|
||||
492 => $"{oidPath}MC",
|
||||
496 => $"{oidPath}MN",
|
||||
498 => $"{oidPath}MD",
|
||||
499 => $"{oidPath}ME",
|
||||
504 => $"{oidPath}MA",
|
||||
508 => $"{oidPath}MZ",
|
||||
512 => $"{oidPath}OM",
|
||||
516 => $"{oidPath}NA",
|
||||
520 => $"{oidPath}NR",
|
||||
524 => $"{oidPath}NP",
|
||||
528 => $"{oidPath}NL",
|
||||
530 => $"{oidPath}AN",
|
||||
548 => $"{oidPath}VU",
|
||||
554 => $"{oidPath}NZ",
|
||||
558 => $"{oidPath}NI",
|
||||
562 => $"{oidPath}NE",
|
||||
566 => $"{oidPath}NG",
|
||||
578 => $"{oidPath}NO",
|
||||
583 => $"{oidPath}FM",
|
||||
584 => $"{oidPath}MH",
|
||||
585 => $"{oidPath}PW",
|
||||
586 => $"{oidPath}PK",
|
||||
591 => $"{oidPath}PA",
|
||||
598 => $"{oidPath}PG",
|
||||
600 => $"{oidPath}PY",
|
||||
604 => $"{oidPath}PE",
|
||||
608 => $"{oidPath}PH",
|
||||
616 => $"{oidPath}PL",
|
||||
620 => $"{oidPath}PT",
|
||||
624 => $"{oidPath}GW",
|
||||
626 => $"{oidPath}TL",
|
||||
634 => $"{oidPath}QA",
|
||||
642 => $"{oidPath}RO",
|
||||
643 => $"{oidPath}RU",
|
||||
646 => $"{oidPath}RW",
|
||||
659 => $"{oidPath}KN",
|
||||
662 => $"{oidPath}LC",
|
||||
670 => $"{oidPath}VC",
|
||||
674 => $"{oidPath}SM",
|
||||
678 => $"{oidPath}ST",
|
||||
682 => $"{oidPath}SA",
|
||||
686 => $"{oidPath}SN",
|
||||
688 => $"{oidPath}RS",
|
||||
690 => $"{oidPath}SC",
|
||||
694 => $"{oidPath}SL",
|
||||
702 => $"{oidPath}SG",
|
||||
703 => $"{oidPath}SK",
|
||||
704 => $"{oidPath}VN",
|
||||
705 => $"{oidPath}SI",
|
||||
706 => $"{oidPath}SO",
|
||||
710 => $"{oidPath}ZA",
|
||||
716 => $"{oidPath}ZW",
|
||||
724 => $"{oidPath}ES",
|
||||
728 => $"{oidPath}SS",
|
||||
729 => $"{oidPath}SD",
|
||||
740 => $"{oidPath}SR",
|
||||
748 => $"{oidPath}SZ",
|
||||
752 => $"{oidPath}SE",
|
||||
756 => $"{oidPath}CH",
|
||||
760 => $"{oidPath}SY",
|
||||
762 => $"{oidPath}TJ",
|
||||
764 => $"{oidPath}TH",
|
||||
768 => $"{oidPath}TG",
|
||||
776 => $"{oidPath}TO",
|
||||
780 => $"{oidPath}TT",
|
||||
784 => $"{oidPath}AE",
|
||||
788 => $"{oidPath}TN",
|
||||
792 => $"{oidPath}TR",
|
||||
795 => $"{oidPath}TM",
|
||||
798 => $"{oidPath}TV",
|
||||
800 => $"{oidPath}UG",
|
||||
804 => $"{oidPath}UA",
|
||||
807 => $"{oidPath}MK",
|
||||
818 => $"{oidPath}EG",
|
||||
826 => $"{oidPath}GB",
|
||||
834 => $"{oidPath}TZ",
|
||||
840 => $"{oidPath}US",
|
||||
854 => $"{oidPath}BF",
|
||||
858 => $"{oidPath}UY",
|
||||
860 => $"{oidPath}UZ",
|
||||
862 => $"{oidPath}VE",
|
||||
882 => $"{oidPath}WS",
|
||||
887 => $"{oidPath}YE",
|
||||
894 => $"{oidPath}ZM",
|
||||
_ => $"{oidPath}{values[index - 1]}",
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
// uuid [TODO: Requires 128-bit values]
|
||||
#region 2.25.*
|
||||
|
||||
oid_2_25:
|
||||
|
||||
oidPath += "/UUID";
|
||||
if (index == values.Length) return oidPath;
|
||||
return values[index++] switch
|
||||
{
|
||||
0 => $"{oidPath}/00000000-0000-0000-0000-000000000000",
|
||||
//case 288786655511405443130567505384701230: return $"{oidPath}/00379e48-0a2b-1085-b288-0002a5d5fd2e";
|
||||
//case 987895962269883002155146617097157934: return $"{oidPath}/00be4308-0c89-1085-8ea0-0002a5d5fd2e";
|
||||
//case 1858228783942312576083372383319475483: return $"{oidPath}/0165e1c0-a655-11e0-95b8-0002a5d5c51b";
|
||||
//case 2474299330026746002885628159579243803: return $"{oidPath}/01dc8860-25fb-11da-82b2-0002a5d5c51b";
|
||||
//case 3263645701162998421821186056373271854: return $"{oidPath}/02748e28-08c4-1085-b21d-0002a5d5fd2e";
|
||||
//case 3325839809379844461264382260940242222: return $"{oidPath}/02808890-0ad8-1085-9bdf-0002a5d5fd2e";
|
||||
// TODO: Left off at http://www.oid-info.com/get/2.25.3664154270495270126161055518190585115
|
||||
_ => $"{oidPath}/{values[index - 1]}",
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
// telebiometrics
|
||||
#region 2.42.*
|
||||
|
||||
oid_2_42:
|
||||
|
||||
oidPath += "/Telebiometrics";
|
||||
if (index == values.Length) return oidPath;
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: goto oid_2_42_0;
|
||||
case 1: goto oid_2_42_1;
|
||||
case 2: goto oid_2_42_2;
|
||||
case 3: goto oid_2_42_3;
|
||||
default: return $"{oidPath}/{values[index - 1]}";
|
||||
}
|
||||
|
||||
// modules
|
||||
#region 2.42.0.*
|
||||
|
||||
oid_2_42_0:
|
||||
|
||||
oidPath += "/Modules";
|
||||
if (index == values.Length) return oidPath;
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: goto oid_2_42_0_0;
|
||||
default: return $"{oidPath}/{values[index - 1]}";
|
||||
}
|
||||
|
||||
// main
|
||||
#region 2.42.0.0.*
|
||||
|
||||
oid_2_42_0_0:
|
||||
|
||||
oidPath += "/Main_Module";
|
||||
if (index == values.Length) return oidPath;
|
||||
return values[index++] switch
|
||||
{
|
||||
1 => $"{oidPath}/Version1",
|
||||
_ => $"{oidPath}/{values[index - 1]}",
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
// tmm
|
||||
#region 2.42.1.*
|
||||
|
||||
oid_2_42_1:
|
||||
|
||||
oidPath += "/TMM";
|
||||
if (index == values.Length) return oidPath;
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: goto oid_2_42_1_0;
|
||||
case 1: goto oid_2_42_1_1;
|
||||
case 2: goto oid_2_42_1_2;
|
||||
case 3: goto oid_2_42_1_3;
|
||||
case 4: return $"{oidPath}/Practitioners";
|
||||
default: return $"{oidPath}/{values[index - 1]}";
|
||||
}
|
||||
|
||||
// modules
|
||||
#region 2.42.1.0.*
|
||||
|
||||
oid_2_42_1_0:
|
||||
|
||||
oidPath += "/Modules";
|
||||
if (index == values.Length) return oidPath;
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: goto oid_2_42_1_0_0;
|
||||
default: return $"{oidPath}/{values[index - 1]}";
|
||||
}
|
||||
|
||||
// main
|
||||
#region 2.42.1.0.0.*
|
||||
|
||||
oid_2_42_1_0_0:
|
||||
|
||||
oidPath += "/Main";
|
||||
if (index == values.Length) return oidPath;
|
||||
return values[index++] switch
|
||||
{
|
||||
0 => $"{oidPath}/First_Version",
|
||||
_ => $"{oidPath}/{values[index - 1]}",
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
// measures, metric
|
||||
#region 2.42.1.1.*
|
||||
|
||||
oid_2_42_1_1:
|
||||
|
||||
oidPath += "/Measures";
|
||||
if (index == values.Length) return oidPath;
|
||||
switch (values[index++])
|
||||
{
|
||||
case 1: goto oid_2_42_1_1_1;
|
||||
case 2: return $"{oidPath}/Units";
|
||||
case 3: return $"{oidPath}";
|
||||
case 4: return $"{oidPath}/Conditions";
|
||||
case 5: goto oid_2_42_1_1_5;
|
||||
default: return $"{oidPath}/{values[index - 1]}";
|
||||
}
|
||||
|
||||
// quantities
|
||||
#region 2.42.1.1.1.*
|
||||
|
||||
oid_2_42_1_1_1:
|
||||
|
||||
oidPath += "/Quantities";
|
||||
if (index == values.Length) return oidPath;
|
||||
return values[index++] switch
|
||||
{
|
||||
1 => $"{oidPath}/Physics",
|
||||
2 => $"{oidPath}/Chemistry",
|
||||
3 => $"{oidPath}/Biology",
|
||||
4 => $"{oidPath}/Culturology",
|
||||
5 => $"{oidPath}/Psychology",
|
||||
_ => $"{oidPath}/{values[index - 1]}",
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
// methods
|
||||
#region 2.42.1.1.5.*
|
||||
|
||||
oid_2_42_1_1_5:
|
||||
|
||||
oidPath += "/Methods";
|
||||
if (index == values.Length) return oidPath;
|
||||
return values[index++] switch
|
||||
{
|
||||
1 => $"{oidPath}/Physics",
|
||||
2 => $"{oidPath}/Chemistry",
|
||||
3 => $"{oidPath}/Biology",
|
||||
4 => $"{oidPath}/Culturology",
|
||||
5 => $"{oidPath}/Psychology",
|
||||
_ => $"{oidPath}/{values[index - 1]}",
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
// fields-of-study, scientific
|
||||
#region 2.42.1.2.*
|
||||
|
||||
oid_2_42_1_2:
|
||||
|
||||
oidPath += "/Fields_of_Study";
|
||||
if (index == values.Length) return oidPath;
|
||||
return values[index++] switch
|
||||
{
|
||||
1 => $"{oidPath}/Physics",
|
||||
2 => $"{oidPath}/Chemistry",
|
||||
3 => $"{oidPath}/Biology",
|
||||
4 => $"{oidPath}/Culturology",
|
||||
5 => $"{oidPath}/Psychology",
|
||||
_ => $"{oidPath}/{values[index - 1]}",
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
// modalities, sensory
|
||||
#region 2.42.1.3.*
|
||||
|
||||
oid_2_42_1_3:
|
||||
|
||||
oidPath += "/Modalities";
|
||||
if (index == values.Length) return oidPath;
|
||||
return values[index++] switch
|
||||
{
|
||||
1 => $"{oidPath}/Tango",
|
||||
2 => $"{oidPath}/Video",
|
||||
3 => $"{oidPath}/Audio",
|
||||
4 => $"{oidPath}/Chemo",
|
||||
5 => $"{oidPath}/Radio",
|
||||
6 => $"{oidPath}/Calor",
|
||||
7 => $"{oidPath}/Electro",
|
||||
_ => $"{oidPath}/{values[index - 1]}",
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
// human-physiology
|
||||
#region 2.42.2.*
|
||||
|
||||
oid_2_42_2:
|
||||
|
||||
oidPath += "/Human_Physiology";
|
||||
if (index == values.Length) return oidPath;
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: goto oid_2_42_2_0;
|
||||
case 1: goto oid_2_42_2_1;
|
||||
case 2: return $"{oidPath}/Symbol_Combinations";
|
||||
default: return $"{oidPath}/{values[index - 1]}";
|
||||
}
|
||||
|
||||
// modules
|
||||
#region 2.42.2.0.*
|
||||
|
||||
oid_2_42_2_0:
|
||||
|
||||
oidPath += "/Modules";
|
||||
if (index == values.Length) return oidPath;
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: goto oid_2_42_2_0_0;
|
||||
default: return $"{oidPath}/{values[index - 1]}";
|
||||
}
|
||||
|
||||
// main
|
||||
#region 2.42.2.0.0.*
|
||||
|
||||
oid_2_42_2_0_0:
|
||||
|
||||
oidPath += "/Main_Module";
|
||||
if (index == values.Length) return oidPath;
|
||||
return values[index++] switch
|
||||
{
|
||||
0 => $"{oidPath}/First_Version",
|
||||
_ => $"{oidPath}/{values[index - 1]}",
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
// symbols
|
||||
#region 2.42.2.1.*
|
||||
|
||||
oid_2_42_2_1:
|
||||
|
||||
oidPath += "/Symbols";
|
||||
if (index == values.Length) return oidPath;
|
||||
return values[index++] switch
|
||||
{
|
||||
1 => $"{oidPath}/Tango_in",
|
||||
2 => $"{oidPath}/Video_in",
|
||||
3 => $"{oidPath}/Audio_in",
|
||||
4 => $"{oidPath}/Chemo_in",
|
||||
5 => $"{oidPath}/Radio_in",
|
||||
6 => $"{oidPath}/Calor_in",
|
||||
7 => $"{oidPath}/Tango_out",
|
||||
8 => $"{oidPath}/Video_out",
|
||||
9 => $"{oidPath}/Audio_out",
|
||||
10 => $"{oidPath}/Chemo_out",
|
||||
11 => $"{oidPath}/Radio_out",
|
||||
12 => $"{oidPath}/Calor_out",
|
||||
13 => $"{oidPath}/Safe",
|
||||
14 => $"{oidPath}/Threshold",
|
||||
_ => $"{oidPath}/{values[index - 1]}",
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
// obj-cat, telehealth, e-health-protocol, th
|
||||
#region 2.42.3.*
|
||||
|
||||
oid_2_42_3:
|
||||
|
||||
oidPath += "/E_Health_Protocol";
|
||||
if (index == values.Length) return oidPath;
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: goto oid_2_42_3_0;
|
||||
case 1: return $"{oidPath}/[Patient schemes]";
|
||||
case 2: return $"{oidPath}/[Medical staff schemes]";
|
||||
case 3: return $"{oidPath}/[Observer schemes]";
|
||||
case 4: return $"{oidPath}/[Pharmaceutical schemes]";
|
||||
case 5: return $"{oidPath}/[Laboratory schemes]";
|
||||
case 6: return $"{oidPath}/[Drug manufacturer schemes]";
|
||||
case 7: return $"{oidPath}/[Medical device schemes]";
|
||||
case 8: return $"{oidPath}/[Medical software schemes]";
|
||||
case 9: return $"{oidPath}/[Medical insurance schemes]";
|
||||
case 10: return $"{oidPath}/[Medical record schemes]";
|
||||
default: return $"{oidPath}/{values[index - 1]}";
|
||||
}
|
||||
|
||||
// obj-cat, telehealth, e-health-protocol, th
|
||||
#region 2.42.3.0.*
|
||||
|
||||
oid_2_42_3_0:
|
||||
|
||||
oidPath += "/Modules";
|
||||
if (index == values.Length) return oidPath;
|
||||
switch (values[index++])
|
||||
{
|
||||
case 0: goto oid_2_42_3_0_0;
|
||||
case 1: goto oid_2_42_3_0_1;
|
||||
case 2: goto oid_2_42_3_0_2;
|
||||
case 3: goto oid_2_42_3_0_3;
|
||||
case 4: goto oid_2_42_3_0_4;
|
||||
case 5: goto oid_2_42_3_0_5;
|
||||
default: return $"{oidPath}/{values[index - 1]}";
|
||||
}
|
||||
|
||||
// identification
|
||||
#region 2.42.3.0.0.*
|
||||
|
||||
oid_2_42_3_0_0:
|
||||
|
||||
oidPath += "/Identification";
|
||||
if (index == values.Length) return oidPath;
|
||||
return values[index++] switch
|
||||
{
|
||||
1 => $"{oidPath}/Version1",
|
||||
_ => $"{oidPath}/{values[index - 1]}",
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
// set-up
|
||||
#region 2.42.3.0.1.*
|
||||
|
||||
oid_2_42_3_0_1:
|
||||
|
||||
oidPath += "/Setup";
|
||||
if (index == values.Length) return oidPath;
|
||||
return values[index++] switch
|
||||
{
|
||||
1 => $"{oidPath}/Version1",
|
||||
_ => $"{oidPath}/{values[index - 1]}",
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
// send-and-ack
|
||||
#region 2.42.3.0.2.*
|
||||
|
||||
oid_2_42_3_0_2:
|
||||
|
||||
oidPath += "/Send-and-ack";
|
||||
if (index == values.Length) return oidPath;
|
||||
return values[index++] switch
|
||||
{
|
||||
1 => $"{oidPath}/Version1",
|
||||
_ => $"{oidPath}/{values[index - 1]}",
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
// command-response
|
||||
#region 2.42.3.0.3.*
|
||||
|
||||
oid_2_42_3_0_3:
|
||||
|
||||
oidPath += "/Command-response";
|
||||
if (index == values.Length) return oidPath;
|
||||
return values[index++] switch
|
||||
{
|
||||
1 => $"{oidPath}/Version1",
|
||||
_ => $"{oidPath}/{values[index - 1]}",
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
// quantity-and-units
|
||||
#region 2.42.3.0.4.*
|
||||
|
||||
oid_2_42_3_0_4:
|
||||
|
||||
oidPath += "/Quantities_And_Units";
|
||||
if (index == values.Length) return oidPath;
|
||||
return values[index++] switch
|
||||
{
|
||||
1 => $"{oidPath}/Version1",
|
||||
_ => $"{oidPath}/{values[index - 1]}",
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
// examples
|
||||
#region 2.42.3.0.5.*
|
||||
|
||||
oid_2_42_3_0_5:
|
||||
|
||||
oidPath += "/Examples";
|
||||
if (index == values.Length) return oidPath;
|
||||
return values[index++] switch
|
||||
{
|
||||
0 => $"{oidPath}/Command_Response",
|
||||
1 => $"{oidPath}/Data_Message",
|
||||
_ => $"{oidPath}/{values[index - 1]}",
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
// cybersecurity
|
||||
#region 2.48.*
|
||||
|
||||
oid_2_48:
|
||||
|
||||
oidPath += "/Cybersecurity";
|
||||
if (index == values.Length) return oidPath;
|
||||
return values[index++] switch
|
||||
{
|
||||
1 => $"{oidPath}/Country",
|
||||
2 => $"{oidPath}/International-Org",
|
||||
_ => $"{oidPath}/{values[index - 1]}",
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
// alerting
|
||||
#region 2.49.*
|
||||
|
||||
oid_2_49:
|
||||
|
||||
oidPath += "/Alerting";
|
||||
if (index == values.Length) return oidPath;
|
||||
return values[index++] switch
|
||||
{
|
||||
0 => $"{oidPath}/WMO",
|
||||
_ => $"{oidPath}/{values[index - 1]}",
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ namespace SabreTools.ASN1
|
||||
int firstNode = Math.DivRem(data[0], 40, out int secondNode);
|
||||
|
||||
// Create a list for all nodes
|
||||
List<ulong> nodes = new List<ulong> { (ulong)firstNode, (ulong)secondNode };
|
||||
List<ulong> nodes = [(ulong)firstNode, (ulong)secondNode];
|
||||
|
||||
// All other nodes are encoded uniquely
|
||||
int offset = 1;
|
||||
@@ -65,7 +65,7 @@ namespace SabreTools.ASN1
|
||||
nodes.Add(dotValue);
|
||||
}
|
||||
|
||||
return nodes.ToArray();
|
||||
return [.. nodes];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.ASN1
|
||||
{
|
||||
/// <summary>
|
||||
@@ -16,7 +18,8 @@ namespace SabreTools.ASN1
|
||||
if (values == null || values.Length == 0)
|
||||
return null;
|
||||
|
||||
return string.Join(".", values);
|
||||
var stringValues = Array.ConvertAll(values, v => v.ToString());
|
||||
return string.Join(".", [.. stringValues]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
39
SabreTools.ASN1/SabreTools.ASN1.csproj
Normal file
39
SabreTools.ASN1/SabreTools.ASN1.csproj
Normal file
@@ -0,0 +1,39 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Assembly Properties -->
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>1.6.4</Version>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski</Authors>
|
||||
<Description>Serialization and deserialization helpers for various types</Description>
|
||||
<Copyright>Copyright (c) Matt Nadareski 2022-2024</Copyright>
|
||||
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<RepositoryUrl>https://github.com/SabreTools/SabreTools.ASN1</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageTags>asn asn1 dot oid</PackageTags>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<InternalsVisibleTo Include="SabreTools.ASN1.Test" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="../README.md" Pack="true" PackagePath="" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NetLegacySupport.Numerics" Version="1.0.1" Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`))" />
|
||||
<PackageReference Include="SabreTools.IO" Version="1.7.5" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
using SabreTools.IO;
|
||||
using SabreTools.IO.Extensions;
|
||||
|
||||
namespace SabreTools.ASN1
|
||||
{
|
||||
@@ -27,6 +27,16 @@ namespace SabreTools.ASN1
|
||||
/// </summary>
|
||||
public object? Value { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Manual constructor
|
||||
/// </summary>
|
||||
public TypeLengthValue(ASN1Type type, ulong length, object? value)
|
||||
{
|
||||
Type = type;
|
||||
Length = length;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from the source data array at an index
|
||||
/// </summary>
|
||||
@@ -34,34 +44,26 @@ namespace SabreTools.ASN1
|
||||
/// <param name="index">Index within the array to read at</param>
|
||||
public TypeLengthValue(byte[] data, ref int index)
|
||||
{
|
||||
// Get the type and modifiers
|
||||
this.Type = (ASN1Type)data[index++];
|
||||
// If the data is invalid
|
||||
if (data.Length == 0)
|
||||
throw new InvalidDataException(nameof(data));
|
||||
if (index < 0 || index >= data.Length)
|
||||
throw new IndexOutOfRangeException(nameof(index));
|
||||
|
||||
// If we have an end indicator, we just return
|
||||
if (this.Type == ASN1Type.V_ASN1_EOC)
|
||||
return;
|
||||
using var stream = new MemoryStream(data);
|
||||
stream.Seek(index, SeekOrigin.Begin);
|
||||
if (!Parse(stream))
|
||||
throw new InvalidDataException(nameof(data));
|
||||
}
|
||||
|
||||
// Get the length of the value
|
||||
this.Length = ReadLength(data, ref index);
|
||||
|
||||
// Read the value
|
||||
if (this.Type.HasFlag(ASN1Type.V_ASN1_CONSTRUCTED))
|
||||
{
|
||||
var valueList = new List<TypeLengthValue>();
|
||||
|
||||
int currentIndex = index;
|
||||
while (index < currentIndex + (int)this.Length)
|
||||
{
|
||||
valueList.Add(new TypeLengthValue(data, ref index));
|
||||
}
|
||||
|
||||
this.Value = valueList.ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Get more granular based on type
|
||||
this.Value = data.ReadBytes(ref index, (int)this.Length);
|
||||
}
|
||||
/// <summary>
|
||||
/// Read from the source data stream
|
||||
/// </summary>
|
||||
/// <param name="data">Stream representing data to read</param>
|
||||
public TypeLengthValue(Stream data)
|
||||
{
|
||||
if (!Parse(data))
|
||||
throw new InvalidDataException(nameof(data));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -72,30 +74,29 @@ namespace SabreTools.ASN1
|
||||
public string Format(int paddingLevel = 0)
|
||||
{
|
||||
// Create the left-padding string
|
||||
string padding = new string(' ', paddingLevel);
|
||||
|
||||
// If we have an invalid item
|
||||
if (this.Type == 0)
|
||||
return $"{padding}UNKNOWN TYPE";
|
||||
string padding = new(' ', paddingLevel);
|
||||
|
||||
// Create the string builder
|
||||
StringBuilder formatBuilder = new StringBuilder();
|
||||
var formatBuilder = new StringBuilder();
|
||||
|
||||
// Append the type
|
||||
formatBuilder.Append($"{padding}Type: {this.Type}");
|
||||
if (this.Type == ASN1Type.V_ASN1_EOC)
|
||||
formatBuilder.Append($"{padding}Type: {Type}");
|
||||
if (Type == ASN1Type.V_ASN1_EOC)
|
||||
return formatBuilder.ToString();
|
||||
|
||||
// Append the length
|
||||
formatBuilder.Append($", Length: {this.Length}");
|
||||
if (this.Length == 0)
|
||||
formatBuilder.Append($", Length: {Length}");
|
||||
if (Length == 0)
|
||||
return formatBuilder.ToString();
|
||||
|
||||
// If we have a constructed type
|
||||
if (this.Type.HasFlag(ASN1Type.V_ASN1_CONSTRUCTED))
|
||||
#if NET20 || NET35
|
||||
if ((Type & ASN1Type.V_ASN1_CONSTRUCTED) != 0)
|
||||
#else
|
||||
if (Type.HasFlag(ASN1Type.V_ASN1_CONSTRUCTED))
|
||||
#endif
|
||||
{
|
||||
var valueAsObjectArray = this.Value as TypeLengthValue[];
|
||||
if (valueAsObjectArray == null)
|
||||
if (Value is not TypeLengthValue[] valueAsObjectArray)
|
||||
{
|
||||
formatBuilder.Append(", Value: [INVALID DATA TYPE]");
|
||||
return formatBuilder.ToString();
|
||||
@@ -113,29 +114,35 @@ namespace SabreTools.ASN1
|
||||
}
|
||||
|
||||
// Get the value as a byte array
|
||||
byte[]? valueAsByteArray = this.Value as byte[];
|
||||
if (valueAsByteArray == null)
|
||||
if (Value is not byte[] valueAsByteArray)
|
||||
{
|
||||
formatBuilder.Append(", Value: [INVALID DATA TYPE]");
|
||||
return formatBuilder.ToString();
|
||||
}
|
||||
else if (valueAsByteArray.Length == 0)
|
||||
{
|
||||
formatBuilder.Append(", Value: [NO DATA]");
|
||||
return formatBuilder.ToString();
|
||||
}
|
||||
|
||||
// If we have a primitive type
|
||||
switch (this.Type)
|
||||
switch (Type)
|
||||
{
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-boolean"/>
|
||||
case ASN1Type.V_ASN1_BOOLEAN:
|
||||
if (this.Length > 1 || valueAsByteArray.Length > 1)
|
||||
if (Length > 1)
|
||||
formatBuilder.Append($" [Expected length of 1]");
|
||||
else if (valueAsByteArray.Length > 1)
|
||||
formatBuilder.Append($" [Expected value length of 1]");
|
||||
|
||||
bool booleanValue = valueAsByteArray[0] == 0x00 ? false : true;
|
||||
bool booleanValue = valueAsByteArray[0] != 0x00;
|
||||
formatBuilder.Append($", Value: {booleanValue}");
|
||||
break;
|
||||
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-integer"/>
|
||||
case ASN1Type.V_ASN1_INTEGER:
|
||||
Array.Reverse(valueAsByteArray);
|
||||
BigInteger integerValue = new BigInteger(valueAsByteArray);
|
||||
var integerValue = new BigInteger(valueAsByteArray);
|
||||
formatBuilder.Append($", Value: {integerValue}");
|
||||
break;
|
||||
|
||||
@@ -143,7 +150,10 @@ namespace SabreTools.ASN1
|
||||
case ASN1Type.V_ASN1_BIT_STRING:
|
||||
// TODO: Read into a BitArray and print that out instead?
|
||||
int unusedBits = valueAsByteArray[0];
|
||||
formatBuilder.Append($", Value with {unusedBits} unused bits: {BitConverter.ToString(valueAsByteArray.Skip(1).ToArray()).Replace('-', ' ')}");
|
||||
if (unusedBits == 0)
|
||||
formatBuilder.Append($", Value with {unusedBits} unused bits");
|
||||
else
|
||||
formatBuilder.Append($", Value with {unusedBits} unused bits: {BitConverter.ToString(valueAsByteArray, 1).Replace('-', ' ')}");
|
||||
break;
|
||||
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-octet-string"/>
|
||||
@@ -155,7 +165,7 @@ namespace SabreTools.ASN1
|
||||
/// <see cref="http://snmpsharpnet.com/index.php/2009/03/02/ber-encoding-and-decoding-oid-values/"/>
|
||||
case ASN1Type.V_ASN1_OBJECT:
|
||||
// Derive array of values
|
||||
ulong[] objectNodes = ObjectIdentifier.ParseDERIntoArray(valueAsByteArray, this.Length);
|
||||
ulong[] objectNodes = ObjectIdentifier.ParseDERIntoArray(valueAsByteArray, Length);
|
||||
|
||||
// Append the dot and modified OID-IRI notations
|
||||
string? dotNotationString = ObjectIdentifier.ParseOIDToDotNotation(objectNodes);
|
||||
@@ -186,7 +196,7 @@ namespace SabreTools.ASN1
|
||||
case ASN1Type.V_ASN1_UTCTIME:
|
||||
string utctimeString = Encoding.ASCII.GetString(valueAsByteArray);
|
||||
if (DateTime.TryParse(utctimeString, out DateTime utctimeDateTime))
|
||||
formatBuilder.Append($", Value: {utctimeDateTime}");
|
||||
formatBuilder.Append($", Value: {utctimeDateTime:yyyy-MM-dd HH:mm:ss}");
|
||||
else
|
||||
formatBuilder.Append($", Value: {utctimeString}");
|
||||
break;
|
||||
@@ -197,11 +207,7 @@ namespace SabreTools.ASN1
|
||||
break;
|
||||
|
||||
default:
|
||||
#if NET40 || NET452
|
||||
formatBuilder.Append($", Value (Unknown Format): {BitConverter.ToString(this.Value as byte[] ?? new byte[0]).Replace('-', ' ')}");
|
||||
#else
|
||||
formatBuilder.Append($", Value (Unknown Format): {BitConverter.ToString(this.Value as byte[] ?? Array.Empty<byte>()).Replace('-', ' ')}");
|
||||
#endif
|
||||
formatBuilder.Append($", Value: {BitConverter.ToString(valueAsByteArray).Replace('-', ' ')}");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -209,20 +215,70 @@ namespace SabreTools.ASN1
|
||||
return formatBuilder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a stream into TLV data
|
||||
/// </summary>
|
||||
/// <param name="data">Stream representing data to read</param>
|
||||
/// <returns>Indication if parsing was successful</returns>
|
||||
private bool Parse(Stream data)
|
||||
{
|
||||
// If the data is invalid
|
||||
if (data.Length == 0 || !data.CanRead)
|
||||
return false;
|
||||
if (data.Position < 0 || data.Position >= data.Length)
|
||||
throw new IndexOutOfRangeException(nameof(data));
|
||||
|
||||
// Get the type and modifiers
|
||||
Type = (ASN1Type)data.ReadByteValue();
|
||||
|
||||
// If we have an end indicator, we just return
|
||||
if (Type == ASN1Type.V_ASN1_EOC)
|
||||
return true;
|
||||
|
||||
// Get the length of the value
|
||||
Length = ReadLength(data);
|
||||
|
||||
// Read the value
|
||||
#if NET20 || NET35
|
||||
if ((Type & ASN1Type.V_ASN1_CONSTRUCTED) != 0)
|
||||
#else
|
||||
if (Type.HasFlag(ASN1Type.V_ASN1_CONSTRUCTED))
|
||||
#endif
|
||||
{
|
||||
var valueList = new List<TypeLengthValue>();
|
||||
|
||||
long currentIndex = data.Position;
|
||||
while (data.Position < currentIndex + (long)Length)
|
||||
{
|
||||
valueList.Add(new TypeLengthValue(data));
|
||||
}
|
||||
|
||||
Value = valueList.ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Get more granular based on type
|
||||
Value = data.ReadBytes((int)Length);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the length field for a type
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array representing data to read</param>
|
||||
/// <param name="index">Index within the array to read at</param>
|
||||
/// <param name="data">Stream representing data to read</param>
|
||||
/// <returns>The length value read from the array</returns>
|
||||
private static ulong ReadLength(byte[] data, ref int index)
|
||||
private static ulong ReadLength(Stream data)
|
||||
{
|
||||
// If we have invalid data, throw an exception
|
||||
if (data == null || index < 0 && index >= data.Length)
|
||||
throw new ArgumentException();
|
||||
// If the data is invalid
|
||||
if (data.Length == 0 || !data.CanRead)
|
||||
throw new InvalidDataException(nameof(data));
|
||||
if (data.Position < 0 || data.Position >= data.Length)
|
||||
throw new IndexOutOfRangeException(nameof(data));
|
||||
|
||||
// Read the first byte, assuming it's the length
|
||||
byte length = data[index++];
|
||||
byte length = data.ReadByteValue();
|
||||
|
||||
// If the bit 7 is not set, then use the value as it is
|
||||
if ((length & 0x80) == 0)
|
||||
@@ -230,36 +286,48 @@ namespace SabreTools.ASN1
|
||||
|
||||
// Otherwise, use the value as the number of remaining bytes to read
|
||||
int bytesToRead = length & ~0x80;
|
||||
byte[]? bytesRead = data.ReadBytes(ref index, bytesToRead);
|
||||
if (bytesRead == null)
|
||||
throw new InvalidOperationException();
|
||||
|
||||
// TODO: Write extensions to read big-endian
|
||||
|
||||
// Reverse the bytes to be in big-endian order
|
||||
Array.Reverse(bytesRead);
|
||||
|
||||
switch (bytesRead.Length)
|
||||
// Assemble the length based on byte count
|
||||
ulong fullLength = 0;
|
||||
switch (bytesToRead)
|
||||
{
|
||||
case 1:
|
||||
return bytesRead[0];
|
||||
case 2:
|
||||
return BitConverter.ToUInt16(bytesRead, 0);
|
||||
case 3:
|
||||
Array.Resize(ref bytesRead, 4);
|
||||
case 8:
|
||||
fullLength |= data.ReadByteValue();
|
||||
fullLength <<= 8;
|
||||
goto case 7;
|
||||
case 7:
|
||||
fullLength |= data.ReadByteValue();
|
||||
fullLength <<= 8;
|
||||
goto case 6;
|
||||
case 6:
|
||||
fullLength |= data.ReadByteValue();
|
||||
fullLength <<= 8;
|
||||
goto case 5;
|
||||
case 5:
|
||||
fullLength |= data.ReadByteValue();
|
||||
fullLength <<= 8;
|
||||
goto case 4;
|
||||
case 4:
|
||||
return BitConverter.ToUInt32(bytesRead, 0);
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
Array.Resize(ref bytesRead, 8);
|
||||
goto case 8;
|
||||
case 8:
|
||||
return BitConverter.ToUInt64(bytesRead, 0);
|
||||
fullLength |= data.ReadByteValue();
|
||||
fullLength <<= 8;
|
||||
goto case 3;
|
||||
case 3:
|
||||
fullLength |= data.ReadByteValue();
|
||||
fullLength <<= 8;
|
||||
goto case 2;
|
||||
case 2:
|
||||
fullLength |= data.ReadByteValue();
|
||||
fullLength <<= 8;
|
||||
goto case 1;
|
||||
case 1:
|
||||
fullLength |= data.ReadByteValue();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return fullLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
36
publish-nix.sh
Executable file
36
publish-nix.sh
Executable file
@@ -0,0 +1,36 @@
|
||||
#! /bin/bash
|
||||
|
||||
# This batch file assumes the following:
|
||||
# - .NET 9.0 (or newer) SDK is installed and in PATH
|
||||
#
|
||||
# If any of these are not satisfied, the operation may fail
|
||||
# in an unpredictable way and result in an incomplete output.
|
||||
|
||||
# Optional parameters
|
||||
NO_BUILD=false
|
||||
while getopts "b" OPTION
|
||||
do
|
||||
case $OPTION in
|
||||
b)
|
||||
NO_BUILD=true
|
||||
;;
|
||||
*)
|
||||
echo "Invalid option provided"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Set the current directory as a variable
|
||||
BUILD_FOLDER=$PWD
|
||||
|
||||
# Only build if requested
|
||||
if [ $NO_BUILD = false ]
|
||||
then
|
||||
# Restore Nuget packages for all builds
|
||||
echo "Restoring Nuget packages"
|
||||
dotnet restore
|
||||
|
||||
# Create Nuget Package
|
||||
dotnet pack SabreTools.ASN1/SabreTools.ASN1.csproj --output $BUILD_FOLDER
|
||||
fi
|
||||
26
publish-win.ps1
Normal file
26
publish-win.ps1
Normal file
@@ -0,0 +1,26 @@
|
||||
# This batch file assumes the following:
|
||||
# - .NET 9.0 (or newer) SDK is installed and in PATH
|
||||
#
|
||||
# If any of these are not satisfied, the operation may fail
|
||||
# in an unpredictable way and result in an incomplete output.
|
||||
|
||||
# Optional parameters
|
||||
param(
|
||||
[Parameter(Mandatory = $false)]
|
||||
[Alias("NoBuild")]
|
||||
[switch]$NO_BUILD
|
||||
)
|
||||
|
||||
# Set the current directory as a variable
|
||||
$BUILD_FOLDER = $PSScriptRoot
|
||||
|
||||
# Only build if requested
|
||||
if (!$NO_BUILD.IsPresent)
|
||||
{
|
||||
# Restore Nuget packages for all builds
|
||||
Write-Host "Restoring Nuget packages"
|
||||
dotnet restore
|
||||
|
||||
# Create Nuget Package
|
||||
dotnet pack SabreTools.ASN1\SabreTools.ASN1.csproj --output $BUILD_FOLDER
|
||||
}
|
||||
Reference in New Issue
Block a user