Kerberos.NET icon indicating copy to clipboard operation
Kerberos.NET copied to clipboard

Tests: using platform-dependent crypto

Open 0x5ECF4ULT opened this issue 2 years ago • 8 comments

Describe the bug Tests.Kerberos.NET runs a few tests using unsupported crypto. The problem is that this makes the tests platform-dependent. This issue documents problematic operations.

To Reproduce Please watch #334. Ported tests dropping soon-ish(tm).

Expected behavior Varies. I expect a perfectly fine test to succeed. Some tests are supposed to fail but aren't covered.

Additional context Bug found in the course of porting the tests to Linux.

0x5ECF4ULT avatar Feb 27 '23 20:02 0x5ECF4ULT

This is the stacktrace for RestrictionType_ApOptions. The culprit lies in a ticket containing delegation.

System.PlatformNotSupportedException: A crypto implementation of MD4 does not exist for Unix
    at Kerberos.NET.Crypto.CryptoPal.PlatformNotSupported(String algorithm) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Crypto/Pal/CryptoPal.cs:line 95
   at Kerberos.NET.Crypto.LinuxCryptoPal.Md4() in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Crypto/Pal/Linux/LinuxCryptoPal.cs:line 22
   at Kerberos.NET.Crypto.RC4Transformer.MD4(ReadOnlyMemory`1 key) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Crypto/RC4/RC4Transformer.cs:line 168
   at Kerberos.NET.Crypto.RC4Transformer.String2Key(KerberosKey key) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Crypto/RC4/RC4Transformer.cs:line 38
   at Kerberos.NET.Crypto.KerberosKey.<>c__DisplayClass45_0.<GetKey>b__0(EncryptionType etype) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Crypto/KerberosKey.cs:line 224
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Kerberos.NET.Crypto.KerberosKey.GetKey(KerberosCryptoTransformer transformer) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Crypto/KerberosKey.cs:line 224
   at Kerberos.NET.Crypto.RC4Transformer.Decrypt(ReadOnlyMemory`1 ciphertext, KerberosKey key, KeyUsage usage) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Crypto/RC4/RC4Transformer.cs:line 82
   at Kerberos.NET.Entities.KrbEncryptedData.Decrypt[T](KerberosKey key, KeyUsage usage, Func`2 func) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Entities/Krb/KrbEncryptedData.cs:line 37
   at Kerberos.NET.Crypto.DecryptedKrbApReq.Decrypt(KerberosKey ticketEncryptingKey) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Crypto/DecryptedKrbApReq.cs:line 75
   at Kerberos.NET.Crypto.DecryptedKrbApReq.Decrypt(KeyTable keytab) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Crypto/DecryptedKrbApReq.cs:line 70
   at Kerberos.NET.Entities.ContextToken.DecryptApReq(KrbApReq token, KeyTable keytab) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Entities/SpNego/ContextToken.cs:line 35
   at Kerberos.NET.Entities.KerberosContextToken.DecryptApReq(KeyTable keys) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Entities/SpNego/KerberosContextToken.cs:line 26
   at Kerberos.NET.Entities.NegotiateContextToken.DecryptApReq(KeyTable keys) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Entities/SpNego/NegotiateContextToken.cs:line 42
   at Kerberos.NET.KerberosValidator.Validate(ReadOnlyMemory`1 requestBytes) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/KerberosValidator.cs:line 70
   at Kerberos.NET.KerberosAuthenticator.Authenticate(ReadOnlyMemory`1 token) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/KerberosAuthenticator.cs:line 73
   at Kerberos.NET.KerberosAuthenticator.Authenticate(Byte[] token) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/KerberosAuthenticator.cs:line 69
   at Tests.Kerberos.NET.AuthorizationsTests.GenerateAuthZ() in /home/.../RiderProjects/Kerberos.NET/Tests/Tests.Kerberos.NET/KrbApReq/AuthorizationsTests.cs:line 27
   at Tests.Kerberos.NET.AuthorizationsTests.RestrictionType_ApOptions() in /home/.../RiderProjects/Kerberos.NET/Tests/Tests.Kerberos.NET/KrbApReq/AuthorizationsTests.cs:line 113

0x5ECF4ULT avatar Feb 27 '23 20:02 0x5ECF4ULT

Inside the testdata there is a certificate called testuser.pfx. This test should not fail on a system that doesn't support the used crypto.

System.PlatformNotSupportedException: A crypto implementation of DH-MODP-14 does not exist for Unix
    at Kerberos.NET.Crypto.CryptoPal.PlatformNotSupported(String algorithm) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Crypto/Pal/CryptoPal.cs:line 95
   at Kerberos.NET.Crypto.LinuxCryptoPal.DiffieHellmanModp14() in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Crypto/Pal/Linux/LinuxCryptoPal.cs:line 55
   at Kerberos.NET.Credentials.KerberosAsymmetricCredential.StartKeyAgreement() in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Credentials/KerberosAsymmetricCredential.cs:line 131
   at Kerberos.NET.Credentials.KerberosAsymmetricCredential.TransformKdcReq(KrbKdcReq req) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Credentials/KerberosAsymmetricCredential.cs:line 203
   at Kerberos.NET.Entities.KrbAsReq.CreateAsReq(KerberosCredential credential, AuthenticationOptions options) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Entities/Krb/KrbAsReq.cs:line 78
   at Kerberos.NET.Client.KerberosClient.RequestTgt(KerberosCredential credential) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Client/KerberosClient.cs:line 1194
   at Kerberos.NET.Client.KerberosClient.AuthenticateCredential(KerberosCredential credential) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Client/KerberosClient.cs:line 374
   at Kerberos.NET.Client.KerberosClient.Authenticate(KerberosCredential credential) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Client/KerberosClient.cs:line 357
   at Tests.Kerberos.NET.KdcListenerTestBase.RequestAndValidateTicketsWithCaches(KdcListener listener, String user, String password, String overrideKdc, KeyTable keytab, String s4u, Boolean encodeNego, Boolean caching, Boolean includePac, X509Certificate2 cert, String spn, KeyAgreementAlgorithm keyAgreement, Boolean allowWeakCrypto, Boolean useWeakCrypto, Boolean mutualAuth, KrbTicket s4uTicket, Boolean useKrb5TicketCache) in /home/.../RiderProjects/Kerberos.NET/Tests/Tests.Kerberos.NET/End2End/KdcListenerTestBase.cs:line 229
   at Tests.Kerberos.NET.KdcListenerTestBase.RequestAndValidateTickets(KdcListener listener, String user, String password, String overrideKdc, KeyTable keytab, String s4u, Boolean encodeNego, Boolean caching, Boolean includePac, X509Certificate2 cert, String spn, KeyAgreementAlgorithm keyAgreement, Boolean allowWeakCrypto, Boolean useWeakCrypto, Boolean mutualAuth, KrbTicket s4uTicket) in /home/.../RiderProjects/Kerberos.NET/Tests/Tests.Kerberos.NET/End2End/KdcListenerTestBase.cs:line 134
   at Tests.Kerberos.NET.ClientToKdcE2ETests.E2E_PKINIT() in /home/.../RiderProjects/Kerberos.NET/Tests/Tests.Kerberos.NET/End2End/ClientToKdcE2ETests.cs:line 106

The same problem applies to E2E_PKINIT_Modp2_Fails, E2E_PKINIT_Synchronous and AsReqPreAuth_PkinitCertificateAccessible.

0x5ECF4ULT avatar Feb 27 '23 20:02 0x5ECF4ULT

Another location is in NdrTests.cs, where tests using either GeneratePacContainingClaims or GeneratePacWithoutClaims through GeneratePac fail. Here is an example stacktrace for NdrLogonInfoRoundtrip:

System.PlatformNotSupportedException: A crypto implementation of MD4 does not exist for Unix
    at Kerberos.NET.Crypto.CryptoPal.PlatformNotSupported(String algorithm) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Crypto/Pal/CryptoPal.cs:line 95
   at Kerberos.NET.Crypto.LinuxCryptoPal.Md4() in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Crypto/Pal/Linux/LinuxCryptoPal.cs:line 22
   at Kerberos.NET.Crypto.RC4Transformer.MD4(ReadOnlyMemory`1 key) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Crypto/RC4/RC4Transformer.cs:line 168
   at Kerberos.NET.Crypto.RC4Transformer.String2Key(KerberosKey key) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Crypto/RC4/RC4Transformer.cs:line 38
   at Kerberos.NET.Crypto.KerberosKey.<>c__DisplayClass45_0.<GetKey>b__0(EncryptionType etype) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Crypto/KerberosKey.cs:line 224
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Kerberos.NET.Crypto.KerberosKey.GetKey(KerberosCryptoTransformer transformer) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Crypto/KerberosKey.cs:line 224
   at Kerberos.NET.Crypto.RC4Transformer.Decrypt(ReadOnlyMemory`1 ciphertext, KerberosKey key, KeyUsage usage) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Crypto/RC4/RC4Transformer.cs:line 82
   at Kerberos.NET.Entities.KrbEncryptedData.Decrypt[T](KerberosKey key, KeyUsage usage, Func`2 func) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Entities/Krb/KrbEncryptedData.cs:line 37
   at Kerberos.NET.Crypto.DecryptedKrbApReq.Decrypt(KerberosKey ticketEncryptingKey) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Crypto/DecryptedKrbApReq.cs:line 75
   at Kerberos.NET.Crypto.DecryptedKrbApReq.Decrypt(KeyTable keytab) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Crypto/DecryptedKrbApReq.cs:line 70
   at Kerberos.NET.Entities.ContextToken.DecryptApReq(KrbApReq token, KeyTable keytab) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Entities/SpNego/ContextToken.cs:line 35
   at Kerberos.NET.Entities.KerberosContextToken.DecryptApReq(KeyTable keys) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Entities/SpNego/KerberosContextToken.cs:line 26
   at Kerberos.NET.Entities.NegotiateContextToken.DecryptApReq(KeyTable keys) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/Entities/SpNego/NegotiateContextToken.cs:line 42
   at Kerberos.NET.KerberosValidator.Validate(ReadOnlyMemory`1 requestBytes) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/KerberosValidator.cs:line 70
   at Kerberos.NET.KerberosValidator.Validate(Byte[] requestBytes) in /home/.../RiderProjects/Kerberos.NET/Kerberos.NET/KerberosValidator.cs:line 58
   at Tests.Kerberos.NET.NdrTests.GeneratePacContainingClaims() in /home/.../RiderProjects/Kerberos.NET/Tests/Tests.Kerberos.NET/Pac/NdrTests.cs:line 66
   at Tests.Kerberos.NET.NdrTests.GeneratePac(Boolean includeClaims) in /home/.../RiderProjects/Kerberos.NET/Tests/Tests.Kerberos.NET/Pac/NdrTests.cs:line 42
   at Tests.Kerberos.NET.NdrTests.NdrLogonInfoRoundtrip() in /home/.../RiderProjects/Kerberos.NET/Tests/Tests.Kerberos.NET/Pac/NdrTests.cs:line 197

0x5ECF4ULT avatar Feb 27 '23 20:02 0x5ECF4ULT

We have a bug tracking the request to change these values. It hasn't been a high priority unfortunately. https://github.com/dotnet/Kerberos.NET/issues/148

SteveSyfuhs avatar Feb 27 '23 20:02 SteveSyfuhs

Is it okay to keep this issue open to document the creds in question?

0x5ECF4ULT avatar Feb 27 '23 21:02 0x5ECF4ULT

Oh, yes, definitely.

SteveSyfuhs avatar Feb 27 '23 21:02 SteveSyfuhs

I'll join the problem. KerberosKey generation also does not work for me in Linux. Framework: .Net 8 OS: Alpine 3.19 in Container

I'm trying to generate a key using:

            var keys = new[] {
                  new KerberosKey(
             "P@ssw0rd*",
             new PrincipalName(PrincipalNameType.NT_PRINCIPAL, "DOMAIN.SRV", new[] { "HTTP/SERVER.domain.srv" }),
             host: "SERVER.domain.srv",
             etype: EncryptionType.AES128_CTS_HMAC_SHA1_96)};
             var krb = new KerberosAuthenticator(new KerberosValidator(keys[0]));
             var identity = krb.Authenticate(authHeader[0].Replace("Negotiate ", ""));

Then I get the same error:

{System.PlatformNotSupportedException: A crypto implementation of MD4 does not exist for Unix
   at Kerberos.NET.Crypto.CryptoPal.PlatformNotSupported(String algorithm) in D:\a\1\s\Kerberos.NET\Crypto\Pal\CryptoPal.cs:line 95
   at Kerberos.NET.Crypto.LinuxCryptoPal.Md4() in D:\a\1\s\Kerberos.NET\Crypto\Pal\Linux\LinuxCryptoPal.cs:line 22
   at Kerberos.NET.Crypto.RC4Transformer.MD4(ReadOnlyMemory`1 key) in D:\a\1\s\Kerberos.NET\Crypto\RC4\RC4Transformer.cs:line 168
   at Kerberos.NET.Crypto.RC4Transformer.String2Key(KerberosKey key) in D:\a\1\s\Kerberos.NET\Crypto\RC4\RC4Transformer.cs:line 38
   at Kerberos.NET.Crypto.KerberosKey.<>c__DisplayClass45_0.<GetKey>b__0(EncryptionType etype) in D:\a\1\s\Kerberos.NET\Crypto\KerberosKey.cs:line 224
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Kerberos.NET.Crypto.KerberosKey.GetKey(KerberosCryptoTransformer transformer) in D:\a\1\s\Kerberos.NET\Crypto\KerberosKey.cs:line 224
   at Kerberos.NET.Crypto.RC4Transformer.Decrypt(ReadOnlyMemory`1 ciphertext, KerberosKey key, KeyUsage usage) in D:\a\1\s\Kerberos.NET\Crypto\RC4\RC4Transformer.cs:line 82
   at Kerberos.NET.Entities.KrbEncryptedData.Decrypt[T](KerberosKey key, KeyUsage usage, Func`2 func) in D:\a\1\s\Kerberos.NET\Entities\Krb\KrbEncryptedData.cs:line 34
   at Kerberos.NET.Crypto.DecryptedKrbApReq.Decrypt(KerberosKey ticketEncryptingKey) in D:\a\1\s\Kerberos.NET\Crypto\DecryptedKrbApReq.cs:line 75
   at Kerberos.NET.Crypto.DecryptedKrbApReq.Decrypt(KeyTable keytab) in D:\a\1\s\Kerberos.NET\Crypto\DecryptedKrbApReq.cs:line 70
   at Kerberos.NET.Entities.ContextToken.DecryptApReq(KrbApReq token, KeyTable keytab) in D:\a\1\s\Kerberos.NET\Entities\SpNego\ContextToken.cs:line 43
   at Kerberos.NET.Entities.KerberosContextToken.DecryptApReq(KeyTable keys) in D:\a\1\s\Kerberos.NET\Entities\SpNego\KerberosContextToken.cs:line 38
   at Kerberos.NET.Entities.NegotiateContextToken.DecryptApReq(KeyTable keys) in D:\a\1\s\Kerberos.NET\Entities\SpNego\NegotiateContextToken.cs:line 38
   at Kerberos.NET.KerberosValidator.Validate(ReadOnlyMemory`1 requestBytes) in D:\a\1\s\Kerberos.NET\KerberosValidator.cs:line 70
   at Kerberos.NET.KerberosAuthenticator.Authenticate(ReadOnlyMemory`1 token) in D:\a\1\s\Kerberos.NET\KerberosAuthenticator.cs:line 73
   at Kerberos.NET.KerberosAuthenticator.Authenticate(Byte[] token) in D:\a\1\s\Kerberos.NET\KerberosAuthenticator.cs:line 69
   at Kerberos.NET.KerberosAuthenticator.Authenticate(String token) in D:\a\1\s\Kerberos.NET\KerberosAuthenticator.cs:line 65
   at TestKerberos2.MiddleWare.Invoke(HttpContext context) in C:\Users\user\source\repos\TestKerberos2\TestKerberos2\MiddleWare.cs:line 45}

