public static void TryReadPrimitiveBitStringValue_Throws( string description, AsnEncodingRules ruleSet, string inputHex) { _ = description; byte[] inputData = inputHex.HexToByteArray(); AsnReader reader = new AsnReader(inputData, ruleSet); Assert.Throws <AsnContentException>( () => { reader.TryReadPrimitiveBitString( out int unusedBitCount, out ReadOnlyMemory <byte> contents); }); Assert.Throws <AsnContentException>( () => { reader.TryReadBitString( new byte[inputData.Length], out int unusedBitCount, out int written); }); Assert.Throws <AsnContentException>( () => reader.ReadBitString(out int unusedBitCount)); }
private static void ReadEcPublicKey(AsnEncodingRules ruleSet, byte[] inputData) { AsnReader mainReader = new AsnReader(inputData, ruleSet); AsnReader spkiReader = mainReader.ReadSequence(); Assert.False(mainReader.HasData, "mainReader.HasData after reading SPKI"); AsnReader algorithmReader = spkiReader.ReadSequence(); Assert.True(spkiReader.HasData, "spkiReader.HasData after reading algorithm"); ReadOnlyMemory <byte> publicKeyValue; int unusedBitCount; if (!spkiReader.TryReadPrimitiveBitString(out unusedBitCount, out publicKeyValue)) { // The correct answer is 65 bytes. for (int i = 10; ; i *= 2) { byte[] buf = new byte[i]; if (spkiReader.TryReadBitString(buf, out unusedBitCount, out int bytesWritten)) { publicKeyValue = new ReadOnlyMemory <byte>(buf, 0, bytesWritten); break; } } } Assert.False(spkiReader.HasData, "spkiReader.HasData after reading subjectPublicKey"); Assert.True(algorithmReader.HasData, "algorithmReader.HasData before reading"); string algorithmOid = algorithmReader.ReadObjectIdentifier(); Assert.True(algorithmReader.HasData, "algorithmReader.HasData after reading first OID"); Assert.Equal("1.2.840.10045.2.1", algorithmOid); string curveOid = algorithmReader.ReadObjectIdentifier(); Assert.False(algorithmReader.HasData, "algorithmReader.HasData after reading second OID"); Assert.Equal("1.2.840.10045.3.1.7", curveOid); const string PublicKeyValue = "04" + "2363DD131DA65E899A2E63E9E05E50C830D4994662FFE883DB2B9A767DCCABA2" + "F07081B5711BE1DEE90DFC8DE17970C2D937A16CD34581F52B8D59C9E9532D13"; Assert.Equal(PublicKeyValue, publicKeyValue.ByteArrayToHex()); Assert.Equal(0, unusedBitCount); }
public static void TryCopyBitStringBytes_Fails(AsnEncodingRules ruleSet, string inputHex) { byte[] inputData = inputHex.HexToByteArray(); AsnReader reader = new AsnReader(inputData, ruleSet); bool didRead = reader.TryReadBitString( Span <byte> .Empty, out int unusedBitCount, out int bytesWritten); Assert.False(didRead, "reader.TryReadBitString"); Assert.Equal(0, unusedBitCount); Assert.Equal(0, bytesWritten); }
private static void TryReadBitString_Throws_Helper( AsnEncodingRules ruleSet, byte[] input) { AsnReader reader = new AsnReader(input, ruleSet); Assert.Throws <AsnContentException>( () => { reader.TryReadBitString( Span <byte> .Empty, out int unusedBitCount, out int bytesWritten); }); }
public static void TryCopyBitStringBytes_Success_CER_MaxPrimitiveLength() { // CER says that the maximum encoding length for a BitString primitive is // 1000 (999 value bytes and 1 unused bit count byte). // // So we need 03 [1000] [0x00-0x07] { 998 anythings } [a byte that's legal for the bitmask] // 1000 => 0x3E8, so the length encoding is 82 03 E8. // 1000 + 3 + 1 == 1003 byte[] input = new byte[1004]; input[0] = 0x03; input[1] = 0x82; input[2] = 0x03; input[3] = 0xE8; // Unused bits input[4] = 0x02; // Payload input[5] = 0xA0; input[1002] = 0xA5; input[1003] = 0xFC; byte[] output = new byte[999]; AsnReader reader = new AsnReader(input, AsnEncodingRules.CER); bool success = reader.TryReadBitString( output, out int unusedBitCount, out int bytesWritten); Assert.True(success, "reader.TryReadBitString"); Assert.Equal(input[4], unusedBitCount); Assert.Equal(999, bytesWritten); Assert.Equal( input.AsSpan(5).ByteArrayToHex(), output.ByteArrayToHex()); reader = new AsnReader(input, AsnEncodingRules.CER); byte[] output2 = reader.ReadBitString(out int ubc2); Assert.Equal(unusedBitCount, ubc2); Assert.Equal(output, output2); }
public static void TryCopyBitStringBytes_Success( AsnEncodingRules ruleSet, string inputHex, string expectedHex, int expectedUnusedBitCount) { byte[] inputData = inputHex.HexToByteArray(); byte[] output = new byte[expectedHex.Length / 2]; AsnReader reader = new AsnReader(inputData, ruleSet); bool didRead = reader.TryReadBitString( output, out int unusedBitCount, out int bytesWritten); Assert.True(didRead, "reader.TryReadBitString"); Assert.Equal(expectedUnusedBitCount, unusedBitCount); Assert.Equal(expectedHex, output.AsSpan(0, bytesWritten).ByteArrayToHex()); }
public static void TryCopyBitStringBytes_ExtremelyNested() { byte[] dataBytes = new byte[4 * 16384]; // This will build 2^14 nested indefinite length values. // In the end, none of them contain any content. // // For what it's worth, the initial algorithm succeeded at 1017, and StackOverflowed with 1018. int end = dataBytes.Length / 2; // UNIVERSAL BIT STRING [Constructed] const byte Tag = 0x20 | (byte)UniversalTagNumber.BitString; for (int i = 0; i < end; i += 2) { dataBytes[i] = Tag; // Indefinite length dataBytes[i + 1] = 0x80; } AsnReader reader = new AsnReader(dataBytes, AsnEncodingRules.BER); int bytesWritten; int unusedBitCount; Assert.True( reader.TryReadBitString(Span <byte> .Empty, out unusedBitCount, out bytesWritten)); Assert.Equal(0, bytesWritten); Assert.Equal(0, unusedBitCount); reader = new AsnReader(dataBytes, AsnEncodingRules.BER); byte[] output = reader.ReadBitString(out unusedBitCount); Assert.Equal(0, unusedBitCount); // It's Same (ReferenceEqual) on .NET Core, but just Equal on .NET Framework Assert.Equal(Array.Empty <byte>(), output); }
public static void TryReadPrimitiveBitStringValue_Throws_CER_TooLong() { // CER says that the maximum encoding length for a BitString primitive is // 1000 (999 value bytes and 1 unused bit count byte). // // So we need 03 [1001] { 1001 0x00s } // 1001 => 0x3E9, so the length encoding is 82 03 E9. // 1001 + 3 + 1 == 1005 byte[] input = new byte[1005]; input[0] = 0x03; input[1] = 0x82; input[2] = 0x03; input[3] = 0xE9; AsnReader reader = new AsnReader(input, AsnEncodingRules.CER); Assert.Throws <AsnContentException>( () => { reader.TryReadPrimitiveBitString( out int unusedBitCount, out ReadOnlyMemory <byte> contents); }); Assert.Throws <AsnContentException>( () => { reader.TryReadBitString( new byte[input.Length], out int unusedBitCount, out int written); }); Assert.Throws <AsnContentException>( () => reader.ReadBitString(out int unusedBitCount)); }
public static void ExpectedTag_IgnoresConstructed( AsnEncodingRules ruleSet, string inputHex, TagClass tagClass, int tagValue) { byte[] inputData = inputHex.HexToByteArray(); AsnReader reader = new AsnReader(inputData, ruleSet); Asn1Tag correctConstructed = new Asn1Tag(tagClass, tagValue, true); Asn1Tag correctPrimitive = new Asn1Tag(tagClass, tagValue, false); Assert.True( reader.TryReadPrimitiveBitString( out int ubc1, out ReadOnlyMemory <byte> val1, correctConstructed)); Assert.False(reader.HasData); reader = new AsnReader(inputData, ruleSet); Assert.True( reader.TryReadPrimitiveBitString( out int ubc2, out ReadOnlyMemory <byte> val2, correctPrimitive)); Assert.False(reader.HasData); string val1Hex = val1.ByteArrayToHex(); Assert.Equal(val1Hex, val2.ByteArrayToHex()); Assert.Equal(ubc1, ubc2); reader = new AsnReader(inputData, ruleSet); byte[] output1 = new byte[inputData.Length]; Assert.True(reader.TryReadBitString(output1.AsSpan(1), out ubc1, out int written, correctConstructed)); Assert.Equal(ubc2, ubc1); Assert.Equal(val1Hex, output1.AsSpan(1, written).ByteArrayToHex()); Assert.False(reader.HasData); reader = new AsnReader(inputData, ruleSet); Assert.True(reader.TryReadBitString(output1.AsSpan(2), out ubc1, out written, correctPrimitive)); Assert.Equal(ubc2, ubc1); Assert.Equal(val1Hex, output1.AsSpan(2, written).ByteArrayToHex()); Assert.False(reader.HasData); reader = new AsnReader(inputData, ruleSet); byte[] output2 = reader.ReadBitString(out ubc1, correctConstructed); Assert.Equal(ubc2, ubc1); Assert.Equal(val1Hex, output2.ByteArrayToHex()); Assert.False(reader.HasData); reader = new AsnReader(inputData, ruleSet); byte[] output3 = reader.ReadBitString(out ubc1, correctPrimitive); Assert.Equal(ubc2, ubc1); Assert.Equal(val1Hex, output3.ByteArrayToHex()); Assert.False(reader.HasData); }
public static void TagMustBeCorrect_Custom(AsnEncodingRules ruleSet) { byte[] inputData = { 0x87, 2, 0, 0x80 }; byte[] output = new byte[inputData.Length]; AsnReader reader = new AsnReader(inputData, ruleSet); Asn1Tag wrongTag1 = new Asn1Tag(TagClass.Application, 0); Asn1Tag wrongTag2 = new Asn1Tag(TagClass.ContextSpecific, 1); Asn1Tag correctTag = new Asn1Tag(TagClass.ContextSpecific, 7); AssertExtensions.Throws <ArgumentException>( "expectedTag", () => reader.TryReadPrimitiveBitString(out _, out _, Asn1Tag.Null)); AssertExtensions.Throws <ArgumentException>( "expectedTag", () => reader.TryReadBitString(output, out _, out _, Asn1Tag.Null)); AssertExtensions.Throws <ArgumentException>( "expectedTag", () => reader.ReadBitString(out _, Asn1Tag.Null)); Assert.True(reader.HasData, "HasData after bad universal tag"); Assert.Throws <AsnContentException>(() => reader.TryReadPrimitiveBitString(out _, out _)); Assert.Throws <AsnContentException>(() => reader.TryReadBitString(output, out _, out _)); Assert.Throws <AsnContentException>(() => reader.ReadBitString(out _)); Assert.True(reader.HasData, "HasData after default tag"); Assert.Throws <AsnContentException>(() => reader.TryReadPrimitiveBitString(out _, out _, wrongTag1)); Assert.Throws <AsnContentException>(() => reader.TryReadBitString(output, out _, out _, wrongTag1)); Assert.Throws <AsnContentException>(() => reader.ReadBitString(out _, wrongTag1)); Assert.True(reader.HasData, "HasData after wrong custom class"); Assert.Throws <AsnContentException>(() => reader.TryReadPrimitiveBitString(out _, out _, wrongTag2)); Assert.Throws <AsnContentException>(() => reader.TryReadBitString(output, out _, out _, wrongTag2)); Assert.Throws <AsnContentException>(() => reader.ReadBitString(out _, wrongTag2)); Assert.True(reader.HasData, "HasData after wrong custom tag value"); Assert.True( reader.TryReadPrimitiveBitString( out int unusedBitCount, out ReadOnlyMemory <byte> contents, correctTag)); Assert.Equal("80", contents.ByteArrayToHex()); Assert.Equal(0, unusedBitCount); Assert.False(reader.HasData, "HasData after reading value"); reader = new AsnReader(inputData, ruleSet); Assert.True( reader.TryReadBitString( output.AsSpan(1), out unusedBitCount, out int written, correctTag)); Assert.Equal("80", output.AsSpan(1, written).ByteArrayToHex()); Assert.Equal(0, unusedBitCount); Assert.False(reader.HasData, "HasData after reading value"); reader = new AsnReader(inputData, ruleSet); byte[] output2 = reader.ReadBitString(out unusedBitCount, correctTag); Assert.Equal("80", output2.ByteArrayToHex()); Assert.Equal(0, unusedBitCount); Assert.False(reader.HasData, "HasData after reading value"); }
public static void TryCopyBitStringBytes_Success_CER_MinConstructedLength() { // CER says that the maximum encoding length for a BitString primitive is // 1000 (999 value bytes and 1 unused bit count byte), and that a constructed // form must be used for values greater than 1000 bytes, with segments dividing // up for each thousand [1000, 1000, ..., len%1000]. // // Bit string primitives are one byte of "unused bits" and the rest are payload, // so the minimum constructed payload has total content length 1002: // [1000 (1+999), 2 (1+1)] // // 23 80 (indefinite constructed bit string) // 03 82 03 E9 (primitive bit string, 1000 bytes) // 00 [999 more payload bytes] // 03 02 (primitive bit string, 2 bytes) // uu pp // 00 00 (end of contents, 0 bytes) // 1010 total. byte[] input = new byte[1012]; int offset = 0; // CONSTRUCTED BIT STRING (Indefinite) input[offset++] = 0x23; input[offset++] = 0x80; // BIT STRING (1000) input[offset++] = 0x03; input[offset++] = 0x82; input[offset++] = 0x03; input[offset++] = 0xE8; // Primitive 1: Unused bits MUST be 0. input[offset++] = 0x00; // Payload (A0 :: A5 FC) (999) input[offset] = 0xA0; offset += 997; input[offset++] = 0xA5; input[offset++] = 0xFC; // BIT STRING (2) input[offset++] = 0x03; input[offset++] = 0x02; // Primitive 2: Unused bits 0-7 input[offset++] = 0x3; // Payload (must have the three least significant bits unset) input[offset] = 0b0000_1000; byte[] expected = new byte[1000]; offset = 0; expected[offset] = 0xA0; offset += 997; expected[offset++] = 0xA5; expected[offset++] = 0xFC; expected[offset] = 0b0000_1000; byte[] output = new byte[1000]; AsnReader reader = new AsnReader(input, AsnEncodingRules.CER); bool success = reader.TryReadBitString( output, out int unusedBitCount, out int bytesWritten); Assert.True(success, "reader.TryReadBitString"); Assert.Equal(input[1006], unusedBitCount); Assert.Equal(1000, bytesWritten); Assert.Equal( expected.ByteArrayToHex(), output.ByteArrayToHex()); reader = new AsnReader(input, AsnEncodingRules.CER); byte[] output2 = reader.ReadBitString(out int ubc2); Assert.Equal(unusedBitCount, ubc2); Assert.Equal(output, output2); }