runtime: ExtendedProtectionPolicy constructor throws unnecessarily on WASM

Description

This was an issue discovered by a WCF customer. WCF tracking issue is dotnet/wcf#4942.

It’s not possible to construct an instance of ExtendedProtectionPolicy on WASM. This makes it impossible to have a public API expose this type unless you return null when running in a browser. ExtendedProtectionPolicy has the ability to have a policy enforcement that it is never used, which is appropriate for platforms where extended protection isn’t supported.

In addition to this problem, the property ExtendedProtectionPolicy.OSSupportsExtendedProtection always returns true with no regard to platform.

WCF exposes a property of type ExtendedProtectionPolicy to enable clients to optionally turn on the use of Extended Protection. The default value for this property is a policy where enforcement is disabled. This is constructed using this line of code:

        private static readonly ExtendedProtectionPolicy s_disabledPolicy = new ExtendedProtectionPolicy(PolicyEnforcement.Never);

In our property, when a new value is being set, we check if the new value has an enforcement policy set to Always, and if it is we check the value of ExtendedProtectionPolicy.OSSupportsExtendedProtection and throw if trying to set a policy which can’t be supported.

                if (value.PolicyEnforcement == PolicyEnforcement.Always &&
                    !System.Security.Authentication.ExtendedProtection.ExtendedProtectionPolicy.OSSupportsExtendedProtection)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        new PlatformNotSupportedException(SR.ExtendedProtectionNotSupported));
                }

If OSSupportsExtendedProtection were implemented to reflect whether extended protection, then this should be sufficient for apps to guard against trying to use extended protection where it’s not supported.

Throwing an exception on construction of a policy instance regardless of enforcement policy means all public properties need to return null where previously they didn’t. This changes a not null value to a sometimes null value. This also requires adding logic to interpret null to mean the same as PolicyEnforcement.Never and duplicating that logic change everywhere the instance propagates through the code base.

Reproduction Steps

In a Blazor app, create a new instance of BasicHttpBinding using the default constructor. It throws with a PlatformNotSupportedException stating “System.Net.Security is not supported on this platform.”

This was customer reported, but based on my understanding of how the throwing of an exception is generated, I suspect getting ExtendedProtectionPolicy.OSSupportsExtendedProtection will throw a PlatformNotSupportedException too instead of returning false.

Expected behavior

When constructing an instance with a PolicyEnforcement value of Never or WhenSupported will not throw. These classes are just OM around describing extended protection so I would expect an exception to only be thrown when a class which accepts an ExtendedProtectionPolicy is passed one with PolicyEnforcement.Always, as WCF does. In this case, the class would never throw.

This isn’t a new expectation; this is what happened on OS’s earlier than Win7 where extended protection isn’t supported.

Actual behavior

Constructing an ExtendedProtectionPolicy with any enforcement policy throws a PlatformNotSupportedException.

Regression?

Regression from .NET Framework and .NET Core outside of a browser. On .NET Framework, OS’s prior to Windows 7 didn’t support extended protection, and ExtendedProtectionPolicy.OSSupportsExtendedProtection would return false so that libraries and applications can avoid an exception being thrown by trying to use extended protection when it’s not supported. The same model should work for .NET too.

Known Workarounds

Add lots of ugly logic through the WCF code base treating null as PolicyEnforcement.Never. This could also cause consuming code to throw a NullReferenceException if expecting the property to return a non-null value as it does on every other platform.

Configuration

No response

Other information

No response

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 19 (18 by maintainers)

Commits related to this issue

Most upvoted comments

@ericstj @ViktorHofer - is there a way to generate PNSE stubs for all the code in an assembly, but still allow a “partial” implementation for one of the APIs? As above - if we want to return false for this static bool property, and have all the other code thrown PNSE.

It looks like ExtendedProtectionPolicy is part of System.Net.Security instead of System.Security.

I’m guessing it’s using an auto-generated PNSE on wasm. @mconnew 's suggestion of making the static supported property return false and the ctor not fail for Never/WhenSupported sounds reasonable to me.