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 ExpectedTag_IgnoresConstructed( AsnEncodingRules ruleSet, string inputHex, TagClass tagClass, int tagValue) { byte[] inputData = inputHex.HexToByteArray(); AsnReader reader = new AsnReader(inputData, ruleSet); Assert.True( reader.TryReadPrimitiveOctetString( out ReadOnlyMemory <byte> val1, new Asn1Tag(tagClass, tagValue, true))); Assert.False(reader.HasData); reader = new AsnReader(inputData, ruleSet); Assert.True( reader.TryReadPrimitiveOctetString( out ReadOnlyMemory <byte> val2, new Asn1Tag(tagClass, tagValue, false))); Assert.False(reader.HasData); Assert.Equal(val1.ByteArrayToHex(), val2.ByteArrayToHex()); }
public static void TryReadPrimitiveOctetStringBytes_Success_CER_MaxLength() { // 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; // Contents input[4] = 0x02; input[5] = 0xA0; input[1002] = 0xA5; input[1003] = 0xFC; AsnReader reader = new AsnReader(input, AsnEncodingRules.CER); bool success = reader.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> contents); Assert.True(success, "reader.TryReadOctetStringBytes"); Assert.Equal(1000, contents.Length); // Check that it is, in fact, the same memory. No copies with this API. Assert.True( Unsafe.AreSame( ref MemoryMarshal.GetReference(contents.Span), ref input[4])); }
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 TagMustBeCorrect_Universal(AsnEncodingRules ruleSet) { byte[] inputData = { 4, 1, 0x7E }; AsnReader reader = new AsnReader(inputData, ruleSet); AssertExtensions.Throws <ArgumentException>( "expectedTag", () => reader.TryReadPrimitiveOctetString(out _, Asn1Tag.Null)); Assert.True(reader.HasData, "HasData after bad universal tag"); Assert.Throws <AsnContentException>( () => reader.TryReadPrimitiveOctetString(out _, new Asn1Tag(TagClass.ContextSpecific, 0))); Assert.True(reader.HasData, "HasData after wrong tag"); Assert.True(reader.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> value)); Assert.Equal("7E", value.ByteArrayToHex()); Assert.False(reader.HasData, "HasData after read"); }
public static void TryReadPrimitiveOctetStringBytes_Throws( string description, AsnEncodingRules ruleSet, string inputHex) { _ = description; byte[] inputData = inputHex.HexToByteArray(); AsnReader reader = new AsnReader(inputData, ruleSet); Assert.Throws <AsnContentException>( () => reader.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> contents)); }
public static void TryReadPrimitiveOctetStringBytes_Success( AsnEncodingRules ruleSet, int expectedLength, string inputHex) { byte[] inputData = inputHex.HexToByteArray(); AsnReader reader = new AsnReader(inputData, ruleSet); bool didRead = reader.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> contents); Assert.True(didRead, "reader.TryReadOctetStringBytes"); Assert.Equal(expectedLength, contents.Length); }
private static void AssertExtension(AsnReader extensions, string oid, bool critical, int index, byte[] bytes) { AsnReader extension = extensions.ReadSequence(); Assert.Equal(oid, extension.ReadObjectIdentifier()); if (critical) { Assert.True(extension.ReadBoolean(), $"{oid} is critical"); } Assert.True(extension.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> extensionBytes)); AssertRefSame(extensionBytes, ref bytes[index], $"{oid} extension value is at byte {index}"); }
public static void TryReadPrimitiveOctetStringBytes_Fails( string description, AsnEncodingRules ruleSet, string inputHex) { _ = description; byte[] inputData = inputHex.HexToByteArray(); AsnReader reader = new AsnReader(inputData, ruleSet); bool didRead = reader.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> contents); Assert.False(didRead, "reader.TryReadOctetStringBytes"); Assert.Equal(0, contents.Length); }
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()); }
public static void ReadMicrosoftComCert() { byte[] bytes = MicrosoftDotComSslCertBytes; AsnReader fileReader = new AsnReader(bytes, AsnEncodingRules.DER); AsnReader certReader = fileReader.ReadSequence(); Assert.False(fileReader.HasData, "fileReader.HasData"); AsnReader tbsCertReader = certReader.ReadSequence(); AsnReader sigAlgReader = certReader.ReadSequence(); Assert.True( certReader.TryReadPrimitiveBitString( out int unusedBitCount, out ReadOnlyMemory <byte> signature), "certReader.TryReadPrimitiveBitStringValue"); Assert.Equal(0, unusedBitCount); AssertRefSame(signature, ref bytes[1176], "Signature is a ref to bytes[1176]"); Assert.False(certReader.HasData, "certReader.HasData"); AsnReader versionExplicitWrapper = tbsCertReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0)); Assert.True(versionExplicitWrapper.TryReadInt32(out int certVersion)); Assert.Equal(2, certVersion); Assert.False(versionExplicitWrapper.HasData, "versionExplicitWrapper.HasData"); ReadOnlyMemory <byte> serialBytes = tbsCertReader.ReadIntegerBytes(); AssertRefSame(serialBytes, ref bytes[15], "Serial number starts at bytes[15]"); AsnReader tbsSigAlgReader = tbsCertReader.ReadSequence(); Assert.Equal("1.2.840.113549.1.1.11", tbsSigAlgReader.ReadObjectIdentifier()); Assert.True(tbsSigAlgReader.HasData, "tbsSigAlgReader.HasData before ReadNull"); tbsSigAlgReader.ReadNull(); Assert.False(tbsSigAlgReader.HasData, "tbsSigAlgReader.HasData after ReadNull"); AsnReader issuerReader = tbsCertReader.ReadSequence(); Asn1Tag printableString = new Asn1Tag(UniversalTagNumber.PrintableString); AssertRdn(issuerReader, "2.5.4.6", 57, printableString, bytes, "issuer[C]"); AssertRdn(issuerReader, "2.5.4.10", 70, printableString, bytes, "issuer[O]"); AssertRdn(issuerReader, "2.5.4.11", 101, printableString, bytes, "issuer[OU]"); AssertRdn(issuerReader, "2.5.4.3", 134, printableString, bytes, "issuer[CN]"); Assert.False(issuerReader.HasData, "issuerReader.HasData"); AsnReader validityReader = tbsCertReader.ReadSequence(); Assert.Equal(new DateTimeOffset(2014, 10, 15, 0, 0, 0, TimeSpan.Zero), validityReader.ReadUtcTime()); Assert.Equal(new DateTimeOffset(2016, 10, 15, 23, 59, 59, TimeSpan.Zero), validityReader.ReadUtcTime()); Assert.False(validityReader.HasData, "validityReader.HasData"); AsnReader subjectReader = tbsCertReader.ReadSequence(); Asn1Tag utf8String = new Asn1Tag(UniversalTagNumber.UTF8String); AssertRdn(subjectReader, "1.3.6.1.4.1.311.60.2.1.3", 220, printableString, bytes, "subject[EV Country]"); AssertRdn(subjectReader, "1.3.6.1.4.1.311.60.2.1.2", 241, utf8String, bytes, "subject[EV State]", "Washington"); AssertRdn(subjectReader, "2.5.4.15", 262, printableString, bytes, "subject[Business Category]"); AssertRdn(subjectReader, "2.5.4.5", 293, printableString, bytes, "subject[Serial Number]"); AssertRdn(subjectReader, "2.5.4.6", 313, printableString, bytes, "subject[C]"); AssertRdn(subjectReader, "2.5.4.17", 326, utf8String, bytes, "subject[Postal Code]", "98052"); AssertRdn(subjectReader, "2.5.4.8", 342, utf8String, bytes, "subject[ST]", "Washington"); AssertRdn(subjectReader, "2.5.4.7", 363, utf8String, bytes, "subject[L]", "Redmond"); AssertRdn(subjectReader, "2.5.4.9", 381, utf8String, bytes, "subject[Street Address]", "1 Microsoft Way"); AssertRdn(subjectReader, "2.5.4.10", 407, utf8String, bytes, "subject[O]", "Microsoft Corporation"); AssertRdn(subjectReader, "2.5.4.11", 439, utf8String, bytes, "subject[OU]", "MSCOM"); AssertRdn(subjectReader, "2.5.4.3", 455, utf8String, bytes, "subject[CN]", "www.microsoft.com"); Assert.False(subjectReader.HasData, "subjectReader.HasData"); AsnReader subjectPublicKeyInfo = tbsCertReader.ReadSequence(); AsnReader spkiAlgorithm = subjectPublicKeyInfo.ReadSequence(); Assert.Equal("1.2.840.113549.1.1.1", spkiAlgorithm.ReadObjectIdentifier()); spkiAlgorithm.ReadNull(); Assert.False(spkiAlgorithm.HasData, "spkiAlgorithm.HasData"); Assert.True( subjectPublicKeyInfo.TryReadPrimitiveBitString( out unusedBitCount, out ReadOnlyMemory <byte> encodedPublicKey), "subjectPublicKeyInfo.TryReadBitStringBytes"); Assert.Equal(0, unusedBitCount); AssertRefSame(encodedPublicKey, ref bytes[498], "Encoded public key starts at byte 498"); Assert.False(subjectPublicKeyInfo.HasData, "subjectPublicKeyInfo.HasData"); AsnReader publicKeyReader = new AsnReader(encodedPublicKey, AsnEncodingRules.DER); AsnReader rsaPublicKeyReader = publicKeyReader.ReadSequence(); AssertRefSame(rsaPublicKeyReader.ReadIntegerBytes(), ref bytes[506], "RSA Modulus is at bytes[502]"); Assert.True(rsaPublicKeyReader.TryReadInt32(out int rsaExponent)); Assert.Equal(65537, rsaExponent); Assert.False(rsaPublicKeyReader.HasData, "rsaPublicKeyReader.HasData"); Assert.False(publicKeyReader.HasData, "publicKeyReader.HasData"); AsnReader extensionsContainer = tbsCertReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 3)); AsnReader extensions = extensionsContainer.ReadSequence(); Assert.False(extensionsContainer.HasData, "extensionsContainer.HasData"); AsnReader sanExtension = extensions.ReadSequence(); Assert.Equal("2.5.29.17", sanExtension.ReadObjectIdentifier()); Assert.True(sanExtension.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> sanExtensionBytes)); Assert.False(sanExtension.HasData, "sanExtension.HasData"); AsnReader sanExtensionPayload = new AsnReader(sanExtensionBytes, AsnEncodingRules.DER); AsnReader sanExtensionValue = sanExtensionPayload.ReadSequence(); Assert.False(sanExtensionPayload.HasData, "sanExtensionPayload.HasData"); Asn1Tag dnsName = new Asn1Tag(TagClass.ContextSpecific, 2); Assert.Equal("www.microsoft.com", sanExtensionValue.ReadCharacterString(UniversalTagNumber.IA5String, dnsName)); Assert.Equal("wwwqa.microsoft.com", sanExtensionValue.ReadCharacterString(UniversalTagNumber.IA5String, dnsName)); Assert.False(sanExtensionValue.HasData, "sanExtensionValue.HasData"); AsnReader basicConstraints = extensions.ReadSequence(); Assert.Equal("2.5.29.19", basicConstraints.ReadObjectIdentifier()); Assert.True(basicConstraints.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> basicConstraintsBytes)); AsnReader basicConstraintsPayload = new AsnReader(basicConstraintsBytes, AsnEncodingRules.DER); AsnReader basicConstraintsValue = basicConstraintsPayload.ReadSequence(); Assert.False(basicConstraintsValue.HasData, "basicConstraintsValue.HasData"); Assert.False(basicConstraintsPayload.HasData, "basicConstraintsPayload.HasData"); AsnReader keyUsageExtension = extensions.ReadSequence(); Assert.Equal("2.5.29.15", keyUsageExtension.ReadObjectIdentifier()); Assert.True(keyUsageExtension.ReadBoolean(), "keyUsageExtension.ReadBoolean() (IsCritical)"); Assert.True(keyUsageExtension.TryReadPrimitiveOctetString(out ReadOnlyMemory <byte> keyUsageBytes)); AsnReader keyUsagePayload = new AsnReader(keyUsageBytes, AsnEncodingRules.DER); Assert.Equal( X509KeyUsageCSharpStyle.DigitalSignature | X509KeyUsageCSharpStyle.KeyEncipherment, keyUsagePayload.ReadNamedBitListValue <X509KeyUsageCSharpStyle>()); Assert.False(keyUsagePayload.HasData, "keyUsagePayload.HasData"); AssertExtension(extensions, "2.5.29.37", false, 863, bytes); AssertExtension(extensions, "2.5.29.32", false, 894, bytes); AssertExtension(extensions, "2.5.29.35", false, 998, bytes); AssertExtension(extensions, "2.5.29.31", false, 1031, bytes); AssertExtension(extensions, "1.3.6.1.5.5.7.1.1", false, 1081, bytes); Assert.False(extensions.HasData, "extensions.HasData"); Assert.Equal("1.2.840.113549.1.1.11", sigAlgReader.ReadObjectIdentifier()); sigAlgReader.ReadNull(); Assert.False(sigAlgReader.HasData); }
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 }); }