Skip to content
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

MDS TOC header certficates and root certificate have changed and it's broken Fido2MetadataServiceRepository #224

Closed
mackie1001 opened this issue Apr 22, 2021 · 3 comments
Labels
enhancement Enhancements or general improvements

Comments

@mackie1001
Copy link
Contributor

mackie1001 commented Apr 22, 2021

I had put a note in my calendar to renew our access token this week as it's going to expire next week.

First challenge was actually renewing it (web site is broken) but thankfully Yuriy Ackermann saw my Google group post and forwarded a new one on but also dropped the bomb that the root cert has changed (and I'm guessing more besides given the error below)

This is what I get if I run 2.0.1 (similar on 1.x too):

fail: Access.Identity.Services.WebAuthn.DistributedCacheMetadataService[0]
      Error getting TOC from Fido2MetadataServiceRepository
System.ArgumentException: Could not parse X509 certificate.
 ---> System.ArgumentNullException: IDX10000: The parameter 'ecdsa' cannot be a 'null' or an empty object. (Parameter 'ecdsa')
   at Microsoft.IdentityModel.Tokens.ECDsaSecurityKey..ctor(ECDsa ecdsa)
   at Fido2NetLib.Fido2MetadataServiceRepository.GetECDsaPublicKey(String certString)
   --- End of inner exception stack trace ---
   at Fido2NetLib.Fido2MetadataServiceRepository.GetECDsaPublicKey(String certString)
   at Fido2NetLib.Fido2MetadataServiceRepository.<DeserializeAndValidateToc>b__13_1(String o)
   at System.Linq.Enumerable.SelectListIterator`2.ToArray()
   at Fido2NetLib.Fido2MetadataServiceRepository.DeserializeAndValidateToc(String rawTocJwt)
   at Fido2NetLib.Fido2MetadataServiceRepository.GetToc()
   at Identity.Services.WebAuthn.DistributedCacheMetadataService.InitializeClient(IMetadataRepository repository) in C:\Projects\Repos\Identity\src\Access.Identity.Services\WebAuthn\DistributedCacheMetadataService.cs:line 177

Having stepped through the code I can see that the new certs in the x5c header use RSA and not ECDsa but it's hard coded to call X509Certificate2.GetECDsaPublicKey()

I can hotfix this locally and we cache the MDS data (and fortunately in a way where it's easy to change the expiry time too) but this may bite others as they've already rolled out the changes to the TOC (on the 19th) and my current entries are cached until the 29th of April which is based on the NextUpdate value from the previous TOC.

The new root cert is here: https://secure.globalsign.com/cacert/root-r3.crt

I'll post a code snippet once I have I have proven it works.

@mackie1001
Copy link
Contributor Author

This is the revised function to get the public key from cert strings that comes from the x5c array - note the return type has changed to the base class:

        private SecurityKey GetPublicKey(string certString)
        {
            try
            {
                var certBytes = Convert.FromBase64String(certString);
                using (var cert = new X509Certificate2(certBytes))
                {
                    if (cert.PublicKey.Oid.Value == "1.2.840.113549.1.1.1") //RSA
                    {
                        var publicKey = cert.GetRSAPublicKey();
                        return new RsaSecurityKey(publicKey);
                    }
                    else //Fall back to ECDsa
                    {
                        var publicKey = cert.GetECDsaPublicKey();
                        return new ECDsaSecurityKey(publicKey);
                    }
                }
            }
            catch (Exception ex)
            {
                throw new ArgumentException("Could not parse X509 certificate.", ex);
            }
        }

And instead of using the const for the root cert I'm downloading it from the advertised URL:

        var rawRootCert = await DownloadDataAsync("https://secure.globalsign.com/cacert/root-r3.crt");
        var rootCert = new X509Certificate2(rawRootCert);

@mackie1001
Copy link
Contributor Author

In my local quick fix I actually embedded the root cert like the old implementation in the end.

@abergs abergs assigned abergs and unassigned abergs Apr 23, 2021
@abergs abergs added the enhancement Enhancements or general improvements label Apr 23, 2021
@aseigler
Copy link
Collaborator

aseigler commented May 3, 2021

Fixed by #225, thanks!

@aseigler aseigler closed this as completed May 3, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Enhancements or general improvements
Projects
None yet
Development

No branches or pull requests

3 participants