DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • How to Convert XLS to XLSX in Java
  • Issue and Present Verifiable Credentials With Spring Boot and Android
  • Thread-Safety Pitfalls in XML Processing
  • Loading XML into MongoDB

Trending

  • Traditional Testing and RAGAS: A Hybrid Strategy for Evaluating AI Chatbots
  • Distributed Consensus: Paxos vs. Raft and Modern Implementations
  • Navigating and Modernizing Legacy Codebases: A Developer's Guide to AI-Assisted Code Understanding
  • Tired of Spring Overhead? Try Dropwizard for Your Next Java Microservice
  1. DZone
  2. Coding
  3. Languages
  4. Why Enabling SHA256 Support for XML Signatures Breaks JWT Signing

Why Enabling SHA256 Support for XML Signatures Breaks JWT Signing

A developer describes a bug he ran into while trying to add authentication protocols to an application. Read on to see how he got around it!

By 
Anders Abel user avatar
Anders Abel
·
Jan. 08, 18 · Tutorial
Likes (1)
Comment
Save
Tweet
Share
6.5K Views

Join the DZone community and get the full member experience.

Join For Free

For some time, there have been bug reports to Kentor.AuthServices, IdentityServer3, and System.IdentityModel.Tokens.Jwt about enabling SHA256 XML signature support sometimes breaks JWT signing. It fails with an error of System.Security.Cryptography.CryptographicException: Invalid algorithm specified.

This has been one of those annoying bugs where everyone's solution works perfectly by itself but, when combined, they fail. I closed this issue in AuthServices with a comment that "works for us, has to be IdentityServer3/System.IdentityModel.Tokens doing something strange." I've finally had some time to look deeper into this thanks to IRM that asked me to do this as a consultancy service. Without someone paying for the time, it's hard to spend the hours needed to find the root cause of a problem like this. When I started out on this I looked at all three systems/components involved to try to understand what triggers the problem. I ended up fixing this in Kentor.AuthServices for now. The fix could also have been done in the .NET Framework, IdentityServer3 or System.IdentityModel.Tokens.Jwt. Doing it in Kentor.AuthServices was mostly a matter of convenience because I control it myself.

That means that the TL;DR of all of this is that if you update to Kentor.AuthServices 0.19.0 or later this problem is solved. If you're interested in how to solve it if you add SHA256 support yourself, please read on.

In .NET, crypto algorithms are held in a process-wide registry in System.Security.Cryptography.CryptoConfig. For SignedXml.CheckSignature there is no way to inject the configuration or do it non-application wide. SignedXml.CheckSignedInfo and Reference.CalculateHashValue both call CryptoConfig.CreateFromName to resolve the algorithms specified in the XML. So to enable support for more algorithms in SignedXml, they have to be added to CryptoConfig. It's promised that additional SHA versions will be included by default in .NET 4.6.2, but the release seems to be lagging behind schedule.

The problem with global registration is that it affects all users of the algorithm. In the case of SignedXml a common recommendation for adding SHA256 support is to register the existing System.Deployment.Internal.CodeSigning.RSAPKCS1SHA256SignatureDescription. This is was what I did for Kentor.AuthServices. It works perfectly fine for validating signatures. But it only works for creating signatures if the certificate used has the right CSP (Crypto Service Provider).

In .NET (and the underlying Win32 CryptoAPI) a private key of a certificate is tied to a Crypto Service Provider when loaded. The most commonly used Crypto Service Provider is type 1, PROV_RSA_FULL. Even though the .NET default is 24 which is PROV_RSA_AES. The commonly used PROV_RSA_FULL doesn't support SHA256. So to get SHA256 support two things are needed:

  • The SHA256 algorithm must be registered.
  • The private key from the certificate must be associated with a Crypto Service Provider that supports SHA256.

