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.TryReadPrimitiveOctetString(out _, Asn1Tag.Null)); AssertExtensions.Throws <ArgumentException>( "expectedTag", () => reader.TryReadOctetString(output, out _, Asn1Tag.Null)); AssertExtensions.Throws <ArgumentException>( "expectedTag", () => reader.ReadOctetString(Asn1Tag.Null)); Assert.True(reader.HasData, "HasData after bad universal tag"); Assert.Throws <AsnContentException>(() => reader.TryReadPrimitiveOctetString(out _)); Assert.Throws <AsnContentException>(() => reader.TryReadOctetString(output, out _)); Assert.Throws <AsnContentException>(() => reader.ReadOctetString()); Assert.True(reader.HasData, "HasData after default tag"); Assert.Throws <AsnContentException>(() => reader.TryReadPrimitiveOctetString(out _, wrongTag1)); Assert.Throws <AsnContentException>(() => reader.TryReadOctetString(output, out _, wrongTag1)); Assert.Throws <AsnContentException>(() => reader.ReadOctetString(wrongTag1)); Assert.True(reader.HasData, "HasData after wrong custom class"); Assert.Throws <AsnContentException>(() => reader.TryReadPrimitiveOctetString(out _, wrongTag2)); Assert.Throws <AsnContentException>(() => reader.TryReadOctetString(output, out _, wrongTag2)); Assert.Throws <AsnContentException>(() => reader.ReadOctetString(wrongTag2)); Assert.True(reader.HasData, "HasData after wrong custom tag value"); Assert.True(reader.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> value, correctTag)); Assert.Equal("0080", value.ByteArrayToHex()); Assert.False(reader.HasData, "HasData after reading value"); reader = new AsnReader(inputData, ruleSet); Assert.True(reader.TryReadOctetString(output.AsSpan(1), out int written, correctTag)); Assert.Equal("0080", output.AsSpan(1, written).ByteArrayToHex()); Assert.False(reader.HasData, "HasData after reading value"); reader = new AsnReader(inputData, ruleSet); byte[] output2 = reader.ReadOctetString(correctTag); Assert.Equal("0080", output2.ByteArrayToHex()); Assert.False(reader.HasData, "HasData after reading value"); }
public static void TryCopyOctetStringBytes_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 1061, and StackOverflowed with 1062. int end = dataBytes.Length / 2; // UNIVERSAL OCTET STRING [Constructed] const byte Tag = 0x20 | (byte)UniversalTagNumber.OctetString; 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; Assert.True(reader.TryReadOctetString(Span <byte> .Empty, out bytesWritten)); Assert.Equal(0, bytesWritten); reader = new AsnReader(dataBytes, AsnEncodingRules.BER); byte[] output2 = reader.ReadOctetString(); // It's Same (ReferenceEqual) on .NET Core, but just Equal on .NET Framework Assert.Equal(Array.Empty <byte>(), output2); }
internal static ReadOnlyMemory <byte> GetContent( ReadOnlyMemory <byte> wrappedContent, string contentType) { // Read the input. // // PKCS7's id-data is written in both PKCS#7 and CMS as an OCTET STRING wrapping // the arbitrary bytes, so the OCTET STRING must always be present. // // For other types, CMS says to always write an OCTET STRING, and to put the properly // encoded data within it. // PKCS#7 originally ommitted the OCTET STRING wrapper for this model, so this is the // dynamic adapter. // // See https://tools.ietf.org/html/rfc5652#section-5.2.1 byte[]? rented = null; int bytesWritten = 0; try { AsnReader reader = new AsnReader(wrappedContent, AsnEncodingRules.BER); if (reader.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> inner)) { return(inner); } rented = CryptoPool.Rent(wrappedContent.Length); if (!reader.TryReadOctetString(rented, out bytesWritten)) { Debug.Fail($"TryCopyOctetStringBytes failed with an array larger than the encoded value"); throw new CryptographicException(); } return(rented.AsSpan(0, bytesWritten).ToArray()); } catch (Exception) when(contentType != Oids.Pkcs7Data) { } catch (AsnContentException e) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); } finally { if (rented != null) { CryptoPool.Return(rented, bytesWritten); } } // PKCS#7 encoding for something other than id-data. Debug.Assert(contentType != Oids.Pkcs7Data); return(wrappedContent); }
public static void TryReadOctetStringBytes_Fails(AsnEncodingRules ruleSet, string inputHex) { byte[] inputData = inputHex.HexToByteArray(); AsnReader reader = new AsnReader(inputData, ruleSet); bool didRead = reader.TryReadOctetString( Span <byte> .Empty, out int bytesWritten); Assert.False(didRead, "reader.TryReadOctetString"); Assert.Equal(0, bytesWritten); }
private static void TryReadOctetStringBytes_Throws_Helper( AsnEncodingRules ruleSet, byte[] input) { AsnReader reader = new AsnReader(input, ruleSet); Assert.Throws <AsnContentException>( () => { reader.TryReadOctetString( Span <byte> .Empty, out int bytesWritten); }); }
public static void TryReadOctetStringBytes_Success( AsnEncodingRules ruleSet, string inputHex, string expectedHex) { byte[] inputData = inputHex.HexToByteArray(); byte[] output = new byte[expectedHex.Length / 2]; AsnReader reader = new AsnReader(inputData, ruleSet); bool didRead = reader.TryReadOctetString( output, out int bytesWritten); Assert.True(didRead, "reader.TryReadOctetString"); Assert.Equal(expectedHex, output.AsSpan(0, bytesWritten).ByteArrayToHex()); reader = new AsnReader(inputData, ruleSet); byte[] output2 = reader.ReadOctetString(); Assert.Equal(output, output2); }
public static void TryCopyOctetStringBytes_Success_CER_MaxPrimitiveLength() { // CER says that the maximum encoding length for an OctetString primitive // is 1000. // // So we need 04 [1000] { 1000 anythings } // 1000 => 0x3E8, so the length encoding is 82 03 E8. // 1000 + 3 + 1 == 1004 byte[] input = new byte[1004]; input[0] = 0x04; input[1] = 0x82; input[2] = 0x03; input[3] = 0xE8; // Content input[4] = 0x02; input[5] = 0xA0; input[1002] = 0xA5; input[1003] = 0xFC; byte[] output = new byte[1000]; AsnReader reader = new AsnReader(input, AsnEncodingRules.CER); bool success = reader.TryReadOctetString( output, out int bytesWritten); Assert.True(success, "reader.TryReadOctetString"); Assert.Equal(1000, bytesWritten); Assert.Equal( input.AsSpan(4).ByteArrayToHex(), output.ByteArrayToHex()); reader = new AsnReader(input, AsnEncodingRules.CER); byte[] output2 = reader.ReadOctetString(); Assert.Equal(output, output2); }
public static void TryReadPrimitiveOctetStringBytes_Throws_CER_TooLong() { // CER says that the maximum encoding length for an OctetString primitive // is 1000. // // So we need 04 [1001] { 1001 0x00s } // 1001 => 0x3E9, so the length encoding is 82 03 E9. // 1001 + 3 + 1 == 1005 byte[] input = new byte[1005]; input[0] = 0x04; input[1] = 0x82; input[2] = 0x03; input[3] = 0xE9; AsnReader reader = new AsnReader(input, AsnEncodingRules.CER); Assert.Throws <AsnContentException>( () => reader.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> contents)); Assert.Throws <AsnContentException>( () => reader.TryReadOctetString(new byte[input.Length], out _)); Assert.Throws <AsnContentException>(() => reader.ReadOctetString()); }
internal static AlgorithmIdentifier ToPresentationObject(this AlgorithmIdentifierAsn asn) { int keyLength; byte[] parameters = Array.Empty <byte>(); switch (asn.Algorithm) { case Oids.Rc2Cbc: { if (asn.Parameters == null) { keyLength = 0; break; } Rc2CbcParameters rc2Params = Rc2CbcParameters.Decode( asn.Parameters.Value, AsnEncodingRules.BER); int keySize = rc2Params.GetEffectiveKeyBits(); // These are the only values .NET Framework would set. switch (keySize) { case 40: case 56: case 64: case 128: keyLength = keySize; break; default: keyLength = 0; break; } break; } case Oids.Rc4: { if (asn.Parameters == null) { keyLength = 0; break; } int saltLen = 0; try { AsnReader reader = new AsnReader(asn.Parameters.Value, AsnEncodingRules.BER); // DER NULL is considered the same as not present. // No call to ReadNull() is necessary because the serializer already verified that // there's no data after the [AnyValue] value. if (reader.PeekTag() != Asn1Tag.Null) { if (reader.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> contents)) { saltLen = contents.Length; } else { Span <byte> salt = stackalloc byte[KeyLengths.Rc4Max_128Bit / 8]; if (!reader.TryReadOctetString(salt, out saltLen)) { throw new CryptographicException(); } } } } catch (AsnContentException e) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); } keyLength = KeyLengths.Rc4Max_128Bit - 8 * saltLen; break; } case Oids.DesCbc: keyLength = KeyLengths.Des_64Bit; break; case Oids.TripleDesCbc: keyLength = KeyLengths.TripleDes_192Bit; break; case Oids.RsaOaep when !asn.HasNullEquivalentParameters(): keyLength = 0; Debug.Assert(asn.Parameters != null); parameters = asn.Parameters.Value.ToArray(); break; default: // .NET Framework doesn't set a keylength for AES, or any other algorithm than the ones // listed here. keyLength = 0; break; } return(new AlgorithmIdentifier(new Oid(asn.Algorithm), keyLength) { Parameters = parameters }); }
public static void TryCopyOctetStringBytes_Success_CER_MinConstructedLength() { // CER says that the maximum encoding length for an OctetString primitive // is 1000, 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]. // // So our smallest constructed form is 1001 bytes, [1000, 1] // // 24 80 (indefinite constructed octet string) // 04 82 03 E9 (primitive octet string, 1000 bytes) // [1000 content bytes] // 04 01 (primitive octet string, 1 byte) // pp // 00 00 (end of contents, 0 bytes) // 1011 total. byte[] input = new byte[1011]; int offset = 0; // CONSTRUCTED OCTET STRING (Indefinite) input[offset++] = 0x24; input[offset++] = 0x80; // OCTET STRING (1000) input[offset++] = 0x04; input[offset++] = 0x82; input[offset++] = 0x03; input[offset++] = 0xE8; // Primitive 1: (55 A0 :: A5 FC) (1000) input[offset++] = 0x55; input[offset] = 0xA0; offset += 997; input[offset++] = 0xA5; input[offset++] = 0xFC; // OCTET STRING (1) input[offset++] = 0x04; input[offset++] = 0x01; // Primitive 2: One more byte input[offset] = 0xF7; byte[] expected = new byte[1001]; offset = 0; expected[offset++] = 0x55; expected[offset] = 0xA0; offset += 997; expected[offset++] = 0xA5; expected[offset++] = 0xFC; expected[offset] = 0xF7; byte[] output = new byte[1001]; AsnReader reader = new AsnReader(input, AsnEncodingRules.CER); bool success = reader.TryReadOctetString( output, out int bytesWritten); Assert.True(success, "reader.TryReadOctetString"); Assert.Equal(1001, bytesWritten); Assert.Equal( expected.ByteArrayToHex(), output.ByteArrayToHex()); reader = new AsnReader(input, AsnEncodingRules.CER); byte[] output2 = reader.ReadOctetString(); Assert.Equal(output, output2); }