In this case, decryption of tickets using keytab is successful.

I tried to revert MD4 to Unix myself, but it didn't help:

  1. Installed the openssl package
  2. Applied the fix from the article https://github.com/dotnet/runtime/issues/67353#issuecomment-1085003764

If my problem is not related to the current one, I can create a separate issuse.

devagleo avatar Apr 04 '24 08:04 devagleo

There is no Linux implementation of MD4. It pinvokes Windows APIs only. You shouldn't be using the RC4/MD4 suite for anything anyway. Your app should be configured to use AES instead.


From: Ivan @.> Sent: Wednesday, April 3, 2024 10:18:33 PM To: dotnet/Kerberos.NET @.> Cc: Comment @.>; Subscribed @.> Subject: Re: [dotnet/Kerberos.NET] Tests: using platform-dependent crypto (Issue #335)

I'll join the problem. KerberosKey generation also does not work for me in Linux. Framework: .Net 8 OS: Alpine 3.19 in Container

I'm trying to generate a key using:

        var keys = new[] {
              new KerberosKey(
         ***@***.****",
         new PrincipalName(PrincipalNameType.NT_PRINCIPAL, "DOMAIN.SRV", new[] { "HTTP/SERVER.domain.srv" }),
         host: "SERVER.domain.srv",
         etype: EncryptionType.AES128_CTS_HMAC_SHA1_96)};
         var krb = new KerberosAuthenticator(new KerberosValidator(keys[0]));
         var identity = krb.Authenticate(authHeader[0].Replace("Negotiate ", ""));

Then I get the same error:

{System.PlatformNotSupportedException: A crypto implementation of MD4 does not exist for Unix at Kerberos.NET.Crypto.CryptoPal.PlatformNotSupported(String algorithm) in D:\a\1\s\Kerberos.NET\Crypto\Pal\CryptoPal.cs:line 95 at Kerberos.NET.Crypto.LinuxCryptoPal.Md4() in D:\a\1\s\Kerberos.NET\Crypto\Pal\Linux\LinuxCryptoPal.cs:line 22 at Kerberos.NET.Crypto.RC4Transformer.MD4(ReadOnlyMemory1 key) in D:\a\1\s\Kerberos.NET\Crypto\RC4\RC4Transformer.cs:line 168 at Kerberos.NET.Crypto.RC4Transformer.String2Key(KerberosKey key) in D:\a\1\s\Kerberos.NET\Crypto\RC4\RC4Transformer.cs:line 38 at Kerberos.NET.Crypto.KerberosKey.<>c__DisplayClass45_0.<GetKey>b__0(EncryptionType etype) in D:\a\1\s\Kerberos.NET\Crypto\KerberosKey.cs:line 224 at System.Collections.Concurrent.ConcurrentDictionary2.GetOrAdd(TKey key, Func2 valueFactory) at Kerberos.NET.Crypto.KerberosKey.GetKey(KerberosCryptoTransformer transformer) in D:\a\1\s\Kerberos.NET\Crypto\KerberosKey.cs:line 224 at Kerberos.NET.Crypto.RC4Transformer.Decrypt(ReadOnlyMemory1 ciphertext, KerberosKey key, KeyUsage usage) in D:\a\1\s\Kerberos.NET\Crypto\RC4\RC4Transformer.cs:line 82 at Kerberos.NET.Entities.KrbEncryptedData.Decrypt[T](KerberosKey key, KeyUsage usage, Func2 func) in D:\a\1\s\Kerberos.NET\Entities\Krb\KrbEncryptedData.cs:line 34 at Kerberos.NET.Crypto.DecryptedKrbApReq.Decrypt(KerberosKey ticketEncryptingKey) in D:\a\1\s\Kerberos.NET\Crypto\DecryptedKrbApReq.cs:line 75 at Kerberos.NET.Crypto.DecryptedKrbApReq.Decrypt(KeyTable keytab) in D:\a\1\s\Kerberos.NET\Crypto\DecryptedKrbApReq.cs:line 70 at Kerberos.NET.Entities.ContextToken.DecryptApReq(KrbApReq token, KeyTable keytab) in D:\a\1\s\Kerberos.NET\Entities\SpNego\ContextToken.cs:line 43 at Kerberos.NET.Entities.KerberosContextToken.DecryptApReq(KeyTable keys) in D:\a\1\s\Kerberos.NET\Entities\SpNego\KerberosContextToken.cs:line 38 at Kerberos.NET.Entities.NegotiateContextToken.DecryptApReq(KeyTable keys) in D:\a\1\s\Kerberos.NET\Entities\SpNego\NegotiateContextToken.cs:line 38 at Kerberos.NET.KerberosValidator.Validate(ReadOnlyMemory1 requestBytes) in D:\a\1\s\Kerberos.NET\KerberosValidator.cs:line 70 at Kerberos.NET.KerberosAuthenticator.Authenticate(ReadOnlyMemory`1 token) in D:\a\1\s\Kerberos.NET\KerberosAuthenticator.cs:line 73 at Kerberos.NET.KerberosAuthenticator.Authenticate(Byte[] token) in D:\a\1\s\Kerberos.NET\KerberosAuthenticator.cs:line 69 at Kerberos.NET.KerberosAuthenticator.Authenticate(String token) in D:\a\1\s\Kerberos.NET\KerberosAuthenticator.cs:line 65 at TestKerberos2.MiddleWare.Invoke(HttpContext context) in C:\Users\user\source\repos\TestKerberos2\TestKerberos2\MiddleWare.cs:line 45}

In this case, decryption of tickets using keytab is successful.

I tried to revert MD4 to Unix myself, but it didn't help:

  1. Installed the openssl package
  2. Applied the fix from the article dotnet/runtime#67353 (comment)https://github.com/dotnet/runtime/issues/67353#issuecomment-1085003764

If my problem is not related to the current one, I can create a separate issuse.

— Reply to this email directly, view it on GitHubhttps://github.com/dotnet/Kerberos.NET/issues/335#issuecomment-2036494345 or unsubscribehttps://github.com/notifications/unsubscribe-auth/AAJHTYJLS4A47H3NK2CKXMDY3UEFVBFKMF2HI4TJMJ2XIZLTSSBKK5TBNR2WLJDUOJ2WLJDOMFWWLO3UNBZGKYLEL5YGC4TUNFRWS4DBNZ2F6YLDORUXM2LUPGBKK5TBNR2WLJDUOJ2WLJDOMFWWLLTXMF2GG2C7MFRXI2LWNF2HTAVFOZQWY5LFUVUXG43VMWSG4YLNMWVXI2DSMVQWIX3UPFYGLAVFOZQWY5LFVE2TMNBSG4ZDGNJVURXGC3LFVFUGC427NRQWEZLMVRZXKYTKMVRXIX3UPFYGLLCJONZXKZKDN5WW2ZLOOSTHI33QNFRXHE4CUR2HS4DFVJZGK4DPONUXI33SPGSXMYLMOVS2QOBVGQ4DSMJTHCBKI5DZOBS2K2LTON2WLJLWMFWHKZNKGE3DAMJYG44TGOJRQKSHI6LQMWSWYYLCMVWKK5TBNR2WLKJVGY2DENZSGM2TLJ3UOJUWOZ3FOKTGG4TFMF2GK. You are receiving this email because you commented on the thread.

Triage notifications on the go with GitHub Mobile for iOShttps://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Androidhttps://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

SteveSyfuhs avatar Apr 04 '24 17:04 SteveSyfuhs