dotnet/Kerberos.NET

Tests: using platform-dependent crypto

Opened this issue · 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.

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

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.

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

We have a bug tracking the request to change these values. It hasn't been a high priority unfortunately. #148

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

Oh, yes, definitely.

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 dotnet/runtime#67353 (comment)

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