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.TryCopyBitStringBytes(Span <byte> .Empty, out unusedBitCount, out bytesWritten)); Assert.Equal(0, bytesWritten); Assert.Equal(0, 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.TryReadPrimitiveBitStringValue(out unusedBitCount, out publicKeyValue)) { // The correct answer is 65 bytes. for (int i = 10; ; i *= 2) { byte[] buf = new byte[i]; if (spkiReader.TryCopyBitStringBytes(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"); Oid algorithmOid = algorithmReader.ReadObjectIdentifier(); Assert.True(algorithmReader.HasData, "algorithmReader.HasData after reading first OID"); Assert.Equal("1.2.840.10045.2.1", algorithmOid.Value); Oid curveOid = algorithmReader.ReadObjectIdentifier(); Assert.False(algorithmReader.HasData, "algorithmReader.HasData after reading second OID"); Assert.Equal("1.2.840.10045.3.1.7", curveOid.Value); const string PublicKeyValue = "04" + "2363DD131DA65E899A2E63E9E05E50C830D4994662FFE883DB2B9A767DCCABA2" + "F07081B5711BE1DEE90DFC8DE17970C2D937A16CD34581F52B8D59C9E9532D13"; Assert.Equal(PublicKeyValue, publicKeyValue.ByteArrayToHex()); Assert.Equal(0, unusedBitCount); }
public static void TryCopyBitStringBytes_Fails(PublicEncodingRules ruleSet, string inputHex) { byte[] inputData = inputHex.HexToByteArray(); AsnReader reader = new AsnReader(inputData, (AsnEncodingRules)ruleSet); bool didRead = reader.TryCopyBitStringBytes( Span <byte> .Empty, out int unusedBitCount, out int bytesWritten); Assert.False(didRead, "reader.TryCopyBitStringBytes"); Assert.Equal(0, unusedBitCount); Assert.Equal(0, bytesWritten); }
private static void TryCopyBitStringBytes_Throws_Helper( PublicEncodingRules ruleSet, byte[] input) { AsnReader reader = new AsnReader(input, (AsnEncodingRules)ruleSet); Assert.Throws <CryptographicException>( () => { reader.TryCopyBitStringBytes( Span <byte> .Empty, out int unusedBitCount, out int bytesWritten); }); }
public static void TryCopyBitStringBytes_Success( PublicEncodingRules ruleSet, string inputHex, string expectedHex, int expectedUnusedBitCount) { byte[] inputData = inputHex.HexToByteArray(); byte[] output = new byte[expectedHex.Length / 2]; AsnReader reader = new AsnReader(inputData, (AsnEncodingRules)ruleSet); bool didRead = reader.TryCopyBitStringBytes( output, out int unusedBitCount, out int bytesWritten); Assert.True(didRead, "reader.TryCopyBitStringBytes"); Assert.Equal(expectedUnusedBitCount, unusedBitCount); Assert.Equal(expectedHex, output.AsSpan(0, bytesWritten).ByteArrayToHex()); }
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.TryCopyBitStringBytes( output, out int unusedBitCount, out int bytesWritten); Assert.True(success, "reader.TryCopyBitStringBytes"); Assert.Equal(input[4], unusedBitCount); Assert.Equal(999, bytesWritten); Assert.Equal( input.AsSpan(5).ByteArrayToHex(), output.ByteArrayToHex()); }
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.TryCopyBitStringBytes( output, out int unusedBitCount, out int bytesWritten); Assert.True(success, "reader.TryCopyBitStringBytes"); Assert.Equal(input[1006], unusedBitCount); Assert.Equal(1000, bytesWritten); Assert.Equal( expected.ByteArrayToHex(), output.ByteArrayToHex()); }