Getting both of these right is a bit hard, so the .NET Framework contains some magic to help. The System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler uses X509AsymmetricSecurityKey.GetSignatureFormatter to get a signature formatter that is used to sign the data. First, it looks among the registered algorithms. In the SHA256 case (which is the default algorithm for System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler) it is normally not found, so a fallback mechanism is activated. That fallback mechanism contains some serious magic that instantiates a SHA256 implementation and wraps the private key in a new RSACryptoServiceProvider associated with the PROV_RSA_AES Crypto Service Provider.

Having that magic in the fallback for when there is no registered SHA256 signature means that as soon as a SHA256 implementation is registered the magic is lost. I think that it is very confusing that it is the fallback mechanism that contains the magic. If there is to be any magic at all it should always be applied, both if a registered SHA256 implementation is found and if the fallback is used. Another option would be to clearly and early reject certificates with the wrong Crypto Service Provider.

But getting such a change into the .NET Framework would take more time than my customer is willing to accept. So I added the same magic to a custom SignatureDescription in Kentor.AuthServices.

This is the final working signature description that both enables SHA256 support for XML Signatures and contains the magic to change Crypto Service Providers when generating signatures.

/// <summary>
/// Crypto description for a Managed implementation of SHA256 signatures.
/// </summary>
public class ManagedSHA256SignatureDescription : SignatureDescription
{
    /// <summary>
    /// Ctor
    /// </summary>
    public ManagedSHA256SignatureDescription()
    {
        KeyAlgorithm = typeof(RSACryptoServiceProvider).FullName;
        DigestAlgorithm = typeof(SHA256Managed).FullName;
    }

    /// <summary>
    /// Create a deformatter
    /// </summary>
    /// <param name="key">Key</param>
    /// <returns>Deformatter</returns>
    public override AsymmetricSignatureDeformatter CreateDeformatter(AsymmetricAlgorithm key)
    {
        if (key == null)
        {
            throw new ArgumentNullException(nameof(key));
        }

        var df = new RSAPKCS1SignatureDeformatter(key);
        df.SetHashAlgorithm(typeof(SHA256Managed).FullName);
        return df;
    }

    /// <summary>
    /// Create a formatter
    /// </summary>
    /// <param name="key">Key</param>
    /// <returns>Formatter</returns>
    public override AsymmetricSignatureFormatter CreateFormatter(AsymmetricAlgorithm key)
    {
        if (key == null)
        {
            throw new ArgumentNullException(nameof(key));
        }

        var provider = (RSACryptoServiceProvider)key;

        // The provider is probably using the default ProviderType. That's
        // a problem, because it doesn't support SHA256. Let's do some
        // black magic and create a new provider of a type that supports
        // SHA256 without the user ever knowing we fix this. This is what 
        // is done in X509AsymmetricKey.GetSignatureFormatter if 
        // http://www.w3.org/2001/04/xmldsig-more#rsa-sha256 isn't
        // a known algorithm, so users kind of expect this to be handled
        // for them magically.

        var cspParams = new CspParameters();
        cspParams.ProviderType = 24; //PROV_RSA_AES
        cspParams.KeyContainerName = provider.CspKeyContainerInfo.KeyContainerName;
        cspParams.KeyNumber = (int)provider.CspKeyContainerInfo.KeyNumber;
        if (provider.CspKeyContainerInfo.MachineKeyStore)
        {
            cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
        }
        cspParams.Flags |= CspProviderFlags.UseExistingKey;

        provider = new RSACryptoServiceProvider(cspParams);

        var f = new RSAPKCS1SignatureFormatter(provider);
        f.SetHashAlgorithm(typeof(SHA256Managed).FullName);
        return f;
    }
}
XML JWT (JSON Web Token)

Published at DZone with permission of Anders Abel, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • How to Convert XLS to XLSX in Java
  • Issue and Present Verifiable Credentials With Spring Boot and Android
  • Thread-Safety Pitfalls in XML Processing
  • Loading XML into MongoDB

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!