From dc78fbf7e8dcf2c690a8a8abad07f493f877851a Mon Sep 17 00:00:00 2001 From: Cody Batt Date: Wed, 25 Jun 2025 12:59:59 -0600 Subject: [PATCH] Additional flexibility around session keys Expose SessionKey, ClientSubSessionKey and ServerSubSessionKey from ApplicationSessionContext Try to decrypt AP_REP with SessionKey and ClientSubSessionKey Remove sequence number validation on decrypted AP_REP --- .../Client/ApplicationSessionContext.cs | 36 ++++++++++++++++--- Kerberos.NET/Client/KerberosClient.cs | 3 +- Kerberos.NET/Crypto/DecryptedKrbApRep.cs | 8 ----- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/Kerberos.NET/Client/ApplicationSessionContext.cs b/Kerberos.NET/Client/ApplicationSessionContext.cs index 2ec1f24e..cd0b961a 100644 --- a/Kerberos.NET/Client/ApplicationSessionContext.cs +++ b/Kerberos.NET/Client/ApplicationSessionContext.cs @@ -15,15 +15,19 @@ public class ApplicationSessionContext public KrbEncryptionKey SessionKey { get; set; } + public KrbEncryptionKey ClientSubSessionKey { get; set; } + + public KrbEncryptionKey ServerSubSessionKey { get; set; } + public int? SequenceNumber { get; set; } public int CuSec { get; set; } public DateTimeOffset CTime { get; set; } - public KrbEncryptionKey AuthenticateServiceResponse(string asRepEncoded) + public KrbEncryptionKey AuthenticateServiceResponse(string apRepEncoded) { - return AuthenticateServiceResponse(Convert.FromBase64String(asRepEncoded)); + return AuthenticateServiceResponse(Convert.FromBase64String(apRepEncoded)); } public KrbEncryptionKey AuthenticateServiceResponse(ReadOnlyMemory apRepBytes) @@ -37,11 +41,35 @@ public KrbEncryptionKey AuthenticateServiceResponse(ReadOnlyMemory apRepBy SequenceNumber = this.SequenceNumber }; - decrypted.Decrypt(this.SessionKey.AsKey()); + DecryptApRep(decrypted); decrypted.Validate(ValidationActions.TokenWindow); + ServerSubSessionKey = decrypted.Response.SubSessionKey; + + return ServerSubSessionKey ?? this.SessionKey; + } - return decrypted.Response.SubSessionKey ?? this.SessionKey; + private void DecryptApRep(DecryptedKrbApRep decrypted) + { + foreach(var key in new[] { + this.SessionKey, + this.ClientSubSessionKey + }) + { + if (key == null) continue; + try + { + decrypted.Decrypt(key.AsKey()); + return; + } + catch (Exception) + { + // Not this key, continue to the next one + } + } + + throw new InvalidOperationException("Failed to decrypt AP_REP with any of the provided keys."); } + } } diff --git a/Kerberos.NET/Client/KerberosClient.cs b/Kerberos.NET/Client/KerberosClient.cs index 1f22b2be..9102a42a 100644 --- a/Kerberos.NET/Client/KerberosClient.cs +++ b/Kerberos.NET/Client/KerberosClient.cs @@ -882,7 +882,8 @@ public async Task GetServiceTicket( rst, out KrbAuthenticator authenticator ), - SessionKey = authenticator.Subkey ?? serviceTicketCacheEntry.SessionKey, + SessionKey = serviceTicketCacheEntry.SessionKey, + ClientSubSessionKey = authenticator.Subkey, CTime = authenticator.CTime, CuSec = authenticator.CuSec, SequenceNumber = authenticator.SequenceNumber diff --git a/Kerberos.NET/Crypto/DecryptedKrbApRep.cs b/Kerberos.NET/Crypto/DecryptedKrbApRep.cs index 13c67a9f..f62df578 100644 --- a/Kerberos.NET/Crypto/DecryptedKrbApRep.cs +++ b/Kerberos.NET/Crypto/DecryptedKrbApRep.cs @@ -61,14 +61,6 @@ public override void Validate(ValidationActions validation) nameof(this.CuSec) ); } - - if (this.SequenceNumber != this.Response.SequenceNumber) - { - throw new KerberosValidationException( - $"SequenceNumber does not match. Sent: {this.SequenceNumber}; Received: {this.Response.SequenceNumber}", - nameof(this.SequenceNumber) - ); - } } } }