New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
API proposal: DSA.IsSupported
property
#53017
Comments
Tagging subscribers to this area: @bartonjs, @vcsjones, @krwq, @GrabYourPitchforks Issue DetailsBackground and MotivationNewly added AEAD cryptographic algorithm classes in .NET have the With the addition of new platforms in .NET 6 some of the old cryptographic algorithms, specifically DSA, are no longer available on all the platforms. iOS, tvOS and Mac Catalyst don't support or implement the DSA algorithm. APIs like It would be useful to offer a way to detect platforms where DSA algorithm is not supported without having to call Proposed APInamespace System.Security.Cryptography.Algorithms
{
public abstract partial class DSA : AsymmetricAlgorithm
{
+ public static bool IsSupported { get; }
}
} with implementation similar to: namespace System.Security.Cryptography.Algorithms
{
public abstract partial class DSA : AsymmetricAlgorithm
{
+ [UnsupportedOSPlatformGuard("ios")]
+ [UnsupportedOSPlatformGuard("tvos")]
+ [UnsupportedOSPlatformGuard("maccatalyst")]
+ public static bool IsSupported => !OperatingSystem.IsIOS() && !OperatingSystem.IsTvOS() && !OperatingSystem.IsMacCatalyst();
}
} Usage ExamplesGuard DSA specific code paths: return keyAlgorithm switch
{
Oids.Rsa => ...,
Oids.Dsa when DSA.IsSupported => ...,
Oids.EcPublicKey when IsECDsa(certificate) => ...,
Oids.EcPublicKey when IsECDiffieHellman(certificate) => ...,
_ => throw new CryptographicException(SR.Format(SR.Cryptography_UnknownKeyAlgorithm, keyAlgorithm)),
}; Loading PKCS blobs (example inspired by #52758): private AsymmetricAlgorithm LoadAnything(ReadOnlySpan<byte> data)
{
DSA dsa = DSA.Create();
ECDsa ecdsa = ECDsa.Create();
try
{
RSA rsa = RSA.Create();
rsa.ImportPkcs8PrivateKey(data, out _);
return rsa;
}
catch (CryptographicException)
{
}
// repeat for ECDsa
if (DSA.IsSupported)
{
try
{
DSA rsa = DSA.Create();
dsa.ImportPkcs8PrivateKey(data, out _);
return dsa;
}
catch (CryptographicException)
{
}
}
// fail
} Alternative DesignsDon't add the Risks
|
Sounds reasonable to me however we might want to actually add @bartonjs what do you think? |
One thing the This is fixable by shadowing the namespace System.Security.Cryptography
{
public sealed partial class DSACng : DSA
{
+ public static new bool IsSupported { get; }
}
public sealed partial class DSAOpenSsl : DSA
{
+ public static new bool IsSupported { get; }
}
} |
@vcsjones That's an excellent point. The problem is that there could be custom implementations outside of the .NET Runtime which would not be aware of this and would not get the shadowing treatment. I am not sure how to approach that. I actually intended to supply a managed DSA implementation as a compatibility shim that would be consumable as a NuGet. |
Yeah, that problem already exists with the My 2 cents: it's fine to add a new API that implementors will have to shadow if they want it to behave correctly for their implementation. In that respect it's similar to adding a new But we should add this for the platform specific types if we decide to add it to the bases. |
Do we have a critical mass of applications using DSA such that this property would actually be useful? DSA is effectively a dead algorithm. The reason we added an IsSupported property to algorithms like |
@vcsjones You actually made me realize that the shadowed properties could be useful for determining if alternate implementation is available. I would be able to check for @GrabYourPitchforks I agree it's effectively a dead algorithm but it's also one that still has widespread legacy use because of protocols that used it for signing of stored content. PGP introduced it around 1998 as the preferred algorithm with the second revision of OpenPGP specification. S/MIME (PKCS #7) also supports it as one of the signing algorithms although it never gained such prominence there. For OpenPGP I maintain my toy implementation at https://github.com/1hub/springburg. It's essentially heavily rewritten version of BouncyCastle OpenPGP code with some improvements to API which uses native .NET cryptography classes where possible. DSA is already broken on macOS where it fails nearly every test (with exception of 1024 bit keys). If I were to support iOS I would have to offer some fallback, possibly to a naïve managed implementation or optionally to OpenSSL bundled with the application. A static property could make my life easier if I could write S/MIME is implemented in the System.Security.Cryptography.Pkcs assembly. Based on my PR #52978 that annotates the code with It's likely that any high-level protocol based on similar patterns as OpenPGP and S/MIME will have similar incidence of the number of checks (single digit number of checks in implementation, few dozen in unit tests). I came up with the proposal because the experience with annotating the existing high-level code made me believe that it's something that will come up even in 3rd-party code. If the assumption is that the set of platforms supporting or not supporting DSA would not change then it may not be worth it. However, it may happen that some platforms drop support for DSA in future versions (macOS already fails to support it in number of newer APIs) and then the property would start to depend on OS version in addition to set of supported platforms. Similar situation could happen on browser target where DSA is not supported today. It may eventually get implemented (PRs using SubtleCrypto and shared array buffers are already there, other experiments are underway) but be supported only on certain browsers (eg. everything but Safari). |
But in your scenarios, you're not falling back to an alternative algorithm. You're either calling into your own custom implementation (which you could just do anyway), or you're skipping the operation entirely (in the case of a unit test), or you're failing the operation entirely (in the case of OpenPGP mandating using DSA for some operation). None of these scenarios requires an IsSupported property. And for the latter two scenarios, since you're already bringing in your own custom DSA implementation, you could call it directly and bypass the built-in implementation entirely. What value does IsSupported add here that I'm missing? |
Alternatively, what if we allowed you to utilize |
It offers a way to determine whether (I don't necessarily want to ship alternate DSA implementation under the same principle that I don't want to write my own crypto but something like fallback to
I was toying with the idea myself. It MAY work. The tricky part is to ensure that it is linker friendly since |
But I keep coming back to "why?" In the scenarios you've laid out, you're not calling into DSA for fun. You're calling into it because you need it. Which means one of two things: you're either going to fail if it doesn't work, at which point IsSupported isn't buying you much; or you're going to fall back to your own known-good-works-everywhere implementation, at which point since you're carrying along such an implementation you may as well skip IsSupported and just call your implementation directly. I'm not seeing that the existence of an IsSupported property enables you to do something that you can't already do today. |
For example, code like this: Lines 15 to 25 in c663d2a
It never actually calls Hard-coding the check to |
Ok, I understand your scenario now. Thanks for the patience. :) |
Thanks for bearing with me. I know that this may not meet the bar for consideration given the legacy nature of the algorithm. It's kinda the opposite concern than the AEAD
but it has some overhead. |
The "inherited" nature of static properties does make |
I see where the usefulness comes from, but don't really think it's a good idea.
IsSupported is mostly useful when you have options. "I'm encrypting new data, I want to use AES-GCM if it's available (and I promise I know what I'm doing. What's nonce reuse? What? How do I? Oh, maybe I shouldn't... OK), and if not then I'll fall back to AES-CBC-PKCS#7+HMAC-SHA256, and leave an algorithm flavor marker in the data. If you're creating new signatures, you're probably not using DSA. If you are, you probably didn't have another choice, so it's just do or do not, there is no IsSupported check. Now, when you're reading the data back, if it says to use AES-GCM you can check IsSupported to get a clear statement of why you need to present a particular error message, or you can just let the exception bleed through, or you can catch it... but no matter what, you will not get to read your message today. It's just variations on "fail". If not for the static bleed-through thing, I'd probably just shrug. But, I do think that the IsSupported is only useful for "this is too new, it's not available yet" (you can't have your first choice). When the algorithm has been forced on you there's almost no benefit in checking it. |
Algorithms like |
They actually don't. There's |
That's something I originally didn't think about and that makes me want to abandon the proposal. On the other hand it would be useful to have In general I would be interested in a mechanism for polyfill like @GrabYourPitchforks mentioned.
I actually did notice and it's one of the reasons why my company still ships BouncyCastle despite my dislike of it (ref: 1hub/springburg#16). I don't particularly care about DSA key creation since that's something actionable (ie. don't let user do it) but I work with data already signed by large DSA keys and that's problematic. I never bothered to rise an issue about it because there's really not much that can be done. As long as you rely on the OS provided cryptography implementation the macOS implementation of DSA is FUBAR. It's FIPS 186-2-only and barely passable at that. Would it help me to know that it's FIPS 186-2-only? Not really since there's nothing to fallback to short of shipping my own DSA implementation which is what I wanted to avoid in the first place. The best I could achieve would be better error than The At the end of the day I am afraid I would still need to provide an optional polyfill DSA implementation whether .NET implements a generic polyfill mechanism or whether I have to do it myself at the library level. |
Background and Motivation
Newly added AEAD cryptographic algorithm classes in .NET have the
IsSupported
property that can be used to determine whether a platform supports particular algorithm or not. This was approved in the ChaCha20Poly1305 API proposal (#45130) and also added toAesGcm
andAesCcm
classes to maintain API symmetry.With the addition of new platforms in .NET 6 some of the old cryptographic algorithms, specifically DSA, are no longer available on all the platforms. iOS, tvOS and Mac Catalyst don't support or implement the DSA algorithm. APIs like
DSA.Create
methods now throwPlatformNotSupportedException
(Issue #52758, PR #52978) on these platforms.It would be useful to offer a way to detect platforms where DSA algorithm is not supported without having to call
DSA.Create
and checking for an exception.Proposed API
namespace System.Security.Cryptography.Algorithms { public abstract partial class DSA : AsymmetricAlgorithm { + public static bool IsSupported { get; } } }
with implementation similar to:
Usage Examples
Guard DSA specific code paths:
Use specific condition in unit tests:
Alternative Designs
Don't add the
IsSupported
property, expect consumers of the API to catchPlatformNotSupportedException
and to rely on platform compatibility analyzer. This is feasible until we hit another platform where DSA is not supported. Since the algorithm is effectively deprecated by NIST in FIPS 186-5 it's possible that some existing platforms may actually drop the support for the algorithm in future.Don't add the
IsSupported
property, expect consumers to callCryptoConfig.CreateFromName("DSA")
instead which is non-throwing. It returnsnull
on non-supported platforms.CryptoConfig
is not very linker friendly though. It also always creates an instance of theDSA
object on supported platforms which may not be desired for particular use case.Risks
The text was updated successfully, but these errors were encountered: