public bool Equals(AdditionalText?x, AdditionalText?y) { if (object.ReferenceEquals(x, y)) { return(true); } if (x is null || y is null) { return(false); } if (!PathUtilities.Comparer.Equals(x.Path, y.Path)) { return(false); } var xText = GetTextOrNullIfBinary(x); var yText = GetTextOrNullIfBinary(y); // If xText and yText are both null, then the additional text is observably not changed // and can be treated as equal. if (xText is null && yText is null) { return(true); } if (xText is null || yText is null || xText.Length != yText.Length) { return(false); } return(ByteSequenceComparer.Equals(xText.GetChecksum(), yText.GetChecksum())); }
public bool Equals(AdditionalText?x, AdditionalText?y) { if (object.ReferenceEquals(x, y)) { return(true); } if (x is null || y is null) { return(false); } if (!PathUtilities.Comparer.Equals(x.Path, y.Path)) { return(false); } var xText = x.GetText(); var yText = y.GetText(); if (xText is null || yText is null || xText.Length != yText.Length) { return(false); } return(ByteSequenceComparer.Equals(xText.GetChecksum(), yText.GetChecksum())); }
public void Equals1() { Assert.True(ByteSequenceComparer.Equals(new byte[] { }, new byte[] { })); Assert.True(ByteSequenceComparer.Equals(new byte[] { 1 }, new byte[] { 1 })); Assert.False(ByteSequenceComparer.Equals(new byte[] { 1 }, new byte[] { 2 })); Assert.True(ByteSequenceComparer.Equals(new byte[] { 1, 2 }, new byte[] { 1, 2 })); Assert.False(ByteSequenceComparer.Equals(new byte[] { 1, 2 }, new byte[] { 1, 3 })); }
public void Equals2() { Assert.True(ByteSequenceComparer.Equals(new byte[] { }, 0, new byte[] { }, 0, 0)); Assert.True(ByteSequenceComparer.Equals(new byte[] { 1 }, 0, new byte[] { }, 0, 0)); Assert.True(ByteSequenceComparer.Equals(new byte[] { 1 }, 1, new byte[] { 1 }, 1, 0)); Assert.True(ByteSequenceComparer.Equals(new byte[] { 1 }, 0, new byte[] { 1 }, 0, 1)); Assert.False(ByteSequenceComparer.Equals(new byte[] { 1 }, 0, new byte[] { 2 }, 0, 1)); Assert.True(ByteSequenceComparer.Equals(new byte[] { 1, 2 }, 1, new byte[] { 2 }, 0, 1)); }
// From StrongNameInternal.cpp // Checks to see if a public key is a valid instance of a PublicKeyBlob as // defined in StongName.h internal static bool IsValidPublicKey(ImmutableArray <byte> blob) { // The number of public key bytes must be at least large enough for the header and one byte of data. if (blob.IsDefault || blob.Length < s_publicKeyHeaderSize + 1) { return(false); } var blobReader = new LittleEndianReader(blob.AsSpan()); // Signature algorithm ID var sigAlgId = blobReader.ReadUInt32(); // Hash algorithm ID var hashAlgId = blobReader.ReadUInt32(); // Size of public key data in bytes, not including the header var publicKeySize = blobReader.ReadUInt32(); // publicKeySize bytes of public key data var publicKey = blobReader.ReadByte(); // The number of public key bytes must be the same as the size of the header plus the size of the public key data. if (blob.Length != s_publicKeyHeaderSize + publicKeySize) { return(false); } // Check for the ECMA key, which does not obey the invariants checked below. if (ByteSequenceComparer.Equals(blob, s_ecmaKey)) { return(true); } // The public key must be in the wincrypto PUBLICKEYBLOB format if (publicKey != PublicKeyBlobId) { return(false); } var signatureAlgorithmId = new AlgorithmId(sigAlgId); if (signatureAlgorithmId.IsSet && signatureAlgorithmId.Class != AlgorithmClass.Signature) { return(false); } var hashAlgorithmId = new AlgorithmId(hashAlgId); if (hashAlgorithmId.IsSet && (hashAlgorithmId.Class != AlgorithmClass.Hash || hashAlgorithmId.SubId < AlgorithmSubId.Sha1Hash)) { return(false); } return(true); }
private void TestContentEquals(byte[] left, byte[] right) { var builder1 = new BlobBuilder(0); builder1.WriteBytes(left); var builder2 = new BlobBuilder(0); builder2.WriteBytes(right); bool expected = ByteSequenceComparer.Equals(left, right); Assert.Equal(expected, builder1.ContentEquals(builder2)); }
private static unsafe bool IsValidPublicKeyUnsafe(ImmutableArray <byte> blob) { fixed(byte *ptr = blob.DangerousGetUnderlyingArray()) { var blobReader = new BlobReader(ptr, blob.Length); // Signature algorithm ID var sigAlgId = blobReader.ReadUInt32(); // Hash algorithm ID var hashAlgId = blobReader.ReadUInt32(); // Size of public key data in bytes, not including the header var publicKeySize = blobReader.ReadUInt32(); // publicKeySize bytes of public key data var publicKey = blobReader.ReadByte(); // The number of public key bytes must be the same as the size of the header plus the size of the public key data. if (blob.Length != s_publicKeyHeaderSize + publicKeySize) { return(false); } // Check for the ECMA key, which does not obey the invariants checked below. if (ByteSequenceComparer.Equals(blob, s_ecmaKey)) { return(true); } // The public key must be in the wincrypto PUBLICKEYBLOB format if (publicKey != PublicKeyBlobId) { return(false); } var signatureAlgorithmId = new AlgorithmId(sigAlgId); if (signatureAlgorithmId.IsSet && signatureAlgorithmId.Class != AlgorithmClass.Signature) { return(false); } var hashAlgorithmId = new AlgorithmId(hashAlgId); if (hashAlgorithmId.IsSet && (hashAlgorithmId.Class != AlgorithmClass.Hash || hashAlgorithmId.SubId < AlgorithmSubId.Sha1Hash)) { return(false); } } return(true); }
public void Equals3() { var b = new byte[] { 1, 2, 1 }; Assert.True(ByteSequenceComparer.Equals(b, b)); Assert.True(ByteSequenceComparer.Equals(b, 0, b, 0, 1)); Assert.True(ByteSequenceComparer.Equals(b, 2, b, 2, 1)); Assert.True(ByteSequenceComparer.Equals(b, 0, b, 2, 1)); Assert.False(ByteSequenceComparer.Equals(b, 0, b, 1, 1)); Assert.False(ByteSequenceComparer.Equals(null, b)); Assert.False(ByteSequenceComparer.Equals(null, new byte[] { })); Assert.True(ByteSequenceComparer.Equals(null, null)); }
// internal for testing /// <exception cref="IOException"/> internal static ImmutableArray <byte> GetPublicKey(byte[] keyFileContents) { try { var lastSeen = lastSeenKeyPair; if (lastSeen != null && ByteSequenceComparer.ValueEquals(lastSeen.Item1, keyFileContents)) { return(lastSeen.Item2); } ICLRStrongName strongName = GetStrongNameInterface(); IntPtr keyBlob; int keyBlobByteCount; //EDMAURER use marshal to be safe? unsafe { fixed(byte *p = keyFileContents) { try { strongName.StrongNameGetPublicKey(null, (IntPtr)p, keyFileContents.Length, out keyBlob, out keyBlobByteCount); } catch (ArgumentException ex) { throw new IOException(ex.Message); } } } byte[] pubKey = new byte[keyBlobByteCount]; Marshal.Copy(keyBlob, pubKey, 0, keyBlobByteCount); strongName.StrongNameFreeBuffer(keyBlob); var result = pubKey.AsImmutableOrNull(); lastSeenKeyPair = Tuple.Create(keyFileContents, result); return(result); } catch (COMException ex) { throw new IOException(ex.Message); } }
// From StrongNameInternal.cpp public static bool TryDecode(ImmutableArray <byte> bytes) { // The number of public key bytes must be at least large enough for the header and one byte of data. if (bytes.IsDefault || bytes.Length < HeaderSize + 1) { return(false); } // The number of public key bytes must be the same as the size of the header plus the size of the public key data. var dataSize = ToUInt32(bytes, PublicKeySizeOffset); if (bytes.Length != HeaderSize + dataSize) { return(false); } // Check for the ECMA key, which does not obey the invariants checked below. if (ByteSequenceComparer.Equals(bytes, s_ecmaKey)) { return(true); } var signatureAlgorithmId = new AlgorithmId(ToUInt32(bytes, 0)); if (signatureAlgorithmId.IsSet && signatureAlgorithmId.Class != AlgorithmClass.Signature) { return(false); } var hashAlgorithmId = new AlgorithmId(ToUInt32(bytes, 4)); if (hashAlgorithmId.IsSet && (hashAlgorithmId.Class != AlgorithmClass.Hash || hashAlgorithmId.SubId < AlgorithmSubId.Sha1Hash)) { return(false); } if (bytes[PublicKeyDataOffset] != PublicKeyBlob) { return(false); } return(true); }
private static unsafe bool IsValidPublicKeyUnsafe(ImmutableArray <byte> blob) { var blobArray = blob.DangerousGetUnderlyingArray(); fixed(byte *blobPtr = blobArray) { var pkb = (SnPublicKeyBlob *)blobPtr; // The number of public key bytes must be the same as the size of the header plus the size of the public key data. if (blob.Length != s_publicKeyHeaderSize + pkb->PublicKeySize) { return(false); } // Check for the ECMA key, which does not obey the invariants checked below. if (ByteSequenceComparer.Equals(blob, s_ecmaKey)) { return(true); } // The public key must be in the wincrypto PUBLICKEYBLOB format if (pkb->PublicKey[0] != PublicKeyBlobId) { return(false); } var signatureAlgorithmId = new AlgorithmId(pkb->SigAlgId); if (signatureAlgorithmId.IsSet && signatureAlgorithmId.Class != AlgorithmClass.Signature) { return(false); } var hashAlgorithmId = new AlgorithmId(pkb->HashAlgId); if (hashAlgorithmId.IsSet && (hashAlgorithmId.Class != AlgorithmClass.Hash || hashAlgorithmId.SubId < AlgorithmSubId.Sha1Hash)) { return(false); } } return(true); }
/// <summary> /// Compares the current content of this writer with another one. /// </summary> /// <exception cref="InvalidOperationException">Content is not available, the builder has been linked with another one.</exception> public bool ContentEquals(BlobBuilder other) { if (!IsHead) { Throw.InvalidOperationBuilderAlreadyLinked(); } if (ReferenceEquals(this, other)) { return(true); } if (other == null) { return(false); } if (!other.IsHead) { Throw.InvalidOperationBuilderAlreadyLinked(); } if (Count != other.Count) { return(false); } var leftEnumerator = GetChunks(); var rightEnumerator = other.GetChunks(); int leftStart = 0; int rightStart = 0; bool leftContinues = leftEnumerator.MoveNext(); bool rightContinues = rightEnumerator.MoveNext(); while (leftContinues && rightContinues) { Debug.Assert(leftStart == 0 || rightStart == 0); var left = leftEnumerator.Current; var right = rightEnumerator.Current; int minLength = Math.Min(left.Length - leftStart, right.Length - rightStart); if (!ByteSequenceComparer.Equals(left._buffer, leftStart, right._buffer, rightStart, minLength)) { return(false); } leftStart += minLength; rightStart += minLength; // nothing remains in left chunk to compare: if (leftStart == left.Length) { leftContinues = leftEnumerator.MoveNext(); leftStart = 0; } // nothing remains in left chunk to compare: if (rightStart == right.Length) { rightContinues = rightEnumerator.MoveNext(); rightStart = 0; } } return(leftContinues == rightContinues); }
public int GetHashCode(AdditionalText obj) { return(Hash.Combine(PathUtilities.Comparer.GetHashCode(obj.Path), ByteSequenceComparer.GetHashCode(GetTextOrNullIfBinary(obj)?.GetChecksum() ?? ImmutableArray <byte> .Empty))); }
/// <summary> /// Compares the current content of this writer with another one. /// </summary> public bool ContentEquals(BlobBuilder other) { return(other != null && Length == other.Length && ByteSequenceComparer.Equals(_buffer, 0, other._buffer, 0, Length)); }
protected IVTConclusion PerformIVTCheck(ImmutableArray <byte> key, AssemblyIdentity otherIdentity) { // This gets a bit complicated. Let's break it down. // // First off, let's assume that the "other" assembly is Smith.DLL, that the "this" // assembly is "Jones.DLL", and that Smith has named Jones as a friend. Whether we // allow Jones to see internals of Smith depends on these four factors: // // q1) Is Smith strong-named? // q2) Did Smith name Jones as a friend via a strong name? // q3) Is Jones strong-named? // q4) Does Smith give a strong-name for Jones that matches our strong name? // // Before we dive into the details, we should mention two additional facts: // // * If the answer to q1 is "yes", and Smith was compiled by the C# compiler, then q2 must be "yes" also. // Strong-named Smith must only be friends with strong-named Jones. See the blog article // http://blogs.msdn.com/b/ericlippert/archive/2009/06/04/alas-smith-and-jones.aspx // for an explanation of why this feature is desirable. // // Now, just because the compiler enforces this rule does not mean that we will never run into // a scenario where Smith is strong-named and names Jones via a weak name. Not all assemblies // were compiled with the C# compiler. We still need to deal sensibly with this situation. // We do so by ignoring the problem; if strong-named Smith extends friendship to weak-named // Jones then we're done; any assembly named Jones is a friend of Smith. // // Incidentally, the compiler produces error CS1726, ERR_FriendAssemblySNReq, when compiling // a strong-named Smith that names a weak-named Jones as its friend. // // * If the answer to q1 is "no" and the answer to q3 is "yes" then we are in a situation where // strong-named Jones is referencing weak-named Smith, which is illegal. In the dev 10 compiler // we do not give an error about this until emit time. In Roslyn we have a new error, CS7029, // which we give before emit time when we detect that weak-named Smith has given friend access // to strong-named Jones, which then references Smith. However, we still want to give friend // access to Jones for the purposes of semantic analysis. // // TODO: Roslyn does not yet give an error in other circumstances whereby a strong-named assembly // TODO: references a weak-named assembly. // // Let's make a chart that illustrates all the possible answers to these four questions, and // what the resulting accessibility should be: // // case q1 q2 q3 q4 Result Explanation // 1 YES YES YES YES SUCCESS Smith has named this strong-named Jones as a friend. // 2 YES YES YES NO NO MATCH Smith has named a different strong-named Jones as a friend. // 3 YES YES NO NO NO MATCH Smith has named a strong-named Jones as a friend, but this Jones is weak-named. // 4 YES NO YES NO SUCCESS Smith has improperly (*) named any Jones as its friend. But we honor its offer of friendship. // 5 YES NO NO NO SUCCESS Smith has improperly (*) named any Jones as its friend. But we honor its offer of friendship. // 6 NO YES YES YES SUCCESS, BAD REF Smith has named this strong-named Jones as a friend, but Jones should not be referring to a weak-named Smith. // 7 NO YES YES NO NO MATCH Smith has named a different strong-named Jones as a friend. // 8 NO YES NO NO NO MATCH Smith has named a strong-named Jones as a friend, but this Jones is weak-named. // 9 NO NO YES NO SUCCESS, BAD REF Smith has named any Jones as a friend, but Jones should not be referring to a weak-named Smith. // 10 NO NO NO NO SUCCESS Smith has named any Jones as its friend. // // (*) Smith was not built with C#, which would have prevented this. // // This method never returns NoRelationshipClaimed because if control got here, then we know that // Smith named Jones as a friend somehow. // // All that said, we also have an easy out here. Suppose Smith names Jones as a friend, and Jones is // being compiled as a module, not as an assembly. You can only strong-name an assembly. So if this module // is named Jones, and Smith is extending friend access to Jones, then we are going to optimistically // assume that Jones is going to be compiled into an assembly with a matching strong name, if necessary. CSharpCompilation compilation = this.DeclaringCompilation; if (compilation != null && compilation.Options.OutputKind.IsNetModule()) { return(IVTConclusion.Match); } bool q1 = otherIdentity.IsStrongName; bool q2 = !key.IsDefaultOrEmpty; bool q3 = !this.PublicKey.IsDefaultOrEmpty; bool q4 = (q2 & q3) && ByteSequenceComparer.Equals(key, this.PublicKey); // Cases 2, 3, 7 and 8: if (q2 && !q4) { return(IVTConclusion.PublicKeyDoesntMatch); } // Cases 6 and 9: if (!q1 && q3) { return(IVTConclusion.OneSignedOneNot); } // Cases 1, 4, 5 and 10: return(IVTConclusion.Match); }
internal static IVTConclusion PerformIVTCheck( this AssemblyIdentity assemblyGrantingAccessIdentity, ImmutableArray <byte> assemblyWantingAccessKey, ImmutableArray <byte> grantedToPublicKey ) { // This gets a bit complicated. Let's break it down. // // First off, let's assume that the "other" assembly is GrantingAssembly.DLL, that the "this" // assembly is "WantingAssembly.DLL", and that GrantingAssembly has named WantingAssembly as a friend (that is a precondition // to calling this method). Whether we allow WantingAssembly to see internals of GrantingAssembly depends on these four factors: // // q1) Is GrantingAssembly strong-named? // q2) Did GrantingAssembly name WantingAssembly as a friend via a strong name? // q3) Is WantingAssembly strong-named? // q4) Does GrantingAssembly give a strong-name for WantingAssembly that matches our strong name? // // Before we dive into the details, we should mention two additional facts: // // * If the answer to q1 is "yes", and GrantingAssembly was compiled by a Roslyn compiler, then q2 must be "yes" also. // Strong-named GrantingAssembly must only be friends with strong-named WantingAssembly. See the blog article // http://blogs.msdn.com/b/ericlippert/archive/2009/06/04/alas-smith-and-jones.aspx // for an explanation of why this feature is desirable. // // Now, just because the compiler enforces this rule does not mean that we will never run into // a scenario where GrantingAssembly is strong-named and names WantingAssembly via a weak name. Not all assemblies // were compiled with a Roslyn compiler. We still need to deal sensibly with this situation. // We do so by ignoring the problem; if strong-named GrantingAssembly extends friendship to weak-named // WantingAssembly then we're done; any assembly named WantingAssembly is a friend of GrantingAssembly. // // Incidentally, the C# compiler produces error CS1726, ERR_FriendAssemblySNReq, and VB produces // the error VB31535, ERR_FriendAssemblyStrongNameRequired, when compiling // a strong-named GrantingAssembly that names a weak-named WantingAssembly as its friend. // // * If the answer to q1 is "no" and the answer to q3 is "yes" then we are in a situation where // strong-named WantingAssembly is referencing weak-named GrantingAssembly, which is illegal. In the dev10 compiler // we do not give an error about this until emit time. In Roslyn we have a new error, CS7029, // which we give before emit time when we detect that weak-named GrantingAssembly has given friend access // to strong-named WantingAssembly, which then references GrantingAssembly. However, we still want to give friend // access to WantingAssembly for the purposes of semantic analysis. // // Roslyn C# does not yet give an error in other circumstances whereby a strong-named assembly // references a weak-named assembly. See https://github.com/dotnet/roslyn/issues/26722 // // Let's make a chart that illustrates all the possible answers to these four questions, and // what the resulting accessibility should be: // // case q1 q2 q3 q4 Result Explanation // 1 YES YES YES YES SUCCESS GrantingAssembly has named this strong-named WantingAssembly as a friend. // 2 YES YES YES NO NO MATCH GrantingAssembly has named a different strong-named WantingAssembly as a friend. // 3 YES YES NO NO NO MATCH GrantingAssembly has named a strong-named WantingAssembly as a friend, but this WantingAssembly is weak-named. // 4 YES NO YES NO SUCCESS GrantingAssembly has improperly (*) named any WantingAssembly as its friend. But we honor its offer of friendship. // 5 YES NO NO NO SUCCESS GrantingAssembly has improperly (*) named any WantingAssembly as its friend. But we honor its offer of friendship. // 6 NO YES YES YES SUCCESS, BAD REF GrantingAssembly has named this strong-named WantingAssembly as a friend, but WantingAssembly should not be referring to a weak-named GrantingAssembly. // 7 NO YES YES NO NO MATCH GrantingAssembly has named a different strong-named WantingAssembly as a friend. // 8 NO YES NO NO NO MATCH GrantingAssembly has named a strong-named WantingAssembly as a friend, but this WantingAssembly is weak-named. // 9 NO NO YES NO SUCCESS, BAD REF GrantingAssembly has named any WantingAssembly as a friend, but WantingAssembly should not be referring to a weak-named GrantingAssembly. // 10 NO NO NO NO SUCCESS GrantingAssembly has named any WantingAssembly as its friend. // // (*) GrantingAssembly was not built with a Roslyn compiler, which would have prevented this. // // This method never returns NoRelationshipClaimed because if control got here, then we assume // (as a precondition) that GrantingAssembly named WantingAssembly as a friend somehow. bool q1 = assemblyGrantingAccessIdentity.IsStrongName; bool q2 = !grantedToPublicKey.IsDefaultOrEmpty; bool q3 = !assemblyWantingAccessKey.IsDefaultOrEmpty; bool q4 = (q2 & q3) && ByteSequenceComparer.Equals(grantedToPublicKey, assemblyWantingAccessKey); // Cases 2, 3, 7 and 8: if (q2 && !q4) { return(IVTConclusion.PublicKeyDoesntMatch); } // Cases 6 and 9: if (!q1 && q3) { return(IVTConclusion.OneSignedOneNot); } // Cases 1, 4, 5 and 10: return(IVTConclusion.Match); }
/// <summary> /// Compares the current content of this writer with another one. /// </summary> public bool ContentEquals(BlobWriter other) { return Length == other.Length && ByteSequenceComparer.Equals(_buffer, _start, other._buffer, other._start, Length); }