public static void TagMustBeCorrect_Custom(AsnEncodingRules ruleSet) { byte[] inputData = "87028837".HexToByteArray(); AsnReader reader = new AsnReader(inputData, ruleSet); AssertExtensions.Throws <ArgumentException>( "expectedTag", () => reader.ReadIntegerBytes(Asn1Tag.Null)); Assert.True(reader.HasData, "HasData after bad universal tag"); Assert.Throws <AsnContentException>(() => reader.ReadObjectIdentifier()); Assert.True(reader.HasData, "HasData after default tag"); Assert.Throws <AsnContentException>( () => reader.ReadObjectIdentifier(new Asn1Tag(TagClass.Application, 0))); Assert.True(reader.HasData, "HasData after wrong custom class"); Assert.Throws <AsnContentException>( () => reader.ReadObjectIdentifier(new Asn1Tag(TagClass.ContextSpecific, 1))); Assert.True(reader.HasData, "HasData after wrong custom tag value"); Assert.Equal( "2.999", reader.ReadObjectIdentifier(new Asn1Tag(TagClass.ContextSpecific, 7))); Assert.False(reader.HasData, "HasData after reading value"); }
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 virtual void DecodeX509EnhancedKeyUsageExtension(byte[] encoded, out OidCollection usages) { // https://tools.ietf.org/html/rfc5924#section-4.1 // // ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId // // KeyPurposeId ::= OBJECT IDENTIFIER try { AsnReader reader = new AsnReader(encoded, AsnEncodingRules.BER); AsnReader sequenceReader = reader.ReadSequence(); reader.ThrowIfNotEmpty(); usages = new OidCollection(); while (sequenceReader.HasData) { usages.Add(new Oid(sequenceReader.ReadObjectIdentifier(), null)); } } catch (AsnContentException e) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); } }
internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out X501AttributeAsn decoded) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } decoded = default; AsnReader sequenceReader = reader.ReadSequence(expectedTag); AsnReader collectionReader; decoded.AttrId = sequenceReader.ReadObjectIdentifier(); // Decode SEQUENCE OF for AttrValues { collectionReader = sequenceReader.ReadSetOf(); var tmpList = new List <ReadOnlyMemory <byte> >(); ReadOnlyMemory <byte> tmpItem; while (collectionReader.HasData) { tmpItem = collectionReader.GetEncodedValue(); tmpList.Add(tmpItem); } decoded.AttrValues = tmpList.ToArray(); } sequenceReader.ThrowIfNotEmpty(); }
public static void ReadVeryLongOidArc(AsnEncodingRules ruleSet) { byte[] inputData = new byte[255]; // 06 81 93 (OBJECT IDENTIFIER, 147 bytes). inputData[0] = 0x06; inputData[1] = 0x81; inputData[2] = 0x93; // With 147 bytes we get 147*7 = 1029 value bits. // The smallest legal number to encode would have a top byte of 0x81, // leaving 1022 bits remaining. If they're all zero then we have 2^1022. // // Since it's our first sub-identifier it's really encoding "2.(2^1022 - 80)". inputData[3] = 0x81; // Leave the last byte as 0. new Span <byte>(inputData, 4, 145).Fill(0x80); const string ExpectedOid = "2." + "449423283715578976932326297697256183404494244735576643183575" + "202894331689513752407831771193306018840052800284699678483394" + "146974422036041556232118576598685310944419733562163713190755" + "549003115235298632707380212514422095376705856157203684782776" + "352068092908376276711465745599868114846199290762088390824060" + "56034224"; AsnReader reader = new AsnReader(inputData, ruleSet); string oidString = reader.ReadObjectIdentifier(); Assert.Equal(ExpectedOid, oidString); }
public static void ReadVeryLongOid(AsnEncodingRules ruleSet) { byte[] inputData = new byte[100000]; // 06 83 02 00 00 (OBJECT IDENTIFIER, 65536 bytes). inputData[0] = 0x06; inputData[1] = 0x83; inputData[2] = 0x01; inputData[3] = 0x00; inputData[4] = 0x00; // and the rest are all zero. // The first byte produces "0.0". Each of the remaining 65535 bytes produce // another ".0". const int ExpectedLength = 65536 * 2 + 1; StringBuilder builder = new StringBuilder(ExpectedLength); builder.Append('0'); for (int i = 0; i <= ushort.MaxValue; i++) { builder.Append('.'); builder.Append(0); } AsnReader reader = new AsnReader(inputData, ruleSet); string oidString = reader.ReadObjectIdentifier(); Assert.Equal(ExpectedLength, oidString.Length); Assert.Equal(builder.ToString(), oidString); }
public static void VerifyMultiByteParsing(string inputHex, string expectedValue) { byte[] inputData = inputHex.HexToByteArray(); AsnReader reader = new AsnReader(inputData, AsnEncodingRules.DER); string oidValue = reader.ReadObjectIdentifier(); Assert.Equal(expectedValue, oidValue); }
public static void ReadObjectIdentifier_Throws( string description, PublicEncodingRules ruleSet, string inputHex) { byte[] inputData = inputHex.HexToByteArray(); AsnReader reader = new AsnReader(inputData, (AsnEncodingRules)ruleSet); Assert.Throws <CryptographicException>(() => reader.ReadObjectIdentifier(true)); }
public static void ReadObjectIdentifier_Throws( string description, AsnEncodingRules ruleSet, string inputHex) { _ = description; byte[] inputData = inputHex.HexToByteArray(); AsnReader reader = new AsnReader(inputData, ruleSet); Assert.Throws <AsnContentException>(() => reader.ReadObjectIdentifier()); }
public static void ReadObjectIdentifier_FriendlyName( PublicEncodingRules ruleSet, string inputHex, string expectedFriendlyName) { byte[] inputData = inputHex.HexToByteArray(); AsnReader reader = new AsnReader(inputData, (AsnEncodingRules)ruleSet); Oid oid = reader.ReadObjectIdentifier(); Assert.Equal(expectedFriendlyName, oid.FriendlyName); }
public static void ReadObjectIdentifier_Success( AsnEncodingRules ruleSet, string inputHex, string expectedValue) { byte[] inputData = inputHex.HexToByteArray(); AsnReader reader = new AsnReader(inputData, ruleSet); string oidValue = reader.ReadObjectIdentifier(); Assert.Equal(expectedValue, oidValue); }
public static string?ReadFromBytes(byte[] data) { try { AsnReader reader = new AsnReader(data, AsnEncodingRules.DER); return(reader.ReadObjectIdentifier()); } catch (AsnContentException) { return(null); } }
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}"); }
private static ECParameters ReadParameters(PublicKey publicKey) { var keySource = new ReadOnlySpan <byte>(publicKey.EncodedKeyValue.RawData); var publicKeyValue = AsnDecoder.ReadOctetString(keySource, AsnEncodingRules.BER, out _); var keySize = publicKeyValue.Length / 2; var publicPoint = new ECPoint { X = publicKeyValue.Subarray(0, keySize), Y = publicKeyValue.Subarray(keySize), }; CryptoUtils.EraseData(ref publicKeyValue); var parametersSource = new ReadOnlyMemory <byte>(publicKey.EncodedParameters.RawData); var reader = new AsnReader(parametersSource, AsnEncodingRules.BER); reader = reader.ReadSequence(); var curve = default(ECCurve); while (reader.HasData) { var tag = reader.PeekTag(); if (tag == Asn1Tag.ObjectIdentifier) { var oidValue = reader.ReadObjectIdentifier(); if (ECCurveOidMap.OidValueRegistered(oidValue)) { curve = ECCurve.CreateFromValue(oidValue); continue; } else if (oidValue == CryptoConstants.Streebog256OidValue || oidValue == CryptoConstants.Streebog512OidValue) { continue; } else { throw new NotImplementedException(); } } else { throw new NotImplementedException(); } } return(new ECParameters { Curve = curve, Q = publicPoint }); }
public DigestAlgorithmIdentifier(AsnReader asnReader) { asnReader = asnReader.ReadSequence(); this.algorithm = asnReader.ReadObjectIdentifier(); if (asnReader.PeekTag() == Asn1Tag.Null) { asnReader.ReadNull(); this.parameters = null; } else { this.parameters = asnReader.ReadEncodedValue().ToArray(); }; asnReader.ThrowIfNotEmpty(); }
private static IEnumerable <KeyValuePair <string, string> > ReadReverseRdns(X500DistinguishedName name) { Stack <AsnReader> rdnReaders; try { AsnReader x500NameReader = new AsnReader(name.RawData, AsnEncodingRules.DER); AsnReader sequenceReader = x500NameReader.ReadSequence(); x500NameReader.ThrowIfNotEmpty(); rdnReaders = new Stack <AsnReader>(); while (sequenceReader.HasData) { rdnReaders.Push(sequenceReader.ReadSetOf()); } } catch (AsnContentException e) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); } while (rdnReaders.Count > 0) { AsnReader rdnReader = rdnReaders.Pop(); while (rdnReader.HasData) { string oid; string value; try { AsnReader tavReader = rdnReader.ReadSequence(); oid = tavReader.ReadObjectIdentifier(); value = tavReader.ReadAnyAsnString(); tavReader.ThrowIfNotEmpty(); } catch (AsnContentException e) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); } yield return(new KeyValuePair <string, string>(oid, value)); } } }
// More! public static void AlgorithmIdentifier_ECC_WithCurves( PublicEncodingRules ruleSet, string inputHex, string curveOid) { byte[] inputData = inputHex.HexToByteArray(); var algorithmIdentifier = AsnSerializer.Deserialize <AlgorithmIdentifier>( inputData, (AsnEncodingRules)ruleSet); Assert.Equal("1.2.840.10045.2.1", algorithmIdentifier.Algorithm.Value); var reader = new AsnReader(algorithmIdentifier.Parameters, (AsnEncodingRules)ruleSet); Oid curveId = reader.ReadObjectIdentifier(skipFriendlyName: true); Assert.Equal(curveOid, curveId.Value); }
public virtual void DecodeX509EnhancedKeyUsageExtension(byte[] encoded, out OidCollection usages) { // https://tools.ietf.org/html/rfc5924#section-4.1 // // ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId // // KeyPurposeId ::= OBJECT IDENTIFIER AsnReader reader = new AsnReader(encoded, AsnEncodingRules.BER); AsnReader sequenceReader = reader.ReadSequence(); reader.ThrowIfNotEmpty(); usages = new OidCollection(); while (sequenceReader.HasData) { usages.Add(sequenceReader.ReadObjectIdentifier()); } }
internal static void Decode <T>(AsnReader reader, Asn1Tag expectedTag, out T decoded) where T : KrbAlgorithmIdentifier, new() { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } decoded = new T(); AsnReader sequenceReader = reader.ReadSequence(expectedTag); decoded.Algorithm = sequenceReader.ReadObjectIdentifier(); if (sequenceReader.HasData) { decoded.Parameters = sequenceReader.ReadEncodedValue(); } sequenceReader.ThrowIfNotEmpty(); }
public static void ExpectedTag_IgnoresConstructed( AsnEncodingRules ruleSet, string inputHex, TagClass tagClass, int tagValue) { byte[] inputData = inputHex.HexToByteArray(); Asn1Tag constructedTag = new Asn1Tag(tagClass, tagValue, true); Asn1Tag primitiveTag = new Asn1Tag(tagClass, tagValue, false); AsnReader reader = new AsnReader(inputData, ruleSet); string val1 = reader.ReadObjectIdentifier(constructedTag); Assert.False(reader.HasData); reader = new AsnReader(inputData, ruleSet); string val2 = reader.ReadObjectIdentifier(primitiveTag); Assert.False(reader.HasData); Assert.Equal(val1, val2); }
private static ISet <string> ReadExtendedKeyUsageExtension(byte[] rawData) { HashSet <string> oids = new HashSet <string>(); try { AsnReader reader = new AsnReader(rawData, AsnEncodingRules.DER); AsnReader sequenceReader = reader.ReadSequence(); reader.ThrowIfNotEmpty(); //OidCollection usages while (sequenceReader.HasData) { oids.Add(sequenceReader.ReadObjectIdentifier()); } } catch (AsnContentException e) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); } return(oids); }
private static void AssertRdn( AsnReader reader, string atvOid, int offset, Asn1Tag valueTag, byte[] bytes, string label, string stringValue = null) { AsnReader rdn = reader.ReadSetOf(); AsnReader attributeTypeAndValue = rdn.ReadSequence(); Assert.Equal(atvOid, attributeTypeAndValue.ReadObjectIdentifier()); ReadOnlyMemory <byte> value = attributeTypeAndValue.ReadEncodedValue(); ReadOnlySpan <byte> valueSpan = value.Span; Assert.True(Asn1Tag.TryDecode(valueSpan, out Asn1Tag actualTag, out int bytesRead)); Assert.Equal(1, bytesRead); Assert.Equal(valueTag, actualTag); AssertRefSame( ref MemoryMarshal.GetReference(valueSpan), ref bytes[offset], $"{label} is at bytes[{offset}]"); if (stringValue != null) { AsnReader valueReader = new AsnReader(value, AsnEncodingRules.DER); Assert.Equal(stringValue, valueReader.ReadCharacterString((UniversalTagNumber)valueTag.TagValue)); Assert.False(valueReader.HasData, "valueReader.HasData"); } Assert.False(attributeTypeAndValue.HasData, $"attributeTypeAndValue.HasData ({label})"); Assert.False(rdn.HasData, $"rdn.HasData ({label})"); }
private static string X500DistinguishedNameDecode( byte[] encodedName, bool printOid, bool reverse, bool quoteIfNeeded, string dnSeparator, string multiValueSeparator, bool addTrailingDelimiter) { try { AsnReader x500NameReader = new AsnReader(encodedName, AsnEncodingRules.DER); AsnReader x500NameSequenceReader = x500NameReader.ReadSequence(); var rdnReaders = new List <AsnReader>(); x500NameReader.ThrowIfNotEmpty(); while (x500NameSequenceReader.HasData) { // To match Windows' behavior, permit multi-value RDN SETs to not // be DER sorted. rdnReaders.Add(x500NameSequenceReader.ReadSetOf(skipSortOrderValidation: true)); } // We need to allocate a StringBuilder to hold the data as we're building it, and there's the usual // arbitrary process of choosing a number that's "big enough" to minimize reallocations without wasting // too much space in the average case. // // So, let's look at an example of what our output might be. // // GitHub.com's SSL cert has a "pretty long" subject (partially due to the unknown OIDs): // businessCategory=Private Organization // 1.3.6.1.4.1.311.60.2.1.3=US // 1.3.6.1.4.1.311.60.2.1.2=Delaware // serialNumber=5157550 // street=548 4th Street // postalCode=94107 // C=US // ST=California // L=San Francisco // O=GitHub, Inc. // CN=github.com // // Which comes out to 228 characters using OpenSSL's default pretty-print // (openssl x509 -in github.cer -text -noout) // Throw in some "maybe-I-need-to-quote-this" quotes, and a couple of extra/extra-long O/OU values // and round that up to the next programmer number, and you get that 512 should avoid reallocations // in all but the most dire of cases. StringBuilder decodedName = new StringBuilder(512); int entryCount = rdnReaders.Count; bool printSpacing = false; for (int i = 0; i < entryCount; i++) { int loc = reverse ? entryCount - i - 1 : i; // RelativeDistinguishedName ::= // SET SIZE (1..MAX) OF AttributeTypeAndValue // // AttributeTypeAndValue::= SEQUENCE { // type AttributeType, // value AttributeValue } // // AttributeType::= OBJECT IDENTIFIER // // AttributeValue ::= ANY-- DEFINED BY AttributeType if (printSpacing) { decodedName.Append(dnSeparator); } else { printSpacing = true; } AsnReader rdnReader = rdnReaders[loc]; bool hadValue = false; while (rdnReader.HasData) { AsnReader tavReader = rdnReader.ReadSequence(); string oid = tavReader.ReadObjectIdentifier(); string attributeValue = tavReader.ReadAnyAsnString(); tavReader.ThrowIfNotEmpty(); if (hadValue) { decodedName.Append(multiValueSeparator); } else { hadValue = true; } if (printOid) { AppendOid(decodedName, oid); } bool quote = quoteIfNeeded && NeedsQuoting(attributeValue); if (quote) { decodedName.Append('"'); // If the RDN itself had a quote within it, that quote needs to be escaped // with another quote. attributeValue = attributeValue.Replace("\"", "\"\""); } decodedName.Append(attributeValue); if (quote) { decodedName.Append('"'); } } } if (addTrailingDelimiter && decodedName.Length > 0) { decodedName.Append(dnSeparator); } return(decodedName.ToString()); } catch (AsnContentException e) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); } }
public byte[]? GetOutgoingBlob(byte[]?incomingBlob) { if (_spnegoMechList == null && incomingBlob.AsSpan().StartsWith(NtlmHeader)) { _ntlmPassthrough = true; // Windows often sends pure NTLM instead of proper Negotiate, handle that as passthrough byte[]? outgoingBlob = _ntlmServer.GetOutgoingBlob(incomingBlob); IsAuthenticated = _ntlmServer.IsAuthenticated; return(outgoingBlob); } Assert.False(_ntlmPassthrough); AsnReader reader = new AsnReader(incomingBlob, AsnEncodingRules.DER); if (_spnegoMechList == null) { AsnReader initialContextTokenReader = reader.ReadSequence(new Asn1Tag(TagClass.Application, 0)); string spNegoOid = initialContextTokenReader.ReadObjectIdentifier(); Assert.Equal(SpnegoOid, spNegoOid); AsnReader negTokenInitReader = initialContextTokenReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegotiationToken.NegTokenInit)).ReadSequence(); AsnReader mechTypesOuterReader = negTokenInitReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenInit.MechTypes)); _spnegoMechList = mechTypesOuterReader.PeekEncodedValue().ToArray(); bool hasNtlm = false; bool isNtlmPreferred = false; bool first = true; AsnReader mechTypesReader = mechTypesOuterReader.ReadSequence(); while (mechTypesReader.HasData) { string mechType = mechTypesReader.ReadObjectIdentifier(); if (mechType == NtlmOid) { hasNtlm = true; isNtlmPreferred = first; } first = false; } // Skip context flags, if present if (negTokenInitReader.HasData && negTokenInitReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenInit.ReqFlags))) { negTokenInitReader.ReadSequence(); } byte[]? mechToken = null; if (negTokenInitReader.HasData && negTokenInitReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenInit.MechToken))) { AsnReader mechTokenReader = negTokenInitReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenInit.MechToken)); mechToken = mechTokenReader.ReadOctetString(); Assert.False(mechTokenReader.HasData); } byte[]? mechListMIC = null; if (negTokenInitReader.HasData && negTokenInitReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenInit.MechListMIC))) { AsnReader mechListMICReader = negTokenInitReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenInit.MechListMIC)); mechListMIC = mechListMICReader.ReadOctetString(); Assert.False(mechListMICReader.HasData); } Assert.True(hasNtlm); // If the preferred mechanism was NTLM then proceed with the given token byte[]? outgoingBlob = null; if (isNtlmPreferred && mechToken != null) { Assert.Null(mechListMIC); outgoingBlob = _ntlmServer.GetOutgoingBlob(mechToken); } // Generate reply AsnWriter writer = new AsnWriter(AsnEncodingRules.DER); using (writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegotiationToken.NegTokenResp))) { using (writer.PushSequence()) { using (writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.NegState))) { if (RequestMIC) { writer.WriteEnumeratedValue(NegState.RequestMic); } else { writer.WriteEnumeratedValue(NegState.AcceptIncomplete); } } using (writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.SupportedMech))) { writer.WriteObjectIdentifier(NtlmOid); } if (outgoingBlob != null) { using (writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.ResponseToken))) { writer.WriteOctetString(outgoingBlob); } } } } return(writer.Encode()); } else { AsnReader negTokenRespReader = reader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegotiationToken.NegTokenResp)).ReadSequence(); Assert.True(negTokenRespReader.HasData); NegState?clientState; if (negTokenRespReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.NegState))) { AsnReader valueReader = negTokenRespReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.NegState)); clientState = valueReader.ReadEnumeratedValue <NegState>(); Assert.False(valueReader.HasData); Assert.NotEqual(NegState.Reject, clientState); Assert.NotEqual(NegState.RequestMic, clientState); } // Client should not send mechanism Assert.False(negTokenRespReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.SupportedMech))); byte[]? mechToken = null; if (negTokenRespReader.HasData && negTokenRespReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.ResponseToken))) { AsnReader mechTokenReader = negTokenRespReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.ResponseToken)); mechToken = mechTokenReader.ReadOctetString(); Assert.False(mechTokenReader.HasData); } byte[]? mechListMIC = null; if (negTokenRespReader.HasData && negTokenRespReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.MechListMIC))) { AsnReader mechListMICReader = negTokenRespReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.MechListMIC)); mechListMIC = mechListMICReader.ReadOctetString(); Assert.False(mechListMICReader.HasData); } Assert.NotNull(mechToken); byte[]? outgoingBlob = _ntlmServer.GetOutgoingBlob(mechToken); if (_ntlmServer.IsAuthenticated) { if (RequestMIC) { Assert.NotNull(mechListMIC); } // Validate mechListMIC, if present if (mechListMIC is not null) { _ntlmServer.VerifyMIC(_spnegoMechList, mechListMIC); } } else { Assert.Null(mechListMIC); } // Generate reply AsnWriter writer = new AsnWriter(AsnEncodingRules.DER); using (writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegotiationToken.NegTokenResp))) { using (writer.PushSequence()) { using (writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.NegState))) { if (_ntlmServer.IsAuthenticated) { writer.WriteEnumeratedValue(NegState.AcceptCompleted); } else if (outgoingBlob != null) { writer.WriteEnumeratedValue(NegState.AcceptIncomplete); } else { writer.WriteEnumeratedValue(NegState.Reject); } } if (outgoingBlob != null) { using (writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.ResponseToken))) { writer.WriteOctetString(outgoingBlob); } } if (mechListMIC != null) { using (writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenResp.MechListMIC))) { Span <byte> mic = stackalloc byte[16]; _ntlmServer.GetMIC(_spnegoMechList, mic); writer.WriteOctetString(mic); // MS-SPNG section 3.2.5.1 NTLM RC4 Key State for MechListMIC and First Signed Message // specifies that the RC4 sealing keys are reset back to the initial state for the // first message. _ntlmServer.ResetKeys(); } } } } IsAuthenticated = _ntlmServer.IsAuthenticated; return(writer.Encode()); } }
internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out Rfc3161TimeStampReq decoded) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } decoded = default; AsnReader sequenceReader = reader.ReadSequence(expectedTag); AsnReader defaultReader; AsnReader collectionReader; if (!sequenceReader.TryReadInt32(out decoded.Version)) { sequenceReader.ThrowIfNotEmpty(); } System.Security.Cryptography.Pkcs.Asn1.MessageImprint.Decode(sequenceReader, out decoded.MessageImprint); if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.ObjectIdentifier)) { decoded.ReqPolicy = sequenceReader.ReadObjectIdentifier(); } if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Integer)) { decoded.Nonce = sequenceReader.ReadIntegerBytes(); } if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Boolean)) { decoded.CertReq = sequenceReader.ReadBoolean(); } else { defaultReader = new AsnReader(s_defaultCertReq, AsnEncodingRules.DER); decoded.CertReq = defaultReader.ReadBoolean(); } if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0))) { // Decode SEQUENCE OF for Extensions { collectionReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0)); var tmpList = new List <System.Security.Cryptography.Asn1.X509ExtensionAsn>(); System.Security.Cryptography.Asn1.X509ExtensionAsn tmpItem; while (collectionReader.HasData) { System.Security.Cryptography.Asn1.X509ExtensionAsn.Decode(collectionReader, out tmpItem); tmpList.Add(tmpItem); } decoded.Extensions = tmpList.ToArray(); } } sequenceReader.ThrowIfNotEmpty(); }
public unsafe string ProcessNegotiateChallenge(string challengeString) { Console.WriteLine($"ChallengesString {challengeString}"); NegState state = NegState.Unknown; string mech = null; byte[] blob = null; byte[] data = Convert.FromBase64String(challengeString); AsnReader reader = new AsnReader(data, AsnEncodingRules.DER); AsnReader challengeReader = reader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegotiationToken.NegTokenResp)); // NegTokenResp::= SEQUENCE { // negState[0] ENUMERATED { // accept - completed(0), // accept - incomplete(1), // reject(2), // request - mic(3) // } OPTIONAL, // --REQUIRED in the first reply from the target // supportedMech[1] MechType OPTIONAL, // --present only in the first reply from the target // responseToken[2] OCTET STRING OPTIONAL, // mechListMIC[3] OCTET STRING OPTIONAL, // ... // } challengeReader = challengeReader.ReadSequence(); while (challengeReader.HasData) { Asn1Tag tag = challengeReader.PeekTag(); if (tag.TagClass == TagClass.ContextSpecific) { NegTokenResp dataType = (NegTokenResp)tag.TagValue; AsnReader specificValue = new AsnReader(challengeReader.PeekContentBytes(), AsnEncodingRules.DER); switch (dataType) { case NegTokenResp.NegState: state = specificValue.ReadEnumeratedValue <NegState>(); break; case NegTokenResp.SupportedMech: mech = specificValue.ReadObjectIdentifier(); break; case NegTokenResp.ResponseToken: blob = specificValue.ReadOctetString(); break; default: // Ignore everything else break; } } challengeReader.ReadEncodedValue(); } if (Diag) { Console.WriteLine("Negotiate challenege: {0} - {1} in {2}", challengeString, mech, state); } // Mechanism should be set on first message. That means always // as NTLM has only one challenege message. if (!NtlmOid.Equals(mech)) { throw new NotSupportedException($"'{mech}' mechanism is not supported"); } if (state != NegState.Unknown && state != NegState.AcceptIncomplete) { // If state was set, it should be AcceptIncomplete for us to proseed. return(""); } if (blob?.Length > 0) { // Process decoded NTLM blob. byte[] response = ProcessChallengeMessage(blob); if (response?.Length > 0) { AsnWriter writer = new AsnWriter(AsnEncodingRules.DER); using (writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegotiationToken.NegTokenResp))) { writer.PushSequence(); using (writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, (int)NegTokenInit.MechToken))) { writer.WriteOctetString(response); } writer.PopSequence(); } return("Negotiate " + Convert.ToBase64String(writer.Encode(), Base64FormattingOptions.None)); } } return(""); }
internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out Rfc3161TstInfo decoded) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } decoded = default; AsnReader sequenceReader = reader.ReadSequence(expectedTag); AsnReader explicitReader; AsnReader defaultReader; AsnReader collectionReader; if (!sequenceReader.TryReadInt32(out decoded.Version)) { sequenceReader.ThrowIfNotEmpty(); } decoded.Policy = sequenceReader.ReadObjectIdentifier(); System.Security.Cryptography.Pkcs.Asn1.MessageImprint.Decode(sequenceReader, out decoded.MessageImprint); decoded.SerialNumber = sequenceReader.GetIntegerBytes(); decoded.GenTime = sequenceReader.GetGeneralizedTime(); if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Sequence)) { System.Security.Cryptography.Pkcs.Asn1.Rfc3161Accuracy tmpAccuracy; System.Security.Cryptography.Pkcs.Asn1.Rfc3161Accuracy.Decode(sequenceReader, out tmpAccuracy); decoded.Accuracy = tmpAccuracy; } if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Boolean)) { decoded.Ordering = sequenceReader.ReadBoolean(); } else { defaultReader = new AsnReader(s_defaultOrdering, AsnEncodingRules.DER); decoded.Ordering = defaultReader.ReadBoolean(); } if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Integer)) { decoded.Nonce = sequenceReader.GetIntegerBytes(); } if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0))) { explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0)); System.Security.Cryptography.Asn1.GeneralNameAsn tmpTsa; System.Security.Cryptography.Asn1.GeneralNameAsn.Decode(explicitReader, out tmpTsa); decoded.Tsa = tmpTsa; explicitReader.ThrowIfNotEmpty(); } if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1))) { // Decode SEQUENCE OF for Extensions { collectionReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1)); var tmpList = new List <System.Security.Cryptography.Asn1.X509ExtensionAsn>(); System.Security.Cryptography.Asn1.X509ExtensionAsn tmpItem; while (collectionReader.HasData) { System.Security.Cryptography.Asn1.X509ExtensionAsn.Decode(collectionReader, out tmpItem); tmpList.Add(tmpItem); } decoded.Extensions = tmpList.ToArray(); } } sequenceReader.ThrowIfNotEmpty(); }
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); }