e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
278 lines
9.8 KiB
C#
278 lines
9.8 KiB
C#
//------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//------------------------------------------------------------
|
|
namespace System.ServiceModel.Channels
|
|
{
|
|
using System;
|
|
using System.Collections;
|
|
using System.Threading;
|
|
using System.Net;
|
|
using System.Net.Security;
|
|
using System.Runtime;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Runtime.ConstrainedExecution;
|
|
using System.Runtime.InteropServices;
|
|
using System.Security;
|
|
using System.Security.Authentication.ExtendedProtection;
|
|
using System.Security.Authentication.ExtendedProtection.Configuration;
|
|
|
|
static class ChannelBindingUtility
|
|
{
|
|
static ExtendedProtectionPolicy disabledPolicy = new ExtendedProtectionPolicy(PolicyEnforcement.Never);
|
|
static ExtendedProtectionPolicy defaultPolicy = disabledPolicy;
|
|
|
|
public static ExtendedProtectionPolicy DisabledPolicy
|
|
{
|
|
get
|
|
{
|
|
return disabledPolicy;
|
|
}
|
|
}
|
|
|
|
public static ExtendedProtectionPolicy DefaultPolicy
|
|
{
|
|
get
|
|
{
|
|
return defaultPolicy;
|
|
}
|
|
}
|
|
|
|
public static bool IsDefaultPolicy(ExtendedProtectionPolicy policy)
|
|
{
|
|
return Object.ReferenceEquals(policy, defaultPolicy);
|
|
}
|
|
|
|
public static void CopyFrom(ExtendedProtectionPolicyElement source, ExtendedProtectionPolicyElement destination)
|
|
{
|
|
destination.PolicyEnforcement = source.PolicyEnforcement;
|
|
destination.ProtectionScenario = source.ProtectionScenario;
|
|
destination.CustomServiceNames.Clear();
|
|
foreach (ServiceNameElement sourceEntry in source.CustomServiceNames)
|
|
{
|
|
ServiceNameElement entry = new ServiceNameElement();
|
|
entry.Name = sourceEntry.Name;
|
|
destination.CustomServiceNames.Add(entry);
|
|
}
|
|
}
|
|
|
|
public static void InitializeFrom(ExtendedProtectionPolicy source, ExtendedProtectionPolicyElement destination)
|
|
{
|
|
if (!IsDefaultPolicy(source))
|
|
{
|
|
destination.PolicyEnforcement = source.PolicyEnforcement;
|
|
destination.ProtectionScenario = source.ProtectionScenario;
|
|
destination.CustomServiceNames.Clear();
|
|
|
|
if (source.CustomServiceNames != null)
|
|
{
|
|
foreach (string name in source.CustomServiceNames)
|
|
{
|
|
ServiceNameElement entry = new ServiceNameElement();
|
|
entry.Name = name;
|
|
destination.CustomServiceNames.Add(entry);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static ExtendedProtectionPolicy BuildPolicy(ExtendedProtectionPolicyElement configurationPolicy)
|
|
{
|
|
//using this pattern allows us to have a different default policy
|
|
//than the NCL team chooses.
|
|
if (configurationPolicy.ElementInformation.IsPresent)
|
|
{
|
|
return configurationPolicy.BuildPolicy();
|
|
}
|
|
else
|
|
{
|
|
return ChannelBindingUtility.DefaultPolicy;
|
|
}
|
|
}
|
|
|
|
public static ChannelBinding GetToken(SslStream stream)
|
|
{
|
|
return GetToken(stream.TransportContext);
|
|
}
|
|
|
|
public static ChannelBinding GetToken(TransportContext context)
|
|
{
|
|
ChannelBinding token = null;
|
|
if (context != null)
|
|
{
|
|
token = context.GetChannelBinding(ChannelBindingKind.Endpoint);
|
|
}
|
|
return token;
|
|
}
|
|
|
|
public static ChannelBinding DuplicateToken(ChannelBinding source)
|
|
{
|
|
if (source == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return DuplicatedChannelBinding.CreateCopy(source);
|
|
}
|
|
|
|
public static void TryAddToMessage(ChannelBinding channelBindingToken, Message message, bool messagePropertyOwnsCleanup)
|
|
{
|
|
if (channelBindingToken != null)
|
|
{
|
|
ChannelBindingMessageProperty property = new ChannelBindingMessageProperty(channelBindingToken, messagePropertyOwnsCleanup);
|
|
property.AddTo(message);
|
|
property.Dispose(); //message.Properties.Add() creates a copy...
|
|
}
|
|
}
|
|
|
|
//does not validate the ExtendedProtectionPolicy.CustomServiceNames collections on the policies
|
|
public static bool AreEqual(ExtendedProtectionPolicy policy1, ExtendedProtectionPolicy policy2)
|
|
{
|
|
Fx.Assert(policy1 != null, "policy1 param cannot be null");
|
|
Fx.Assert(policy2 != null, "policy2 param cannot be null");
|
|
|
|
if (policy1.PolicyEnforcement == PolicyEnforcement.Never && policy2.PolicyEnforcement == PolicyEnforcement.Never)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (policy1.PolicyEnforcement != policy2.PolicyEnforcement)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (policy1.ProtectionScenario != policy2.ProtectionScenario)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (policy1.CustomChannelBinding != policy2.CustomChannelBinding)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public static bool IsSubset(ServiceNameCollection primaryList, ServiceNameCollection subset)
|
|
{
|
|
bool result = false;
|
|
if (subset == null || subset.Count == 0)
|
|
{
|
|
result = true;
|
|
}
|
|
else if (primaryList == null || primaryList.Count < subset.Count)
|
|
{
|
|
result = false;
|
|
}
|
|
else
|
|
{
|
|
ServiceNameCollection merged = primaryList.Merge(subset);
|
|
|
|
//The merge routine only adds an entry if it is unique.
|
|
result = (merged.Count == primaryList.Count);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public static void Dispose(ref ChannelBinding channelBinding)
|
|
{
|
|
// Explicitly cast to IDisposable to avoid the SecurityException.
|
|
IDisposable disposable = (IDisposable)channelBinding;
|
|
channelBinding = null;
|
|
if (disposable != null)
|
|
{
|
|
disposable.Dispose();
|
|
}
|
|
}
|
|
|
|
class DuplicatedChannelBinding : ChannelBinding
|
|
{
|
|
[Fx.Tag.SecurityNote(Critical = "Used when referencing raw native memory")]
|
|
[SecurityCritical]
|
|
int size;
|
|
|
|
DuplicatedChannelBinding()
|
|
{
|
|
|
|
}
|
|
|
|
public override int Size
|
|
{
|
|
[Fx.Tag.SecurityNote(Critical = "Used when referencing raw native memory",
|
|
Safe = "All inputs are validated during initization")]
|
|
[SecuritySafeCritical]
|
|
get { return this.size; }
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Invokes unsafe code.",
|
|
Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")]
|
|
[SecuritySafeCritical]
|
|
internal static ChannelBinding CreateCopy(ChannelBinding source)
|
|
{
|
|
Fx.Assert(source != null, "source ChannelBinding should have been checked for null previously");
|
|
|
|
if (source.IsInvalid || source.IsClosed)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ObjectDisposedException(source.GetType().FullName));
|
|
}
|
|
|
|
if (source.Size <= 0)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("source.Size", source.Size,
|
|
SR.GetString(SR.ValueMustBePositive)));
|
|
}
|
|
|
|
//Instantiate the SafeHandle before trying to allocate the native memory
|
|
DuplicatedChannelBinding duplicate = new DuplicatedChannelBinding();
|
|
|
|
//allocate the native memory and make a deep copy of the original.
|
|
duplicate.Initialize(source);
|
|
|
|
return duplicate;
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Contains unsafe code.")]
|
|
[SecurityCritical]
|
|
unsafe void Initialize(ChannelBinding source)
|
|
{
|
|
//allocates the memory pointed to by this.handle
|
|
//and sets this.size after allocation succeeds.
|
|
AllocateMemory(source.Size);
|
|
|
|
byte* sourceBuffer = (byte*)source.DangerousGetHandle().ToPointer();
|
|
byte* destinationBuffer = (byte*)this.handle.ToPointer();
|
|
|
|
for (int i = 0; i < source.Size; i++)
|
|
{
|
|
destinationBuffer[i] = sourceBuffer[i];
|
|
}
|
|
|
|
this.size = source.Size;
|
|
}
|
|
|
|
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
|
void AllocateMemory(int bytesToAllocate)
|
|
{
|
|
Fx.Assert(bytesToAllocate > 0, "bytesToAllocate must be positive");
|
|
|
|
//this protects us from problems like an appdomain shutdown occuring
|
|
//after allocating the native memory but before the handle gets set (which would result in a memory leak)
|
|
RuntimeHelpers.PrepareConstrainedRegions();
|
|
try { }
|
|
finally
|
|
{
|
|
base.SetHandle(Marshal.AllocHGlobal(bytesToAllocate));
|
|
}
|
|
}
|
|
|
|
protected override bool ReleaseHandle()
|
|
{
|
|
Marshal.FreeHGlobal(this.handle);
|
|
base.SetHandle(IntPtr.Zero);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|